Julian Steenbakker

imp: fix scan area on both ios and android

... ... @@ -26,7 +26,7 @@ import io.flutter.view.TextureRegistry
import kotlin.math.roundToInt
typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?) -> Unit
typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int?) -> Unit
typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit
typealias MobileScannerErrorCallback = (error: String) -> Unit
typealias TorchStateCallback = (state: Int) -> Unit
... ... @@ -151,17 +151,22 @@ class MobileScanner(
for ( barcode in barcodes) {
if(scanWindow != null) {
val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy)
if(!match) continue
if(!match) {
continue
} else {
barcodeMap.add(barcode.data)
}
} else {
barcodeMap.add(barcode.data)
}
Log.d("mobile_scanner: ", "width: ${inputImage.width}, height: ${inputImage.height}")
barcodeMap.add(barcode.data)
}
if (barcodeMap.isNotEmpty()) {
mobileScannerCallback(
barcodeMap,
if (returnImage) mediaImage.toByteArray() else null
if (returnImage) mediaImage.toByteArray() else null,
if (returnImage) mediaImage.width else null,
if (returnImage) mediaImage.height else null
)
}
}
... ... @@ -194,12 +199,7 @@ class MobileScanner(
val bottom = (scanWindow[3] * imageHeight).roundToInt()
val scaledScanWindow = Rect(left, top, right, bottom)
// Log.d("mobile_scanner: ", "scanWindow: $scaledScanWindow")
// Log.d("mobile_scanner: ", "bounding box: $barcodeBoundingBox")
// Log.d("mobile_scanner: ", "contains: ${scaledScanWindow.contains(barcodeBoundingBox)}")
return true
// return scaledScanWindow.contains(barcodeBoundingBox)
return scaledScanWindow.contains(barcodeBoundingBox)
}
/**
... ...
... ... @@ -25,12 +25,14 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa
private var analyzerResult: MethodChannel.Result? = null
private val callback: MobileScannerCallback = { barcodes: List<Map<String, Any?>>, image: ByteArray? ->
private val callback: MobileScannerCallback = { barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int? ->
if (image != null) {
barcodeHandler.publishEvent(mapOf(
"name" to "barcode",
"data" to barcodes,
"image" to image
"image" to image,
"width" to width!!.toDouble(),
"height" to height!!.toDouble()
))
} else {
barcodeHandler.publishEvent(mapOf(
... ...
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
... ... @@ -13,8 +15,10 @@ class _BarcodeScannerWithScanWindowState
extends State<BarcodeScannerWithScanWindow> {
late MobileScannerController controller = MobileScannerController();
Barcode? barcode;
BarcodeCapture? capture;
Future<void> onDetect(BarcodeCapture barcode) async {
capture = barcode;
setState(() => this.barcode = barcode.barcodes.first);
}
... ... @@ -50,7 +54,7 @@ class _BarcodeScannerWithScanWindowState
barcode?.corners != null &&
arguments != null)
CustomPaint(
painter: BarcodeOverlay(barcode!, arguments!, BoxFit.contain, MediaQuery.of(context).devicePixelRatio),
painter: BarcodeOverlay(barcode!, arguments!, BoxFit.contain, MediaQuery.of(context).devicePixelRatio, capture!),
),
CustomPaint(
painter: ScannerOverlay(scanWindow),
... ... @@ -122,8 +126,9 @@ class ScannerOverlay extends CustomPainter {
}
class BarcodeOverlay extends CustomPainter {
BarcodeOverlay(this.barcode, this.arguments, this.boxFit, this.devicePixelRatio);
BarcodeOverlay(this.barcode, this.arguments, this.boxFit, this.devicePixelRatio, this.capture);
final BarcodeCapture capture;
final Barcode barcode;
final MobileScannerArguments arguments;
final BoxFit boxFit;
... ... @@ -132,9 +137,6 @@ class BarcodeOverlay extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
if (barcode.corners == null) return;
// final realsize = Size(arguments.size.width * devicePixelRatio, arguments.size.height * devicePixelRatio);
final adjustedSize = applyBoxFit(boxFit, arguments.size, size);
double verticalPadding = size.height - adjustedSize.destination.height;
... ... @@ -151,8 +153,8 @@ class BarcodeOverlay extends CustomPainter {
horizontalPadding = 0;
}
final ratioWidth = arguments.size.width / adjustedSize.destination.width;
final ratioHeight = arguments.size.height / adjustedSize.destination.height;
final ratioWidth = (Platform.isIOS ? capture.width! : arguments.size.width)/ adjustedSize.destination.width;
final ratioHeight = (Platform.isIOS ? capture.height! : arguments.size.height) / adjustedSize.destination.height;
final List<Offset> adjustedOffset = [];
for (final offset in barcode.corners!) {
... ...
... ... @@ -12,16 +12,45 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
/// The handler sends all information via an event channel back to Flutter
private let barcodeHandler: BarcodeHandler
var scanWindow: CGRect?
static var scanWindow: [CGFloat]?
private static func isBarcodeInScanWindow(barcode: Barcode, imageSize: CGSize) -> Bool {
let scanwindow = SwiftMobileScannerPlugin.scanWindow!
let barcodeminX = barcode.cornerPoints![0].cgPointValue.x
let barcodeminY = barcode.cornerPoints![1].cgPointValue.y
let barcodewidth = barcode.cornerPoints![2].cgPointValue.x - barcodeminX
let barcodeheight = barcode.cornerPoints![3].cgPointValue.y - barcodeminY
let barcodeBox = CGRect(x: barcodeminX, y: barcodeminY, width: barcodewidth, height: barcodeheight)
let minX = scanwindow[0] * imageSize.width
let minY = scanwindow[1] * imageSize.height
let width = (scanwindow[2] * imageSize.width) - minX
let height = (scanwindow[3] * imageSize.height) - minY
let scaledWindow = CGRect(x: minX, y: minY, width: width, height: height)
return scaledWindow.contains(barcodeBox)
}
init(barcodeHandler: BarcodeHandler, registry: FlutterTextureRegistry) {
self.mobileScanner = MobileScanner(registry: registry, mobileScannerCallback: { barcodes, error, image in
if barcodes != nil {
let barcodesMap = barcodes!.map { barcode in
return barcode.data
let barcodesMap = barcodes!.compactMap { barcode in
if (SwiftMobileScannerPlugin.scanWindow != nil) {
if (SwiftMobileScannerPlugin.isBarcodeInScanWindow(barcode: barcode, imageSize: image.size)) {
return barcode.data
} else {
return nil
}
} else {
return barcode.data
}
}
if (!barcodesMap.isEmpty) {
barcodeHandler.publishEvent(["name": "barcode", "data": barcodesMap, "image": FlutterStandardTypedData(bytes: image.jpegData(compressionQuality: 0.8)!)])
barcodeHandler.publishEvent(["name": "barcode", "data": barcodesMap, "image": FlutterStandardTypedData(bytes: image.jpegData(compressionQuality: 0.8)!), "width": image.size.width, "height": image.size.height])
}
} else if (error != nil){
barcodeHandler.publishEvent(["name": "error", "data": error!.localizedDescription])
... ... @@ -53,7 +82,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
case "analyzeImage":
analyzeImage(call, result)
case "updateScanWindow":
updateScanWindow(call)
updateScanWindow(call, result)
default:
result(FlutterMethodNotImplemented)
}
... ... @@ -128,6 +157,28 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
result(nil)
}
/// Toggles the torch
func updateScanWindow(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
let scanWindowData: Array? = (call.arguments as? [String: Any])?["rect"] as? [CGFloat]
SwiftMobileScannerPlugin.scanWindow = scanWindowData
result(nil)
}
static func arrayToRect(scanWindowData: [CGFloat]?) -> CGRect? {
if (scanWindowData == nil) {
return nil
}
let minX = scanWindowData![0]
let minY = scanWindowData![1]
let width = scanWindowData![2] - minX
let height = scanWindowData![3] - minY
return CGRect(x: minX, y: minY, width: width, height: height)
}
/// Analyzes a single image
private func analyzeImage(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
let uiImage = UIImage(contentsOfFile: call.arguments as? String ?? "")
... ... @@ -141,12 +192,6 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin {
mobileScanner.analyzeImage(image: uiImage!, position: AVCaptureDevice.Position.back, callback: { [self] barcodes, error in
if error == nil && barcodes != nil {
for barcode in barcodes! {
if scanWindow != nil {
let match = isbarCodeInScanWindow(scanWindow!, barcode, buffer!.image)
if (!match) {
continue
}
}
let event: [String: Any?] = ["name": "barcode", "data": barcode.data]
barcodeHandler.publishEvent(event)
}
... ...
... ... @@ -323,6 +323,8 @@ class MobileScannerController {
BarcodeCapture(
barcodes: parsed,
image: event['image'] as Uint8List?,
width: event['width'] as double?,
height: event['height'] as double?,
),
);
break;
... ...
... ... @@ -12,8 +12,14 @@ class BarcodeCapture {
final Uint8List? image;
final double? width;
final double? height;
BarcodeCapture({
required this.barcodes,
this.image,
this.width,
this.height
});
}
... ...