Sander Roest

Fix coordinate space image and barcode.corners

... ... @@ -25,14 +25,10 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> {
final _mobileScannerController = MobileScannerController(
// The controller is started from the initState method.
autoStart: false,
// The know the placing of the barcodes, we need to know the size of the
// canvas they are placed on. Unfortunately the only known reliable way
// to get the dimensions, is to receive the complete image from the native
// side.
// https://github.com/juliansteenbakker/mobile_scanner/issues/1183
returnImage: true,
);
final orientation = DeviceOrientation.portraitUp;
// On this subscription the barcodes are received.
StreamSubscription<Object?>? _subscription;
... ... @@ -45,17 +41,8 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> {
@override
void initState() {
// Enable and disable scanning on the native side, so we don't get a stream
// of images when not needed. This also improves the behavior (false
// positives) when the user switches quickly to another barcode after
// enabling the scanner by releasing the finger.
_scannerEnabled.addListener(() {
_scannerEnabled.value
? _mobileScannerController.updateScanWindow(null)
: _mobileScannerController.updateScanWindow(Rect.zero);
});
// Lock to portrait (may not work on iPad with multitasking).
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
SystemChrome.setPreferredOrientations([orientation]);
// Get a stream subscription and listen to received barcodes.
_subscription = _mobileScannerController.barcodes.listen(_handleBarcodes);
super.initState();
... ... @@ -83,7 +70,7 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> {
if (!_scannerEnabled.value || _validBarcodeFound) {
return;
}
final barcode = findBarcodeAtCenter(barcodeCapture);
final barcode = findBarcodeAtCenter(barcodeCapture, orientation);
if (barcode != null) {
_validBarcodeFound = true;
Navigator.of(context).pop(barcode);
... ...
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:mobile_scanner_example/picklist/classes/fix_coordinate_space.dart';
/// This function finds the barcode that touches the center of the
/// image. If no barcode is found that touches the center, null is returned.
/// See [_BarcodeScannerPicklistState] and the returnImage option for more info.
///
/// https://github.com/juliansteenbakker/mobile_scanner/issues/1183
Barcode? findBarcodeAtCenter(BarcodeCapture barcodeCapture) {
final imageSize = barcodeCapture.size;
Barcode? findBarcodeAtCenter(
BarcodeCapture barcodeCapture,
DeviceOrientation orientation,
) {
final imageSize = fixPortraitLandscape(barcodeCapture.size, orientation);
for (final barcode in barcodeCapture.barcodes) {
final corners = fixCorners(barcode.corners);
if (_isPolygonTouchingTheCenter(
imageSize: imageSize,
polygon: barcode.corners,
polygon: corners,
)) {
return barcode;
}
... ...
import 'package:flutter/services.dart';
Size fixPortraitLandscape(
Size imageSize,
DeviceOrientation orientation,
) {
switch (orientation) {
case DeviceOrientation.portraitUp:
case DeviceOrientation.portraitDown:
return Size(imageSize.shortestSide, imageSize.longestSide);
case DeviceOrientation.landscapeLeft:
case DeviceOrientation.landscapeRight:
return Size(imageSize.longestSide, imageSize.shortestSide);
}
}
List<Offset> fixCorners(List<Offset> corners) {
// Clone the original list to avoid side-effects
final sorted = List<Offset>.from(corners);
sorted.sort((a, b) {
// Prioritize y-axis (dy), and within that, the x-axis (dx)
int compare = a.dy.compareTo(b.dy);
if (compare == 0) {
compare = a.dx.compareTo(b.dx);
}
return compare;
});
final topLeft = sorted.first; // smallest x, smallest y
final topRight = sorted[1]; // larger x, smaller y
final bottomLeft = sorted[2]; // smaller x, larger y
final bottomRight = sorted.last; // larger x, larger y
return [topLeft, topRight, bottomRight, bottomLeft];
}
... ...