---
Source: https://docs.microblink.com/blinkid/scan-image
Title: Scan from a static image
Description: Scan identity documents from image files or gallery uploads without a live camera feed
---

# 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.

<Tabs queryString="platform">

  <TabItem value="web" label="Web (TS)" default>

  ```typescript
  import { loadBlinkIdCore } from "@microblink/blinkid-core";

  const blinkIdCore = await loadBlinkIdCore({
    licenseKey: "your-license-key",
  });

  const session = await blinkIdCore.createBlinkIdScanningSession({
    inputImageSource: "photo",
  });
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  ```kotlin
  val sdk = BlinkIdSdk.initializeSdk(
      context,
      BlinkIdSdkSettings(licenseKey = "your-license-key")
  ).getOrThrow()

  val session = sdk.createScanningSession(
      BlinkIdSessionSettings(inputImageSource = InputImageSource.Photo)
  ).getOrThrow()
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  ```swift
  let sdk = try await BlinkIDSdk.createBlinkIDSdk(
      withSettings: BlinkIDSdkSettings(licenseKey: "your-license-key")
  )

  let session = try await sdk.createScanningSession(
      sessionSettings: BlinkIDSessionSettings(inputImageSource: .photo)
  )
  ```

  </TabItem>
</Tabs>

## Load an image for scanning

Each platform requires converting a raw image into the format the scanning engine expects.

<Tabs queryString="platform">

  <TabItem value="web" label="Web (TS)" default>

  The scanning engine accepts `ImageData` objects.
  Use an offscreen canvas to decode a `File` or `Blob` into the required format.

  ```typescript
  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);
    }
  }
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  The scanning engine requires an `ARGB_8888` bitmap wrapped in an `InputImage`.

  ```kotlin
  val bitmap = BitmapFactory.decodeFile(imagePath)
      ?.copy(Bitmap.Config.ARGB_8888, false)
      ?: return

  val inputImage = InputImage.createFromBitmap(bitmap)
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  Wrap a `UIImage` in an `InputImage` to pass it to the scanning engine.

  ```swift
  let inputImage = InputImage(uiImage: uiImage)
  ```

  </TabItem>
</Tabs>

## 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.

<Tabs queryString="platform">

  <TabItem value="web" label="Web (TS)" default>

  ```typescript
  // 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);
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  ```kotlin
  // 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}")
  ```

  </TabItem>
  <TabItem value="ios" label="iOS (Swift)">

  ```swift
  // 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 ?? "")
  ```

  </TabItem>
</Tabs>

## 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.

<Tabs queryString="platform">

  <TabItem value="web" label="Web (TS)" default>

  ```typescript
  await session.delete();
  await blinkIdCore.terminate();
  ```

  </TabItem>
  <TabItem value="android" label="Android (Kotlin)">

  ```kotlin
  session.close()
  ```

  </TabItem>
  

<!-- interactive component omitted -->


</Tabs>

## Related articles

- [How to scan in real time via camera](scan-camera.md)
- [How to scan a single-sided document](scan-single-side.md)
- [How to scan a double-sided document](scan-double-side.md)
- [How to extract specific fields](extract-fields.md)


Last updated on Jul 24, 2026
