# How to Perform OCR on Specific Pages When pdf‑inspector Detects Them as Scanned

> Learn how to perform OCR on specific pages with pdf-inspector. Optimize your workflow by running OCR only on scanned pages, saving time and resources.

- Repository: [Firecrawl/pdf-inspector](https://github.com/firecrawl/pdf-inspector)
- Tags: how-to-guide
- Published: 2026-08-13

---

**pdf‑inspector analyzes PDF content streams in [`src/detector.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/detector.rs) and returns a `pages_needing_ocr` array containing exact 1‑based page numbers via the `PdfProcessResult` struct, allowing you to run external OCR engines like Tesseract only on pages that actually contain scanned images rather than selectable text.**

The firecrawl/pdf‑inspector repository provides a Rust‑based pipeline for classifying PDF documents as `TextBased`, `Scanned`, `ImageBased`, or `Mixed`. When processing documents classified as `Scanned` or `Mixed`, the library identifies exactly which pages require optical character recognition (OCR) through specific metadata fields, eliminating redundant processing of text‑based pages and optimizing your document digitization workflow.

## How pdf‑inspector Classifies and Flags Scanned Pages

### Detection Logic in src/detector.rs

In [`src/detector.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/detector.rs), the `detect_from_document` function scans each page’s content streams for the presence of text operators, image operators, and OCR‑layer markers (lines 250‑300). Pages that contain only raster images or have an invisible OCR text layer are marked with the reason `OCR_REASON_SCANNED` (string value `"scanned"`). This granular detection populates the final page list used downstream.

### The PdfProcessResult Structure

After detection completes, the core pipeline in [`src/lib.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/lib.rs) (lines 3912‑3930) constructs a `PdfProcessResult` struct that surfaces two critical fields:
- **`pages_needing_ocr`**: A `Vec<u32>` of 1‑based page numbers requiring OCR
- **`ocr_reasons_by_page`**: A HashMap explaining why each specific page was flagged

When the PDF type is `Scanned` or `ImageBased`, the extractor short‑circuits and returns only this OCR metadata without Markdown content (lines 3912‑3916), signaling that external processing is required.

## Retrieving the List of Pages Requiring OCR

### Rust API Implementation

Use `process_pdf_with_options` to obtain the result struct containing the flagged pages:

```rust
use pdf_inspector::{process_pdf_with_options, PdfOptions, PdfProcessResult};

let opts = PdfOptions::default();  // Optionally set page_filter here
let result: PdfProcessResult = process_pdf_with_options("document.pdf", opts).unwrap();

println!("PDF type: {:?}", result.pdf_type);
println!("Pages needing OCR: {:?}", result.pages_needing_ocr);
// Output example: [2, 5, 7]

```

### CLI with JSON Output

The `pdf2md` binary exposes the OCR metadata when you pass the `--json` flag (implementation in [`src/bin/pdf2md.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/bin/pdf2md.rs), lines 426‑433):

```bash
pdf2md --json input.pdf > report.json

# Extract the page list using jq

jq '.pages_needing_ocr' report.json

# Returns: [2, 5, 7]

```

### Python Bindings

The Python module exposes the same functionality through `process_pdf`, defined in [`src/python.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/python.rs) (lines 318‑340):

```python
import pdf_inspector

result = pdf_inspector.process_pdf("document.pdf")
print(result.pdf_type)             # "Scanned" or "Mixed"

print(result.pages_needing_ocr)    # [2, 5, 7]

```

## Performing OCR on Specific Pages Only

Once you have the exact page numbers, render only those pages to images and process them through your preferred OCR engine.

### Rendering Target Pages to Images

Use `pdf2image` in Python or `pdfium-render` in Rust to convert specific pages rather than the entire document:

```python
from pdf2image import convert_from_path

for page_num in result.pages_needing_ocr:
    # Render only the specific page

    images = convert_from_path(
        "document.pdf", 
        first_page=page_num, 
        last_page=page_num
    )
    # images[0] contains the PIL Image for processing

```

### Running External OCR Engines

Feed the rendered images to Tesseract, PaddleOCR, or cloud vision APIs:

```python
import pytesseract

ocr_results = {}
for page_num in result.pages_needing_ocr:
    image = convert_from_path(
        "document.pdf", 
        first_page=page_num, 
        last_page=page_num
    )[0]
    
    text = pytesseract.image_to_string(image)
    ocr_results[page_num] = text

```

### Integrating Results Back

Because `pdf2md` returns empty Markdown for `Scanned` or `ImageBased` documents, you must merge the OCR text back into your final output manually. Create a page‑mapping dictionary that combines the original page numbers with the recognized text, then concatenate or insert the content according to your document structure requirements.

## Summary

- **Detection** happens in [`src/detector.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/detector.rs) (lines 250‑300), where content streams are analyzed for text operators and image markers
- **Metadata** is stored in `PdfProcessResult.pages_needing_ocr` as defined in [`src/lib.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/lib.rs) (lines 3918‑3930)
- **Access** the list via the Rust API (`process_pdf_with_options`), CLI (`pdf2md --json`), or Python bindings (`process_pdf`)
- **Optimization** is achieved by rendering only the specified pages (1‑based indexing) to images using libraries like `pdf2image`
- **Completion** requires running external OCR engines (Tesseract, etc.) on the flagged pages and merging results back into your document pipeline

## Frequently Asked Questions

### Does pdf‑inspector perform the actual OCR or just detect which pages need it?

pdf‑inspector only detects and reports which pages require OCR via the `pages_needing_ocr` field. You must use external engines like Tesseract, PaddleOCR, or Google Vision API to perform the actual text recognition on rendered page images, as the library’s extraction pipeline short‑circuits for scanned content.

### What page numbering system does pdf‑inspector use for the OCR list?

The `pages_needing_ocr` vector uses 1‑based indexing, meaning the first page of the document is page 1. This convention aligns with standard document referencing and matches the input parameters of most PDF rendering libraries like `pdf2image` and `poppler`.

### Why does pdf‑inspector return empty Markdown for Scanned PDFs?

According to lines 3912‑3916 in [`src/lib.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/lib.rs), when the detector classifies a document as `Scanned` or `ImageBased`, the extraction pipeline intentionally returns only metadata and no Markdown content. This design prevents attempts to extract non‑existent text layers and explicitly signals that you must run external OCR on the `pages_needing_ocr` list to obtain the actual document content.

### Can I limit processing to specific page ranges before detection?

Yes. When using the Rust API, set the `page_filter` field in `PdfOptions` before calling `process_pdf_with_options`. This restricts both the detection phase in [`src/detector.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/detector.rs) and subsequent extraction to your specified range, significantly improving performance on large documents by avoiding analysis of pages you already know are text‑based.