OCR Reason Codes in pdf‑inspector: suspected_garbled_text, scanned, no_text, vector_text Explained

The pdf-inspector library uses four OCR reason codes—suspected_garbled_text, scanned, no_text, and vector_text—to explain why a PDF page requires optical character recognition rather than native text extraction.

These codes originate from the Rust core library and surface through language bindings to help developers diagnose PDF content issues programmatically. This article breaks down each code's meaning, detection logic, and where to find the implementation in the source code.


Where OCR Reason Codes Are Defined

The four reason codes are declared as public string constants in src/lib.rs, which serves as the entry point for the pdf-inspector crate. These constants ensure consistent naming across the Rust core, Python bindings, and any future language wrappers.

Constant Value Typical Location in Source
OCR_REASON_SUSPECTED_GARBLED_TEXT "suspected_garbled_text" src/lib.rs (constant definition)
OCR_REASON_SCANNED "scanned" src/lib.rs (constant definition)
OCR_REASON_NO_TEXT "no_text" src/lib.rs (constant definition)
OCR_REASON_VECTOR_TEXT "vector_text" src/lib.rs (constant definition)

The library exposes these through the ocr_reasons_by_page API, which returns a mapping of page numbers to lists of applicable reasons.


suspected_garbled_text: Low-Quality Text Layer Detection

The suspected_garbled_text reason triggers when the library detects a text layer that exists but appears corrupted or incorrectly encoded.

Detection logic: The src/text_quality.rs module analyzes character frequency distributions and cosine-similarity metrics against expected language patterns. When extracted text contains excessive non-printable characters, mismapped Unicode glyphs, or statistically improbable character sequences, the module flags the page.

Common causes:

  • PDFs where font encoding tables are broken or missing
  • Documents with subsetted fonts that reference incorrect glyph IDs
  • Files processed through low-quality OCR engines that produced malformed text layers

Example Python output:

{
    2: ["suspected_garbled_text"],
    7: ["suspected_garbled_text", "vector_text"]
}

scanned: Image-Only Page Identification

The scanned reason indicates a page containing only raster image content with no extractable text layer.

Detection logic: The src/detector.rs module examines page content streams. When a page consists solely of bitmap XObjects (typically JPEG, PNG, or TIFF embedded images) without accompanying text operators, the detector classifies it as scanned.

This is the most straightforward OCR trigger—physical documents converted to PDF through scanning hardware or mobile capture apps typically produce these pages.

Key distinction from no_text: A scanned page has image content available for OCR, whereas no_text pages lack both text and image data.


no_text: Empty Page Fallback

The no_text reason applies when a page contains neither detectable text nor recognizable image content.

Detection logic: The OCR fallback pipeline in src/lib.rs activates after both text extraction and image detection return empty results. This occurs for:

  • Truly blank pages
  • Pages with only vector graphics (charts, diagrams without labels)
  • Corrupted content streams that fail to parse

Unlike scanned, pages with this reason may not benefit from OCR at all—there is simply nothing to recognize.


vector_text: Outline-Based Text Detection

The vector_text reason identifies pages where text appears as vector path outlines rather than standard text glyphs.

Detection logic: The content stream parser in src/lib.rs (and supporting modules) distinguishes between text-show operators (Tj, TJ) and path construction operators (m, l, c, re) that form character shapes. When character-like paths are detected without corresponding text operators, the page receives this classification.

Why this matters: Vectorized text is visually readable but not searchable or selectable. This commonly occurs when:

  • Scanned documents are processed through "PDF vectorization" tools that trace bitmaps into curves
  • Designers convert text to outlines for font embedding compatibility
  • CAD or illustration software exports drawings with text as geometry

Pages flagged with vector_text often appear alongside suspected_garbled_text when vectorization produces distorted or incomplete character shapes.


Accessing OCR Reasons in Code

The Python bindings expose OCR reasons through the ocr_reasons_by_page return value. Here's a minimal working example:

from pdf_inspector import inspect_pdf

result = inspect_pdf("document.pdf")

# Check which pages need OCR and why

for page_num, reasons in result["ocr_reasons_by_page"].items():
    print(f"Page {page_num}: requires OCR due to {reasons}")

The underlying Rust function populates this map by aggregating flags from src/text_quality.rs, src/detector.rs, and the core processing pipeline defined in src/lib.rs.


File Reference Guide

File Purpose
src/lib.rs Defines OCR reason constants and orchestrates the inspection pipeline
src/text_quality.rs Implements statistical text quality analysis for suspected_garbled_text
src/detector.rs Handles page content type detection for scanned classification
src/python.rs Marshals Rust data structures into Python-compatible dictionaries
tests/integration_tests.rs Contains fixtures verifying each OCR reason triggers appropriately

Summary

  • suspected_garbled_text — Text layer exists but appears corrupted or misencoded; detected via statistical quality metrics in src/text_quality.rs
  • scanned — Page contains only raster images, no text layer; identified by src/detector.rs
  • no_text — Page has neither text nor image content; fallback classification when all detection pipelines return empty
  • vector_text — Text rendered as vector outlines rather than glyphs; detected through content stream operator analysis

These codes enable precise diagnostics for PDF processing workflows, letting developers route documents appropriately—whether that means invoking OCR, flagging quality issues, or skipping unrecognizable pages entirely.


Frequently Asked Questions

How do I suppress certain OCR reason codes from triggering processing?

The pdf-inspector library does not currently expose a filter API for specific reason codes. You can post-process the ocr_reasons_by_page result to ignore codes that don't match your workflow requirements before deciding whether to invoke OCR.

Can a single page have multiple OCR reason codes?

Yes. The ocr_reasons_by_page structure returns a list of reasons per page. A page with vectorized text that also fails quality checks might return ["suspected_garbled_text", "vector_text"] simultaneously.

What's the difference between scanned and vector_text?

scanned indicates raster image content—pixels that require OCR to extract text. vector_text indicates text rendered as mathematical paths—curves and lines that appear as text visually but lack searchable character data. The former needs bitmap OCR; the latter may need vector-to-text conversion or specialized handling.

Which OCR reason is most common in enterprise document pipelines?

Based on typical document distributions, scanned appears most frequently due to the prevalence of legacy scanned documents and mobile capture workflows. However, suspected_garbled_text is increasingly common with PDFs from mixed-generation sources where automated conversion tools produce malformed text layers.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →