What Happens When You Process an Image-Only PDF in Book-to-Skill

Book-to-Skill immediately aborts the extraction pipeline and raises an explicit ExtractionError with instructions to OCR the document first, preventing silent failures on scanned image files.

When processing documents in the virgiliojr94/book-to-skill repository, the extraction system includes built-in safeguards against image-only PDFs. Unlike tools that return empty strings or garbled output on scanned documents, Book-to-Skill detects these files early and provides actionable guidance for preprocessing.

Fast Pre-Flight Detection with looks_image_only

Before attempting full text extraction, Book-to-Skill runs a lightweight validation check. The looks_image_only function, defined at line 93 in book_to_skill/parsers/pdf.py, executes pdftotext on the first five pages of the PDF by default.

If pdftotext returns no extractable text, the function returns True, flagging the document as image-only:

from book_to_skill.parsers.pdf import looks_image_only

pdf_path = "my_scanned_book.pdf"
if looks_image_only(pdf_path):
    print("This PDF is image-only – run OCR before extraction.")
else:
    print("Text extraction can proceed.")

This early detection prevents wasted processing time on files that cannot yield selectable text.

The Extraction Abort Mechanism

When the main extraction logic calls extract_single_file (see the PDF branch around line 50 in book_to_skill/parsers/pdf.py), it inspects the looks_image_only result before proceeding. If the check returns True, the pipeline raises ExtractionError defined in book_to_skill/exceptions.py:

if looks_image_only(input_str):
    raise ExtractionError(
        f"{input_path.name} looks like a scanned (image-only) PDF: its first pages "
        "contain no extractable text, only images.\n"
        "Run OCR on it first, then retry:\n"
        "  ocrmypdf input.pdf output.pdf"
    )

The exception bubbles up to the top-level loop in main(), which logs a warning and skips the file entirely. This ensures image-only PDFs never reach the downstream skill generation logic.

Command-Line Experience

When using the CLI tool, users receive immediate, actionable feedback. Instead of cryptic failures or empty output files, the terminal displays:

$ book-to-skill scanned_book.pdf
book-to-skill · turns a document into a structured agent skill

Extracting PDF: /home/user/scanned_book.pdf
  [warn] scanned_book.pdf looks like a scanned (image-only) PDF: its first pages contain no extractable text, only images.
  Run OCR on it first, then retry:
    ocrmypdf scanned_book.pdf scanned_book_ocr.pdf

This clear messaging eliminates guesswork about why extraction failed.

Fixing Image-Only PDFs with OCR

To process a scanned document through Book-to-Skill, you must first apply Optical Character Recognition (OCR). The error message explicitly suggests using ocrmypdf, a command-line tool that adds a text layer to image-based PDFs:

ocrmypdf input.pdf output.pdf

After OCR processing, the PDF contains selectable text, allowing looks_image_only to return False and permitting normal extraction to proceed.

Programmatic Error Handling

When integrating Book-to-Skill into larger applications, catch ExtractionError to handle image-only PDFs gracefully:

from book_to_skill.utils import extract_single_file
from book_to_skill.exceptions import ExtractionError
from pathlib import Path

try:
    result = extract_single_file(
        Path("scanned_book.pdf"), 
        extraction_mode="text", 
        install_mode="ask"
    )
except ExtractionError as exc:
    print(f"Extraction failed: {exc}")
    # Implement logic to trigger OCR or notify users

This pattern allows automated workflows to route unscanned documents through preprocessing pipelines.

Key Source Files

File Role
book_to_skill/parsers/pdf.py Implements looks_image_only, the PDF-only detection logic, and the various PDF extraction back-ends.
book_to_skill/utils.py Calls looks_image_only before attempting extraction; raises ExtractionError on image-only PDFs.
tests/test_book_to_skill.py Unit test confirming that looks_image_only correctly identifies image-only PDFs and that the extractor aborts with a helpful error (around line 1965).
book_to_skill/exceptions.py Defines ExtractionError, the exception type used for the early abort.

Summary

  • Early Detection: The looks_image_only function in book_to_skill/parsers/pdf.py checks the first five pages using pdftotext to identify scanned documents.
  • Explicit Failure: Instead of returning empty content, Book-to-Skill raises ExtractionError with specific OCR instructions.
  • Actionable Guidance: Error messages include the exact ocrmypdf command needed to preprocess the file.
  • Test Coverage: The behavior is validated in tests/test_book_to_skill.py around line 1965, ensuring reliable detection of image-only PDFs.

Frequently Asked Questions

Can Book-to-Skill extract text from scanned image-only PDFs?

No. Book-to-Skill explicitly rejects image-only PDFs during the pre-flight check. The looks_image_only function detects when a PDF contains no selectable text and aborts processing before extraction begins. You must first run OCR tools like ocrmypdf to add a text layer to the document.

What error message appears when processing an image-only PDF?

Book-to-Skill raises an ExtractionError with the message: [filename] looks like a scanned (image-only) PDF: its first pages contain no extractable text, only images. Run OCR on it first, then retry: ocrmypdf input.pdf output.pdf. This appears in both CLI output and exception traces.

How does Book-to-Skill detect if a PDF is image-only?

The detection happens in book_to_skill/parsers/pdf.py via the looks_image_only function. It runs pdftotext on the first five pages of the PDF. If the command returns no text content, the function returns True, triggering the extraction abort in extract_single_file.

Which file handles the image-only PDF error in Book-to-Skill?

The primary detection logic resides in book_to_skill/parsers/pdf.py, while book_to_skill/utils.py contains the extract_single_file function that actually raises the ExtractionError. The exception class itself is defined in book_to_skill/exceptions.py.

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 →