From cfb1311eb32a5ac40e8e9154a580fc61f5a496ff Mon Sep 17 00:00:00 2001 From: Glenn <33450392+glenn2223@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:49:27 +0000 Subject: [PATCH 1/3] Implement `Decode(Stream)` Implemented stream decoding Not happy with: (WIP - for now) - Windows: having to use `Skia` - Android: seems slow but it's no the stream conversion --- ZXing.Net.MAUI/IBarcodeReader.cs | 8 +-- ZXing.Net.MAUI/PixelBufferHolder.cs | 103 ++++++++++++++++++++++++++- ZXing.Net.MAUI/ZXing.Net.MAUI.csproj | 3 + ZXing.Net.MAUI/ZXingBarcodeReader.cs | 41 +++++++---- 4 files changed, 137 insertions(+), 18 deletions(-) diff --git a/ZXing.Net.MAUI/IBarcodeReader.cs b/ZXing.Net.MAUI/IBarcodeReader.cs index 24649a1..ddce73c 100644 --- a/ZXing.Net.MAUI/IBarcodeReader.cs +++ b/ZXing.Net.MAUI/IBarcodeReader.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.IO; namespace ZXing.Net.Maui.Readers { @@ -11,5 +7,7 @@ public interface IBarcodeReader BarcodeReaderOptions Options { get; set; } BarcodeResult[] Decode(PixelBufferHolder image); + + BarcodeResult[] Decode(Stream stream); } } diff --git a/ZXing.Net.MAUI/PixelBufferHolder.cs b/ZXing.Net.MAUI/PixelBufferHolder.cs index bcebd8a..3e37c41 100644 --- a/ZXing.Net.MAUI/PixelBufferHolder.cs +++ b/ZXing.Net.MAUI/PixelBufferHolder.cs @@ -1,4 +1,11 @@ using Microsoft.Maui.Graphics; +using System.IO; +using System; +#if WINDOWS || ANDROID +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +#endif namespace ZXing.Net.Maui.Readers { @@ -17,5 +24,99 @@ public record PixelBufferHolder #endif Data { get; init; } + + internal byte[] ByteData { get; set; } + + public PixelBufferHolder() { } + + /// + /// Create the necessary from a stream + /// + /// The stream to pick pixel data from + /// + /// + public static PixelBufferHolder FromStream(Stream stream) + { +#if WINDOWS + + var image = new Microsoft.Maui.Graphics.Skia.SkiaImageLoadingService().FromStream(stream) as Microsoft.Maui.Graphics.Skia.SkiaImage; + + var dataList = new List { }; + + var mySpan = CollectionsMarshal.AsSpan(image!.PlatformRepresentation.Pixels.ToList()); + for (var i = 0; i < mySpan.Length; i++) + { + dataList.Add(mySpan[i].Red); + dataList.Add(mySpan[i].Green); + dataList.Add(mySpan[i].Blue); + } + + var data = dataList.ToArray(); + +#else + + var image = + (Microsoft.Maui.Graphics.Platform.PlatformImage.FromStream(stream) + as Microsoft.Maui.Graphics.Platform.PlatformImage)!; + +#if IOS || MACCATALYST + + var uiImage = image.PlatformRepresentation; + + var pixelBuffer = uiImage.CIImage?.PixelBuffer; + + if (pixelBuffer != null) + return new PixelBufferHolder + { + Size = new(image.Width, image.Height), + Data = pixelBuffer + }; + + var data = uiImage.CGImage?.DataProvider.CopyData()?.ToArray(); + + if (data == null) + throw new NullReferenceException("Could not convert stream to native bytes"); + +#elif ANDROID + + var pixelArr = new int[(int)(image.Width * image.Height)]; + + image!.PlatformRepresentation.GetPixels(pixelArr, 0, (int)image.Width, 0, 0, (int)image.Width, (int)image.Height); + image!.PlatformRepresentation.Recycle(); + + var dataList = new List { }; + + var mySpan = CollectionsMarshal.AsSpan(pixelArr.ToList()); + + for (var i = 0; i < mySpan.Length; i++) + { + var intValue = mySpan[i]; + + dataList.Add( + (byte)(( + (intValue >> 24) + + (intValue >> 16) + + (intValue >> 8) + + (byte)intValue + ) / 4) + ); + } + + var data = dataList.ToArray(); + +#else + + throw new PlatformNotSupportedException(); + +#endif + +#endif + + return new PixelBufferHolder + { + Size = new(image.Width, image.Height), + ByteData = data + }; + } } -} +} \ No newline at end of file diff --git a/ZXing.Net.MAUI/ZXing.Net.MAUI.csproj b/ZXing.Net.MAUI/ZXing.Net.MAUI.csproj index 98985af..a3586b0 100644 --- a/ZXing.Net.MAUI/ZXing.Net.MAUI.csproj +++ b/ZXing.Net.MAUI/ZXing.Net.MAUI.csproj @@ -36,6 +36,9 @@ + + + diff --git a/ZXing.Net.MAUI/ZXingBarcodeReader.cs b/ZXing.Net.MAUI/ZXingBarcodeReader.cs index f7c39da..42d0d9e 100644 --- a/ZXing.Net.MAUI/ZXingBarcodeReader.cs +++ b/ZXing.Net.MAUI/ZXingBarcodeReader.cs @@ -1,8 +1,8 @@ -using Microsoft.Maui.Graphics; +using System.IO; namespace ZXing.Net.Maui.Readers { - public class ZXingBarcodeReader : Readers.IBarcodeReader + public class ZXingBarcodeReader : IBarcodeReader { BarcodeReaderGeneric zxingReader; @@ -28,16 +28,7 @@ public BarcodeReaderOptions Options public BarcodeResult[] Decode(PixelBufferHolder image) { - var w = (int)image.Size.Width; - var h = (int)image.Size.Height; - - LuminanceSource ls = default; - -#if ANDROID - ls = new ByteBufferYUVLuminanceSource(image.Data, w, h, 0, 0, w, h); -#elif MACCATALYST || IOS - ls = new CVPixelBufferBGRA32LuminanceSource(image.Data, w, h); -#endif + LuminanceSource ls = GetLuminanceSource(image); if (Options.Multiple) return zxingReader.DecodeMultiple(ls)?.ToBarcodeResults(); @@ -48,5 +39,31 @@ public BarcodeResult[] Decode(PixelBufferHolder image) return null; } + + public BarcodeResult[] Decode(Stream stream) + => Decode(PixelBufferHolder.FromStream(stream)); + + static LuminanceSource GetLuminanceSource(PixelBufferHolder image) + { + var w = (int)image.Size.Width; + var h = (int)image.Size.Height; + +#if MACCATALYST || IOS + if (image.Data != null) + return new CVPixelBufferBGRA32LuminanceSource(image.Data, w, h); +#elif ANDROID + if (image.Data != null) + return new ByteBufferYUVLuminanceSource(image.Data, w, h, 0, 0, w, h); +#endif + + return + new RGBLuminanceSource( + image.ByteData, + w, h +#if ANDROID || MACCATALYST || IOS + , RGBLuminanceSource.BitmapFormat.Gray8 +#endif + ); + } } } From fc34dcf2411cbb21effec270c3a45b4617b1a865 Mon Sep 17 00:00:00 2001 From: Glenn <33450392+glenn2223@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:52:14 +0000 Subject: [PATCH 2/3] Extended example project Extended the example project to use stream decoding on two new pages --- BigIslandBarcode/App.xaml.cs | 2 +- BigIslandBarcode/MainPage.xaml | 16 ++- BigIslandBarcode/MainPage.xaml.cs | 14 ++- BigIslandBarcode/PickImage.xaml | 56 +++++++++ BigIslandBarcode/PickImage.xaml.cs | 164 +++++++++++++++++++++++++++ BigIslandBarcode/TakeImage.xaml | 56 +++++++++ BigIslandBarcode/TakeImage.xaml.cs | 175 +++++++++++++++++++++++++++++ 7 files changed, 479 insertions(+), 4 deletions(-) create mode 100644 BigIslandBarcode/PickImage.xaml create mode 100644 BigIslandBarcode/PickImage.xaml.cs create mode 100644 BigIslandBarcode/TakeImage.xaml create mode 100644 BigIslandBarcode/TakeImage.xaml.cs diff --git a/BigIslandBarcode/App.xaml.cs b/BigIslandBarcode/App.xaml.cs index d570a94..675cc5a 100644 --- a/BigIslandBarcode/App.xaml.cs +++ b/BigIslandBarcode/App.xaml.cs @@ -11,7 +11,7 @@ public App() { InitializeComponent(); - MainPage = new MainPage(); + MainPage = new NavigationPage(new MainPage()); } } } diff --git a/BigIslandBarcode/MainPage.xaml b/BigIslandBarcode/MainPage.xaml index 42d5db3..f1118b9 100644 --- a/BigIslandBarcode/MainPage.xaml +++ b/BigIslandBarcode/MainPage.xaml @@ -15,7 +15,21 @@ -