Skip to content

Commit

Permalink
add progress feedback cause mrz take sometimes to much time
Browse files Browse the repository at this point in the history
  • Loading branch information
Verbruik committed Aug 9, 2024
1 parent 8e86435 commit 3f12eeb
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,6 @@ class BarcodeScannerController(private val activity: Activity, messenger: Binary

if (cameraParams?.get("scanner_type") == "mrz") {

Log.i("scanner_native", "#####################################################################################################")

val mrz: String? = MrzUtil.extractMRZ(visionText.textBlocks, mrzResult!!)

if (mrz != null) {
Expand Down Expand Up @@ -421,6 +419,8 @@ class BarcodeScannerController(private val activity: Activity, messenger: Binary

if (points?.isNotEmpty() == true) {

Log.i("native_scanner", "Extract MRZ done with result $mrz")

var x = points!![0].x
var y = points!![0].y
var width = points!![1].x - points!![0].x
Expand Down Expand Up @@ -456,8 +456,31 @@ class BarcodeScannerController(private val activity: Activity, messenger: Binary
imageProxy.image?.close()
imageProxy.close()

} else {

Log.i("native_scanner", "Extract MRZ done with result $mrz but image is not loaded yet")

eventSink?.success(mapOf(
"progress" to 90,
))

}

} else {

var progress = 5
if (mrzResult!!.size == 1) {
progress = 25
} else if (mrzResult!!.size == 2) {
progress = 75
}

Log.i("native_scanner", "Extract MRZ progress with current $mrzResult (progress $progress)")

eventSink?.success(mapOf(
"progress" to progress,
))

}

} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@ object MrzUtil {

mrzLines.forEach { line ->

val text = line.text.replace("«", "<").replace(" ", "").uppercase().trim()
var text = line.text.replace("«", "<").replace(" ", "").uppercase().trim()

if (text.matches("^[A-Z0-9<]*$".toRegex())) {

while (text.matches("<<<[KC]".toRegex())) {
text = text.replaceFirst("<<<[KC]".toRegex(), "<<<<")
}

if (((mrzResult.size < 3 && text.length == 30) || mrzResult.size < 2 && (text.length == 36 || text.length == 44))) {

if (!mrzResult.any { res -> res.substring(0, 20) == text.substring(0, 20) } && (mrzResult.isEmpty() || mrzResult.first().length == text.length)) {
Expand All @@ -78,8 +82,6 @@ object MrzUtil {
val map = mutableMapOf<Int, String>()
val missed = mutableListOf<Int>()

Log.i("native_scanner_res", "result : $mrzResult")

mrzResult.forEachIndexed{ index, it ->

if (mrzResult.size == 3) {
Expand Down Expand Up @@ -111,6 +113,7 @@ object MrzUtil {
}
}
} else {

var result = "${map[0]}\n${map[1]}"
if (mrzResult.size == 3) result += "\n${map[2]}"
return result
Expand Down
171 changes: 98 additions & 73 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ class MyDemoApp extends StatefulWidget {

class _MyDemoAppState extends State<MyDemoApp> {

int? progress;
bool withOverlay = true;
ScannerType scannerType = ScannerType.barcode;
ScannerType scannerType = ScannerType.mrz;

@override
Widget build(BuildContext context) {

return Scaffold(
appBar: AppBar(title: Text('Scanner ${scannerType.name} example'), actions: [
PopupMenuButton<CameraActions>(
Expand Down Expand Up @@ -117,83 +119,106 @@ class _MyDemoAppState extends State<MyDemoApp> {
],
),
]),
body: Builder(builder: (builderContext) {
Widget child = BarcodeScannerWidget(
scannerType: ScannerType.mrz,
onBarcodeDetected: (barcode) async {
await showDialog(
context: builderContext,
builder: (dialogContext) {
return Align(
alignment: Alignment.center,
child: Card(
body: Stack(
children: [
Positioned.fill(
child: Builder(builder: (builderContext) {
Widget child = BarcodeScannerWidget(
scannerType: ScannerType.mrz,
onBarcodeDetected: (barcode) async {
await showDialog(
context: builderContext,
builder: (dialogContext) {
return Align(
alignment: Alignment.center,
child: Card(
margin: const EdgeInsets.all(24),
child: Container(
padding: const EdgeInsets.all(16),
child: Column(mainAxisSize: MainAxisSize.min, children: [Text('barcode : ${barcode.value}'), Text('format : ${barcode.format.name}'), ElevatedButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Close dialog'))]))));
});
},
onTextDetected: (String text) async {
await showDialog(
context: builderContext,
builder: (dialogContext) {
return Align(
alignment: Alignment.center,
child: Card(
margin: const EdgeInsets.all(24),
child: Container(
padding: const EdgeInsets.all(16),
child: Column(mainAxisSize: MainAxisSize.min, children: [Text('barcode : ${barcode.value}'), Text('format : ${barcode.format.name}'), ElevatedButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Close dialog'))]))));
});
},
onTextDetected: (String text) async {
await showDialog(
context: builderContext,
builder: (dialogContext) {
return Align(
alignment: Alignment.center,
child: Card(
margin: const EdgeInsets.all(24),
child: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('text : \n$text'),
ElevatedButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Close dialog')),
],
),
),
),
);
},
);
},
onMrzDetected: (String text, Uint8List bytes) {
showDialog(
context: builderContext,
builder: (dialogContext) {
return Align(
alignment: Alignment.center,
child: Card(
margin: const EdgeInsets.all(24),
child: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(text),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Image.memory(bytes),
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('text : \n$text'),
ElevatedButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Close dialog')),
],
),
),
ElevatedButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Close dialog')),
],
),
),
),
);
},
);
},
onError: (dynamic error) {
debugPrint('$error');
},
);
),
);
},
);
},
onScanProgress: (int? progress) => setState(() => this.progress = progress),
onMrzDetected: (String text, Uint8List bytes) {
setState(() => progress = null);
showDialog(
context: builderContext,
builder: (dialogContext) {
return Align(
alignment: Alignment.center,
child: Card(
margin: const EdgeInsets.all(24),
child: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(text),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Image.memory(bytes),
),
ElevatedButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Close dialog')),
],
),
),
),
);
},
);
},
onError: (dynamic error) {
debugPrint('$error');
},
);

if (withOverlay) {
return buildWithOverlay(builderContext, child);
}

if (withOverlay) {
return buildWithOverlay(builderContext, child);
}
return child;

return child;
}));
}),
),
progress == null ? Container() : Positioned(
bottom: 0, left: 0, right: 0,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
color: Colors.white,
child: Row(
children: [
const Expanded(child: LinearProgressIndicator()),
const SizedBox(width: 16,),
Text('$progress %'),
],
),
),
),
],
));
}

buildWithOverlay(BuildContext builderContext, Widget scannerWidget) {
Expand Down
26 changes: 22 additions & 4 deletions lib/barcode_scanner.widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ class BarcodeScannerWidget extends StatefulWidget {
/// This function will be called when a barcode is detected.
final Function(Barcode barcode)? onBarcodeDetected;

/// This function will be called when a bloc of text or a MRZ is detected.
/// This function will be called when a bloc of text is detected.
final Function(String textResult)? onTextDetected;

/// This function will be called when a bloc MRZ is detected.
final Function(String mrz, Uint8List image)? onMrzDetected;

final Function(int? progress)? onScanProgress;

final Function(dynamic error) onError;

const BarcodeScannerWidget(
Expand All @@ -48,6 +51,7 @@ class BarcodeScannerWidget extends StatefulWidget {
this.onBarcodeDetected,
this.onTextDetected,
this.onMrzDetected,
this.onScanProgress,
required this.onError,
})
: assert(onBarcodeDetected != null || onTextDetected != null),
Expand Down Expand Up @@ -76,31 +80,45 @@ class _BarcodeScannerWidgetState extends State<BarcodeScannerWidget> {
};

eventSubscription = eventChannel.receiveBroadcastStream().listen((dynamic event) async {

if (widget.onScanProgress != null) {
widget.onScanProgress!(event["progress"] as int?);
}

if (widget.onBarcodeDetected != null && widget.scannerType == ScannerType.barcode) {

final format = BarcodeFormat.unserialize(event['format']);

if (format != null && event['barcode'] != null) {

await BarcodeScanner.stopScanner();

await widget.onBarcodeDetected!(Barcode(format: format, value: event['barcode'] as String));

if (!widget.stopScanOnBarcodeDetected) {
BarcodeScanner.startScanner();
}
} else {

} else if (event["progress"] == null) {
widget.onError(const FormatException('Barcode not found'));
}

} else if (widget.onTextDetected != null && widget.scannerType == ScannerType.text) {

if (event['text'] != null) {
await widget.onTextDetected!(event['text'] as String);
} else {
} else if (event["progress"] == null) {
widget.onError(const FormatException('Text not found'));
}

} else if (widget.onMrzDetected != null && widget.scannerType == ScannerType.mrz) {

if (event['mrz'] != null && event["img"] != null) {
await widget.onMrzDetected!(event['mrz'] as String, Uint8List.fromList(event["img"]));
} else {
} else if (event["progress"] == null) {
widget.onError(const FormatException('MRZ not found'));
}

}
}, onError: (dynamic error) {
widget.onError(error);
Expand Down

0 comments on commit 3f12eeb

Please sign in to comment.