Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Narrow scanning area (Android and iOS) #921

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
31 changes: 31 additions & 0 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,6 +19,7 @@ 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());
};

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
32 changes: 24 additions & 8 deletions Samples/Sample.iOS/HomeViewController.cs
@@ -1,10 +1,6 @@
using System;
using MonoTouch.Dialog;

using Foundation;
using CoreGraphics;
using UIKit;

using ZXing;
using ZXing.Mobile;
using System.Collections.Generic;
Expand All @@ -25,18 +21,38 @@ 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(new MobileBarcodeScanningOptions
{
ScanningArea = ScanningArea.From(0f, 0.3f, 1f, 0.7f)
});

new StyledStringElement ("Scan with Default View", async () => {
HandleScanResult(result);
}),
new StyledStringElement("Scan with Default View using laser point", 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 ();
var result = await scanner.Scan(new MobileBarcodeScanningOptions
{
ScanningArea = ScanningArea.From(0f, 0.49f, 1f, 0.51f)
});

HandleScanResult(result);
}),
Expand Down Expand Up @@ -145,4 +161,4 @@ public void UITestBackdoorScan(string param)
});
}
}
}
}
28 changes: 24 additions & 4 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);
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
9 changes: 8 additions & 1 deletion 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 Expand Up @@ -118,4 +125,4 @@ public CameraResolution GetResolution(List<CameraResolution> availableResolution
return r;
}
}
}
}
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);
}
}
7 changes: 7 additions & 0 deletions ZXing.Net.Mobile/ZXing.Net.Mobile.csproj
Expand Up @@ -49,9 +49,13 @@
<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" />
<Compile Include="iOS\Helpers\Rect.cs">
<SubType></SubType>
</Compile>
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
<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>