├── LICENSE ├── README.md ├── android ├── app │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── io │ │ │ └── flutter │ │ │ └── plugins │ │ │ └── GeneratedPluginRegistrant.java │ │ ├── kotlin │ │ └── waynelu │ │ │ └── flutterocr │ │ │ └── MainActivity.kt │ │ └── res │ │ ├── drawable │ │ └── launch_background.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties └── settings.gradle ├── flutter_ocr.iml ├── flutter_ocr_android.iml ├── fonts └── Imgcrop.ttf ├── images ├── bottomLeft.png ├── bottomRight.png ├── demo1.jpg ├── demo2.jpg ├── demo3.jpg ├── demo4.jpg ├── topLeft.png └── topRight.png ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Generated.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── GeneratedPluginRegistrant.h │ ├── GeneratedPluginRegistrant.m │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── image_page.dart ├── imgcrop_icons.dart ├── main.dart ├── result_page.dart ├── rotatescale.dart └── text_list.dart └── pubspec.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_ocr 2 | 3 | flutter_ocr是用flutter开发的使用百度api进行文字识别的拍照取字软件。 4 | 5 | 包含了拍照,旋转,放大,拖拽来选取合适的大小和角度来截取要识别的图片内容。 6 | 7 | 8 | 9 | 10 | 11 | ## Getting Started 12 | 13 | For help getting started with Flutter, view our online 14 | [documentation](https://flutter.io/). 15 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 27 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "waynelu.flutterocr" 42 | minSdkVersion 21 43 | targetSdkVersion 27 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 66 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 67 | } 68 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import io.flutter.plugin.common.PluginRegistry; 4 | import io.flutter.plugins.camera.CameraPlugin; 5 | import io.flutter.plugins.imagepicker.ImagePickerPlugin; 6 | import io.flutter.plugins.pathprovider.PathProviderPlugin; 7 | import io.flutter.plugins.videoplayer.VideoPlayerPlugin; 8 | 9 | /** 10 | * Generated file. Do not edit. 11 | */ 12 | public final class GeneratedPluginRegistrant { 13 | public static void registerWith(PluginRegistry registry) { 14 | if (alreadyRegisteredWith(registry)) { 15 | return; 16 | } 17 | CameraPlugin.registerWith(registry.registrarFor("io.flutter.plugins.camera.CameraPlugin")); 18 | ImagePickerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.imagepicker.ImagePickerPlugin")); 19 | PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); 20 | VideoPlayerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.videoplayer.VideoPlayerPlugin")); 21 | } 22 | 23 | private static boolean alreadyRegisteredWith(PluginRegistry registry) { 24 | final String key = GeneratedPluginRegistrant.class.getCanonicalName(); 25 | if (registry.hasPlugin(key)) { 26 | return true; 27 | } 28 | registry.registrarFor(key); 29 | return false; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/waynelu/flutterocr/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package waynelu.flutterocr 2 | 3 | import android.os.Bundle 4 | 5 | import io.flutter.app.FlutterActivity 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | GeneratedPluginRegistrant.registerWith(this) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.2.71' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.2.1' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/local.properties: -------------------------------------------------------------------------------- 1 | sdk.dir=/Users/waynelu/Library/Android/sdk 2 | flutter.sdk=/Users/waynelu/flutter 3 | flutter.versionName=1.0.0 4 | flutter.versionCode=1 5 | flutter.buildMode=debug -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /flutter_ocr.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /flutter_ocr_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /fonts/Imgcrop.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/fonts/Imgcrop.ttf -------------------------------------------------------------------------------- /images/bottomLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/bottomLeft.png -------------------------------------------------------------------------------- /images/bottomRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/bottomRight.png -------------------------------------------------------------------------------- /images/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/demo1.jpg -------------------------------------------------------------------------------- /images/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/demo2.jpg -------------------------------------------------------------------------------- /images/demo3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/demo3.jpg -------------------------------------------------------------------------------- /images/demo4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/demo4.jpg -------------------------------------------------------------------------------- /images/topLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/topLeft.png -------------------------------------------------------------------------------- /images/topRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/images/topRight.png -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Generated.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=/Users/waynelu/flutter 3 | FLUTTER_APPLICATION_PATH=/Users/waynelu/q/flutter_ocr 4 | FLUTTER_TARGET=lib/main.dart 5 | FLUTTER_BUILD_MODE=debug 6 | FLUTTER_BUILD_DIR=build 7 | SYMROOT=${SOURCE_ROOT}/../build/ios 8 | FLUTTER_FRAMEWORK_DIR=/Users/waynelu/flutter/bin/cache/artifacts/engine/ios 9 | FLUTTER_BUILD_NAME=1.0.0 10 | FLUTTER_BUILD_NUMBER=1 11 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 16 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 17 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 32 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 33 | ); 34 | name = "Embed Frameworks"; 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 42 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 43 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 44 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 45 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 46 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 48 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 49 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 50 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 51 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 64 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 9740EEB11CF90186004384FC /* Flutter */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 75 | 3B80C3931E831B6300D905FE /* App.framework */, 76 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 77 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 78 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 79 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 80 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 81 | ); 82 | name = Flutter; 83 | sourceTree = ""; 84 | }; 85 | 97C146E51CF9000F007C117D = { 86 | isa = PBXGroup; 87 | children = ( 88 | 9740EEB11CF90186004384FC /* Flutter */, 89 | 97C146F01CF9000F007C117D /* Runner */, 90 | 97C146EF1CF9000F007C117D /* Products */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 97C146EF1CF9000F007C117D /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146EE1CF9000F007C117D /* Runner.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 97C146F01CF9000F007C117D /* Runner */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 106 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 107 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 108 | 97C147021CF9000F007C117D /* Info.plist */, 109 | 97C146F11CF9000F007C117D /* Supporting Files */, 110 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 111 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 112 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 113 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 114 | ); 115 | path = Runner; 116 | sourceTree = ""; 117 | }; 118 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | ); 122 | name = "Supporting Files"; 123 | sourceTree = ""; 124 | }; 125 | /* End PBXGroup section */ 126 | 127 | /* Begin PBXNativeTarget section */ 128 | 97C146ED1CF9000F007C117D /* Runner */ = { 129 | isa = PBXNativeTarget; 130 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 131 | buildPhases = ( 132 | 9740EEB61CF901F6004384FC /* Run Script */, 133 | 97C146EA1CF9000F007C117D /* Sources */, 134 | 97C146EB1CF9000F007C117D /* Frameworks */, 135 | 97C146EC1CF9000F007C117D /* Resources */, 136 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 137 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 138 | ); 139 | buildRules = ( 140 | ); 141 | dependencies = ( 142 | ); 143 | name = Runner; 144 | productName = Runner; 145 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 146 | productType = "com.apple.product-type.application"; 147 | }; 148 | /* End PBXNativeTarget section */ 149 | 150 | /* Begin PBXProject section */ 151 | 97C146E61CF9000F007C117D /* Project object */ = { 152 | isa = PBXProject; 153 | attributes = { 154 | LastUpgradeCheck = 0910; 155 | ORGANIZATIONNAME = "The Chromium Authors"; 156 | TargetAttributes = { 157 | 97C146ED1CF9000F007C117D = { 158 | CreatedOnToolsVersion = 7.3.1; 159 | LastSwiftMigration = 0910; 160 | }; 161 | }; 162 | }; 163 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 164 | compatibilityVersion = "Xcode 3.2"; 165 | developmentRegion = English; 166 | hasScannedForEncodings = 0; 167 | knownRegions = ( 168 | en, 169 | Base, 170 | ); 171 | mainGroup = 97C146E51CF9000F007C117D; 172 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 173 | projectDirPath = ""; 174 | projectRoot = ""; 175 | targets = ( 176 | 97C146ED1CF9000F007C117D /* Runner */, 177 | ); 178 | }; 179 | /* End PBXProject section */ 180 | 181 | /* Begin PBXResourcesBuildPhase section */ 182 | 97C146EC1CF9000F007C117D /* Resources */ = { 183 | isa = PBXResourcesBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 187 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 188 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 189 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 190 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 191 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXResourcesBuildPhase section */ 196 | 197 | /* Begin PBXShellScriptBuildPhase section */ 198 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 199 | isa = PBXShellScriptBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | ); 203 | inputPaths = ( 204 | ); 205 | name = "Thin Binary"; 206 | outputPaths = ( 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | shellPath = /bin/sh; 210 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 211 | }; 212 | 9740EEB61CF901F6004384FC /* Run Script */ = { 213 | isa = PBXShellScriptBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | ); 217 | inputPaths = ( 218 | ); 219 | name = "Run Script"; 220 | outputPaths = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | shellPath = /bin/sh; 224 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 225 | }; 226 | /* End PBXShellScriptBuildPhase section */ 227 | 228 | /* Begin PBXSourcesBuildPhase section */ 229 | 97C146EA1CF9000F007C117D /* Sources */ = { 230 | isa = PBXSourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 234 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | /* End PBXSourcesBuildPhase section */ 239 | 240 | /* Begin PBXVariantGroup section */ 241 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 242 | isa = PBXVariantGroup; 243 | children = ( 244 | 97C146FB1CF9000F007C117D /* Base */, 245 | ); 246 | name = Main.storyboard; 247 | sourceTree = ""; 248 | }; 249 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 250 | isa = PBXVariantGroup; 251 | children = ( 252 | 97C147001CF9000F007C117D /* Base */, 253 | ); 254 | name = LaunchScreen.storyboard; 255 | sourceTree = ""; 256 | }; 257 | /* End PBXVariantGroup section */ 258 | 259 | /* Begin XCBuildConfiguration section */ 260 | 97C147031CF9000F007C117D /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 263 | buildSettings = { 264 | ALWAYS_SEARCH_USER_PATHS = NO; 265 | CLANG_ANALYZER_NONNULL = YES; 266 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 267 | CLANG_CXX_LIBRARY = "libc++"; 268 | CLANG_ENABLE_MODULES = YES; 269 | CLANG_ENABLE_OBJC_ARC = YES; 270 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 271 | CLANG_WARN_BOOL_CONVERSION = YES; 272 | CLANG_WARN_COMMA = YES; 273 | CLANG_WARN_CONSTANT_CONVERSION = YES; 274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INFINITE_RECURSION = YES; 278 | CLANG_WARN_INT_CONVERSION = YES; 279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 282 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 283 | CLANG_WARN_STRICT_PROTOTYPES = YES; 284 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 285 | CLANG_WARN_UNREACHABLE_CODE = YES; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 288 | COPY_PHASE_STRIP = NO; 289 | DEBUG_INFORMATION_FORMAT = dwarf; 290 | ENABLE_STRICT_OBJC_MSGSEND = YES; 291 | ENABLE_TESTABILITY = YES; 292 | GCC_C_LANGUAGE_STANDARD = gnu99; 293 | GCC_DYNAMIC_NO_PIC = NO; 294 | GCC_NO_COMMON_BLOCKS = YES; 295 | GCC_OPTIMIZATION_LEVEL = 0; 296 | GCC_PREPROCESSOR_DEFINITIONS = ( 297 | "DEBUG=1", 298 | "$(inherited)", 299 | ); 300 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 301 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 302 | GCC_WARN_UNDECLARED_SELECTOR = YES; 303 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 304 | GCC_WARN_UNUSED_FUNCTION = YES; 305 | GCC_WARN_UNUSED_VARIABLE = YES; 306 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 307 | MTL_ENABLE_DEBUG_INFO = YES; 308 | ONLY_ACTIVE_ARCH = YES; 309 | SDKROOT = iphoneos; 310 | TARGETED_DEVICE_FAMILY = "1,2"; 311 | }; 312 | name = Debug; 313 | }; 314 | 97C147041CF9000F007C117D /* Release */ = { 315 | isa = XCBuildConfiguration; 316 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 317 | buildSettings = { 318 | ALWAYS_SEARCH_USER_PATHS = NO; 319 | CLANG_ANALYZER_NONNULL = YES; 320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 321 | CLANG_CXX_LIBRARY = "libc++"; 322 | CLANG_ENABLE_MODULES = YES; 323 | CLANG_ENABLE_OBJC_ARC = YES; 324 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 325 | CLANG_WARN_BOOL_CONVERSION = YES; 326 | CLANG_WARN_COMMA = YES; 327 | CLANG_WARN_CONSTANT_CONVERSION = YES; 328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INFINITE_RECURSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 334 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 335 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 337 | CLANG_WARN_STRICT_PROTOTYPES = YES; 338 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 344 | ENABLE_NS_ASSERTIONS = NO; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_NO_COMMON_BLOCKS = YES; 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 355 | MTL_ENABLE_DEBUG_INFO = NO; 356 | SDKROOT = iphoneos; 357 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 358 | TARGETED_DEVICE_FAMILY = "1,2"; 359 | VALIDATE_PRODUCT = YES; 360 | }; 361 | name = Release; 362 | }; 363 | 97C147061CF9000F007C117D /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 366 | buildSettings = { 367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 368 | CLANG_ENABLE_MODULES = YES; 369 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 370 | ENABLE_BITCODE = NO; 371 | FRAMEWORK_SEARCH_PATHS = ( 372 | "$(inherited)", 373 | "$(PROJECT_DIR)/Flutter", 374 | ); 375 | INFOPLIST_FILE = Runner/Info.plist; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 377 | LIBRARY_SEARCH_PATHS = ( 378 | "$(inherited)", 379 | "$(PROJECT_DIR)/Flutter", 380 | ); 381 | PRODUCT_BUNDLE_IDENTIFIER = waynelu.flutterOcr; 382 | PRODUCT_NAME = "$(TARGET_NAME)"; 383 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 384 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 385 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 386 | SWIFT_VERSION = 4.0; 387 | VERSIONING_SYSTEM = "apple-generic"; 388 | }; 389 | name = Debug; 390 | }; 391 | 97C147071CF9000F007C117D /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 394 | buildSettings = { 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 396 | CLANG_ENABLE_MODULES = YES; 397 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 398 | ENABLE_BITCODE = NO; 399 | FRAMEWORK_SEARCH_PATHS = ( 400 | "$(inherited)", 401 | "$(PROJECT_DIR)/Flutter", 402 | ); 403 | INFOPLIST_FILE = Runner/Info.plist; 404 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 405 | LIBRARY_SEARCH_PATHS = ( 406 | "$(inherited)", 407 | "$(PROJECT_DIR)/Flutter", 408 | ); 409 | PRODUCT_BUNDLE_IDENTIFIER = waynelu.flutterOcr; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 412 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 413 | SWIFT_VERSION = 4.0; 414 | VERSIONING_SYSTEM = "apple-generic"; 415 | }; 416 | name = Release; 417 | }; 418 | /* End XCBuildConfiguration section */ 419 | 420 | /* Begin XCConfigurationList section */ 421 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 422 | isa = XCConfigurationList; 423 | buildConfigurations = ( 424 | 97C147031CF9000F007C117D /* Debug */, 425 | 97C147041CF9000F007C117D /* Release */, 426 | ); 427 | defaultConfigurationIsVisible = 0; 428 | defaultConfigurationName = Release; 429 | }; 430 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 431 | isa = XCConfigurationList; 432 | buildConfigurations = ( 433 | 97C147061CF9000F007C117D /* Debug */, 434 | 97C147071CF9000F007C117D /* Release */, 435 | ); 436 | defaultConfigurationIsVisible = 0; 437 | defaultConfigurationName = Release; 438 | }; 439 | /* End XCConfigurationList section */ 440 | }; 441 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 442 | } 443 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luyongfugx/flutter_ocr/0063a2697e691253911f97fc291f4873fda97c98/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | 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. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GeneratedPluginRegistrant_h 6 | #define GeneratedPluginRegistrant_h 7 | 8 | #import 9 | 10 | @interface GeneratedPluginRegistrant : NSObject 11 | + (void)registerWithRegistry:(NSObject*)registry; 12 | @end 13 | 14 | #endif /* GeneratedPluginRegistrant_h */ 15 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.m: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #import "GeneratedPluginRegistrant.h" 6 | #import 7 | #import 8 | #import 9 | #import 10 | 11 | @implementation GeneratedPluginRegistrant 12 | 13 | + (void)registerWithRegistry:(NSObject*)registry { 14 | [CameraPlugin registerWithRegistrar:[registry registrarForPlugin:@"CameraPlugin"]]; 15 | [FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]]; 16 | [FLTPathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPathProviderPlugin"]]; 17 | [FLTVideoPlayerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTVideoPlayerPlugin"]]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_ocr 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /lib/image_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:flutter/gestures.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter/rendering.dart'; 7 | import 'dart:io'; 8 | import 'package:dio/dio.dart'; 9 | import 'dart:math' as math; 10 | import 'dart:async'; 11 | import 'dart:convert'; 12 | import 'dart:isolate'; 13 | import 'dart:ui' as ui; 14 | import 'rotatescale.dart'; 15 | import 'imgcrop_icons.dart'; 16 | import 'result_page.dart'; 17 | import 'package:image/image.dart' as ImageUtil; 18 | class CropPage extends StatefulWidget { 19 | CropPage({Key key, this.title, this.image, this.imageInfo}) : super(key: key); 20 | final String title; 21 | final ui.Image image; 22 | ImageInfo imageInfo; 23 | @override 24 | _CropPageState createState() => new _CropPageState(); 25 | } 26 | 27 | class _CropPageState extends State with SingleTickerProviderStateMixin{ 28 | GlobalKey globalKey = new GlobalKey(); 29 | ui.Image corpImg; 30 | String maskDirection = "center"; 31 | double opacity = 0.5; 32 | double maskTop = 60.0; 33 | double maskLeft = 40.0; 34 | double maskWidth = 0.0; 35 | double maskHeight = 0.0; 36 | double dragStartX = 0.0; 37 | double dragStartY = 0.0; 38 | double imgDragStartX = 0.0; 39 | double imgDragStartY = 0.0; 40 | double imgWidth = 0.0; 41 | double imgHeight = 0.0; 42 | double oldScale = 1.0; 43 | double _scale = 1.0; 44 | double oldRotate = 0.0; 45 | String baiduApi = "https://aip.baidubce.com/oauth/2.0/token?"; 46 | String baiduRestApi = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?"; 47 | String baiduGrantType = "client_credentials"; 48 | String baiduClientId = "";//百度ocr api的 clientId,请自行申请 49 | String baiduClientSecret = "";//百度ocr api的 Secret 50 | 51 | double rotate = 0.0; 52 | Offset topLeft = new Offset(40.0, 60.0); 53 | Matrix4 matrix = new Matrix4.identity(); 54 | GlobalKey imgKey = new GlobalKey(); 55 | AnimationController _controller;//扫描动画 56 | @override 57 | void initState() { 58 | super.initState(); 59 | _controller = new AnimationController( 60 | duration: new Duration(seconds: 3), 61 | vsync: this 62 | ) 63 | ..addListener(() { 64 | this.setState(() {}); 65 | }); 66 | 67 | } 68 | 69 | static decodePng(SendPort sendPort) async { 70 | var port = new ReceivePort(); 71 | sendPort.send(port.sendPort); 72 | // 监听消息 73 | await for (var msg in port) { 74 | var data = msg[0]; 75 | ImageUtil.Image image = ImageUtil.decodePng(data); 76 | SendPort replyTo = msg[1]; 77 | replyTo.send(image); 78 | port.close(); 79 | } 80 | } 81 | /// 对某个port发送消息,并接收结果 82 | Future sendReceive(SendPort port, msg) { 83 | ReceivePort response = new ReceivePort(); 84 | port.send([msg, response.sendPort]); 85 | return response.first; 86 | } 87 | 88 | static encodePng(SendPort sendPort) async { 89 | var port = new ReceivePort(); 90 | sendPort.send(port.sendPort); 91 | // 监听消息 92 | await for (var msg in port) { 93 | var data = msg[0]; 94 | List byteList = ImageUtil.encodePng(data); 95 | SendPort replyTo = msg[1]; 96 | replyTo.send(byteList); 97 | port.close(); 98 | } 99 | // return new Future(() => ImageUtil.encodePng(image)); 100 | } 101 | 102 | Future copyCrop(ImageUtil.Image image,int corpX, int corpY, int corpWidth, int corpHeight) async { 103 | return new Future(() => ImageUtil.copyCrop(image, corpX, corpY, corpWidth, corpHeight)); 104 | } 105 | 106 | Future _capturePng() async { 107 | RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject(); 108 | double pixelRatio = 1.5; 109 | ui.Image image = await boundary.toImage(pixelRatio:pixelRatio); 110 | ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png); 111 | Uint8List pngBytes = byteData.buffer.asUint8List(); 112 | var receivePort = new ReceivePort(); 113 | await Isolate.spawn(decodePng, receivePort.sendPort); 114 | var sendPort = await receivePort.first; 115 | ImageUtil.Image uImage = await sendReceive(sendPort, pngBytes); 116 | int corpX = (maskLeft*pixelRatio).toInt(); 117 | int corpY = (maskTop*pixelRatio).toInt(); 118 | int corpWidth = (maskWidth*pixelRatio).toInt(); 119 | int corpHeight = (maskHeight*pixelRatio).toInt(); 120 | print(uImage.width.toString()+" "+uImage.height.toString()+" "+corpX.toString()+" " +corpY.toString()+" "+corpWidth.toString()+" "+ corpHeight.toString()); 121 | var nImage = await copyCrop(uImage, corpX, corpY, corpWidth, corpHeight); 122 | var receivePort1 = new ReceivePort(); 123 | await Isolate.spawn(encodePng, receivePort1.sendPort); 124 | var sendPort1 = await receivePort1.first; 125 | List byteList = await sendReceive(sendPort1, nImage); 126 | 127 | String base64Image = base64Encode(byteList);//base 64 128 | var codec = await ui.instantiateImageCodec(byteList); 129 | var frame = await codec.getNextFrame(); 130 | 131 | Dio dio = new Dio(); 132 | String tokenUrl = baiduApi+"grant_type="+baiduGrantType+"&client_id="+baiduClientId+"&client_secret="+baiduClientSecret; 133 | 134 | Response response=await dio.post(tokenUrl); 135 | String accessToken = response.data['access_token'].toString(); 136 | String ocrUrl = baiduRestApi+"access_token="+accessToken; 137 | Response res = await dio.post(ocrUrl,data:{"image":base64Image}, options: new Options(contentType:ContentType.parse("application/x-www-form-urlencoded"))); 138 | int wordsNum = int.parse(res.data["words_result_num"].toString()); 139 | print(res.data.toString()); 140 | List ocrContent = new List(); 141 | if(wordsNum>0){ 142 | var array = res.data["words_result"]; 143 | for(var ar in array){ 144 | ocrContent.add(ar["words"].toString()); 145 | // ocrContent += ar["words"].toString()+"\n"; 146 | print(ar["words"].toString()); 147 | } 148 | 149 | } 150 | //if(res.data["words_result_num"]) 151 | //重置 152 | _controller.reset(); 153 | _controller.stop(); 154 | 155 | Navigator.push( 156 | context, 157 | new MaterialPageRoute( 158 | builder: (context) => new ResultPage( 159 | title: 'crop', 160 | ocrContent: ocrContent, 161 | image: frame.image))); 162 | 163 | } 164 | void doCapturePng() async { 165 | _controller.repeat(); 166 | _capturePng(); 167 | 168 | } 169 | void onPanStart(DragStartDetails dragInfo) { 170 | dragStartX = dragInfo.globalPosition.dx; 171 | dragStartY = dragInfo.globalPosition.dy; 172 | } 173 | void onMaskPanStart(DragStartDetails dragInfo) { 174 | dragStartX = dragInfo.globalPosition.dx; 175 | dragStartY = dragInfo.globalPosition.dy; 176 | double margin = 20.0; 177 | //点击位置离跟左边点在10以内 178 | if((dragStartX -maskLeft).abs() < margin && dragStartY>(maskTop+margin) && dragStartY<(maskTop+maskHeight-margin)){ 179 | maskDirection = "left"; 180 | } 181 | else if((dragStartY -maskTop).abs() < margin && dragStartX>(maskLeft+margin) && dragStartX<(maskLeft+maskWidth-margin)){ 182 | maskDirection = "top"; 183 | } 184 | else if((dragStartX -(maskLeft+maskWidth)).abs() < margin && dragStartY>(maskTop+margin) && dragStartY<(maskTop+maskHeight-margin)){ 185 | maskDirection = "right"; 186 | } 187 | else if((dragStartY -(maskTop+maskHeight)).abs() < margin && dragStartX>(maskLeft+margin) && dragStartX<(maskLeft+maskWidth-margin)){ 188 | maskDirection = "bottom"; 189 | } 190 | else{ 191 | maskDirection = "center"; 192 | } 193 | //print(maskDirection+" " +dragStartX.toString()+" "+maskLeft.toString()+" "+(dragStartX -maskLeft).abs().toString()); 194 | 195 | } 196 | void onPanEnd(DragEndDetails details) { 197 | dragStartX = 0.0; 198 | dragStartY = 0.0; 199 | } 200 | 201 | void onScaleStart(ScaleRotateStartDetails details) { 202 | imgDragStartX = details.focalPoint.dx; 203 | imgDragStartY = details.focalPoint.dy; 204 | rotate = 0.0; 205 | } 206 | 207 | void onScaleUpdate(ScaleRotateUpdateDetails details) { 208 | double degrees = details.rotation * (180 / math.pi); 209 | if (details.scale == 1 && details.rotation == 0) { 210 | double moveX = (details.focalPoint.dx - imgDragStartX); 211 | double moveY = (details.focalPoint.dy - imgDragStartY); 212 | imgDragStartX = imgDragStartX + moveX; 213 | imgDragStartY = imgDragStartY + moveY; 214 | double dx = (topLeft.dx + moveX); 215 | double dy = (topLeft.dy + moveY); 216 | // print("topLeft:"+topLeft.dx.toString()+" "+topLeft.dy.toString()); 217 | //print("dragInfo.globalPosition.dx:"+details.focalPoint.dx.toString()+" dragInfo.globalPosition.dy:"+details.focalPoint.dy.toString()); 218 | //print("moveX:"+moveX.toString()+" moveY:"+moveY.toString()+" this.context.size.width:"+this.context.size.width.toString()+" dx:"+dx.toString()); 219 | // if(dx <= (10-this.context.size.width)){//不能往左拖动太厉害 220 | // dx = 10-this.context.size.width; 221 | // } 222 | // if(dx >= this.context.size.width-10){//不能往右拖动太厉害 223 | // dx = this.context.size.width-10; 224 | // } 225 | // 226 | // double imageHeight = imageInfo.image.height*((MediaQuery.of(this.context).size.width-20)/imageInfo.image.width); 227 | // 228 | // if(dy <= (10-imageHeight)){//不能太网上拖 229 | // dy = 10-imageHeight; 230 | // } 231 | // if(dy >= this.context.size.height+imageHeight-10){//不能往下拖动太厉害 232 | // dy = this.context.size.height+imageHeight-10; 233 | // } 234 | 235 | Offset offset = new Offset(dx, dy); 236 | //print("offset:"+offset.dx.toString()+" "+offset.dy.toString()); 237 | setState(() { 238 | topLeft = offset; 239 | }); 240 | } else { 241 | doRotateAndZoom(details.rotation, details.scale); 242 | } 243 | } 244 | 245 | void doRotateAndZoom(double rt, double scale) { 246 | rotate = rt; 247 | var matrix1 = new Matrix4.identity()..rotateZ(oldRotate + rotate); 248 | var diffScale = scale - _scale; 249 | oldScale = oldScale + diffScale; 250 | // if(diffScale>0.05 || diffScale<0.05){ 251 | matrix1 = new Matrix4.identity() 252 | ..rotateZ(oldRotate + rotate) 253 | ..scale(oldScale); 254 | //} 255 | setState(() { 256 | matrix = matrix1; 257 | }); 258 | _scale = scale; 259 | } 260 | 261 | void onScaleEnd(ScaleRotateEndDetails details) { 262 | imgDragStartX = 0.0; 263 | imgDragStartY = 0.0; 264 | oldRotate = oldRotate + rotate; 265 | rotate = 0.0; 266 | _scale = 1.0; 267 | } 268 | 269 | void onPanUpdate(String btn, DragUpdateDetails dragInfo) { 270 | //重新计算move 271 | //重新计算move 272 | double moveX = (dragInfo.globalPosition.dx - dragStartX); 273 | double moveY = (dragInfo.globalPosition.dy - dragStartY); 274 | 275 | dragStartX = dragStartX + moveX; 276 | dragStartY = dragStartY + moveY; 277 | 278 | double _maskHeight = maskHeight; 279 | double _maskWidth = maskWidth; 280 | double _maskTop = maskTop; 281 | double _maskLeft = maskLeft; 282 | //topleft,都变化了 283 | if (btn == "topleft") { 284 | _maskHeight = maskHeight - moveY; 285 | _maskWidth = maskWidth - moveX; 286 | _maskTop = maskTop + moveY; 287 | _maskLeft = maskLeft + moveX; 288 | } 289 | 290 | //topright,left不变 291 | if (btn == "topright") { 292 | _maskWidth = maskWidth + moveX; 293 | _maskHeight = maskHeight - moveY; 294 | _maskTop = maskTop + moveY; 295 | } 296 | 297 | //bottomLeft 298 | if (btn == "bottomleft") { 299 | _maskWidth = maskWidth - moveX; 300 | _maskLeft = maskLeft + moveX; 301 | _maskHeight = maskHeight + moveY; 302 | //_maskTop = maskTop+ moveY; 303 | } 304 | 305 | //bottomRight 306 | if (btn == "bottomright") { 307 | _maskWidth = maskWidth + moveX; 308 | _maskHeight = maskHeight + moveY; 309 | } 310 | if (btn == "left") { 311 | _maskWidth = maskWidth - moveX; 312 | _maskLeft = maskLeft + moveX; 313 | } 314 | 315 | if (btn == "top") { 316 | _maskHeight = maskHeight - moveY; 317 | _maskTop = maskTop + moveY; 318 | } 319 | if (btn == "bottom") { 320 | _maskHeight = maskHeight + moveY; 321 | } 322 | if (btn == "right") { 323 | _maskWidth = maskWidth + moveX; 324 | } 325 | 326 | //center 327 | if (btn == "center") { 328 | _maskLeft = maskLeft + moveX; 329 | _maskTop = maskTop + moveY; 330 | } 331 | 332 | //debugPrint("undate x:"+dragInfo.globalPosition.dx.toString()+" y:"+dragInfo.globalPosition.dy.toString()+" move:"+moveX.toString()+" maskWidth:" +maskWidth.toString()); 333 | setState(() { 334 | maskWidth = _maskWidth; 335 | maskHeight = _maskHeight; 336 | maskTop = _maskTop; 337 | maskLeft = _maskLeft; 338 | }); 339 | } 340 | 341 | Widget buildLoading() { 342 | return new Center( 343 | child: new Text( 344 | "Loading", 345 | style: new TextStyle(color: Colors.white), 346 | )); 347 | } 348 | @override 349 | void didChangeDependencies() { 350 | super.didChangeDependencies(); 351 | var size = MediaQuery.of(context).size; 352 | //手机宽高比 353 | var devW = size.width-40*2; 354 | var devH = size.height-2*60; 355 | var devWh = devW/devH; 356 | var imgWh = widget.imageInfo.image.width/widget.imageInfo.image.height; 357 | if(devWh[ 381 | new RawGestureDetector( 382 | gestures: { 383 | ScaleRotateGestureRecognizer: 384 | new GestureRecognizerFactoryWithHandlers< 385 | ScaleRotateGestureRecognizer>( 386 | () => new ScaleRotateGestureRecognizer(), 387 | (ScaleRotateGestureRecognizer instance) { 388 | instance 389 | ..onStart = onScaleStart 390 | ..onUpdate = onScaleUpdate 391 | ..onEnd = onScaleEnd; 392 | }, 393 | ), 394 | }, 395 | child:new RepaintBoundary( 396 | key: globalKey, 397 | child:new Container( 398 | margin: const EdgeInsets.only( 399 | left: 0.0, top: 0.0, right: 0.0, bottom: 0.0), 400 | padding: const EdgeInsets.only( 401 | left: 0.0, top: 0.0, right: 0.0, bottom: 0.0), 402 | color: Colors.black, 403 | width: MediaQuery.of(context).size.width, 404 | height: MediaQuery.of(context).size.height, 405 | child: new CustomSingleChildLayout( 406 | delegate: new ImagePositionDelegate( 407 | imgWidth, 408 | imgHeight, 409 | topLeft), 410 | child: Transform( 411 | child: new RawImage( 412 | image: widget.image, 413 | scale: widget.imageInfo.scale, 414 | ), 415 | alignment: FractionalOffset.center, 416 | transform: matrix, 417 | ), 418 | ), 419 | ), 420 | ), 421 | ), 422 | new Positioned( 423 | left: 0.0, 424 | top: 0.0, 425 | width: MediaQuery.of(context).size.width, 426 | height: maskTop, 427 | child: new IgnorePointer( 428 | child: new Opacity( 429 | opacity: opacity, 430 | child: new Container( 431 | color: Colors.black, 432 | ), 433 | ))), 434 | new Positioned( 435 | left: 0.0, 436 | top: maskTop, 437 | width: this.maskLeft, 438 | height: this.maskHeight, 439 | child: new IgnorePointer( 440 | child: new Opacity( 441 | opacity: opacity, 442 | child: new Container(color: Colors.black), 443 | ))), 444 | new Positioned( 445 | right: 0.0, 446 | top: maskTop, 447 | width: (MediaQuery.of(context).size.width - 448 | this.maskWidth - 449 | this.maskLeft), 450 | height: this.maskHeight, 451 | child: new IgnorePointer( 452 | child: new Opacity( 453 | opacity: opacity, 454 | child: new Container(color: Colors.black), 455 | ))), 456 | new Positioned( 457 | left: 0.0, 458 | top: this.maskTop + this.maskHeight, 459 | width: MediaQuery.of(context).size.width, 460 | height: MediaQuery.of(context).size.height - 461 | (this.maskTop + this.maskHeight), 462 | child: new IgnorePointer( 463 | child: new Opacity( 464 | opacity: opacity, 465 | child: new Container(color: Colors.black), 466 | ))), 467 | new Positioned( 468 | left: this.maskLeft, 469 | top: this.maskTop, 470 | width: this.maskWidth, 471 | height: this.maskHeight, 472 | child: new GestureDetector( 473 | child: new Container( 474 | color: Colors.transparent, 475 | child: new CustomPaint( 476 | painter: new GridPainter(), 477 | ), 478 | ), 479 | onPanStart: onMaskPanStart, 480 | onPanUpdate: (dragInfo) { 481 | 482 | this.onPanUpdate(maskDirection, dragInfo); 483 | }, 484 | onPanEnd: onPanEnd 485 | ) 486 | ), 487 | new Positioned( //scan 488 | left: this.maskLeft, 489 | top: this.maskTop, 490 | width: this.maskWidth, 491 | height: this.maskHeight*_controller.value, 492 | child: new Opacity( 493 | opacity: 0.5, 494 | child: new Container(color: Colors.blue), 495 | ) 496 | ), 497 | new Positioned( 498 | top: maskTop - 2, 499 | left: this.maskLeft - 2, 500 | child: new GestureDetector( 501 | child: new Image.asset("images/topLeft.png"), 502 | onPanStart: onPanStart, 503 | onPanUpdate: (dragInfo) { 504 | this.onPanUpdate("topleft", dragInfo); 505 | }, 506 | onPanEnd: onPanEnd), 507 | ), 508 | new Positioned( 509 | top: maskTop - 2, 510 | right: (MediaQuery.of(context).size.width - 511 | this.maskWidth - 512 | this.maskLeft - 513 | 2), 514 | child: new GestureDetector( 515 | child: new Image.asset("images/topRight.png"), 516 | onPanStart: onPanStart, 517 | onPanUpdate: (dragInfo) { 518 | this.onPanUpdate("topright", dragInfo); 519 | }, 520 | onPanEnd: onPanEnd 521 | ), 522 | ), 523 | new Positioned( 524 | top: this.maskTop + this.maskHeight - 12.0, 525 | left: this.maskLeft - 2, 526 | child: new GestureDetector( 527 | child: new Image.asset("images/bottomLeft.png"), 528 | onPanStart: onPanStart, 529 | onPanUpdate: (dragInfo) { 530 | this.onPanUpdate("bottomleft", dragInfo); 531 | }, 532 | onPanEnd: onPanEnd), 533 | ), 534 | new Positioned( 535 | top: this.maskTop + this.maskHeight - 12.0, 536 | right: (MediaQuery.of(context).size.width - 537 | this.maskWidth - 538 | this.maskLeft - 539 | 2), 540 | child: new GestureDetector( 541 | child: new Image.asset("images/bottomRight.png"), 542 | onPanStart: onPanStart, 543 | onPanUpdate: (dragInfo) { 544 | this.onPanUpdate("bottomright", dragInfo); 545 | }, 546 | onPanEnd: onPanEnd, 547 | ), 548 | ), 549 | new Positioned( 550 | bottom: 10.0, 551 | height: 40.0, 552 | width: 40.0, 553 | left: (20.0), 554 | child: new RaisedButton( 555 | onPressed: () => Navigator.pop(context,""), 556 | padding: EdgeInsets.all(10.0), 557 | splashColor: Colors.white, 558 | shape: new RoundedRectangleBorder( 559 | borderRadius: BorderRadius.all(Radius.circular(40.0))), 560 | child: new Icon(Imgcrop.back, size: 20.0, color: Colors.red) 561 | ), 562 | ), 563 | new Positioned( 564 | bottom: 10.0, 565 | height: 40.0, 566 | width: 40.0, 567 | right: 20.0, 568 | child: new RaisedButton( 569 | onPressed: doCapturePng, 570 | padding: EdgeInsets.all(10.0), 571 | splashColor: Colors.white, 572 | shape: new RoundedRectangleBorder( 573 | borderRadius: BorderRadius.all(Radius.circular(40.0))), 574 | child: new Icon(Imgcrop.check, size: 20.0, color: Colors.red)), 575 | ) 576 | ], 577 | ); 578 | } 579 | 580 | @override 581 | Widget build(BuildContext context) { 582 | return new Scaffold( 583 | body: new Center( 584 | child: new Container( 585 | child: new Column(children: [ 586 | new Expanded(child: new Center(child: _buildImage(context))), 587 | //_buildButtons() 588 | ]))), // This trailing comma makes auto-formatting nicer for build methods. 589 | ); 590 | } 591 | @override 592 | void dispose() { 593 | _controller.dispose(); 594 | super.dispose(); 595 | } 596 | } 597 | 598 | class GridPainter extends CustomPainter { 599 | GridPainter(); 600 | 601 | @override 602 | void paint(Canvas canvas, Size size) { 603 | Paint paint = new Paint() 604 | ..color = Colors.white 605 | ..strokeCap = StrokeCap.round 606 | ..isAntiAlias = true; 607 | 608 | for (int i = 0; i <= 3; i++) { 609 | if (i == 0 || i == 3) { 610 | paint.strokeWidth = 3.0; 611 | } else { 612 | paint.strokeWidth = 1.0; 613 | } 614 | double dy = (size.height / 3) * i; 615 | canvas.drawLine(new Offset(0.0, dy), new Offset(size.width, dy), paint); 616 | } 617 | for (int i = 0; i <= 3; i++) { 618 | if (i == 0 || i == 3) { 619 | paint.strokeWidth = 3.0; 620 | } else { 621 | paint.strokeWidth = 1.0; 622 | } 623 | double dx = (size.width / 3) * i; 624 | canvas.drawLine(new Offset(dx, 0.0), new Offset(dx, size.height), paint); 625 | } 626 | } 627 | 628 | @override 629 | bool shouldRepaint(CustomPainter oldDelegate) { 630 | return true; 631 | } 632 | } 633 | 634 | class ImagePositionDelegate extends SingleChildLayoutDelegate { 635 | final double imageWidth; 636 | final double imageHeight; 637 | final Offset topLeft; 638 | 639 | const ImagePositionDelegate(this.imageWidth, this.imageHeight, this.topLeft); 640 | 641 | @override 642 | Offset getPositionForChild(Size size, Size childSize) { 643 | return topLeft; 644 | } 645 | 646 | @override 647 | BoxConstraints getConstraintsForChild(BoxConstraints constraints) { 648 | return new BoxConstraints( 649 | maxWidth: imageWidth, 650 | maxHeight: imageHeight, 651 | minHeight: imageHeight, 652 | minWidth: imageWidth, 653 | ); 654 | } 655 | 656 | @override 657 | bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) { 658 | return true; 659 | } 660 | } 661 | -------------------------------------------------------------------------------- /lib/imgcrop_icons.dart: -------------------------------------------------------------------------------- 1 | /// Flutter icons Imgcrop 2 | /// Copyright (C) 2018 by original authors @ fluttericon.com, fontello.com 3 | /// This font was generated by FlutterIcon.com, which is derived from Fontello. 4 | /// 5 | /// To use this font, place it in your fonts/ directory and include the 6 | /// following in your pubspec.yaml 7 | /// 8 | /// flutter: 9 | /// fonts: 10 | /// - family: Imgcrop 11 | /// fonts: 12 | /// - asset: fonts/Imgcrop.ttf 13 | /// 14 | /// 15 | /// * Typicons, (c) Stephen Hutchings 2012 16 | /// Author: Stephen Hutchings 17 | /// License: SIL (http://scripts.sil.org/OFL) 18 | /// Homepage: http://typicons.com/ 19 | /// * Material Design Icons, Copyright (C) Google, Inc 20 | /// Author: Google 21 | /// License: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) 22 | /// Homepage: https://design.google.com/icons/ 23 | /// * Entypo, Copyright (C) 2012 by Daniel Bruce 24 | /// Author: Daniel Bruce 25 | /// License: SIL (http://scripts.sil.org/OFL) 26 | /// Homepage: http://www.entypo.com 27 | /// * Font Awesome, Copyright (C) 2016 by Dave Gandy 28 | /// Author: Dave Gandy 29 | /// License: SIL () 30 | /// Homepage: http://fortawesome.github.com/Font-Awesome/ 31 | /// 32 | import 'package:flutter/widgets.dart'; 33 | 34 | class Imgcrop { 35 | Imgcrop._(); 36 | 37 | static const _kFontFam = 'Imgcrop'; 38 | 39 | static const IconData picture_outline = const IconData(0xe800, fontFamily: _kFontFam); 40 | static const IconData text = const IconData(0xe801, fontFamily: _kFontFam); 41 | static const IconData back = const IconData(0xe802, fontFamily: _kFontFam); 42 | static const IconData check = const IconData(0xe803, fontFamily: _kFontFam); 43 | static const IconData camera = const IconData(0xe804, fontFamily: _kFontFam); 44 | static const IconData assessment = const IconData(0xe805, fontFamily: _kFontFam); 45 | static const IconData account = const IconData(0xe806, fontFamily: _kFontFam); 46 | static const IconData pdf = const IconData(0xe807, fontFamily: _kFontFam); 47 | static const IconData book = const IconData(0xe808, fontFamily: _kFontFam); 48 | } 49 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/gestures.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'dart:io'; 5 | import 'package:image_picker/image_picker.dart'; 6 | import 'package:video_player/video_player.dart'; 7 | import 'dart:async'; 8 | import 'dart:ui' as ui; 9 | import 'imgcrop_icons.dart'; 10 | import 'image_page.dart'; 11 | import 'text_list.dart'; 12 | import 'package:camera/camera.dart'; 13 | import 'package:path_provider/path_provider.dart'; 14 | import 'package:flutter/services.dart'; 15 | 16 | List cameras; 17 | CameraDescription camera; 18 | 19 | Future main() async { 20 | cameras = await availableCameras(); 21 | camera = cameras[0]; 22 | runApp(new MyApp()); 23 | } 24 | 25 | class MyApp extends StatelessWidget { 26 | @override 27 | Widget build(BuildContext context) { 28 | return new MaterialApp( 29 | title: 'croper', 30 | theme: new ThemeData( 31 | primarySwatch: Colors.brown, 32 | ), 33 | home: new MyHomePage(title: 'croper'), 34 | ); 35 | } 36 | } 37 | 38 | class MyHomePage extends StatefulWidget { 39 | MyHomePage({Key key, this.title}) : super(key: key); 40 | final String title; 41 | 42 | @override 43 | _MyHomePageState createState() => new _MyHomePageState(); 44 | } 45 | 46 | class _MyHomePageState extends State with WidgetsBindingObserver { 47 | CameraController controller; 48 | VideoPlayerController _controller; 49 | double maskTop = 60.0; 50 | double maskLeft = 60.0; 51 | double maskWidth = 200.0; 52 | double maskHeight = 200.0; 53 | double dragStartX = 0.0; 54 | double dragStartY = 0.0; 55 | double imgDragStartX = 0.0; 56 | double imgDragStartY = 0.0; 57 | double oldScale = 1.0; 58 | double oldRotate = 0.0; 59 | double rotate = 0.0; 60 | ImageInfo imageInfo; 61 | Offset topLeft = new Offset(0.0, 0.0); 62 | Matrix4 matrix = new Matrix4.identity(); 63 | 64 | @override 65 | void initState() { 66 | super.initState(); 67 | initCamera(); 68 | SystemChannels.lifecycle.setMessageHandler((msg) { 69 | if (msg == AppLifecycleState.resumed.toString()) { 70 | reloadCamera(); 71 | } 72 | }); 73 | } 74 | 75 | void reloadCamera() { 76 | availableCameras().then((cameras) { 77 | camera = cameras[0]; 78 | controller = new CameraController(camera, ResolutionPreset.medium); 79 | controller.initialize().then((_) { 80 | if (!mounted) { 81 | return; 82 | } 83 | setState(() {}); 84 | }); 85 | }); 86 | } 87 | 88 | void initCamera() async { 89 | controller = new CameraController(camera, ResolutionPreset.medium); 90 | controller.initialize().then((_) { 91 | if (!mounted) { 92 | return; 93 | } 94 | setState(() {}); 95 | }); 96 | } 97 | 98 | void captureImage(ImageSource captureMode) async { 99 | try { 100 | var imageFile = await ImagePicker.pickImage(source: captureMode); 101 | _loadImage(imageFile).then((image) { 102 | if (image != null) { 103 | Navigator.push( 104 | context, 105 | new MaterialPageRoute( 106 | builder: (context) => new CropPage( 107 | title: 'crop', 108 | image: image, 109 | imageInfo: new ImageInfo(image: image, scale: 1.0)))); 110 | } 111 | }); 112 | } catch (e) { 113 | print(e); 114 | } 115 | } 116 | 117 | @override 118 | void dispose() { 119 | super.dispose(); 120 | } 121 | 122 | String timestamp() => new DateTime.now().millisecondsSinceEpoch.toString(); 123 | 124 | Future capture() async { 125 | if (!controller.value.initialized) { 126 | return null; 127 | } 128 | final Directory extDir = await getApplicationDocumentsDirectory(); 129 | final String dirPath = '${extDir.path}/Pictures/imgcroper'; 130 | await new Directory(dirPath).create(recursive: true); 131 | final String filePath = '$dirPath/${timestamp()}.jpg'; 132 | try { 133 | await controller.capture(filePath); 134 | try { 135 | File imageFile = new File(filePath); 136 | _loadImage(imageFile).then((image) { 137 | Navigator.push( 138 | context, 139 | new MaterialPageRoute( 140 | builder: (context) => new CropPage( 141 | title: 'crop', 142 | image: image, 143 | imageInfo: new ImageInfo(image: image, scale: 1.0)))); 144 | }); 145 | } catch (e) { 146 | print(e); 147 | } 148 | } on CameraException catch (e) { 149 | return null; 150 | } 151 | return filePath; 152 | } 153 | 154 | Future _buildImage(BuildContext context) async { 155 | return new Stack(children: [ 156 | new Container( 157 | height: MediaQuery.of(context).size.height, 158 | width: MediaQuery.of(context).size.width, 159 | child: new Transform.scale( 160 | scale: 1 / controller.value.aspectRatio, 161 | child: new Center( 162 | child: new AspectRatio( 163 | aspectRatio: controller.value.aspectRatio, 164 | child: new CameraPreview(controller)), 165 | ))), 166 | new Positioned( 167 | bottom: 20.0, 168 | height: 40.0, 169 | width: 40.0, 170 | left: (20.0), 171 | child: new RaisedButton( 172 | onPressed: () => captureImage(ImageSource.gallery), 173 | padding: EdgeInsets.all(10.0), 174 | shape: new RoundedRectangleBorder( 175 | borderRadius: BorderRadius.all(Radius.circular(40.0))), 176 | child: new Icon(Imgcrop.picture_outline, 177 | size: 20.0, color: Colors.red)), 178 | ), 179 | new Positioned( 180 | bottom: 20.0, 181 | height: 60.0, 182 | width: 60.0, 183 | left: (MediaQuery.of(context).size.width / 2 - 30.0), 184 | child: new RaisedButton( 185 | onPressed: capture, 186 | padding: EdgeInsets.all(10.0), 187 | shape: new RoundedRectangleBorder( 188 | borderRadius: BorderRadius.all(Radius.circular(60.0))), 189 | child: new Icon(Imgcrop.camera, size: 40.0, color: Colors.red)), 190 | ), 191 | new Positioned( 192 | bottom: 20.0, 193 | height: 40.0, 194 | width: 40.0, 195 | right: (20.0), 196 | child: new RaisedButton( 197 | onPressed: goToTextListPage, 198 | padding: EdgeInsets.all(10.0), 199 | shape: new RoundedRectangleBorder( 200 | borderRadius: BorderRadius.all(Radius.circular(40.0))), 201 | child: new Icon(Imgcrop.book, size: 20.0, color: Colors.red)), 202 | ), 203 | ]); 204 | } 205 | 206 | void goToTextListPage() { 207 | Navigator.push(this.context, 208 | new MaterialPageRoute(builder: (BuildContext context) { 209 | return new Scaffold( 210 | appBar: new AppBar( 211 | title: new Text("历史记录"), 212 | ), 213 | body: new TextListPage()); 214 | })); 215 | } 216 | 217 | Future _loadImage(File img) async { 218 | if (img != null) { 219 | var codec = await ui.instantiateImageCodec(img.readAsBytesSync()); 220 | var frame = await codec.getNextFrame(); 221 | return frame.image; 222 | } 223 | return null; 224 | } 225 | 226 | @override 227 | Widget build(BuildContext context) { 228 | return new Scaffold( 229 | body: new Center( 230 | child: new Container( 231 | child: new Column(children: [ 232 | new Expanded( 233 | child: new Center( 234 | child: new FutureBuilder( 235 | future: _buildImage(context), 236 | builder: (BuildContext context, AsyncSnapshot snapshot) { 237 | if (snapshot.hasData) { 238 | return snapshot.data; 239 | } else { 240 | return new Container(); 241 | } 242 | }, 243 | ))), 244 | ]))), // This trailing comma makes auto-formatting nicer for build methods. 245 | ); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /lib/result_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'dart:ui' as ui; 4 | import 'imgcrop_icons.dart'; 5 | 6 | class ResultPage extends StatefulWidget { 7 | ResultPage({Key key, this.title, this.image, this.ocrContent}) 8 | : super(key: key); 9 | final String title; 10 | final ui.Image image; 11 | final List ocrContent; 12 | 13 | @override 14 | ResultState createState() => new ResultState(); 15 | } 16 | 17 | class ResultState extends State { 18 | @override 19 | void initState() { 20 | super.initState(); 21 | } 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | var height = MediaQuery.of(context).size.height; 26 | var picHeight = 260.0; 27 | var scrollHeight = height - (260.0 + 120.0); 28 | return new Scaffold( 29 | body: new Center( 30 | child: new Stack(children: [ 31 | new Container( 32 | child: new Column(children: [ 33 | new Container( 34 | child: new RawImage( 35 | image: widget.image, 36 | scale: 0.5, 37 | ), 38 | padding: 39 | const EdgeInsets.only(left: 20.0, top: 30.0, right: 20.0), 40 | height: picHeight), 41 | new Container( 42 | color: Colors.white, 43 | margin: new EdgeInsets.only(top: 60.0), 44 | padding: new EdgeInsets.all(7.0), 45 | height: scrollHeight, 46 | child: new ConstrainedBox( 47 | constraints: new BoxConstraints( 48 | minHeight: scrollHeight, 49 | maxHeight: scrollHeight, 50 | ), 51 | child: new SingleChildScrollView( 52 | scrollDirection: Axis.vertical, 53 | reverse: true, 54 | child: new Text(widget.ocrContent.join("/n").toString()), 55 | ), 56 | ), 57 | ) 58 | ]), 59 | ), 60 | new Positioned( 61 | top: 30.0, 62 | height: 40.0, 63 | width: 40.0, 64 | left: 10.0, 65 | child: new RaisedButton( 66 | onPressed: () => Navigator.pop(context, ""), 67 | padding: EdgeInsets.all(10.0), 68 | splashColor: Colors.white, 69 | shape: new RoundedRectangleBorder( 70 | borderRadius: BorderRadius.all(Radius.circular(40.0))), 71 | child: new Icon(Imgcrop.back, size: 20.0, color: Colors.red)), 72 | ), 73 | ]))); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/rotatescale.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/gestures.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:flutter/cupertino.dart'; 8 | import 'dart:math' as math; 9 | 10 | 11 | /// The possible states of a [ScaleGestureRecognizer]. 12 | enum _ScaleRotateState { 13 | /// The recognizer is ready to start recognizing a gesture. 14 | ready, 15 | 16 | /// The sequence of pointer events seen thus far is consistent with a scale 17 | /// gesture but the gesture has not been accepted definitively. 18 | possible, 19 | 20 | /// The sequence of pointer events seen thus far has been accepted 21 | /// definitively as a scale gesture. 22 | accepted, 23 | 24 | /// The sequence of pointer events seen thus far has been accepted 25 | /// definitively as a scale gesture and the pointers established a focal point 26 | /// and initial scale. 27 | started, 28 | } 29 | 30 | /// Details for [GestureScaleStartCallback]. 31 | class ScaleRotateStartDetails { 32 | /// Creates details for [GestureScaleStartCallback]. 33 | /// 34 | /// The [focalPoint] argument must not be null. 35 | ScaleRotateStartDetails({ this.focalPoint: Offset.zero }) 36 | : assert(focalPoint != null); 37 | 38 | /// The initial focal point of the pointers in contact with the screen. 39 | /// Reported in global coordinates. 40 | final Offset focalPoint; 41 | 42 | @override 43 | String toString() => 'ScaleRotateStartDetails(focalPoint: $focalPoint)'; 44 | } 45 | 46 | /// Details for [GestureScaleUpdateCallback]. 47 | class ScaleRotateUpdateDetails { 48 | /// Creates details for [GestureScaleUpdateCallback]. 49 | /// 50 | /// The [focalPoint], [scale] and [rotation] arguments must not be null. The [scale] 51 | /// argument must be greater than or equal to zero. 52 | ScaleRotateUpdateDetails({ 53 | this.focalPoint: Offset.zero, 54 | this.scale: 1.0, 55 | this.rotation: 0.0, 56 | }) : assert(focalPoint != null), 57 | assert(scale != null && scale >= 0.0), 58 | assert(rotation != null); 59 | 60 | /// The focal point of the pointers in contact with the screen. Reported in 61 | /// global coordinates. 62 | final Offset focalPoint; 63 | 64 | /// The scale implied by the pointers in contact with the screen. A value 65 | /// greater than or equal to zero. 66 | final double scale; 67 | 68 | /// The Rotation implied by the first two pointers to enter in contact with 69 | /// the screen. Expressed in radians. 70 | final double rotation; 71 | 72 | @override 73 | String toString() => 'ScaleRotateUpdateDetails(focalPoint: $focalPoint, scale: $scale, rotation: $rotation)'; 74 | } 75 | 76 | /// Details for [GestureScaleEndCallback]. 77 | class ScaleRotateEndDetails { 78 | /// Creates details for [GestureScaleEndCallback]. 79 | /// 80 | /// The [velocity] argument must not be null. 81 | ScaleRotateEndDetails({ this.velocity: Velocity.zero }) 82 | : assert(velocity != null); 83 | 84 | /// The velocity of the last pointer to be lifted off of the screen. 85 | final Velocity velocity; 86 | 87 | @override 88 | String toString() => 'ScaleRotateEndDetails(velocity: $velocity)'; 89 | } 90 | 91 | /// Signature for when the pointers in contact with the screen have established 92 | /// a focal point and initial scale of 1.0. 93 | typedef void GestureRotateScaleStartCallback(ScaleRotateStartDetails details); 94 | 95 | /// Signature for when the pointers in contact with the screen have indicated a 96 | /// new focal point and/or scale. 97 | typedef void GestureRotateScaleUpdateCallback(ScaleRotateUpdateDetails details); 98 | 99 | /// Signature for when the pointers are no longer in contact with the screen. 100 | typedef void GestureRotateScaleEndCallback(ScaleRotateEndDetails details); 101 | 102 | bool _isFlingGesture(Velocity velocity) { 103 | assert(velocity != null); 104 | final double speedSquared = velocity.pixelsPerSecond.distanceSquared; 105 | return speedSquared > kMinFlingVelocity * kMinFlingVelocity; 106 | } 107 | 108 | 109 | /// Defines a line between two pointers on screen. 110 | /// 111 | /// [_LineBetweenPointers] is an abstraction of a line between two pointers in 112 | /// contact with the screen. Used to track the rotation of a scale gesture. 113 | class _LineBetweenPointers{ 114 | 115 | /// Creates a [_LineBetweenPointers]. None of the [pointerStartLocation], [pointerStartId] 116 | /// [pointerEndLocation] and [pointerEndId] must be null. [pointerStartId] and [pointerEndId] 117 | /// should be different. 118 | _LineBetweenPointers({ 119 | this.pointerStartLocation, 120 | this.pointerStartId, 121 | this.pointerEndLocation, 122 | this.pointerEndId 123 | }) : assert(pointerStartLocation != null && pointerEndLocation != null), 124 | assert(pointerStartId != null && pointerEndId != null), 125 | assert(pointerStartId != pointerEndId); 126 | 127 | /// The location and the id of the pointer that marks the start of the line, 128 | final Offset pointerStartLocation; 129 | final int pointerStartId; 130 | 131 | /// The location and the id of the pointer that marks the end of the line, 132 | final Offset pointerEndLocation; 133 | final int pointerEndId; 134 | 135 | } 136 | 137 | 138 | /// Recognizes a scale gesture. 139 | /// 140 | /// [ScaleGestureRecognizer] tracks the pointers in contact with the screen and 141 | /// calculates their focal point, indicated scale and rotation. When a focal pointer is 142 | /// established, the recognizer calls [onStart]. As the focal point, scale and rotation 143 | /// change, the recognizer calls [onUpdate]. When the pointers are no longer in 144 | /// contact with the screen, the recognizer calls [onEnd]. 145 | class ScaleRotateGestureRecognizer extends OneSequenceGestureRecognizer { 146 | /// Create a gesture recognizer for interactions intended for scaling content. 147 | ScaleRotateGestureRecognizer({ Object debugOwner }) : super(debugOwner: debugOwner); 148 | 149 | /// The pointers in contact with the screen have established a focal point and 150 | /// initial scale of 1.0. 151 | GestureRotateScaleStartCallback onStart; 152 | 153 | /// The pointers in contact with the screen have indicated a new focal point 154 | /// and/or scale. 155 | GestureRotateScaleUpdateCallback onUpdate; 156 | 157 | /// The pointers are no longer in contact with the screen. 158 | GestureRotateScaleEndCallback onEnd; 159 | 160 | _ScaleRotateState _state = _ScaleRotateState.ready; 161 | 162 | Offset _initialFocalPoint; 163 | Offset _currentFocalPoint; 164 | double _initialSpan; 165 | double _currentSpan; 166 | _LineBetweenPointers _initialLine; 167 | _LineBetweenPointers _currentLine; 168 | Map _pointerLocations; 169 | /// A queue to sort pointers in order of entrance 170 | List _pointerQueue; 171 | final Map _velocityTrackers = {}; 172 | 173 | double get _scaleFactor => _initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0; 174 | 175 | double _rotationFactor () { 176 | if(_initialLine == null || _currentLine == null){ 177 | return 0.0; 178 | } 179 | final double fx = _initialLine.pointerStartLocation.dx; 180 | final double fy = _initialLine.pointerStartLocation.dy; 181 | final double sx = _initialLine.pointerEndLocation.dx; 182 | final double sy = _initialLine.pointerEndLocation.dy; 183 | 184 | final double nfx = _currentLine.pointerStartLocation.dx; 185 | final double nfy = _currentLine.pointerStartLocation.dy; 186 | final double nsx = _currentLine.pointerEndLocation.dx; 187 | final double nsy = _currentLine.pointerEndLocation.dy; 188 | 189 | final double angle1 = math.atan2(fy - sy, fx - sx); 190 | final double angle2 = math.atan2(nfy - nsy, nfx - nsx); 191 | 192 | return angle2 - angle1; 193 | } 194 | 195 | @override 196 | void addPointer(PointerEvent event) { 197 | startTrackingPointer(event.pointer); 198 | _velocityTrackers[event.pointer] = new VelocityTracker(); 199 | if (_state == _ScaleRotateState.ready) { 200 | _state = _ScaleRotateState.possible; 201 | _initialSpan = 0.0; 202 | _currentSpan = 0.0; 203 | _pointerLocations = {}; 204 | _pointerQueue = []; 205 | } 206 | } 207 | 208 | @override 209 | void handleEvent(PointerEvent event) { 210 | assert(_state != _ScaleRotateState.ready); 211 | bool didChangeConfiguration = false; 212 | bool shouldStartIfAccepted = false; 213 | if (event is PointerMoveEvent) { 214 | final VelocityTracker tracker = _velocityTrackers[event.pointer]; 215 | assert(tracker != null); 216 | if (!event.synthesized) 217 | tracker.addPosition(event.timeStamp, event.position); 218 | _pointerLocations[event.pointer] = event.position; 219 | shouldStartIfAccepted = true; 220 | } else if (event is PointerDownEvent) { 221 | _pointerLocations[event.pointer] = event.position; 222 | _pointerQueue.add(event.pointer); 223 | didChangeConfiguration = true; 224 | shouldStartIfAccepted = true; 225 | } else if (event is PointerUpEvent || event is PointerCancelEvent) { 226 | _pointerLocations.remove(event.pointer); 227 | _pointerQueue.remove(event.pointer); 228 | didChangeConfiguration = true; 229 | } 230 | 231 | _updateLines(); 232 | _update(); 233 | 234 | if (!didChangeConfiguration || _reconfigure(event.pointer)) 235 | _advanceStateMachine(shouldStartIfAccepted); 236 | stopTrackingIfPointerNoLongerDown(event); 237 | } 238 | 239 | void _update() { 240 | final int count = _pointerLocations.keys.length; 241 | 242 | // Compute the focal point 243 | Offset focalPoint = Offset.zero; 244 | for (int pointer in _pointerLocations.keys) 245 | focalPoint += _pointerLocations[pointer]; 246 | _currentFocalPoint = count > 0 ? focalPoint / count.toDouble() : Offset.zero; 247 | 248 | // Span is the average deviation from focal point 249 | double totalDeviation = 0.0; 250 | for (int pointer in _pointerLocations.keys) 251 | totalDeviation += (_currentFocalPoint - _pointerLocations[pointer]).distance; 252 | _currentSpan = count > 0 ? totalDeviation / count : 0.0; 253 | } 254 | 255 | /// Updates [_initialLine] and [_currentLine] accordingly to the situation of 256 | /// the registered pointers 257 | void _updateLines(){ 258 | final int count = _pointerLocations.keys.length; 259 | 260 | /// In case of just one pointer registered, reconfigure [_initialLine] 261 | if(count < 2 ){ 262 | _initialLine = _currentLine; 263 | } else if(_initialLine != null 264 | && _initialLine.pointerStartId == _pointerQueue[0] 265 | && _initialLine.pointerEndId == _pointerQueue[1]){ 266 | /// Rotation updated, set the [_currentLine] 267 | _currentLine = new _LineBetweenPointers( 268 | pointerStartId: _pointerQueue[0], 269 | pointerStartLocation: _pointerLocations[_pointerQueue[0]], 270 | pointerEndId: _pointerQueue[1], 271 | pointerEndLocation: _pointerLocations[ _pointerQueue[1]] 272 | ); 273 | } else { 274 | /// A new rotation process is on the way, set the [_initialLine] 275 | _initialLine = new _LineBetweenPointers( 276 | pointerStartId: _pointerQueue[0], 277 | pointerStartLocation: _pointerLocations[_pointerQueue[0]], 278 | pointerEndId: _pointerQueue[1], 279 | pointerEndLocation: _pointerLocations[ _pointerQueue[1]] 280 | ); 281 | _currentLine = null; 282 | } 283 | } 284 | 285 | bool _reconfigure(int pointer) { 286 | _initialFocalPoint = _currentFocalPoint; 287 | _initialSpan = _currentSpan; 288 | _initialLine = _currentLine; 289 | if (_state == _ScaleRotateState.started) { 290 | if (onEnd != null) { 291 | final VelocityTracker tracker = _velocityTrackers[pointer]; 292 | assert(tracker != null); 293 | 294 | Velocity velocity = tracker.getVelocity(); 295 | if (_isFlingGesture(velocity)) { 296 | final Offset pixelsPerSecond = velocity.pixelsPerSecond; 297 | if (pixelsPerSecond.distanceSquared > kMaxFlingVelocity * kMaxFlingVelocity) 298 | velocity = new Velocity(pixelsPerSecond: (pixelsPerSecond / pixelsPerSecond.distance) * kMaxFlingVelocity); 299 | invokeCallback('onEnd', () => onEnd(new ScaleRotateEndDetails(velocity: velocity))); 300 | } else { 301 | invokeCallback('onEnd', () => onEnd(new ScaleRotateEndDetails(velocity: Velocity.zero))); 302 | } 303 | } 304 | _state = _ScaleRotateState.accepted; 305 | return false; 306 | } 307 | return true; 308 | } 309 | 310 | void _advanceStateMachine(bool shouldStartIfAccepted) { 311 | if (_state == _ScaleRotateState.ready) 312 | _state = _ScaleRotateState.possible; 313 | 314 | if (_state == _ScaleRotateState.possible) { 315 | final double spanDelta = (_currentSpan - _initialSpan).abs(); 316 | final double focalPointDelta = (_currentFocalPoint - _initialFocalPoint).distance; 317 | if (spanDelta > kScaleSlop || focalPointDelta > kPanSlop) 318 | resolve(GestureDisposition.accepted); 319 | } else if (_state.index >= _ScaleRotateState.accepted.index) { 320 | resolve(GestureDisposition.accepted); 321 | } 322 | 323 | if (_state == _ScaleRotateState.accepted && shouldStartIfAccepted) { 324 | _state = _ScaleRotateState.started; 325 | _dispatchOnStartCallbackIfNeeded(); 326 | } 327 | 328 | if (_state == _ScaleRotateState.started && onUpdate != null) 329 | invokeCallback('onUpdate', () => onUpdate(new ScaleRotateUpdateDetails(scale: _scaleFactor, focalPoint: _currentFocalPoint, rotation: _rotationFactor()))); 330 | } 331 | 332 | void _dispatchOnStartCallbackIfNeeded() { 333 | assert(_state == _ScaleRotateState.started); 334 | if (onStart != null) 335 | invokeCallback('onStart', () => onStart(new ScaleRotateStartDetails(focalPoint: _currentFocalPoint))); 336 | } 337 | 338 | @override 339 | void acceptGesture(int pointer) { 340 | if (_state == _ScaleRotateState.possible) { 341 | _state = _ScaleRotateState.started; 342 | _dispatchOnStartCallbackIfNeeded(); 343 | } 344 | } 345 | 346 | @override 347 | void rejectGesture(int pointer) { 348 | stopTrackingPointer(pointer); 349 | } 350 | 351 | @override 352 | void didStopTrackingLastPointer(int pointer) { 353 | switch (_state) { 354 | case _ScaleRotateState.possible: 355 | resolve(GestureDisposition.rejected); 356 | break; 357 | case _ScaleRotateState.ready: 358 | assert(false); // We should have not seen a pointer yet 359 | break; 360 | case _ScaleRotateState.accepted: 361 | break; 362 | case _ScaleRotateState.started: 363 | assert(false); // We should be in the accepted state when user is done 364 | break; 365 | } 366 | _state = _ScaleRotateState.ready; 367 | } 368 | 369 | @override 370 | void dispose() { 371 | _velocityTrackers.clear(); 372 | super.dispose(); 373 | } 374 | 375 | @override 376 | String get debugDescription => 'scale'; 377 | } -------------------------------------------------------------------------------- /lib/text_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | import 'package:flutter/cupertino.dart'; 4 | 5 | class TextListPage extends StatefulWidget { 6 | TextListPage({Key key, this.title}) : super(key: key); 7 | final String title; 8 | 9 | @override 10 | TextListState createState() => new TextListState(); 11 | } 12 | 13 | class TextListState extends State { 14 | Future _dataFuture; 15 | 16 | Future loadFeeds() async { 17 | List resultList = ['曾经的你', '再见理想', '平凡之路', '两天']; 18 | return resultList; 19 | } 20 | 21 | @override 22 | void initState() { 23 | super.initState(); 24 | _dataFuture = loadFeeds(); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return new FutureBuilder( 30 | future: _dataFuture, 31 | builder: (BuildContext context, AsyncSnapshot snapshot) { 32 | switch (snapshot.connectionState) { 33 | case ConnectionState.active: 34 | return new Text("active"); 35 | case ConnectionState.none: 36 | return new Center( 37 | child: new Text("none"), 38 | ); 39 | case ConnectionState.waiting: 40 | return new Center( 41 | child: new CupertinoActivityIndicator(), 42 | ); 43 | default: 44 | if (snapshot.hasError) { 45 | debugPrint("${snapshot.error}"); 46 | return new Center( 47 | child: new Text('Error: ${snapshot.error}'), 48 | ); 49 | } else { 50 | List data = snapshot.data; 51 | if (null == data || data.length == 0) { 52 | return new Center( 53 | child: new Text('No Data'), 54 | ); 55 | } 56 | List columns = []; 57 | data.forEach((name) { 58 | columns.add(new ListTile( 59 | leading: new CircleAvatar( 60 | backgroundColor: Colors.brown.shade800, 61 | child: new Text(name.substring(0, 1)), 62 | ), 63 | title: new Text(name), 64 | trailing: const Icon(Icons.music_note), 65 | // onTap: (){ 66 | // Navigator.push(this.context, 67 | // new MaterialPageRoute(builder: (BuildContext context) { 68 | // return new Scaffold( 69 | // appBar: new AppBar( 70 | // title: new Text(name), 71 | // ), 72 | // body: new DetailPage( 73 | // )); 74 | // })); 75 | // }, 76 | )); 77 | columns.add(const Divider()); 78 | }); 79 | return new ListView( 80 | shrinkWrap: true, 81 | padding: const EdgeInsets.all(20.0), 82 | children: columns, 83 | ); 84 | } 85 | } 86 | }); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_ocr 2 | description: A new Flutter application. 3 | 4 | dependencies: 5 | flutter: 6 | sdk: flutter 7 | 8 | # The following adds the Cupertino Icons font to your application. 9 | # Use with the CupertinoIcons class for iOS style icons. 10 | cupertino_icons: ^0.1.2 11 | path_provider: 0.4.1 12 | video_player: 0.5.2 13 | camera: ^0.1.2 14 | image: 2.0.4 15 | dio: 16 | image_picker: 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | 22 | # For information on the generic Dart part of this file, see the 23 | # following page: https://www.dartlang.org/tools/pub/pubspec 24 | 25 | # The following section is specific to Flutter. 26 | flutter: 27 | 28 | # The following line ensures that the Material Icons font is 29 | # included with your application, so that you can use the icons in 30 | # the material Icons class. 31 | uses-material-design: true 32 | assets: 33 | - images/bottomLeft.png 34 | - images/bottomRight.png 35 | - images/topLeft.png 36 | - images/topRight.png 37 | # To add assets to your application, add an assets section, like this: 38 | # assets: 39 | # - images/a_dot_burr.jpeg 40 | # - images/a_dot_ham.jpeg 41 | 42 | # An image asset can refer to one or more resolution-specific "variants", see 43 | # https://flutter.io/assets-and-images/#resolution-aware. 44 | 45 | # For details regarding adding assets from package dependencies, see 46 | # https://flutter.io/assets-and-images/#from-packages 47 | 48 | # To add custom fonts to your application, add a fonts section here, 49 | # in this "flutter" section. Each entry in this list should have a 50 | # "family" key with the font family name, and a "fonts" key with a 51 | # list giving the asset and other descriptors for the font. For 52 | # example: 53 | 54 | fonts: 55 | - family: Imgcrop 56 | fonts: 57 | - asset: fonts/Imgcrop.ttf 58 | # - family: Trajan Pro 59 | # fonts: 60 | # - asset: fonts/TrajanPro.ttf 61 | # - asset: fonts/TrajanPro_Bold.ttf 62 | # weight: 700 63 | # 64 | # For details regarding fonts from package dependencies, 65 | # see https://flutter.io/custom-fonts/#from-packages 66 | --------------------------------------------------------------------------------