Skip to content

Commit

Permalink
Narrow scanning area (Android and iOS) Redth#921
Browse files Browse the repository at this point in the history
  • Loading branch information
NazarStasiv committed Nov 7, 2020
1 parent 21afd64 commit fd2e6d0
Show file tree
Hide file tree
Showing 11 changed files with 440 additions and 65 deletions.
5 changes: 4 additions & 1 deletion Samples/Sample.Android/MainActivity.cs
Expand Up @@ -45,7 +45,10 @@ protected override void OnCreate(Bundle bundle)
scanner.BottomText = "Wait for the barcode to automatically scan!";

//Start scanning
var result = await scanner.Scan();
var result = await scanner.Scan(new MobileBarcodeScanningOptions
{
ScanningArea = ScanningArea.From(0f, 0.49f, 1f, 0.51f)
});

HandleScanResult(result);
};
Expand Down
2 changes: 1 addition & 1 deletion Samples/Sample.Forms/Sample.Forms.Android/MainActivity.cs
@@ -1,5 +1,5 @@
using System;

using Android;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
Expand Down
35 changes: 33 additions & 2 deletions Samples/Sample.Forms/Sample.Forms/HomePage.cs
Expand Up @@ -4,6 +4,8 @@
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using ZXing;
using ZXing.Mobile;
using ZXing.Net.Mobile.Forms;

namespace Sample.Forms
Expand All @@ -17,7 +19,8 @@ public class HomePage : ContentPage
Button buttonScanContinuousCustomPage;
Button buttonScanCustomPage;
Button buttonGenerateBarcode;

Button buttonScanMiddle1D;


public HomePage() : base()
{
Expand Down Expand Up @@ -130,8 +133,36 @@ public HomePage() : base()
await Navigation.PushAsync(new BarcodePage());
};

var stack = new StackLayout();
buttonScanMiddle1D = new Button
{
Text = "Scan 1D only in the middle (Android and iOS only)",
AutomationId = "barcodeMiddleScan1D"
};
buttonScanMiddle1D.Clicked += async delegate
{
scanPage = new ZXingScannerPage(new MobileBarcodeScanningOptions
{
ScanningArea = ScanningArea.From(0f, 0.49f, 1f, 0.51f),
PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.All_1D }
});

scanPage.OnScanResult += (result) =>
{
scanPage.IsScanning = false;
Device.BeginInvokeOnMainThread(async () =>
{
await Navigation.PopAsync();
await DisplayAlert("Scanned Barcode", result.Text, "OK");
});
};

await Navigation.PushAsync(scanPage);
};

var stack = new StackLayout();
stack.Children.Add(buttonScanDefaultOverlay);
stack.Children.Add(buttonScanMiddle1D);
stack.Children.Add(buttonScanCustomOverlay);
stack.Children.Add(buttonScanContinuously);
stack.Children.Add(buttonScanCustomPage);
Expand Down
45 changes: 25 additions & 20 deletions Samples/Sample.iOS/HomeViewController.cs
@@ -1,10 +1,7 @@
using System;
using MonoTouch.Dialog;

using Foundation;
using CoreGraphics;
using UIKit;

using ZXing;
using ZXing.Mobile;
using System.Collections.Generic;
Expand All @@ -25,23 +22,27 @@ public override void ViewDidLoad()
//Create a new instance of our scanner
scanner = new MobileBarcodeScanner(this.NavigationController);

