Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
19768a0
The idea of this commit is to make barcode capability as a plugin.
programatix Nov 8, 2023
28199e5
- Renamed projects
programatix Nov 9, 2023
8c2e861
Fixed a NULL exception issue in MLKitBarcodeDecoder.cs in Android.
programatix Nov 9, 2023
390d953
Forced execute garbage collection in MLKitBarcodeDecoder.Decode as th…
programatix Nov 10, 2023
fd8f906
Automatically stops camera when app is sent to background and restart…
programatix Nov 10, 2023
4c5d38b
Moved garbage collection trigger from plugin to MauiCameraView.
programatix Nov 14, 2023
6b69776
Added PluginDecoder for binding handling.
programatix Nov 14, 2023
df23450
- Updated to .NET 8.0.
programatix Nov 16, 2023
5f41a69
Fixed Readme.md
programatix Nov 16, 2023
7256a59
Reverted back to .NET 7.0 due to restriction on iOS SDK requirement.
programatix Nov 21, 2023
c179c28
Updated CropImage() in iOS MauiCameraView to use UIGraphicsImageRende…
programatix Nov 21, 2023
8b8ae26
Fixed iOS UI freeze issue and resolved obsolete warning in iOS MauiCa…
programatix Nov 22, 2023
806e3ff
Applied fixes from https://github.com/hjam40/Camera.MAUI/pull/69 (#69)
programatix Nov 22, 2023
b3811a7
Fixed incorrect cropping in Android when taking a snap from the preview.
programatix Nov 22, 2023
2c36f77
Added CameraView.PluginDecoders to attach CameraView to more than one…
programatix Nov 22, 2023
95a5079
Fixed random crash for Android and other misc changes
programatix Nov 23, 2023
dbd6660
Fixed more race condition crashes and corrected Torch implementation …
programatix Nov 24, 2023
05d4404
Fixed Android camera zoom control
programatix Nov 27, 2023
6dccf72
Resolved iOS issue where multiple decoding processes occured even whe…
programatix Dec 4, 2023
3364765
Another attempt to fix iOS issue where multiple decoding processes oc…
programatix Dec 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions Camera.MAUI.Plugin.MLKit/Camera.MAUI.Plugin.MLKit.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0-android;net7.0-ios;</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>

<Authors>programatix</Authors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0-ios'">
<PackageReference Include="Xamarin.Firebase.iOS.Core" Version="8.10.0.3" />
<PackageReference Include="Xamarin.MLKit.iOS.BarcodeScanning.JimmyPun610" Version="1.6.0.1" />
<PackageReference Include="Xamarin.MLKit.iOS.Core.JimmyPun610" Version="5.0.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Camera.MAUI.Plugin\Camera.MAUI.Plugin.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0-android'">
<PackageReference Include="Xamarin.AndroidX.Activity">
<Version>1.8.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx">
<Version>1.8.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Collection.Jvm">
<Version>1.3.0.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Collection.Ktx">
<Version>1.3.0.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.Lifecycle.Common">
<Version>2.6.2.3</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.MLKit.BarcodeScanning">
<Version>117.2.0.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.MLKit.BarcodeScanning.Common">
<Version>117.0.0.7</Version>
</PackageReference>
<PackageReference Include="Xamarin.GooglePlayServices.MLKit.BarcodeScanning">
<Version>118.3.0.2</Version>
</PackageReference>
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions Camera.MAUI.Plugin.MLKit/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Camera.MAUI.Plugin.MLKit
{
internal static class Extensions
{
}
}
107 changes: 107 additions & 0 deletions Camera.MAUI.Plugin.MLKit/MLKitBarcodeDecoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#if IOS || MACCATALYST
using Foundation;
using global::MLKit.BarcodeScanning;
using global::MLKit.Core;
using DecodeDataType = UIKit.UIImage;
#elif ANDROID

using Xamarin.Google.MLKit.Vision.BarCode;
using Xamarin.Google.MLKit.Vision.Common;
using static Xamarin.Google.MLKit.Vision.Barcode.Common.Barcode;
using BarcodeScanner = Xamarin.Google.MLKit.Vision.BarCode.IBarcodeScanner;
using DecodeDataType = Android.Graphics.Bitmap;

