diff --git a/classic-components-example/adjustable-filters/build.gradle b/classic-components-example/adjustable-filters/build.gradle
index d76fef57..2a342282 100644
--- a/classic-components-example/adjustable-filters/build.gradle
+++ b/classic-components-example/adjustable-filters/build.gradle
@@ -37,8 +37,6 @@ dependencies {
implementation("androidx.appcompat:appcompat:${project.ext.androidxAppcompatVersion}")
implementation("androidx.constraintlayout:constraintlayout:${project.ext.constraintLayoutVersion}")
implementation("io.scanbot:sdk-package-1:${project.ext.scanbotSdkVersion}")
- implementation("io.scanbot:sdk-package-ui:${project.ext.scanbotSdkVersion}")
- implementation("io.scanbot:sdk-ml-imageprocessor-assets:${project.ext.scanbotSdkVersion}")
implementation("com.squareup.picasso:picasso:${project.ext.picassoVersion}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${project.ext.coroutinesCoreVersion}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:${project.ext.coroutinesAndroidVersion}")
diff --git a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/ExampleApplication.kt
index d6f608f1..cc53c9fd 100755
--- a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -2,9 +2,9 @@ package io.scanbot.example
import android.app.Application
import io.scanbot.example.common.Const
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
+import io.scanbot.sdk.licensing.Feature
import io.scanbot.sdk.util.log.LoggerProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -37,11 +37,9 @@ class ExampleApplication : Application(), CoroutineScope {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
+ .licenseErrorHandler { status, feature, statusMessage ->
logger.d(Const.LOG_TAG, "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- logger.d(Const.LOG_TAG, "+++> Feature not available: ${feature.name}")
- }
+ logger.d(Const.LOG_TAG, "+++> Feature not available: ${feature.name}")
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
.initialize(this)
@@ -51,7 +49,7 @@ class ExampleApplication : Application(), CoroutineScope {
val licenseInfo = ScanbotSDK(this).licenseInfo
logger.d(Const.LOG_TAG, "License status: ${licenseInfo.status}")
logger.d(Const.LOG_TAG, "License isValid: ${licenseInfo.isValid}")
- logger.d(Const.LOG_TAG, "License expirationDate: ${licenseInfo.expirationDate}")
+ logger.d(Const.LOG_TAG, "License expirationDate: ${licenseInfo.expirationDateString}")
launch {
// Clear all previously created documents in storage
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 dcda679d..f0423758 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
@@ -12,18 +12,25 @@ import androidx.lifecycle.lifecycleScope
import com.squareup.picasso.Callback
import com.squareup.picasso.MemoryPolicy
import com.squareup.picasso.Picasso
+import io.scanbot.common.onFailure
import io.scanbot.example.common.Const
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.common.showToast
import io.scanbot.example.databinding.ActivityFiltersTunesBinding
import io.scanbot.example.fragment.ErrorFragment
import io.scanbot.example.fragment.FiltersBottomSheetMenuFragment
-import io.scanbot.sdk.imagefilters.ParametricFilter
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.docprocessing.Document
import io.scanbot.sdk.docprocessing.Page
+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:
+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 FilterActivity : AppCompatActivity(), FiltersListener {
companion object {
@@ -89,7 +96,12 @@ class FilterActivity : AppCompatActivity(), FiltersListener {
}
private suspend fun loadDocument(docId: String) {
- val doc = withContext(Dispatchers.IO) { scanbotSdk.documentApi.loadDocument(docId) }
+ val doc = withContext(Dispatchers.IO) {
+ scanbotSdk.documentApi.loadDocument(docId)
+ .onFailure {
+ Log.e(Const.LOG_TAG, "Document with ID $docId loading failed: ${it.message}")
+ }.getOrNull()
+ }
withContext(Dispatchers.Main) {
if (doc == null) {
showToast("Document with given ID was not found!")
diff --git a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FiltersListener.kt b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FiltersListener.kt
index 7b4f1d8f..b59c3f7b 100644
--- a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FiltersListener.kt
+++ b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/FiltersListener.kt
@@ -1,6 +1,6 @@
package io.scanbot.example
-import io.scanbot.sdk.imagefilters.ParametricFilter
+import io.scanbot.sdk.imageprocessing.ParametricFilter
interface FiltersListener {
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 3e13e2ce..8604397d 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
@@ -1,6 +1,5 @@
package io.scanbot.example
-import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
@@ -9,45 +8,61 @@ import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
+import io.scanbot.common.mapSuccess
+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.DocumentDetectionStatus
+import io.scanbot.sdk.image.ImageRef
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 binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private val scanbotSdk: ScanbotSDK by lazy { ScanbotSDK(this) }
- 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
- }
+ 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
+ }
- lifecycleScope.launch {
- val documentId = createAndScanDocumentPage(uri)
+ if (uri == null) {
+ showToast("Error obtaining selected image!")
+ Log.e(Const.LOG_TAG, "Error obtaining selected image!")
+ return@registerForActivityResult
+ }
- if (documentId != null) {
- filterActivityResultLauncher.launch(FilterActivity.newIntent(this@MainActivity, documentId))
- } else {
- Log.e(Const.LOG_TAG, "Error creating document with page!")
- showToast("Error creating document with page!")
+ lifecycleScope.launch {
+ val documentId = createAndScanDocumentPage(uri)
+
+ if (documentId != null) {
+ filterActivityResultLauncher.launch(
+ FilterActivity.newIntent(
+ this@MainActivity,
+ documentId
+ )
+ )
+ } else {
+ Log.e(Const.LOG_TAG, "Error creating document with page!")
+ showToast("Error creating document with page!")
+ }
}
}
- }
private val filterActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
@@ -61,7 +76,9 @@ class MainActivity : AppCompatActivity() {
return@registerForActivityResult
}
- val page = ScanbotSDK(this).documentApi.loadDocument(documentId)?.pages?.firstOrNull()
+ val page =
+ ScanbotSDK(this).documentApi.loadDocument(documentId)
+ .getOrNull()?.pages?.firstOrNull()
if (page == null) {
Log.e(Const.LOG_TAG, "Error loading document with page!")
showToast("Error loading document with page!")
@@ -87,15 +104,10 @@ class MainActivity : AppCompatActivity() {
}
private suspend fun createAndScanDocumentPage(imageUri: Uri): String? {
- val bitmap = withContext(Dispatchers.IO) {
+ val imageRef = withContext(Dispatchers.IO) {
val inputStream = contentResolver.openInputStream(imageUri)
- BitmapFactory.decodeStream(inputStream)
- }
-
- if (bitmap == null) {
- Log.e(Const.LOG_TAG, "Error loading image (bitmap is `null`)!")
- showToast("Error loading image!")
- return null
+ ?: throw Exception("Cannot open input stream from URI")
+ ImageRef.fromInputStream(inputStream)
}
val sdk = ScanbotSDK(this)
@@ -107,31 +119,38 @@ class MainActivity : AppCompatActivity() {
binding.progressBar.visibility = View.VISIBLE
val resultDocument = withContext(Dispatchers.Default) {
- val result = sdk.createDocumentScanner().scanFromBitmap(bitmap)
+ sdk.createDocumentScanner().mapSuccess { documentScanner ->
+
+ val result = documentScanner?.scan(imageRef)
+ ?.getOrReturn() // it is also possible to check specific error by che
+ val detectionResult = result?.detectionResult
+ Log.d(Const.LOG_TAG, "Doc found: ${result}")
+
+ val status =
+ detectionResult?.status ?: DocumentDetectionStatus.ERROR_NOTHING_DETECTED
+
+ /** We allow all `OK_*` [statuses][DocumentDetectionStatus] just for purpose of this example.
+ * Otherwise it is a good practice to differentiate between statuses and handle them accordingly.
+ */
+
+ val isScanOk = status?.name?.startsWith("OK", true) ?: false
+ if (isScanOk.not()) {
+ Log.e(
+ Const.LOG_TAG,
+ "Bad document photo - scanning status was ${status.name}!"
+ )
+ showToast("Bad document photo - status ${status.name}!")
+ throw Exception("Bad document photo - scanning status was ${status.name}!")
+ }
- if (result == null) {
- Log.e(Const.LOG_TAG, "Error finding document (result is `null`)!")
- showToast("Error finding document!")
- return@withContext null
- }
- Log.d(Const.LOG_TAG, "Doc found: ${result.status}")
-
- /** We allow all `OK_*` [statuses][DocumentDetectionStatus] just for purpose of this example.
- * Otherwise it is a good practice to differentiate between statuses and handle them accordingly.
- */
- val isScanOk = result.status.name.startsWith("OK", true)
- if (isScanOk.not()) {
- Log.e(Const.LOG_TAG, "Bad document photo - scanning status was ${result.status.name}!")
- showToast("Bad document photo - status ${result.status.name}!")
- return@withContext null
+ sdk.documentApi.createDocument().onSuccess { document ->
+ val page = document.addPage(imageRef).getOrReturn() //can be handled with .getOrNull() if needed
+ Log.d(Const.LOG_TAG, "Page added: ${page.uuid}")
+ page.apply(newPolygon = detectionResult?.pointsNormalized)
+ document
+ }.getOrReturn()
}
-
- val document = sdk.documentApi.createDocument()
- val page = document.addPage(bitmap)
- Log.d(Const.LOG_TAG, "Page added: ${page.uuid}")
- page.apply(newPolygon = result.pointsNormalized)
- document
- }
+ }.getOrNull()
binding.progressBar.visibility = View.GONE
Log.d(Const.LOG_TAG, "Document created: ${resultDocument?.uuid}")
diff --git a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/Utils.kt b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/Utils.kt
index 7b3d4c2c..2b9c15f2 100644
--- a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/Utils.kt
+++ b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/Utils.kt
@@ -1,6 +1,7 @@
package io.scanbot.example
-import io.scanbot.sdk.imagefilters.ParametricFilter
+import io.scanbot.sdk.imageprocessing.ParametricFilter
+
fun ParametricFilter?.getFilterName(): String {
return this?.javaClass?.simpleName ?: "None"
diff --git a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/fragment/FiltersBottomSheetMenuFragment.kt b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/fragment/FiltersBottomSheetMenuFragment.kt
index 60914e60..a537fff5 100644
--- a/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/fragment/FiltersBottomSheetMenuFragment.kt
+++ b/classic-components-example/adjustable-filters/src/main/java/io/scanbot/example/fragment/FiltersBottomSheetMenuFragment.kt
@@ -8,14 +8,14 @@ import android.widget.Button
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import io.scanbot.example.FiltersListener
import io.scanbot.example.R
-import io.scanbot.sdk.imagefilters.BrightnessFilter
-import io.scanbot.sdk.imagefilters.ColorDocumentFilter
-import io.scanbot.sdk.imagefilters.ContrastFilter
-import io.scanbot.sdk.imagefilters.CustomBinarizationFilter
-import io.scanbot.sdk.imagefilters.GrayscaleFilter
-import io.scanbot.sdk.imagefilters.ParametricFilter
-import io.scanbot.sdk.imagefilters.ScanbotBinarizationFilter
-import io.scanbot.sdk.imagefilters.WhiteBlackPointFilter
+import io.scanbot.sdk.imageprocessing.BrightnessFilter
+import io.scanbot.sdk.imageprocessing.ColorDocumentFilter
+import io.scanbot.sdk.imageprocessing.ContrastFilter
+import io.scanbot.sdk.imageprocessing.CustomBinarizationFilter
+import io.scanbot.sdk.imageprocessing.GrayscaleFilter
+import io.scanbot.sdk.imageprocessing.ParametricFilter
+import io.scanbot.sdk.imageprocessing.ScanbotBinarizationFilter
+import io.scanbot.sdk.imageprocessing.WhiteBlackPointFilter
/** Represents bottom menu sheet for page filters screen. */
class FiltersBottomSheetMenuFragment : BottomSheetDialogFragment() {
diff --git a/classic-components-example/adjustable-filters/src/main/res/layout/activity_filters_tunes.xml b/classic-components-example/adjustable-filters/src/main/res/layout/activity_filters_tunes.xml
index de2b6a16..3cd30322 100644
--- a/classic-components-example/adjustable-filters/src/main/res/layout/activity_filters_tunes.xml
+++ b/classic-components-example/adjustable-filters/src/main/res/layout/activity_filters_tunes.xml
@@ -18,7 +18,6 @@
@@ -30,7 +29,6 @@
diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
index 39a3c0ef..e2d05857 100644
--- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -1,7 +1,6 @@
package io.scanbot.example
import android.app.Application
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
import io.scanbot.sdk.util.log.LoggerProvider
@@ -24,11 +23,15 @@ class ExampleApplication : Application() {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
- LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
- }
+ .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)
@@ -38,6 +41,9 @@ class ExampleApplication : Application() {
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.expirationDate}")
+ LoggerProvider.logger.d(
+ "ExampleApplication",
+ "License expirationDate: ${licenseInfo.expirationDateString}"
+ )
}
}
diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeResultActivity.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeResultActivity.kt
index d6a849ed..3612e82d 100644
--- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeResultActivity.kt
+++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeResultActivity.kt
@@ -58,7 +58,7 @@ class BarcodeResultActivity : AppCompatActivity() {
BarcodeItemBinding.inflate(layoutInflater, binding.scannedItems, false)
.also {
item.sourceImage?.let { image ->
- it.image.setImageBitmap(image.toBitmap())
+ it.image.setImageBitmap(image.toBitmap()?.getOrNull())
}
it.barcodeFormat.text = item.format.name
it.docFormat.text = item.extractedDocument?.let {
diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScanAndCountViewActivity.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScanAndCountViewActivity.kt
index 3d450727..7f3afb5e 100644
--- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScanAndCountViewActivity.kt
+++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScanAndCountViewActivity.kt
@@ -19,6 +19,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
+import io.scanbot.common.onSuccess
import io.scanbot.example.R
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.repository.BarcodeTypeRepository
@@ -50,53 +51,55 @@ class BarcodeScanAndCountViewActivity : AppCompatActivity() {
nextButton = findViewById(R.id.nextButton)
snapResult = findViewById(R.id.snapped_message)
- val scanner = ScanbotSDK(this).createBarcodeScanner()
- scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
- setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
- } )
- scanButton.setOnClickListener {
- scanCountView.viewController.scanAndCount() // call this to run the scan and count
- }
- nextButton.setOnClickListener {
- scanCountView.viewController.continueScanning() // call this after the scan to reset the view state and continue scanning
+ ScanbotSDK(this).createBarcodeScanner().onSuccess { scanner ->
+
+ scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
+ setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
+ })
+ scanButton.setOnClickListener {
+ scanCountView.viewController.scanAndCount() // call this to run the scan and count
+ }
+ nextButton.setOnClickListener {
+ scanCountView.viewController.continueScanning() // call this after the scan to reset the view state and continue scanning
+ scanButton.isEnabled = true
+ nextButton.isEnabled = false
+ }
+
scanButton.isEnabled = true
nextButton.isEnabled = false
- }
- scanButton.isEnabled = true
- nextButton.isEnabled = false
-
- scanCountView.apply {
- initCamera()
- initScanningBehavior(
- scanner,
- callback = object : IBarcodeScanCountViewCallback {
- override fun onCameraOpen() {
- scanCountView.viewController.useFlash(flashEnabled)
- }
+ scanCountView.apply {
+ initCamera()
+ initScanningBehavior(
+ scanner,
+ callback = object : IBarcodeScanCountViewCallback {
+ override fun onCameraOpen() {
+ scanCountView.viewController.useFlash(flashEnabled)
+ }
- override fun onLicenseError() {
- scanCountView.post {
- Toast.makeText(
- this@BarcodeScanAndCountViewActivity,
- "1-minute trial license has expired!",
- Toast.LENGTH_LONG
- ).show()
+ override fun onLicenseError() {
+ scanCountView.post {
+ Toast.makeText(
+ this@BarcodeScanAndCountViewActivity,
+ "1-minute trial license has expired!",
+ Toast.LENGTH_LONG
+ ).show()
+ }
}
- }
- override fun onScanAndCountStarted() {
- scanButton.isEnabled = false
- }
+ override fun onScanAndCountStarted() {
+ scanButton.isEnabled = false
+ }
- override fun onScanAndCountFinished(barcodes: List) {
- scanButton.isEnabled = false
- nextButton.isEnabled = true
- // barcodes is the result of the last scanning session, but to ge all counted barcodes, use the following code
- handleSnap(scanCountView.countedBarcodes)
+ override fun onScanAndCountFinished(barcodes: List) {
+ scanButton.isEnabled = false
+ nextButton.isEnabled = true
+ // barcodes is the result of the last scanning session, but to ge all counted barcodes, use the following code
+ handleSnap(scanCountView.countedBarcodes)
+ }
}
- }
- )
+ )
+ }
}
// Setting the Selection Overlay (AR)
@@ -106,7 +109,7 @@ class BarcodeScanAndCountViewActivity : AppCompatActivity() {
defaultStyle: BarcodePolygonsStaticView.BarcodePolygonStyle,
barcodeItem: BarcodeItem
): BarcodePolygonsStaticView.BarcodePolygonStyle {
- return defaultStyle
+ return defaultStyle
}
})
scanCountView.counterOverlayController.setBarcodeItemViewFactory(object :
diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerActivity.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerActivity.kt
index 422f0eae..c0c2dc03 100644
--- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerActivity.kt
+++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/BarcodeScannerActivity.kt
@@ -13,19 +13,23 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
+import io.scanbot.common.Result
+import io.scanbot.common.onFailure
+import io.scanbot.common.onSuccess
+
import io.scanbot.example.R
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.model.BarcodeResultBundle
import io.scanbot.example.repository.BarcodeResultRepository
import io.scanbot.example.repository.BarcodeTypeRepository
import io.scanbot.sdk.ScanbotSDK
-import io.scanbot.sdk.SdkLicenseError
import io.scanbot.sdk.barcode.BarcodeAutoSnappingController
import io.scanbot.sdk.barcode.BarcodeScannerFrameHandler
import io.scanbot.sdk.barcode.BarcodeScannerResult
import io.scanbot.sdk.barcode.setBarcodeFormats
import io.scanbot.sdk.camera.*
-import io.scanbot.sdk.common.AspectRatio
+import io.scanbot.sdk.geometry.AspectRatio
+import io.scanbot.sdk.image.ImageRef
import io.scanbot.sdk.ui.camera.FinderOverlayView
import io.scanbot.sdk.ui.camera.ScanbotCameraXView
@@ -56,27 +60,34 @@ class BarcodeScannerActivity : AppCompatActivity(), BarcodeScannerFrameHandler.R
}
finderOverlay.setRequiredAspectRatios(listOf(AspectRatio(1.0, 1.0)))
- val scanner = ScanbotSDK(this).createBarcodeScanner()
- scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
- setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
- } )
- scannerFrameHandler =
- BarcodeScannerFrameHandler.attach(cameraView, scanner)
+ ScanbotSDK(this).createBarcodeScanner().onSuccess { scanner ->
+ scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
+ setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
+ })
+ scannerFrameHandler =
+ BarcodeScannerFrameHandler.attach(cameraView, scanner)
- scannerFrameHandler?.let { frameHandler ->
- frameHandler.setScanningInterval(1000)
- frameHandler.addResultHandler(this)
+ scannerFrameHandler?.let { frameHandler ->
+ frameHandler.setScanningInterval(1000)
+ frameHandler.addResultHandler(this@BarcodeScannerActivity)
- val barcodeAutoSnappingController =
- BarcodeAutoSnappingController.attach(cameraView, frameHandler)
- barcodeAutoSnappingController.setSensitivity(1f)
+ val barcodeAutoSnappingController =
+ BarcodeAutoSnappingController.attach(cameraView, frameHandler)
+ barcodeAutoSnappingController.setSensitivity(1f)
- }
- cameraView.addPictureCallback(object : PictureCallback() {
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
- processPictureTaken(image, captureInfo.imageOrientation)
}
- })
+ cameraView.addPictureCallback(object : PictureCallback() {
+
+ override fun onPictureTaken(
+ image: ImageRef,
+ captureInfo: CaptureInfo
+ ) {
+ processPictureTaken(image, captureInfo.imageOrientation)
+ }
+ })
+
+ }
+
}
override fun onResume() {
@@ -95,27 +106,25 @@ class BarcodeScannerActivity : AppCompatActivity(), BarcodeScannerFrameHandler.R
}
}
- private fun handleSuccess(result: FrameHandlerResult.Success) {
- result.value?.let {
- BarcodeResultRepository.barcodeResultBundle = BarcodeResultBundle(it)
- val intent = Intent(this, BarcodeResultActivity::class.java)
- startActivity(intent)
- finish()
- }
+ private fun handleSuccess(result: BarcodeScannerResult) {
+ BarcodeResultRepository.barcodeResultBundle = BarcodeResultBundle(result)
+ val intent = Intent(this, BarcodeResultActivity::class.java)
+ startActivity(intent)
+ finish()
}
- fun processPictureTaken(image: ByteArray, imageOrientation: Int) {
- val bitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
-
- val matrix = Matrix()
- matrix.setRotate(imageOrientation.toFloat(), bitmap.width / 2f, bitmap.height / 2f)
- val resultBitmap =
- Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, false)
+ fun processPictureTaken(image: ImageRef, imageOrientation: Int) {
+ image.toBitmap().onSuccess { bitmap ->
+ val matrix = Matrix()
+ matrix.setRotate(imageOrientation.toFloat(), bitmap.width / 2f, bitmap.height / 2f)
+ val resultBitmap =
+ Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, false)
- resultView.post {
- resultView.setImageBitmap(resultBitmap)
- cameraView.continuousFocus()
- cameraView.startPreview()
+ resultView.post {
+ resultView.setImageBitmap(resultBitmap)
+ cameraView.continuousFocus()
+ cameraView.startPreview()
+ }
}
}
@@ -124,13 +133,13 @@ class BarcodeScannerActivity : AppCompatActivity(), BarcodeScannerFrameHandler.R
private const val REQUEST_PERMISSION_CODE = 200
}
- override fun handle(result: FrameHandlerResult): Boolean {
- if (result is FrameHandlerResult.Success) {
- handleSuccess(result)
- } else {
+ override fun handle(result: Result, frame: FrameHandler.Frame): Boolean {
+ result.onSuccess {
+ handleSuccess(it)
+ }.onFailure {
cameraView.post {
Toast.makeText(
- this,
+ this@BarcodeScannerActivity,
"1-minute trial license has expired!",
Toast.LENGTH_LONG
).show()
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 3a094a47..7a38a12e 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
@@ -15,6 +15,10 @@ 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
+
import io.scanbot.example.R
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.model.BarcodeResultBundle
@@ -27,7 +31,7 @@ import io.scanbot.sdk.barcode.setBarcodeFormats
import io.scanbot.sdk.barcode.ui.BarcodeScannerView
import io.scanbot.sdk.barcode.ui.IBarcodeScannerViewCallback
import io.scanbot.sdk.camera.CaptureInfo
-import io.scanbot.sdk.camera.FrameHandlerResult
+import io.scanbot.sdk.image.ImageRef
class BarcodeScannerViewActivity : AppCompatActivity() {
private lateinit var barcodeScannerView: BarcodeScannerView
@@ -45,42 +49,54 @@ class BarcodeScannerViewActivity : AppCompatActivity() {
barcodeScannerView = findViewById(R.id.barcode_scanner_view)
resultView = findViewById(R.id.result)
- val scanner = ScanbotSDK(this).createBarcodeScanner()
- scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
- setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
- } )
-
- barcodeScannerView.apply {
- initCamera()
- initScanningBehavior(scanner,
- { result ->
- if (result is FrameHandlerResult.Success) {
- handleSuccess(result)
- } else {
- barcodeScannerView.post {
- Toast.makeText(
- this@BarcodeScannerViewActivity,
- "1-minute trial license has expired!",
- Toast.LENGTH_LONG
- ).show()
+ ScanbotSDK(this).createBarcodeScanner().onSuccess { scanner ->
+ scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
+ setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
+ })
+ barcodeScannerView.apply {
+ initCamera()
+ initScanningBehavior(
+ scanner,
+ { result, frame ->
+ result.onSuccess { data ->
+ handleSuccess(data)
+ }.onFailure {
+ if (it is Result.InvalidLicenseError) {
+ barcodeScannerView.post {
+ Toast.makeText(
+ this@BarcodeScannerViewActivity,
+ "1-minute trial license has expired!",
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ } else {
+ Toast.makeText(
+ this@BarcodeScannerViewActivity,
+ "Error occurred during scanner init",
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
+ false
+ },
+ object : IBarcodeScannerViewCallback {
+ override fun onCameraOpen() {
+ barcodeScannerView.viewController.useFlash(flashEnabled)
}
- }
- false
- },
- object : IBarcodeScannerViewCallback {
- override fun onCameraOpen() {
- barcodeScannerView.viewController.useFlash(flashEnabled)
- }
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
- // we don't need full size pictures in this example
- }
+ override fun onPictureTaken(
+ image: ImageRef,
+ captureInfo: CaptureInfo
+ ) {
+ TODO("Not yet implemented")
+ }
- override fun onSelectionOverlayBarcodeClicked(barcodeItem: BarcodeItem) {
+ override fun onSelectionOverlayBarcodeClicked(barcodeItem: BarcodeItem) {
+ }
}
- }
- )
+ )
+ }
}
barcodeScannerView.viewController.apply {
@@ -92,9 +108,17 @@ class BarcodeScannerViewActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
barcodeScannerView.viewController.onResume()
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.CAMERA
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
// Use onActivityResult to handle permission rejection
- ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_PERMISSION_CODE)
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.CAMERA),
+ REQUEST_PERMISSION_CODE
+ )
}
}
@@ -103,9 +127,9 @@ class BarcodeScannerViewActivity : AppCompatActivity() {
barcodeScannerView.viewController.onPause()
}
- private fun handleSuccess(result: FrameHandlerResult.Success) {
- result.value?.let {
- BarcodeResultRepository.barcodeResultBundle = BarcodeResultBundle(it)
+ private fun handleSuccess(result: BarcodeScannerResult) {
+ result.takeIf { it.barcodes.isNotEmpty() }?.let {
+ BarcodeResultRepository.barcodeResultBundle = BarcodeResultBundle(result)
val intent = Intent(this, BarcodeResultActivity::class.java)
startActivity(intent)
finish()
diff --git a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/DetailedItemDataActivity.kt b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/DetailedItemDataActivity.kt
index ece9fa38..86c96f06 100644
--- a/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/DetailedItemDataActivity.kt
+++ b/classic-components-example/barcode-scanner/src/main/java/io/scanbot/example/ui/DetailedItemDataActivity.kt
@@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
+
import io.scanbot.example.R
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.databinding.ActivityDetailedItemDataBinding
@@ -38,7 +39,7 @@ class DetailedItemDataActivity : AppCompatActivity() {
BarcodeResultRepository.selectedBarcodeItem?.let { item ->
binding.container?.also {
- binding.image.setImageBitmap(item.sourceImage?.toBitmap())
+ binding.image.setImageBitmap(item.sourceImage?.toBitmap()?.getOrNull())
binding.barcodeFormat.text = item.format.name
binding.docFormat.text = item.extractedDocument?.let {
it::class.java.simpleName
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 2f192853..6bceff29 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
@@ -1,20 +1,16 @@
package io.scanbot.example.ui
import android.content.Intent
-import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
-import android.view.View
-import android.view.ViewGroup
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
-import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
+
+
import io.scanbot.example.R
import io.scanbot.example.common.Const
import io.scanbot.example.common.applyEdgeToEdge
@@ -23,13 +19,21 @@ import io.scanbot.example.databinding.ActivityMainBinding
import io.scanbot.example.model.BarcodeResultBundle
import io.scanbot.example.repository.BarcodeResultRepository
import io.scanbot.example.repository.BarcodeTypeRepository
-import io.scanbot.sap.Status
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.barcode.setBarcodeFormats
+import io.scanbot.sdk.image.ImageRef
+import io.scanbot.sdk.licensing.LicenseStatus
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 binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
@@ -89,7 +93,7 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
- binding.warningView.isVisible = ScanbotSDK(this).licenseInfo.status == Status.StatusTrial
+ binding.warningView.isVisible = ScanbotSDK(this).licenseInfo.status == LicenseStatus.TRIAL
}
private suspend fun scanBarcodeAndShowResult(uri: Uri) {
@@ -98,14 +102,14 @@ class MainActivity : AppCompatActivity() {
}
withContext(Dispatchers.Default) {
- val inputStream = contentResolver.openInputStream(uri)
- val bitmap = BitmapFactory.decodeStream(inputStream)
+ val inputStream = contentResolver.openInputStream(uri) ?: throw IllegalStateException("Cannot open input stream from URI: $uri")
+ val imageRef = ImageRef.fromInputStream(inputStream)
- val scanner = scanbotSdk.createBarcodeScanner()
+ val scanner = scanbotSdk.createBarcodeScanner().getOrThrow()
scanner.setConfiguration(scanner.copyCurrentConfiguration().copy().apply {
setBarcodeFormats(barcodeFormats = BarcodeTypeRepository.selectedTypes.toList())
} )
- val result = scanner.scanFromBitmap(bitmap, 0)
+ val result = scanner.run(imageRef).getOrNull()
BarcodeResultRepository.barcodeResultBundle = result?.let { BarcodeResultBundle(it, null, null) }
}
diff --git a/classic-components-example/build.gradle b/classic-components-example/build.gradle
index 200232c8..624363e4 100644
--- a/classic-components-example/build.gradle
+++ b/classic-components-example/build.gradle
@@ -1,7 +1,7 @@
plugins {
id("com.android.application") version "8.3.2" apply false
id("com.android.library") version "8.3.2" apply false
- id("org.jetbrains.kotlin.android") version "1.9.25" apply false
+ id("org.jetbrains.kotlin.android") version "2.2.20" apply false
}
allprojects {
@@ -15,12 +15,12 @@ allprojects {
jvmToolchainVersion = 17
- scanbotSdkVersion = "7.1.1"
+ scanbotSdkVersion = "8.0.0.58-STAGING-SNAPSHOT"
androidCoreKtxVersion = "1.6.0"
constraintLayoutVersion = "2.0.4"
- coroutinesAndroidVersion = "1.7.3"
- coroutinesCoreVersion = "1.7.3"
+ coroutinesAndroidVersion = "1.10.1"
+ coroutinesCoreVersion = "1.10.1"
androidxAppcompatVersion = "1.7.0"
materialVersion = "1.4.0"
diff --git a/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/CameraDialogFragment.kt b/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/CameraDialogFragment.kt
index 230cf9ec..ef383507 100755
--- a/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/CameraDialogFragment.kt
+++ b/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/CameraDialogFragment.kt
@@ -9,12 +9,17 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.fragment.app.DialogFragment
+import io.scanbot.common.onSuccess
+
+
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.camera.CaptureInfo
import io.scanbot.sdk.camera.PictureCallback
-import io.scanbot.sdk.document.DocumentScanner
+import io.scanbot.sdk.common.catchWithResult
import io.scanbot.sdk.document.DocumentAutoSnappingController
import io.scanbot.sdk.document.DocumentScannerFrameHandler
+import io.scanbot.sdk.documentscanner.DocumentScanner
+import io.scanbot.sdk.image.ImageRef
import io.scanbot.sdk.process.ImageProcessor
import io.scanbot.sdk.ui.PolygonView
import io.scanbot.sdk.ui.camera.ScanbotCameraXView
@@ -24,41 +29,49 @@ class CameraDialogFragment : DialogFragment() {
private lateinit var cameraView: ScanbotCameraXView
private lateinit var resultView: ImageView
- private lateinit var scanner: DocumentScanner
private var flashEnabled = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val scanbotSDK = ScanbotSDK(requireContext())
- scanner = scanbotSDK.createDocumentScanner()
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val baseView = requireActivity().layoutInflater.inflate(R.layout.scanbot_camera_view, container, false)
- cameraView = baseView.findViewById(R.id.camera) as ScanbotCameraXView
- cameraView.setCameraOpenCallback {
- cameraView.postDelayed({
- cameraView.continuousFocus()
- cameraView.useFlash(flashEnabled)
- }, 700)
- }
- resultView = baseView.findViewById(R.id.result) as ImageView
- val frameHandler = DocumentScannerFrameHandler.attach(cameraView, scanner)
- val polygonView: PolygonView = baseView.findViewById(R.id.polygonView)
- frameHandler.addResultHandler(polygonView.documentScannerResultHandler)
- DocumentAutoSnappingController.attach(cameraView, frameHandler)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val scanbotSDK = ScanbotSDK(requireContext())
+ val baseView =
+ requireActivity().layoutInflater.inflate(R.layout.scanbot_camera_view, container, false)
- cameraView.addPictureCallback(object : PictureCallback() {
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
- processPictureTaken(image, captureInfo.imageOrientation)
+ scanbotSDK.createDocumentScanner().onSuccess { scanner ->
+
+ cameraView = baseView.findViewById(R.id.camera) as ScanbotCameraXView
+ cameraView.setCameraOpenCallback {
+ cameraView.postDelayed({
+ cameraView.continuousFocus()
+ cameraView.useFlash(flashEnabled)
+ }, 700)
}
- })
+ resultView = baseView.findViewById(R.id.result) as ImageView
+ val frameHandler = DocumentScannerFrameHandler.attach(cameraView, scanner)
+ val polygonView: PolygonView = baseView.findViewById(R.id.polygonView)
+ frameHandler.addResultHandler(polygonView.documentScannerResultHandler)
+ DocumentAutoSnappingController.attach(cameraView, frameHandler)
+
+ cameraView.addPictureCallback(object : PictureCallback() {
+ override fun onPictureTaken(image: ImageRef, captureInfo: CaptureInfo) {
+ processPictureTaken(image, scanner)
+ }
+ })
- baseView.findViewById(R.id.snap).setOnClickListener { cameraView.takePicture(false) }
- baseView.findViewById(R.id.flash).setOnClickListener {
- flashEnabled = !flashEnabled
- cameraView.useFlash(flashEnabled)
+ baseView.findViewById(R.id.snap)
+ .setOnClickListener { cameraView.takePicture(false) }
+ baseView.findViewById(R.id.flash).setOnClickListener {
+ flashEnabled = !flashEnabled
+ cameraView.useFlash(flashEnabled)
+ }
}
return baseView
}
@@ -72,34 +85,17 @@ class CameraDialogFragment : DialogFragment() {
}
}
- private fun processPictureTaken(image: ByteArray, imageOrientation: Int) {
- // Here we get the full image from the camera.
- // Implement a suitable async(!) scanning and image handling here.
- // This is just a demo showing scanning image as downscaled preview image.
-
- // Decode Bitmap from bytes of original image:
- val options = BitmapFactory.Options()
- options.inSampleSize = 8 // use 1 for original size (if you want no downscale)!
- // in this demo we downscale the image to 1/8 for the preview.
- var originalBitmap = BitmapFactory.decodeByteArray(image, 0, image.size, options)
-
- // rotate original image if required:
- if (imageOrientation > 0) {
- val matrix = Matrix()
- matrix.setRotate(imageOrientation.toFloat(), originalBitmap.width / 2f, originalBitmap.height / 2f)
- originalBitmap =
- Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.width, originalBitmap.height, matrix, false)
- }
-
+ private fun processPictureTaken(image: ImageRef, scanner: DocumentScanner) = catchWithResult {
// Run document scanning on original image:
- val result = scanner.scanFromBitmap(originalBitmap)
- result?.pointsNormalized?.let { polygonF ->
- val documentImage = ImageProcessor(originalBitmap).crop(polygonF).processedBitmap()
- if (documentImage != null) resultView.post {
- resultView.setImageBitmap(documentImage)
- cameraView.continuousFocus()
- cameraView.startPreview()
- }
+ val result = scanner.run(image).getOrReturn()
+ val documentImage =
+ result.pointsNormalized.takeIf { it.size == 4 }
+ ?.let { ImageProcessor(image).crop(it).resize(200).processedBitmap() }
+ ?.getOrReturn()
+ resultView.post {
+ resultView.setImageBitmap(documentImage)
+ cameraView.continuousFocus()
+ cameraView.startPreview()
}
}
diff --git a/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/ExampleApplication.kt
index 1f90ff74..eafab0a2 100755
--- a/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/camera-fragment/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -2,7 +2,6 @@ package io.scanbot.example
import android.app.Application
import io.scanbot.example.common.getAppStorageDir
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
import io.scanbot.sdk.util.log.LoggerProvider
@@ -35,11 +34,9 @@ class ExampleApplication : Application(), CoroutineScope {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
+ .licenseErrorHandler { status, feature, statusMessage ->
LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
- }
+ LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
.initialize(this)
@@ -49,7 +46,7 @@ class ExampleApplication : Application(), CoroutineScope {
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.expirationDate}")
+ LoggerProvider.logger.d("ExampleApplication", "License expirationDate: ${licenseInfo.expirationDateString}")
launch {
getAppStorageDir(this@ExampleApplication).deleteRecursively()
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 2d2f7354..7d6927a6 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
@@ -1,7 +1,6 @@
package io.scanbot.example
import android.Manifest
-import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
@@ -12,19 +11,30 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
+
+
import io.scanbot.example.common.Const
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.common.showToast
import io.scanbot.sdk.ScanbotSDK
-import io.scanbot.sdk.document.DocumentScanner
+import io.scanbot.sdk.common.catchWithResult
+import io.scanbot.sdk.documentscanner.DocumentScanner
+import io.scanbot.sdk.image.ImageRef
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 scanner: DocumentScanner by lazy { scanbotSdk.createDocumentScanner() }
+ private val scanner: DocumentScanner? by lazy { scanbotSdk.createDocumentScanner().getOrNull() }
private val requestCameraLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
@@ -50,7 +60,14 @@ class MainActivity : AppCompatActivity() {
}
if (scanbotSdk.licenseInfo.isValid) {
- lifecycleScope.launch { processImageForAutoDocumentScanning(uri) }
+ lifecycleScope.launch {
+ scanner?.let {
+ processImageForAutoDocumentScanning(
+ uri,
+ it
+ )
+ }
+ }
} else {
this@MainActivity.showToast("1-minute trial license has expired!")
}
@@ -59,6 +76,7 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+
supportActionBar?.hide()
applyEdgeToEdge(findViewById(R.id.root_view))
@@ -85,7 +103,10 @@ class MainActivity : AppCompatActivity() {
}
/** Imports a selected image as original image and performs auto document scanning on it. */
- private suspend fun processImageForAutoDocumentScanning(imageUri: Uri) {
+ private suspend fun processImageForAutoDocumentScanning(
+ imageUri: Uri,
+ scanner: DocumentScanner
+ ) {
val progressBar = findViewById(R.id.progress_bar)
val importResultImage = findViewById(R.id.import_result)
withContext(Dispatchers.Main) {
@@ -93,33 +114,38 @@ class MainActivity : AppCompatActivity() {
this@MainActivity.showToast("Importing image...")
}
- val page = withContext(Dispatchers.Default) {
- // load the selected image:
- val inputStream = contentResolver.openInputStream(imageUri)
- val bitmap = BitmapFactory.decodeStream(inputStream)
-
- // create a new Document object with given image as original image:
- val newDocument = scanbotSdk.documentApi.createDocument()
- val page = newDocument.addPage(bitmap)
-
- // run auto document scanning on it:
- val result = scanner.scanFromBitmap(bitmap)
-
- /** We allow all `OK_*` [statuses][DocumentDetectionStatus] just for purpose of this example.
- * Otherwise it is a good practice to differentiate between statuses and handle them accordingly.
- */
- val statusOk = (result?.status?.name?.startsWith("OK_")) ?: false
- if (result != null && statusOk && result.pointsNormalized.isNotEmpty()) {
- // apply the detected polygon to the new page:
- page.apply(newPolygon = result.pointsNormalized)
- }
- page
+ 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)
+
+ // create a new Document object with given image as original image:
+ val newDocument = scanbotSdk.documentApi.createDocument()
+ .getOrReturn() // can be handled with .getOrNull() if needed
+ val page = newDocument.addPage(image)
+ .getOrReturn() // can be handled with .getOrNull() if needed
+
+ // run auto document scanning on it:
+ val result = scanner.run(image).getOrReturn()
+
+ /** We allow all `OK_*` [statuses][io.scanbot.sdk.documentscanner.DocumentDetectionStatus] just for purpose of this example.
+ * Otherwise it is a good practice to differentiate between statuses and handle them accordingly.
+ */
+ val statusOk = (result.status.name.startsWith("OK_"))
+ if (statusOk && result.pointsNormalized.isNotEmpty()) {
+ // apply the detected polygon to the new page:
+ page.apply(newPolygon = result.pointsNormalized)
+ }
+ page.documentImage
+ }.getOrNull()
}
withContext(Dispatchers.Main) {
progressBar.visibility = View.GONE
// show Page's document image:
- importResultImage.setImageBitmap(page.documentImage)
+ importResultImage.setImageBitmap(documentImage)
importResultImage.visibility = View.VISIBLE
}
}
diff --git a/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/ExampleApplication.kt
index 39a3c0ef..2dd3a1fa 100755
--- a/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/camera-view-aspect-ratio-finder/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -1,7 +1,6 @@
package io.scanbot.example
import android.app.Application
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
import io.scanbot.sdk.util.log.LoggerProvider
@@ -24,11 +23,9 @@ class ExampleApplication : Application() {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
+ .licenseErrorHandler { status, feature, statusMessage ->
LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
- }
+ LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
.initialize(this)
@@ -38,6 +35,6 @@ class ExampleApplication : Application() {
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.expirationDate}")
+ LoggerProvider.logger.d("ExampleApplication", "License expirationDate: ${licenseInfo.expirationDateString}")
}
}
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 772e6939..c783f3fe 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
@@ -13,20 +13,32 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
+import io.scanbot.common.Result
+import io.scanbot.common.mapSuccess
+import io.scanbot.common.onSuccess
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.sdk.ScanbotSDK
-import io.scanbot.sdk.SdkLicenseError
import io.scanbot.sdk.camera.*
-import io.scanbot.sdk.common.AspectRatio
-import io.scanbot.sdk.document.DocumentDetectionStatus
-import io.scanbot.sdk.document.DocumentScanner
-import io.scanbot.sdk.document.DocumentScannerParameters
import io.scanbot.sdk.document.DocumentAutoSnappingController
import io.scanbot.sdk.document.DocumentScannerFrameHandler
+import io.scanbot.sdk.documentscanner.DocumentDetectionStatus
+import io.scanbot.sdk.documentscanner.DocumentScanner
+import io.scanbot.sdk.documentscanner.DocumentScannerParameters
+import io.scanbot.sdk.geometry.AspectRatio
+import io.scanbot.sdk.image.ImageRef
+import io.scanbot.sdk.imageprocessing.ScanbotSdkImageProcessor
import io.scanbot.sdk.process.ImageProcessor
import io.scanbot.sdk.ui.camera.AdaptiveFinderOverlayView
import io.scanbot.sdk.ui.camera.ScanbotCameraXView
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:
+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(), DocumentScannerFrameHandler.ResultHandler {
private lateinit var cameraView: ScanbotCameraXView
@@ -46,7 +58,7 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
super.onCreate(savedInstanceState)
scanbotSDK = ScanbotSDK(this)
- scanner = scanbotSDK.createDocumentScanner()
+ scanner = scanbotSDK.createDocumentScanner().getOrThrow()
askPermission()
setContentView(R.layout.activity_main)
@@ -74,9 +86,11 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
val finderOverlayView = findViewById(R.id.finder_overlay) as AdaptiveFinderOverlayView
finderOverlayView.setRequiredAspectRatios(requiredPageAspectRatios)
- scanner.setParameters(scanner.copyCurrentConfiguration().parameters.apply {
- this.aspectRatios = requiredPageAspectRatios
- this.ignoreOrientationMismatch = true
+ scanner.setConfiguration(scanner.copyCurrentConfiguration().apply {
+ parameters.apply {
+ this.aspectRatios = requiredPageAspectRatios
+ this.ignoreOrientationMismatch = true
+ }
})
frameHandler.addResultHandler(finderOverlayView.documentScannerFrameHandler)
frameHandler.addResultHandler(this)
@@ -86,7 +100,7 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
}
cameraView.addPictureCallback(object : PictureCallback() {
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
+ override fun onPictureTaken(image: ImageRef, captureInfo: CaptureInfo) {
processPictureTaken(image, captureInfo.imageOrientation)
}
})
@@ -113,14 +127,18 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
}
}
- override fun handle(result: FrameHandlerResult): Boolean {
+ override fun handle(
+ result: Result,
+ frame: FrameHandler.Frame
+ ): Boolean {
// Here you are continuously notified about document scanning results.
// For example, you can show a user guidance text depending on the current scanning status.
- userGuidanceHint.post {
- if (result is FrameHandlerResult.Success) {
- showUserGuidance(result.value.detectionStatus)
+ result.onSuccess { value ->
+ userGuidanceHint.post {
+ showUserGuidance(value.detectionStatus)
}
}
+
return false // typically you need to return false
}
@@ -173,47 +191,29 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
lastUserGuidanceHintTs = System.currentTimeMillis()
}
- private fun processPictureTaken(image: ByteArray, imageOrientation: Int) {
- // Here we get the full (original) image from the camera.
-
- // Decode Bitmap from bytes of original image:
- val options = BitmapFactory.Options()
-
- // Please note: In this simple demo we downscale the original image to 1/8 for the preview!
- options.inSampleSize = 8
-
- // Typically you will need the full resolution of the original image! So please change the "inSampleSize" value to 1!
- //options.inSampleSize = 1
- var originalBitmap = BitmapFactory.decodeByteArray(image, 0, image.size, options)
-
- // Rotate the original image based on the imageOrientation value.
- // Required for some Android devices like Samsung!
- if (imageOrientation > 0) {
- val matrix = Matrix()
- matrix.setRotate(
- imageOrientation.toFloat(),
- originalBitmap.width / 2f,
- originalBitmap.height / 2f
- )
- originalBitmap = Bitmap.createBitmap(
- originalBitmap,
- 0,
- 0,
- originalBitmap.width,
- originalBitmap.height,
- matrix,
- false
- )
- }
-
- scanner.setParameters(DocumentScannerParameters(aspectRatios = requiredPageAspectRatios))
- val polygon = scanner.scanFromBitmap(originalBitmap)!!.pointsNormalized
+ private fun processPictureTaken(image: ImageRef, imageOrientation: Int) {
- val documentImage = ImageProcessor(originalBitmap).crop(polygon).processedBitmap()
- resultView.post {
- resultView.setImageBitmap(documentImage)
- cameraView.continuousFocus()
- cameraView.startPreview()
+ scanner.setConfiguration(scanner.copyCurrentConfiguration().apply {
+ parameters.apply {
+ this.aspectRatios = requiredPageAspectRatios
+ this.ignoreOrientationMismatch = true
+ }
+ })
+ val image = scanner.run(image).mapSuccess { result ->
+ val polygon = result.pointsNormalized
+ polygon.takeIf { it.isNotEmpty() && it.size == 4 } ?: PolygonHelper.getFullPolygon()
+ }.mapSuccess { polygonCrop ->
+ var documentImage = ScanbotSdkImageProcessor.create()
+ .crop(image, polygonCrop)
+ .getOrReturn()
+ ScanbotSdkImageProcessor.create().resize(documentImage, 200).getOrReturn()
+ }.onSuccess { documentImage ->
+ resultView.post {
+ resultView.setImageBitmap(documentImage.toBitmap().getOrNull())
+ documentImage.close()
+ cameraView.continuousFocus()
+ cameraView.startPreview()
+ }
}
}
}
diff --git a/classic-components-example/camera-view/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/camera-view/src/main/java/io/scanbot/example/ExampleApplication.kt
index 39a3c0ef..2dd3a1fa 100755
--- a/classic-components-example/camera-view/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/camera-view/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -1,7 +1,6 @@
package io.scanbot.example
import android.app.Application
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
import io.scanbot.sdk.util.log.LoggerProvider
@@ -24,11 +23,9 @@ class ExampleApplication : Application() {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
+ .licenseErrorHandler { status, feature, statusMessage ->
LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
- }
+ LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
.initialize(this)
@@ -38,6 +35,6 @@ class ExampleApplication : Application() {
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.expirationDate}")
+ LoggerProvider.logger.d("ExampleApplication", "License expirationDate: ${licenseInfo.expirationDateString}")
}
}
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 7f390704..8494ad07 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
@@ -19,20 +19,32 @@ 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.mapSuccess
+import io.scanbot.common.onSuccess
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.sdk.ScanbotSDK
-import io.scanbot.sdk.SdkLicenseError
import io.scanbot.sdk.camera.CaptureInfo
-import io.scanbot.sdk.camera.FrameHandlerResult
+import io.scanbot.sdk.camera.FrameHandler
import io.scanbot.sdk.camera.PictureCallback
-import io.scanbot.sdk.document.DocumentDetectionStatus
-import io.scanbot.sdk.document.DocumentScanner
import io.scanbot.sdk.document.DocumentAutoSnappingController
import io.scanbot.sdk.document.DocumentScannerFrameHandler
+import io.scanbot.sdk.documentscanner.DocumentDetectionStatus
+import io.scanbot.sdk.documentscanner.DocumentScanner
+import io.scanbot.sdk.image.ImageRef
+import io.scanbot.sdk.imageprocessing.ScanbotSdkImageProcessor
import io.scanbot.sdk.process.ImageProcessor
import io.scanbot.sdk.ui.PolygonView
import io.scanbot.sdk.ui.camera.ScanbotCameraXView
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:
+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(), DocumentScannerFrameHandler.ResultHandler {
private lateinit var cameraView: ScanbotCameraXView
@@ -45,8 +57,6 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
private lateinit var documentScannerFrameHandler: DocumentScannerFrameHandler
private lateinit var autoSnappingController: DocumentAutoSnappingController
- private lateinit var scanbotSDK: ScanbotSDK
- private lateinit var documentScanner: DocumentScanner
private var lastUserGuidanceHintTs = 0L
private var flashEnabled = false
@@ -61,18 +71,37 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
applyEdgeToEdge(this.findViewById(R.id.root_view))
- scanbotSDK = ScanbotSDK(this)
- documentScanner = scanbotSDK.createDocumentScanner()
-
- documentScanner .apply {
- // Please note: https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/ui-components/
- setParameters(copyCurrentConfiguration().parameters.apply {
- this.ignoreOrientationMismatch = ignoreOrientationMistmatch
- this.acceptedSizeScore = 75
- this.acceptedAngleScore = 60
+ val scanbotSDK = ScanbotSDK(this)
+ scanbotSDK.createDocumentScanner().onSuccess { documentScanner ->
+ documentScanner.apply {
+ // Please note: https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/ui-components/
+ setConfiguration(copyCurrentConfiguration().apply {
+ parameters.apply {
+ this.ignoreOrientationMismatch = ignoreOrientationMistmatch
+ this.acceptedSizeScore = 75
+ this.acceptedAngleScore = 60
+ }
+ })
+ }
+ documentScannerFrameHandler =
+ DocumentScannerFrameHandler.attach(cameraView, documentScanner)
+ cameraView.addPictureCallback(object : PictureCallback() {
+ override fun onPictureTaken(image: ImageRef, captureInfo: CaptureInfo) {
+ processPictureTaken(image, documentScanner)
+ }
})
+
+ documentScannerFrameHandler.addResultHandler(polygonView.documentScannerResultHandler)
+ documentScannerFrameHandler.addResultHandler(this@MainActivity)
+
+ autoSnappingController =
+ DocumentAutoSnappingController.attach(cameraView, documentScannerFrameHandler)
+
+ // Please note: https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/ui-components/#sensitivity
+ autoSnappingController.setSensitivity(0.85f)
}
+
cameraView = findViewById(R.id.camera) as ScanbotCameraXView
// In this example we demonstrate how to lock the orientation of the UI (Activity)
@@ -97,21 +126,7 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
polygonView.setFillColor(POLYGON_FILL_COLOR)
polygonView.setFillColorOK(POLYGON_FILL_COLOR_OK)
- documentScannerFrameHandler = DocumentScannerFrameHandler.attach(cameraView, documentScanner)
-
- documentScannerFrameHandler.addResultHandler(polygonView.documentScannerResultHandler)
- documentScannerFrameHandler.addResultHandler(this)
- autoSnappingController = DocumentAutoSnappingController.attach(cameraView, documentScannerFrameHandler)
-
- // Please note: https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/ui-components/#sensitivity
- autoSnappingController.setSensitivity(0.85f)
-
- cameraView.addPictureCallback(object : PictureCallback() {
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
- processPictureTaken(image, captureInfo.imageOrientation)
- }
- })
userGuidanceHint = findViewById(R.id.userGuidanceHint)
shutterButton = findViewById(R.id.shutterButton)
@@ -132,19 +147,27 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
}
private fun askPermission() {
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(
+ this,
+ Manifest.permission.CAMERA
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), 999)
}
}
- override fun handle(result: FrameHandlerResult): Boolean {
+ override fun handle(
+ result: Result,
+ frame: FrameHandler.Frame
+ ): Boolean {
// Here you are continuously notified about document scanning results.
// For example, you can show a user guidance text depending on the current scanning status.
- userGuidanceHint.post {
- if (result is FrameHandlerResult.Success<*>) {
- showUserGuidance((result as FrameHandlerResult.Success).value.detectionStatus)
+ result.onSuccess { data ->
+ userGuidanceHint.post {
+ showUserGuidance(data.detectionStatus)
}
}
+
return false // typically you need to return false
}
@@ -163,22 +186,27 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
userGuidanceHint.text = "Don't move"
userGuidanceHint.visibility = View.VISIBLE
}
+
DocumentDetectionStatus.OK_BUT_TOO_SMALL -> {
userGuidanceHint.text = "Move closer"
userGuidanceHint.visibility = View.VISIBLE
}
+
DocumentDetectionStatus.OK_BUT_BAD_ANGLES -> {
userGuidanceHint.text = "Perspective"
userGuidanceHint.visibility = View.VISIBLE
}
+
DocumentDetectionStatus.ERROR_NOTHING_DETECTED -> {
userGuidanceHint.text = "No Document"
userGuidanceHint.visibility = View.VISIBLE
}
+
DocumentDetectionStatus.ERROR_TOO_NOISY -> {
userGuidanceHint.text = "Background too noisy"
userGuidanceHint.visibility = View.VISIBLE
}
+
DocumentDetectionStatus.OK_BUT_BAD_ASPECT_RATIO -> {
if (ignoreOrientationMistmatch) {
userGuidanceHint.text = "Don't move"
@@ -189,40 +217,34 @@ class MainActivity : AppCompatActivity(), DocumentScannerFrameHandler.ResultHand
}
userGuidanceHint.visibility = View.VISIBLE
}
+
DocumentDetectionStatus.ERROR_TOO_DARK -> {
userGuidanceHint.text = "Poor light"
userGuidanceHint.visibility = View.VISIBLE
}
+
else -> userGuidanceHint.visibility = View.GONE
}
lastUserGuidanceHintTs = System.currentTimeMillis()
}
- private fun processPictureTaken(image: ByteArray, imageOrientation: Int) {
- // Here we get the full image from the camera.
- // Please see https://docs.scanbot.io/document-scanner-sdk/android/features/document-scanner/classic-ui/
- // This is just a demo showing the scanned document image as a downscaled(!) preview image.
-
- // Decode Bitmap from bytes of original image:
- val options = BitmapFactory.Options()
- // Please note: In this simple demo we downscale the original image to 1/8 for the preview!
- options.inSampleSize = 8
- // Typically you will need the full resolution of the original image! So please change the "inSampleSize" value to 1!
- //options.inSampleSize = 1
- var originalBitmap = BitmapFactory.decodeByteArray(image, 0, image.size, options)
-
- // Rotate the original image based on the imageOrientation value.
- // Required for some Android devices like Samsung!
- if (imageOrientation > 0) {
- val matrix = Matrix()
- matrix.setRotate(imageOrientation.toFloat(), originalBitmap.width / 2f, originalBitmap.height / 2f)
- originalBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.width, originalBitmap.height, matrix, false)
- }
+ private fun processPictureTaken(image: ImageRef, documentScanner: DocumentScanner) {
// Run document scanning on original image:
- val polygon = documentScanner.scanFromBitmap(originalBitmap)!!.pointsNormalized
-
- val documentImage = ImageProcessor(originalBitmap).crop(polygon).processedBitmap()
- resultView.post { resultView.setImageBitmap(documentImage) }
+ val polygon =
+ documentScanner.run(image).getOrNull()?.pointsNormalized ?: throw IllegalStateException(
+ "No document detected"
+ )
+ val polygonCrop =
+ polygon.takeIf { it.isNotEmpty() && it.size == 4 } ?: PolygonHelper.getFullPolygon()
+ val documentImage = ScanbotSdkImageProcessor.create()
+ .crop(image, polygonCrop)
+ .mapSuccess { documentImage ->
+ ScanbotSdkImageProcessor.create().resize(documentImage, 200).getOrReturn()
+ }.getOrNull()
+
+ resultView.post {
+ resultView.setImageBitmap(documentImage?.toBitmap()?.getOrNull())
+ }
// continue scanning
cameraView.postDelayed({
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 8de408b7..f5df0939 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
@@ -10,17 +10,17 @@ import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
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.CameraPreviewMode
import io.scanbot.sdk.camera.CaptureInfo
-import io.scanbot.sdk.camera.FrameHandlerResult
import io.scanbot.sdk.camera.PictureCallback
-import io.scanbot.sdk.check.CheckScanner
-import io.scanbot.sdk.document.DocumentScanner
import io.scanbot.sdk.document.DocumentAutoSnappingController
import io.scanbot.sdk.document.DocumentScannerFrameHandler
-import io.scanbot.sdk.process.ImageProcessor
+import io.scanbot.sdk.image.ImageRef
import io.scanbot.sdk.ui.PolygonView
import io.scanbot.sdk.ui.camera.ScanbotCameraXView
@@ -55,17 +55,19 @@ class AutoSnappingCheckScannerActivity : AppCompatActivity() {
resultView = findViewById(R.id.result) as TextView
scanbotSDK = ScanbotSDK(this)
- val documentScanner = scanbotSDK.createDocumentScanner()
+ val documentScanner = scanbotSDK.createDocumentScanner().getOrThrow()
polygonView = findViewById(R.id.polygonView) as PolygonView
frameHandler =
DocumentScannerFrameHandler.attach(cameraView, documentScanner)
- documentScanner.setParameters(documentScanner.copyCurrentConfiguration().parameters.apply {
- this.ignoreOrientationMismatch = true
- this.acceptedSizeScore = 75
- this.acceptedAngleScore = 60
+ documentScanner.setConfiguration(documentScanner.copyCurrentConfiguration().apply {
+ parameters.apply {
+ this.ignoreOrientationMismatch = true
+ this.acceptedSizeScore = 75
+ this.acceptedAngleScore = 60
+ }
})
frameHandler.addResultHandler(polygonView.documentScannerResultHandler)
@@ -76,7 +78,7 @@ class AutoSnappingCheckScannerActivity : AppCompatActivity() {
autoSnappingController.setSensitivity(0.85f)
cameraView.addPictureCallback(object : PictureCallback() {
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
+ override fun onPictureTaken(image: ImageRef, captureInfo: CaptureInfo) {
frameHandler.isEnabled = false
processPictureTaken(image)
runOnUiThread {
@@ -90,13 +92,13 @@ class AutoSnappingCheckScannerActivity : AppCompatActivity() {
cameraView.useFlash(flashEnabled)
}
- frameHandler.addResultHandler {
- if (it !is FrameHandlerResult.Success) {
+ frameHandler.addResultHandler { result, frame ->
+ result.onSuccess {
if (!scanbotSDK.licenseInfo.isValid) {
frameHandler.isEnabled = false
runOnUiThread {
Toast.makeText(
- this,
+ this@AutoSnappingCheckScannerActivity,
"License is expired",
Toast.LENGTH_LONG
).show()
@@ -108,14 +110,12 @@ class AutoSnappingCheckScannerActivity : AppCompatActivity() {
}
}
- private fun processPictureTaken(image: ByteArray) {
- val options = BitmapFactory.Options()
- val originalBitmap = BitmapFactory.decodeByteArray(image, 0, image.size, options)
- // documentImage will be recycled inside scanCheckBitmap
- val checkScanner = scanbotSDK.createCheckScanner()
- val checkResult = checkScanner.scanFromBitmap(originalBitmap, 0)
+ private fun processPictureTaken(image: ImageRef) {
+
+ val checkScanner = scanbotSDK.createCheckScanner().getOrThrow()
+ val checkResult = checkScanner.run(image).getOrNull()
if (checkResult?.check != null) {
- CheckScannerResultActivity.tempDocumentImage = checkResult.croppedImage?.toBitmap()
+ CheckScannerResultActivity.tempDocumentImage = checkResult.croppedImage?.toBitmap()?.getOrNull()
startActivity(CheckScannerResultActivity.newIntent(this, checkResult))
} else {
runOnUiThread {
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 ad889e8b..3275ebcc 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
@@ -8,11 +8,13 @@ import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
+import io.scanbot.common.Result
+import io.scanbot.common.onFailure
+import io.scanbot.common.onSuccess
+
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.sdk.ScanbotSDK
-import io.scanbot.sdk.SdkLicenseError
import io.scanbot.sdk.camera.CameraPreviewMode
-import io.scanbot.sdk.camera.FrameHandlerResult
import io.scanbot.sdk.check.CheckScannerFrameHandler
import io.scanbot.sdk.check.CheckScannerFrameHandler.Companion.attach
import io.scanbot.sdk.check.CheckScanningResult
@@ -45,28 +47,37 @@ class CheckScannerActivity : AppCompatActivity() {
resultView = findViewById(R.id.result) as TextView
val scanbotSDK = ScanbotSDK(this)
- val checkScanner = scanbotSDK.createCheckScanner()
- frameHandler = attach(cameraView, checkScanner)
- frameHandler.addResultHandler { result: FrameHandlerResult? ->
- if (result is FrameHandlerResult.Success<*>) {
- val scanningResult = (result as FrameHandlerResult.Success<*>).value as CheckScanningResult?
- if (scanningResult?.status == CheckMagneticInkStripScanningStatus.SUCCESS) {
- frameHandler.isEnabled = false
- startActivity(CheckScannerResultActivity.newIntent(this, scanningResult))
- }
- } else if (!scanbotSDK.licenseInfo.isValid) {
- frameHandler.isEnabled = false
- runOnUiThread {
- Toast.makeText(
- this,
- "License is expired",
- Toast.LENGTH_LONG
- ).show()
- finish()
+ scanbotSDK.createCheckScanner().onSuccess { checkScanner ->
+ frameHandler = attach(cameraView, checkScanner)
+ frameHandler.addResultHandler { result, frame ->
+ result.onSuccess { scanningResult ->
+ if (scanningResult?.status == CheckMagneticInkStripScanningStatus.SUCCESS) {
+ frameHandler.isEnabled = false
+ startActivity(
+ CheckScannerResultActivity.newIntent(
+ this@CheckScannerActivity,
+ scanningResult
+ )
+ )
+ }
+ }.onFailure {
+ if (it is Result.InvalidLicenseError) {
+ frameHandler.isEnabled = false
+ runOnUiThread {
+ Toast.makeText(
+ this@CheckScannerActivity,
+ "License is expired",
+ Toast.LENGTH_LONG
+ ).show()
+ finish()
+ }
+ }
}
+
+ false
}
- false
}
+
findViewById(R.id.flash).setOnClickListener {
flashEnabled = !flashEnabled
cameraView.useFlash(flashEnabled)
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 8673879d..a0fd2d03 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
@@ -11,7 +11,7 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.sdk.check.CheckScanningResult
-import io.scanbot.sdk.genericdocument.entity.GenericDocument
+import io.scanbot.sdk.genericdocument.GenericDocument
class CheckScannerResultActivity : AppCompatActivity() {
private lateinit var checkResultImageView: ImageView
diff --git a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
index 39a3c0ef..bba5689b 100755
--- a/classic-components-example/check-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/check-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -1,9 +1,9 @@
package io.scanbot.example
import android.app.Application
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
+import io.scanbot.sdk.licensing.LicenseStatus
import io.scanbot.sdk.util.log.LoggerProvider
class ExampleApplication : Application() {
@@ -24,11 +24,9 @@ class ExampleApplication : Application() {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
+ .licenseErrorHandler { status, feature, statusMessage ->
LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
- }
+ LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
.initialize(this)
@@ -38,6 +36,6 @@ class ExampleApplication : Application() {
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.expirationDate}")
+ LoggerProvider.logger.d("ExampleApplication", "License expirationDate: ${licenseInfo.expirationDateString}")
}
}
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 daed07f8..d42d517d 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
@@ -2,7 +2,6 @@ package io.scanbot.example
import android.Manifest
import android.content.pm.PackageManager
-import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
@@ -13,15 +12,25 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
+
+
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.image.ImageRef
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) }
@@ -69,16 +78,16 @@ class MainActivity : AppCompatActivity() {
withContext(Dispatchers.Main) { binding.progressBar.isVisible = true }
val result = withContext(Dispatchers.Default) {
- val inputStream = contentResolver.openInputStream(uri)
- val bitmap = BitmapFactory.decodeStream(inputStream)
+ val inputStream = contentResolver.openInputStream(uri) ?: throw IllegalStateException("Cannot open input stream from URI: $uri")
+ val imageRef = ImageRef.fromInputStream(inputStream)
- val scanner = scanbotSdk.createCheckScanner()
- scanner.scanFromBitmap(bitmap, 0)
+ val scanner = scanbotSdk.createCheckScanner().getOrThrow()
+ scanner.run(imageRef).getOrNull()
}
withContext(Dispatchers.Main) {
result?.let {
- CheckScannerResultActivity.tempDocumentImage = it.croppedImage?.toBitmap()
+ CheckScannerResultActivity.tempDocumentImage = it?.croppedImage?.toBitmap()?.getOrNull()
startActivity(CheckScannerResultActivity.newIntent(this@MainActivity, it))
} ?: this@MainActivity.showToast("No data found!")
}
diff --git a/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
index 8ed9ed1d..eff756b8 100755
--- a/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/creditcard-scanner/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -1,7 +1,6 @@
package io.scanbot.example
import android.app.Application
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
import io.scanbot.sdk.util.log.LoggerProvider
@@ -24,11 +23,9 @@ class ExampleApplication : Application() {
.withLogging(true)
// TODO 2/2: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
+ .licenseErrorHandler { status, feature, statusMessage ->
LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
- }
+ LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
.prepareOCRLanguagesBlobs(true)
@@ -39,6 +36,6 @@ class ExampleApplication : Application() {
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.expirationDate}")
+ LoggerProvider.logger.d("ExampleApplication", "License expirationDate: ${licenseInfo.expirationDateString}")
}
}
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 cea0fdf2..5bf14381 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
@@ -12,6 +12,13 @@ import androidx.core.app.ActivityCompat
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:
+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() {
override fun onCreate(savedInstanceState: Bundle?) {
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 6ea6ece0..43327b2c 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
@@ -2,26 +2,27 @@ package io.scanbot.example
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
+import io.scanbot.common.mapFailure
+import io.scanbot.common.mapSuccess
+import io.scanbot.common.onSuccess
+
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.example.databinding.ActivityScannerBinding
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.camera.CameraPreviewMode
-import io.scanbot.sdk.camera.FrameHandlerResult
-import io.scanbot.sdk.common.AspectRatio
import io.scanbot.sdk.creditcard.CreditCardScanner
import io.scanbot.sdk.creditcard.CreditCardScannerFrameHandler
import io.scanbot.sdk.creditcard.CreditCardScanningStatus
import io.scanbot.sdk.creditcard.entity.CreditCard
+import io.scanbot.sdk.geometry.AspectRatio
class ScannerActivity : AppCompatActivity() {
// @Tag("Credit Card Classic Camera")
private lateinit var binding: ActivityScannerBinding
- private lateinit var scanner: CreditCardScanner
private var useFlash = false
- private lateinit var frameHandler: CreditCardScannerFrameHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -31,36 +32,42 @@ class ScannerActivity : AppCompatActivity() {
applyEdgeToEdge(this.findViewById(R.id.root_view))
// init scanbot sdk and create credit card scanner
- scanner = ScanbotSDK(this).createCreditCardScanner()
- // set aspect ration for finder overlay
- binding.finderOverlay.setRequiredAspectRatios(listOf(AspectRatio(1.586, 1.0))) // standard credit card aspect ratio
-
- // set camera preview mode to fit in the camera container
- binding.cameraView.setPreviewMode(CameraPreviewMode.FIT_IN)
-
- // attach scanner to the camera view
- frameHandler = CreditCardScannerFrameHandler.attach(binding.cameraView, scanner)
- // handle live credit card scanning results
- frameHandler.addResultHandler { result ->
- val resultText: String = when (result) {
- is FrameHandlerResult.Success -> {
- if (result.value.scanningStatus == CreditCardScanningStatus.SUCCESS ||
- result.value.scanningStatus == CreditCardScanningStatus.INCOMPLETE
+ ScanbotSDK(this).createCreditCardScanner().onSuccess { scanner ->
+ // attach scanner to the camera view
+ val frameHandler = CreditCardScannerFrameHandler.attach(binding.cameraView, scanner)
+ // handle live credit card scanning results
+ frameHandler.addResultHandler { result, frame ->
+ val resultText: String = result.mapSuccess { value ->
+ if (value.scanningStatus == CreditCardScanningStatus.SUCCESS ||
+ value.scanningStatus == CreditCardScanningStatus.INCOMPLETE
) {
- CreditCard(result.value.creditCard!!).cardNumber.value.text
+ CreditCard(value.creditCard!!).cardNumber.value.text
} else {
"Credit card not found"
}
- }
+ }.mapFailure {
+ it.message ?: "Unknown error"
+ }.getOrNull() ?: ""
- is FrameHandlerResult.Failure -> "Check your setup or license"
+ // NOTE: 'handle' method runs in background thread - don't forget to switch to main before touching any Views
+ runOnUiThread { binding.resultTextView.text = resultText }
+
+ false
}
+ }
+ // set aspect ration for finder overlay
+ binding.finderOverlay.setRequiredAspectRatios(
+ listOf(
+ AspectRatio(
+ 1.586,
+ 1.0
+ )
+ )
+ ) // standard credit card aspect ratio
- // NOTE: 'handle' method runs in background thread - don't forget to switch to main before touching any Views
- runOnUiThread { binding.resultTextView.text = resultText }
+ // set camera preview mode to fit in the camera container
+ binding.cameraView.setPreviewMode(CameraPreviewMode.FIT_IN)
- false
- }
// configure camera view
binding.cameraView.setCameraOpenCallback {
diff --git a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ExampleApplication.kt b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ExampleApplication.kt
index f91dec8d..8d7972bb 100755
--- a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ExampleApplication.kt
+++ b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ExampleApplication.kt
@@ -4,7 +4,6 @@ import android.app.Application
import android.os.Handler
import android.os.Looper
import android.widget.Toast
-import io.scanbot.sap.SdkFeature
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.ScanbotSDKInitializer
import io.scanbot.sdk.util.log.LoggerProvider
@@ -28,15 +27,20 @@ class ExampleApplication : Application() {
.withLogging(true)
// TODO 2/3: Enable the Scanbot SDK license key
//.license(this, licenseKey)
- .licenceErrorHandler { status, feature, statusMessage ->
- LoggerProvider.logger.d("ExampleApplication", "+++> License status: ${status.name}. Status message: $statusMessage")
- if (feature != SdkFeature.NoSdkFeature) {
- LoggerProvider.logger.d("ExampleApplication", "+++> Feature not available: ${feature.name}")
+ .licenseErrorHandler { status, feature, statusMessage ->
+ LoggerProvider.logger.d(
+ "ExampleApplication",
+ "+++> License status: ${status.name}. Status message: $statusMessage"
+ )
+ LoggerProvider.logger.d(
+ "ExampleApplication",
+ "+++> Feature not available: ${feature.name}"
+ )
- // TODO: 3/3 Handle license error properly
- uiHandler.post {
- Toast.makeText(applicationContext, "Trial license expired", Toast.LENGTH_SHORT).show()
- }
+ // TODO: 3/3 Handle license error properly
+ uiHandler.post {
+ Toast.makeText(applicationContext, "Trial license expired", Toast.LENGTH_SHORT)
+ .show()
}
}
//.sdkFilesDirectory(this, getExternalFilesDir(null)!!)
@@ -47,6 +51,9 @@ class ExampleApplication : Application() {
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.expirationDate}")
+ LoggerProvider.logger.d(
+ "ExampleApplication",
+ "License expirationDate: ${licenseInfo.expirationDateString}"
+ )
}
}
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 b5534f89..0f0d3c65 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
@@ -2,7 +2,6 @@ package io.scanbot.example
import android.Manifest
import android.content.Intent
-import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Log
import android.view.View
@@ -10,16 +9,25 @@ import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
+
+
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.documentdata.DocumentDataExtractionMode
+import io.scanbot.sdk.image.ImageRef
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 binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
@@ -41,12 +49,12 @@ class MainActivity : AppCompatActivity() {
}
lifecycleScope.launch {
- val dataExtractor = scanbotSdk.createDocumentDataExtractor()
+ val dataExtractor = scanbotSdk.createDocumentDataExtractor().getOrThrow()
val result = withContext(Dispatchers.Default) {
- val inputStream = contentResolver.openInputStream(uri)
- val bitmap = BitmapFactory.decodeStream(inputStream)
- dataExtractor.extractFromBitmap(bitmap, 0, DocumentDataExtractionMode.SINGLE_SHOT)
+ val inputStream = contentResolver.openInputStream(uri) ?: throw IllegalStateException("Cannot open input stream from URI: $uri")
+ val imageRef = ImageRef.fromInputStream(inputStream)
+ dataExtractor.run(imageRef).getOrNull()
}
withContext(Dispatchers.Main) {
diff --git a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ResultActivity.kt b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ResultActivity.kt
index 6ef081ec..5ce8b7c4 100755
--- a/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ResultActivity.kt
+++ b/classic-components-example/document-data-extractor-autosnapping/src/main/java/io/scanbot/example/ResultActivity.kt
@@ -9,9 +9,10 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
+
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.sdk.documentdata.DocumentDataExtractionResult
-import io.scanbot.sdk.genericdocument.entity.Field
+import io.scanbot.sdk.genericdocument.Field
class ResultActivity : AppCompatActivity() {
@@ -71,7 +72,7 @@ private class Adapter(private val scanResult: DocumentDataExtractionResult) :
val confidence = String.format(FIELD_CONFIDENCE_FLOAT_FORMAT, (item.value?.confidence ?: 0.0) * 100)
fieldType.text = String.format(FIELD_TYPE_FORMAT, item.type.name.capitalize())
- fieldCroppedImage.setImageBitmap(item.image?.toBitmap())
+ fieldCroppedImage.setImageBitmap(item.image?.toBitmap()?.getOrNull())
fieldTextConfidence.text = String.format(FIELD_CONFIDENCE_FORMAT, confidence)
fieldExtractedText.text = item.value?.text
}
@@ -83,7 +84,7 @@ private class Adapter(private val scanResult: DocumentDataExtractionResult) :
private val cardType: TextView = itemView.findViewById(R.id.cardType)
fun bind(item: DocumentDataExtractionResult) {
- croppedCard.setImageBitmap(item.croppedImage?.toBitmap())
+ croppedCard.setImageBitmap(item.croppedImage?.toBitmap()?.getOrNull())
cardType.text = item.document?.type?.name
}
}
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 4f0b09e5..8d8d6399 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
@@ -6,16 +6,20 @@ import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import io.scanbot.common.onSuccess
+
+
import io.scanbot.example.common.applyEdgeToEdge
import io.scanbot.sdk.ScanbotSDK
import io.scanbot.sdk.camera.CameraPreviewMode
import io.scanbot.sdk.camera.CaptureInfo
import io.scanbot.sdk.camera.PictureCallback
-import io.scanbot.sdk.common.AspectRatio
import io.scanbot.sdk.documentdata.DocumentDataAutoSnappingController
import io.scanbot.sdk.documentdata.DocumentDataExtractionResult
import io.scanbot.sdk.documentdata.DocumentDataExtractionStatus
import io.scanbot.sdk.documentdata.DocumentDataExtractor
+import io.scanbot.sdk.geometry.AspectRatio
+import io.scanbot.sdk.image.ImageRef
import io.scanbot.sdk.ui.camera.FinderOverlayView
import io.scanbot.sdk.ui.camera.IScanbotCameraView
import io.scanbot.sdk.ui.camera.ScanbotCameraXView
@@ -40,23 +44,27 @@ class ScannerActivity : AppCompatActivity() {
scanbotSdk = ScanbotSDK(this)
cameraView = findViewById(R.id.cameraView)
- findViewById(R.id.finder_overlay).setRequiredAspectRatios(listOf(
- AspectRatio(4.0, 3.0)
- ))
+ findViewById(R.id.finder_overlay).setRequiredAspectRatios(
+ listOf(
+ AspectRatio(4.0, 3.0)
+ )
+ )
cameraView.setPreviewMode(CameraPreviewMode.FIT_IN)
-
- autoSnappingController = DocumentDataAutoSnappingController.attach(cameraView, scanbotSdk.createDocumentDataExtractor())
+ scanbotSdk.createDocumentDataExtractor().onSuccess { extractor ->
+ autoSnappingController =
+ DocumentDataAutoSnappingController.attach(cameraView, extractor)
+ cameraView.addPictureCallback(object : PictureCallback() {
+ override fun onPictureTaken(image: ImageRef, captureInfo: CaptureInfo) {
+ processPictureTaken(image, extractor)
+ }
+ })
+ }
cameraView.setCameraOpenCallback {
cameraView.useFlash(useFlash)
cameraView.continuousFocus()
}
- cameraView.addPictureCallback(object : PictureCallback() {
- override fun onPictureTaken(image: ByteArray, captureInfo: CaptureInfo) {
- processPictureTaken(image, captureInfo.imageOrientation)
- }
- })
findViewById