The conclusion first: a scan that yields nothing is not a failure, it never had readable text. Text in a PDF exists in two forms — a text layer of extractable characters, and an image of pixels. Scans only have the second.
Measured on two files, the difference is plain:
| File | Pages | Extractable chars | Embedded images | Reads as text? |
|---|---|---|---|---|
| PDF with a text layer | 1 | 34 | 0 | Yes |
| Same page rendered to an image, wrapped in a PDF | 1 | 0 | 1 | No |
Detection method, no model involved:
import pymupdf d = pymupdf.open(path) txt = "".join(p.get_text() for p in d) print(len(txt.strip()), "chars", sum(len(p.get_images(full=True)) for p in d), "images")
Zero characters with one or more images means a scan. This check runs before the file reaches the model and saves a whole round.
Why check first
Handed a PDF with no text layer, the model has three options: say it cannot read it, invent something plausible, or fall back to OCR if the toolchain has it. The third is best; the first two cost you time to distinguish.
What to do
- Run the character-count check across the batch and pull out the zero cases into their own section.
- If OCR is available, run it; otherwise mark them 'read failed, no text layer' with filename and page count.
- Write it into the instruction: anything unreadable gets marked as failed, never inferred from the filename.