#elif WINDOWS
using BarcodeScanner = System.Object;
using DecodeDataType = Windows.Graphics.Imaging.SoftwareBitmap;
#endif

namespace Camera.MAUI.Plugin.MLKit
{
public class MLKitBarcodeDecoder : PluginDecoder<MLKitBarcodeDecoderOptions, BarcodeResult>
{
#region Private Fields

private BarcodeScanner barcodeScanner;

#endregion Private Fields

#region Public Methods

public override void ClearResults()
{
}

public
#if ANDROID
async
#endif
override void Decode(DecodeDataType data)
{
try
{
#if ANDROID
var image = InputImage.FromBitmap(data, 0);
var result = await barcodeScanner.Process(image).ToAwaitableTask();
var results = Methods.ProcessBarcodeResult(result);
if (results?.Count > 0)
{
OnDecoded(new PluginDecodedEventArgs { Results = results.ToArray() });
}
image.Dispose();
#elif IOS
var image = new MLImage(data) { Orientation = UIKit.UIImageOrientation.Up };
barcodeScanner.ProcessImage(image, (barcodes, error) =>
{
var results = new List<BarcodeResult>();
foreach (var barcode in barcodes)
results.Add(Methods.ProcessBarcodeResult(barcode));

if (results.Count > 0)
{
OnDecoded(new PluginDecodedEventArgs { Results = results.ToArray() });
}

image.Dispose();
});
#else
throw new NotImplementedException();
#endif
}
catch { }
finally
{
}
}

#endregion Public Methods

#region Protected Methods

protected override void OnOptionsChanged(object oldValue, object newValue)
{
if (newValue is BarcodeDecoderOptions barcodeOptions)
{
#if ANDROID || IOS
var platformFormats = barcodeOptions.PossibleFormats?.Count > 0
? barcodeOptions.PossibleFormats.Select(x => x.ToPlatform()).Aggregate((r, x) => r |= x)
: default;
#if ANDROID
barcodeScanner = BarcodeScanning.GetClient(new BarcodeScannerOptions.Builder()
.SetBarcodeFormats(platformFormats == default ? FormatAllFormats : platformFormats)
.Build()
);
#elif IOS
var scannerOptions = new BarcodeScannerOptions(platformFormats == default ? global::MLKit.BarcodeScanning.BarcodeFormat.Unknown : platformFormats);
barcodeScanner = BarcodeScanner.BarcodeScannerWithOptions(scannerOptions);
#endif
#endif
}
if (newValue is MLKitBarcodeDecoderOptions mlkitOptions)
{
}
}

#endregion Protected Methods
}
}
6 changes: 6 additions & 0 deletions Camera.MAUI.Plugin.MLKit/MLKitBarcodeDecoderOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Camera.MAUI.Plugin.MLKit
{
public record MLKitBarcodeDecoderOptions : BarcodeDecoderOptions
{
}
}
83 changes: 83 additions & 0 deletions Camera.MAUI.Plugin.MLKit/Platforms/Android/Methods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Android.Runtime;
using Java.Util;
using Xamarin.Google.MLKit.Vision.Barcode.Common;

