diff --git a/README.md b/README.md index 8e097a7f..86251ae1 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Google's ML Kit for Flutter is a set of [Flutter plugins](https://flutter.io/pla | [Pose Detection (Beta)](https://developers.google.com/ml-kit/vision/pose-detection) | [google_mlkit_pose_detection](https://pub.dev/packages/google_mlkit_pose_detection) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_pose_detection)](https://pub.dev/packages/google_mlkit_pose_detection) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_pose_detection) | ✅ | ✅ | | [Selfie Segmentation (Beta)](https://developers.google.com/ml-kit/vision/selfie-segmentation) | [google_mlkit_selfie_segmentation](https://pub.dev/packages/google_mlkit_selfie_segmentation) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_selfie_segmentation)](https://pub.dev/packages/google_mlkit_selfie_segmentation) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_selfie_segmentation) | ✅ | ✅ | | [Subject Segmentation (Beta)](https://developers.google.com/ml-kit/vision/subject-segmentation) | [google_mlkit_subject_segmentation](https://pub.dev/packages/google_mlkit_subject_segmentation) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_subject_segmentation)](https://pub.dev/packages/google_mlkit_subject_segmentation) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_subject_segmentation) | ✅ | ❌ | -| [Document Scanner (Beta)](https://developers.google.com/ml-kit/vision/doc-scanner) | [google_mlkit_document_scanner](https://pub.dev/packages/google_mlkit_document_scanner) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_document_scanner)](https://pub.dev/packages/google_mlkit_document_scanner) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_document_scanner) | ✅ | ❌ | +| [Document Scanner](https://developers.google.com/ml-kit/vision/doc-scanner) | [google_mlkit_document_scanner](https://pub.dev/packages/google_mlkit_document_scanner) [![Pub Version](https://img.shields.io/pub/v/google_mlkit_document_scanner)](https://pub.dev/packages/google_mlkit_document_scanner) | [![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge&logo=github&logoColor=white)](https://github.com/flutter-ml/google_ml_kit_flutter/tree/master/packages/google_mlkit_document_scanner) | ✅ | ❌ | ### Natural Language APIs diff --git a/packages/example/lib/vision_detector_views/document_scanner_view.dart b/packages/example/lib/vision_detector_views/document_scanner_view.dart index 3eec7b17..2fc16694 100644 --- a/packages/example/lib/vision_detector_views/document_scanner_view.dart +++ b/packages/example/lib/vision_detector_views/document_scanner_view.dart @@ -1,9 +1,13 @@ +import 'dart:collection'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart'; import 'package:google_mlkit_document_scanner/google_mlkit_document_scanner.dart'; +typedef MenuEntry = DropdownMenuEntry; +const List list = ['Select option', 'pdf', 'jpeg', 'pdf-jpeg']; + class DocumentScannerView extends StatefulWidget { @override State createState() => _DocumentScannerViewState(); @@ -12,7 +16,11 @@ class DocumentScannerView extends StatefulWidget { class _DocumentScannerViewState extends State { DocumentScanner? _documentScanner; DocumentScanningResult? _result; - + static final List menuEntries = UnmodifiableListView( + list.map((String name) => MenuEntry( + value: name, + label: + name == 'Select option' ? name : 'Scan ${name.toUpperCase()}'))); @override void dispose() { _documentScanner?.close(); @@ -27,103 +35,84 @@ class _DocumentScannerViewState extends State { centerTitle: true, elevation: 0, ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.document_scanner_outlined, - size: 50, - ), - SizedBox(width: 8), - ElevatedButton( - style: ButtonStyle( - backgroundColor: - WidgetStateProperty.all(Colors.black), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - ), - onPressed: () => startScan(DocumentFormat.pdf), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: const Text( - 'Scan PDF', - style: TextStyle(color: Colors.white), - ), + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.document_scanner_outlined, + size: 50, ), + SizedBox(width: 8), + DropdownMenu( + initialSelection: list.first, + onSelected: (String? value) { + if (value != null) { + if (value == 'pdf') { + startScan({DocumentFormat.pdf}); + } + if (value == 'jpeg') { + startScan({DocumentFormat.jpeg}); + } + if (value == 'pdf-jpeg') { + startScan( + {DocumentFormat.pdf, DocumentFormat.jpeg}); + } + } + }, + dropdownMenuEntries: menuEntries), + ], + ), + if (_result?.pdf != null) ...[ + Padding( + padding: const EdgeInsets.only( + top: 16, bottom: 8, right: 8, left: 8), + child: Align( + alignment: Alignment.centerLeft, + child: Text('PDF Document:')), ), - SizedBox(width: 8), - ElevatedButton( - style: ButtonStyle( - backgroundColor: - WidgetStateProperty.all(Colors.black), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - ), - onPressed: () => startScan(DocumentFormat.jpeg), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: const Text( - 'Scan JPEG', - style: TextStyle(color: Colors.white), - ), + SizedBox( + height: 300, + child: PDFView( + filePath: _result!.pdf!.uri, + enableSwipe: true, + swipeHorizontal: true, + autoSpacing: false, + pageFling: false, ), ), ], - ), - if (_result?.pdf != null) ...[ - Padding( - padding: const EdgeInsets.only( - top: 16, bottom: 8, right: 8, left: 8), - child: Align( - alignment: Alignment.centerLeft, - child: Text('PDF Document:')), - ), - SizedBox( - height: 300, - child: PDFView( - filePath: _result!.pdf!.uri, - enableSwipe: true, - swipeHorizontal: true, - autoSpacing: false, - pageFling: false, + if (_result?.images?.isNotEmpty == true) ...[ + Padding( + padding: const EdgeInsets.only( + top: 16, bottom: 8, right: 8, left: 8), + child: Align( + alignment: Alignment.centerLeft, + child: Text('Images [0]:')), ), - ), - ], - if (_result?.images.isNotEmpty == true) ...[ - Padding( - padding: const EdgeInsets.only( - top: 16, bottom: 8, right: 8, left: 8), - child: Align( - alignment: Alignment.centerLeft, - child: Text('Images [0]:')), - ), - SizedBox( - height: 400, child: Image.file(File(_result!.images.first))), + SizedBox( + height: 400, + child: Image.file(File(_result!.images!.first))), + ], ], - ], + ), ), ), ); } - void startScan(DocumentFormat format) async { + void startScan(Set formats) async { try { _result = null; setState(() {}); _documentScanner?.close(); _documentScanner = DocumentScanner( options: DocumentScannerOptions( - documentFormat: format, + documentFormats: formats, mode: ScannerMode.full, isGalleryImport: false, pageLimit: 1, diff --git a/packages/google_mlkit_document_scanner/README.md b/packages/google_mlkit_document_scanner/README.md index b2d1140b..51140978 100644 --- a/packages/google_mlkit_document_scanner/README.md +++ b/packages/google_mlkit_document_scanner/README.md @@ -55,7 +55,7 @@ The document scanner API provides a high-quality fully fledged UI flow that is c ### iOS -This feature is still in Beta, and it is only available for Android. Stay tune for updates in [Google's website](https://developers.google.com/ml-kit/vision/doc-scanner) and request the feature [here](https://github.com/googlesamples/mlkit/issues). +This feature is only available for Android. Stay tune for updates in [Google's website](https://developers.google.com/ml-kit/vision/doc-scanner) and request the feature [here](https://github.com/googlesamples/mlkit/issues). ### Android @@ -70,8 +70,13 @@ This feature is still in Beta, and it is only available for Android. Stay tune f #### Create an instance of `DocumentScannerOptions` ```dart +// set output document formats +const Set documentFormats = { + DocumentFormat.jpeg, + DocumentFormat.pdf +}; DocumentScannerOptions documentOptions = DocumentScannerOptions( - documentFormat: DocumentFormat.jpeg, // set output document format + documentFormats: documentFormats, mode: ScannerMode.filter, // to control what features are enabled pageLimit: 1, // setting a limit to the number of pages scanned isGalleryImport: true, // importing from the photo gallery diff --git a/packages/google_mlkit_document_scanner/android/build.gradle b/packages/google_mlkit_document_scanner/android/build.gradle index 91147c2d..8264c2d4 100644 --- a/packages/google_mlkit_document_scanner/android/build.gradle +++ b/packages/google_mlkit_document_scanner/android/build.gradle @@ -36,6 +36,6 @@ android { } dependencies { - implementation("com.google.android.gms:play-services-mlkit-document-scanner:16.0.0-beta1") + implementation("com.google.android.gms:play-services-mlkit-document-scanner:16.0.0") } } diff --git a/packages/google_mlkit_document_scanner/android/gradle/wrapper/gradle-wrapper.properties b/packages/google_mlkit_document_scanner/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..128196a7 --- /dev/null +++ b/packages/google_mlkit_document_scanner/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-milestone-1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/google_mlkit_document_scanner/android/src/main/java/com/google_mlkit_document_scanner/DocumentScanner.java b/packages/google_mlkit_document_scanner/android/src/main/java/com/google_mlkit_document_scanner/DocumentScanner.java index 7b84f182..2720b220 100644 --- a/packages/google_mlkit_document_scanner/android/src/main/java/com/google_mlkit_document_scanner/DocumentScanner.java +++ b/packages/google_mlkit_document_scanner/android/src/main/java/com/google_mlkit_document_scanner/DocumentScanner.java @@ -95,17 +95,21 @@ public void onFailure(@NonNull Exception e) { private GmsDocumentScannerOptions parseOptions(Map options) { boolean isGalleryImportAllowed = (boolean) options.get("isGalleryImport"); int pageLimit = (int) options.get("pageLimit"); - int format; - switch ((String) Objects.requireNonNull(options.get("format"))) { - case "pdf": - format = GmsDocumentScannerOptions.RESULT_FORMAT_PDF; - break; - case "jpeg": - format = GmsDocumentScannerOptions.RESULT_FORMAT_JPEG; - break; - default: - throw new IllegalArgumentException("Not a format:" + options.get("format")); + List formatStrings = (List) options.get("formats"); + List formatConstants = new ArrayList<>(); + for (String format: formatStrings) { + switch (format) { + case "pdf": + formatConstants.add(GmsDocumentScannerOptions.RESULT_FORMAT_PDF); + break; + case "jpeg": + formatConstants.add(GmsDocumentScannerOptions.RESULT_FORMAT_JPEG); + break; + default: + throw new IllegalArgumentException("Not a format:" + options.get("format")); + } } + int mode; switch ((String) options.get("mode")) { case "base": @@ -120,7 +124,21 @@ private GmsDocumentScannerOptions parseOptions(Map options) { default: throw new IllegalArgumentException("Not a mode:" + options.get("mode")); } - GmsDocumentScannerOptions.Builder builder = new GmsDocumentScannerOptions.Builder().setGalleryImportAllowed(isGalleryImportAllowed).setPageLimit(pageLimit).setResultFormats(format).setScannerMode(mode); + GmsDocumentScannerOptions.Builder builder = new GmsDocumentScannerOptions + .Builder() + .setGalleryImportAllowed(isGalleryImportAllowed) + .setPageLimit(pageLimit) + .setScannerMode(mode); + + // Set formats + if (!formatConstants.isEmpty()) { + if(formatConstants.size() > 1) { + builder.setResultFormats(formatConstants.get(0), formatConstants.get(1)); + } else { + builder.setResultFormats(formatConstants.get(0)); + } + + } return builder.build(); } diff --git a/packages/google_mlkit_document_scanner/lib/src/document_scanner.dart b/packages/google_mlkit_document_scanner/lib/src/document_scanner.dart index 1a6a501a..911b3765 100644 --- a/packages/google_mlkit_document_scanner/lib/src/document_scanner.dart +++ b/packages/google_mlkit_document_scanner/lib/src/document_scanner.dart @@ -35,7 +35,7 @@ class DocumentScanner { class DocumentScannerOptions { /// Constructor for [DocumentScannerOptions]. DocumentScannerOptions({ - this.documentFormat = DocumentFormat.jpeg, + this.documentFormats = const {DocumentFormat.jpeg}, this.pageLimit = 1, this.mode = ScannerMode.full, this.isGalleryImport = false, @@ -46,7 +46,7 @@ class DocumentScannerOptions { /// Sets scanner result formats. /// Available formats: PDF, JPG and default format is JPG. - final DocumentFormat documentFormat; + final Set documentFormats; /// Sets the scanner mode which determines what features are enabled. default = ScannerModel.full. final ScannerMode mode; @@ -57,7 +57,7 @@ class DocumentScannerOptions { /// Returns a json representation of an instance of [DocumentScannerOptions]. Map toJson() => { 'pageLimit': pageLimit, - 'format': documentFormat.name, + 'formats': documentFormats.map((f) => f.name).toList(), 'mode': mode.name, 'isGalleryImport': isGalleryImport, }; @@ -82,7 +82,7 @@ class DocumentScanningResult { final DocumentScanningResultPdf? pdf; /// Returns the scanned images or null if `DocumentFormat.jpeg` was not specified when creating the scanner options. - final List images; + final List? images; /// Constructor to create an instance of [DocumentScanningResult]. DocumentScanningResult({required this.pdf, required this.images});