-
Notifications
You must be signed in to change notification settings - Fork 48
Expand file tree
/
Copy pathMainActivity.kt
More file actions
executable file
·163 lines (140 loc) · 6.29 KB
/
MainActivity.kt
File metadata and controls
executable file
·163 lines (140 loc) · 6.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package io.scanbot.example
import android.Manifest
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.ImageView
import androidx.activity.result.PickVisualMediaRequest
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.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
/**
This example uses the SDK APIs introduced in Scanbot SDK v8.x.x.
Please check the official documentation for more details:
Result API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/result-api/
ImageRef API https://docs.scanbot.io/android/document-scanner-sdk/detailed-setup-guide/image-ref-api/
*/
class MainActivity : AppCompatActivity() {
private val scanbotSdk: ScanbotSDK by lazy { ScanbotSDK(this) }
private val scanner: DocumentScanner? by lazy { scanbotSdk.createDocumentScanner().getOrNull() }
private val requestCameraLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
openCameraDialog()
} else {
this@MainActivity.showToast("Camera permission is required to run this example!")
}
}
private val selectGalleryImageResultLauncher =
registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (!scanbotSdk.licenseInfo.isValid) {
this@MainActivity.showToast("1-minute trial license has expired!")
Log.e(Const.LOG_TAG, "1-minute trial license has expired!")
return@registerForActivityResult
}
if (uri == null) {
showToast("Error obtaining selected image!")
Log.e(Const.LOG_TAG, "Error obtaining selected image!")
return@registerForActivityResult
}
if (scanbotSdk.licenseInfo.isValid) {
lifecycleScope.launch {
scanner?.let {
processImageForAutoDocumentScanning(
uri,
it
)
}
}
} else {
this@MainActivity.showToast("1-minute trial license has expired!")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
applyEdgeToEdge(findViewById(R.id.root_view))
findViewById<View>(R.id.show_dialog_btn).setOnClickListener {
requestCameraLauncher.launch(Manifest.permission.CAMERA)
}
findViewById<View>(R.id.import_image).setOnClickListener {
selectGalleryImageResultLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
}
private fun openCameraDialog() {
val ft = supportFragmentManager.beginTransaction()
val prev = supportFragmentManager.findFragmentByTag(DIALOG_TAG)
if (prev != null) {
ft.remove(prev)
}
ft.addToBackStack(null)
// Create and show the dialog.
val newFragment: DialogFragment = CameraDialogFragment.newInstance()
newFragment.show(ft, DIALOG_TAG)
}
/** Imports a selected image as original image and performs auto document scanning on it. */
private suspend fun processImageForAutoDocumentScanning(
imageUri: Uri,
scanner: DocumentScanner
) {
val progressBar = findViewById<View>(R.id.progress_bar)
val importResultImage = findViewById<ImageView>(R.id.import_result)
withContext(Dispatchers.Main) {
progressBar.visibility = View.VISIBLE
this@MainActivity.showToast("Importing image...")
}
val documentImage = withContext(Dispatchers.Default) {
val image = contentResolver.openInputStream(imageUri)?.use { inputStream ->
ImageRef.fromInputStream(inputStream)
}
if (image == null) {
Log.e(Const.LOG_TAG, "Cannot open input stream from URI: $imageUri")
return@withContext null
}
catchWithResult {
// create a new Document object with given image as original image:
val newDocument = scanbotSdk.documentApi.createDocument()
.getOrReturn() // can be handled with .getOrNull() if needed
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
if (documentImage == null) {
this@MainActivity.showToast("Error opening selected image!")
return@withContext
}
// show Page's document image:
importResultImage.setImageBitmap(documentImage)
importResultImage.visibility = View.VISIBLE
}
}
private companion object {
const val DIALOG_TAG = "scanbot_dialog"
}
}