Julian Steenbakker
Committed by GitHub

Merge pull request #42 from juliansteenbakker/barcode-formats-allowed

Barcode formats allowed
... ... @@ -3,6 +3,9 @@ You can provide a path to controller.analyzeImage(path) in order to scan a local
Check out the example app to see how you can use the image_picker plugin to retrieve a photo from
the gallery. Please keep in mind that this feature is only supported on Android and iOS.
Another feature that has been added is a format selector!
Just keep in mind that iOS for now only supports 1 selected barcode.
## 0.1.3
* Fixed crash after asking permission. [#29](https://github.com/juliansteenbakker/mobile_scanner/issues/29)
* Upgraded cameraX from 1.1.0-beta01 to 1.1.0-beta02
... ...
package dev.steenbakker.mobile_scanner
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import java.util.ArrayList
enum class BarcodeFormats(val intValue: Int) {
UNKNOWN(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_UNKNOWN),
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(
com.google.mlkit.vision.barcode.common.Barcode.FORMAT_CODE_39
),
... ... @@ -17,76 +17,4 @@ enum class BarcodeFormats(val intValue: Int) {
com.google.mlkit.vision.barcode.common.Barcode.FORMAT_UPC_E
),
PDF417(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_PDF417), AZTEC(com.google.mlkit.vision.barcode.common.Barcode.FORMAT_AZTEC);
companion object {
private var formatsMap: MutableMap<String, Int>? = null
/**
* Return the integer value resuling from OR-ing all of the values
* of the supplied strings.
*
*
* Note that if ALL_FORMATS is defined as well as other values, ALL_FORMATS
* will be ignored (following how it would work with just OR-ing the ints).
*
* @param strings - list of strings representing the various formats
* @return integer value corresponding to OR of all the values.
*/
fun intFromStringList(strings: List<String>?): Int {
if (strings == null) return ALL_FORMATS.intValue
var `val` = 0
for (string in strings) {
val asInt = formatsMap!![string]
if (asInt != null) {
`val` = `val` or asInt
}
}
return `val`
}
fun optionsFromStringList(strings: List<String>?): BarcodeScannerOptions {
if (strings == null) {
return BarcodeScannerOptions.Builder().setBarcodeFormats(ALL_FORMATS.intValue)
.build()
}
val ints: MutableList<Int> = ArrayList(strings.size)
run {
var i = 0
val l = strings.size
while (i < l) {
val integer =
formatsMap!![strings[i]]
if (integer != null) {
ints.add(integer)
}
++i
}
}
if (ints.size == 0) {
return BarcodeScannerOptions.Builder().setBarcodeFormats(ALL_FORMATS.intValue)
.build()
}
if (ints.size == 1) {
return BarcodeScannerOptions.Builder().setBarcodeFormats(ints[0]).build()
}
val first = ints[0]
val rest = IntArray(ints.size - 1)
var i = 0
for (e in ints.subList(1, ints.size)) {
rest[i++] = e
}
return BarcodeScannerOptions.Builder()
.setBarcodeFormats(first, *rest).build()
}
init {
val values = values()
formatsMap =
HashMap<String, Int>(values.size * 4 / 3)
for (value in values) {
formatsMap!![value.name] =
value.intValue
}
}
}
}
\ No newline at end of file
... ...
... ... @@ -128,11 +128,18 @@ class MobileScanner(private val activity: Activity, private val textureRegistry:
val facing: Int = call.argument<Int>("facing") ?: 0
val ratio: Int? = call.argument<Int>("ratio")
val torch: Boolean = call.argument<Boolean>("torch") ?: false
val formatStrings: List<String>? = call.argument<List<String>>("formats")
val formats: List<Int>? = call.argument<List<Int>>("formats")
if (formatStrings != null) {
val options: BarcodeScannerOptions = BarcodeFormats.optionsFromStringList(formatStrings)
scanner = BarcodeScanning.getClient(options)
if (formats != null) {
val formatsList: MutableList<Int> = mutableListOf()
for (index in formats) {
formatsList.add(BarcodeFormats.values()[index].intValue)
}
scanner = if (formatsList.size == 1) {
BarcodeScanning.getClient( BarcodeScannerOptions.Builder().setBarcodeFormats(formatsList.first()).build());
} else {
BarcodeScanning.getClient( BarcodeScannerOptions.Builder().setBarcodeFormats(formatsList.first(), *formatsList.subList(1, formatsList.size).toIntArray() ).build());
}
}
val future = ProcessCameraProvider.getInstance(activity)
... ...
... ... @@ -17,6 +17,7 @@ class _BarcodeScannerWithControllerState
MobileScannerController controller = MobileScannerController(
torchEnabled: true,
// formats: [BarcodeFormat.qrCode]
// facing: CameraFacing.front,
);
... ...
... ... @@ -26,7 +26,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
var analyzing: Bool = false
var position = AVCaptureDevice.Position.back
let scanner = BarcodeScanner.barcodeScanner()
var scanner = BarcodeScanner.barcodeScanner()
public static func register(with registrar: FlutterPluginRegistrar) {
let instance = SwiftMobileScannerPlugin(registrar.textures())
... ... @@ -171,6 +171,15 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan
// let ratio: Int = argReader.int(key: "ratio")
let torch: Bool = argReader.bool(key: "torch") ?? false
let facing: Int = argReader.int(key: "facing") ?? 1
let formats: Array = argReader.intArray(key: "formats") ?? []
let formatList: NSMutableArray = []
for index in formats {
formatList.add(BarcodeFormat(rawValue: index))
}
let barcodeOptions = BarcodeScannerOptions(formats: formatList.firstObject as! BarcodeFormat)
scanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
// Set the camera to use
position = facing == 0 ? AVCaptureDevice.Position.front : .back
... ... @@ -357,4 +366,8 @@ class MapArgumentReader {
return args?[key] as? [String]
}
func intArray(key: String) -> [Int]? {
return args?[key] as? [Int]
}
}
... ...
... ... @@ -24,12 +24,9 @@ class MobileScanner extends StatefulWidget {
final BoxFit fit;
/// Create a [MobileScanner] with a [controller], the [controller] must has been initialized.
const MobileScanner({
Key? key,
this.onDetect,
this.controller,
this.fit = BoxFit.cover,
}) : super(key: key);
const MobileScanner(
{Key? key, this.onDetect, this.controller, this.fit = BoxFit.cover})
: super(key: key);
@override
State<MobileScanner> createState() => _MobileScannerState();
... ...
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
... ... @@ -43,6 +44,11 @@ class MobileScannerController {
final Ratio? ratio;
final bool? torchEnabled;
/// If provided, the scanner will only detect those specific formats.
///
/// WARNING: On iOS, only 1 format is supported.
final List<BarcodeFormat>? formats;
CameraFacing facing;
bool hasTorch = false;
late StreamController<Barcode> barcodesController;
... ... @@ -50,7 +56,10 @@ class MobileScannerController {
Stream<Barcode> get barcodes => barcodesController.stream;
MobileScannerController(
{this.facing = CameraFacing.back, this.ratio, this.torchEnabled}) {
{this.facing = CameraFacing.back,
this.ratio,
this.torchEnabled,
this.formats}) {
// In case a new instance is created before calling dispose()
if (_controllerHashcode != null) {
stop();
... ... @@ -138,6 +147,14 @@ class MobileScannerController {
if (ratio != null) arguments['ratio'] = ratio;
if (torchEnabled != null) arguments['torch'] = torchEnabled;
if (formats != null) {
if (Platform.isAndroid) {
arguments['formats'] = formats!.map((e) => e.index).toList();
} else if (Platform.isIOS || Platform.isMacOS) {
arguments['formats'] = formats!.map((e) => e.rawValue).toList();
}
}
// Start the camera with arguments
Map<String, dynamic>? startResult = {};
try {
... ...
... ... @@ -553,6 +553,43 @@ enum BarcodeFormat {
aztec,
}
extension BarcodeValue on BarcodeFormat {
int get rawValue {
switch (this) {
case BarcodeFormat.unknown:
return -1;
case BarcodeFormat.all:
return 0;
case BarcodeFormat.code128:
return 1;
case BarcodeFormat.code39:
return 2;
case BarcodeFormat.code93:
return 4;
case BarcodeFormat.codebar:
return 8;
case BarcodeFormat.dataMatrix:
return 16;
case BarcodeFormat.ean13:
return 32;
case BarcodeFormat.ean8:
return 64;
case BarcodeFormat.itf:
return 128;
case BarcodeFormat.qrCode:
return 256;
case BarcodeFormat.upcA:
return 512;
case BarcodeFormat.upcE:
return 1024;
case BarcodeFormat.pdf417:
return 2048;
case BarcodeFormat.aztec:
return 4096;
}
}
}
/// Address type constants.
enum AddressType {
/// Unknown address type.
... ...