diff --git a/Libraries.txt b/Libraries.txt index a03f7760..d6338af0 100644 --- a/Libraries.txt +++ b/Libraries.txt @@ -1,4 +1,4 @@ -Open Source libraries used in the Scanbot SDK for Android version 8.1.0 +Open Source libraries used in the Scanbot SDK for Android version 9.0.0 CWAC-Camera diff --git a/README.md b/README.md index 7550815f..a6d3d77e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Make sure you have the latest stable version of [Android Studio](https://develop 2. There are 4 separate folders with standalone examples: - * **classic-components-example**: Example project for the Scanbot SDK Classic Components which allow for full customization. + * **classic-components-example**: Example project for the Scanbot SDK Classic Components which allow for full customization. * **compose-custom-ui-example**: Example project for the Scanbot SDK Compose Custom Components which allow for full customization. * **document-scanner-ready-to-use-ui-example:** Example project for the Scanbot Document Scanner SDK using our Ready-To-Use UI components. * **data-capture-ready-to-use-ui-example**: Example project showcasing the Scanbot Data Capture Modules using our Ready-to-Use UI components. diff --git a/classic-components-example/README.md b/classic-components-example/README.md new file mode 100644 index 00000000..05ee2654 --- /dev/null +++ b/classic-components-example/README.md @@ -0,0 +1,11 @@ +# Scanbot SDK Classic Components examples + +This project contains multiple standalone Android app modules demonstrating the Scanbot SDK Classic Components. Each module can be opened and run on its own. The only shared code lives in the `common` module. + +## How to run a module + +1. Open `scanbot-sdk-example-android/classic-components-example` in Android Studio. +2. Sync Gradle. +3. Choose one module in the **Run** configuration (each module is an `application`). +4. Add your Scanbot SDK license key in the module’s `ExampleApplication` or stay on demo mode. +5. Run the app on a device or emulator. diff --git a/classic-components-example/adjustable-filters/proguard-rules.pro b/classic-components-example/adjustable-filters/proguard-rules.pro deleted file mode 100755 index f1b42451..00000000 --- a/classic-components-example/adjustable-filters/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FilterActivity.kt b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FilterActivity.kt index facb3372..ee30d555 100644 --- a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FilterActivity.kt +++ b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FilterActivity.kt @@ -25,8 +25,8 @@ import io.scanbot.sdk.imageprocessing.ParametricFilter import kotlinx.coroutines.* /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ diff --git a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/MainActivity.kt index 8604397d..27519171 100755 --- a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/MainActivity.kt @@ -22,8 +22,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** - Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x - Please, check the official documentation for more details: + This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. + Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -105,9 +105,16 @@ class MainActivity : AppCompatActivity() { private suspend fun createAndScanDocumentPage(imageUri: Uri): String? { val imageRef = withContext(Dispatchers.IO) { - val inputStream = contentResolver.openInputStream(imageUri) - ?: throw Exception("Cannot open input stream from URI") - ImageRef.fromInputStream(inputStream) + contentResolver.openInputStream(imageUri)?.use { inputStream -> + ImageRef.fromInputStream(inputStream) + } + } + if (imageRef == null) { + withContext(Dispatchers.Main) { + Log.e(Const.LOG_TAG, "Cannot open input stream from URI: $imageUri") + showToast("Error opening selected image!") + } + return null } val sdk = ScanbotSDK(this) diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerViewActivity.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerViewActivity.kt index 7a38a12e..54949c9f 100644 --- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerViewActivity.kt +++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerViewActivity.kt @@ -4,17 +4,12 @@ import android.Manifest import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle -import android.view.View -import android.view.ViewGroup import android.widget.ImageView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.updateLayoutParams import io.scanbot.common.Result import io.scanbot.common.onFailure import io.scanbot.common.onSuccess @@ -88,7 +83,11 @@ class BarcodeScannerViewActivity : AppCompatActivity() { image: ImageRef, captureInfo: CaptureInfo ) { - TODO("Not yet implemented") + image.toBitmap().onSuccess { bitmap -> + resultView.post { + resultView.setImageBitmap(bitmap) + } + } } override fun onSelectionOverlayBarcodeClicked(barcodeItem: BarcodeItem) { @@ -107,7 +106,6 @@ class BarcodeScannerViewActivity : AppCompatActivity() { override fun onResume() { super.onResume() - barcodeScannerView.viewController.onResume() if (ContextCompat.checkSelfPermission( this, Manifest.permission.CAMERA @@ -122,11 +120,6 @@ class BarcodeScannerViewActivity : AppCompatActivity() { } } - override fun onPause() { - super.onPause() - barcodeScannerView.viewController.onPause() - } - private fun handleSuccess(result: BarcodeScannerResult) { result.takeIf { it.barcodes.isNotEmpty() }?.let { BarcodeResultRepository.barcodeResultBundle = BarcodeResultBundle(result) diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/MainActivity.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/MainActivity.kt index b92d96a5..ebd15f03 100644 --- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/MainActivity.kt +++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/MainActivity.kt @@ -28,8 +28,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -101,14 +101,25 @@ class MainActivity : AppCompatActivity() { binding.progressBar.isVisible = true } - withContext(Dispatchers.Default) { - val inputStream = contentResolver.openInputStream(uri) ?: throw IllegalStateException("Cannot open input stream from URI: $uri") - val imageRef = ImageRef.fromInputStream(inputStream) + val imageRef = withContext(Dispatchers.IO) { + contentResolver.openInputStream(uri)?.use { inputStream -> + ImageRef.fromInputStream(inputStream) + } + } + if (imageRef == null) { + withContext(Dispatchers.Main) { + binding.progressBar.isVisible = false + showToast("Error opening selected image!") + Log.e(Const.LOG_TAG, "Cannot open input stream from URI: $uri") + } + return + } + withContext(Dispatchers.Default) { val scanner = scanbotSdk.createBarcodeScanner().getOrThrow() scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply { setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList()) - } ) + }) val result = scanner.run(imageRef).getOrNull() BarcodeResultRepository.barcodeResultBundle = result?.let { BarcodeResultBundle(it, imageRef) } diff --git a/classic-components-example/build.gradle b/classic-components-example/build.gradle index c3b0b6fa..090d3bbf 100644 --- a/classic-components-example/build.gradle +++ b/classic-components-example/build.gradle @@ -1,5 +1,5 @@ plugins { - id("com.android.application") version "8.3.2" apply false + id("com.android.application") version "8.9.1" apply false id("com.android.library") version "8.3.2" apply false id("org.jetbrains.kotlin.android") version "2.2.20" apply false } @@ -10,12 +10,12 @@ allprojects { submodulesNamespace = "io.scanbot.example" compileSdkVersion = 36 - minSdkVersion = 21 + minSdkVersion = 23 targetSdkVersion = 35 jvmToolchainVersion = 17 - scanbotSdkVersion = "8.1.0" + scanbotSdkVersion = "9.0.0.109-STAGING-SNAPSHOT" androidCoreKtxVersion = "1.6.0" constraintLayoutVersion = "2.0.4" diff --git a/classic-components-example/camera-fragment/proguard-rules.pro b/classic-components-example/camera-fragment/proguard-rules.pro deleted file mode 100755 index a988b426..00000000 --- a/classic-components-example/camera-fragment/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /Users/artem.kubiria/Development/sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/MainActivity.kt index 7d6927a6..37bf2c88 100755 --- a/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/MainActivity.kt @@ -25,8 +25,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -115,12 +115,15 @@ class MainActivity : AppCompatActivity() { } val documentImage = withContext(Dispatchers.Default) { - catchWithResult { - // load the selected image: - val inputStream = contentResolver.openInputStream(imageUri) - ?: throw IllegalStateException("Cannot open input stream from URI: $imageUri") - val image = ImageRef.fromInputStream(inputStream) + val image = contentResolver.openInputStream(imageUri)?.use { inputStream -> + ImageRef.fromInputStream(inputStream) + } + if (image == null) { + Log.e(Const.LOG_TAG, "Cannot open input stream from URI: $imageUri") + return@withContext null + } + catchWithResult { // create a new Document object with given image as original image: val newDocument = scanbotSdk.documentApi.createDocument() .getOrReturn() // can be handled with .getOrNull() if needed @@ -144,6 +147,10 @@ class MainActivity : AppCompatActivity() { withContext(Dispatchers.Main) { progressBar.visibility = View.GONE + if (documentImage == null) { + this@MainActivity.showToast("Error opening selected image!") + return@withContext + } // show Page's document image: importResultImage.setImageBitmap(documentImage) importResultImage.visibility = View.VISIBLE diff --git a/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/MainActivity.kt index 4ecce016..966b646a 100755 --- a/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/MainActivity.kt @@ -36,8 +36,8 @@ import io.scanbot.sdk.ui.camera.ShutterButton import io.scanbot.sdk.util.PolygonHelper /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -64,7 +64,7 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand askPermission() setContentView(R.layout.activity_main) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) cameraView = findViewById(R.id.camera) as ScanbotCameraXView diff --git a/classic-components-example/camera-view/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/camera-view/src/main/java/io/scanbot/example/MainActivity.kt index 0cd1654d..0df39e65 100755 --- a/classic-components-example/camera-view/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/camera-view/src/main/java/io/scanbot/example/MainActivity.kt @@ -43,8 +43,8 @@ import io.scanbot.sdk.ui.camera.ShutterButton import io.scanbot.sdk.util.PolygonHelper /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -63,13 +63,13 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand private var lastUserGuidanceHintTs = 0L private var flashEnabled = false private var autoSnappingEnabled = true - private val ignoreOrientationMistmatch = true + private val ignoreOrientationMismatch = true override fun onCreate(savedInstanceState: Bundle?) { supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY) super.onCreate(savedInstanceState) askPermission() setContentView(R.layout.activity_main) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) cameraView = findViewById(R.id.camera) as ScanbotCameraXView @@ -83,7 +83,7 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand // Please note: https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/ui-components/ setConfiguration(copyCurrentConfiguration().apply { parameters.apply { - this.ignoreOrientationMismatch = ignoreOrientationMistmatch + this.ignoreOrientationMismatch = ignoreOrientationMismatch this.acceptedSizeScore = 75 this.acceptedAngleScore = 60 } @@ -150,11 +150,11 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand ) } }.onFailure { error -> - when(error){ - is Result.InvalidLicenseError ->{ + when (error) { + is Result.InvalidLicenseError -> { Toast.makeText(this@MainActivity, "License is invalid: ${error.message}", Toast.LENGTH_LONG).show() } - else -> { + else -> { Toast.makeText(this@MainActivity, "${error.message}", Toast.LENGTH_LONG).show() } } @@ -224,7 +224,7 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand } DocumentDetectionStatus.OK_BUT_BAD_ASPECT_RATIO -> { - if (ignoreOrientationMistmatch) { + if (ignoreOrientationMismatch) { userGuidanceHint.text = "Don't move" // change polygon color to "OK" polygonView.setFillColor(POLYGON_FILL_COLOR_OK) diff --git a/classic-components-example/check-scanner/proguard-rules.pro b/classic-components-example/check-scanner/proguard-rules.pro deleted file mode 100755 index f1b42451..00000000 --- a/classic-components-example/check-scanner/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/AutoSnappingCheckRecognizerActivity.kt b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/AutoSnappingCheckRecognizerActivity.kt index f5df0939..71d08e9e 100644 --- a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/AutoSnappingCheckRecognizerActivity.kt +++ b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/AutoSnappingCheckRecognizerActivity.kt @@ -39,7 +39,7 @@ class AutoSnappingCheckScannerActivity : AppCompatActivity() { supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY) super.onCreate(savedInstanceState) setContentView(R.layout.activity_autosnapping_check_scanner) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) cameraView = findViewById(R.id.camera).also { cameraView -> diff --git a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerActivity.kt b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerActivity.kt index d9cf7677..9ac8bf25 100644 --- a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerActivity.kt +++ b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerActivity.kt @@ -31,7 +31,7 @@ class CheckScannerActivity : AppCompatActivity() { supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY) super.onCreate(savedInstanceState) setContentView(R.layout.activity_check_scanner) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) cameraView = findViewById(R.id.camera).also { cameraView -> diff --git a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerResultActivity.kt b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerResultActivity.kt index a0fd2d03..7e6cedb1 100644 --- a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerResultActivity.kt +++ b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/CheckScannerResultActivity.kt @@ -19,7 +19,7 @@ class CheckScannerResultActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_check_result) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) val fieldsLayout = findViewById(R.id.check_result_fields_layout) diff --git a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/MainActivity.kt index d42d517d..de3ed48e 100644 --- a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/MainActivity.kt @@ -25,8 +25,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -77,10 +77,21 @@ class MainActivity : AppCompatActivity() { private suspend fun scanCheck(uri: Uri) { withContext(Dispatchers.Main) { binding.progressBar.isVisible = true } - val result = withContext(Dispatchers.Default) { - val inputStream = contentResolver.openInputStream(uri) ?: throw IllegalStateException("Cannot open input stream from URI: $uri") - val imageRef = ImageRef.fromInputStream(inputStream) + val imageRef = withContext(Dispatchers.IO) { + contentResolver.openInputStream(uri)?.use { inputStream -> + ImageRef.fromInputStream(inputStream) + } + } + if (imageRef == null) { + withContext(Dispatchers.Main) { + binding.progressBar.isVisible = false + showToast("Error opening selected image!") + Log.e(Const.LOG_TAG, "Cannot open input stream from URI: $uri") + } + return + } + val result = withContext(Dispatchers.Default) { val scanner = scanbotSdk.createCheckScanner().getOrThrow() scanner.run(imageRef).getOrNull() } diff --git a/classic-components-example/common/build.gradle b/classic-components-example/common/build.gradle index e2a1776f..ef52fd20 100644 --- a/classic-components-example/common/build.gradle +++ b/classic-components-example/common/build.gradle @@ -9,14 +9,11 @@ android { defaultConfig { minSdk = project.ext.minSdkVersion - - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro", "consumer-rules.pro") } buildTypes { named("release") { minifyEnabled = false - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } diff --git a/classic-components-example/common/consumer-rules.pro b/classic-components-example/common/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/classic-components-example/common/proguard-rules.pro b/classic-components-example/common/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/classic-components-example/common/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/classic-components-example/creditcard-scanner/proguard-rules.pro b/classic-components-example/creditcard-scanner/proguard-rules.pro deleted file mode 100755 index f1b42451..00000000 --- a/classic-components-example/creditcard-scanner/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/MainActivity.kt index 5bf14381..329ac035 100755 --- a/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/MainActivity.kt @@ -13,8 +13,8 @@ import androidx.core.content.ContextCompat import io.scanbot.example.common.applyEdgeToEdge /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ diff --git a/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ScannerActivity.kt b/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ScannerActivity.kt index 43327b2c..6bcddc17 100644 --- a/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ScannerActivity.kt +++ b/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ScannerActivity.kt @@ -28,7 +28,7 @@ class ScannerActivity : AppCompatActivity() { super.onCreate(savedInstanceState) binding = ActivityScannerBinding.inflate(layoutInflater) setContentView(binding.root) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) // init scanbot sdk and create credit card scanner diff --git a/classic-components-example/document-data-extractor-autosnapping/proguard-rules.pro b/classic-components-example/document-data-extractor-autosnapping/proguard-rules.pro deleted file mode 100755 index f1b42451..00000000 --- a/classic-components-example/document-data-extractor-autosnapping/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/MainActivity.kt index 0f0d3c65..2038fdad 100755 --- a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/MainActivity.kt @@ -22,8 +22,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ @@ -51,11 +51,22 @@ class MainActivity : AppCompatActivity() { lifecycleScope.launch { val dataExtractor = scanbotSdk.createDocumentDataExtractor().getOrThrow() - val result = withContext(Dispatchers.Default) { - val inputStream = contentResolver.openInputStream(uri) ?: throw IllegalStateException("Cannot open input stream from URI: $uri") - val imageRef = ImageRef.fromInputStream(inputStream) - dataExtractor.run(imageRef).getOrNull() - } + val imageRef = withContext(Dispatchers.IO) { + contentResolver.openInputStream(uri)?.use { inputStream -> + ImageRef.fromInputStream(inputStream) + } + } + if (imageRef == null) { + withContext(Dispatchers.Main) { + showToast("Error opening selected image!") + Log.e(Const.LOG_TAG, "Cannot open input stream from URI: $uri") + } + return@launch + } + + val result = withContext(Dispatchers.Default) { + dataExtractor.run(imageRef).getOrNull() + } withContext(Dispatchers.Main) { DocumentsResultsStorage.result = result diff --git a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ScannerActivity.kt b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ScannerActivity.kt index 8d8d6399..d440f4b0 100644 --- a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ScannerActivity.kt +++ b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ScannerActivity.kt @@ -38,7 +38,7 @@ class ScannerActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_scanner) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) scanbotSdk = ScanbotSDK(this) diff --git a/classic-components-example/document-data-extractor-livedetection/proguard-rules.pro b/classic-components-example/document-data-extractor-livedetection/proguard-rules.pro deleted file mode 100755 index f1b42451..00000000 --- a/classic-components-example/document-data-extractor-livedetection/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/MainActivity.kt index f792adc3..2305a525 100755 --- a/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/MainActivity.kt +++ b/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/MainActivity.kt @@ -10,8 +10,8 @@ import io.scanbot.example.common.showToast import io.scanbot.example.databinding.ActivityMainBinding /** -Ths example uses new sdk APIs presented in Scanbot SDK v.8.x.x -Please, check the official documentation for more details: +This example uses the SDK APIs introduced in Scanbot SDK v8.x.x. +Please check the official documentation for more details: Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ */ diff --git a/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/ScannerActivity.kt b/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/ScannerActivity.kt index 25011a5c..1b5bc7fc 100644 --- a/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/ScannerActivity.kt +++ b/classic-components-example/document-data-extractor-livedetection/src/main/java/io/scanbot/example/ScannerActivity.kt @@ -28,7 +28,7 @@ class ScannerActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_scanner) - supportActionBar!!.hide() + supportActionBar?.hide() applyEdgeToEdge(this.findViewById(R.id.root_view)) cameraView = findViewById(R.id.cameraView) diff --git a/classic-components-example/document-enhancer/build.gradle b/classic-components-example/document-enhancer/build.gradle new file mode 100644 index 00000000..c3414bb5 --- /dev/null +++ b/classic-components-example/document-enhancer/build.gradle @@ -0,0 +1,47 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = project.ext.submodulesNamespace + compileSdk = project.ext.compileSdkVersion + + defaultConfig { + applicationId = project.ext.exampleAppId + minSdk = project.ext.minSdkVersion + targetSdk = project.ext.targetSdkVersion + versionCode = 1 + versionName = "1.0" + } + + buildTypes { + named("debug") { + // set this to `false` to allow debugging and run a "non-release" build + minifyEnabled = false + debuggable = true + } + } + + kotlin { + jvmToolchain(project.ext.jvmToolchainVersion) + } + + packagingOptions { + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/LICENSE' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/DEPENDENCIES' + } + + buildFeatures { + viewBinding = true + } +} + +dependencies { + implementation(project(":common")) + implementation("io.scanbot:sdk-package-1:${project.ext.scanbotSdkVersion}") + implementation("androidx.appcompat:appcompat:${project.ext.androidxAppcompatVersion}") +} diff --git a/classic-components-example/document-enhancer/src/main/AndroidManifest.xml b/classic-components-example/document-enhancer/src/main/AndroidManifest.xml new file mode 100755 index 00000000..4d1192e4 --- /dev/null +++ b/classic-components-example/document-enhancer/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/DocumentCameraActivity.kt b/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/DocumentCameraActivity.kt new file mode 100755 index 00000000..333c3103 --- /dev/null +++ b/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/DocumentCameraActivity.kt @@ -0,0 +1,187 @@ +package io.scanbot.example + +import android.Manifest +import android.content.pm.PackageManager +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.graphics.Matrix +import android.os.Bundle +import android.view.View +import android.widget.Button +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.core.view.WindowCompat +import io.scanbot.common.onSuccess + + +import io.scanbot.example.common.applyEdgeToEdge +import io.scanbot.sdk.ScanbotSDK +import io.scanbot.sdk.camera.CaptureInfo +import io.scanbot.sdk.document.DocumentScannerFrameHandler +import io.scanbot.sdk.document.ui.DocumentScannerView +import io.scanbot.sdk.document.ui.IDocumentScannerViewCallback +import io.scanbot.sdk.documentscanner.DocumentDetectionStatus +import io.scanbot.sdk.documentscanner.DocumentEnhancer +import io.scanbot.sdk.documentscanner.DocumentScanner +import io.scanbot.sdk.documentscanner.DocumentStraighteningMode +import io.scanbot.sdk.documentscanner.DocumentStraighteningParameters +import io.scanbot.sdk.geometry.AspectRatio +import io.scanbot.sdk.image.ImageRef +import io.scanbot.sdk.process.ImageProcessor +import io.scanbot.sdk.ui.camera.ShutterButton +import io.scanbot.sdk.ui.view.base.configuration.CameraOrientationMode + +class DocumentCameraActivity : AppCompatActivity() { + + private var lastUserGuidanceHintTs = 0L + private var flashEnabled = false + private var autoSnappingEnabled = true + private val ignoreOrientationMistmatch = true + + private lateinit var documentScannerView: DocumentScannerView + + private lateinit var resultView: ImageView + private lateinit var userGuidanceHint: TextView + private lateinit var autoSnappingToggleButton: Button + private lateinit var shutterButton: ShutterButton + + + override fun onCreate(savedInstanceState: Bundle?) { + supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY) + + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_camera) + askPermission() + supportActionBar!!.hide() + applyEdgeToEdge(findViewById(R.id.root_view)) + + val scanbotSdk = ScanbotSDK(this) + + documentScannerView = findViewById(R.id.document_scanner_view) + + resultView = findViewById(R.id.result) as ImageView + val documentEnhancer = scanbotSdk.createDocumentEnhancer() + scanbotSdk.createDocumentScanner().onSuccess { documentScanner -> + + documentScannerView.apply { + initCamera() + initScanningBehavior( + documentScanner, + { result, frame -> + // Here you are continuously notified about document scanning results. + // For example, you can show a user guidance text depending on the current scanning status. + result.onSuccess { data -> + } + false // typically you need to return false + }, + object : IDocumentScannerViewCallback { + override fun onCameraOpen() { + documentScannerView.viewController.useFlash(flashEnabled) + } + + override fun onPictureTaken(image: ImageRef, captureInfo: CaptureInfo) { + documentEnhancer.onSuccess { documentEnhancer -> + processPictureTaken(image, documentEnhancer) + } + + + // continue scanning + documentScannerView.postDelayed({ + documentScannerView.viewController.startPreview() + }, 1000) + } + } + ) + } + } + + documentScannerView.polygonConfiguration.apply { + setPolygonFillColor(POLYGON_FILL_COLOR) + setPolygonFillColorOK(POLYGON_FILL_COLOR_OK) + } + + documentScannerView.viewController.apply { + setAcceptedAngleScore(60.0) + setAcceptedSizeScore(75.0) + setIgnoreOrientationMismatch(ignoreOrientationMistmatch) + + // Please note: https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/autosnapping/#sensitivity + setAutoSnappingSensitivity(0.85f) + } + + shutterButton = findViewById(R.id.shutterButton) + shutterButton.setOnClickListener { documentScannerView.viewController.takePicture(false) } + shutterButton.visibility = View.VISIBLE + + findViewById(R.id.flashToggle).setOnClickListener { + flashEnabled = !flashEnabled + documentScannerView.viewController.useFlash(flashEnabled) + } + + autoSnappingToggleButton = findViewById(R.id.autoSnappingToggle) + autoSnappingToggleButton.setOnClickListener { + autoSnappingEnabled = !autoSnappingEnabled + setAutoSnapEnabled(autoSnappingEnabled) + } + autoSnappingToggleButton.post { setAutoSnapEnabled(autoSnappingEnabled) } + } + + private fun askPermission() { + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.CAMERA + ) != PackageManager.PERMISSION_GRANTED + ) { + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 999) + } + } + + override fun onResume() { + super.onResume() + } + + override fun onPause() { + super.onPause() + } + + private fun processPictureTaken(image: ImageRef, documentEnhancer: DocumentEnhancer) { + // STRAIGHTEN SCANNED IMAGE ASSUMING DOCUMENT IS BENT + // Run document enhancer unwarping on original image: + val result = documentEnhancer.straighten(image, DocumentStraighteningParameters().apply { + straighteningMode = DocumentStraighteningMode.STRAIGHTEN + // uncomment if you want wo set specific aspect ratios for documents + // aspectRatios = listOf(AspectRatio(29.0, 21.0)) + }).getOrNull() + + resultView.post { + resultView.setImageBitmap( + result?.straightenedImage?.toBitmap()?.getOrNull() + ) + } + } + + private fun setAutoSnapEnabled(enabled: Boolean) { + documentScannerView.viewController.apply { + autoSnappingEnabled = enabled + isFrameProcessingEnabled = enabled + } + documentScannerView.polygonConfiguration.setPolygonViewVisible(enabled) + + autoSnappingToggleButton.text = "Automatic ${if (enabled) "ON" else "OFF"}" + if (enabled) { + shutterButton.showAutoButton() + } else { + shutterButton.showManualButton() + userGuidanceHint.visibility = View.GONE + } + } + + companion object { + private val POLYGON_FILL_COLOR = Color.parseColor("#55ff0000") + private val POLYGON_FILL_COLOR_OK = Color.parseColor("#4400ff00") + } +} diff --git a/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/ExampleApplication.kt new file mode 100755 index 00000000..d366bec5 --- /dev/null +++ b/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/ExampleApplication.kt @@ -0,0 +1,55 @@ +package io.scanbot.example + +import android.app.Application +import io.scanbot.sdk.ScanbotSDK +import io.scanbot.sdk.ScanbotSDKInitializer +import io.scanbot.sdk.util.log.LoggerProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext + +class ExampleApplication : Application(), CoroutineScope { + + private var job: Job = Job() + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job + + /* + * TODO 1/2: Add the Scanbot SDK license key here. + * Please note: The Scanbot SDK will run without a license key for one minute per session! + * After the trial period is over all Scanbot SDK functions as well as the UI components will stop working. + * You can get an unrestricted "no-strings-attached" 30 day trial license key for free. + * Please submit the trial license form (https://scanbot.io/trial/) on our website by using + * the app identifier "io.scanbot.example.sdk.android" of this example app. + */ + val licenseKey = "" + + override fun onCreate() { + super.onCreate() + + ScanbotSDKInitializer() + .withLogging(true) + // TODO 2/2: Enable the Scanbot SDK license key + //.license(this, licenseKey) + .licenseErrorHandler { status, feature, statusMessage -> + LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage") + LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}") + } + //.sdkFilesDirectory(this, getExternalFilesDir(null)!!) + .initialize(this) + + LoggerProvider.logger.d("ExampleApplication", "Scanbot SDK was initialized") + + val licenseInfo = ScanbotSDK(this).licenseInfo + LoggerProvider.logger.d("ExampleApplication", "License status: ${licenseInfo.status}") + LoggerProvider.logger.d("ExampleApplication", "License isValid: ${licenseInfo.isValid}") + LoggerProvider.logger.d("ExampleApplication", "License expirationDate: ${licenseInfo.expirationDateString}") + + launch { + // Clear all previously created documents in storage + ScanbotSDK(this@ExampleApplication).documentApi.deleteAllDocuments() + } + } +} diff --git a/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/MainActivity.kt new file mode 100644 index 00000000..c54eeb4e --- /dev/null +++ b/classic-components-example/document-enhancer/src/main/java/io/scanbot/example/MainActivity.kt @@ -0,0 +1,119 @@ +package io.scanbot.example + +import android.Manifest +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.Log +import android.view.View +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import io.scanbot.common.onSuccess + + +import io.scanbot.example.common.Const +import io.scanbot.example.common.applyEdgeToEdge +import io.scanbot.example.common.showToast +import io.scanbot.example.databinding.ActivityMainBinding +import io.scanbot.sdk.ScanbotSDK +import io.scanbot.sdk.documentscanner.DocumentStraighteningMode +import io.scanbot.sdk.documentscanner.DocumentStraighteningParameters +import io.scanbot.sdk.image.ImageRef +import io.scanbot.sdk.util.PolygonHelper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** +Ths example uses new SDK APIs presented in Scanbot SDK v.8.x.x +Please, check the official documentation for more details: +Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/ +ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/ + */ + +class MainActivity : AppCompatActivity() { + + private val scanbotSdk: ScanbotSDK by lazy { ScanbotSDK(this) } + + private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) } + + private val requestCameraLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (isGranted) { + startActivity(Intent(this, DocumentCameraActivity::class.java)) + } else { + this@MainActivity.showToast("Camera permission is required to run this example!") + } + } + + private val selectGalleryImageResultLauncher = + registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> + if (!scanbotSdk.licenseInfo.isValid) { + this@MainActivity.showToast("1-minute trial license has expired!") + Log.e(Const.LOG_TAG, "1-minute trial license has expired!") + return@registerForActivityResult + } + + if (uri == null) { + showToast("Error obtaining selected image!") + Log.e(Const.LOG_TAG, "Error obtaining selected image!") + return@registerForActivityResult + } + + lifecycleScope.launch { processImage(uri) } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + supportActionBar?.hide() + applyEdgeToEdge(findViewById(R.id.root_view)) + + binding.showDocScannerBtn.setOnClickListener { + requestCameraLauncher.launch(Manifest.permission.CAMERA) + } + + binding.importImage.setOnClickListener { + selectGalleryImageResultLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) + } + } + + /** Imports a selected image as original image and performs auto document scanning on it. */ + private suspend fun processImage(uri: Uri) { + withContext(Dispatchers.Main) { + binding.progressBar.visibility = View.VISIBLE + this@MainActivity.showToast("Importing page...") + } + + val documentImage = withContext(Dispatchers.Default) { + // load the selected image + val image = contentResolver.openInputStream(uri)?.use { inputStream -> + ImageRef.fromInputStream(inputStream) + } ?: throw IllegalStateException("Cannot open input stream from URI: $uri") + + // create a new Page object with given image as original image: + val document = scanbotSdk.documentApi.createDocument() + .getOrNull() //can be handled with .getOrThrow() if needed + val page = + document?.addPage(image)?.getOrNull() //can be handled with .getOrThrow() if needed + + // run document scanning on the page image: + page?.apply(newStraighteningParameters = DocumentStraighteningParameters().apply { + straighteningMode = DocumentStraighteningMode.STRAIGHTEN + // uncomment if you want wo set specific aspect ratios for documents + // aspectRatios = listOf(AspectRatio(29.0, 21.0)) + }) + page?.documentImage + } + + withContext(Dispatchers.Main) { + binding.progressBar.visibility = View.GONE + + // present cropped page image: + binding.importResultImage.setImageBitmap(documentImage) + binding.importResultImage.visibility = View.VISIBLE + } + } +} diff --git a/classic-components-example/document-enhancer/src/main/res/layout/activity_camera.xml b/classic-components-example/document-enhancer/src/main/res/layout/activity_camera.xml new file mode 100755 index 00000000..f059f4db --- /dev/null +++ b/classic-components-example/document-enhancer/src/main/res/layout/activity_camera.xml @@ -0,0 +1,43 @@ + + + + +