1
+ package com.chaione.c1scanner
2
+
3
+ import android.Manifest
4
+ import android.annotation.SuppressLint
5
+ import android.content.pm.PackageManager
6
+ import android.net.Uri
7
+ import android.opengl.Visibility
8
+ import android.os.Bundle
9
+ import android.util.Log
10
+ import android.util.Size
11
+ import android.widget.TextView
12
+ import android.widget.Toast
13
+ import androidx.appcompat.app.AppCompatActivity
14
+ import androidx.camera.core.*
15
+ import androidx.camera.lifecycle.ProcessCameraProvider
16
+ import androidx.camera.view.PreviewView
17
+ import androidx.core.app.ActivityCompat
18
+ import androidx.core.content.ContextCompat
19
+ import androidx.core.view.isVisible
20
+ import com.google.android.gms.tasks.OnFailureListener
21
+ import com.google.android.gms.tasks.OnSuccessListener
22
+ import com.google.mlkit.vision.common.InputImage
23
+ import com.google.mlkit.vision.text.TextRecognition
24
+ import com.google.mlkit.vision.text.TextRecognizer
25
+ import com.google.mlkit.vision.text.Text
26
+ import kotlinx.android.synthetic.main.activity_main.*
27
+ import java.io.File
28
+ import java.text.SimpleDateFormat
29
+ import java.util.*
30
+ import java.util.concurrent.ExecutorService
31
+ import java.util.concurrent.Executors
32
+
33
+
34
+ typealias LumaListener = (luma: Double ) -> Unit
35
+
36
+ class MainActivity : AppCompatActivity () {
37
+ private var preview: Preview ? = null
38
+ private var imageCapture: ImageCapture ? = null
39
+ private var imageAnalyzer: ImageAnalysis ? = null
40
+ private var camera: Camera ? = null
41
+ private var results: TextView ? = null
42
+
43
+ private lateinit var outputDirectory: File
44
+ private lateinit var cameraExecutor: ExecutorService
45
+
46
+ override fun onCreate (savedInstanceState : Bundle ? ) {
47
+ super .onCreate(savedInstanceState)
48
+ setContentView(R .layout.activity_main)
49
+ results = findViewById(R .id.results)
50
+ // viewFinder = findViewById(R.id.viewFinder);
51
+
52
+ // Request camera permissions
53
+ if (allPermissionsGranted()) {
54
+ startCamera()
55
+ } else {
56
+ ActivityCompat .requestPermissions(
57
+ this , REQUIRED_PERMISSIONS , REQUEST_CODE_PERMISSIONS )
58
+ }
59
+
60
+ // Setup the listener for take photo button
61
+ camera_capture_button.setOnClickListener { takePhoto() }
62
+
63
+ outputDirectory = getOutputDirectory()
64
+
65
+ cameraExecutor = Executors .newSingleThreadExecutor()
66
+ }
67
+ private fun startCamera () {
68
+ val cameraProviderFuture = ProcessCameraProvider .getInstance(this )
69
+
70
+ cameraProviderFuture.addListener(Runnable {
71
+ // Used to bind the lifecycle of cameras to the lifecycle owner
72
+ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
73
+
74
+ // Preview
75
+ preview = Preview .Builder ().build()
76
+
77
+ imageCapture = ImageCapture .Builder ()
78
+ .setCaptureMode(ImageCapture .CAPTURE_MODE_MAXIMIZE_QUALITY )
79
+ .build()
80
+ //
81
+ imageAnalyzer = ImageAnalysis .Builder ()
82
+ .setBackpressureStrategy(ImageAnalysis .STRATEGY_KEEP_ONLY_LATEST )
83
+ .build()
84
+ .also {
85
+ it.setAnalyzer(cameraExecutor, OcrAnalyzer ())
86
+ }
87
+
88
+ // Select back camera
89
+ val cameraSelector = CameraSelector .Builder ().requireLensFacing(CameraSelector .LENS_FACING_BACK ).build()
90
+
91
+ try {
92
+ // Unbind use cases before rebinding
93
+ cameraProvider.unbindAll()
94
+
95
+ // Bind use cases to camera
96
+ camera = cameraProvider.bindToLifecycle(
97
+ this , cameraSelector, preview, imageCapture, imageAnalyzer)
98
+ preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))
99
+ } catch (exc: Exception ) {
100
+ Log .e(TAG , " Use case binding failed" , exc)
101
+ }
102
+
103
+ }, ContextCompat .getMainExecutor(this ))
104
+ }
105
+
106
+ private fun takePhoto () {
107
+ val imageCapture = imageCapture ? : return
108
+ val photoFile = File (outputDirectory,SimpleDateFormat (FILENAME_FORMAT , Locale .US ).format(System .currentTimeMillis()) + " .jpg" )
109
+ val outputOptions = ImageCapture .OutputFileOptions .Builder (photoFile).build()
110
+
111
+ imageCapture.takePicture(outputOptions, ContextCompat .getMainExecutor(this ), object : ImageCapture .OnImageSavedCallback {
112
+ override fun onError (exception : ImageCaptureException ) {
113
+ Log .e(TAG , " Photo capture failed ${exception.message} " , exception)
114
+ }
115
+
116
+ override fun onImageSaved (outputFileResults : ImageCapture .OutputFileResults ) {
117
+ val savedUri = Uri .fromFile(photoFile)
118
+ val msg = " Photo capture succeeded: $savedUri "
119
+ Toast .makeText(baseContext, msg, Toast .LENGTH_SHORT ).show()
120
+ Log .d(TAG , msg)
121
+
122
+ val file = InputImage .fromFilePath(baseContext, savedUri)
123
+ runTextRecognition(file)
124
+ }
125
+ })
126
+ }
127
+
128
+ private fun runTextRecognition (image : InputImage ) {
129
+ val recognizer: TextRecognizer = TextRecognition .getClient()
130
+ recognizer.process(image)
131
+ .addOnSuccessListener { texts ->
132
+ processTextRecognitionResult(texts as Text )
133
+ }
134
+ .addOnFailureListener{ e -> // Task failed with an exception
135
+ e.printStackTrace()
136
+ }
137
+ }
138
+ private fun processTextRecognitionResult (texts : Text ) {
139
+ Log .d(TAG , " Processing..." )
140
+ val blocks: List <Text .TextBlock > = texts.getTextBlocks()
141
+ if (blocks.size == = 0 ) {
142
+ Log .d(TAG , " No text found" )
143
+ return
144
+ }
145
+ var result = " "
146
+ for (i in 0 until blocks.size) {
147
+ val lines: List <Text .Line > = blocks[i].getLines()
148
+ for (j in 0 until lines.size) {
149
+ val elements: List <Text .Element > = lines[j].getElements()
150
+ for (k in 0 until elements.size) {
151
+ Log .d(TAG ," Text found: ${elements[k]} " )
152
+ result + = elements[k].text + " , "
153
+ // val textGraphic: Graphic = TextGraphic(mGraphicOverlay, elements[k])
154
+ // mGraphicOverlay.add(textGraphic)
155
+ }
156
+ }
157
+ }
158
+ results?.text = result
159
+ }
160
+
161
+ override fun onRequestPermissionsResult (requestCode : Int , permissions : Array <String >, grantResults : IntArray ) {
162
+ if (requestCode == REQUEST_CODE_PERMISSIONS ) {
163
+ if (allPermissionsGranted()) {
164
+ startCamera()
165
+ } else {
166
+ Toast .makeText(this ,
167
+ " Permissions not granted." ,
168
+ Toast .LENGTH_SHORT ).show()
169
+ finish()
170
+ }
171
+ }
172
+ }
173
+ private fun allPermissionsGranted () = REQUIRED_PERMISSIONS .all {
174
+ ContextCompat .checkSelfPermission(baseContext, it) == PackageManager .PERMISSION_GRANTED
175
+ }
176
+
177
+ fun getOutputDirectory (): File {
178
+ val mediaDir = externalMediaDirs.firstOrNull()?.let {
179
+ File (it, resources.getString(R .string.app_name)).apply { mkdirs() } }
180
+ return if (mediaDir != null && mediaDir.exists())
181
+ mediaDir else filesDir
182
+ }
183
+
184
+ companion object {
185
+ private const val TAG = " C1_Scanner"
186
+ private const val FILENAME_FORMAT = " yyyy-MM-dd-HH-mm-ss-SSS"
187
+ private const val REQUEST_CODE_PERMISSIONS = 10
188
+ private val REQUIRED_PERMISSIONS = arrayOf(Manifest .permission.CAMERA )
189
+ }
190
+
191
+ private class OcrAnalyzer : ImageAnalysis .Analyzer {
192
+
193
+ @SuppressLint(" UnsafeExperimentalUsageError" )
194
+ override fun analyze (image : ImageProxy ) {
195
+ val mediaImage = image.image
196
+ if (mediaImage != null ) {
197
+ // val image = InputImage.fromMediaImage(mediaImage, image.imageInfo.rotationDegrees)
198
+ // runTextRecognition(image);
199
+ }
200
+ image.close()
201
+ }
202
+ }
203
+ }
0 commit comments