Julian Steenbakker

feat: add formats selector

1 package dev.steenbakker.mobile_scanner 1 package dev.steenbakker.mobile_scanner
2 2
3 import com.google.mlkit.vision.barcode.BarcodeScannerOptions 3 import com.google.mlkit.vision.barcode.BarcodeScannerOptions
4 -import java.util.ArrayList  
5 4
6 enum class BarcodeFormats(val intValue: Int) { 5 enum class BarcodeFormats(val intValue: Int) {
  6 + UNKNOWN(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_UNKNOWN),
7 ALL_FORMATS(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_ALL_FORMATS), CODE_128(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_CODE_128), CODE_39( 7 ALL_FORMATS(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_ALL_FORMATS), CODE_128(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_CODE_128), CODE_39(
8 com.google.mlkit.vision.barcode.common.Barcode.FORMAT_CODE_39 8 com.google.mlkit.vision.barcode.common.Barcode.FORMAT_CODE_39
9 ), 9 ),
@@ -17,76 +17,4 @@ enum class BarcodeFormats(val intValue: Int) { @@ -17,76 +17,4 @@ enum class BarcodeFormats(val intValue: Int) {
17 com.google.mlkit.vision.barcode.common.Barcode.FORMAT_UPC_E 17 com.google.mlkit.vision.barcode.common.Barcode.FORMAT_UPC_E
18 ), 18 ),
19 PDF417(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_PDF417), AZTEC(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_AZTEC); 19 PDF417(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_PDF417), AZTEC(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_AZTEC);
20 -  
21 - companion object {  
22 - private var formatsMap: MutableMap<String, Int>? = null  
23 -  
24 - /**  
25 - * Return the integer value resuling from OR-ing all of the values  
26 - * of the supplied strings.  
27 - *  
28 - *  
29 - * Note that if ALL_FORMATS is defined as well as other values, ALL_FORMATS  
30 - * will be ignored (following how it would work with just OR-ing the ints).  
31 - *  
32 - * @param strings - list of strings representing the various formats  
33 - * @return integer value corresponding to OR of all the values.  
34 - */  
35 - fun intFromStringList(strings: List<String>?): Int {  
36 - if (strings == null) return ALL_FORMATS.intValue  
37 - var `val` = 0  
38 - for (string in strings) {  
39 - val asInt = formatsMap!![string]  
40 - if (asInt != null) {  
41 - `val` = `val` or asInt  
42 - }  
43 - }  
44 - return `val`  
45 - }  
46 -  
47 - fun optionsFromStringList(strings: List<String>?): BarcodeScannerOptions {  
48 - if (strings == null) {  
49 - return BarcodeScannerOptions.Builder().setBarcodeFormats(ALL_FORMATS.intValue)  
50 - .build()  
51 - }  
52 - val ints: MutableList<Int> = ArrayList(strings.size)  
53 - run {  
54 - var i = 0  
55 - val l = strings.size  
56 - while (i < l) {  
57 - val integer =  
58 - formatsMap!![strings[i]]  
59 - if (integer != null) {  
60 - ints.add(integer)  
61 - }  
62 - ++i  
63 - }  
64 - }  
65 - if (ints.size == 0) {  
66 - return BarcodeScannerOptions.Builder().setBarcodeFormats(ALL_FORMATS.intValue)  
67 - .build()  
68 - }  
69 - if (ints.size == 1) {  
70 - return BarcodeScannerOptions.Builder().setBarcodeFormats(ints[0]).build()  
71 - }  
72 - val first = ints[0]  
73 - val rest = IntArray(ints.size - 1)  
74 - var i = 0  
75 - for (e in ints.subList(1, ints.size)) {  
76 - rest[i++] = e  
77 - }  
78 - return BarcodeScannerOptions.Builder()  
79 - .setBarcodeFormats(first, *rest).build()  
80 - }  
81 -  
82 - init {  
83 - val values = values()  
84 - formatsMap =  
85 - HashMap<String, Int>(values.size * 4 / 3)  
86 - for (value in values) {  
87 - formatsMap!![value.name] =  
88 - value.intValue  
89 - }  
90 - }  
91 - }  
92 } 20 }
@@ -128,11 +128,18 @@ class MobileScanner(private val activity: Activity, private val textureRegistry: @@ -128,11 +128,18 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
128 val facing: Int = call.argument<Int>("facing") ?: 0 128 val facing: Int = call.argument<Int>("facing") ?: 0
129 val ratio: Int? = call.argument<Int>("ratio") 129 val ratio: Int? = call.argument<Int>("ratio")
130 val torch: Boolean = call.argument<Boolean>("torch") ?: false 130 val torch: Boolean = call.argument<Boolean>("torch") ?: false
131 - val formatStrings: List<String>? = call.argument<List<String>>("formats") 131 + val formats: List<Int>? = call.argument<List<Int>>("formats")
132 132
133 - if (formatStrings != null) {  
134 - val options: BarcodeScannerOptions = BarcodeFormats.optionsFromStringList(formatStrings)  
135 - scanner = BarcodeScanning.getClient(options) 133 + if (formats != null) {
  134 + val formatsList: MutableList<Int> = mutableListOf()
  135 + for (index in formats) {
  136 + formatsList.add(BarcodeFormats.values()[index].intValue)
  137 + }
  138 + scanner = if (formatsList.size == 1) {
  139 + BarcodeScanning.getClient( BarcodeScannerOptions.Builder().setBarcodeFormats(formatsList.first()).build());
  140 + } else {
  141 + BarcodeScanning.getClient( BarcodeScannerOptions.Builder().setBarcodeFormats(formatsList.first(), *formatsList.subList(1, formatsList.size).toIntArray() ).build());
  142 + }
136 } 143 }
137 144
138 val future = ProcessCameraProvider.getInstance(activity) 145 val future = ProcessCameraProvider.getInstance(activity)
@@ -17,6 +17,7 @@ class _BarcodeScannerWithControllerState @@ -17,6 +17,7 @@ class _BarcodeScannerWithControllerState
17 17
18 MobileScannerController controller = MobileScannerController( 18 MobileScannerController controller = MobileScannerController(
19 torchEnabled: true, 19 torchEnabled: true,
  20 + // formats: [BarcodeFormat.ean13, BarcodeFormat.ean8]
20 // facing: CameraFacing.front, 21 // facing: CameraFacing.front,
21 ); 22 );
22 23
@@ -26,7 +26,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan @@ -26,7 +26,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
26 var analyzing: Bool = false 26 var analyzing: Bool = false
27 var position = AVCaptureDevice.Position.back 27 var position = AVCaptureDevice.Position.back
28 28
29 - let scanner = BarcodeScanner.barcodeScanner() 29 + var scanner = BarcodeScanner.barcodeScanner()
30 30
31 public static func register(with registrar: FlutterPluginRegistrar) { 31 public static func register(with registrar: FlutterPluginRegistrar) {
32 let instance = SwiftMobileScannerPlugin(registrar.textures()) 32 let instance = SwiftMobileScannerPlugin(registrar.textures())
@@ -171,6 +171,15 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan @@ -171,6 +171,15 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
171 // let ratio: Int = argReader.int(key: "ratio") 171 // let ratio: Int = argReader.int(key: "ratio")
172 let torch: Bool = argReader.bool(key: "torch") ?? false 172 let torch: Bool = argReader.bool(key: "torch") ?? false
173 let facing: Int = argReader.int(key: "facing") ?? 1 173 let facing: Int = argReader.int(key: "facing") ?? 1
  174 + let formats: Array = argReader.intArray(key: "formats") ?? []
  175 +
  176 + let formatList: NSMutableArray = []
  177 + for index in formats {
  178 + formatList.add(BarcodeFormat(rawValue: index))
  179 + }
  180 +
  181 + let barcodeOptions = BarcodeScannerOptions(formats: formatList.firstObject as! BarcodeFormat)
  182 + scanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
174 183
175 // Set the camera to use 184 // Set the camera to use
176 position = facing == 0 ? AVCaptureDevice.Position.front : .back 185 position = facing == 0 ? AVCaptureDevice.Position.front : .back
@@ -357,4 +366,8 @@ class MapArgumentReader { @@ -357,4 +366,8 @@ class MapArgumentReader {
357 return args?[key] as? [String] 366 return args?[key] as? [String]
358 } 367 }
359 368
  369 + func intArray(key: String) -> [Int]? {
  370 + return args?[key] as? [Int]
  371 + }
  372 +
360 } 373 }
@@ -28,7 +28,7 @@ class MobileScanner extends StatefulWidget { @@ -28,7 +28,7 @@ class MobileScanner extends StatefulWidget {
28 Key? key, 28 Key? key,
29 this.onDetect, 29 this.onDetect,
30 this.controller, 30 this.controller,
31 - this.fit = BoxFit.cover, 31 + this.fit = BoxFit.cover
32 }) : super(key: key); 32 }) : super(key: key);
33 33
34 @override 34 @override
1 import 'dart:async'; 1 import 'dart:async';
  2 +import 'dart:io';
