diff --git a/classic-components-example/pdf-generation/build.gradle b/classic-components-example/pdf-generation/build.gradle
index baf5c167..763eab52 100644
--- a/classic-components-example/pdf-generation/build.gradle
+++ b/classic-components-example/pdf-generation/build.gradle
@@ -23,10 +23,6 @@ android {
}
}
- kotlin {
- jvmToolchain(project.ext.jvmToolchainVersion)
- }
-
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/LICENSE'
@@ -35,13 +31,15 @@ android {
exclude 'META-INF/DEPENDENCIES'
}
- buildFeatures {
- viewBinding = true
- }
+ buildFeatures.viewBinding = true
}
+kotlin.jvmToolchain(project.ext.jvmToolchainVersion)
+
dependencies {
implementation(project(":common"))
implementation("androidx.appcompat:appcompat:${project.ext.androidxAppcompatVersion}")
- implementation("io.scanbot:sdk-package-1:${project.ext.scanbotSdkVersion}")
+
+ // NOTE: use `sdk-package-1` when OCR feature is not needed:
+ implementation("io.scanbot:sdk-package-2:${project.ext.scanbotSdkVersion}")
}
diff --git a/classic-components-example/pdf-generation/src/main/AndroidManifest.xml b/classic-components-example/pdf-generation/src/main/AndroidManifest.xml
index 6d6cf0e3..5d06a1e7 100755
--- a/classic-components-example/pdf-generation/src/main/AndroidManifest.xml
+++ b/classic-components-example/pdf-generation/src/main/AndroidManifest.xml
@@ -16,21 +16,22 @@
android:exported="true">
-
+
+
+
+
-
-
diff --git a/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/MainActivity.kt b/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/MainActivity.kt
index 6c228c9d..5da20194 100755
--- a/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/MainActivity.kt
+++ b/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/MainActivity.kt
@@ -1,145 +1,28 @@
package io.scanbot.example
import android.content.Intent
-import android.content.pm.PackageManager
-import android.net.Uri
import android.os.Bundle
-import android.util.Log
-import android.view.View
-import androidx.activity.result.PickVisualMediaRequest
-import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.FileProvider
-import androidx.core.net.toFile
-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.image.ImageRef
-import io.scanbot.sdk.imageprocessing.ParametricFilter
-import io.scanbot.sdk.ocr.OcrEngineManager
-import io.scanbot.sdk.pdfgeneration.PageSize
-import io.scanbot.sdk.pdfgeneration.PdfConfiguration
-import io.scanbot.sdk.pdfgeneration.PdfGenerator
-import io.scanbot.sdk.util.PolygonHelper
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withContext
-import java.io.File
-
-/**
-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 runOcr = false
- private val scanbotSdk by lazy { ScanbotSDK(this) }
- private val pdfGenerator by lazy { scanbotSdk.createPdfGenerator(if (runOcr) OcrEngineManager.OcrConfig() else null) }
-
- private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
-
- private val selectGalleryImageResultLauncher =
- // limit to 5 images for example purposes
- registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
- if (uris.isEmpty()) {
- this@MainActivity.showToast("No images were selected!")
- Log.w(Const.LOG_TAG, "No images were selected!")
- return@registerForActivityResult
- }
-
- if (!scanbotSdk.licenseInfo.isValid) {
- this@MainActivity.showToast("Scanbot SDK license (1-minute trial) has expired!")
- Log.w(Const.LOG_TAG, "Scanbot SDK license (1-minute trial) has expired!")
- return@registerForActivityResult
- }
-
- lifecycleScope.launch { processDocument(uris, isGrayscaleChecked) }
- }
-
- private val isGrayscaleChecked: Boolean
- get() = binding.grayscaleCheckBox.isChecked
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar!!.hide()
- applyEdgeToEdge(findViewById(R.id.root_view))
-
- binding.scanButton.setOnClickListener {
- selectGalleryImageResultLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
- }
- }
-
- private suspend fun processDocument(uris: List, applyGrayscale: Boolean) {
- val filters =
- if (applyGrayscale) listOf(ParametricFilter.grayscaleFilter()) else emptyList()
- withContext(Dispatchers.Main) { binding.progressBar.visibility = View.VISIBLE }
-
- withContext(Dispatchers.Default) {
- scanbotSdk.createDocumentScanner().mapSuccess { documentScanner ->
- //can be handled with .getOrNull() if needed
- val document = scanbotSdk.documentApi.createDocument()
- .getOrReturn() //can be handled with .getOrNull() if needed
- uris.asSequence().forEach { uri ->
- val imageRef = contentResolver.openInputStream(uri)?.use { inputStream ->
- ImageRef.fromInputStream(inputStream)
- }
- if (imageRef == null) {
- Log.w(Const.LOG_TAG, "Cannot open input stream from URI: $uri")
- return@forEach
- }
- val newPolygon = documentScanner.run(imageRef).getOrNull()?.pointsNormalized
- ?: PolygonHelper.getFullPolygon()
- val page = document.addPage(imageRef)
- .getOrReturn() //can be handled with .getOrNull() if needed
- page.apply(newPolygon = newPolygon, newFilters = filters)
- }
- pdfGenerator.generate(
- document,
- PdfConfiguration.default().copy(pageSize = PageSize.A4)
- )
- document.pdfUri.toFile()
- }.onSuccess { renderedPdfFile ->
- runBlocking(Dispatchers.Main) {
- binding.progressBar.visibility = View.GONE
- openPdfDocument(renderedPdfFile)
- }
- }
- }
- }
+ applyEdgeToEdge(binding.root)
- private fun openPdfDocument(file: File) {
- val uri = FileProvider.getUriForFile(this, "${this.packageName}.provider", file)
-
- val openIntent = Intent(Intent.ACTION_VIEW).apply {
- setDataAndType(uri, "application/pdf")
- flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ binding.pdfButton.setOnClickListener {
+ val intent = Intent(this, PdfActivity::class.java)
+ startActivity(intent)
}
- if (intent.resolveActivity(packageManager) != null) {
- val chooser = Intent.createChooser(openIntent, file.name)
- val resInfoList = this.packageManager.queryIntentActivities(
- chooser,
- PackageManager.MATCH_DEFAULT_ONLY
- )
-
- for (resolveInfo in resInfoList) {
- val packageName = resolveInfo.activityInfo.packageName
- grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- }
- startActivity(chooser)
- } else {
- // Handle the case where no app can open PDF files
- showToast("No app found to open PDF files")
- Log.w(Const.LOG_TAG, "No app found to open PDF files")
+ binding.pdfWithOcrButton.setOnClickListener {
+ val intent = Intent(this, PdfWithOcrActivity::class.java)
+ startActivity(intent)
}
}
}
diff --git a/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/PdfActivity.kt b/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/PdfActivity.kt
new file mode 100644
index 00000000..e78c8b04
--- /dev/null
+++ b/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/PdfActivity.kt
@@ -0,0 +1,148 @@
+package io.scanbot.example
+
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.activity.result.PickVisualMediaRequest
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.FileProvider
+import androidx.core.net.toFile
+import androidx.lifecycle.lifecycleScope
+import io.scanbot.common.mapSuccess
+import io.scanbot.common.onFailure
+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.ActivityPdfBinding
+import io.scanbot.sdk.ScanbotSDK
+import io.scanbot.sdk.image.ImageRef
+import io.scanbot.sdk.imageprocessing.ParametricFilter
+import io.scanbot.sdk.pdfgeneration.PageSize
+import io.scanbot.sdk.pdfgeneration.PdfConfiguration
+import io.scanbot.sdk.util.PolygonHelper
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import java.io.File
+
+/** This 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 PdfActivity : AppCompatActivity() {
+
+ private val scanbotSdk by lazy { ScanbotSDK(this) }
+
+ private val binding by lazy { ActivityPdfBinding.inflate(layoutInflater) }
+
+ private val isGrayscaleChecked: Boolean
+ get() = binding.grayscaleCheckBox.isChecked
+
+ private val selectGalleryImageResultLauncher =
+ // limit to 5 images for example purposes
+ registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
+ if (uris.isEmpty()) {
+ this@PdfActivity.showToast("No images were selected!")
+ Log.w(Const.LOG_TAG, "No images were selected!")
+ return@registerForActivityResult
+ }
+
+ if (!scanbotSdk.licenseInfo.isValid) {
+ this@PdfActivity.showToast("Scanbot SDK license (1-minute trial) has expired!")
+ Log.w(Const.LOG_TAG, "Scanbot SDK license (1-minute trial) has expired!")
+ return@registerForActivityResult
+ }
+
+ lifecycleScope.launch { processDocument(uris, isGrayscaleChecked) }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ supportActionBar!!.hide()
+ applyEdgeToEdge(findViewById(R.id.root_view))
+
+ binding.scanButton.setOnClickListener {
+ selectGalleryImageResultLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ }
+ }
+
+ private suspend fun processDocument(uris: List, applyGrayscale: Boolean) {
+ val filters =
+ if (applyGrayscale) listOf(ParametricFilter.grayscaleFilter()) else emptyList()
+ withContext(Dispatchers.Main) { binding.progressBar.visibility = View.VISIBLE }
+
+ withContext(Dispatchers.Default) {
+ scanbotSdk.createDocumentScanner().mapSuccess { documentScanner ->
+
+ val document = scanbotSdk.documentApi.createDocument()
+ .getOrReturn() // can be handled with .getOrNull() if needed
+
+ uris.asSequence().forEach { uri ->
+ val imageRef = contentResolver.openInputStream(uri)?.use { inputStream ->
+ ImageRef.fromInputStream(inputStream)
+ }
+ if (imageRef == null) {
+ Log.w(Const.LOG_TAG, "Cannot open input stream from URI: $uri")
+ return@forEach
+ }
+ val newPolygon = documentScanner.run(imageRef).getOrNull()?.pointsNormalized
+ ?: PolygonHelper.getFullPolygon()
+ val page = document.addPage(imageRef).getOrReturn() // can be handled with .getOrNull() if needed
+ page.apply(newPolygon = newPolygon, newFilters = filters)
+ }
+
+ val pdfOcrGenerator = scanbotSdk.createPdfGenerator()
+ val pdfConfig = PdfConfiguration.default().copy(pageSize = PageSize.A4)
+
+ pdfOcrGenerator.generate(document, pdfConfig).getOrReturn() // can be handled with .getOrNull() if needed
+
+ document.pdfUri.toFile()
+ }.onSuccess { renderedPdfFile ->
+ runBlocking(Dispatchers.Main) {
+ binding.progressBar.visibility = View.GONE
+ openPdfDocument(renderedPdfFile)
+ }
+ }.onFailure { error ->
+ runBlocking(Dispatchers.Main) {
+ binding.progressBar.visibility = View.GONE
+ Log.w(Const.LOG_TAG, "Error during PDF generation: ${error.message}", error)
+ showToast("Error during PDF generation:\n${error.message}")
+ }
+ }
+ }
+ }
+
+ private fun openPdfDocument(file: File) {
+ val uri = FileProvider.getUriForFile(this, "${this.packageName}.provider", file)
+
+ val openIntent = Intent(Intent.ACTION_VIEW).apply {
+ setDataAndType(uri, "application/pdf")
+ flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ }
+
+ if (intent.resolveActivity(packageManager) != null) {
+ val chooser = Intent.createChooser(openIntent, file.name)
+ val resInfoList = packageManager.queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY)
+
+ for (resolveInfo in resInfoList) {
+ val packageName = resolveInfo.activityInfo.packageName
+ grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+
+ startActivity(chooser)
+ } else {
+ // Handle the case where no app can open PDF files
+ showToast("No app found to open PDF files")
+ Log.w(Const.LOG_TAG, "No app found to open PDF files")
+ }
+ }
+}
diff --git a/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/PdfWithOcrActivity.kt b/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/PdfWithOcrActivity.kt
new file mode 100644
index 00000000..eb59f928
--- /dev/null
+++ b/classic-components-example/pdf-generation/src/main/java/io/scanbot/example/PdfWithOcrActivity.kt
@@ -0,0 +1,149 @@
+package io.scanbot.example
+
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.activity.result.PickVisualMediaRequest
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.FileProvider
+import androidx.core.net.toFile
+import androidx.lifecycle.lifecycleScope
+import io.scanbot.common.mapSuccess
+import io.scanbot.common.onFailure
+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.ActivityPdfBinding
+import io.scanbot.sdk.ScanbotSDK
+import io.scanbot.sdk.image.ImageRef
+import io.scanbot.sdk.imageprocessing.ParametricFilter
+import io.scanbot.sdk.ocr.OcrEngineManager
+import io.scanbot.sdk.pdfgeneration.PageSize
+import io.scanbot.sdk.pdfgeneration.PdfConfiguration
+import io.scanbot.sdk.util.PolygonHelper
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import java.io.File
+
+/** This 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 PdfWithOcrActivity : AppCompatActivity() {
+
+ private val scanbotSdk by lazy { ScanbotSDK(this) }
+
+ private val binding by lazy { ActivityPdfBinding.inflate(layoutInflater) }
+
+ private val isGrayscaleChecked: Boolean
+ get() = binding.grayscaleCheckBox.isChecked
+
+ private val selectGalleryImageResultLauncher =
+ // limit to 5 images for example purposes
+ registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris ->
+ if (uris.isEmpty()) {
+ this@PdfWithOcrActivity.showToast("No images were selected!")
+ Log.w(Const.LOG_TAG, "No images were selected!")
+ return@registerForActivityResult
+ }
+
+ if (!scanbotSdk.licenseInfo.isValid) {
+ this@PdfWithOcrActivity.showToast("Scanbot SDK license (1-minute trial) has expired!")
+ Log.w(Const.LOG_TAG, "Scanbot SDK license (1-minute trial) has expired!")
+ return@registerForActivityResult
+ }
+
+ lifecycleScope.launch { processDocument(uris, isGrayscaleChecked) }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ supportActionBar!!.hide()
+ applyEdgeToEdge(binding.root)
+
+ binding.scanButton.setOnClickListener {
+ selectGalleryImageResultLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ }
+ }
+
+ private suspend fun processDocument(uris: List, applyGrayscale: Boolean) {
+ val filters =
+ if (applyGrayscale) listOf(ParametricFilter.grayscaleFilter()) else emptyList()
+ withContext(Dispatchers.Main) { binding.progressBar.visibility = View.VISIBLE }
+
+ withContext(Dispatchers.Default) {
+ scanbotSdk.createDocumentScanner().mapSuccess { documentScanner ->
+
+ val document = scanbotSdk.documentApi.createDocument()
+ .getOrReturn() // can be handled with .getOrNull() if needed
+
+ uris.asSequence().forEach { uri ->
+ val imageRef = contentResolver.openInputStream(uri)?.use { inputStream ->
+ ImageRef.fromInputStream(inputStream)
+ }
+ if (imageRef == null) {
+ Log.w(Const.LOG_TAG, "Cannot open input stream from URI: $uri")
+ return@forEach
+ }
+ val newPolygon = documentScanner.run(imageRef).getOrNull()?.pointsNormalized
+ ?: PolygonHelper.getFullPolygon()
+ val page = document.addPage(imageRef).getOrReturn() //can be handled with .getOrNull() if needed
+ page.apply(newPolygon = newPolygon, newFilters = filters)
+ }
+
+ val pdfOcrGenerator = scanbotSdk.createPdfGenerator(OcrEngineManager.OcrConfig())
+ val pdfConfig = PdfConfiguration.default().copy(pageSize = PageSize.A4)
+
+ pdfOcrGenerator.generate(document, pdfConfig).getOrReturn()
+
+ document.pdfUri.toFile()
+ }.onSuccess { renderedPdfFile ->
+ runBlocking(Dispatchers.Main) {
+ binding.progressBar.visibility = View.GONE
+ openPdfDocument(renderedPdfFile)
+ }
+ }.onFailure { error ->
+ runBlocking(Dispatchers.Main) {
+ binding.progressBar.visibility = View.GONE
+ Log.w(Const.LOG_TAG, "Error during PDF generation: ${error.message}", error)
+ showToast("Error during PDF generation:\n${error.message}")
+ }
+ }
+ }
+ }
+
+ private fun openPdfDocument(file: File) {
+ val uri = FileProvider.getUriForFile(this, "${this.packageName}.provider", file)
+
+ val openIntent = Intent(Intent.ACTION_VIEW).apply {
+ setDataAndType(uri, "application/pdf")
+ flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ }
+
+ if (intent.resolveActivity(packageManager) != null) {
+ val chooser = Intent.createChooser(openIntent, file.name)
+ val resInfoList = packageManager.queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY)
+
+ for (resolveInfo in resInfoList) {
+ val packageName = resolveInfo.activityInfo.packageName
+ grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+
+ startActivity(chooser)
+ } else {
+ // Handle the case where no app can open PDF files
+ showToast("No app found to open PDF files")
+ Log.w(Const.LOG_TAG, "No app found to open PDF files")
+ }
+ }
+}
diff --git a/classic-components-example/pdf-generation/src/main/res/layout/activity_main.xml b/classic-components-example/pdf-generation/src/main/res/layout/activity_main.xml
index fef7ccd1..36462b41 100755
--- a/classic-components-example/pdf-generation/src/main/res/layout/activity_main.xml
+++ b/classic-components-example/pdf-generation/src/main/res/layout/activity_main.xml
@@ -1,44 +1,36 @@
-
-
-
+ android:layout_gravity="center_horizontal"
+ android:textSize="22sp"
+ android:textStyle="bold"
+ android:text="Scanbot SDK Example"
+ />
-
-
-
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="PDF with OCR"
+ />
+
diff --git a/classic-components-example/pdf-generation/src/main/res/layout/activity_pdf.xml b/classic-components-example/pdf-generation/src/main/res/layout/activity_pdf.xml
new file mode 100755
index 00000000..bbc97960
--- /dev/null
+++ b/classic-components-example/pdf-generation/src/main/res/layout/activity_pdf.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+