delphi-docscanner
Google ML Kit Document Scanner for Delphi/FMX Android — JPEG & PDF output, one unit, zero UI code
- Active · last change 5-13-2026
- ★ 17 on GitHub
README
delphi-docscanner
A production-ready Delphi/FMX JNI bridge for Google ML Kit Document Scanner on Android. Scan documents with automatic edge detection, perspective correction, and cropping — output as JPEG or multi-page PDF.
One unit. One singleton call. Zero UI code.
Features
- Automatic document detection and edge recognition
- Perspective correction and cropping
- JPEG output (per page) and PDF output (multi-page)
- Gallery import support
- ML Kit availability check (
IsMLKitAvailable) - Re-entrancy protection (
IsScanning) - Configurable output directory (
OutputSubDir)
Requirements
- RAD Studio 12 Athens or later
- Target platform: Android 32-bit or 64-bit
- Minimum Android API: 21 (Android 5.0)
- Google Play Services on the target device
Installation
1. Download the dependencies
The scanner requires two Android libraries. They are published as .aar files on
Google's Maven repository (not Maven Central — com.google.android.gms:*
artifacts are only hosted by Google):
| Dependency | Version | Direct download (.aar) |
|---|---|---|
| play-services-mlkit-document-scanner | 16.0.0 | dl.google.com |
mlkit-common (com.google.mlkit:common) |
18.11.0 | dl.google.com |
RAD Studio's Java references only accepts .jar files, so extract the
classes.jar from inside each .aar (an .aar is a ZIP archive), rename it
(e.g. play-services-mlkit-document-scanner-16.0.0.jar) and put it in your
project's lib\ folder.
Alternative: Download via Gradle
Create a build.gradle in your lib\ folder — this resolves all transitive
dependencies automatically:
plugins { id 'java' }
repositories {
google()
mavenCentral()
}
configurations { mlkit }
dependencies {
mlkit 'com.google.android.gms:play-services-mlkit-document-scanner:16.0.0'
}
task copyDeps(type: Copy) {
from configurations.mlkit
into "$projectDir/deps"
}Run: gradle copyDeps
2. Add the JARs to your Delphi project
In RAD Studio:
- Project > Options > Delphi Compiler > Other > Java references
- Add both
.jarfiles (theclasses.jarextracted from each.aar) - Set Container to
Classes.dex
3. Add Search Path
Add the path to Source\ to your Delphi project search path:
Project > Options > Delphi Compiler > Search path:
<path-to>\delphi-docscanner\Source4. AndroidManifest.template.xml
Add the following entries inside the <application> tag of your AndroidManifest.template.xml:
<!-- Google ML Kit Document Scanner -->
<service
android:name="com.google.mlkit.common.internal.MlKitComponentDiscoveryService"
android:exported="false"
android:directBootAware="true">
<meta-data
android:name="com.google.firebase.components:com.google.mlkit.common.internal.CommonComponentRegistrar"
android:value="com.google.firebase.components.ComponentRegistrar" />
</service>
<activity
android:name="com.google.mlkit.vision.documentscanner.internal.GmsDocumentScanningDelegateActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" />Important: These entries must be placed inside
<application>...</application>, not at the root level. Without them, the scanner will fail silently at runtime.
Quick Start
uses
mxDocScannerUnit;
procedure TForm1.btnScanClick(Sender: TObject);
begin
if not TmxDocScanner.Instance.IsMLKitAvailable then
begin
ShowMessage('ML Kit Document Scanner not available on this device.');
Exit;
end;
TmxDocScanner.Instance.StartScan(
5, // max pages
True, // allow gallery import
dsfJPEG, // output format: dsfJPEG or dsfPDF
procedure(const AFilePath: string; APageIndex, ATotalPages: Integer)
begin
// Called once per page (JPEG) or once (PDF)
ShowMessage('Page ' + IntToStr(APageIndex + 1) + ': ' + AFilePath);
end,
procedure(const AErrorMessage: string)
begin
ShowMessage('Error: ' + AErrorMessage);
end
);
end;Custom output directory
Scanned files are saved to <SharedPictures>/<OutputSubDir>/. The default subdirectory is mxDocScanner. To change it:
TmxDocScanner.Instance.OutputSubDir := 'MyApp';Set this before calling StartScan.
API Reference
TmxDocScanner
| Member | Description |
|---|---|
class function Instance: TmxDocScanner |
Singleton access |
class procedure ReleaseInstance |
Free the singleton (typically not needed) |
function IsMLKitAvailable: Boolean |
Check if ML Kit Document Scanner is available on the device |
procedure StartScan(...) |
Start a document scan |
property IsScanning: Boolean |
True while a scan is in progress |
property OutputSubDir: string |
Subdirectory name for scanned files (default: 'mxDocScanner') |
StartScan parameters
| Parameter | Type | Description |
|---|---|---|
AMaxPages |
Integer |
Maximum number of pages to scan |
AGalleryImport |
Boolean |
Allow importing images from gallery |
AFormat |
TDocScanFormat |
dsfJPEG for JPEG per page, dsfPDF for multi-page PDF |
AOnPageResult |
TDocScanPageCallback |
Called per scanned page with file path, page index, and total pages. In PDF mode, JPEG callbacks fire first (for preview), then one PDF callback. |
AOnError |
TDocScanErrorCallback |
Called on error or cancellation with message |
AMode |
TDocScanMode |
Scanner mode (optional, default: dsmFull) |
Types
TDocScanMode = (dsmBase, dsmBaseWithFilter, dsmFull);
TDocScanFormat = (dsfJPEG, dsfPDF);
TDocScanPageCallback = reference to procedure(
const AFilePath: string; APageIndex, ATotalPages: Integer);
TDocScanErrorCallback = reference to procedure(
const AErrorMessage: string);Scanner modes
| Mode | Description |
|---|---|
dsmBase |
Basic scanning (edge detection, cropping) |
dsmBaseWithFilter |
Basic scanning + image filters |
dsmFull |
Full features: edge detection, cropping, rotation, filters (default) |
PDF mode behavior
In PDF mode (dsfPDF), the scanner delivers both JPEG and PDF results:
AOnPageResultis called once per page with the JPEG file path (useful for preview)AOnPageResultis called once more with the PDF file path
This allows apps to show page previews while also receiving the final PDF for upload or storage.
Edge Cases
| Scenario | Behavior |
|---|---|
| Device without Google Play Services | IsMLKitAvailable returns False |
| User cancels scan | Error callback fires with 'Scan cancelled', IsScanning resets to False |
| PDF mode with 1 page | Produces a single-page PDF, JPEG preview callback fires first |
| Multiple concurrent scan calls | Blocked by IsScanning check, error callback fired |
| Non-Android platform | StartScan fires error callback: 'Document Scanner is only available on Android' |
Known Limitations
- Internal ML Kit API: The unit uses
com.google.mlkit.common.sdkinternal.MlKitContextfor manual initialization, which is an internal Google API. This is necessary because Delphi does not support Android ContentProvider-based auto-initialization. The class has been stable across ML Kit versions, but could change without notice in future SDK updates. - Google Play Services required: The scanner depends on Google Play Services. Devices without GMS (e.g., Huawei) are not supported. Use
IsMLKitAvailableto check at runtime. - Singleton pattern:
TmxDocScanneris designed for main-thread use. Do not callStartScanfrom background threads.
Cleanup
The singleton is automatically released in the finalization section. To release it manually:
TmxDocScanner.ReleaseInstance;License
MIT License — see LICENSE for details.
Copyright (c) 2026 MicrotronX - Speditionssoftware vom Profi

