Workflow Guide Pixelnetica™ Document Scanning SDK for Android

This guide walks through the standard workflow for processing a document photo with the Pixelnetica Document Scanning SDK (DSSDK): open an image, detect the document in it, correct its orientation, refine it, recognize its text, and save the result as a searchable PDF. The pipeline needs no camera of its own — the input is any image URI, whether it came from the Smart Camera, the system photo picker, or a file. Each step is a short snippet you can adapt; the sample application source code shows the same pipeline in a complete application.

Every stage links to its step below. Steps 2 and 4 are optional — skip orientation detection or recognition if your application does not need them — and the Release the Page section closes the loop on the native memory the pipeline holds.

Step 1: Open an Image and Detect Document Bounds

Prerequisites: An imageUri obtained from the Image Picker, Gallery, or other local storage sources.

// Create and configure ScanPicture
val picture = ScanPicture(context, imageUri)
picture.shadows = true   // Even out shadows and uneven lighting

// Detect document corners
val cutout = picture.detectCutout()
if (!cutout.isDefined) {
  // In cases where document borders cannot be determined,
  // consider displaying a warning to the user.
}

A ScanPicture holds its image in native memory, outside the Java heap — and so does the cutout it just returned. You can release that memory the moment you are done by calling close(); because this guide keeps both objects across several steps, it closes them together in the last step. The other native-handle objects the guide creates, the detector and the reader, live inside a single step each, so they are scoped with use { } and released as soon as their step completes. The native memory guide explains the contract in full.

Step 2: Automatically Detect Picture Orientation

Prerequisites: A language directory path (languagesDir) as described in the Setup OCR Languages section.

// The detector holds native memory: use { } releases it
// as soon as orientation detection is done
ScanDetector(languagesDir).use { orientationDetector ->
    picture.detectOrientation(orientationDetector)
}

Step 3: Process the Image

Execute the refine pipeline to crop the page to its detected outline, apply the desired colour profile, and rotate it upright for display. Pass a list holding at most one RefineFeature of each kind; kinds you leave out stay unchanged. The colour profiles guide shows what each profile is for and how the results look.

picture.refine(
  listOf(
    RefineFeature.Rectify.WithCutout(cutout),  // Crop and straighten to the detected outline
    RefineFeature.Profile(RefineFeature.Profile.Type.Bitonal),  // Black-and-white (bitonal) processing
    RefineFeature.Display.Normal,  // Rotate the page upright for display
  )
)

// Obtain the processed image
val bitmap: Bitmap = picture.createBitmap()

When no document outline is available, pass RefineFeature.Rectify.SkipCutout to leave the page uncropped, or RefineFeature.Rectify.AutoDetect to let the SDK find the corners without asking the user.

Step 4: Recognize Text in the Image

Prerequisites: A language directory path (languagesDir) and a list of languages (languageNames), as described in the Setup OCR Languages section.

// The reader holds native memory too: use { } releases it after recognition
ScanReader(languagesDir, languageNames).use { scanReader ->
    picture.read(scanReader)
}

// Retrieve the recognized text
val text: String = picture.scanText.toString()

Pass the picture at full resolution — no caller-side resize is needed. The SDK manages memory for the recognition step internally, and recognized text positions are reported in the original image’s coordinates. If a device does run out of memory, read() fails with a catchable ScanningSdkException instead of crashing, and the reader stays usable for the next page.

Step 5: Save Results as a Searchable PDF

Prerequisites:

  • picture from the Process the Image section.
  • TrueType font files supporting the necessary languages.
  1. Define a list, e.g., fontList, containing the font files.
  2. Set the desired image compression using predefined values:

    val imageCompression = ImageWriterPdf.ImageCompression.Medium
    

    Alternatively, specify the image compression ratio manually:

    val imageCompression = ImageWriterPdf.ImageCompression(60.0F)
    

DSSDK provides five compression presets for images in PDFs: Lossless, Low, Medium, High, and Extreme.

Note: Compression levels apply only to color and grayscale images. Black-and-white (bitonal) images always use highly efficient lossless compression.

// Obtain an ImageWriterPdf instance
ImageWriterPdf(fileName).use { writer ->
   writer.setFontFiles(fontList)
   writer.setImageCompression(imageCompression)
   writer.write(picture)
}

Release the Page

When the page’s work is finished, release the native memory of both objects the guide kept — the cutout from step 1 and the page itself:

cutout.close()
picture.close()

Closing is optional — if you skip it, the garbage collector releases the memory eventually, and existing code keeps working unchanged. It matters in loops: an application that scans or recognizes many pages in a row keeps its native memory flat by closing each page as it finishes, instead of accumulating pages until the collector runs. close() is safe to call twice, and an operation that needs a closed page’s native state throws a catchable ScanningSdkException. The native memory guide covers the details.

Performance Notes

Numbers measured with release builds on a mid-range reference phone, so you can set expectations before profiling your own integration:

  • Document detection takes about 43 ms.
  • Refining a page costs 161–220 ms per colour profile.
  • Recognizing a full-resolution page takes about 55 seconds and peaks at about 57 MB of native memory.
  • PDF export is the memory-hungriest step, peaking at about 113 MB.

Debug builds are several times slower than these figures — profile with a release build before drawing conclusions.

Top