diff --git a/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraAnalyzer.cs b/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraAnalyzer.cs index bdbe10a5e..a94c1c621 100644 --- a/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraAnalyzer.cs +++ b/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraAnalyzer.cs @@ -1,19 +1,60 @@ -using System; +/* +* Copyright 2018 ZXing/Redth - https://github.com/Redth/ZXing.Net.Mobile +* +* 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. +* +* Edited by VK, Apacheta Corp 11/14/2018. +* http://www.apacheta.com/ +* +*/ + +using System; using System.Collections.Generic; using System.Threading.Tasks; using Android.Views; using ApxLabs.FastAndroidCamera; +using Android.Graphics; +using Android.Content; +using Android.Util; namespace ZXing.Mobile.CameraAccess { public class CameraAnalyzer { + /// + ///START - Scanning Improvement, VK 11/14/2018 + /// + private const int MIN_FRAME_WIDTH = 240; + private const int MIN_FRAME_HEIGHT = 240; + private const int MAX_FRAME_WIDTH = 640; // = 5/8 * 1920 + private const int MAX_FRAME_HEIGHT = 480; // = 5/8 * 1080 + /// + /// END - Scanning Improvement, VK 11/14/2018 + /// + /// + private readonly CameraController _cameraController; private readonly CameraEventsListener _cameraEventListener; + private int _screenHeight = -1; + private int _screenWidth = -1; private Task _processingTask; private DateTime _lastPreviewAnalysis = DateTime.UtcNow; private bool _wasScanned; IScannerSessionHost _scannerHost; + + private Rect framingRectInPreview; + private Rect framingRect; + private IWindowManager manager; private bool _cameraSetup; public CameraAnalyzer(SurfaceView surfaceView, IScannerSessionHost scannerHost) @@ -22,6 +63,14 @@ public CameraAnalyzer(SurfaceView surfaceView, IScannerSessionHost scannerHost) _cameraEventListener = new CameraEventsListener(); _cameraController = new CameraController(surfaceView, _cameraEventListener, scannerHost); Torch = new Torch(_cameraController, surfaceView.Context); + try + { + manager = (surfaceView.Context as ZxingActivity)?.WindowManager; + } + catch (Exception ex) + { + Log.Debug(MobileBarcodeScanner.TAG, "Error occured while getting window manager : " + ex.ToString()); + } } public event EventHandler BarcodeFound; @@ -66,6 +115,15 @@ public void AutoFocus() _cameraController.AutoFocus(); } + /// + ///Scanning Improvement, VK 10/2018 + ///Removed this method for now. + /// + //public void LowLightMode(bool on) + //{ + // _cameraController.LowLightMode(on); + //} + public void AutoFocus(int x, int y) { _cameraController.AutoFocus(x, y); @@ -74,31 +132,39 @@ public void AutoFocus(int x, int y) public void RefreshCamera() { //only refresh the camera if it is actually setup - if(_cameraSetup) + if (_cameraSetup) _cameraController.RefreshCamera(); } + private bool Valid_ScreenResolution + { + get + { + return _screenHeight > 0 && _screenWidth > 0; + } + } + private bool CanAnalyzeFrame { get { - if (!IsAnalyzing) - return false; - + 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; + if (elapsedTimeMs < _scannerHost.ScanningOptions.DelayBetweenAnalyzingFrames) + return false; + + // Delay a minimum between scans + if (_wasScanned && elapsedTimeMs < _scannerHost.ScanningOptions.DelayBetweenContinuousScans) + return false; + + return true; } } @@ -110,18 +176,21 @@ private void HandleOnPreviewFrameReady(object sender, FastJavaByteArray fastArra _wasScanned = false; _lastPreviewAnalysis = DateTime.UtcNow; - _processingTask = Task.Run(() => - { - try - { - DecodeFrame(fastArray); - } catch (Exception ex) { - Console.WriteLine(ex); - } - }).ContinueWith(task => + _processingTask = Task.Run(() => + { + try + { + Log.Debug(MobileBarcodeScanner.TAG, "Preview Analyzing."); + DecodeFrame(fastArray); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + }).ContinueWith(task => { if (task.IsFaulted) - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "DecodeFrame exception occurs"); + Log.Debug(MobileBarcodeScanner.TAG, "DecodeFrame exception occurs"); }, TaskContinuationOptions.OnlyOnFaulted); } @@ -150,7 +219,28 @@ private 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); + /// + ///START - Scanning Improvement, VK Apacheta Corp 11/14/2018 + ///Added a new frame to get the center part of the captured image. + ///To create a FastJavaByteArray from the cropped captured frame and use it to decode the barcode. + ///To decrease the processing time drastically for higher resolution cameras. + /// + var frame_width = width * 3 / 5; + var frame_height = height * 3 / 5; + var frame_left = width * 1 / 5; + var frame_top = height * 1 / 5; + + LuminanceSource fast = new FastJavaByteArrayYUVLuminanceSource(fastArray, width, height, + //framingRectPreview?.Width() ?? width, + // framingRectPreview?.Height() ?? height, + frame_left, + frame_top, + frame_width, + frame_height); // _area.Left, _area.Top, _area.Width, _area.Height); + + /// + ///END - Scanning Improvement, VK Apacheta Corp 11/14/2018 + /// if (rotate) fast = fast.rotateCounterClockwise(); @@ -160,17 +250,139 @@ private void DecodeFrame(FastJavaByteArray fastArray) fastArray = null; PerformanceCounter.Stop(start, - "Decode Time: {0} ms (width: " + width + ", height: " + height + ", degrees: " + cDegrees + ", rotate: " + - rotate + ")"); + $"width: {width}, height: {height}, frame_top :{frame_top}, frame_left: {frame_left}, frame_width: {frame_width}, frame_height: {frame_height}, degrees: {cDegrees}, rotate: {rotate}; " + "Decode Time: {0} ms"); if (result != null) { - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found"); + Log.Debug(MobileBarcodeScanner.TAG, "Barcode Found"); _wasScanned = true; BarcodeFound?.Invoke(this, result); return; } } + + + /// + ///Scanning Improvement, VK 10/2018 + /// + private Rect GetFramingRectInPreview() + { + if (framingRectInPreview == null) + { + //if (!Valid_ScreenResolution) + // GetScreenResolution(); + var cameraParameters = _cameraController?.Camera?.GetParameters(); + var width = cameraParameters.PreviewSize.Width; + var height = cameraParameters.PreviewSize.Height; + if (cameraParameters == null)//|| !Valid_ScreenResolution) + { + // Called early, before init even finished + return null; + } + + var framingRect = GetFramingRect(width, height); + if (framingRect == null) + { + return null; + } + + var rect = new Rect(framingRect); + //var cameraParameters = _cameraController?.Camera?.GetParameters(); + //var width = cameraParameters.PreviewSize.Width; + //var height = cameraParameters.PreviewSize.Height; + + + //rect.Left = rect.Left * width / _screenWidth; + //rect.Right = rect.Right * width / _screenHeight; + //rect.Top = rect.Top * height / _screenWidth; + //rect.Bottom = rect.Bottom * height / _screenHeight; + framingRectInPreview = rect; + Log.Debug(MobileBarcodeScanner.TAG, $"preview resolution: w={width}; h={height}; _screenWidth ={_screenWidth}; _screenHeight={_screenHeight}; framingRect={framingRect?.ToString()}"); + } + + Log.Debug(MobileBarcodeScanner.TAG, $"Calculated preview framing rect: {framingRectInPreview?.FlattenToString()}"); + return framingRectInPreview; + } + + /// + ///Scanning Improvement, VK 10/2018 + /// + public Rect GetFramingRect(int _width, int _height) + { + if (framingRect == null) + { + if (_cameraController == null) + { + return null; + } + + if (!(_width > 0 && _height > 0))//Valid_ScreenResolution) + { + // Called early, before init even finished + return null; + } + + int width = findDesiredDimensionInRange(_width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + int height = findDesiredDimensionInRange(_height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + + int leftOffset = (_width - width) / 2; + int topOffset = (_height - height) / 2; + framingRect = new Rect(leftOffset, topOffset, width, height); + Log.Debug(MobileBarcodeScanner.TAG, $"Calculated framing rect: {framingRect?.FlattenToString()}; screenWidth: {_screenWidth}; screenHeight: {_screenHeight}"); + } + + return framingRect; + } + + /// + ///Scanning Improvement, VK 10/2018 + /// + private void GetScreenResolution() + { + var screenResolution = new DisplayMetrics(); + try + { + if (manager == null) + { + Log.Debug(MobileBarcodeScanner.TAG, $"Window manager is null."); + } + + Display display = manager?.DefaultDisplay; + if (display == null) + { + Log.Debug(MobileBarcodeScanner.TAG, $"Default display is null."); + } + else + { + + display?.GetMetrics(screenResolution); + _screenWidth = screenResolution.WidthPixels; + _screenHeight = screenResolution.HeightPixels; + } + Log.Debug(MobileBarcodeScanner.TAG, $"Screen Display Rect- Width = {_screenWidth}; Height = {_screenHeight} "); + } + catch (Exception ex) + { + Log.Debug(MobileBarcodeScanner.TAG, "Error occured while getting screen resolution : " + ex.ToString()); + } + } + + /// + ///Scanning Improvement, VK 10/2018 + /// + private int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) + { + int dim = 5 * resolution / 8; // Target 5/8 of each dimension + if (dim < hardMin) + { + return hardMin; + } + if (dim > hardMax) + { + return hardMax; + } + return dim; + } } -} \ No newline at end of file +} diff --git a/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraController.cs b/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraController.cs index 61f7b8e3b..8bb5c8b5f 100644 --- a/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraController.cs +++ b/Source/ZXing.Net.Mobile.Android/CameraAccess/CameraController.cs @@ -1,4 +1,24 @@ -using System; +/* +* Copyright 2018 ZXing/Redth - https://github.com/Redth/ZXing.Net.Mobile +* +* 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. +* +* Edited by VK, Apacheta Corp 11/14/2018. +* http://www.apacheta.com/ +* +*/ + +using System; using System.Collections.Generic; using System.Linq; using Android.Content; @@ -9,17 +29,21 @@ using Android.Views; using ApxLabs.FastAndroidCamera; using Camera = Android.Hardware.Camera; +using Android.Util; namespace ZXing.Mobile.CameraAccess { public class CameraController { + private const float MAX_EXPOSURE_COMPENSATION = 1.5f; + private const float MIN_EXPOSURE_COMPENSATION = 0.0f; + private const int AREA_PER_1000 = 300; private readonly Context _context; private readonly ISurfaceHolder _holder; private readonly SurfaceView _surfaceView; private readonly CameraEventsListener _cameraEventListener; private int _cameraId; - IScannerSessionHost _scannerHost; + IScannerSessionHost _scannerHost; public CameraController(SurfaceView surfaceView, CameraEventsListener cameraEventListener, IScannerSessionHost scannerHost) { @@ -27,7 +51,7 @@ public CameraController(SurfaceView surfaceView, CameraEventsListener cameraEven _holder = surfaceView.Holder; _surfaceView = surfaceView; _cameraEventListener = cameraEventListener; - _scannerHost = scannerHost; + _scannerHost = scannerHost; } public Camera Camera { get; private set; } @@ -69,30 +93,31 @@ public void SetupCamera() try { Camera.SetPreviewDisplay(_holder); - + var previewParameters = Camera.GetParameters(); var previewSize = previewParameters.PreviewSize; var bitsPerPixel = ImageFormat.GetBitsPerPixel(previewParameters.PreviewFormat); - int bufferSize = (previewSize.Width * previewSize.Height * bitsPerPixel) / 8; - const int NUM_PREVIEW_BUFFERS = 5; - for (uint i = 0; i < NUM_PREVIEW_BUFFERS; ++i) - { - using (var buffer = new FastJavaByteArray(bufferSize)) - Camera.AddCallbackBuffer(buffer); - } - + Log.Debug(MobileBarcodeScanner.TAG, $"bitsPerPixed={bitsPerPixel}; bufferSize={bufferSize}"); + const int NUM_PREVIEW_BUFFERS = 5; + for (uint i = 0; i < NUM_PREVIEW_BUFFERS; ++i) + { + using (var buffer = new FastJavaByteArray(bufferSize)) + Camera.AddCallbackBuffer(buffer); + } - Camera.StartPreview(); + + + Camera.StartPreview(); Camera.SetNonMarshalingPreviewCallback(_cameraEventListener); } catch (Exception ex) { - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, ex.ToString()); + Log.Debug(MobileBarcodeScanner.TAG, ex.ToString()); return; } finally @@ -112,6 +137,20 @@ public void AutoFocus() AutoFocus(0, 0, false); } + + /// + ///Scanning Improvement, VK 10/2018 + /// + public void LowLightMode(bool on) + { + var parameters = Camera?.GetParameters(); + if (parameters != null) + { + SetBestExposure(parameters, on); + Camera.SetParameters(parameters); + } + } + public void AutoFocus(int x, int y) { // The bounds for focus areas are actually -1000 to 1000 @@ -150,7 +189,7 @@ public void ShutdownCamera() } catch (Exception e) { - Android.Util.Log.Error(MobileBarcodeScanner.TAG, e.ToString()); + Log.Error(MobileBarcodeScanner.TAG, e.ToString()); } PerformanceCounter.Stop(perf, "Shutdown camera took {0}ms"); @@ -173,7 +212,7 @@ private void OpenCamera() var whichCamera = CameraFacing.Back; - if (_scannerHost.ScanningOptions.UseFrontCameraIfAvailable.HasValue && + if (_scannerHost.ScanningOptions.UseFrontCameraIfAvailable.HasValue && _scannerHost.ScanningOptions.UseFrontCameraIfAvailable.Value) whichCamera = CameraFacing.Front; @@ -182,7 +221,7 @@ private void OpenCamera() Camera.GetCameraInfo(i, camInfo); if (camInfo.Facing == whichCamera) { - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, + Log.Debug(MobileBarcodeScanner.TAG, "Found " + whichCamera + " Camera, opening..."); Camera = Camera.Open(i); _cameraId = i; @@ -193,7 +232,7 @@ private void OpenCamera() if (!found) { - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, + Log.Debug(MobileBarcodeScanner.TAG, "Finding " + whichCamera + " camera failed, opening camera 0..."); Camera = Camera.Open(0); _cameraId = 0; @@ -232,30 +271,69 @@ private void ApplyCameraSettings() var supportedFocusModes = parameters.SupportedFocusModes; if (_scannerHost.ScanningOptions.DisableAutofocus) parameters.FocusMode = Camera.Parameters.FocusModeFixed; + else if (supportedFocusModes.Contains(Camera.Parameters.FocusModeAuto)) + parameters.FocusMode = Camera.Parameters.FocusModeAuto; else if (Build.VERSION.SdkInt >= BuildVersionCodes.IceCreamSandwich && supportedFocusModes.Contains(Camera.Parameters.FocusModeContinuousPicture)) parameters.FocusMode = Camera.Parameters.FocusModeContinuousPicture; else if (supportedFocusModes.Contains(Camera.Parameters.FocusModeContinuousVideo)) parameters.FocusMode = Camera.Parameters.FocusModeContinuousVideo; - else if (supportedFocusModes.Contains(Camera.Parameters.FocusModeAuto)) - parameters.FocusMode = Camera.Parameters.FocusModeAuto; else if (supportedFocusModes.Contains(Camera.Parameters.FocusModeFixed)) parameters.FocusMode = Camera.Parameters.FocusModeFixed; + + Log.Debug(MobileBarcodeScanner.TAG, + $"FocusMode ={parameters.FocusMode}"); var selectedFps = parameters.SupportedPreviewFpsRange.FirstOrDefault(); if (selectedFps != null) { + Log.Debug(MobileBarcodeScanner.TAG, + $"Old Selected fps Min:{selectedFps[0]}, Max {selectedFps[1]}"); // This will make sure we select a range with the lowest minimum FPS // and maximum FPS which still has the lowest minimum // This should help maximize performance / support for hardware + //foreach (var fpsRange in parameters.SupportedPreviewFpsRange) + //{ + // if (fpsRange[0] < selectedFps[0] && fpsRange[1] >= selectedFps[1]) + // selectedFps = fpsRange; + //} + + /// + ///Scanning Improvement, VK 10/2018 + /// foreach (var fpsRange in parameters.SupportedPreviewFpsRange) { - if (fpsRange[0] <= selectedFps[0] && fpsRange[1] > selectedFps[1]) + if (fpsRange[1] > selectedFps[1] || fpsRange[1] == selectedFps[1] && fpsRange[0] < selectedFps[0]) selectedFps = fpsRange; } + + Log.Debug(MobileBarcodeScanner.TAG, + $" Setting Selected fps to Min:{selectedFps[0]}, Max {selectedFps[1]}"); + + /// + ///Scanning Improvement, Apacheta corporation 11/14/2018 + ///Changed the fps to use low and high. instead of low value and low value ie., selectedFps[0]. + ///Old code :: parameters.SetPreviewFpsRange(selectedFps[0], selectedFps[0]); + /// parameters.SetPreviewFpsRange(selectedFps[0], selectedFps[1]); } + if (_scannerHost.ScanningOptions.LowLightMode == true) + SetBestExposure(parameters, parameters.FlashMode != Camera.Parameters.FlashModeOn); + + /* + * Edited by VK - Apacheta corporation 11/14/2018 + * Improvements based on zxing android library + * - Setting default auto focus areas instead of single focus point + * - Setting Barcode scene mode if available for the device + * - Set metering to improve lighting/ exposure in the focused area (i.e., rectangular focus area in the center) + * - **** Imp ==> In UI project a layout should be created to mask other areas except the center rectangular area. + * To inform the user that app/ camera only scans the center rectangular area of the device. + */ + SetDefaultFocusArea(parameters); + SetBarcodeSceneMode(parameters); + SetMetering(parameters); + CameraResolution resolution = null; var supportedPreviewSizes = parameters.SupportedPreviewSizes; if (supportedPreviewSizes != null) @@ -302,7 +380,7 @@ private void ApplyCameraSettings() // Hopefully a resolution was selected at some point if (resolution != null) { - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, + Log.Debug(MobileBarcodeScanner.TAG, "Selected Resolution: " + resolution.Width + "x" + resolution.Height); parameters.SetPreviewSize(resolution.Width, resolution.Height); } @@ -312,15 +390,195 @@ private void ApplyCameraSettings() SetCameraDisplayOrientation(); } + /// + ///Scanning Improvement, VK, Apacheta Corp 11/14/2018. + ///This method sets the best expsure setting for the device. + /// + private void SetBestExposure(Camera.Parameters parameters, bool lowLight) + { + int minExposure = parameters.MinExposureCompensation; + int maxExposure = parameters.MaxExposureCompensation; + float step = parameters.ExposureCompensationStep; + if ((minExposure != 0 || maxExposure != 0) && step > 0.0f) + { + // Set low when light is on + float targetCompensation = MAX_EXPOSURE_COMPENSATION; + int compensationSteps = (int)(targetCompensation / step); + float actualCompensation = step * compensationSteps; + // Clamp value: + compensationSteps = lowLight ? Math.Max(Math.Min(compensationSteps, maxExposure), minExposure) : (int)MIN_EXPOSURE_COMPENSATION; + if (parameters.ExposureCompensation == compensationSteps) + { + Log.Debug(MobileBarcodeScanner.TAG, "Exposure compensation already set to " + compensationSteps + " / " + actualCompensation); + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Setting exposure compensation to " + compensationSteps + " / " + actualCompensation); + parameters.ExposureCompensation = compensationSteps; + } + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Camera does not support exposure compensation"); + } + } + + /// + ///Scanning Improvement, VK Apacheta Corp 11/14/2018. + ///This method sets the focus area setting for the device. center rectangle + /// + private void SetDefaultFocusArea(Camera.Parameters parameters) + { + if (parameters?.MaxNumFocusAreas > 0) + { + List middleArea = BuildMiddleArea(AREA_PER_1000); + Log.Debug(MobileBarcodeScanner.TAG, "Setting focus area to : " + middleArea.Select(f => f.Rect.FlattenToString()).Aggregate((first, next) => first + "; " + next)); + parameters.FocusAreas = middleArea; + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Device does not support focus areas"); + } + } + + + /// + ///Scanning Improvement, VK Apacheta Corp 11/14/2018. + ///This method sets the meter setting for the device. center rectangle + /// + private void SetMetering(Camera.Parameters parameters) + { + if (parameters?.MaxNumMeteringAreas > 0) + { + List middleArea = BuildMiddleArea(AREA_PER_1000); + Log.Debug(MobileBarcodeScanner.TAG, "Setting metering areas: " + middleArea.Select(f => f.Rect.FlattenToString()).Aggregate((first, next) => first + "; " + next)); + parameters.MeteringAreas = middleArea; + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Device does not support metering areas"); + } + } + + /// + ///Scanning Improvement, VK Apacheta Corp 11/14/2018. + ///This method builds the middle are i.e., center rectangle for the device + /// + private List BuildMiddleArea(int areaPer1000) + { + return new List() + { + new Camera.Area(new Rect(-areaPer1000, -areaPer1000, areaPer1000, areaPer1000), 1) + }; + } + + + /// + ///Scanning Improvement, VK Apacheta Corp 11/14/2018. + ///This method sets the Video stabilization setting for the device. + ///This method is not used in the code for now. + /// + private void SetVideoStabilization(Camera.Parameters parameters) + { + if (parameters.IsVideoStabilizationSupported) + { + if (parameters.VideoStabilization) + { + Log.Debug(MobileBarcodeScanner.TAG, "Video stabilization already enabled"); + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Enabling video stabilization..."); + parameters.VideoStabilization = true; + } + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "This device does not support video stabilization"); + } + } + + /// + ///Scanning Improvement, VK Apacheta Corp 11/14/2018. + ///This method sets the scene to barcode for the device. If the device supports scenes. + /// + private void SetBarcodeSceneMode(Camera.Parameters parameters) + { + if (parameters.SceneMode == Camera.Parameters.SceneModeBarcode) + { + Log.Debug(MobileBarcodeScanner.TAG, "Barcode scene mode already set"); + return; + } + var supportedSceneModes = parameters.SupportedSceneModes; + if (supportedSceneModes?.Contains(Camera.Parameters.SceneModeBarcode) == true) + { + Log.Debug(MobileBarcodeScanner.TAG, $"Previous SceneMode={parameters.SceneMode}"); + parameters.SceneMode = Camera.Parameters.SceneModeBarcode; + Log.Debug(MobileBarcodeScanner.TAG, "Barcode scene mode is set"); + } + + } + + private void SetZoom(Camera.Parameters parameters, double targetZoomRatio) + { + if (parameters.IsZoomSupported) + { + var zoom = IndexOfClosestZoom(parameters, targetZoomRatio); + if (zoom == null) + { + return; + } + if (parameters.Zoom == zoom) + { + Log.Debug(MobileBarcodeScanner.TAG, "Zoom is already set to " + zoom); + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Setting zoom to " + zoom); + parameters.Zoom = (int)zoom; + } + } + else + { + Log.Debug(MobileBarcodeScanner.TAG, "Zoom is not supported"); + } + } + + private int? IndexOfClosestZoom(Camera.Parameters parameters, double targetZoomRatio) + { + var ratios = parameters.ZoomRatios.ToList(); + Log.Debug(MobileBarcodeScanner.TAG, "Zoom ratios: " + ratios); + int maxZoom = parameters.MaxZoom; + if (ratios == null || ratios.Count == 0 || ratios.Count != maxZoom + 1) + { + Log.Debug(MobileBarcodeScanner.TAG, "Invalid zoom ratios!"); + return null; + } + double target100 = 100.0 * targetZoomRatio; + double smallestDiff = Double.PositiveInfinity; + int closestIndex = 0; + for (int i = 0; i < ratios.Count; i++) + { + double diff = Math.Abs(ratios[i]?.LongValue() ?? 0 - target100); + if (diff < smallestDiff) + { + smallestDiff = diff; + closestIndex = i; + } + } + Log.Debug(MobileBarcodeScanner.TAG, "Chose zoom ratio of " + ((ratios[closestIndex]?.LongValue() ?? 0) / 100.0)); + return closestIndex; + } + private void AutoFocus(int x, int y, bool useCoordinates) { if (Camera == null) return; - if (_scannerHost.ScanningOptions.DisableAutofocus) - { - Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "AutoFocus Disabled"); - return; - } + if (_scannerHost.ScanningOptions.DisableAutofocus) + { + Android.Util.Log.Debug(MobileBarcodeScanner.TAG, "AutoFocus Disabled"); + return; + } var cameraParams = Camera.GetParameters(); @@ -360,6 +618,7 @@ private void AutoFocus(int x, int y, bool useCoordinates) { new Camera.Area(new Rect(x, y, x + 20, y + 20), 1000) }; + Android.Util.Log.Debug(MobileBarcodeScanner.TAG, $"AutoFocus Area =(x={x}, y={y}, right = {x + 20}, bottom ={y + 20})"); Camera.SetParameters(cameraParams); } @@ -420,16 +679,16 @@ private int GetCameraDisplayOrientation() int correctedDegrees; if (info.Facing == CameraFacing.Front) { - correctedDegrees = (info.Orientation + degrees)%360; - correctedDegrees = (360 - correctedDegrees)%360; // compensate the mirror + correctedDegrees = (info.Orientation + degrees) % 360; + correctedDegrees = (360 - correctedDegrees) % 360; // compensate the mirror } else { // back-facing - correctedDegrees = (info.Orientation - degrees + 360)%360; + correctedDegrees = (info.Orientation - degrees + 360) % 360; } return correctedDegrees; } } -} \ No newline at end of file +}