Skip to content

Commit

Permalink
ZXing.Net.Maui
Browse files Browse the repository at this point in the history
  • Loading branch information
DyIgor committed Aug 21, 2022
1 parent 083d703 commit 7747bc7
Show file tree
Hide file tree
Showing 19 changed files with 1,921 additions and 8 deletions.
92 changes: 92 additions & 0 deletions ZXing.Net.Maui/Platforms/Android/BitmapRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using Android.Graphics;

using ZXing.Common;
using ZXing.Rendering;
using Color = Android.Graphics.Color;

namespace ZXing.Net.Maui.Platforms.Android
{
/// <summary>
/// Renders a <see cref="BitMatrix" /> to a <see cref="Bitmap" /> image
/// </summary>
public class BitmapRenderer : IBarcodeRenderer<Bitmap>
{
/// <summary>
/// Gets or sets the foreground color.
/// </summary>
/// <value>The foreground color.</value>
public Color Foreground { get; set; }

/// <summary>
/// Gets or sets the background color.
/// </summary>
/// <value>The background color.</value>
public Color Background { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="BitmapRenderer"/> class.
/// </summary>
public BitmapRenderer()
{
Foreground = Color.Black;
Background = Color.White;
}

/// <summary>
/// Renders the specified matrix.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <param name="format">The format.</param>
/// <param name="content">The content.</param>
/// <returns></returns>
public Bitmap Render(BitMatrix matrix, BarcodeFormat format, string content)
=> Render(matrix, format, content, new EncodingOptions());

/// <summary>
/// Renders the specified matrix.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <param name="format">The format.</param>
/// <param name="content">The content.</param>
/// <param name="options">The options.</param>
/// <returns></returns>
public Bitmap Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options)
{
var width = matrix.Width;
var height = matrix.Height;
var pixels = new int[width * height];
var outputIndex = 0;
var fColor = Foreground.ToArgb();
var bColor = Background.ToArgb();

for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
pixels[outputIndex] = matrix[x, y] ? fColor : bColor;
outputIndex++;
}
}

var bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
bitmap.SetPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
}
}
31 changes: 31 additions & 0 deletions ZXing.Net.Maui/Platforms/Android/BitmapWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using Android.Graphics;

namespace ZXing.Net.Maui.Platforms.Android
{
/// <summary>
/// A smart class to encode some content to a barcode image
/// </summary>
public class BarcodeWriter : BarcodeWriter<Bitmap>, IBarcodeWriter
{
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeWriter"/> class.
/// </summary>
public BarcodeWriter() => Renderer = new BitmapRenderer();
}
}
154 changes: 154 additions & 0 deletions ZXing.Net.Maui/Platforms/Android/CameraAccess/CameraAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using Android.Util;
using Android.Views;
using ApxLabs.FastAndroidCamera;

namespace ZXing.Net.Maui.Platforms.Android.CameraAccess
{
public class CameraAnalyzer
{
readonly CameraController cameraController;
readonly CameraEventsListener cameraEventListener;
Task processingTask;
DateTime lastPreviewAnalysis = DateTime.UtcNow;
bool wasScanned;
readonly IScannerSessionHost scannerHost;
BarcodeReaderGeneric barcodeReader;

public CameraAnalyzer(SurfaceView surfaceView, IScannerSessionHost scannerHost)
{
this.scannerHost = scannerHost;
cameraEventListener = new CameraEventsListener();
cameraController = new CameraController(surfaceView, cameraEventListener, scannerHost);
Torch = new Torch(cameraController, surfaceView.Context);
}

public Action<Result> BarcodeFound;

public Torch Torch { get; }

public bool IsAnalyzing { get; private set; }

public void PauseAnalysis()
=> IsAnalyzing = false;

public void ResumeAnalysis()
=> IsAnalyzing = true;

public void ShutdownCamera()
{
IsAnalyzing = false;
cameraEventListener.OnPreviewFrameReady -= HandleOnPreviewFrameReady;
cameraController.ShutdownCamera();
}

public void SetupCamera()
{
cameraEventListener.OnPreviewFrameReady += HandleOnPreviewFrameReady;
cameraController.SetupCamera();
barcodeReader = scannerHost.ScanningOptions.BuildBarcodeReader();
}

public void AutoFocus()
=> cameraController.AutoFocus();

public void AutoFocus(int x, int y)
=> cameraController.AutoFocus(x, y);

public void RefreshCamera()
=> cameraController.RefreshCamera();

bool CanAnalyzeFrame
{
get
{
if (!IsAnalyzing)
return false;

//Check and see if we're still processing a previous frame
// todo: check if we can run as many as possible or mby run two analyzers at once (Vision + ZXing)
if (processingTask != null && !processingTask.IsCompleted)
return false;

var elapsedTimeMs = (DateTime.UtcNow - lastPreviewAnalysis).TotalMilliseconds;
if (elapsedTimeMs < scannerHost.ScanningOptions.DelayBetweenAnalyzingFrames)
return false;

// Delay a minimum between scans
if (wasScanned && elapsedTimeMs < scannerHost.ScanningOptions.DelayBetweenContinuousScans)
return false;

return true;
}
}

void HandleOnPreviewFrameReady(object sender, FastJavaByteArray fastArray)
{
if (!CanAnalyzeFrame)
return;

wasScanned = false;
lastPreviewAnalysis = DateTime.UtcNow;

processingTask = Task.Run(() =>
{
try
{
DecodeFrame(fastArray);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}).ContinueWith(task =>
{
if (task.IsFaulted)
Log.Debug(MobileBarcodeScanner.TAG, "DecodeFrame exception occurs");
}, TaskContinuationOptions.OnlyOnFaulted);
}

void DecodeFrame(FastJavaByteArray fastArray)
{
var resolution = cameraController.CameraResolution;
var width = resolution.Width;
var height = resolution.Height;

var rotate = false;
var newWidth = width;
var newHeight = height;

// use last value for performance gain
var cDegrees = cameraController.LastCameraDisplayOrientationDegree;

if (cDegrees == 90 || cDegrees == 270)
{
rotate = true;
newWidth = height;
newHeight = width;
}

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 result = barcodeReader.Decode(fast);

fastArray.Dispose();
fastArray = null;

PerformanceCounter.Stop(start,
"Decode Time: {0} ms (width: " + width + ", height: " + height + ", degrees: " + cDegrees + ", rotate: " +
rotate + ")");

if (result != null)
{
Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found");

wasScanned = true;
BarcodeFound?.Invoke(result);
return;
}
}
}
}
Loading

0 comments on commit 7747bc7

Please sign in to comment.