2 3
3 import 'package:flutter/cupertino.dart'; 4 import 'package:flutter/cupertino.dart';
4 import 'package:flutter/services.dart'; 5 import 'package:flutter/services.dart';
@@ -42,6 +43,7 @@ class MobileScannerController { @@ -42,6 +43,7 @@ class MobileScannerController {
42 late final ValueNotifier<CameraFacing> cameraFacingState; 43 late final ValueNotifier<CameraFacing> cameraFacingState;
43 final Ratio? ratio; 44 final Ratio? ratio;
44 final bool? torchEnabled; 45 final bool? torchEnabled;
  46 + final List<BarcodeFormat>? formats;
45 47
46 CameraFacing facing; 48 CameraFacing facing;
47 bool hasTorch = false; 49 bool hasTorch = false;
@@ -50,7 +52,7 @@ class MobileScannerController { @@ -50,7 +52,7 @@ class MobileScannerController {
50 Stream<Barcode> get barcodes => barcodesController.stream; 52 Stream<Barcode> get barcodes => barcodesController.stream;
51 53
52 MobileScannerController( 54 MobileScannerController(
53 - {this.facing = CameraFacing.back, this.ratio, this.torchEnabled}) { 55 + {this.facing = CameraFacing.back, this.ratio, this.torchEnabled, this.formats}) {
54 // In case a new instance is created before calling dispose() 56 // In case a new instance is created before calling dispose()
55 if (_controllerHashcode != null) { 57 if (_controllerHashcode != null) {
56 stop(); 58 stop();
@@ -138,6 +140,15 @@ class MobileScannerController { @@ -138,6 +140,15 @@ class MobileScannerController {
138 if (ratio != null) arguments['ratio'] = ratio; 140 if (ratio != null) arguments['ratio'] = ratio;
139 if (torchEnabled != null) arguments['torch'] = torchEnabled; 141 if (torchEnabled != null) arguments['torch'] = torchEnabled;
140 142
  143 + if (formats != null) {
  144 + if (Platform.isAndroid) {
  145 + arguments['formats'] = formats!.map((e) => e.index).toList();
  146 + } else if (Platform.isIOS || Platform.isMacOS) {
  147 + arguments['formats'] = formats!.map((e) => e.rawValue).toList();
  148 + }
  149 +
  150 + }
  151 +
141 // Start the camera with arguments 152 // Start the camera with arguments
142 Map<String, dynamic>? startResult = {}; 153 Map<String, dynamic>? startResult = {};
143 try { 154 try {
@@ -553,6 +553,45 @@ enum BarcodeFormat { @@ -553,6 +553,45 @@ enum BarcodeFormat {
553 aztec, 553 aztec,
554 } 554 }
555 555
  556 +extension BarcodeValue on BarcodeFormat {
  557 +
  558 + int get rawValue {
  559 + switch (this) {
  560 + case BarcodeFormat.unknown:
  561 + return -1;
  562 + case BarcodeFormat.all:
  563 + return 0;
  564 + case BarcodeFormat.code128:
  565 + return 1;
  566 + case BarcodeFormat.code39:
  567 + return 2;
  568 + case BarcodeFormat.code93:
  569 + return 4;
  570 + case BarcodeFormat.codebar:
  571 + return 8;
  572 + case BarcodeFormat.dataMatrix:
  573 + return 16;
  574 + case BarcodeFormat.ean13:
  575 + return 32;
  576 + case BarcodeFormat.ean8:
  577 + return 64;
  578 + case BarcodeFormat.itf:
  579 + return 128;
  580 + case BarcodeFormat.qrCode:
  581 + return 256;
  582 + case BarcodeFormat.upcA:
  583 + return 512;
  584 + case BarcodeFormat.upcE:
  585 + return 1024;
  586 + case BarcodeFormat.pdf417:
  587 + return 2048;
  588 + case BarcodeFormat.aztec:
  589 + return 4096;
  590 + }
  591 + }
  592 +
  593 +}
  594 +
556 /// Address type constants. 595 /// Address type constants.
557 enum AddressType { 596 enum AddressType {
558 /// Unknown address type. 597 /// Unknown address type.