Root = new RootElement("ZXing.Net.Mobile") {
Root = new RootElement("ZXing.Net.Mobile")
{
new Section {

new StyledStringElement ("Scan with Default View", async () => {
//Tell our scanner to use the default overlay
scanner.UseCustomOverlay = false;
//We can customize the top and bottom text of the default overlay
scanner.TopText = "Hold camera up to barcode to scan";
scanner.BottomText = "Barcode will automatically scan";
//Start scanning
var result = await scanner.Scan ();
HandleScanResult(result);
}),

new StyledStringElement ("Scan Continuously", () => {
new StyledStringElement("Scan with Default View", async () =>
{
//Tell our scanner to use the default overlay
scanner.UseCustomOverlay = false;
//We can customize the top and bottom text of the default overlay
scanner.TopText = "Hold camera up to barcode to scan";
scanner.BottomText = "Barcode will automatically scan";
//Start scanning
var result = await scanner.Scan(new MobileBarcodeScanningOptions
{
ScanningArea = ScanningArea.From(0f, 0.3f, 1f, 0.7f)
});
HandleScanResult(result);
}),
new StyledStringElement("Scan with Default View using laser point", async () =>
{
//Tell our scanner to use the default overlay
scanner.UseCustomOverlay = false;
Expand All @@ -50,7 +51,11 @@ public override void ViewDidLoad()
scanner.CustomOverlay = customOverlay;
var opt = new MobileBarcodeScanningOptions ();
var opt = new MobileBarcodeScanningOptions
{
ScanningArea = ScanningArea.From(0f, 0.49f, 1f, 0.51f)
};
opt.DelayBetweenContinuousScans = 3000;
//Start scanning
Expand Down
34 changes: 27 additions & 7 deletions ZXing.Net.Mobile/Android/CameraAccess/CameraAnalyzer.android.cs
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Android.Views;
using ApxLabs.FastAndroidCamera;
Expand Down Expand Up @@ -112,8 +111,6 @@ void DecodeFrame(FastJavaByteArray fastArray)
var width = cameraParameters.PreviewSize.Width;
var height = cameraParameters.PreviewSize.Height;

var barcodeReader = scannerHost.ScanningOptions.BuildBarcodeReader();

var rotate = false;
var newWidth = width;
var newHeight = height;
Expand All @@ -131,10 +128,33 @@ void DecodeFrame(FastJavaByteArray fastArray)
ZXing.Result result = null;
var start = PerformanceCounter.Start();

LuminanceSource fast = new FastJavaByteArrayYUVLuminanceSource(fastArray, width, height, 0, 0, width, height); // _area.Left, _area.Top, _area.Width, _area.Height);
if (rotate)
fast = fast.rotateCounterClockwise();

var scanningRect = scannerHost.ScanningOptions.ScanningArea;
if (rotate)
{
scanningRect = scanningRect.RotateCounterClockwise();
}

var left = (int)(width * scanningRect.StartX);
var top = (int)(height * scanningRect.StartY);
var endHeight = (int)(scanningRect.EndY * height) - top;
var endWidth = (int)(scanningRect.EndX * width) - left;

LuminanceSource fast =
new FastJavaByteArrayYUVLuminanceSource(
fastArray,
width,
height,
left,
top,
endWidth,
endHeight);

if (rotate)
{
fast = fast.rotateCounterClockwise();
}

var barcodeReader = scannerHost.ScanningOptions.BuildBarcodeReader();
result = barcodeReader.Decode(fast);

fastArray.Dispose();
Expand Down
7 changes: 7 additions & 0 deletions ZXing.Net.Mobile/MobileBarcodeScanningOptions.shared.cs
Expand Up @@ -21,12 +21,19 @@ public MobileBarcodeScanningOptions()
InitialDelayBeforeAnalyzingFrames = 300;
DelayBetweenContinuousScans = 1000;
UseNativeScanning = false;
ScanningArea = ScanningArea.Default;
}

public CameraResolutionSelectorDelegate CameraResolutionSelector { get; set; }

public IEnumerable<BarcodeFormat> PossibleFormats { get; set; }

/// <summary>
/// Narrow chosen scanning area.<br/>
/// <b>Works only on iOS and Android</b>
/// </summary>
public ScanningArea ScanningArea { get; set; }

public bool? TryHarder { get; set; }

public bool? PureBarcode { get; set; }
Expand Down
107 changes: 107 additions & 0 deletions ZXing.Net.Mobile/ScanningArea.cs
@@ -0,0 +1,107 @@
using System;

namespace ZXing.Mobile
{
/// <summary>
/// Representation of restricted scanning area in PERCENTAGE.
/// Allowed values: 0 <= value <= 1 AND startY != endY
/// Values of startY and endY are ABSOLUTE to image that means if use values of
/// startY:0.49 and endY:0.51 we will scan only 2% of the whole image
/// starting at 49% and finishing at 51% of the image height.
/// </summary>
public class ScanningArea
{
public float StartX { get; }
public float StartY { get; }
public float EndX { get; }
public float EndY { get; }

ScanningArea(float startX, float startY, float endX, float endY)
{
//if difference between parameters is less than 1% we assume those are equal
if (Math.Abs(startY - endY) < 0.01f)
{
throw new ArgumentException($"Values of {nameof(startY)} and {nameof(endY)} cannot be the same");
}

//if difference between parameters is less than 1% we assume those are equal
if (Math.Abs(startX - endX) < 0.01f)
{
throw new ArgumentException($"Values of {nameof(startX)} and {nameof(endX)} cannot be the same");
}

//Reverse values instead of throwing argument exception
if (startY > endY)
{
var temp = endY;
endY = startY;
startY = temp;
}

if (startX > endX)
{
var temp = endX;
endX = startX;
startX = temp;
}

if (startY < 0)
{
startY = 0;
}

if (endY > 1)
{
endY = 1;
}

if (startX < 0)
{
startX = 0;
}

if (endX > 1)
{
endX = 1;
}

StartY = startY;
EndY = endY;
StartX = startX;
EndX = endX;
}

public ScanningArea RotateCounterClockwise()
{
var startX = StartY;
var startY = EndX;
var endX = EndY;
var endY = StartX;

if (startY > endY)
{
startY = 1f - startY;
endY = 1 - endY;
}

if (startX > endX)
{
startX = 1 - startX;
endX = 1 - endX;
}

return new ScanningArea(startX, startY, endX, endY);
}


static ScanningArea _default = new ScanningArea(0f, 0f, 1f, 1f);

/// <summary>
/// Returns value that represents whole image.
/// </summary>
public static ScanningArea Default => _default;

public static ScanningArea From(float startX, float startY, float endX, float endY) =>
new ScanningArea(startX, startY, endX, endY);
}
}
9 changes: 8 additions & 1 deletion ZXing.Net.Mobile/ZXing.Net.Mobile.csproj
Expand Up @@ -49,10 +49,14 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Compile Include="ScanningArea.cs" />
<None Include="..\Art\ZXing.Net.Mobile-Icon.png" PackagePath="icon.png" Pack="true" />
<Compile Include="**\*.shared.cs" />
<Compile Include="**\*.shared.*.cs" />
</ItemGroup>
<Compile Include="iOS\Helpers\Rect.cs">
<SubType></SubType>
</Compile>
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
<Compile Include="**\*.netstandard.cs" />
<Compile Include="**\*.netstandard.*.cs" />
Expand Down Expand Up @@ -126,4 +130,7 @@
<None Include="..\ZXing.Net\zxing.dll" Pack="True" PackagePath="lib\xamarinios10" />
<None Include="..\ZXing.Net\zxing.dll" Pack="True" PackagePath="lib\xamarinmac20" />
</ItemGroup>
<ItemGroup>
<Folder Include="iOS\Helpers\" />
</ItemGroup>
</Project>

0 comments on commit fd2e6d0

Please sign in to comment.