Scan a card from a static image
For file upload or gallery flows, use the lower-level scanning session directly, without the camera UI. This lets you feed images into the scanning engine one at a time.
Initialize and create a session
Create a session with the input image source set to photo.
This tells the engine to expect static images rather than a video stream.
On Web, load the core engine with loadBlinkCardCore, then create the session.
On Android, initialize the SDK, then create the session.
On iOS, create the SDK, then create the session.
- Web (JS)
- Android (Kotlin)
- iOS (Swift)
import { loadBlinkCardCore } from "@microblink/blinkcard-core";
const blinkCardCore = await loadBlinkCardCore({
licenseKey: "your-license-key",
});
const session = await blinkCardCore.createScanningSession({
inputImageSource: "photo",
});
val sdk = BlinkCardSdk.initializeSdk(
context,
BlinkCardSdkSettings(licenseKey = "your-license-key")
).getOrThrow()
val session = sdk.createScanningSession(
BlinkCardSessionSettings(inputImageSource = InputImageSource.Photo)
)
let sdk = try await BlinkCardSdk.createBlinkCardSdk(
withSettings: BlinkCardSdkSettings(licenseKey: "your-license-key")
)
let session = try await sdk.createScanningSession(
sessionSettings: BlinkCardSessionSettings(inputImageSource: .photo)
)
For installation, license setup, and hosting the WASM resources, see the quickstart.
Load an image for scanning
Each platform wraps a decoded image in the format the scanning engine expects.
On Web, the engine accepts ImageData.
Use an offscreen canvas to decode a File or Blob into the required format.
On Android, build an InputImage from an ARGB_8888 Bitmap loaded from the gallery or a file.
On iOS, build an InputImage from a UIImage loaded from the photo library or a file.
- Web (JS)
- Android (Kotlin)
- iOS (Swift)
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);
}
}
val inputImage = InputImage.createFromBitmap(bitmap)
The bitmap must be in ARGB_8888 configuration.
let inputImage = InputImage(uiImage: image)
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 card's other side before it can return a final result.
When the card is fully scanned, retrieve the result with getResult.
- Web (JS)
- Android (Kotlin)
- iOS (Swift)
// Process the first side (the side with the card number)
const firstImageData = await fileToImageData(firstFile);
const firstProcessResult = session.process(firstImageData);
const status = firstProcessResult.inputImageAnalysisResult.processingStatus;
if (status === "awaiting-other-side") {
// The card has more data on the other side — process it too
const secondImageData = await fileToImageData(secondFile);
session.process(secondImageData);
}
// Retrieve the final result
const result = session.getResult();
console.log("Card number:", result.cardAccounts[0].cardNumber);
console.log("Expiry:", result.cardAccounts[0].expiryDate.originalString);
// Process the first side (the side with the card number)
val firstResult = session.process(
InputImage.createFromBitmap(firstBitmap)
).getOrThrow()
if (firstResult.inputImageAnalysisResult.processingStatus
== ProcessingStatus.AwaitingOtherSide) {
// The card has more data on the other side — process it too
session.process(InputImage.createFromBitmap(secondBitmap)).getOrThrow()
}
// Retrieve the final result
val result = session.getResult()
val account = result.cardAccounts[0]
println("Card number: ${account.cardNumber}")
println("Expiry: ${account.expiryDate?.originalString}")
// Process the first side (the side with the card number)
let firstResult = try await session.process(inputImage: InputImage(uiImage: firstImage))
if firstResult.processResult?.inputImageAnalysisResult.processingStatus == .awaitingOtherSide {
// The card has more data on the other side — process it too
try await session.process(inputImage: InputImage(uiImage: secondImage))
}
// Retrieve the final result
let result = session.getResult()
let account = result.cardAccounts[0]
print("Card number:", account.cardNumber)
print("Expiry:", account.expiryDate?.originalString ?? "")
Clean up
Release the session and SDK when done.
On Web, call session.delete(), then terminate the core instance.
On Android, close the session and the SDK to release native resources.
On iOS, the session releases its resources when it is deallocated; terminate the SDK when you are done with it.
- Web (JS)
- Android (Kotlin)
- iOS (Swift)
session.delete();
await blinkCardCore.terminate();
session.close()
sdk.close()
BlinkCardSdk.terminateBlinkCardSdk()