├── ios
├── Assets
│ └── .gitkeep
├── Classes
│ ├── CunningDocumentScannerPlugin.h
│ ├── CunningDocumentScannerPlugin.m
│ ├── CunningScannerOptions.swift
│ └── SwiftCunningDocumentScannerPlugin.swift
├── .gitignore
└── cunning_document_scanner.podspec
├── android
├── settings.gradle
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ ├── integers.xml
│ │ │ ├── themes.xml
│ │ │ └── dimens.xml
│ │ ├── xml
│ │ │ └── file_paths.xml
│ │ ├── drawable
│ │ │ ├── ic_baseline_add_24.xml
│ │ │ ├── ic_baseline_check_24.xml
│ │ │ └── ic_baseline_arrow_back_24.xml
│ │ ├── animator
│ │ │ └── button_grow_animation.xml
│ │ └── layout
│ │ │ └── activity_image_crop.xml
│ │ ├── kotlin
│ │ └── biz
│ │ │ └── cunning
│ │ │ └── cunning_document_scanner
│ │ │ ├── fallback
│ │ │ ├── DocumentScannerFileProvider.kt
│ │ │ ├── enums
│ │ │ │ └── QuadCorner.kt
│ │ │ ├── constants
│ │ │ │ ├── DefaultSetting.kt
│ │ │ │ └── DocumentScannerExtra.kt
│ │ │ ├── models
│ │ │ │ ├── Line.kt
│ │ │ │ ├── Document.kt
│ │ │ │ ├── Point.kt
│ │ │ │ └── Quad.kt
│ │ │ ├── extensions
│ │ │ │ ├── ImageButton.kt
│ │ │ │ ├── Bitmap.kt
│ │ │ │ ├── AppCompatActivity.kt
│ │ │ │ ├── Point.kt
│ │ │ │ └── Canvas.kt
│ │ │ ├── utils
│ │ │ │ ├── FileUtil.kt
│ │ │ │ ├── CameraUtil.kt
│ │ │ │ └── ImageUtil.kt
│ │ │ ├── ui
│ │ │ │ ├── CircleButton.kt
│ │ │ │ ├── DoneButton.kt
│ │ │ │ └── ImageCropView.kt
│ │ │ └── DocumentScannerActivity.kt
│ │ │ └── CunningDocumentScannerPlugin.kt
│ │ └── AndroidManifest.xml
└── build.gradle
├── example
├── ios
│ ├── Runner
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Assets.xcassets
│ │ │ ├── LaunchImage.imageset
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ ├── README.md
│ │ │ │ └── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── 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-1024x1024@1x.png
│ │ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ │ └── Contents.json
│ │ ├── AppDelegate.swift
│ │ ├── Base.lproj
│ │ │ ├── Main.storyboard
│ │ │ └── LaunchScreen.storyboard
│ │ └── Info.plist
│ ├── Flutter
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── AppFrameworkInfo.plist
│ ├── Runner.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ ├── xcshareddata
│ │ │ └── xcschemes
│ │ │ │ └── Runner.xcscheme
│ │ └── project.pbxproj
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── .gitignore
│ ├── Podfile.lock
│ └── Podfile
├── android
│ ├── gradle.properties
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── 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
│ │ │ │ │ ├── drawable
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── values
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values-night
│ │ │ │ │ │ └── styles.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── com
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ └── settings.gradle
├── .metadata
├── README.md
├── .gitignore
├── test
│ └── widget_test.dart
├── analysis_options.yaml
├── lib
│ └── main.dart
├── pubspec.yaml
└── pubspec.lock
├── analysis_options.yaml
├── lib
├── cunning_document_scanner.dart
└── src
│ ├── ios_image_format.dart
│ ├── exceptions.dart
│ ├── ios_scanner_options.dart
│ └── cunning_document_scanner.dart
├── .metadata
├── .github
├── workflows
│ ├── publish.yml
│ └── dart.yml
└── dependabot.yml
├── .vscode
└── launch.json
├── .gitignore
├── LICENSE
├── pubspec.yaml
├── test
├── mocks
│ └── mock_permission_handler_platform.dart
├── cunning_document_scanner_test.dart
└── src
│ └── exceptions_test.dart
├── CHANGELOG.md
└── README.md
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'cunning_document_scanner'
2 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4G
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/android/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Original Image With Cropper
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Classes/CunningDocumentScannerPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface CunningDocumentScannerPlugin : NSObject
4 | @end
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | # Additional information about this file can be found at
4 | # https://dart.dev/guides/language/analysis-options
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/android/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 | #D0E4FF
5 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jachzen/cunning_document_scanner/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner_example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity()
6 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 100
4 | 150
5 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/DocumentScannerFileProvider.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback
2 |
3 | import androidx.core.content.FileProvider
4 |
5 | class DocumentScannerFileProvider: FileProvider() {
6 | }
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
6 |
--------------------------------------------------------------------------------
/lib/cunning_document_scanner.dart:
--------------------------------------------------------------------------------
1 | // Cunning Document Scanner - A simple document scanning library for Flutter.
2 |
3 | export 'src/cunning_document_scanner.dart';
4 | export 'src/exceptions.dart';
5 | export 'src/ios_image_format.dart';
6 | export 'src/ios_scanner_options.dart';
7 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/enums/QuadCorner.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.enums
2 |
3 | /**
4 | * enums for all 4 quad corners
5 | */
6 | enum class QuadCorner {
7 | TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT
8 | }
--------------------------------------------------------------------------------
/lib/src/ios_image_format.dart:
--------------------------------------------------------------------------------
1 | /// Enumerates the different output image formats are supported.
2 | enum IosImageFormat {
3 | /// Indicates the output image should be formatted as JPEG image.
4 | jpg,
5 |
6 | /// Indicates the output image should be formatted as PNG image.
7 | png,
8 | }
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b
8 | channel: stable
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/src/main/res/drawable/ic_baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/drawable/ic_baseline_check_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to pub.dev
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v[0-9]+.[0-9]+.[0-9]+*'
7 |
8 | jobs:
9 | publish:
10 | permissions:
11 | id-token: write # Required for authentication using OIDC
12 | uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
13 | # with:
14 | # working-directory: path/to/package/within/repository
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/constants/DefaultSetting.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.constants
2 |
3 | /**
4 | * This class contains default document scanner options
5 | */
6 | class DefaultSetting {
7 | companion object {
8 | const val CROPPED_IMAGE_QUALITY = 100
9 | const val MAX_NUM_DOCUMENTS = 24
10 | }
11 | }
--------------------------------------------------------------------------------
/example/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.
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | project.buildDir = "${rootProject.buildDir}/${project.name}"
11 | }
12 | subprojects {
13 | project.evaluationDependsOn(':app')
14 | }
15 |
16 | tasks.register("clean", Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
--------------------------------------------------------------------------------
/android/src/main/res/drawable/ic_baseline_arrow_back_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/android/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "example",
9 | "cwd": "example",
10 | "request": "launch",
11 | "type": "dart"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/constants/DocumentScannerExtra.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.constants
2 |
3 | /**
4 | * This class contains constants meant to be used as intent extras
5 | */
6 | class DocumentScannerExtra {
7 | companion object {
8 | const val EXTRA_CROPPED_IMAGE_QUALITY = "croppedImageQuality"
9 | const val EXTRA_MAX_NUM_DOCUMENTS = "maxNumDocuments"
10 | }
11 | }
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @main
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/models/Line.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.models
2 |
3 | import android.graphics.PointF
4 |
5 | /**
6 | * represents a line connecting 2 Android points
7 | *
8 | * @param fromPoint the 1st point
9 | * @param toPoint the 2nd point
10 | * @constructor creates a line connecting 2 points
11 | */
12 | class Line(fromPoint: PointF, toPoint: PointF) {
13 | val from: PointF = fromPoint
14 | val to: PointF = toPoint
15 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/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/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/Generated.xcconfig
37 | /Flutter/ephemeral/
38 | /Flutter/flutter_export_environment.sh
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
25 | /pubspec.lock
26 | **/doc/api/
27 | .dart_tool/
28 | .packages
29 | build/
30 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # cunning_document_scanner_example
2 |
3 | Demonstrates how to use the cunning_document_scanner plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/extensions/ImageButton.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.extensions
2 |
3 | import android.widget.ImageButton
4 |
5 | /**
6 | * This function adds an on click listener to the button. It makes the button not clickable,
7 | * calls the on click function, and then makes the button clickable. This prevents the on click
8 | * function from being called while it runs.
9 | *
10 | * @param onClick the click event handler
11 | */
12 | fun ImageButton.onClick(onClick: () -> Unit) {
13 | setOnClickListener {
14 | isClickable = false
15 | onClick()
16 | isClickable = true
17 | }
18 | }
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pub"
9 | directory: "/"
10 | schedule:
11 | interval: "weekly"
12 | time: "09:00"
13 | timezone: Europe/Berlin
14 | - package-ecosystem: "pub"
15 | directory: "/example/"
16 | schedule:
17 | interval: "weekly"
18 | time: "09:00"
19 | timezone: Europe/Berlin
--------------------------------------------------------------------------------
/.github/workflows/dart.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 |
6 | name: Flutter CI
7 |
8 | on:
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v6
18 | - uses: subosito/flutter-action@v2
19 |
20 | - name: Install Dependencies
21 | run: flutter pub get
22 |
23 | - name: Analyze Project Source
24 | run: flutter analyze
25 |
26 | - name: Run tests
27 | run: flutter test
28 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Classes/CunningDocumentScannerPlugin.m:
--------------------------------------------------------------------------------
1 | #import "CunningDocumentScannerPlugin.h"
2 | #if __has_include()
3 | #import
4 | #else
5 | // Support project import fallback if the generated compatibility header
6 | // is not copied when this plugin is created as a library.
7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
8 | #import "cunning_document_scanner-Swift.h"
9 | #endif
10 |
11 | @implementation CunningDocumentScannerPlugin
12 | + (void)registerWithRegistrar:(NSObject*)registrar {
13 | [SwiftCunningDocumentScannerPlugin registerWithRegistrar:registrar];
14 | }
15 | @end
16 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/models/Document.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.models
2 |
3 | /**
4 | * This class contains the original document photo, and a cropper. The user can drag the corners
5 | * to make adjustments to the detected corners.
6 | *
7 | * @param originalPhotoFilePath the photo file path before cropping
8 | * @param originalPhotoWidth the original photo width
9 | * @param originalPhotoHeight the original photo height
10 | * @param corners the document's 4 corner points
11 | * @constructor creates a document
12 | */
13 | class Document(
14 | val originalPhotoFilePath: String,
15 | private val originalPhotoWidth: Int,
16 | val originalPhotoHeight: Int,
17 | var corners: Quad
18 | ) {
19 | }
--------------------------------------------------------------------------------
/example/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 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | plugins {
21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
22 | id "com.android.application" version '8.13.1' apply false
23 | id "org.jetbrains.kotlin.android" version "2.2.21" apply false
24 | }
25 |
26 | include ":app"
27 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | .cxx/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Web related
36 | lib/generated_plugin_registrant.dart
37 |
38 | # Symbolication related
39 | app.*.symbols
40 |
41 | # Obfuscation related
42 | app.*.map.json
43 |
44 | # Android Studio will place build artifacts here
45 | /android/app/debug
46 | /android/app/profile
47 | /android/app/release
48 |
--------------------------------------------------------------------------------
/ios/cunning_document_scanner.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 | # Run `pod lib lint cunning_document_scanner.podspec` to validate before publishing.
4 | #
5 | Pod::Spec.new do |s|
6 | s.name = 'cunning_document_scanner'
7 | s.version = '1.0.0'
8 | s.summary = 'A new flutter plugin project.'
9 | s.description = <<-DESC
10 | A new flutter plugin project.
11 | DESC
12 | s.homepage = 'http://example.com'
13 | s.license = { :file => '../LICENSE' }
14 | s.author = { 'Cunning GmbH' => 'marcel@cunning.biz' }
15 | s.source = { :path => '.' }
16 | s.source_files = 'Classes/**/*'
17 | s.dependency 'Flutter'
18 | s.platform = :ios, '13.0'
19 |
20 | # Flutter.framework does not contain a i386 slice.
21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
22 | s.swift_version = '5.0'
23 | end
24 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:cunning_document_scanner_example/main.dart';
12 |
13 | void main() {
14 | testWidgets('View is created', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(const MyApp());
17 |
18 | // Verify that platform version is retrieved.
19 | expect(
20 | find.byWidgetPredicate(
21 | (Widget widget) =>
22 | widget is Text && widget.data!.startsWith('Add Pictures'),
23 | ),
24 | findsOneWidget,
25 | );
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/src/exceptions.dart:
--------------------------------------------------------------------------------
1 | /// Custom exceptions thrown by `CunningDocumentScanner`.
2 | class CunningDocumentScannerException implements Exception {
3 | /// A short message describing the error.
4 | final String message;
5 |
6 | /// Optional code to categorize errors (e.g. 'permission_denied').
7 | final String? code;
8 |
9 | const CunningDocumentScannerException(this.message, {this.code});
10 |
11 | /// Named constructor for permission errors.
12 | const CunningDocumentScannerException.permissionDenied([
13 | String message = 'Permission not granted',
14 | ]) : this(message, code: 'permission_denied');
15 |
16 | @override
17 | String toString() =>
18 | 'CunningDocumentScannerException(${code ?? 'error'}): $message';
19 |
20 | @override
21 | bool operator ==(Object other) =>
22 | identical(this, other) ||
23 | other is CunningDocumentScannerException &&
24 | runtimeType == other.runtimeType &&
25 | message == other.message &&
26 | code == other.code;
27 |
28 | @override
29 | int get hashCode => message.hashCode ^ code.hashCode;
30 | }
31 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/extensions/Bitmap.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.extensions
2 |
3 | import android.graphics.Bitmap
4 | import java.io.File
5 | import java.io.FileOutputStream
6 | import kotlin.math.sqrt
7 |
8 | /**
9 | * This converts the bitmap to base64
10 | *
11 | * @param file the bitmap gets saved to this file
12 | */
13 | fun Bitmap.saveToFile(file: File, quality: Int) {
14 | val fileOutputStream = FileOutputStream(file)
15 | compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream)
16 | fileOutputStream.close()
17 | }
18 |
19 | /**
20 | * This resizes the image, so that the byte count is a little less than targetBytes
21 | *
22 | * @param targetBytes the returned bitmap has a size a little less than targetBytes
23 | */
24 | fun Bitmap.changeByteCountByResizing(targetBytes: Int): Bitmap {
25 | val scale = sqrt(targetBytes.toDouble() / byteCount.toDouble())
26 | return Bitmap.createScaledBitmap(
27 | this,
28 | (width * scale).toInt(),
29 | (height * scale).toInt(),
30 | true
31 | )
32 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Marcel Pater
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 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/extensions/AppCompatActivity.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.extensions
2 |
3 | import android.graphics.Rect
4 | import androidx.appcompat.app.AppCompatActivity
5 |
6 | @Suppress("DEPRECATION")
7 | /**
8 | * @property screenBounds the screen bounds (used to get screen width and height)
9 | */
10 | val AppCompatActivity.screenBounds: Rect get() {
11 | // currentWindowMetrics was added in Android R
12 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
13 | return windowManager.currentWindowMetrics.bounds
14 | }
15 |
16 | // fall back to get screen width and height if using a version before Android R
17 | return Rect(
18 | 0, 0 , windowManager.defaultDisplay.width, windowManager.defaultDisplay.height
19 | )
20 | }
21 |
22 | /**
23 | * @property screenWidth the screen width
24 | */
25 | val AppCompatActivity.screenWidth: Int get() = screenBounds.width()
26 |
27 | /**
28 | * @property screenHeight the screen height
29 | */
30 | val AppCompatActivity.screenHeight: Int get() = screenBounds.height()
--------------------------------------------------------------------------------
/android/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0dp
4 | 1
5 | 0.1dp
6 | 5dp
7 | 200dp
8 | 25px
9 | 4px
10 | 5px
11 | 1dp
12 | 1.07
13 | 0dp
14 | 15.4dp
15 | 75dp
16 | 2.91dp
17 | 8dp
18 | 54.5dp
19 | 2dp
20 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'biz.cunning.cunning_document_scanner'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | ext.kotlin_version = '1.8.22'
6 | repositories {
7 | google()
8 | mavenCentral()
9 | }
10 |
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:8.3.0'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | }
15 | }
16 |
17 | rootProject.allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 | }
23 |
24 | apply plugin: 'com.android.library'
25 | apply plugin: 'kotlin-android'
26 |
27 | android {
28 | namespace 'biz.cunning.cunning_document_scanner'
29 |
30 | compileSdk 34
31 |
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_8
34 | targetCompatibility JavaVersion.VERSION_1_8
35 | }
36 |
37 | kotlinOptions {
38 | jvmTarget = '1.8'
39 | }
40 |
41 | sourceSets {
42 | main.java.srcDirs += 'src/main/kotlin'
43 | }
44 |
45 | defaultConfig {
46 | minSdk 21
47 | }
48 | }
49 |
50 | dependencies {
51 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
52 | implementation 'com.google.android.gms:play-services-mlkit-document-scanner:16.0.0'
53 | }
54 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - cunning_document_scanner (1.0.0):
3 | - Flutter
4 | - Flutter (1.0.0)
5 | - path_provider_foundation (0.0.1):
6 | - Flutter
7 | - FlutterMacOS
8 | - permission_handler_apple (9.3.0):
9 | - Flutter
10 |
11 | DEPENDENCIES:
12 | - cunning_document_scanner (from `.symlinks/plugins/cunning_document_scanner/ios`)
13 | - Flutter (from `Flutter`)
14 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
15 | - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
16 |
17 | EXTERNAL SOURCES:
18 | cunning_document_scanner:
19 | :path: ".symlinks/plugins/cunning_document_scanner/ios"
20 | Flutter:
21 | :path: Flutter
22 | path_provider_foundation:
23 | :path: ".symlinks/plugins/path_provider_foundation/darwin"
24 | permission_handler_apple:
25 | :path: ".symlinks/plugins/permission_handler_apple/ios"
26 |
27 | SPEC CHECKSUMS:
28 | cunning_document_scanner: 7cb9bd173f7cc7b11696dde98d01492187fc3a67
29 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
30 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
31 | permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
32 |
33 | PODFILE CHECKSUM: e78c989774f3b5b54daf69ce13097109fe4b0da3
34 |
35 | COCOAPODS: 1.15.2
36 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
8 |
9 |
14 |
15 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/utils/FileUtil.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.utils
2 |
3 | import android.os.Environment
4 | import androidx.activity.ComponentActivity
5 | import java.io.File
6 | import java.io.IOException
7 | import java.text.SimpleDateFormat
8 | import java.util.Locale
9 | import java.util.Date
10 |
11 | /**
12 | * This class contains a helper function creating temporary files
13 | *
14 | * @constructor creates file util
15 | */
16 | class FileUtil {
17 | /**
18 | * create a temporary file
19 | *
20 | * @param activity the current activity
21 | * @param pageNumber the current document page number
22 | */
23 | @Throws(IOException::class)
24 | fun createImageFile(activity: ComponentActivity, pageNumber: Int): File {
25 | // use current time to make file name more unique
26 | val dateTime: String = SimpleDateFormat(
27 | "yyyyMMdd_HHmmss",
28 | Locale.US
29 | ).format(Date())
30 |
31 | // create file in pictures directory
32 | val storageDir: File? = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
33 | return File.createTempFile(
34 | "DOCUMENT_SCAN_${pageNumber}_${dateTime}",
35 | ".jpg",
36 | storageDir
37 | )
38 | }
39 | }
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: cunning_document_scanner
2 | description: A document scanner plugin for flutter. Scan and crop automatically on iOS and Android.
3 | version: 2.0.0
4 | homepage: https://cunning.biz
5 | repository: https://github.com/jachzen/cunning_document_scanner
6 |
7 | environment:
8 | sdk: '>=3.0.0 <4.0.0'
9 | flutter: ">=2.5.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | permission_handler: ^12.0.1
15 | permission_handler_platform_interface: ^4.3.0
16 | plugin_platform_interface: ^2.1.8
17 |
18 | dev_dependencies:
19 | flutter_test:
20 | sdk: flutter
21 | flutter_lints: ">=3.0.1 <7.0.0"
22 | mockito: ^5.6.1
23 |
24 | # For information on the generic Dart part of this file, see the
25 | # following page: https://dart.dev/tools/pub/pubspec
26 |
27 | # The following section is specific to Flutter.
28 | flutter:
29 | # This section identifies this Flutter project as a plugin project.
30 | # The 'pluginClass' and Android 'package' identifiers should not ordinarily
31 | # be modified. They are used by the tooling to maintain consistency when
32 | # adding or updating assets for this project.
33 | plugin:
34 | platforms:
35 | android:
36 | package: biz.cunning.cunning_document_scanner
37 | pluginClass: CunningDocumentScannerPlugin
38 | ios:
39 | pluginClass: CunningDocumentScannerPlugin
40 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/biz/cunning/cunning_document_scanner/fallback/models/Point.kt:
--------------------------------------------------------------------------------
1 | package biz.cunning.cunning_document_scanner.fallback.models
2 |
3 |
4 | //javadoc:Point_
5 | class Point @JvmOverloads constructor(x: Double = 0.0, y: Double = 0.0) {
6 | var x = 0.0
7 | var y = 0.0
8 |
9 | init {
10 | this.x = x
11 | this.y = y
12 | }
13 |
14 | fun set(vals: DoubleArray?) {
15 | if (vals != null) {
16 | x = if (vals.size > 0) vals[0] else 0.0
17 | y = if (vals.size > 1) vals[1] else 0.0
18 | } else {
19 | x = 0.0
20 | y = 0.0
21 | }
22 | }
23 |
24 |
25 | override fun hashCode(): Int {
26 | val prime = 31
27 | var result = 1
28 | var temp: Long
29 | temp = java.lang.Double.doubleToLongBits(x)
30 | result = prime * result + (temp xor (temp ushr 32)).toInt()
31 | temp = java.lang.Double.doubleToLongBits(y)
32 | result = prime * result + (temp xor (temp ushr 32)).toInt()
33 | return result
34 | }
35 |
36 | override fun equals(other: Any?): Boolean {
37 | if (this === other) return true
38 | if (other !is Point) return false
39 | val it = other
40 | return x == it.x && y == it.y
41 | }
42 |
43 | override fun toString(): String {
44 | return "{$x, $y}"
45 | }
46 | }
--------------------------------------------------------------------------------
/lib/src/ios_scanner_options.dart:
--------------------------------------------------------------------------------
1 | import 'ios_image_format.dart';
2 |
3 | /// Different options that modify the behavior of the document scanner on iOS.
4 | ///
5 | /// The [imageFormat] specifies the format of the output image file. Available
6 | /// options are [IosImageFormat.jpeg] or [IosImageFormat.png]. Default value is
7 | /// [IosImageFormat.png].
8 | ///
9 | /// If [imageFormat] is set to [IosImageFormat.jpeg] the [jpgCompressionQuality]
10 | /// can be used to control the quality of the resulting JPEG image. The value
11 | /// 0.0 represents the maximum compression (or lowest quality) while the value
12 | /// 1.0 represents the least compression (or best quality). Default value is 1.0.
13 | final class IosScannerOptions {
14 | /// Creates a [IosScannerOptions].
15 | const IosScannerOptions({
16 | this.imageFormat = IosImageFormat.png,
17 | this.jpgCompressionQuality = 1.0,
18 | });
19 |
20 | final IosImageFormat imageFormat;
21 |
22 | /// The quality of the resulting JPEG image, expressed as a value from 0.0 to
23 | /// 1.0.
24 | ///
25 | /// The value 0.0 represents the maximum compression (or lowest quality) while
26 | /// the value 1.0 represents the least compression (or best quality). The
27 | /// [jpgCompressionQuality] only has an effect if the [imageFormat] is set to
28 | /// [IosImageFormat.jpeg] and is ignored otherwise.
29 | final double jpgCompressionQuality;
30 | }
31 |
--------------------------------------------------------------------------------
/example/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/test/mocks/mock_permission_handler_platform.dart:
--------------------------------------------------------------------------------
1 | import 'package:mockito/mockito.dart';
2 | import 'package:permission_handler_platform_interface/permission_handler_platform_interface.dart';
3 | import 'package:plugin_platform_interface/plugin_platform_interface.dart';
4 |
5 | class MockPermissionHandlerPlatform extends Mock
6 | with MockPlatformInterfaceMixin
7 | implements PermissionHandlerPlatform {
8 | final PermissionStatus permissionStatus;
9 | final ServiceStatus serviceStatus;
10 |
11 | MockPermissionHandlerPlatform(
12 | {this.permissionStatus = PermissionStatus.granted,
13 | this.serviceStatus = ServiceStatus.enabled});
14 |
15 | @override
16 | Future checkPermissionStatus(Permission permission) =>
17 | Future.value(permissionStatus);
18 |
19 | @override
20 | Future checkServiceStatus(Permission permission) =>
21 | Future.value(serviceStatus);
22 |
23 | @override
24 | Future openAppSettings() => Future.value(true);
25 |
26 | @override
27 | Future