namespace Camera.MAUI.Plugin.MLKit
{
internal static class Methods
{
internal static int ToPlatform(this BarcodeFormat format)
{
return format switch
{
BarcodeFormat.AZTEC => Barcode.FormatAztec,
BarcodeFormat.CODABAR => Barcode.FormatCodabar,
BarcodeFormat.CODE_128 => Barcode.FormatCode128,
BarcodeFormat.CODE_39 => Barcode.FormatCode39,
BarcodeFormat.CODE_93 => Barcode.FormatCode93,
BarcodeFormat.DATA_MATRIX => Barcode.FormatDataMatrix,
BarcodeFormat.EAN_13 => Barcode.FormatEan13,
BarcodeFormat.EAN_8 => Barcode.FormatEan8,
BarcodeFormat.ITF => Barcode.FormatItf,
BarcodeFormat.PDF_417 => Barcode.FormatPdf417,
BarcodeFormat.QR_CODE => Barcode.FormatQrCode,
BarcodeFormat.UPC_A => Barcode.FormatUpcA,
BarcodeFormat.UPC_E => Barcode.FormatUpcE,
_ => Barcode.FormatUnknown,
};
}

internal static BarcodeFormat BarcodeFormatToNative(this int format)
{
return format switch
{
Barcode.FormatAztec => BarcodeFormat.AZTEC,
Barcode.FormatCodabar => BarcodeFormat.CODABAR,
Barcode.FormatCode128 => BarcodeFormat.CODE_128,
Barcode.FormatCode39 => BarcodeFormat.CODE_39,
Barcode.FormatCode93 => BarcodeFormat.CODE_93,
Barcode.FormatDataMatrix => BarcodeFormat.DATA_MATRIX,
Barcode.FormatEan13 => BarcodeFormat.EAN_13,
Barcode.FormatEan8 => BarcodeFormat.EAN_8,
Barcode.FormatItf => BarcodeFormat.ITF,
Barcode.FormatPdf417 => BarcodeFormat.PDF_417,
Barcode.FormatQrCode => BarcodeFormat.QR_CODE,
Barcode.FormatUpcA => BarcodeFormat.UPC_A,
Barcode.FormatUpcE => BarcodeFormat.UPC_E,
_ => throw new NotSupportedException()
};
}

internal static List<BarcodeResult> ProcessBarcodeResult(Java.Lang.Object result)
{
if (result == null)
return null;
var javaList = result.JavaCast<ArrayList>();
if (javaList.IsEmpty)
return null;
var resultList = new List<BarcodeResult>();

foreach (var barcode in javaList.ToArray())
{
var mapped = barcode.JavaCast<Barcode>();
var cornerPoints = new List<Point>();

foreach (var cornerPoint in mapped.GetCornerPoints())
cornerPoints.Add(new Point(cornerPoint.X, cornerPoint.Y));

resultList.Add(new BarcodeResult(mapped.DisplayValue, mapped.GetRawBytes(), cornerPoints.ToArray(), mapped.Format.BarcodeFormatToNative()));
}

return resultList;
}

internal static Task<Java.Lang.Object> ToAwaitableTask(this global::Android.Gms.Tasks.Task task)
{
var taskCompletionSource = new TaskCompletionSource<Java.Lang.Object>();
var taskCompleteListener = new TaskCompleteListener(taskCompletionSource);
task.AddOnCompleteListener(taskCompleteListener);

return taskCompletionSource.Task;
}
}
}
30 changes: 30 additions & 0 deletions Camera.MAUI.Plugin.MLKit/Platforms/Android/TaskCompleteListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Android.Gms.Tasks;

