diff --git a/BigIslandBarcode/MainPage.xaml b/BigIslandBarcode/MainPage.xaml
index 7ef9b2b..53300f9 100644
--- a/BigIslandBarcode/MainPage.xaml
+++ b/BigIslandBarcode/MainPage.xaml
@@ -22,7 +22,7 @@
Grid.Row="3"
BackgroundColor="#aa000000"
Padding="20"
- ColumnDefinitions="Auto,Auto,*,Auto">
+ ColumnDefinitions="Auto,Auto,*,Auto,Auto">
@@ -41,7 +41,9 @@
CharacterSet="UTF-8"
BarcodeMargin="1" />
-
+
+
+
diff --git a/BigIslandBarcode/MainPage.xaml.cs b/BigIslandBarcode/MainPage.xaml.cs
index 85fdd81..072d873 100644
--- a/BigIslandBarcode/MainPage.xaml.cs
+++ b/BigIslandBarcode/MainPage.xaml.cs
@@ -80,5 +80,32 @@ void TorchButton_Clicked(object sender, EventArgs e)
{
barcodeView.IsTorchOn = !barcodeView.IsTorchOn;
}
+
+ async void SaveBarcodeButton_Clicked(object sender, EventArgs e)
+ {
+ try
+ {
+ // Generate barcode from the view
+ var barcode = await barcodeGenerator.GenerateBarcodeAsync();
+
+ if (barcode != null)
+ {
+ // Save to app data directory (no permissions needed)
+ var filePath = System.IO.Path.Combine(FileSystem.AppDataDirectory, $"barcode_{DateTime.Now:yyyyMMddHHmmss}.png");
+ await barcode.SaveAsync(filePath);
+
+ await DisplayAlert("Success", $"Barcode saved to:\n{filePath}", "OK");
+ ResultLabel.Text = "Barcode saved!";
+ }
+ else
+ {
+ await DisplayAlert("Error", "Failed to generate barcode", "OK");
+ }
+ }
+ catch (Exception ex)
+ {
+ await DisplayAlert("Error", $"Failed to save barcode: {ex.Message}", "OK");
+ }
+ }
}
}
diff --git a/README.md b/README.md
index 2fbe580..cae2202 100644
--- a/README.md
+++ b/README.md
@@ -156,6 +156,170 @@ The `BarcodeGeneratorView` supports UTF-8 character encoding by default, which a
The `CharacterSet` property defaults to "UTF-8" if not specified. Other common values include "ISO-8859-1", "Shift_JIS", etc., depending on your barcode format requirements.
+## Generating and Saving Barcode Images
+
+You can generate barcode images programmatically and save them to files or streams using the `BarcodeGenerator` class:
+
+```csharp
+using ZXing.Net.Maui;
+
+// Create a barcode generator
+var generator = new BarcodeGenerator
+{
+ Format = BarcodeFormat.QrCode,
+ Value = "https://dotnet.microsoft.com",
+ Width = 300,
+ Height = 300,
+ Margin = 10,
+ ForegroundColor = Colors.Black,
+ BackgroundColor = Colors.White
+};
+
+// Generate the barcode image
+var barcodeImage = await generator.GenerateAsync("https://dotnet.microsoft.com");
+
+// Save to file
+await barcodeImage.SaveAsync("/path/to/barcode.png");
+
+// Or save to a stream
+using var stream = new MemoryStream();
+await barcodeImage.SaveAsync(stream, BarcodeImageFormat.Png);
+```
+
+### Supported Image Formats
+
+- **PNG** (all platforms) - Recommended for best quality
+- **JPEG** (all platforms) - For smaller file sizes with compression
+- **WebP** (Android only)
+- **BMP** (Windows only)
+- **GIF** (Windows only)
+- **TIFF** (Windows only)
+
+### Required Permissions for Saving Files
+
+#### Android
+
+To save barcode images to external storage on Android, add the following permissions to your `AndroidManifest.xml` file (under the Platforms\Android folder) inside the `manifest` node:
+
+For Android 12 and below (API level 32 and below):
+```xml
+
+
+```
+
+For Android 13+ (API level 33+), the above permissions are not needed if you're using app-specific directories or the MediaStore API. However, for accessing shared storage, you may need:
+```xml
+
+```
+
+**Note:** You must also request these permissions at runtime using `Permissions.RequestAsync()` and `Permissions.RequestAsync()`.
+
+For app-specific directories (recommended), no permissions are needed:
+```csharp
+// Save to app-specific directory (no permissions needed)
+var path = Path.Combine(FileSystem.AppDataDirectory, "barcode.png");
+await barcodeImage.SaveAsync(path);
+```
+
+#### iOS
+
+To save barcode images to the photo library on iOS, add the following permission to your `info.plist` file (under the Platforms\iOS folder) inside the `dict` node:
+
+```xml
+NSPhotoLibraryAddUsageDescription
+This app needs permission to save barcode images to your photo library
+```
+
+For app-specific directories (recommended), no permissions are needed:
+```csharp
+// Save to app-specific directory (no permissions needed)
+var path = Path.Combine(FileSystem.AppDataDirectory, "barcode.png");
+await barcodeImage.SaveAsync(path);
+```
+
+#### Windows
+
+No special permissions are required for Windows. However, to access certain folders like Documents or Pictures, you may need to declare capabilities in your `Package.appxmanifest`:
+
+```xml
+
+
+
+
+```
+
+For app-specific directories (recommended), no capabilities are needed:
+```csharp
+// Save to app-specific directory (no capabilities needed)
+var path = Path.Combine(FileSystem.AppDataDirectory, "barcode.png");
+await barcodeImage.SaveAsync(path);
+```
+
+### Complete Example
+
+```csharp
+using ZXing.Net.Maui;
+
+public async Task GenerateAndSaveBarcodeAsync()
+{
+ try
+ {
+ // Create the generator
+ var generator = new BarcodeGenerator
+ {
+ Format = BarcodeFormat.QrCode,
+ Width = 500,
+ Height = 500,
+ Margin = 10
+ };
+
+ // Generate barcode
+ var barcode = await generator.GenerateAsync("https://github.com/Redth/ZXing.Net.Maui");
+
+ if (barcode != null)
+ {
+ // Save to app data directory (no permissions needed)
+ var filePath = Path.Combine(FileSystem.AppDataDirectory, "mybarcode.png");
+ await barcode.SaveAsync(filePath);
+
+ Console.WriteLine($"Barcode saved to: {filePath}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error generating barcode: {ex.Message}");
+ }
+}
+```
+
+### Saving from BarcodeGeneratorView
+
+You can also generate and save a barcode image directly from a `BarcodeGeneratorView` control:
+
+```csharp
+// In your XAML
+
+
+
+
+// In your code-behind
+private async void OnSaveClicked(object sender, EventArgs e)
+{
+ var barcode = await barcodeView.GenerateBarcodeAsync();
+
+ if (barcode != null)
+ {
+ var filePath = Path.Combine(FileSystem.AppDataDirectory, "barcode.png");
+ await barcode.SaveAsync(filePath);
+ await DisplayAlert("Success", $"Barcode saved to {filePath}", "OK");
+ }
+}
+```
diff --git a/ZXing.Net.MAUI.Controls/Controls/BarcodeGeneratorView.cs b/ZXing.Net.MAUI.Controls/Controls/BarcodeGeneratorView.cs
index f2caa35..00819ac 100644
--- a/ZXing.Net.MAUI.Controls/Controls/BarcodeGeneratorView.cs
+++ b/ZXing.Net.MAUI.Controls/Controls/BarcodeGeneratorView.cs
@@ -1,5 +1,6 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
+using System.Threading.Tasks;
namespace ZXing.Net.Maui.Controls
{
@@ -58,5 +59,29 @@ public string CharacterSet
get => (string)GetValue(CharacterSetProperty);
set => SetValue(CharacterSetProperty, value);
}
+
+ ///
+ /// Generates a barcode image from the current view settings
+ ///
+ /// The generated barcode image, or null if the value is empty
+ public async Task GenerateBarcodeAsync()
+ {
+ // Use WidthRequest/HeightRequest or default to 300x300 if not set (WidthRequest defaults to -1)
+ var width = WidthRequest > 0 ? (int)WidthRequest : 300;
+ var height = HeightRequest > 0 ? (int)HeightRequest : 300;
+
+ var generator = new BarcodeGenerator
+ {
+ Format = Format,
+ ForegroundColor = ForegroundColor,
+ BackgroundColor = BackgroundColor,
+ Width = width,
+ Height = height,
+ Margin = BarcodeMargin,
+ CharacterSet = CharacterSet
+ };
+
+ return await generator.GenerateAsync(Value);
+ }
}
}
diff --git a/ZXing.Net.MAUI/Apple/BarcodeImageExtensions.ios.maccatalyst.cs b/ZXing.Net.MAUI/Apple/BarcodeImageExtensions.ios.maccatalyst.cs
new file mode 100644
index 0000000..c0e885c
--- /dev/null
+++ b/ZXing.Net.MAUI/Apple/BarcodeImageExtensions.ios.maccatalyst.cs
@@ -0,0 +1,76 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Foundation;
+using UIKit;
+
+#nullable enable
+
+#if IOS || MACCATALYST
+namespace ZXing.Net.Maui
+{
+ ///
+ /// Extension methods for saving barcode images on iOS and MacCatalyst
+ ///
+ public static class BarcodeImageExtensions
+ {
+ ///
+ /// Saves a barcode UIImage to a stream
+ ///
+ /// The image to save
+ /// The stream to write to
+ /// The image format (default: PNG)
+ /// The quality (0-1, default: 1.0)
+ public static async Task SaveAsync(this UIImage? image, Stream stream, BarcodeImageFormat format = BarcodeImageFormat.Png, double quality = 1.0)
+ {
+ if (image == null)
+ throw new ArgumentNullException(nameof(image));
+
+ if (stream == null)
+ throw new ArgumentNullException(nameof(stream));
+
+ NSData? data = format switch
+ {
+ BarcodeImageFormat.Png => image.AsPNG(),
+ BarcodeImageFormat.Jpeg => image.AsJPEG((nfloat)quality),
+ _ => image.AsPNG()
+ };
+
+ if (data == null)
+ throw new InvalidOperationException("Failed to convert image to data");
+
+ await Task.Run(() =>
+ {
+ using var nsStream = data.AsStream();
+ nsStream.CopyTo(stream);
+ });
+ }
+
+ ///
+ /// Saves a barcode UIImage to a file
+ ///
+ /// The image to save
+ /// The file path to write to
+ /// The image format (default: PNG)
+ /// The quality (0-1, default: 1.0)
+ public static async Task SaveAsync(this UIImage? image, string filePath, BarcodeImageFormat format = BarcodeImageFormat.Png, double quality = 1.0)
+ {
+ if (image == null)
+ throw new ArgumentNullException(nameof(image));
+
+ if (string.IsNullOrEmpty(filePath))
+ throw new ArgumentNullException(nameof(filePath));
+
+ // Create directory if it doesn't exist
+ var directory = Path.GetDirectoryName(filePath);
+ if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+
+ using var stream = File.Create(filePath);
+ await image.SaveAsync(stream, format, quality);
+ }
+ }
+}
+#endif
diff --git a/ZXing.Net.MAUI/BarcodeGenerator.cs b/ZXing.Net.MAUI/BarcodeGenerator.cs
new file mode 100644
index 0000000..3406ba8
--- /dev/null
+++ b/ZXing.Net.MAUI/BarcodeGenerator.cs
@@ -0,0 +1,94 @@
+using Microsoft.Maui.Graphics;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using ZXing;
+
+#nullable enable
+
+namespace ZXing.Net.Maui
+{
+ ///
+ /// Provides methods to generate barcode images programmatically
+ ///
+ public class BarcodeGenerator
+ {
+ private readonly BarcodeWriter writer;
+
+ ///
+ /// Gets or sets the barcode format
+ ///
+ public BarcodeFormat Format { get; set; } = BarcodeFormat.QrCode;
+
+ ///
+ /// Gets or sets the foreground color of the barcode
+ ///
+ public Color ForegroundColor { get; set; } = Colors.Black;
+
+ ///
+ /// Gets or sets the background color of the barcode
+ ///
+ public Color BackgroundColor { get; set; } = Colors.White;
+
+ ///
+ /// Gets or sets the width of the barcode in pixels
+ ///
+ public int Width { get; set; } = 300;
+
+ ///
+ /// Gets or sets the height of the barcode in pixels
+ ///
+ public int Height { get; set; } = 300;
+
+ ///
+ /// Gets or sets the margin around the barcode
+ ///
+ public int Margin { get; set; } = 1;
+
+ ///
+ /// Gets or sets the character encoding for the barcode content
+ ///
+ public string CharacterSet { get; set; } = "UTF-8";
+
+ public BarcodeGenerator()
+ {
+ writer = new BarcodeWriter();
+ }
+
+ ///
+ /// Generates a barcode image from the given value
+ ///
+ /// The value to encode in the barcode
+ /// The generated barcode image
+ public NativePlatformImage? Generate(string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ return null;
+
+ writer.Format = Format.ToZXingList().FirstOrDefault();
+ writer.Options.Width = Width;
+ writer.Options.Height = Height;
+ writer.Options.Margin = Margin;
+ writer.ForegroundColor = ForegroundColor;
+ writer.BackgroundColor = BackgroundColor;
+
+ if (!string.IsNullOrEmpty(CharacterSet))
+ {
+ writer.Options.Hints[EncodeHintType.CHARACTER_SET] = CharacterSet;
+ }
+
+ return writer.Write(value);
+ }
+
+ ///
+ /// Generates a barcode image from the given value asynchronously
+ ///
+ /// The value to encode in the barcode
+ /// The generated barcode image
+ public Task GenerateAsync(string value)
+ {
+ return Task.Run(() => Generate(value));
+ }
+ }
+}
diff --git a/ZXing.Net.MAUI/BarcodeImageFormat.cs b/ZXing.Net.MAUI/BarcodeImageFormat.cs
new file mode 100644
index 0000000..0abaecf
--- /dev/null
+++ b/ZXing.Net.MAUI/BarcodeImageFormat.cs
@@ -0,0 +1,38 @@
+namespace ZXing.Net.Maui
+{
+ ///
+ /// Represents the image format for saving barcode images
+ ///
+ public enum BarcodeImageFormat
+ {
+ ///
+ /// PNG format (lossless, recommended)
+ ///
+ Png,
+
+ ///
+ /// JPEG format (lossy compression)
+ ///
+ Jpeg,
+
+ ///
+ /// WebP format (Android only)
+ ///
+ Webp,
+
+ ///
+ /// BMP format (Windows only)
+ ///
+ Bmp,
+
+ ///
+ /// GIF format (Windows only)
+ ///
+ Gif,
+
+ ///
+ /// TIFF format (Windows only)
+ ///
+ Tiff
+ }
+}
diff --git a/ZXing.Net.MAUI/Net/BarcodeImageExtensions.net.cs b/ZXing.Net.MAUI/Net/BarcodeImageExtensions.net.cs
new file mode 100644
index 0000000..41b1036
--- /dev/null
+++ b/ZXing.Net.MAUI/Net/BarcodeImageExtensions.net.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+#nullable enable
+
+namespace ZXing.Net.Maui
+{
+ ///
+ /// Extension methods for saving barcode images (fallback for non-supported platforms)
+ ///
+ public static class BarcodeImageExtensions
+ {
+ ///
+ /// Saves a barcode image to a stream (not implemented for this platform)
+ ///
+ public static Task SaveAsync(this NativePlatformImage? image, Stream stream, BarcodeImageFormat format = BarcodeImageFormat.Png, double quality = 1.0)
+ {
+ throw new PlatformNotSupportedException("Saving barcode images is not supported on this platform. Use Android, iOS, MacCatalyst, or Windows.");
+ }
+
+ ///
+ /// Saves a barcode image to a file (not implemented for this platform)
+ ///
+ public static Task SaveAsync(this NativePlatformImage? image, string filePath, BarcodeImageFormat format = BarcodeImageFormat.Png, double quality = 1.0)
+ {
+ throw new PlatformNotSupportedException("Saving barcode images is not supported on this platform. Use Android, iOS, MacCatalyst, or Windows.");
+ }
+ }
+}
diff --git a/ZXing.Net.MAUI/Platforms/Android/BarcodeImageExtensions.android.cs b/ZXing.Net.MAUI/Platforms/Android/BarcodeImageExtensions.android.cs
new file mode 100644
index 0000000..b5f0675
--- /dev/null
+++ b/ZXing.Net.MAUI/Platforms/Android/BarcodeImageExtensions.android.cs
@@ -0,0 +1,67 @@
+using Android.Graphics;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+#nullable enable
+
+namespace ZXing.Net.Maui
+{
+ ///
+ /// Extension methods for saving barcode images on Android
+ ///
+ public static class BarcodeImageExtensions
+ {
+ ///
+ /// Saves a barcode bitmap to a stream in PNG format
+ ///
+ /// The bitmap to save
+ /// The stream to write to
+ /// The image format (default: PNG)
+ /// The quality (0-100, default: 100)
+ public static async Task SaveAsync(this Bitmap? bitmap, Stream stream, BarcodeImageFormat format = BarcodeImageFormat.Png, int quality = 100)
+ {
+ if (bitmap == null)
+ throw new ArgumentNullException(nameof(bitmap));
+
+ if (stream == null)
+ throw new ArgumentNullException(nameof(stream));
+
+ var androidFormat = format switch
+ {
+ BarcodeImageFormat.Png => Bitmap.CompressFormat.Png!,
+ BarcodeImageFormat.Jpeg => Bitmap.CompressFormat.Jpeg!,
+ BarcodeImageFormat.Webp => Bitmap.CompressFormat.Webp!,
+ _ => Bitmap.CompressFormat.Png!
+ };
+
+ await Task.Run(() => bitmap.Compress(androidFormat, quality, stream));
+ }
+
+ ///
+ /// Saves a barcode bitmap to a file
+ ///
+ /// The bitmap to save
+ /// The file path to write to
+ /// The image format (default: PNG)
+ /// The quality (0-100, default: 100)
+ public static async Task SaveAsync(this Bitmap? bitmap, string filePath, BarcodeImageFormat format = BarcodeImageFormat.Png, int quality = 100)
+ {
+ if (bitmap == null)
+ throw new ArgumentNullException(nameof(bitmap));
+
+ if (string.IsNullOrEmpty(filePath))
+ throw new ArgumentNullException(nameof(filePath));
+
+ // Create directory if it doesn't exist
+ var directory = Path.GetDirectoryName(filePath);
+ if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+
+ using var stream = File.Create(filePath);
+ await bitmap.SaveAsync(stream, format, quality);
+ }
+ }
+}
diff --git a/ZXing.Net.MAUI/Platforms/Windows/BarcodeImageExtensions.windows.cs b/ZXing.Net.MAUI/Platforms/Windows/BarcodeImageExtensions.windows.cs
new file mode 100644
index 0000000..c1a9250
--- /dev/null
+++ b/ZXing.Net.MAUI/Platforms/Windows/BarcodeImageExtensions.windows.cs
@@ -0,0 +1,88 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Threading.Tasks;
+using Microsoft.UI.Xaml.Media.Imaging;
+using Windows.Graphics.Imaging;
+using Windows.Storage.Streams;
+
+#nullable enable
+
+namespace ZXing.Net.Maui
+{
+ ///
+ /// Extension methods for saving barcode images on Windows
+ ///
+ public static class BarcodeImageExtensions
+ {
+ ///
+ /// Saves a barcode WriteableBitmap to a stream
+ ///
+ /// The bitmap to save
+ /// The stream to write to
+ /// The image format (default: PNG)
+ /// The quality (0-1, default: 1.0)
+ public static async Task SaveAsync(this WriteableBitmap? bitmap, Stream stream, BarcodeImageFormat format = BarcodeImageFormat.Png, double quality = 1.0)
+ {
+ if (bitmap == null)
+ throw new ArgumentNullException(nameof(bitmap));
+
+ if (stream == null)
+ throw new ArgumentNullException(nameof(stream));
+
+ var encoderId = format switch
+ {
+ BarcodeImageFormat.Png => BitmapEncoder.PngEncoderId,
+ BarcodeImageFormat.Jpeg => BitmapEncoder.JpegEncoderId,
+ BarcodeImageFormat.Bmp => BitmapEncoder.BmpEncoderId,
+ BarcodeImageFormat.Gif => BitmapEncoder.GifEncoderId,
+ BarcodeImageFormat.Tiff => BitmapEncoder.TiffEncoderId,
+ _ => BitmapEncoder.PngEncoderId
+ };
+
+ using var memoryStream = new InMemoryRandomAccessStream();
+ var encoder = await BitmapEncoder.CreateAsync(encoderId, memoryStream);
+
+ var pixelBuffer = bitmap.PixelBuffer.ToArray();
+ encoder.SetPixelData(
+ BitmapPixelFormat.Bgra8,
+ BitmapAlphaMode.Premultiplied,
+ (uint)bitmap.PixelWidth,
+ (uint)bitmap.PixelHeight,
+ 96, // DPI X
+ 96, // DPI Y
+ pixelBuffer);
+
+ await encoder.FlushAsync();
+
+ memoryStream.Seek(0);
+ await memoryStream.AsStreamForRead().CopyToAsync(stream);
+ }
+
+ ///
+ /// Saves a barcode WriteableBitmap to a file
+ ///
+ /// The bitmap to save
+ /// The file path to write to
+ /// The image format (default: PNG)
+ /// The quality (0-1, default: 1.0)
+ public static async Task SaveAsync(this WriteableBitmap? bitmap, string filePath, BarcodeImageFormat format = BarcodeImageFormat.Png, double quality = 1.0)
+ {
+ if (bitmap == null)
+ throw new ArgumentNullException(nameof(bitmap));
+
+ if (string.IsNullOrEmpty(filePath))
+ throw new ArgumentNullException(nameof(filePath));
+
+ // Create directory if it doesn't exist
+ var directory = Path.GetDirectoryName(filePath);
+ if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+
+ using var stream = File.Create(filePath);
+ await bitmap.SaveAsync(stream, format, quality);
+ }
+ }
+}