B4A Library [class] DocumentScanner based on Google ML Kit

This class allows using ML Kit to scan documents: https://developers.google.com/ml-kit/vision/doc-scanner

1713362813439.png


It requires some configuration:

1. Main module:
B4X:
#AdditionalJar: com.google.android.gms:play-services-mlkit-document-scanner
#AdditionalJar: kotlin-stdlib-1.6.10
#AdditionalJar: androidx.arch.core:core-runtime
2. Manifest editor:
B4X:
CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase) 'add if not already there
'*********  ML kit **********
AddApplicationText(
 <activity
            android:name="com.google.mlkit.vision.documentscanner.internal.GmsDocumentScanningDelegateActivity"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
             >
        </activity>
         <provider
            android:name="com.google.mlkit.common.internal.MlKitInitProvider"
            android:authorities="${applicationId}.mlkitinitprovider"
            android:exported="false"
            android:initOrder="99" />

        <service
            android:name="com.google.mlkit.common.internal.MlKitComponentDiscoveryService"
            android:directBootAware="true"
            android:exported="false"
             >
            <meta-data
                android:name="com.google.firebase.components:com.google.mlkit.common.internal.CommonComponentRegistrar"
                android:value="com.google.firebase.components.ComponentRegistrar" />
        </service>
)
'******************************

Usage is simple. You call scan, the scanning UI appears, after the user scans you get a list of image uris that are loaded using the special "ContentDir" virtual folder.
See the attached example. The class is inside.
This is a B4A only class.

Updates

- v1.01 - New option to generate a PDF document. The Scan method now accepts a single boolean parameter. If true then a PDF document will be created, as well as the jpeg images. See the updated example.
 

Attachments

  • DocumentScanner.zip
    16.8 KB · Views: 92
Last edited:

fredo

Well-Known Member
Licensed User
Longtime User
This seems very useful.

However, I encounter an error during compilation:

B4X:
Organizing libraries.
Error Maven artifact not found:
com.google.mlkit/common Source: com.google.android.gms:play-services-mlkit-document-scanner
The artifact was installed via the SDK Manager and the IDE was restarted afterwards.
18-04-2024_16-14-02.png

Also, the `kotlin-stdlib-1.6.10` was not found in the SDK Manager.

What would be the next logical step on my part?
 

ThePlankton

Member
Licensed User
This seems very useful.

However, I encounter an error during compilation:

B4X:
Organizing libraries.
Error Maven artifact not found:
com.google.mlkit/common Source: com.google.android.gms:play-services-mlkit-document-scanner
The artifact was installed via the SDK Manager and the IDE was restarted afterwards.
View attachment 152810

Also, the `kotlin-stdlib-1.6.10` was not found in the SDK Manager.

What would be the next logical step on my part?
Were you able to solve this? I'm having the same issue (Error Maven artifact not found)
 

benyamin

Member
In the main sample of Google, the images can be saved in PDF format. What should we do to be able to save them in this format?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
How can I save or share the created image?
You can use bmp.WriteToStream or File.Copy("ContentDir", uri, ...)
Share file: https://www.b4x.com/android/forum/threads/class-fileprovider-share-files.97865/#content

And to create a pdf document:
1. Change the Scan method to:
B4X:
Public Sub Scan As ResumableSub
    Dim options As JavaObject
    options.InitializeNewInstance("com/google/mlkit/vision/documentscanner/GmsDocumentScannerOptions$Builder".Replace("/", "."), Null)
    options.RunMethod("setResultFormats", Array(102, Array As Int()))
    options = options.RunMethod("build", Null)
    Dim scanner As JavaObject
    scanner = scanner.InitializeStatic("com/google/mlkit/vision/documentscanner/GmsDocumentScanning".Replace("/", ".")).RunMethod("getClient", Array(options))
    Dim ctxt As JavaObject
    ctxt.InitializeContext
    Dim IntentSender As Object = scanner.RunMethodJO("getStartScanIntent", Array(ctxt)).RunMethod("getResult", Null)
    Me.as(JavaObject).RunMethod("sendIntentSenderForResult", Array(ctxt, IntentSender))
    Wait For Result_Arrived(Intent1 As Object)
    Dim ScanResult As DocumentScanResult
    ScanResult.Initialize
    ScanResult.ImageUris.Initialize
    If Intent1 = Null Then
        ScanResult.Success = False
    Else
        ScanResult.Success = True
        Dim Result As JavaObject
        Result = Result.InitializeStatic("com/google/mlkit/vision/documentscanner/GmsDocumentScanningResult".Replace("/", ".")).RunMethod("fromActivityResultIntent", Array(Intent1))
        Dim pdf As JavaObject = Result.RunMethod("getPdf", Null)
        ScanResult.ImageUris.Add(pdf.RunMethodJO("getUri", Null).RunMethod("toString", Null))
    End If
    Return ScanResult
