casvanluijtelaar

fixed Boxfit.cover scanwindow alignment

... ... @@ -166,7 +166,7 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
result.success(answer)
} else {
val facing: Int = call.argument<Int>("facing") ?: 0
val ratio: Int? = call.argument<Int>("ratio")
val ratio: Int = call.argument<Int>("ratio") ?: 1
val torch: Boolean = call.argument<Boolean>("torch") ?: false
val formats: List<Int>? = call.argument<List<Int>>("formats")
... ... @@ -197,6 +197,7 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
result.error("textureEntry", "textureEntry is null", null)
return@addListener
}
// Preview
val surfaceProvider = Preview.SurfaceProvider { request ->
val texture = textureEntry!!.surfaceTexture()
... ... @@ -207,17 +208,15 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
// Build the preview to be shown on the Flutter texture
val previewBuilder = Preview.Builder()
if (ratio != null) {
previewBuilder.setTargetAspectRatio(ratio)
}
.setTargetAspectRatio(ratio)
preview = previewBuilder.build().apply { setSurfaceProvider(surfaceProvider) }
// Build the analyzer to be passed on to MLKit
val analysisBuilder = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setTargetResolution(preview!!.resolutionInfo?.resolution ?: Size(640, 480))
.setTargetAspectRatio(ratio)
if (ratio != null) { analysisBuilder.setTargetAspectRatio(ratio) }
val analysis = analysisBuilder.build().apply { setAnalyzer(executor, analyzer) }
// Select the correct camera
... ... @@ -228,7 +227,6 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
val analysisSize = analysis.resolutionInfo?.resolution ?: Size(0, 0)
val previewSize = preview!!.resolutionInfo?.resolution ?: Size(0, 0)
Log.i("LOG", "Analyzer: $analysisSize")
Log.i("LOG", "Preview: $previewSize")
... ...
... ... @@ -22,10 +22,16 @@ class _BarcodeScannerWithScanWindowState
}
Future<void> restart() async {
await controller.stop();
// await controller.stop();
await controller.start();
}
Future<void> onDetect(Barcode barcode, MobileScannerArguments? _) async {
setState(() => this.barcode = barcode.rawValue);
await Future.delayed(const Duration(seconds: 1));
setState(() => this.barcode = '');
}
@override
Widget build(BuildContext context) {
final scanWindow = Rect.fromCenter(
... ... @@ -41,12 +47,11 @@ class _BarcodeScannerWithScanWindowState
return Stack(
children: [
MobileScanner(
fit: BoxFit.contain,
fit: BoxFit.cover,
scanWindow: scanWindow,
controller: controller,
onDetect: (barcode, _) => setState(() {
this.barcode = barcode.rawValue;
}),
onDetect: onDetect,
allowDuplicates: true,
),
CustomPaint(
painter: ScannerOverlay(scanWindow),
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide applyBoxFit;
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:mobile_scanner/src/objects/barcode_utility.dart';
enum Ratio { ratio_4_3, ratio_16_9 }
... ... @@ -89,22 +90,17 @@ class _MobileScannerState extends State<MobileScanner>
Size textureSize,
Size widgetSize,
) {
/// map the texture size to get its new size after fitted to screen
final fittedSizes = applyBoxFit(fit, textureSize, widgetSize);
final fittedTextureSize = fittedSizes.destination;
final fittedTextureSize = applyBoxFit(fit, textureSize, widgetSize);
/// create a new rectangle that represents the texture on the screen
final minX = widgetSize.width / 2 - fittedTextureSize.width / 2;
final minY = widgetSize.height / 2 - fittedTextureSize.height / 2;
final width = fittedTextureSize.width;
final height = fittedTextureSize.height;
final textureWindow = Rect.fromLTWH(minX, minY, width, height);
final textureWindow = Offset(minX, minY) & fittedTextureSize;
/// create a new scan window and with only the area of the rect intersecting the texture window
final scanWindowInTexture = scanWindow.intersect(textureWindow);
/// update the scanWindow left and top to be relative to the texture not the widget
final newLeft = scanWindowInTexture.left - textureWindow.left;
final newTop = scanWindowInTexture.top - textureWindow.top;
... ... @@ -114,21 +110,12 @@ class _MobileScannerState extends State<MobileScanner>
/// new scanWindow that is adapted to the boxfit and relative to the texture
final windowInTexture = Rect.fromLTWH(newLeft, newTop, newWidth, newHeight);
print(windowInTexture);
/// get the scanWindow as a percentage of the texture
final percentageLeft = windowInTexture.left / fittedTextureSize.width;
final percentageTop = windowInTexture.top / fittedTextureSize.height;
final percentageRight = windowInTexture.right / fittedTextureSize.width;
final percentagebottom = windowInTexture.bottom / fittedTextureSize.height;
print(Rect.fromLTRB(
percentageLeft,
percentageTop,
percentageRight,
percentagebottom,
));
/// this rectangle can be send to native code and used to cut out a rectangle of the scan image
return Rect.fromLTRB(
percentageLeft,
... ...
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
... ... @@ -147,3 +149,79 @@ WiFi? toWiFi(Map? data) {
return null;
}
}
Size applyBoxFit(BoxFit fit, Size input, Size output) {
if (input.height <= 0.0 ||
input.width <= 0.0 ||
output.height <= 0.0 ||
output.width <= 0.0) {
return Size.zero;
}
Size destination;
final inputAspectRatio = input.width / input.height;
final outputAspectRatio = output.width / output.height;
switch (fit) {
case BoxFit.fill:
destination = output;
break;
case BoxFit.contain:
if (outputAspectRatio > inputAspectRatio) {
destination = Size(
input.width * output.height / input.height,
output.height,
);
} else {
destination = Size(
output.width,
input.height * output.width / input.width,
);
}
break;
case BoxFit.cover:
if (outputAspectRatio > inputAspectRatio) {
destination = Size(
output.width,
input.height * (output.width / input.width),
);
} else {
destination = Size(
input.width * (output.height / input.height),
output.height,
);
}
break;
case BoxFit.fitWidth:
destination = Size(
output.width,
input.height * (output.width / input.width),
);
break;
case BoxFit.fitHeight:
destination = Size(
input.width * (output.height / input.height),
output.height,
);
break;
case BoxFit.none:
destination = Size(
math.min(input.width, output.width),
math.min(input.height, output.height),
);
break;
case BoxFit.scaleDown:
destination = input;
if (destination.height > output.height) {
destination = Size(output.height * inputAspectRatio, output.height);
}
if (destination.width > output.width) {
destination = Size(output.width, output.width / inputAspectRatio);
}
break;
}
return destination;
}
... ...