Showing
6 changed files
with
89 additions
and
32 deletions
| @@ -26,7 +26,7 @@ import io.flutter.view.TextureRegistry | @@ -26,7 +26,7 @@ import io.flutter.view.TextureRegistry | ||
| 26 | import kotlin.math.roundToInt | 26 | import kotlin.math.roundToInt |
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | -typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?) -> Unit | 29 | +typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int?) -> Unit |
| 30 | typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit | 30 | typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit |
| 31 | typealias MobileScannerErrorCallback = (error: String) -> Unit | 31 | typealias MobileScannerErrorCallback = (error: String) -> Unit |
| 32 | typealias TorchStateCallback = (state: Int) -> Unit | 32 | typealias TorchStateCallback = (state: Int) -> Unit |
| @@ -151,17 +151,22 @@ class MobileScanner( | @@ -151,17 +151,22 @@ class MobileScanner( | ||
| 151 | for ( barcode in barcodes) { | 151 | for ( barcode in barcodes) { |
| 152 | if(scanWindow != null) { | 152 | if(scanWindow != null) { |
| 153 | val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy) | 153 | val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy) |
| 154 | - if(!match) continue | 154 | + if(!match) { |
| 155 | + continue | ||
| 156 | + } else { | ||
| 157 | + barcodeMap.add(barcode.data) | ||
| 158 | + } | ||
| 159 | + } else { | ||
| 160 | + barcodeMap.add(barcode.data) | ||
| 155 | } | 161 | } |
| 156 | - Log.d("mobile_scanner: ", "width: ${inputImage.width}, height: ${inputImage.height}") | ||
| 157 | - barcodeMap.add(barcode.data) | ||
| 158 | } | 162 | } |
| 159 | 163 | ||
| 160 | if (barcodeMap.isNotEmpty()) { | 164 | if (barcodeMap.isNotEmpty()) { |
| 161 | - | ||
| 162 | mobileScannerCallback( | 165 | mobileScannerCallback( |
| 163 | barcodeMap, | 166 | barcodeMap, |
| 164 | - if (returnImage) mediaImage.toByteArray() else null | 167 | + if (returnImage) mediaImage.toByteArray() else null, |
| 168 | + if (returnImage) mediaImage.width else null, | ||
| 169 | + if (returnImage) mediaImage.height else null | ||
| 165 | ) | 170 | ) |
| 166 | } | 171 | } |
| 167 | } | 172 | } |
| @@ -194,12 +199,7 @@ class MobileScanner( | @@ -194,12 +199,7 @@ class MobileScanner( | ||
| 194 | val bottom = (scanWindow[3] * imageHeight).roundToInt() | 199 | val bottom = (scanWindow[3] * imageHeight).roundToInt() |
| 195 | 200 | ||
| 196 | val scaledScanWindow = Rect(left, top, right, bottom) | 201 | val scaledScanWindow = Rect(left, top, right, bottom) |
| 197 | - | ||
| 198 | -// Log.d("mobile_scanner: ", "scanWindow: $scaledScanWindow") | ||
| 199 | -// Log.d("mobile_scanner: ", "bounding box: $barcodeBoundingBox") | ||
| 200 | -// Log.d("mobile_scanner: ", "contains: ${scaledScanWindow.contains(barcodeBoundingBox)}") | ||
| 201 | - return true | ||
| 202 | -// return scaledScanWindow.contains(barcodeBoundingBox) | 202 | + return scaledScanWindow.contains(barcodeBoundingBox) |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | /** | 205 | /** |
| @@ -25,12 +25,14 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa | @@ -25,12 +25,14 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa | ||
| 25 | 25 | ||
| 26 | private var analyzerResult: MethodChannel.Result? = null | 26 | private var analyzerResult: MethodChannel.Result? = null |
| 27 | 27 | ||
| 28 | - private val callback: MobileScannerCallback = { barcodes: List<Map<String, Any?>>, image: ByteArray? -> | 28 | + private val callback: MobileScannerCallback = { barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int? -> |
| 29 | if (image != null) { | 29 | if (image != null) { |
| 30 | barcodeHandler.publishEvent(mapOf( | 30 | barcodeHandler.publishEvent(mapOf( |
| 31 | "name" to "barcode", | 31 | "name" to "barcode", |
| 32 | "data" to barcodes, | 32 | "data" to barcodes, |
| 33 | - "image" to image | 33 | + "image" to image, |
| 34 | + "width" to width!!.toDouble(), | ||
| 35 | + "height" to height!!.toDouble() | ||
| 34 | )) | 36 | )) |
| 35 | } else { | 37 | } else { |
| 36 | barcodeHandler.publishEvent(mapOf( | 38 | barcodeHandler.publishEvent(mapOf( |
| 1 | +import 'dart:io'; | ||
| 2 | + | ||
| 1 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
| 2 | import 'package:mobile_scanner/mobile_scanner.dart'; | 4 | import 'package:mobile_scanner/mobile_scanner.dart'; |
| 3 | 5 | ||
| @@ -13,8 +15,10 @@ class _BarcodeScannerWithScanWindowState | @@ -13,8 +15,10 @@ class _BarcodeScannerWithScanWindowState | ||
| 13 | extends State<BarcodeScannerWithScanWindow> { | 15 | extends State<BarcodeScannerWithScanWindow> { |
| 14 | late MobileScannerController controller = MobileScannerController(); | 16 | late MobileScannerController controller = MobileScannerController(); |
| 15 | Barcode? barcode; | 17 | Barcode? barcode; |
| 18 | + BarcodeCapture? capture; | ||
| 16 | 19 | ||
| 17 | Future<void> onDetect(BarcodeCapture barcode) async { | 20 | Future<void> onDetect(BarcodeCapture barcode) async { |
| 21 | + capture = barcode; | ||
| 18 | setState(() => this.barcode = barcode.barcodes.first); | 22 | setState(() => this.barcode = barcode.barcodes.first); |
| 19 | } | 23 | } |
| 20 | 24 | ||
| @@ -50,7 +54,7 @@ class _BarcodeScannerWithScanWindowState | @@ -50,7 +54,7 @@ class _BarcodeScannerWithScanWindowState | ||
| 50 | barcode?.corners != null && | 54 | barcode?.corners != null && |
| 51 | arguments != null) | 55 | arguments != null) |
| 52 | CustomPaint( | 56 | CustomPaint( |
| 53 | - painter: BarcodeOverlay(barcode!, arguments!, BoxFit.contain, MediaQuery.of(context).devicePixelRatio), | 57 | + painter: BarcodeOverlay(barcode!, arguments!, BoxFit.contain, MediaQuery.of(context).devicePixelRatio, capture!), |
| 54 | ), | 58 | ), |
| 55 | CustomPaint( | 59 | CustomPaint( |
| 56 | painter: ScannerOverlay(scanWindow), | 60 | painter: ScannerOverlay(scanWindow), |
| @@ -122,8 +126,9 @@ class ScannerOverlay extends CustomPainter { | @@ -122,8 +126,9 @@ class ScannerOverlay extends CustomPainter { | ||
| 122 | } | 126 | } |
| 123 | 127 | ||
| 124 | class BarcodeOverlay extends CustomPainter { | 128 | class BarcodeOverlay extends CustomPainter { |
| 125 | - BarcodeOverlay(this.barcode, this.arguments, this.boxFit, this.devicePixelRatio); | 129 | + BarcodeOverlay(this.barcode, this.arguments, this.boxFit, this.devicePixelRatio, this.capture); |
| 126 | 130 | ||
| 131 | + final BarcodeCapture capture; | ||
| 127 | final Barcode barcode; | 132 | final Barcode barcode; |
| 128 | final MobileScannerArguments arguments; | 133 | final MobileScannerArguments arguments; |
| 129 | final BoxFit boxFit; | 134 | final BoxFit boxFit; |
| @@ -132,9 +137,6 @@ class BarcodeOverlay extends CustomPainter { | @@ -132,9 +137,6 @@ class BarcodeOverlay extends CustomPainter { | ||
| 132 | @override | 137 | @override |
| 133 | void paint(Canvas canvas, Size size) { | 138 | void paint(Canvas canvas, Size size) { |
| 134 | if (barcode.corners == null) return; | 139 | if (barcode.corners == null) return; |
| 135 | - | ||
| 136 | - // final realsize = Size(arguments.size.width * devicePixelRatio, arguments.size.height * devicePixelRatio); | ||
| 137 | - | ||
| 138 | final adjustedSize = applyBoxFit(boxFit, arguments.size, size); | 140 | final adjustedSize = applyBoxFit(boxFit, arguments.size, size); |
| 139 | 141 | ||
| 140 | double verticalPadding = size.height - adjustedSize.destination.height; | 142 | double verticalPadding = size.height - adjustedSize.destination.height; |
| @@ -151,8 +153,8 @@ class BarcodeOverlay extends CustomPainter { | @@ -151,8 +153,8 @@ class BarcodeOverlay extends CustomPainter { | ||
| 151 | horizontalPadding = 0; | 153 | horizontalPadding = 0; |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | - final ratioWidth = arguments.size.width / adjustedSize.destination.width; | ||
| 155 | - final ratioHeight = arguments.size.height / adjustedSize.destination.height; | 156 | + final ratioWidth = (Platform.isIOS ? capture.width! : arguments.size.width)/ adjustedSize.destination.width; |
| 157 | + final ratioHeight = (Platform.isIOS ? capture.height! : arguments.size.height) / adjustedSize.destination.height; | ||
| 156 | 158 | ||
| 157 | final List<Offset> adjustedOffset = []; | 159 | final List<Offset> adjustedOffset = []; |
| 158 | for (final offset in barcode.corners!) { | 160 | for (final offset in barcode.corners!) { |
| @@ -12,16 +12,45 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | @@ -12,16 +12,45 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | ||
| 12 | /// The handler sends all information via an event channel back to Flutter | 12 | /// The handler sends all information via an event channel back to Flutter |
| 13 | private let barcodeHandler: BarcodeHandler | 13 | private let barcodeHandler: BarcodeHandler |
| 14 | 14 | ||
| 15 | - var scanWindow: CGRect? | 15 | + static var scanWindow: [CGFloat]? |
| 16 | + | ||
| 17 | + private static func isBarcodeInScanWindow(barcode: Barcode, imageSize: CGSize) -> Bool { | ||
| 18 | + let scanwindow = SwiftMobileScannerPlugin.scanWindow! | ||
| 19 | + let barcodeminX = barcode.cornerPoints![0].cgPointValue.x | ||
| 20 | + let barcodeminY = barcode.cornerPoints![1].cgPointValue.y | ||
| 21 | + | ||
| 22 | + let barcodewidth = barcode.cornerPoints![2].cgPointValue.x - barcodeminX | ||
| 23 | + let barcodeheight = barcode.cornerPoints![3].cgPointValue.y - barcodeminY | ||
| 24 | + let barcodeBox = CGRect(x: barcodeminX, y: barcodeminY, width: barcodewidth, height: barcodeheight) | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + let minX = scanwindow[0] * imageSize.width | ||
| 28 | + let minY = scanwindow[1] * imageSize.height | ||
| 29 | + | ||
| 30 | + let width = (scanwindow[2] * imageSize.width) - minX | ||
| 31 | + let height = (scanwindow[3] * imageSize.height) - minY | ||
| 32 | + | ||
| 33 | + let scaledWindow = CGRect(x: minX, y: minY, width: width, height: height) | ||
| 34 | + | ||
| 35 | + return scaledWindow.contains(barcodeBox) | ||
| 36 | + } | ||
| 16 | 37 | ||
| 17 | init(barcodeHandler: BarcodeHandler, registry: FlutterTextureRegistry) { | 38 | init(barcodeHandler: BarcodeHandler, registry: FlutterTextureRegistry) { |
| 18 | self.mobileScanner = MobileScanner(registry: registry, mobileScannerCallback: { barcodes, error, image in | 39 | self.mobileScanner = MobileScanner(registry: registry, mobileScannerCallback: { barcodes, error, image in |
| 19 | if barcodes != nil { | 40 | if barcodes != nil { |
| 20 | - let barcodesMap = barcodes!.map { barcode in | ||
| 21 | - return barcode.data | 41 | + let barcodesMap = barcodes!.compactMap { barcode in |
| 42 | + if (SwiftMobileScannerPlugin.scanWindow != nil) { | ||
| 43 | + if (SwiftMobileScannerPlugin.isBarcodeInScanWindow(barcode: barcode, imageSize: image.size)) { | ||
| 44 | + return barcode.data | ||
| 45 | + } else { | ||
| 46 | + return nil | ||
| 47 | + } | ||
| 48 | + } else { | ||
| 49 | + return barcode.data | ||
| 50 | + } | ||
| 22 | } | 51 | } |
| 23 | if (!barcodesMap.isEmpty) { | 52 | if (!barcodesMap.isEmpty) { |
| 24 | - barcodeHandler.publishEvent(["name": "barcode", "data": barcodesMap, "image": FlutterStandardTypedData(bytes: image.jpegData(compressionQuality: 0.8)!)]) | 53 | + barcodeHandler.publishEvent(["name": "barcode", "data": barcodesMap, "image": FlutterStandardTypedData(bytes: image.jpegData(compressionQuality: 0.8)!), "width": image.size.width, "height": image.size.height]) |
| 25 | } | 54 | } |
| 26 | } else if (error != nil){ | 55 | } else if (error != nil){ |
| 27 | barcodeHandler.publishEvent(["name": "error", "data": error!.localizedDescription]) | 56 | barcodeHandler.publishEvent(["name": "error", "data": error!.localizedDescription]) |
| @@ -53,7 +82,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | @@ -53,7 +82,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | ||
| 53 | case "analyzeImage": | 82 | case "analyzeImage": |
| 54 | analyzeImage(call, result) | 83 | analyzeImage(call, result) |
| 55 | case "updateScanWindow": | 84 | case "updateScanWindow": |
| 56 | - updateScanWindow(call) | 85 | + updateScanWindow(call, result) |
| 57 | default: | 86 | default: |
| 58 | result(FlutterMethodNotImplemented) | 87 | result(FlutterMethodNotImplemented) |
| 59 | } | 88 | } |
| @@ -128,6 +157,28 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | @@ -128,6 +157,28 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | ||
| 128 | result(nil) | 157 | result(nil) |
| 129 | } | 158 | } |
| 130 | 159 | ||
| 160 | + /// Toggles the torch | ||
| 161 | + func updateScanWindow(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | ||
| 162 | + let scanWindowData: Array? = (call.arguments as? [String: Any])?["rect"] as? [CGFloat] | ||
| 163 | + SwiftMobileScannerPlugin.scanWindow = scanWindowData | ||
| 164 | + | ||
| 165 | + result(nil) | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + static func arrayToRect(scanWindowData: [CGFloat]?) -> CGRect? { | ||
| 169 | + if (scanWindowData == nil) { | ||
| 170 | + return nil | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + let minX = scanWindowData![0] | ||
| 174 | + let minY = scanWindowData![1] | ||
| 175 | + | ||
| 176 | + let width = scanWindowData![2] - minX | ||
| 177 | + let height = scanWindowData![3] - minY | ||
| 178 | + | ||
| 179 | + return CGRect(x: minX, y: minY, width: width, height: height) | ||
| 180 | + } | ||
| 181 | + | ||
| 131 | /// Analyzes a single image | 182 | /// Analyzes a single image |
| 132 | private func analyzeImage(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { | 183 | private func analyzeImage(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { |
| 133 | let uiImage = UIImage(contentsOfFile: call.arguments as? String ?? "") | 184 | let uiImage = UIImage(contentsOfFile: call.arguments as? String ?? "") |
| @@ -141,12 +192,6 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | @@ -141,12 +192,6 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin { | ||
| 141 | mobileScanner.analyzeImage(image: uiImage!, position: AVCaptureDevice.Position.back, callback: { [self] barcodes, error in | 192 | mobileScanner.analyzeImage(image: uiImage!, position: AVCaptureDevice.Position.back, callback: { [self] barcodes, error in |
| 142 | if error == nil && barcodes != nil { | 193 | if error == nil && barcodes != nil { |
| 143 | for barcode in barcodes! { | 194 | for barcode in barcodes! { |
| 144 | - if scanWindow != nil { | ||
| 145 | - let match = isbarCodeInScanWindow(scanWindow!, barcode, buffer!.image) | ||
| 146 | - if (!match) { | ||
| 147 | - continue | ||
| 148 | - } | ||
| 149 | - } | ||
| 150 | let event: [String: Any?] = ["name": "barcode", "data": barcode.data] | 195 | let event: [String: Any?] = ["name": "barcode", "data": barcode.data] |
| 151 | barcodeHandler.publishEvent(event) | 196 | barcodeHandler.publishEvent(event) |
| 152 | } | 197 | } |
| @@ -323,6 +323,8 @@ class MobileScannerController { | @@ -323,6 +323,8 @@ class MobileScannerController { | ||
| 323 | BarcodeCapture( | 323 | BarcodeCapture( |
| 324 | barcodes: parsed, | 324 | barcodes: parsed, |
| 325 | image: event['image'] as Uint8List?, | 325 | image: event['image'] as Uint8List?, |
| 326 | + width: event['width'] as double?, | ||
| 327 | + height: event['height'] as double?, | ||
| 326 | ), | 328 | ), |
| 327 | ); | 329 | ); |
| 328 | break; | 330 | break; |
| @@ -12,8 +12,14 @@ class BarcodeCapture { | @@ -12,8 +12,14 @@ class BarcodeCapture { | ||
| 12 | 12 | ||
| 13 | final Uint8List? image; | 13 | final Uint8List? image; |
| 14 | 14 | ||
| 15 | + final double? width; | ||
| 16 | + | ||
| 17 | + final double? height; | ||
| 18 | + | ||
| 15 | BarcodeCapture({ | 19 | BarcodeCapture({ |
| 16 | required this.barcodes, | 20 | required this.barcodes, |
| 17 | this.image, | 21 | this.image, |
| 22 | + this.width, | ||
| 23 | + this.height | ||
| 18 | }); | 24 | }); |
| 19 | } | 25 | } |
-
Please register or login to post a comment