End Sub

Usage example (make sure to add FileProvider manifest snippet):
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private scanner As DocumentScanner
    Private CustomListView1 As CustomListView
    Private Provider As FileProvider
End Sub

Public Sub Initialize
'    B4XPages.GetManager.LogEvents = True
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    scanner.Initialize(Me, "Scanner")
    Provider.Initialize
End Sub

Private Sub btnScan_Click
    CustomListView1.Clear
    Wait For (scanner.Scan) Complete (Result As DocumentScanResult)
    If Result.Success Then
        Dim PdfUri As String = Result.ImageUris.Get(0)
        File.Copy("ContentDir", PdfUri, Provider.SharedFolder, "file.pdf")
        'open the pdf with an external pdf viewer:
        Dim in As Intent
        in.Initialize(in.ACTION_VIEW, "")
        Provider.SetFileUriAsIntentData(in, "file.pdf")
        in.SetType("application/pdf")
        StartActivity(in)
    End If
End Sub
 

benyamin

Member
You can use bmp.WriteToStream or File.Copy("ContentDir", uri, ...)
Share file: https://www.b4x.com/android/forum/threads/class-fileprovider-share-files.97865/#content

And to create a pdf document:
1. Change the Scan method to:
B4X:
Public Sub Scan As ResumableSub
    Dim options As JavaObject
    options.InitializeNewInstance("com/google/mlkit/vision/documentscanner/GmsDocumentScannerOptions$Builder".Replace("/", "."), Null)
    options.RunMethod("setResultFormats", Array(102, Array As Int()))
    options = options.RunMethod("build", Null)
    Dim scanner As JavaObject
    scanner = scanner.InitializeStatic("com/google/mlkit/vision/documentscanner/GmsDocumentScanning".Replace("/", ".")).RunMethod("getClient", Array(options))
    Dim ctxt As JavaObject
    ctxt.InitializeContext
    Dim IntentSender As Object = scanner.RunMethodJO("getStartScanIntent", Array(ctxt)).RunMethod("getResult", Null)
    Me.as(JavaObject).RunMethod("sendIntentSenderForResult", Array(ctxt, IntentSender))
    Wait For Result_Arrived(Intent1 As Object)
    Dim ScanResult As DocumentScanResult
    ScanResult.Initialize
    ScanResult.ImageUris.Initialize
    If Intent1 = Null Then
        ScanResult.Success = False
    Else
        ScanResult.Success = True
        Dim Result As JavaObject
        Result = Result.InitializeStatic("com/google/mlkit/vision/documentscanner/GmsDocumentScanningResult".Replace("/", ".")).RunMethod("fromActivityResultIntent", Array(Intent1))
        Dim pdf As JavaObject = Result.RunMethod("getPdf", Null)
        ScanResult.ImageUris.Add(pdf.RunMethodJO("getUri", Null).RunMethod("toString", Null))
    End If
    Return ScanResult
End Sub

Usage example (make sure to add FileProvider manifest snippet):
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private scanner As DocumentScanner
    Private CustomListView1 As CustomListView
    Private Provider As FileProvider
End Sub

Public Sub Initialize
'    B4XPages.GetManager.LogEvents = True
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    scanner.Initialize(Me, "Scanner")
    Provider.Initialize
End Sub

Private Sub btnScan_Click
    CustomListView1.Clear
    Wait For (scanner.Scan) Complete (Result As DocumentScanResult)
    If Result.Success Then
        Dim PdfUri As String = Result.ImageUris.Get(0)
        File.Copy("ContentDir", PdfUri, Provider.SharedFolder, "file.pdf")
        'open the pdf with an external pdf viewer:
        Dim in As Intent
        in.Initialize(in.ACTION_VIEW, "")
        Provider.SetFileUriAsIntentData(in, "file.pdf")
        in.SetType("application/pdf")
        StartActivity(in)
    End If
End Sub
How to get both formats together so that the user can choose which format to save the file?
 

benyamin

Member
A problem it has is that when we select several files, it saves them all in one PDF, but if we want to receive the files in JPEG format, an address is given for each file, can't this problem be fixed?
- v1.01 - New option to generate a PDF document. The Scan method now accepts a single boolean parameter. If true then a PDF document will be created, as well as the jpeg images. See the updated example.
 
Top