Hello there, Stanley here, or Sam. Today am gonna talk you through brief steps for which you can be able to make a simple and yet super efficient document scanner App. We are going to implement this by using Kotlin as our back-end programming language. So let's get hands dirty for a couple of minutes. Keep in mind, the process is surprisingly simple than you think.
A super useful tool at hand is called Document Scanner. It is a library that is going to offer us the ability to scan documents based on CameraX API. This library was previously offered by Document-Scanning-Android-SDK. It was then taken away and enhanced with Improved logic of image processing, and as you can predict, the word enhance has to have better stuff. It's current processing time is promising being 5 times than it used to. Scanning a document under ideal scanning conditions takes approximately 5 seconds.
Let's give it a Go
The thing am about to lay out is not really relevant if you have the most current version of android studio in place, and if you don't, you have to know that this library is supported on devices of SDK 21 or later ( it's a fancy way to actually refer to devices of android 5.1 or above)
How to integrate the library with your project
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}Put the lines above in your root project build.gradle. It's the first real thing we are doing right here, but let me warn you. The part gets real tricky with the current version of android studio as you wont find the all-projects part that easily.
Well, worry about that no more, what you simply have got to do is move to your settings build.gradle and you will find the repository in there. I kept getting confused a number of times as am in the settings part of gradle, and you probably will too, or maybe not. But the point is, you probably will find two copycats written repository and please pick the one down of the other.
The next thing you wanna do here is move to your app build.gradle and add the following implementation
implementation 'com.github.Krobys:document-scanner-fast:1.0.0'
You then sync your project and you are ready to fire up the magic. How do you do this? Well let's take a look at it together.
Make an Application Class
I admit, this kind of Class sounded a little weird to me when i first came into contact. It's actually not something super fancy or professional as it sounds, you will have to create an ordinary class then make it inherit from Application( ), just as your activities classes always have got to inherit from AppCompatActivity( ). It's as simple as that. Assuming you already have your class in place, copy the following code in there (or you could try and understand the flow too). Either way, the task gets done.
class AnyNameApplication: Application() { override fun onCreate() { val configuration = DocumentScanner.Configuration() configuration.imageQuality = 100 configuration.imageSize = 1000000 // 1 MB configuration.imageType = Bitmap.CompressFormat.JPEG DocumentScanner.init(this, configuration) // or simply DocumentScanner.init(this) } }
One thing i keep forgetting each time am coding this kind of stuff is the fact that as soon as you finish with the making of your application class, you must go to your manifest and find a tag there written <Application. In there add a name property with the name of your Application class which for my case is Any bla bla..
Create an Empty Activity
This is the actual place we are going to launch the camera for the scanning task. This process should not be necessary if you have an activity available already. Since it is a place where a camera will be launched, i prefer the activity to always be on portrait, so for my case i would head to manifest and do the following adjustments.
<activity android:name=".TheActivityNameYouJustCreated"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.NoActionBar" /> Again, the step is not really something necessary. So if it does not make so much sense for now, you go ahead and skip to the next step.
On the Activity you just created
So, on the activity you created, there is this one place where your class inherits from AppCompatActivity. On that very spot, you replace the character sequence with ScanActivity( ). Literary, your class should now be extending to ScanActivity and not AppCompatActivity anymore.
class WhateverYouNamedYourActivity: ScanActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.app_scan_activity_layout) addFragmentContentLayout() //this is the most crucial part } override fun onError(error: DocumentScannerErrorModel) { } override fun onSuccess(scannerResults: ScannerResults) { } override fun onClose() { finish() }
You need to have something similar to that to be on the safer side of android studio (I hate the red lines on the logs down the studio).
Quickly, let us go through what you have been looking at. There is this one thing i labelled as the most crucial one, well, that's the one thing that brings the scanning camera int action.
But wait, we are launching the camera and we even did not bother to ask the permission to do that in the code. It's pretty weird that the code would have worked even though you did not notice that anyway. The library does that for us somewhere deep in the code you don't openly see, but it's in there (trust the system). Just try not to make the trust a perfect 100 percent, coz the SDK versions keep changing so rapidly and the android supports too. I would not say the same thing for the library. One solid example i encountered recently is that the WRITE_EXTERNAL_STORAGE permission does not offer the rights we are used to in the past, meaning that you gotta go an extra mile if you are targeting android 12 or later. Sometimes these libraries don't get updated very often, so you have to be ready to do shit yourself in case it comes to it.
Having said all that, i as well have written a couple of articles regarding asking the run time permissions, you can check one here. This one is about asking READ_EXTERNAL_STORAGE, but it applies the same for writing external storage. All you have gotta do is replace READ with WRITE.
How do we pick the results
Thanks to the library, the scanned result is openly provided in the onSuccess method. It returns some kind of file? type of data, so you be careful if you are loading this image on an ImageView because the process was not that easy for me. I struggled for a couple of minute (with the error infos i hate). Then i realized that i had to convert the file? into a Bitmap using BitmapFactory.decodefile.
No one likes errors, (especially me 😂), but Hey, what does not kill you only makes you stronger. Guess what am trying to say is that, most errors you meet don't necessarily insult your capacity. Bad shit happens, we just have to face them and move up. onError method is so pleasured to present you with a wide of errors at your exposal
- TAKE_IMAGE_FROM_GALLERY_ERROR
- PHOTO_CAPTURE_FAILED
- CAMERA_USE_CASE_BINDING_FAILED
- DETECT_LARGEST_QUADRILATERAL_FAILED
- INVALID_IMAGE
- CAMERA_PERMISSION_REFUSED_WITHOUT_NEVER_ASK_AGAIN
- CAMERA_PERMISSION_REFUSED_GO_TO_SETTINGS
- STORAGE_PERMISSION_REFUSED_WITHOUT_NEVER_ASK_AGAIN
- STORAGE_PERMISSION_REFUSED_GO_TO_SETTINGS
- CROPPING_FAILED
You might want to save the scanned image to your device, in the shared storage, that's cool, i will have to write an article about that. So there is this one fancy way i normally save an image with, where i use a Bottom Sheet Dialog to ask for the confirmation of saving an image from the user. You can learn to implement this here
Thanks for having me.
#Sam
0 Comments