diff --git a/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj b/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj index 845d018..ff206f4 100644 --- a/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj +++ b/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj @@ -10,7 +10,7 @@ true true enable - 2.0.1 + 2.1.0 Alen Friščić MIT README.md @@ -51,12 +51,15 @@ - - + + + + + diff --git a/BarcodeScanning.Native.Maui/Platform/Android/CameraManager.cs b/BarcodeScanning.Native.Maui/Platform/Android/CameraManager.cs index 18430a2..1e82b4a 100644 --- a/BarcodeScanning.Native.Maui/Platform/Android/CameraManager.cs +++ b/BarcodeScanning.Native.Maui/Platform/Android/CameraManager.cs @@ -230,7 +230,7 @@ internal void UpdateZoomFactor() UsingRotationDegrees = true } .GetOutputTransform(proxy); - var previewOutputTransform = MainThread.InvokeOnMainThreadAsync(() => _previewView?.OutputTransform).Result; + var previewOutputTransform = MainThread.InvokeOnMainThreadAsync(() => _previewView?.OutputTransform).GetAwaiter().GetResult(); if (imageOutputTransform is not null && previewOutputTransform is not null) return new CoordinateTransform(imageOutputTransform, previewOutputTransform); diff --git a/BarcodeScanning.Native.Maui/Platform/Android/Methods.cs b/BarcodeScanning.Native.Maui/Platform/Android/Methods.cs index 3c30485..3e49814 100644 --- a/BarcodeScanning.Native.Maui/Platform/Android/Methods.cs +++ b/BarcodeScanning.Native.Maui/Platform/Android/Methods.cs @@ -3,8 +3,7 @@ using Android.Runtime; using Java.Net; using Java.Util; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; +using System.Runtime.InteropServices; using Xamarin.Google.MLKit.Vision.Barcode.Common; using Xamarin.Google.MLKit.Vision.BarCode; using Xamarin.Google.MLKit.Vision.Common; @@ -17,11 +16,12 @@ namespace BarcodeScanning; public static partial class Methods { + private static readonly bool neonSupported = IsNeonSupported(); private static readonly ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 }; - + public static async Task> ScanFromImageAsync(byte[] imageArray) => await ProcessBitmapAsync(await BitmapFactory.DecodeByteArrayAsync(imageArray, 0, imageArray.Length)); public static async Task> ScanFromImageAsync(FileResult file) @@ -85,34 +85,32 @@ private static void ProcessBarcodeResult(Java.Lang.Object? inputResults, HashSet } } + [LibraryImport("InvertBytes.so")] + private static partial int InvertBytes(IntPtr data, int length); + internal static void InvertLuminance(Image image) { var yBuffer = image.GetPlanes()?[0].Buffer; if (yBuffer is null) return; - + if (yBuffer.IsDirect) { - unsafe + var data = yBuffer.GetDirectBufferAddress(); + var length = yBuffer.Capacity(); + + int result; + if (neonSupported) + result = InvertBytes(data, length); + else + result = -1; + + if (result != 0) { - if (AdvSimd.IsSupported) + unsafe { - var data = (byte*)yBuffer.GetDirectBufferAddress(); - var length = yBuffer.Capacity(); - - for (int i = 0; i < length; i += Vector128.Count) - { - var vector = AdvSimd.LoadVector128(data + i); - var inverted = AdvSimd.Not(vector); - AdvSimd.Store(data + i, inverted); - } - } - else - { - var data = (ulong*)yBuffer.GetDirectBufferAddress(); - var length = yBuffer.Capacity() >> 3; - - Parallel.For(0, length, parallelOptions, (i) => data[i] = ~data[i]); + var dataPtr = (ulong*)data; + Parallel.For(0, length >> 3, parallelOptions, (i) => dataPtr[i] = ~dataPtr[i]); } } } @@ -191,4 +189,17 @@ internal static Size TargetResolution(CaptureQuality? captureQuality) _ => new Size(1280, 720) }; } + + private static bool IsNeonSupported() + { + try + { + var info = File.ReadAllText("/proc/cpuinfo"); + return info.Contains("neon") || info.Contains("asimd"); + } + catch (Exception) + { + return false; + } + } } \ No newline at end of file diff --git a/BarcodeScanning.Native.Maui/Platform/Android/Native/InvertBytes.cpp b/BarcodeScanning.Native.Maui/Platform/Android/Native/InvertBytes.cpp new file mode 100644 index 0000000..6a06dbb --- /dev/null +++ b/BarcodeScanning.Native.Maui/Platform/Android/Native/InvertBytes.cpp @@ -0,0 +1,33 @@ +#include +#include + +extern "C" int InvertBytes(uint8_t* data, int length) { + if (!data || length <= 0) { + return -1; + } + + const int vectorSize = 64; + int i; + + try { + for (i = 0; i <= length - vectorSize; i += vectorSize) { + uint8x16x4_t vec = vld1q_u8_x4(data + i); + + vec.val[0] = vmvnq_u8(vec.val[0]); + vec.val[1] = vmvnq_u8(vec.val[1]); + vec.val[2] = vmvnq_u8(vec.val[2]); + vec.val[3] = vmvnq_u8(vec.val[3]); + + vst1q_u8_x4(data + i, vec); + } + + for (; i < length; i++) { + data[i] = ~data[i]; + } + } + catch (...) { + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/BarcodeScanning.Native.Maui/Platform/Android/Native/arm64-v8a/InvertBytes.so b/BarcodeScanning.Native.Maui/Platform/Android/Native/arm64-v8a/InvertBytes.so new file mode 100755 index 0000000..ef9a75c Binary files /dev/null and b/BarcodeScanning.Native.Maui/Platform/Android/Native/arm64-v8a/InvertBytes.so differ diff --git a/BarcodeScanning.Native.Maui/Platform/Android/Native/armeabi-v7a/InvertBytes.so b/BarcodeScanning.Native.Maui/Platform/Android/Native/armeabi-v7a/InvertBytes.so new file mode 100755 index 0000000..056dccf Binary files /dev/null and b/BarcodeScanning.Native.Maui/Platform/Android/Native/armeabi-v7a/InvertBytes.so differ diff --git a/BarcodeScanning.Native.Maui/Platform/MaciOS/Extensions.cs b/BarcodeScanning.Native.Maui/Platform/MaciOS/Extensions.cs index 44f7c93..372b3e2 100644 --- a/BarcodeScanning.Native.Maui/Platform/MaciOS/Extensions.cs +++ b/BarcodeScanning.Native.Maui/Platform/MaciOS/Extensions.cs @@ -16,7 +16,7 @@ public static BarcodeResult AsBarcodeResult(this VNBarcodeObservation barcode, A BarcodeFormat = Methods.ConvertFromIOSFormats(barcode.Symbology), DisplayValue = barcode.PayloadStringValue ?? string.Empty, RawValue = barcode.PayloadStringValue ?? string.Empty, - RawBytes = OperatingSystem.IsIOSVersionAtLeast(17) ? [.. barcode.PayloadData ?? []] : Encoding.ASCII.GetBytes(barcode.PayloadStringValue ?? string.Empty), + RawBytes = OperatingSystem.IsIOSVersionAtLeast(17) ? barcode.PayloadData?.ToArray() ?? [] : Encoding.ASCII.GetBytes(barcode.PayloadStringValue ?? string.Empty), PreviewBoundingBox = previewLayer?.MapToLayerCoordinates(InvertY(barcode.BoundingBox)).AsRectangleF() ?? RectF.Zero, ImageBoundingBox = barcode.BoundingBox.AsRectangleF() }; diff --git a/README.md b/README.md index f1a9e0a..0506933 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,9 @@ This library was inspired by existing MAUI barcode scanning libraries: [BarcodeS ```csharp public ICommand DetectionFinishedCommand { get; set; } ... - DetectionFinishedCommand = new Command(BarcodeResult[] result) => + DetectionFinishedCommand = new Command(IReadOnlySet result) => { - if (result.Length > 0) + if (result.Count > 0) ... } ```