From 6a4f75925c1fa25ae8e5815e2f1401eb13e5b041 Mon Sep 17 00:00:00 2001 From: Khoren Markosyan Date: Sun, 5 Jun 2022 23:39:42 +0400 Subject: [PATCH] added processCameraImage function --- lib/flutter_zxing.dart | 35 ++++++++++++++++++++++++++++++++++- lib/isolate_utils.dart | 10 +++++----- lib/reader_widget.dart | 42 ++++++++---------------------------------- 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/lib/flutter_zxing.dart b/lib/flutter_zxing.dart index 850e5b1..bcc710f 100644 --- a/lib/flutter_zxing.dart +++ b/lib/flutter_zxing.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:io'; +import 'dart:isolate'; import 'dart:typed_data'; import 'package:camera/camera.dart'; @@ -10,6 +11,7 @@ import 'package:flutter/services.dart'; import 'package:image/image.dart' as imglib; import 'generated_bindings.dart'; +import 'isolate_utils.dart'; export 'generated_bindings.dart'; export 'reader_widget.dart'; @@ -17,6 +19,7 @@ export 'writer_widget.dart'; export 'image_converter.dart'; export 'scanner_overlay.dart'; +/// The main class for reading barcodes from images or camera. class FlutterZxing { static const MethodChannel _channel = MethodChannel('flutter_zxing'); @@ -27,6 +30,8 @@ class FlutterZxing { static final bindings = GeneratedBindings(dylib); + static IsolateUtils? isolateUtils; + static bool logEnabled = false; static void setLogEnabled(bool enabled) { @@ -36,6 +41,16 @@ class FlutterZxing { /// Returns a version of the zxing library static String version() => bindings.version().cast().toDartString(); + /// Starts reading barcode from the camera + static Future startCameraProcessing() async { + // Spawn a new isolate + isolateUtils = IsolateUtils(); + await isolateUtils?.startReadingBarcode(); + } + + /// Stops reading barcode from the camera + static stopCameraProcessing() => isolateUtils?.stopReadingBarcode(); + /// Reads barcode from String image path static Future readImagePathString( String path, { @@ -114,7 +129,25 @@ class FlutterZxing { return result; } - static int get _logEnabled => logEnabled ? 1 : 0; + static Future processCameraImage( + CameraImage image, int format, double cropPercent) async { + var isolateData = IsolateData(image, format, cropPercent); + CodeResult result = await _inference(isolateData); + return result; + } + + /// Runs inference in another isolate + static Future _inference(IsolateData isolateData) async { + ReceivePort responsePort = ReceivePort(); + isolateUtils?.sendPort + ?.send(isolateData..responsePort = responsePort.sendPort); + var results = await responsePort.first; + return results; + } + + static int get _logEnabled { + return logEnabled ? 1 : 0; + } static String formatName(int format) => _formatNames[format] ?? 'Unknown'; } diff --git a/lib/isolate_utils.dart b/lib/isolate_utils.dart index b69ef5f..a23ca96 100644 --- a/lib/isolate_utils.dart +++ b/lib/isolate_utils.dart @@ -33,9 +33,9 @@ class IsolateUtils { SendPort? get sendPort => _sendPort; - Future start() async { + Future startReadingBarcode() async { _isolate = await Isolate.spawn( - entryPoint, + readBarcodeEntryPoint, _receivePort.sendPort, debugName: kDebugName, ); @@ -43,13 +43,13 @@ class IsolateUtils { _sendPort = await _receivePort.first; } - void stop() { + void stopReadingBarcode() { _isolate?.kill(priority: Isolate.immediate); _isolate = null; _sendPort = null; } - static void entryPoint(SendPort sendPort) async { + static void readBarcodeEntryPoint(SendPort sendPort) async { final port = ReceivePort(); sendPort.send(port.sendPort); @@ -66,7 +66,7 @@ class IsolateUtils { image.width, image.height, cropSize, cropSize); isolateData.responsePort?.send(result); - } on Exception catch (e) { + } catch (e) { isolateData.responsePort?.send(e); } } diff --git a/lib/reader_widget.dart b/lib/reader_widget.dart index 4291c4f..a138d07 100644 --- a/lib/reader_widget.dart +++ b/lib/reader_widget.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; import 'dart:math'; import 'package:camera/camera.dart'; @@ -60,8 +59,7 @@ class _ReaderWidgetState extends State void initStateAsync() async { // Spawn a new isolate - isolateUtils = IsolateUtils(); - await isolateUtils?.start(); + await FlutterZxing.startCameraProcessing(); availableCameras().then((cameras) { setState(() { @@ -94,8 +92,8 @@ class _ReaderWidgetState extends State @override void dispose() { + FlutterZxing.stopCameraProcessing(); controller?.dispose(); - isolateUtils?.stop(); super.dispose(); } @@ -116,7 +114,7 @@ class _ReaderWidgetState extends State await controller?.initialize(); controller?.startImageStream(processCameraImage); } on CameraException catch (e) { - _showCameraException(e); + debugPrint('${e.code}: ${e.description}'); } controller?.addListener(() { @@ -131,30 +129,15 @@ class _ReaderWidgetState extends State widget.onControllerCreated?.call(controller); } - void _showCameraException(CameraException e) { - logError(e.code, e.description); - showInSnackBar('Error: ${e.code}\n${e.description}'); - } - - void showInSnackBar(String message) {} - - void logError(String code, String? message) { - if (message != null) { - debugPrint('Error: $code\nError Message: $message'); - } else { - debugPrint('Error: $code'); - } - } - processCameraImage(CameraImage image) async { if (!_isProcessing) { _isProcessing = true; try { - var isolateData = - IsolateData(image, widget.codeFormat, widget.cropPercent); - - /// perform inference in separate isolate - CodeResult result = await inference(isolateData); + CodeResult result = await FlutterZxing.processCameraImage( + image, + widget.codeFormat, + widget.cropPercent, + ); if (result.isValidBool) { if (widget.beep) { FlutterBeep.beep(); @@ -175,15 +158,6 @@ class _ReaderWidgetState extends State return null; } - /// Runs inference in another isolate - Future inference(IsolateData isolateData) async { - ReceivePort responsePort = ReceivePort(); - isolateUtils?.sendPort - ?.send(isolateData..responsePort = responsePort.sendPort); - var results = await responsePort.first; - return results; - } - @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size;