namespace Camera.MAUI.Plugin.MLKit
{
internal class TaskCompleteListener : Java.Lang.Object, IOnCompleteListener
{
private readonly TaskCompletionSource<Java.Lang.Object> _taskCompletionSource;

public TaskCompleteListener(TaskCompletionSource<Java.Lang.Object> tcs)
{
_taskCompletionSource = tcs;
}

public void OnComplete(global::Android.Gms.Tasks.Task task)
{
if (task.IsCanceled)
{
_taskCompletionSource.SetCanceled();
}
else if (task.IsSuccessful)
{
_taskCompletionSource.SetResult(task.Result);
}
else
{
_taskCompletionSource.SetException(task.Exception);
}
}
}
}
57 changes: 57 additions & 0 deletions Camera.MAUI.Plugin.MLKit/Platforms/iOS/Methods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace Camera.MAUI.Plugin.MLKit
{
internal static class Methods
{
internal static global::MLKit.BarcodeScanning.BarcodeFormat ToPlatform(this BarcodeFormat format)
{
return format switch
{
BarcodeFormat.AZTEC => global::MLKit.BarcodeScanning.BarcodeFormat.Aztec,
BarcodeFormat.CODABAR => global::MLKit.BarcodeScanning.BarcodeFormat.CodaBar,
BarcodeFormat.CODE_128 => global::MLKit.BarcodeScanning.BarcodeFormat.Code128,
BarcodeFormat.CODE_39 => global::MLKit.BarcodeScanning.BarcodeFormat.Code39,
BarcodeFormat.CODE_93 => global::MLKit.BarcodeScanning.BarcodeFormat.Code93,
BarcodeFormat.DATA_MATRIX => global::MLKit.BarcodeScanning.BarcodeFormat.DataMatrix,
BarcodeFormat.EAN_13 => global::MLKit.BarcodeScanning.BarcodeFormat.Ean13,
BarcodeFormat.EAN_8 => global::MLKit.BarcodeScanning.BarcodeFormat.Ean8,
BarcodeFormat.ITF => global::MLKit.BarcodeScanning.BarcodeFormat.Itf,
BarcodeFormat.PDF_417 => global::MLKit.BarcodeScanning.BarcodeFormat.Pdf417,
BarcodeFormat.QR_CODE => global::MLKit.BarcodeScanning.BarcodeFormat.QrCode,
BarcodeFormat.UPC_A => global::MLKit.BarcodeScanning.BarcodeFormat.Upca,
BarcodeFormat.UPC_E => global::MLKit.BarcodeScanning.BarcodeFormat.Upce,
_ => global::MLKit.BarcodeScanning.BarcodeFormat.Unknown,
};
}

internal static BarcodeFormat BarcodeFormatToNative(this global::MLKit.BarcodeScanning.BarcodeFormat format)
{
return format switch
{
global::MLKit.BarcodeScanning.BarcodeFormat.Aztec => BarcodeFormat.AZTEC,
global::MLKit.BarcodeScanning.BarcodeFormat.CodaBar => BarcodeFormat.CODABAR,
global::MLKit.BarcodeScanning.BarcodeFormat.Code128 => BarcodeFormat.CODE_128,
global::MLKit.BarcodeScanning.BarcodeFormat.Code39 => BarcodeFormat.CODE_39,
global::MLKit.BarcodeScanning.BarcodeFormat.Code93 => BarcodeFormat.CODE_93,
global::MLKit.BarcodeScanning.BarcodeFormat.DataMatrix => BarcodeFormat.DATA_MATRIX,
global::MLKit.BarcodeScanning.BarcodeFormat.Ean13 => BarcodeFormat.EAN_13,
global::MLKit.BarcodeScanning.BarcodeFormat.Ean8 => BarcodeFormat.EAN_8,
global::MLKit.BarcodeScanning.BarcodeFormat.Itf => BarcodeFormat.ITF,
global::MLKit.BarcodeScanning.BarcodeFormat.Pdf417 => BarcodeFormat.PDF_417,
global::MLKit.BarcodeScanning.BarcodeFormat.QrCode => BarcodeFormat.QR_CODE,
global::MLKit.BarcodeScanning.BarcodeFormat.Upca => BarcodeFormat.UPC_A,
global::MLKit.BarcodeScanning.BarcodeFormat.Upce => BarcodeFormat.UPC_E,
_ => throw new NotSupportedException()
};
}

internal static BarcodeResult ProcessBarcodeResult(global::MLKit.BarcodeScanning.Barcode barcode)
{
var cornerPoints = new List<Point>();

foreach (var cornerPoint in barcode.CornerPoints)
cornerPoints.Add(new Point(cornerPoint.CGPointValue.X, cornerPoint.CGPointValue.Y));

return new BarcodeResult(barcode.DisplayValue, barcode.RawData.ToArray(), cornerPoints.ToArray(), barcode.Format.BarcodeFormatToNative());
}
}
}
35 changes: 35 additions & 0 deletions Camera.MAUI.Plugin.ZXing/Camera.MAUI.Plugin.ZXing.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0;net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>

<Authors>hjam40,programatix</Authors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ZXing.Net" Version="0.16.9" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Camera.MAUI.Plugin\Camera.MAUI.Plugin.csproj" />
</ItemGroup>

<!-- Both iOS and Mac Catalyst -->
<ItemGroup Condition="$(TargetFramework.StartsWith('net7.0-ios')) != true AND $(TargetFramework.StartsWith('net7.0-maccatalyst')) != true">
<Compile Remove="**\MaciOS\**\*.cs" />
<None Include="**\MaciOS\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
</Project>
Loading