Repository: rushio-consulting/flutter_camera_ml_vision Branch: master Commit: 502409a4d62c Files: 49 Total size: 89.4 KB Directory structure: gitextract_meceayu3/ ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── main.yml ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example/ │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── android/ │ │ ├── app/ │ │ │ ├── build.gradle │ │ │ └── src/ │ │ │ ├── debug/ │ │ │ │ └── AndroidManifest.xml │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java/ │ │ │ │ │ └── fr/ │ │ │ │ │ └── rushioconsulting/ │ │ │ │ │ └── flutter_camera_ml_vision_example/ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── launch_background.xml │ │ │ │ └── values/ │ │ │ │ └── styles.xml │ │ │ └── profile/ │ │ │ └── AndroidManifest.xml │ │ ├── build.gradle │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ └── gradle-wrapper.properties │ │ ├── gradle.properties │ │ └── settings.gradle │ ├── ios/ │ │ ├── Flutter/ │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Podfile │ │ ├── Runner/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.imageset/ │ │ │ │ ├── Contents.json │ │ │ │ └── README.md │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ └── main.m │ │ ├── Runner.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ └── Runner.xcscheme │ │ └── Runner.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── lib/ │ │ ├── main.dart │ │ ├── main_face.dart │ │ └── main_live.dart │ ├── pubspec.yaml │ └── test/ │ └── widget_test.dart ├── flutter_camera_ml_vision.iml ├── lib/ │ ├── flutter_camera_ml_vision.dart │ └── utils.dart ├── pubspec.yaml └── test/ └── flutter_camera_ml_vision_test.dart ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [Kleak,jaumard]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: ['kleak*keybase.io'] ================================================ FILE: .github/workflows/main.yml ================================================ name: CI on: pull_request: branches: - master jobs: analyze: runs-on: ubuntu-latest container: image: cirrusci/flutter:stable steps: - uses: actions/checkout@v1 - run: sudo chown -R cirrus:cirrus ./ /github/home/ - name: Flutter pub get run: flutter packages get - name: Flutter analyze --suppress-analytics run: flutter analyze --suppress-analytics ================================================ FILE: .gitignore ================================================ .DS_Store .dart_tool/ .packages .pub/ .vscode/ idea/ build/ ios/.generated/ ios/Flutter/Generated.xcconfig ios/Runner/GeneratedPluginRegistrant.* google-services.json .idea/ /example/ios/GoogleService-Info.plist /example/ios/Runner/GoogleService-Info.plist example/ios/Flutter/flutter_export_environment.sh ================================================ FILE: .metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713 channel: stable project_type: package ================================================ FILE: CHANGELOG.md ================================================ ## [3.0.1] - 30/04/2021 - update deps - fix camera distortion ## [3.0.0] - 17/04/2021 - migrate to null safety ## [2.3.0] - 03/10/2020 - fix NPE on aspect ratio - update deps ## [2.2.5] - 12/02/2020 - fix crash on android app lifecycle - expose camera controller - pass default resolution to high to improve reading of barcode - update deps ## [2.2.4] - 04/11/2019 - simplify pause stream when not on screen by using VisibilityDetector widget ## [2.2.3] - 23/10/2019 - fix crash when setState is called when unmounted - update dependencies ## [2.2.2] - 02/09/2019 - fix black screen on some Android device in profile/release mode ## [2.2.1] - 19/06/2019 - fix bug when specifying resolution ## [2.2.0] - 16/06/2019 - disable audio (#43) - let user define camera resolution (#45) ## [2.1.0] - 16/05/2019 expose more function from camera controller - prepareForVideoRecording - startVideoRecording - stopVideoRecording - takePicture ## [2.0.1] - 5/05/2019 * fix a crash when poping a route with the camera preview ## [2.0.0] - 2/05/2019 * We now forward the result from firebase_ml_vision for onResult ## [1.5.0] - 24/04/2019 * fix installation problems * Expose camera value ## [1.4.0] - 24/04/2019 * add cameraLensDirection parameter (this default to back) ## [1.3.0] - 17/04/2019 * add overlayBuilder parameter ## [1.2.0] - 12/04/2019 * fix crash above android api 21. * fix pause when a new route is pushed. ## [1.1.0] - 11/04/2019 * Allow usage under android api 21. * Add error type on error builder. ## [1.0.0] - 10/04/2019 * Initial release. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 Rushio Consulting Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Flutter Camera Ml Vision [![pub package](https://img.shields.io/pub/v/flutter_camera_ml_vision.svg)](https://pub.dartlang.org/packages/flutter_camera_ml_vision) A Flutter package for iOS and Android to show a preview of the camera and detect things with Firebase ML Vision. ## Installation First, add `flutter_camera_ml_vision` as a dependency. ```yaml ... dependencies: flutter: sdk: flutter flutter_camera_ml_vision: ^2.2.4 ... ``` ## Configure Firebase You must also configure Firebase for each platform project: Android and iOS (see the `example` folder or https://firebase.google.com/codelabs/firebase-get-to-know-flutter#3 for step by step details). ### iOS Add two rows to the ios/Runner/Info.plist: * one with the key Privacy - Camera Usage Description and a usage description. * and one with the key Privacy - Microphone Usage Description and a usage description. Or in text format add the key: ``` NSCameraUsageDescription Can I use the camera please? NSMicrophoneUsageDescription Can I use the mic please? ``` If you're using one of the on-device APIs, include the corresponding ML Kit library model in your Podfile. Then run pod update in a terminal within the same directory as your Podfile. ``` pod 'Firebase/MLVisionBarcodeModel' pod 'Firebase/MLVisionFaceModel' pod 'Firebase/MLVisionLabelModel' pod 'Firebase/MLVisionTextModel' ``` ### Android Change the minimum Android sdk version to 21 (or higher) in your `android/app/build.gradle` file. ``` minSdkVersion 21 ``` _ps: This is due to the dependency on the camera plugin._ If you're using the on-device `LabelDetector`, include the latest matching [ML Kit: Image Labeling](https://firebase.google.com/support/release-notes/android) dependency in your app-level `build.gradle` file. ```gradle android { dependencies { // ... api 'com.google.firebase:firebase-ml-vision-image-label-model:19.0.0' } } ``` If you receive compilation errors, try an earlier version of [ML Kit: Image Labeling](https://firebase.google.com/support/release-notes/android). Optional but recommended: If you use the on-device API, configure your app to automatically download the ML model to the device after your app is installed from the Play Store. To do so, add the following declaration to your app's `AndroidManifest.xml` file: ```xml ... ``` ## Usage ### 1. Example with Barcode ```dart CameraMlVision>( detector: FirebaseVision.instance.barcodeDetector().detectInImage, onResult: (List barcodes) { if (!mounted || resultSent) { return; } resultSent = true; Navigator.of(context).pop(barcodes.first); }, ) ``` `CameraMlVision` is a widget that shows the preview of the camera. It takes a detector as a parameter here we pass the `detectInImage` method of the `BarcodeDetector` object. The detector parameter can take all the different FirebaseVision Detector. Here is a list : ``` FirebaseVision.instance.barcodeDetector().detectInImage FirebaseVision.instance.cloudLabelDetector().detectInImage FirebaseVision.instance.faceDetector().processImage FirebaseVision.instance.labelDetector().detectInImage FirebaseVision.instance.textRecognizer().processImage ``` Then when something is detected the onResult callback is called with the data in the parameter of the function. ### Exposed functionality from CameraController We expose some functionality from the CameraController class here a list of these : - value - prepareForVideoRecording - startVideoRecording - stopVideoRecording - takePicture ## Getting Started See the `example` directory for a complete sample app. ## Features and bugs Please file feature requests and bugs at the [issue tracker](https://github.com/santetis/flutter_camera_ml_vision/issues). ## Technical Support For any technical support, don't hesitate to contact us. Find more information in our [website](https://rushio-consulting.fr) For now, all the issues with the label `support` mean that they come out of the scope of the following project. So you can [contact us](https://rushio-consulting.fr/support) as a support. ================================================ FILE: analysis_options.yaml ================================================ include: package:pedantic/analysis_options.yaml ================================================ FILE: example/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ # IntelliJ related *.iml *.ipr *.iws .idea/ # Visual Studio Code related .vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins .packages .pub-cache/ .pub/ /build/ # Android related **/android/**/gradle-wrapper.jar **/android/.gradle **/android/captures/ **/android/gradlew **/android/gradlew.bat **/android/local.properties **/android/**/GeneratedPluginRegistrant.java # iOS/XCode related **/ios/**/*.mode1v3 **/ios/**/*.mode2v3 **/ios/**/*.moved-aside **/ios/**/*.pbxuser **/ios/**/*.perspectivev3 **/ios/**/*sync/ **/ios/**/.sconsign.dblite **/ios/**/.tags* **/ios/**/.vagrant/ **/ios/**/DerivedData/ **/ios/**/Icon? **/ios/**/Pods/ **/ios/**/.symlinks/ **/ios/**/profile **/ios/**/xcuserdata **/ios/.generated/ **/ios/Flutter/App.framework **/ios/Flutter/Flutter.framework **/ios/Flutter/Generated.xcconfig **/ios/Flutter/app.flx **/ios/Flutter/app.zip **/ios/Flutter/flutter_assets/ **/ios/ServiceDefinitions.json **/ios/Runner/GeneratedPluginRegistrant.* # Exceptions to above rules. !**/ios/**/default.mode1v3 !**/ios/**/default.mode2v3 !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages /ios/GoogleService-Info.plist /.flutter-plugins-dependencies ================================================ FILE: example/.metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713 channel: stable project_type: app ================================================ FILE: example/README.md ================================================ ```dart import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/material.dart'; import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { List data = []; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ RaisedButton( child: Text('Scan product'), onPressed: () async { final barcode = await Navigator.of(context).push( MaterialPageRoute( builder: (c) { return ScanPage(); }, ), ); if (barcode == null) { return; } setState(() { data.add(barcode.displayValue); }); }, ), Expanded( child: ListView( children: data.map((d) => Text(d)).toList(), ), ), ], ), // This trailing comma makes auto-formatting nicer for build methods. ); } } class ScanPage extends StatefulWidget { @override _ScanPageState createState() => _ScanPageState(); } class _ScanPageState extends State { bool resultSent = false; @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: SizedBox( width: MediaQuery.of(context).size.width, child: CameraMlVision>( detector: FirebaseVision.instance.barcodeDetector().detectInImage, onResult: (List barcodes) { if (!mounted || resultSent) { return; } resultSent = true; Navigator.of(context).pop(barcodes.first); }, ), ), ), ); } } ``` ================================================ FILE: example/android/app/build.gradle ================================================ def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { flutterVersionName = '1.0' } apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 28 lintOptions { disable 'InvalidPackage' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "fr.rushioconsulting.flutter_camera_ml_vision_example" minSdkVersion 21 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug } } } flutter { source '../..' } dependencies { api 'com.google.firebase:firebase-ml-vision-barcode-model:16.1.2' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } apply plugin: 'com.google.gms.google-services' ================================================ FILE: example/android/app/src/debug/AndroidManifest.xml ================================================ ================================================ FILE: example/android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: example/android/app/src/main/java/fr/rushioconsulting/flutter_camera_ml_vision_example/MainActivity.java ================================================ package fr.rushioconsulting.flutter_camera_ml_vision_example; import android.os.Bundle; import io.flutter.app.FlutterActivity; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); } } ================================================ FILE: example/android/app/src/main/res/drawable/launch_background.xml ================================================ ================================================ FILE: example/android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: example/android/app/src/profile/AndroidManifest.xml ================================================ ================================================ FILE: example/android/build.gradle ================================================ buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:4.1.3' classpath 'com.google.gms:google-services:4.3.5' } } allprojects { repositories { google() jcenter() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { project.evaluationDependsOn(':app') } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: example/android/gradle/wrapper/gradle-wrapper.properties ================================================ #Thu Apr 15 16:29:32 CEST 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip ================================================ FILE: example/android/gradle.properties ================================================ org.gradle.jvmargs=-Xmx1536M android.enableJetifier=true android.useAndroidX=true android.enableR8=true ================================================ FILE: example/android/settings.gradle ================================================ include ':app' def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() def plugins = new Properties() def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') if (pluginsFile.exists()) { pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } } plugins.each { name, path -> def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() include ":$name" project(":$name").projectDir = pluginDirectory } ================================================ FILE: example/ios/Flutter/AppFrameworkInfo.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable App CFBundleIdentifier io.flutter.flutter.app CFBundleInfoDictionaryVersion 6.0 CFBundleName App CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 MinimumOSVersion 8.0 ================================================ FILE: example/ios/Flutter/Debug.xcconfig ================================================ #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" ================================================ FILE: example/ios/Flutter/Release.xcconfig ================================================ #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" ================================================ FILE: example/ios/Podfile ================================================ # Uncomment this line to define a global platform for your project platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } def flutter_root generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) unless File.exist?(generated_xcode_build_settings_path) raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end File.foreach(generated_xcode_build_settings_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/) return matches[1].strip if matches end raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) flutter_ios_podfile_setup target 'Runner' do flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) # because of issue https://github.com/FirebaseExtended/flutterfire/issues/4625#issuecomment-821792539 # need custom git version until it's done pod 'FirebaseMLVisionBarcodeModel', '0.21', :source => 'git@github.com:rozdonmobile/CocoaPodsSpecs.git' end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) end end ================================================ FILE: example/ios/Runner/AppDelegate.h ================================================ #import #import @interface AppDelegate : FlutterAppDelegate @end ================================================ FILE: example/ios/Runner/AppDelegate.m ================================================ #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end ================================================ FILE: example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "20x20", "idiom" : "iphone", "filename" : "Icon-App-20x20@3x.png", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-App-29x29@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-App-40x40@3x.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-App-60x60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-App-60x60@3x.png", "scale" : "3x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-App-20x20@1x.png", "scale" : "1x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-App-40x40@1x.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-App-76x76@1x.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-App-76x76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" }, { "size" : "1024x1024", "idiom" : "ios-marketing", "filename" : "Icon-App-1024x1024@1x.png", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "LaunchImage.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "LaunchImage@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "LaunchImage@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md ================================================ # Launch Screen Assets You can customize the launch screen with your own desired assets by replacing the image files in this directory. You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. ================================================ FILE: example/ios/Runner/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: example/ios/Runner/Base.lproj/Main.storyboard ================================================ ================================================ FILE: example/ios/Runner/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName flutter_camera_ml_vision_example CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion $(FLUTTER_BUILD_NUMBER) FirebaseScreenReportingEnabled LSRequiresIPhoneOS NSCameraUsageDescription What do you think ;) UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance ================================================ FILE: example/ios/Runner/main.m ================================================ #import #import #import "AppDelegate.h" int main(int argc, char* argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: example/ios/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 9B3F00512A092EB63507600C /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE99F0092DC98CB10C7128A7 /* libPods-Runner.a */; }; BD05840B228E98DD00D7684A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BD05840A228E98DD00D7684A /* GoogleService-Info.plist */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2409E7A613325A687028AE0F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BD05840A228E98DD00D7684A /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; CE99F0092DC98CB10C7128A7 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F51EA479259F9D93D435315C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; FDC4259C7A63125CD0C3D54C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 9B3F00512A092EB63507600C /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 5BABECA882D889E73F189ACB /* Pods */ = { isa = PBXGroup; children = ( FDC4259C7A63125CD0C3D54C /* Pods-Runner.debug.xcconfig */, 2409E7A613325A687028AE0F /* Pods-Runner.release.xcconfig */, F51EA479259F9D93D435315C /* Pods-Runner.profile.xcconfig */, ); name = Pods; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, ); name = Flutter; sourceTree = ""; }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 5BABECA882D889E73F189ACB /* Pods */, F7B13BC660916DD00ED1C090 /* Frameworks */, ); sourceTree = ""; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, ); name = Products; sourceTree = ""; }; 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( BD05840A228E98DD00D7684A /* GoogleService-Info.plist */, 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, ); path = Runner; sourceTree = ""; }; 97C146F11CF9000F007C117D /* Supporting Files */ = { isa = PBXGroup; children = ( 97C146F21CF9000F007C117D /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; F7B13BC660916DD00ED1C090 /* Frameworks */ = { isa = PBXGroup; children = ( CE99F0092DC98CB10C7128A7 /* libPods-Runner.a */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( F343DCC5B5CF7B2EC0AA5D44 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, ); buildRules = ( ); dependencies = ( ); name = Runner; productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0910; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; DevelopmentTeam = A9C4HVFYJX; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, en, Base, ); mainGroup = 97C146E51CF9000F007C117D; productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, BD05840B228E98DD00D7684A /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; F343DCC5B5CF7B2EC0AA5D44 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 97C146F31CF9000F007C117D /* main.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 97C146FB1CF9000F007C117D /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 97C147001CF9000F007C117D /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Profile; }; 249021D4217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = A9C4HVFYJX; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = "fr.rushioconsulting.flutter-camera-ml-vision-example"; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 97C147061CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = A9C4HVFYJX; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = "fr.rushioconsulting.flutter-camera-ml-vision-example"; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 97C147071CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = A9C4HVFYJX; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); PRODUCT_BUNDLE_IDENTIFIER = "fr.rushioconsulting.flutter-camera-ml-vision-example"; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } ================================================ FILE: example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: example/ios/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: example/lib/main.dart ================================================ import 'dart:ui'; import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/material.dart'; import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { List data = []; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ ElevatedButton( onPressed: () async { final barcode = await Navigator.of(context).push( MaterialPageRoute( builder: (c) { return ScanPage(); }, ), ); if (barcode == null) { return; } setState(() { data.add(barcode.displayValue); }); }, child: Text('Scan product'), ), Expanded( child: ListView( children: data.map((d) => Text(d)).toList(), ), ), ], ), // This trailing comma makes auto-formatting nicer for build methods. ); } } class ScanPage extends StatefulWidget { @override _ScanPageState createState() => _ScanPageState(); } class _ScanPageState extends State { bool resultSent = false; BarcodeDetector detector = FirebaseVision.instance.barcodeDetector(); @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: SizedBox( width: MediaQuery.of(context).size.width, child: CameraMlVision>( overlayBuilder: (c) { return Container( decoration: ShapeDecoration( shape: _ScannerOverlayShape( borderColor: Theme.of(context).primaryColor, borderWidth: 3.0, ), ), ); }, detector: detector.detectInImage, onResult: (List barcodes) { if (!mounted || resultSent || barcodes == null || barcodes.isEmpty) { return; } resultSent = true; Navigator.of(context).pop(barcodes.first); }, onDispose: () { detector.close(); }, ), ), ), ); } } class _ScannerOverlayShape extends ShapeBorder { final Color borderColor; final double borderWidth; final Color overlayColor; _ScannerOverlayShape({ this.borderColor = Colors.white, this.borderWidth = 1.0, this.overlayColor = const Color(0x88000000), }); @override EdgeInsetsGeometry get dimensions => EdgeInsets.all(10.0); @override Path getInnerPath(Rect rect, {TextDirection textDirection}) { return Path() ..fillType = PathFillType.evenOdd ..addPath(getOuterPath(rect), Offset.zero); } @override Path getOuterPath(Rect rect, {TextDirection textDirection}) { Path _getLeftTopPath(Rect rect) { return Path() ..moveTo(rect.left, rect.bottom) ..lineTo(rect.left, rect.top) ..lineTo(rect.right, rect.top); } return _getLeftTopPath(rect) ..lineTo( rect.right, rect.bottom, ) ..lineTo( rect.left, rect.bottom, ) ..lineTo( rect.left, rect.top, ); } @override void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) { const lineSize = 30; final width = rect.width; final borderWidthSize = width * 10 / 100; final height = rect.height; final borderHeightSize = height - (width - borderWidthSize); final borderSize = Size(borderWidthSize / 2, borderHeightSize / 2); var paint = Paint() ..color = overlayColor ..style = PaintingStyle.fill; canvas ..drawRect( Rect.fromLTRB( rect.left, rect.top, rect.right, borderSize.height + rect.top), paint, ) ..drawRect( Rect.fromLTRB(rect.left, rect.bottom - borderSize.height, rect.right, rect.bottom), paint, ) ..drawRect( Rect.fromLTRB(rect.left, rect.top + borderSize.height, rect.left + borderSize.width, rect.bottom - borderSize.height), paint, ) ..drawRect( Rect.fromLTRB( rect.right - borderSize.width, rect.top + borderSize.height, rect.right, rect.bottom - borderSize.height), paint, ); paint = Paint() ..color = borderColor ..style = PaintingStyle.stroke ..strokeWidth = borderWidth; final borderOffset = borderWidth / 2; final realReact = Rect.fromLTRB( borderSize.width + borderOffset, borderSize.height + borderOffset + rect.top, width - borderSize.width - borderOffset, height - borderSize.height - borderOffset + rect.top); //Draw top right corner canvas ..drawPath( Path() ..moveTo(realReact.right, realReact.top) ..lineTo(realReact.right, realReact.top + lineSize), paint) ..drawPath( Path() ..moveTo(realReact.right, realReact.top) ..lineTo(realReact.right - lineSize, realReact.top), paint) ..drawPoints( PointMode.points, [Offset(realReact.right, realReact.top)], paint, ) //Draw top left corner ..drawPath( Path() ..moveTo(realReact.left, realReact.top) ..lineTo(realReact.left, realReact.top + lineSize), paint) ..drawPath( Path() ..moveTo(realReact.left, realReact.top) ..lineTo(realReact.left + lineSize, realReact.top), paint) ..drawPoints( PointMode.points, [Offset(realReact.left, realReact.top)], paint, ) //Draw bottom right corner ..drawPath( Path() ..moveTo(realReact.right, realReact.bottom) ..lineTo(realReact.right, realReact.bottom - lineSize), paint) ..drawPath( Path() ..moveTo(realReact.right, realReact.bottom) ..lineTo(realReact.right - lineSize, realReact.bottom), paint) ..drawPoints( PointMode.points, [Offset(realReact.right, realReact.bottom)], paint, ) //Draw bottom left corner ..drawPath( Path() ..moveTo(realReact.left, realReact.bottom) ..lineTo(realReact.left, realReact.bottom - lineSize), paint) ..drawPath( Path() ..moveTo(realReact.left, realReact.bottom) ..lineTo(realReact.left + lineSize, realReact.bottom), paint) ..drawPoints( PointMode.points, [Offset(realReact.left, realReact.bottom)], paint, ); } @override ShapeBorder scale(double t) { return _ScannerOverlayShape( borderColor: borderColor, borderWidth: borderWidth, overlayColor: overlayColor, ); } } ================================================ FILE: example/lib/main_face.dart ================================================ import 'package:camera/camera.dart'; import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/material.dart'; import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { List _faces = []; final _scanKey = GlobalKey(); CameraLensDirection cameraLensDirection = CameraLensDirection.front; FaceDetector detector = FirebaseVision.instance.faceDetector(FaceDetectorOptions( enableTracking: true, mode: FaceDetectorMode.accurate, )); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: SizedBox.expand( child: CameraMlVision>( key: _scanKey, cameraLensDirection: cameraLensDirection, detector: detector.processImage, overlayBuilder: (c) { return CustomPaint( painter: FaceDetectorPainter( _scanKey.currentState.cameraValue.previewSize.flipped, _faces, reflection: cameraLensDirection == CameraLensDirection.front), ); }, onResult: (faces) { if (faces == null || faces.isEmpty || !mounted) { return; } setState(() { _faces = [...faces]; }); }, onDispose: () { detector.close(); }, ), ), ); } } class FaceDetectorPainter extends CustomPainter { FaceDetectorPainter(this.imageSize, this.faces, {this.reflection = false}); final bool reflection; final Size imageSize; final List faces; @override void paint(Canvas canvas, Size size) { final paint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 2.0 ..color = Colors.red; for (final face in faces) { final faceRect = _reflectionRect(reflection, face.boundingBox, imageSize.width); canvas.drawRect( _scaleRect( rect: faceRect, imageSize: imageSize, widgetSize: size, ), paint, ); } } @override bool shouldRepaint(FaceDetectorPainter oldDelegate) { return oldDelegate.imageSize != imageSize || oldDelegate.faces != faces; } } Rect _reflectionRect(bool reflection, Rect boundingBox, double width) { if (!reflection) { return boundingBox; } final centerX = width / 2; final left = ((boundingBox.left - centerX) * -1) + centerX; final right = ((boundingBox.right - centerX) * -1) + centerX; return Rect.fromLTRB(left, boundingBox.top, right, boundingBox.bottom); } Rect _scaleRect({ @required Rect rect, @required Size imageSize, @required Size widgetSize, }) { final scaleX = widgetSize.width / imageSize.width; final scaleY = widgetSize.height / imageSize.height; final scaledRect = Rect.fromLTRB( rect.left.toDouble() * scaleX, rect.top.toDouble() * scaleY, rect.right.toDouble() * scaleX, rect.bottom.toDouble() * scaleY, ); return scaledRect; } ================================================ FILE: example/lib/main_live.dart ================================================ import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/material.dart'; import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { List data = []; final _scanKey = GlobalKey(); BarcodeDetector detector = FirebaseVision.instance.barcodeDetector(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Stack( fit: StackFit.expand, children: [ CameraMlVision>( key: _scanKey, detector: detector.detectInImage, resolution: ResolutionPreset.high, onResult: (barcodes) { if (barcodes == null || barcodes.isEmpty || data.contains(barcodes.first.displayValue) || !mounted) { return; } setState(() { data.add(barcodes.first.displayValue); }); }, onDispose: () { detector.close(); }, ), Container( alignment: Alignment.bottomCenter, child: Column( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: ConstrainedBox( constraints: BoxConstraints(maxHeight: 250), child: Scrollbar( child: ListView( children: data.map((d) { return Container( color: Color(0xAAFFFFFF), child: Padding( padding: const EdgeInsets.all(16), child: Text(d), ), ); }).toList(), ), ), ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: () { _scanKey.currentState.toggle(); }, child: Text('Start/Pause camera'), ), ElevatedButton( onPressed: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => _SecondScreen())); }, child: Text('Push new route'), ), ], ), ], ), ), ], ), // This trailing comma makes auto-formatting nicer for build methods. ); } } class _SecondScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: ElevatedButton( onPressed: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => _SecondScreen(), )); }, child: Text('Push new route'), ), ); } } ================================================ FILE: example/pubspec.yaml ================================================ name: example description: A new Flutter project. # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 environment: sdk: ">=2.2.2 <3.0.0" dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.3 flutter_camera_ml_vision: path: ../ dev_dependencies: flutter_test: sdk: flutter # For information on the generic Dart part of this file, see the # following page: https://www.dartlang.org/tools/pub/pubspec # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see # https://flutter.io/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.io/custom-fonts/#from-packages ================================================ FILE: example/test/widget_test.dart ================================================ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester // utility that Flutter provides. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. // import 'package:flutter/material.dart'; // import 'package:flutter_test/flutter_test.dart'; // import 'package:example/main.dart'; // void main() { // testWidgets('Counter increments smoke test', (WidgetTester tester) async { // // Build our app and trigger a frame. // await tester.pumpWidget(MyApp()); // // Verify that our counter starts at 0. // expect(find.text('0'), findsOneWidget); // expect(find.text('1'), findsNothing); // // Tap the '+' icon and trigger a frame. // await tester.tap(find.byIcon(Icons.add)); // await tester.pump(); // // Verify that our counter has incremented. // expect(find.text('0'), findsNothing); // expect(find.text('1'), findsOneWidget); // }); // } ================================================ FILE: flutter_camera_ml_vision.iml ================================================ ================================================ FILE: lib/flutter_camera_ml_vision.dart ================================================ library flutter_camera_ml_vision; import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; import 'dart:ui'; import 'package:camera/camera.dart'; import 'package:collection/collection.dart'; import 'package:device_info/device_info.dart'; import 'package:firebase_ml_vision/firebase_ml_vision.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:visibility_detector/visibility_detector.dart'; export 'package:camera/camera.dart'; part 'utils.dart'; typedef HandleDetection = Future Function(FirebaseVisionImage image); typedef ErrorWidgetBuilder = Widget Function( BuildContext context, CameraError error); enum CameraError { unknown, cantInitializeCamera, androidVersionNotSupported, noCameraAvailable, } enum _CameraState { loading, error, ready, } class CameraMlVision extends StatefulWidget { final HandleDetection detector; final Function(T) onResult; final WidgetBuilder? loadingBuilder; final ErrorWidgetBuilder? errorBuilder; final WidgetBuilder? overlayBuilder; final CameraLensDirection cameraLensDirection; final ResolutionPreset? resolution; final Function? onDispose; CameraMlVision({ Key? key, required this.onResult, required this.detector, this.loadingBuilder, this.errorBuilder, this.overlayBuilder, this.cameraLensDirection = CameraLensDirection.back, this.resolution, this.onDispose, }) : super(key: key); @override CameraMlVisionState createState() => CameraMlVisionState(); } class CameraMlVisionState extends State> with WidgetsBindingObserver { XFile? _lastImage; final _visibilityKey = UniqueKey(); CameraController? _cameraController; ImageRotation? _rotation; _CameraState _cameraMlVisionState = _CameraState.loading; CameraError _cameraError = CameraError.unknown; bool _alreadyCheckingImage = false; bool _isStreaming = false; bool _isDeactivate = false; @override void initState() { super.initState(); WidgetsBinding.instance!.addObserver(this); _initialize(); } @override void didUpdateWidget(CameraMlVision oldWidget) { if (oldWidget.resolution != widget.resolution) { _initialize(); } super.didUpdateWidget(oldWidget); } @override void didChangeAppLifecycleState(AppLifecycleState state) { // App state changed before we got the chance to initialize. if (_cameraController == null || !_cameraController!.value.isInitialized) { return; } if (state == AppLifecycleState.inactive) { _stop(true).then((value) => _cameraController?.dispose()); } else if (state == AppLifecycleState.resumed && _isStreaming) { _initialize(); } } Future stop() async { if (_cameraController != null) { await _stop(true); try { final image = await _cameraController!.takePicture(); setState(() { _lastImage = image; }); } on PlatformException catch (e) { debugPrint('$e'); } } } Future _stop(bool silently) { final completer = Completer(); scheduleMicrotask(() async { if (_cameraController?.value.isStreamingImages == true && mounted) { await _cameraController!.stopImageStream().catchError((_) {}); } if (silently) { _isStreaming = false; } else { setState(() { _isStreaming = false; }); } completer.complete(); }); return completer.future; } void start() { if (_cameraController != null) { _start(); } } void _start() { _cameraController!.startImageStream(_processImage); setState(() { _isStreaming = true; }); } CameraValue? get cameraValue => _cameraController?.value; ImageRotation? get imageRotation => _rotation; Future Function() get prepareForVideoRecording => _cameraController!.prepareForVideoRecording; Future startVideoRecording() async { await _cameraController!.stopImageStream(); return _cameraController!.startVideoRecording(); } Future stopVideoRecording(String path) async { final file = await _cameraController!.stopVideoRecording(); await _cameraController!.startImageStream(_processImage); return file; } CameraController? get cameraController => _cameraController; Future takePicture(String path) async { await _stop(true); final image = await _cameraController!.takePicture(); _start(); return image; } Future flash(FlashMode mode) async { await _cameraController!.setFlashMode(mode); } Future focus(FocusMode mode) async { await _cameraController!.setFocusMode(mode); } Future focusPoint(Offset point) async { await _cameraController!.setFocusPoint(point); } Future zoom(double zoom) async { await _cameraController!.setZoomLevel(zoom); } Future exposure(ExposureMode mode) async { await _cameraController!.setExposureMode(mode); } Future exposureOffset(double offset) async { await _cameraController!.setExposureOffset(offset); } Future exposurePoint(Offset offset) async { await _cameraController!.setExposurePoint(offset); } Future _initialize() async { if (Platform.isAndroid) { final deviceInfo = DeviceInfoPlugin(); final androidInfo = await deviceInfo.androidInfo; if (androidInfo.version.sdkInt < 21) { debugPrint('Camera plugin doesn\'t support android under version 21'); if (mounted) { setState(() { _cameraMlVisionState = _CameraState.error; _cameraError = CameraError.androidVersionNotSupported; }); } return; } } final description = await _getCamera(widget.cameraLensDirection); if (description == null) { _cameraMlVisionState = _CameraState.error; _cameraError = CameraError.noCameraAvailable; return; } if (_cameraController != null) { await _stop(true); await _cameraController?.dispose(); } _cameraController = CameraController( description, widget.resolution ?? ResolutionPreset.high, enableAudio: false, ); if (!mounted) { return; } try { await _cameraController!.initialize(); } catch (ex, stack) { debugPrint('Can\'t initialize camera'); debugPrint('$ex, $stack'); if (mounted) { setState(() { _cameraMlVisionState = _CameraState.error; _cameraError = CameraError.cantInitializeCamera; }); } return; } if (!mounted) { return; } setState(() { _cameraMlVisionState = _CameraState.ready; }); _rotation = _rotationIntToImageRotation( description.sensorOrientation, ); //FIXME hacky technique to avoid having black screen on some android devices await Future.delayed(Duration(milliseconds: 200)); start(); } @override void dispose() { if (widget.onDispose != null) { widget.onDispose!(); } if (_cameraController != null) { _stop(true).then((value) { _cameraController?.dispose(); }); } super.dispose(); } @override Widget build(BuildContext context) { if (_cameraMlVisionState == _CameraState.loading) { return widget.loadingBuilder == null ? Center(child: CircularProgressIndicator()) : widget.loadingBuilder!(context); } if (_cameraMlVisionState == _CameraState.error) { return widget.errorBuilder == null ? Center(child: Text('$_cameraMlVisionState $_cameraError')) : widget.errorBuilder!(context, _cameraError); } var cameraPreview = _isStreaming ? CameraPreview( _cameraController!, ) : _getPicture(); if (widget.overlayBuilder != null) { cameraPreview = Stack( fit: StackFit.passthrough, children: [ cameraPreview, (cameraController?.value.isInitialized ?? false) ? AspectRatio( aspectRatio: _isLandscape() ? cameraController!.value.aspectRatio : (1 / cameraController!.value.aspectRatio), child: widget.overlayBuilder!(context), ) : Container(), ], ); } return VisibilityDetector( onVisibilityChanged: (VisibilityInfo info) { if (info.visibleFraction == 0) { //invisible stop the streaming _isDeactivate = true; _stop(true); } else if (_isDeactivate) { //visible restart streaming if needed _isDeactivate = false; _start(); } }, key: _visibilityKey, child: cameraPreview, ); } DeviceOrientation? _getApplicableOrientation() { return (cameraController?.value.isRecordingVideo ?? false) ? cameraController?.value.recordingOrientation : (cameraController?.value.lockedCaptureOrientation ?? cameraController?.value.deviceOrientation); } bool _isLandscape() { return [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight] .contains(_getApplicableOrientation()); } void _processImage(CameraImage cameraImage) async { if (!_alreadyCheckingImage && mounted) { _alreadyCheckingImage = true; try { final results = await _detect(cameraImage, widget.detector, _rotation!); widget.onResult(results); } catch (ex, stack) { debugPrint('$ex, $stack'); } _alreadyCheckingImage = false; } } void toggle() { if (_isStreaming && _cameraController!.value.isStreamingImages) { stop(); } else { start(); } } Widget _getPicture() { if (_lastImage != null) { return Image.file(File(_lastImage!.path)); } return Container(); } } ================================================ FILE: lib/utils.dart ================================================ part of 'flutter_camera_ml_vision.dart'; Future _getCamera(CameraLensDirection dir) async { final cameras = await availableCameras(); final camera = cameras.firstWhereOrNull((camera) => camera.lensDirection == dir); return camera ?? (cameras.isEmpty ? null : cameras.first); } Uint8List _concatenatePlanes(List planes) { final allBytes = WriteBuffer(); planes.forEach((plane) => allBytes.putUint8List(plane.bytes)); return allBytes.done().buffer.asUint8List(); } FirebaseVisionImageMetadata buildMetaData( CameraImage image, ImageRotation rotation, ) { return FirebaseVisionImageMetadata( rawFormat: image.format.raw, size: Size(image.width.toDouble(), image.height.toDouble()), rotation: rotation, planeData: image.planes .map( (plane) => FirebaseVisionImagePlaneMetadata( bytesPerRow: plane.bytesPerRow, height: plane.height, width: plane.width, ), ) .toList(), ); } Future _detect( CameraImage image, HandleDetection handleDetection, ImageRotation rotation, ) async { return handleDetection( FirebaseVisionImage.fromBytes( _concatenatePlanes(image.planes), buildMetaData(image, rotation), ), ); } ImageRotation _rotationIntToImageRotation(int rotation) { switch (rotation) { case 0: return ImageRotation.rotation0; case 90: return ImageRotation.rotation90; case 180: return ImageRotation.rotation180; default: assert(rotation == 270); return ImageRotation.rotation270; } } ================================================ FILE: pubspec.yaml ================================================ name: flutter_camera_ml_vision description: A flutter widget that show the camera stream and allow ML vision recognition on it, it allow you to detect barcodes, labels, text, faces... version: 3.0.1 repository: https://github.com/rushio-consulting/flutter_camera_ml_vision homepage: https://github.com/rushio-consulting/flutter_camera_ml_vision environment: sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter firebase_ml_vision: ^0.12.0+1 #git: # url: git://github.com/algirdasmac/flutterfire # path: packages/firebase_ml_vision firebase_core: ^1.1.0 visibility_detector: ^0.2.0 path_provider: ^2.0.1 pedantic: ^1.11.0 device_info: ^2.0.0 camera: ^0.8.1 collection: ^1.15.0 dev_dependencies: flutter_test: sdk: flutter ================================================ FILE: test/flutter_camera_ml_vision_test.dart ================================================ // import 'package:flutter_test/flutter_test.dart'; // import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart'; void main() {}