Showing
6 changed files
with
156 additions
and
89 deletions
| @@ -3,12 +3,11 @@ package dev.steenbakker.mobile_scanner | @@ -3,12 +3,11 @@ package dev.steenbakker.mobile_scanner | ||
| 3 | import android.Manifest | 3 | import android.Manifest |
| 4 | import android.app.Activity | 4 | import android.app.Activity |
| 5 | import android.content.pm.PackageManager | 5 | import android.content.pm.PackageManager |
| 6 | -import android.graphics.Point | ||
| 7 | import android.graphics.Rect | 6 | import android.graphics.Rect |
| 8 | -import android.graphics.RectF | ||
| 9 | import android.net.Uri | 7 | import android.net.Uri |
| 10 | import android.os.Handler | 8 | import android.os.Handler |
| 11 | import android.os.Looper | 9 | import android.os.Looper |
| 10 | +import android.util.Log | ||
| 12 | import android.view.Surface | 11 | import android.view.Surface |
| 13 | import androidx.camera.core.* | 12 | import androidx.camera.core.* |
| 14 | import androidx.camera.lifecycle.ProcessCameraProvider | 13 | import androidx.camera.lifecycle.ProcessCameraProvider |
| @@ -17,19 +16,22 @@ import androidx.core.content.ContextCompat | @@ -17,19 +16,22 @@ import androidx.core.content.ContextCompat | ||
| 17 | import androidx.lifecycle.LifecycleOwner | 16 | import androidx.lifecycle.LifecycleOwner |
| 18 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions | 17 | import com.google.mlkit.vision.barcode.BarcodeScannerOptions |
| 19 | import com.google.mlkit.vision.barcode.BarcodeScanning | 18 | import com.google.mlkit.vision.barcode.BarcodeScanning |
| 19 | +import com.google.mlkit.vision.barcode.common.Barcode | ||
| 20 | import com.google.mlkit.vision.common.InputImage | 20 | import com.google.mlkit.vision.common.InputImage |
| 21 | import dev.steenbakker.mobile_scanner.objects.DetectionSpeed | 21 | import dev.steenbakker.mobile_scanner.objects.DetectionSpeed |
| 22 | import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters | 22 | import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters |
| 23 | import io.flutter.plugin.common.MethodChannel | 23 | import io.flutter.plugin.common.MethodChannel |
| 24 | import io.flutter.plugin.common.PluginRegistry | 24 | import io.flutter.plugin.common.PluginRegistry |
| 25 | import io.flutter.view.TextureRegistry | 25 | import io.flutter.view.TextureRegistry |
| 26 | +import kotlin.math.roundToInt | ||
| 27 | + | ||
| 28 | + | ||
| 26 | typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?) -> Unit | 29 | typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?) -> Unit |
| 27 | typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit | 30 | typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit |
| 28 | typealias MobileScannerErrorCallback = (error: String) -> Unit | 31 | typealias MobileScannerErrorCallback = (error: String) -> Unit |
| 29 | typealias TorchStateCallback = (state: Int) -> Unit | 32 | typealias TorchStateCallback = (state: Int) -> Unit |
| 30 | typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit | 33 | typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit |
| 31 | -import java.io.File | ||
| 32 | -import kotlin.math.roundToInt | 34 | + |
| 33 | 35 | ||
| 34 | class NoCamera : Exception() | 36 | class NoCamera : Exception() |
| 35 | class AlreadyStarted : Exception() | 37 | class AlreadyStarted : Exception() |
| @@ -58,7 +60,7 @@ class MobileScanner( | @@ -58,7 +60,7 @@ class MobileScanner( | ||
| 58 | private var pendingPermissionResult: MethodChannel.Result? = null | 60 | private var pendingPermissionResult: MethodChannel.Result? = null |
| 59 | private var preview: Preview? = null | 61 | private var preview: Preview? = null |
| 60 | private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null | 62 | private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null |
| 61 | - private var scanWindow: List<Float>? = null; | 63 | + var scanWindow: List<Float>? = null |
| 62 | 64 | ||
| 63 | private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES | 65 | private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES |
| 64 | private var detectionTimeout: Long = 250 | 66 | private var detectionTimeout: Long = 250 |
| @@ -144,13 +146,19 @@ class MobileScanner( | @@ -144,13 +146,19 @@ class MobileScanner( | ||
| 144 | lastScanned = newScannedBarcodes | 146 | lastScanned = newScannedBarcodes |
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | - val barcodeMap = barcodes.map { barcode -> barcode.data } | 149 | + val barcodeMap: MutableList<Map<String, Any?>> = mutableListOf() |
| 148 | 150 | ||
| 149 | - if(scanWindow != null) { | ||
| 150 | - val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy) | ||
| 151 | - if(!match) continue | 151 | + for ( barcode in barcodes) { |
| 152 | + if(scanWindow != null) { | ||
| 153 | + val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy) | ||
| 154 | + if(!match) continue | ||
| 155 | + } | ||
| 156 | + Log.d("mobile_scanner: ", "width: ${inputImage.width}, height: ${inputImage.height}") | ||
| 157 | + barcodeMap.add(barcode.data) | ||
| 152 | } | 158 | } |
| 159 | + | ||
| 153 | if (barcodeMap.isNotEmpty()) { | 160 | if (barcodeMap.isNotEmpty()) { |
| 161 | + | ||
| 154 | mobileScannerCallback( | 162 | mobileScannerCallback( |
| 155 | barcodeMap, | 163 | barcodeMap, |
| 156 | if (returnImage) mediaImage.toByteArray() else null | 164 | if (returnImage) mediaImage.toByteArray() else null |
| @@ -172,18 +180,13 @@ class MobileScanner( | @@ -172,18 +180,13 @@ class MobileScanner( | ||
| 172 | } | 180 | } |
| 173 | } | 181 | } |
| 174 | 182 | ||
| 175 | - private fun updateScanWindow(call: MethodCall) { | ||
| 176 | - scanWindow = call.argument<List<Float>>("rect") | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | // scales the scanWindow to the provided inputImage and checks if that scaled | 183 | // scales the scanWindow to the provided inputImage and checks if that scaled |
| 180 | // scanWindow contains the barcode | 184 | // scanWindow contains the barcode |
| 181 | private fun isbarCodeInScanWindow(scanWindow: List<Float>, barcode: Barcode, inputImage: ImageProxy): Boolean { | 185 | private fun isbarCodeInScanWindow(scanWindow: List<Float>, barcode: Barcode, inputImage: ImageProxy): Boolean { |
| 182 | - val barcodeBoundingBox = barcode.getBoundingBox() | ||
| 183 | - if(barcodeBoundingBox == null) return false | 186 | + val barcodeBoundingBox = barcode.boundingBox ?: return false |
| 184 | 187 | ||
| 185 | - val imageWidth = inputImage.getHeight(); | ||
| 186 | - val imageHeight = inputImage.getWidth(); | 188 | + val imageWidth = inputImage.height |
| 189 | + val imageHeight = inputImage.width | ||
| 187 | 190 | ||
| 188 | val left = (scanWindow[0] * imageWidth).roundToInt() | 191 | val left = (scanWindow[0] * imageWidth).roundToInt() |
| 189 | val top = (scanWindow[1] * imageHeight).roundToInt() | 192 | val top = (scanWindow[1] * imageHeight).roundToInt() |
| @@ -192,9 +195,11 @@ class MobileScanner( | @@ -192,9 +195,11 @@ class MobileScanner( | ||
| 192 | 195 | ||
| 193 | val scaledScanWindow = Rect(left, top, right, bottom) | 196 | val scaledScanWindow = Rect(left, top, right, bottom) |
| 194 | 197 | ||
| 195 | - print("scanWindow: ") | ||
| 196 | - println(scaledScanWindow) | ||
| 197 | - return scaledScanWindow.contains(barcodeBoundingBox) | 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) | ||
| 198 | } | 203 | } |
| 199 | 204 | ||
| 200 | /** | 205 | /** |
| @@ -279,7 +284,7 @@ class MobileScanner( | @@ -279,7 +284,7 @@ class MobileScanner( | ||
| 279 | // Enable torch if provided | 284 | // Enable torch if provided |
| 280 | camera!!.cameraControl.enableTorch(torch) | 285 | camera!!.cameraControl.enableTorch(torch) |
| 281 | 286 | ||
| 282 | - val resolution = preview!!.resolutionInfo!!.resolution | 287 | + val resolution = analysis.resolutionInfo!!.resolution |
| 283 | val portrait = camera!!.cameraInfo.sensorRotationDegrees % 180 == 0 | 288 | val portrait = camera!!.cameraInfo.sensorRotationDegrees % 180 == 0 |
| 284 | val width = resolution.width.toDouble() | 289 | val width = resolution.width.toDouble() |
| 285 | val height = resolution.height.toDouble() | 290 | val height = resolution.height.toDouble() |
| @@ -77,6 +77,7 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa | @@ -77,6 +77,7 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa | ||
| 77 | "torch" -> toggleTorch(call, result) | 77 | "torch" -> toggleTorch(call, result) |
| 78 | "stop" -> stop(result) | 78 | "stop" -> stop(result) |
| 79 | "analyzeImage" -> analyzeImage(call, result) | 79 | "analyzeImage" -> analyzeImage(call, result) |
| 80 | + "updateScanWindow" -> updateScanWindow(call) | ||
| 80 | else -> result.notImplemented() | 81 | else -> result.notImplemented() |
| 81 | } | 82 | } |
| 82 | } | 83 | } |
| @@ -215,4 +216,8 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa | @@ -215,4 +216,8 @@ class MobileScannerPlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCa | ||
| 215 | result.error("MobileScanner", "Called toggleTorch() while stopped!", null) | 216 | result.error("MobileScanner", "Called toggleTorch() while stopped!", null) |
| 216 | } | 217 | } |
| 217 | } | 218 | } |
| 219 | + | ||
| 220 | + private fun updateScanWindow(call: MethodCall) { | ||
| 221 | + handler!!.scanWindow = call.argument<List<Float>>("rect") | ||
| 222 | + } | ||
| 218 | } | 223 | } |
| @@ -357,7 +357,7 @@ | @@ -357,7 +357,7 @@ | ||
| 357 | CODE_SIGN_IDENTITY = "Apple Development"; | 357 | CODE_SIGN_IDENTITY = "Apple Development"; |
| 358 | CODE_SIGN_STYLE = Automatic; | 358 | CODE_SIGN_STYLE = Automatic; |
| 359 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | 359 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
| 360 | - DEVELOPMENT_TEAM = QAJQ4586J2; | 360 | + DEVELOPMENT_TEAM = 75Y2P2WSQQ; |
| 361 | ENABLE_BITCODE = NO; | 361 | ENABLE_BITCODE = NO; |
| 362 | INFOPLIST_FILE = Runner/Info.plist; | 362 | INFOPLIST_FILE = Runner/Info.plist; |
| 363 | LD_RUNPATH_SEARCH_PATHS = ( | 363 | LD_RUNPATH_SEARCH_PATHS = ( |
| @@ -489,7 +489,7 @@ | @@ -489,7 +489,7 @@ | ||
| 489 | CODE_SIGN_IDENTITY = "Apple Development"; | 489 | CODE_SIGN_IDENTITY = "Apple Development"; |
| 490 | CODE_SIGN_STYLE = Automatic; | 490 | CODE_SIGN_STYLE = Automatic; |
| 491 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | 491 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
| 492 | - DEVELOPMENT_TEAM = QAJQ4586J2; | 492 | + DEVELOPMENT_TEAM = 75Y2P2WSQQ; |
| 493 | ENABLE_BITCODE = NO; | 493 | ENABLE_BITCODE = NO; |
| 494 | INFOPLIST_FILE = Runner/Info.plist; | 494 | INFOPLIST_FILE = Runner/Info.plist; |
| 495 | LD_RUNPATH_SEARCH_PATHS = ( | 495 | LD_RUNPATH_SEARCH_PATHS = ( |
| @@ -515,7 +515,7 @@ | @@ -515,7 +515,7 @@ | ||
| 515 | CODE_SIGN_IDENTITY = "Apple Development"; | 515 | CODE_SIGN_IDENTITY = "Apple Development"; |
| 516 | CODE_SIGN_STYLE = Automatic; | 516 | CODE_SIGN_STYLE = Automatic; |
| 517 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | 517 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
| 518 | - DEVELOPMENT_TEAM = QAJQ4586J2; | 518 | + DEVELOPMENT_TEAM = 75Y2P2WSQQ; |
| 519 | ENABLE_BITCODE = NO; | 519 | ENABLE_BITCODE = NO; |
| 520 | INFOPLIST_FILE = Runner/Info.plist; | 520 | INFOPLIST_FILE = Runner/Info.plist; |
| 521 | LD_RUNPATH_SEARCH_PATHS = ( | 521 | LD_RUNPATH_SEARCH_PATHS = ( |
| @@ -11,35 +11,23 @@ class BarcodeScannerWithScanWindow extends StatefulWidget { | @@ -11,35 +11,23 @@ class BarcodeScannerWithScanWindow extends StatefulWidget { | ||
| 11 | 11 | ||
| 12 | class _BarcodeScannerWithScanWindowState | 12 | class _BarcodeScannerWithScanWindowState |
| 13 | extends State<BarcodeScannerWithScanWindow> { | 13 | extends State<BarcodeScannerWithScanWindow> { |
| 14 | - late MobileScannerController controller; | ||
| 15 | - String? barcode; | 14 | + late MobileScannerController controller = MobileScannerController(); |
| 15 | + Barcode? barcode; | ||
| 16 | 16 | ||
| 17 | - @override | ||
| 18 | - void initState() { | ||
| 19 | - super.initState(); | ||
| 20 | - controller = MobileScannerController(); | ||
| 21 | - restart(); | ||
| 22 | - } | ||
| 23 | - | ||
| 24 | - Future<void> restart() async { | ||
| 25 | - // await controller.stop(); | ||
| 26 | - await controller.start(); | 17 | + Future<void> onDetect(BarcodeCapture barcode) async { |
| 18 | + setState(() => this.barcode = barcode.barcodes.first); | ||
| 27 | } | 19 | } |
| 28 | 20 | ||
| 29 | - Future<void> onDetect(Barcode barcode, MobileScannerArguments? _) async { | ||
| 30 | - setState(() => this.barcode = barcode.rawValue); | ||
| 31 | - await Future.delayed(const Duration(seconds: 1)); | ||
| 32 | - setState(() => this.barcode = ''); | ||
| 33 | - } | 21 | + MobileScannerArguments? arguments; |
| 34 | 22 | ||
| 35 | @override | 23 | @override |
| 36 | Widget build(BuildContext context) { | 24 | Widget build(BuildContext context) { |
| 25 | + final query = MediaQuery.of(context); | ||
| 37 | final scanWindow = Rect.fromCenter( | 26 | final scanWindow = Rect.fromCenter( |
| 38 | center: MediaQuery.of(context).size.center(Offset.zero), | 27 | center: MediaQuery.of(context).size.center(Offset.zero), |
| 39 | width: 200, | 28 | width: 200, |
| 40 | height: 200, | 29 | height: 200, |
| 41 | ); | 30 | ); |
| 42 | - | ||
| 43 | return Scaffold( | 31 | return Scaffold( |
| 44 | backgroundColor: Colors.black, | 32 | backgroundColor: Colors.black, |
| 45 | body: Builder( | 33 | body: Builder( |
| @@ -51,9 +39,19 @@ class _BarcodeScannerWithScanWindowState | @@ -51,9 +39,19 @@ class _BarcodeScannerWithScanWindowState | ||
| 51 | fit: BoxFit.contain, | 39 | fit: BoxFit.contain, |
| 52 | scanWindow: scanWindow, | 40 | scanWindow: scanWindow, |
| 53 | controller: controller, | 41 | controller: controller, |
| 42 | + onScannerStarted: (arguments) { | ||
| 43 | + setState(() { | ||
| 44 | + this.arguments = arguments; | ||
| 45 | + }); | ||
| 46 | + }, | ||
| 54 | onDetect: onDetect, | 47 | onDetect: onDetect, |
| 55 | - allowDuplicates: true, | ||
| 56 | ), | 48 | ), |
| 49 | + if (barcode != null && | ||
| 50 | + barcode?.corners != null && | ||
| 51 | + arguments != null) | ||
| 52 | + CustomPaint( | ||
| 53 | + painter: BarcodeOverlay(barcode!, arguments!, BoxFit.contain, MediaQuery.of(context).devicePixelRatio), | ||
| 54 | + ), | ||
| 57 | CustomPaint( | 55 | CustomPaint( |
| 58 | painter: ScannerOverlay(scanWindow), | 56 | painter: ScannerOverlay(scanWindow), |
| 59 | ), | 57 | ), |
| @@ -72,7 +70,7 @@ class _BarcodeScannerWithScanWindowState | @@ -72,7 +70,7 @@ class _BarcodeScannerWithScanWindowState | ||
| 72 | height: 50, | 70 | height: 50, |
| 73 | child: FittedBox( | 71 | child: FittedBox( |
| 74 | child: Text( | 72 | child: Text( |
| 75 | - barcode ?? 'Scan something!', | 73 | + barcode?.displayValue ?? 'Scan something!', |
| 76 | overflow: TextOverflow.fade, | 74 | overflow: TextOverflow.fade, |
| 77 | style: Theme.of(context) | 75 | style: Theme.of(context) |
| 78 | .textTheme | 76 | .textTheme |
| @@ -122,3 +120,57 @@ class ScannerOverlay extends CustomPainter { | @@ -122,3 +120,57 @@ class ScannerOverlay extends CustomPainter { | ||
| 122 | return false; | 120 | return false; |
| 123 | } | 121 | } |
| 124 | } | 122 | } |
| 123 | + | ||
| 124 | +class BarcodeOverlay extends CustomPainter { | ||
| 125 | + BarcodeOverlay(this.barcode, this.arguments, this.boxFit, this.devicePixelRatio); | ||
| 126 | + | ||
| 127 | + final Barcode barcode; | ||
| 128 | + final MobileScannerArguments arguments; | ||
| 129 | + final BoxFit boxFit; | ||
| 130 | + final double devicePixelRatio; | ||
| 131 | + | ||
| 132 | + @override | ||
| 133 | + void paint(Canvas canvas, Size size) { | ||
| 134 | + 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); | ||
| 139 | + | ||
| 140 | + double verticalPadding = size.height - adjustedSize.destination.height; | ||
| 141 | + double horizontalPadding = size.width - adjustedSize.destination.width; | ||
| 142 | + if (verticalPadding > 0) { | ||
| 143 | + verticalPadding = verticalPadding / 2; | ||
| 144 | + } else { | ||
| 145 | + verticalPadding = 0; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + if (horizontalPadding > 0) { | ||
| 149 | + horizontalPadding = horizontalPadding / 2; | ||
| 150 | + } else { | ||
| 151 | + horizontalPadding = 0; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + final ratioWidth = arguments.size.width / adjustedSize.destination.width; | ||
| 155 | + final ratioHeight = arguments.size.height / adjustedSize.destination.height; | ||
| 156 | + | ||
| 157 | + final List<Offset> adjustedOffset = []; | ||
| 158 | + for (final offset in barcode.corners!) { | ||
| 159 | + adjustedOffset.add(Offset(offset.dx / ratioWidth + horizontalPadding, | ||
| 160 | + offset.dy / ratioHeight + verticalPadding)); | ||
| 161 | + } | ||
| 162 | + final cutoutPath = Path()..addPolygon(adjustedOffset, true); | ||
| 163 | + | ||
| 164 | + final backgroundPaint = Paint() | ||
| 165 | + ..color = Colors.red.withOpacity(0.3) | ||
| 166 | + ..style = PaintingStyle.fill | ||
| 167 | + ..blendMode = BlendMode.dstOut; | ||
| 168 | + | ||
| 169 | + canvas.drawPath(cutoutPath, backgroundPaint); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + @override | ||
| 173 | + bool shouldRepaint(covariant CustomPainter oldDelegate) { | ||
| 174 | + return false; | ||
| 175 | + } | ||
| 176 | +} |
| @@ -2,6 +2,7 @@ import 'dart:async'; | @@ -2,6 +2,7 @@ import 'dart:async'; | ||
| 2 | 2 | ||
| 3 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
| 4 | import 'package:flutter/material.dart' hide applyBoxFit; | 4 | import 'package:flutter/material.dart' hide applyBoxFit; |
| 5 | +import 'package:flutter/material.dart'; | ||
| 5 | import 'package:mobile_scanner/src/mobile_scanner_controller.dart'; | 6 | import 'package:mobile_scanner/src/mobile_scanner_controller.dart'; |
| 6 | import 'package:mobile_scanner/src/objects/barcode_capture.dart'; | 7 | import 'package:mobile_scanner/src/objects/barcode_capture.dart'; |
| 7 | import 'package:mobile_scanner/src/objects/mobile_scanner_arguments.dart'; | 8 | import 'package:mobile_scanner/src/objects/mobile_scanner_arguments.dart'; |
| @@ -143,9 +144,9 @@ class _MobileScannerState extends State<MobileScanner> | @@ -143,9 +144,9 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 143 | final fittedTextureSize = applyBoxFit(fit, textureSize, widgetSize); | 144 | final fittedTextureSize = applyBoxFit(fit, textureSize, widgetSize); |
| 144 | 145 | ||
| 145 | /// create a new rectangle that represents the texture on the screen | 146 | /// create a new rectangle that represents the texture on the screen |
| 146 | - final minX = widgetSize.width / 2 - fittedTextureSize.width / 2; | ||
| 147 | - final minY = widgetSize.height / 2 - fittedTextureSize.height / 2; | ||
| 148 | - final textureWindow = Offset(minX, minY) & fittedTextureSize; | 147 | + final minX = widgetSize.width / 2 - fittedTextureSize.destination.width / 2; |
| 148 | + final minY = widgetSize.height / 2 - fittedTextureSize.destination.height / 2; | ||
| 149 | + final textureWindow = Offset(minX, minY) & fittedTextureSize.destination; | ||
| 149 | 150 | ||
| 150 | /// create a new scan window and with only the area of the rect intersecting the texture window | 151 | /// create a new scan window and with only the area of the rect intersecting the texture window |
| 151 | final scanWindowInTexture = scanWindow.intersect(textureWindow); | 152 | final scanWindowInTexture = scanWindow.intersect(textureWindow); |
| @@ -160,10 +161,10 @@ class _MobileScannerState extends State<MobileScanner> | @@ -160,10 +161,10 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 160 | final windowInTexture = Rect.fromLTWH(newLeft, newTop, newWidth, newHeight); | 161 | final windowInTexture = Rect.fromLTWH(newLeft, newTop, newWidth, newHeight); |
| 161 | 162 | ||
| 162 | /// get the scanWindow as a percentage of the texture | 163 | /// get the scanWindow as a percentage of the texture |
| 163 | - final percentageLeft = windowInTexture.left / fittedTextureSize.width; | ||
| 164 | - final percentageTop = windowInTexture.top / fittedTextureSize.height; | ||
| 165 | - final percentageRight = windowInTexture.right / fittedTextureSize.width; | ||
| 166 | - final percentagebottom = windowInTexture.bottom / fittedTextureSize.height; | 164 | + final percentageLeft = windowInTexture.left / fittedTextureSize.destination.width; |
| 165 | + final percentageTop = windowInTexture.top / fittedTextureSize.destination.height; | ||
| 166 | + final percentageRight = windowInTexture.right / fittedTextureSize.destination.width; | ||
| 167 | + final percentagebottom = windowInTexture.bottom / fittedTextureSize.destination.height; | ||
| 167 | 168 | ||
| 168 | /// this rectangle can be send to native code and used to cut out a rectangle of the scan image | 169 | /// this rectangle can be send to native code and used to cut out a rectangle of the scan image |
| 169 | return Rect.fromLTRB( | 170 | return Rect.fromLTRB( |
| @@ -176,45 +177,49 @@ class _MobileScannerState extends State<MobileScanner> | @@ -176,45 +177,49 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 176 | 177 | ||
| 177 | @override | 178 | @override |
| 178 | Widget build(BuildContext context) { | 179 | Widget build(BuildContext context) { |
| 179 | - return ValueListenableBuilder<MobileScannerArguments?>( | ||
| 180 | - valueListenable: _controller.startArguments, | ||
| 181 | - builder: (context, value, child) { | ||
| 182 | - if (value == null) { | ||
| 183 | - return widget.placeholderBuilder?.call(context, child) ?? | ||
| 184 | - const ColoredBox(color: Colors.black); | ||
| 185 | - } | ||
| 186 | - | ||
| 187 | - if (widget.scanWindow != null) { | ||
| 188 | - final window = calculateScanWindowRelativeToTextureInPercentage( | ||
| 189 | - widget.fit, | ||
| 190 | - widget.scanWindow!, | ||
| 191 | - value.size, | ||
| 192 | - Size(constraints.maxWidth, constraints.maxHeight), | ||
| 193 | - ); | ||
| 194 | - controller.updateScanWindow(window); | ||
| 195 | - } | ||
| 196 | - | ||
| 197 | - | ||
| 198 | - return ClipRect( | ||
| 199 | - child: LayoutBuilder( | ||
| 200 | - builder: (_, constraints) { | ||
| 201 | - return SizedBox.fromSize( | ||
| 202 | - size: constraints.biggest, | ||
| 203 | - child: FittedBox( | ||
| 204 | - fit: widget.fit, | ||
| 205 | - child: SizedBox( | ||
| 206 | - width: value.size.width, | ||
| 207 | - height: value.size.height, | ||
| 208 | - child: kIsWeb | ||
| 209 | - ? HtmlElementView(viewType: value.webId!) | ||
| 210 | - : Texture(textureId: value.textureId!), | ||
| 211 | - ), | ||
| 212 | - ), | 180 | + return LayoutBuilder( |
| 181 | + builder: (context, constraints) { | ||
| 182 | + return ValueListenableBuilder<MobileScannerArguments?>( | ||
| 183 | + valueListenable: _controller.startArguments, | ||
| 184 | + builder: (context, value, child) { | ||
| 185 | + if (value == null) { | ||
| 186 | + return widget.placeholderBuilder?.call(context, child) ?? | ||
| 187 | + const ColoredBox(color: Colors.black); | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + if (widget.scanWindow != null) { | ||
| 191 | + final window = calculateScanWindowRelativeToTextureInPercentage( | ||
| 192 | + widget.fit, | ||
| 193 | + widget.scanWindow!, | ||
| 194 | + value.size, | ||
| 195 | + Size(constraints.maxWidth, constraints.maxHeight), | ||
| 213 | ); | 196 | ); |
| 214 | - }, | ||
| 215 | - ), | 197 | + _controller.updateScanWindow(window); |
| 198 | + } | ||
| 199 | + | ||
| 200 | + | ||
| 201 | + return ClipRect( | ||
| 202 | + child: LayoutBuilder( | ||
| 203 | + builder: (_, constraints) { | ||
| 204 | + return SizedBox.fromSize( | ||
| 205 | + size: constraints.biggest, | ||
| 206 | + child: FittedBox( | ||
| 207 | + fit: widget.fit, | ||
| 208 | + child: SizedBox( | ||
| 209 | + width: value.size.width, | ||
| 210 | + height: value.size.height, | ||
| 211 | + child: kIsWeb | ||
| 212 | + ? HtmlElementView(viewType: value.webId!) | ||
| 213 | + : Texture(textureId: value.textureId!), | ||
| 214 | + ), | ||
| 215 | + ), | ||
| 216 | + ); | ||
| 217 | + }, | ||
| 218 | + ), | ||
| 219 | + ); | ||
| 220 | + }, | ||
| 216 | ); | 221 | ); |
| 217 | - }, | 222 | + } |
| 218 | ); | 223 | ); |
| 219 | } | 224 | } |
| 220 | 225 |
| @@ -363,6 +363,6 @@ class MobileScannerController { | @@ -363,6 +363,6 @@ class MobileScannerController { | ||
| 363 | /// updates the native scanwindow | 363 | /// updates the native scanwindow |
| 364 | Future<void> updateScanWindow(Rect window) async { | 364 | Future<void> updateScanWindow(Rect window) async { |
| 365 | final data = [window.left, window.top, window.right, window.bottom]; | 365 | final data = [window.left, window.top, window.right, window.bottom]; |
| 366 | - await methodChannel.invokeMethod('updateScanWindow', {'rect': data}); | 366 | + await _methodChannel.invokeMethod('updateScanWindow', {'rect': data}); |
| 367 | } | 367 | } |
| 368 | } | 368 | } |
-
Please register or login to post a comment