Scan from a static image
For image file or gallery upload flows, use the SDK without the camera UI. This lets you feed images into the scanning engine one at a time.
Initialize and create a session
Initialize the SDK and create a session configured for photo input. Setting the input image source to photo tells the engine to expect static images rather than a video stream.
- Web (TS)
- Android (Kotlin)
- iOS (Swift)
- Flutter (Dart)
- React Native (TS)
import { loadBlinkIdCore } from "@microblink/blinkid-core";
const blinkIdCore = await loadBlinkIdCore({
licenseKey: "your-license-key",
});
const session = await blinkIdCore.createBlinkIdScanningSession({
inputImageSource: "photo",
});
val sdk = BlinkIdSdk.initializeSdk(
context,
BlinkIdSdkSettings(licenseKey = "your-license-key")
).getOrThrow()
val session = sdk.createScanningSession(
BlinkIdSessionSettings(inputImageSource = InputImageSource.Photo)
).getOrThrow()
let sdk = try await BlinkIDSdk.createBlinkIDSdk(
withSettings: BlinkIDSdkSettings(licenseKey: "your-license-key")
)
let session = try await sdk.createScanningSession(
sessionSettings: BlinkIDSessionSettings(inputImageSource: .photo)
)
Flutter scans static images through DirectAPI.
Configure the SDK and session settings up front, then pass them to performDirectApiScan along with the image data.
import 'package:blinkid_flutter/blinkid_flutter.dart';
import 'package:flutter/services.dart';
final blinkIdPlugin = BlinkIdFlutter();
final sdkSettings = BlinkIdSdkSettings(licenseKey: "your-license-key");
sdkSettings.downloadResources = true;
final sessionSettings = BlinkIdSessionSettings(
scanningMode: ScanningMode.automatic,
scanningSettings: BlinkIdScanningSettings(
documentCaptureModule: DocumentCaptureModuleSettings(documentImageReturnEnabled: true),
mrzModule: MrzModuleSettings(),
barcodeModule: BarcodeModuleSettings(),
vizModule: VizModuleSettings(),
),
);
React Native scans static images through DirectAPI.
Prepare the SDK and session settings up front, then pass them to performDirectApiScan along with the image data.
import { performDirectApiScan } from "@microblink/blinkid-react-native";
const sdkSettings = {
licenseKey: "your-license-key",
downloadResources: true,
};
const sessionSettings = {
scanningMode: "automatic",
scanningSettings: {
documentCaptureModule: { documentImageReturnEnabled: true, inputImageCropped: false },
mrzModule: {},
barcodeModule: { pdf417ScanningEnabled: true, qrScanningEnabled: true },
vizModule: {},
},
};
Load an image for scanning
Each platform requires converting a raw image into the format the scanning engine expects.
- Web (TS)
- Android (Kotlin)
- iOS (Swift)
- Flutter (Dart)
- React Native (TS)
The scanning engine accepts ImageData objects.
Use an offscreen canvas to decode a File or Blob into the required format.
async function fileToImageData(file: File): Promise<ImageData> {
const img = new Image();
const url = URL.createObjectURL(file);
img.src = url;
try {
await new Promise<void>((resolve) => {
img.onload = () => resolve();
});
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Could not get canvas context");
ctx.drawImage(img, 0, 0);
return ctx.getImageData(0, 0, canvas.width, canvas.height);
} finally {
URL.revokeObjectURL(url);
}
}
The scanning engine requires an ARGB_8888 bitmap wrapped in an InputImage.
val bitmap = BitmapFactory.decodeFile(imagePath)
?.copy(Bitmap.Config.ARGB_8888, false)
?: return
val inputImage = InputImage.createFromBitmap(bitmap)
Wrap a UIImage in an InputImage to pass it to the scanning engine.
let inputImage = InputImage(uiImage: uiImage)
DirectAPI accepts Base64-encoded image strings. Read the image files from disk or gallery and encode them.
import 'dart:convert';
import 'dart:io';
final frontImageBase64 = base64Encode(await File(frontImagePath).readAsBytes());
final backImageBase64 = base64Encode(await File(backImagePath).readAsBytes());
DirectAPI accepts Base64-encoded image strings.
Read the image files from disk or gallery and encode them, for example with react-native-fs.
import RNFS from "react-native-fs";
const firstImageBase64 = await RNFS.readFile(frontImagePath, "base64");
const secondImageBase64 = await RNFS.readFile(backImagePath, "base64");
Process images and get the result
Pass each image to the session and check the processing status after each call.
A status of awaiting-other-side means the engine needs the document's other side before it can return a final result.
When the status is success, retrieve the final result.
- Web (TS)
- Android (Kotlin)
- iOS (Swift)
- Flutter (Dart)
- React Native (TS)
// Process the front side
const frontImageData = await fileToImageData(frontFile);
const frontProcessResult = await session.process(frontImageData);
const status = frontProcessResult.inputImageAnalysisResult.processingStatus;
if (status === "awaiting-other-side") {
// The document has a back side — process it too
const backImageData = await fileToImageData(backFile);
await session.process(backImageData);
}
// Retrieve the final result
const result = await session.getResult();
console.log("First name:", result.firstName?.latin?.value);
console.log("Document number:", result.documentNumber?.latin?.value);
console.log("Date of expiry:", result.dateOfExpiry?.originalString?.latin?.value);
// Process the front side
val frontBitmap = BitmapFactory.decodeFile(frontImagePath)
?.copy(Bitmap.Config.ARGB_8888, false) ?: return
val frontProcessResult = session.process(
InputImage.createFromBitmap(frontBitmap)
).getOrThrow()
if (frontProcessResult.inputImageAnalysisResult.processingStatus
== ProcessingStatus.AwaitingOtherSide) {
// The document has a back side — process it too
val backBitmap = BitmapFactory.decodeFile(backImagePath)
?.copy(Bitmap.Config.ARGB_8888, false) ?: return
session.process(InputImage.createFromBitmap(backBitmap)).getOrThrow()
}
// Retrieve the final result
val result = session.getResult().getOrNull()
println("First name: ${result?.firstName?.value}")
println("Document number: ${result?.documentNumber?.value}")
// Process the front side
let frontFrameResult = try await session.process(inputImage: InputImage(uiImage: frontImage))
if frontFrameResult.processResult?.inputImageAnalysisResult.processingStatus
== .awaitingOtherSide {
// The document has a back side — process it too
try await session.process(inputImage: InputImage(uiImage: backImage))
}
// Retrieve the final result
let result = session.getResult()
print("First name:", result?.firstName?.value ?? "")
print("Document number:", result?.documentNumber?.value ?? "")
Pass both images to performDirectApiScan.
Provide secondImage only when the document has a back side; for a single-sided document, omit it and use ScanningMode.single.
try {
final result = await blinkIdPlugin.performDirectApiScan(
blinkIdSdkSettings: sdkSettings,
blinkIdSessionSettings: sessionSettings,
firstImage: frontImageBase64,
secondImage: backImageBase64, // optional; omit for single-side
);
if (result != null) {
print("First name: ${result.firstName?.value}");
print("Document number: ${result.documentNumber?.value}");
}
} on PlatformException catch (e) {
print(e.message);
}
Pass both images to performDirectApiScan.
Provide secondImage only when the document has a back side; for a single-sided document, omit it and set scanningMode to "single".
try {
const result = await performDirectApiScan({
sdkSettings,
sessionSettings,
firstImage: firstImageBase64,
secondImage: secondImageBase64, // optional; omit for single-side
});
console.log("First name:", result.firstName?.value);
console.log("Full name:", result.fullName?.value);
} catch (error) {
console.error(error);
}
Clean up
Release the session when done to free scanning resources. On Android and iOS, closing or releasing the session is sufficient. On web, also terminate the core instance.
- Web (TS)
- Android (Kotlin)
- iOS (Swift)
- Flutter (Dart)
- React Native (TS)
await session.delete();
await blinkIdCore.terminate();
session.close()
No explicit cleanup is needed. The session releases its resources automatically when it goes out of scope.
No explicit cleanup is needed.
DirectAPI manages the scanning resources for the duration of the performDirectApiScan call.
No explicit cleanup is needed.
DirectAPI manages the scanning resources for the duration of the performDirectApiScan call.