If your PDF extractor returns an empty string, the file probably isn't broken

Reddit r/AI_Agents Tools

Summary

A developer describes building a PDF triage tool that inspects the PDF structure to determine if it contains a text layer or is made of scanned images, preventing silent empty extraction failures, and shares pitfalls around false text detection and phantom tables.

Spent an afternoon last week convinced a bank statement PDF was corrupt. pdfplumber returned nothing. pypdf returned nothing. The file opened fine in Preview and I could see all 12 pages of transactions. Here's what `pdftotext` actually gave back: ``` $ pdftotext statement.pdf - | wc -c 12 ``` Twelve bytes. One form-feed character per page, and nothing else. The file wasn't corrupt — it contained no text at all. It was 620 images of text, and every extractor was behaving correctly by returning nothing. That's the thing that cost me the afternoon: **the failure is silent.** No exception, no warning, just an empty string that looks exactly like "this document is empty." So I wrote a triage step that runs before extraction and says what the file actually is: ``` $ python3 pdf_triage.py statement.pdf statement.pdf Type SCANNED Pages 12 Size 1532 KB PDF 1.4 Text 0 chars (0/page) Images 620 Fields 0 Route Effectively no text layer -- this is pictures of text. Every text extractor will return empty or near-empty output, which is correct behaviour, not a bug. OCR is the only route. Have pdftotext, pdftoppm, pdfinfo, tesseract ``` It reads the PDF's own object structure and inflates the content streams with zlib, so it's standard library only — no pypdf, no pdfplumber, nothing to install. It classifies TEXT / SCANNED / MIXED / FORM / XFA / ENCRYPTED / NO_TEXT_LAYER, and tells you which tool you're missing for *that* specific file. Then OCR on the same file gives 1,980 characters on page one. **Two mistakes I made building it, in case you build something similar:** The first version reported 1,745 characters on that scan. Completely phantom. I was measuring strings in every stream I could inflate, which includes object streams, XMP metadata and embedded font programs — all full of strings that no extractor will ever return. Worse, I gated on `b"BT" in stream`, and inflated binary contains those two bytes by coincidence constantly. Once that test passed, every parenthesis in the noise counted as a text string. The fix is requiring properly delimited `BT`/`Tf` operator tokens plus an ASCII-dominant body, since content streams are ASCII. That bug was the worst one available, because it turns "needs OCR" into "extract directly" and the user gets nothing. The second: table detection on a plain contract produced **23 phantom tables**. Wrapped prose keeps producing a character column that's blank on every line, which splits a paragraph into a "table" whose second column is empty on most rows. Then my first fix rejected a genuine 6-column table. What actually separates them isn't how full the columns are, it's how *evenly* full — real tables sit at CV 0.07–0.55 across columns, prose splits at 0.50–0.90. It also writes real multi-sheet `.xlsx` with nothing but `zipfile` and string formatting, because the machine that needs a spreadsheet is often the one where `pip install` isn't an option. And it keeps leading zeros and 16-digit account numbers as text, since those are exactly the fields Excel destroys silently on import. ``` npx skills add prashant-cr/skills --skill pdf-parsing ``` Works in Claude Code, Cursor, Copilot, Codex and the other agents the `skills` CLI supports. **Limits, so nobody wastes time:** merged cells and stacked headers aren't modelled — it tells you rather than guessing. OCR runs about 6 seconds a page at 300 DPI and misreads digits, so it says so instead of handing you financial figures as if they were extracted. Happy to answer questions about the PDF internals side, it's a weirder format than it looks.
Original Article

Similar Articles

Tests for a PDF

Lobsters Hottest

The author describes building a test suite for their CV PDF to ensure it is parseable by applicant tracking systems, and experimentally checks whether disabling ligatures affects pdftotext output.

How to parse tables from pdf's

Reddit r/AI_Agents

Advice on parsing tables from PDFs by converting to PNGs and using Gemini 3.1 Pro with low thinking, claiming 95% accuracy. Other tools like Extend, Reducto, Landing are poor for this task.

@knowledgefxg: Practical Open-Source Tool Recommendation: pdf-inspector solves a very real problem: not all PDFs need OCR. For example, you throw a PDF at it, and it first determines what type of PDF it is—whether it's a normal text-based version (e.g., exported from Word) or a scanned version (image)…

X AI KOLs Timeline

pdf-inspector is an open-source Rust library for intelligently classifying PDF types (text or scanned), extracting text, and converting to Markdown, avoiding unnecessary OCR to improve speed and save costs.