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
[](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() {}