How to Handle Image-Only PDFs with book-to-skill: Detection and OCR Workflows
book-to-skill detects image-only PDFs by running a lightweight pre-flight check using pdftotext on the first five pages; if no text is extracted, it raises an ExtractionError to prevent wasted CPU cycles, allowing you to route the file to an OCR engine like Tesseract instead.
Processing scanned documents and image-based PDFs requires special handling in text extraction pipelines. The virgiliojr94/book-to-skill repository provides a dedicated detection mechanism that identifies PDFs containing only raster images—no extractable text layers—before attempting expensive parsing operations. This guide explains how the detection logic works, where it lives in the source code, and how to implement OCR fallbacks for scanned documents.
How Image-Only PDF Detection Works in book-to-skill
The detection system treats image-only PDFs as a special case to avoid false-negative results from standard text extraction backends. When you attempt to process a PDF, the pipeline first determines whether the file contains selectable text or only scanned images.
The looks_image_only Function Implementation
The core detection logic resides in book_to_skill/parsers/pdf.py within the looks_image_only function. This utility performs a fast pre-flight check on the initial pages of the document using the external pdftotext command-line tool.
The implementation follows three verification steps:
-
Binary availability check: The function uses
shutil.which("pdftotext")to verify the helper utility is installed. Ifpdftotextis missing, the function returnsFalseand the normal extraction pipeline proceeds without blocking the file. -
Sample text extraction: When
pdftotextis available, the function executes a subprocess call with page range constraints:pdftotext -f 1 -l 5 input.pdf -This limits the check to the first five pages (configurable via the
pagesparameter) for speed. -
Emptiness validation: The function returns
Trueonly when the command succeeds (returncode == 0) and produces no character output (not result.stdout.strip()). Any exception during execution triggers a fallback toFalse, ensuring the pipeline attempts normal extraction rather than failing silently.
Integrating Detection into Your Extraction Pipeline
According to the book-to-skill source code in book_to_skill/utils.py, the detection result determines whether the heavy-weight extraction steps execute. When looks_image_only returns True, the pipeline short-circuits and raises an ExtractionError, bypassing downstream parsers like extract_with_pdftotext, extract_with_pypdf, and extract_with_pdfminer.
Here is a practical implementation pattern for your scripts:
from book_to_skill.parsers.pdf import looks_image_only, extract_with_pdftotext
pdf_path = "my_scanned_book.pdf"
# 1️⃣ Quick pre-flight check
if looks_image_only(pdf_path):
print(f"⚠️ {pdf_path} contains only images – text extraction will fail.")
# Route to OCR workflow here
else:
# 2️⃣ Continue with normal extraction
text = extract_with_pdftotext(pdf_path)
if text:
print("✅ Extraction succeeded.")
else:
print("❌ Extraction failed – try another backend.")
This pattern prevents CPU-intensive parsing attempts on documents that contain no machine-readable text layers.
Handling Image-Only PDFs with OCR Fallback
When the detection confirms an image-only PDF, you should invoke an optical character recognition (OCR) engine to extract text from the raster images. The following example demonstrates how to convert PDF pages to PNG images and process them with Tesseract:
import subprocess
from pathlib import Path
def ocr_pdf(pdf_path: str, out_txt: str) -> None:
"""Run Tesseract OCR on each page of an image-only PDF."""
# Convert PDF pages to PNG images
subprocess.run(
["pdf2image", "-pdf", pdf_path, "-o", "page_%03d.png"],
check=True,
)
# Combine OCR output from each page
pages = sorted(Path(".").glob("page_*.png"))
with open(out_txt, "w", encoding="utf-8") as out_f:
for img in pages:
subprocess.run(
["tesseract", str(img), "stdout", "-l", "eng"],
stdout=out_f,
check=True,
)
You can integrate this ocr_pdf function into the conditional block from the previous section to automatically handle scanned documents when looks_image_only returns True.
Summary
looks_image_onlyinbook_to_skill/parsers/pdf.pyprovides lightweight detection using the externalpdftotextutility on the first five pages.- The function returns
Trueonly whenpdftotextsucceeds but produces empty output, indicating pure image content. - When detection returns
True,book-to-skillraises anExtractionErrorinbook_to_skill/utils.pyto short-circuit expensive extraction backends. - The detection defaults to
Falseifpdftotextis unavailable or encounters errors, ensuring robust fallback behavior. - For detected image-only PDFs, implement an OCR workflow using Tesseract or similar engines to extract text from raster images.
Frequently Asked Questions
How does book-to-skill detect image-only PDFs?
The library uses the looks_image_only function in book_to_skill/parsers/pdf.py to run pdftotext -f 1 -l 5 against the input file. If the command executes successfully but returns zero characters, the PDF is classified as image-only. This check requires the pdftotext binary to be installed on the system path.
What happens when an image-only PDF is detected?
When looks_image_only returns True, the main extraction flow in book_to_skill/utils.py raises an ExtractionError before invoking heavy-weight parsers like extract_with_pdfminer. This short-circuit prevents wasted computation on OCR-free extraction attempts and signals your application to route the file to an OCR engine or skip it.
Can I customize the number of pages checked?
Yes. The looks_image_only function accepts a pages parameter that defaults to 5. You can increase or decrease this value depending on your accuracy requirements and performance constraints. Checking more pages improves detection reliability for documents with late-starting text content, while fewer pages increase speed.
Which OCR engines work with book-to-skill?
The repository does not bundle a specific OCR engine, but the detection output is designed to trigger any external OCR tool. The examples in the documentation use Tesseract via command-line invocation on PNG conversions of PDF pages. You can substitute alternatives like EasyOCR, PaddleOCR, or cloud-based services by replacing the subprocess calls in your OCR fallback function.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →