How book-to-skill Handles Scanned or Image-Only PDFs: Detection and Extraction Guide

book-to-skill detects scanned PDFs using a fast pre-flight check in looks_image_only and deliberately raises an ExtractionError directing users to run OCR externally rather than attempting automatic text extraction on image-based pages.

When processing document collections with virgiliojr94/book-to-skill, encountering scanned books or image-only PDFs requires special handling. Unlike tools that attempt silent OCR failures, this library implements a deterministic two-stage detection system that fails fast with actionable guidance. Understanding exactly how book-to-skill handles scanned or image-only PDFs helps developers integrate proper preprocessing steps into their document pipelines.

Two-Stage Detection Architecture

The library identifies image-only documents through a coordinated pipeline spanning two core modules. This architecture separates detection logic from extraction orchestration, ensuring that scanned PDFs are caught early before resource-heavy processing begins.

Stage 1: Fast Pre-Flight Detection in pdf.py

The looks_image_only function in book_to_skill/parsers/pdf.py (lines 93-107) performs rapid screening by running pdftotext on the first N pages of the document. By default, the system checks the first 5 pages. If the command executes successfully but returns an empty string, the function returns True, signaling that the PDF contains no extractable text layers.

This approach intentionally avoids loading entire documents into memory, making the check lightweight even for large scanned books.

Stage 2: Extraction Guard in utils.py

Following detection, the main extraction flow in book_to_skill/utils.py (lines 805-815) evaluates the boolean result. When looks_image_only returns True, the pipeline immediately raises an ExtractionError with specific instructions to apply OCR preprocessing. This guard prevents the fallback extraction chain—Docling → pdftotext → pypdf → pdfminer—from attempting futile text extraction on raster images.

The looks_image_only Implementation

The detection logic relies on external pdftotext utility execution to probe for text content. Here is how the function behaves in practice:

from book_to_skill.parsers.pdf import looks_image_only

# Check if PDF requires OCR preprocessing

if looks_image_only("scanned_book.pdf"):
    print("📄 This PDF appears to be image-only; run OCR first.")

Internally, the function samples the initial pages (configurable via the default parameter) and examines the stdout of the pdftotext command. An empty response indicates the absence of text-based content, triggering the scanned PDF classification.

Pipeline Integration and Error Handling

When the extraction guard identifies an image-only document, book-to-skill fails explicitly rather than returning empty or partial results. The error handling in utils.py constructs a detailed ExtractionError message that includes the specific command needed to resolve the issue.

The error output follows this pattern:


# Simplified logic from utils.py extraction flow

if ext == ".pdf":
    print(f"Extracting PDF: {input_str}")
    if looks_image_only(input_str):
        raise ExtractionError(
            f"{input_path.name} looks like a scanned (image-only) PDF …\n"
            "Run OCR on it first, then retry:\n"
            "  ocrmypdf input.pdf output.pdf"
        )
    # ... continues with Docling, pdftotext, pypdf, pdfminer chain

As implemented in virgiliojr94/book-to-skill, this behavior ensures users receive immediate, actionable feedback rather than silent data loss.

Why book-to-skill Does Not Perform OCR Automatically

The library intentionally excludes automatic OCR capabilities to maintain flexibility and reduce dependency overhead. By raising ExtractionError defined in book_to_skill/exceptions.py, the codebase delegates optical character recognition to specialized external tools like ocrmypdf. This design choice allows users to:

  • Select their preferred OCR engine based on language requirements
  • Control preprocessing quality settings independently
  • Avoid bloating the installation with heavy OCR dependencies

After applying external OCR (e.g., ocrmypdf input.pdf output.pdf), the processed file passes through the standard extraction pipeline successfully.

Testing the Scanned PDF Detection

The test suite in tests/test_book_to_skill.py validates this early-fail behavior, confirming that image-only PDFs trigger the appropriate exception path with OCR hints. This ensures the detection mechanism remains reliable across updates to the underlying PDF parsing dependencies.

Summary

  • book-to-skill detects scanned PDFs by probing the first 5 pages with pdftotext via the looks_image_only function in book_to_skill/parsers/pdf.py.
  • Image-only documents trigger an immediate ExtractionError in book_to_skill/utils.py (lines 805-815) before resource-intensive extraction begins.
  • The library does not perform automatic OCR; instead, it provides explicit command-line instructions for external tools like ocrmypdf.
  • After OCR preprocessing, the standard extraction chain (Docling → pdftotext → pypdf → pdfminer) processes the document normally.
  • The ExtractionError class in book_to_skill/exceptions.py standardizes error messaging for unscanned document workflows.

Frequently Asked Questions

Does book-to-skill automatically perform OCR on scanned PDFs?

No. According to the source code in book_to_skill/utils.py, the library deliberately raises an ExtractionError when encountering image-only PDFs rather than attempting automatic OCR. Users must preprocess documents using external tools like ocrmypdf before retrying extraction.

How does book-to-skill detect if a PDF is image-only?

The detection occurs in book_to_skill/parsers/pdf.py (lines 93-107) through the looks_image_only function. This helper runs pdftotext on the first 5 pages of the document; if the command returns an empty string, the PDF is classified as scanned or image-only.

What error message does book-to-skill display for scanned PDFs?

When looks_image_only returns True, the extraction pipeline raises an ExtractionError with a message instructing users to run OCR first, specifically suggesting: ocrmypdf input.pdf output.pdf. This appears in the exception handling logic at lines 805-815 of book_to_skill/utils.py.

Can I configure the number of pages checked for image-only detection?

The looks_image_only function accepts parameters to adjust the sampling scope, though the default configuration checks the first 5 pages. Developers can modify the function call in utils.py or invoke looks_image_only directly with custom page limits when implementing custom preprocessing workflows.

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 →