← Blog
Problem AegisPDF

Why your scanned PDF extracts as an empty page

“Scanned PDFs come out as empty text and nothing tells me anything is missing.”

You hand a PDF to something that reads PDFs, and it gives you nothing back. No error, no warning, just an empty string where the document should have been. The file opens fine. You can read it on screen. The words are visibly there.

They are there the way words are there in a photograph of a page, which is to say they are not text at all.

A PDF is not required to contain any text

A PDF describes marks on a page. Some of those marks can be text, and usually are when the file was produced by software. When the file was produced by a scanner or a phone camera, the page is one image, and there is nothing in it that any parser can read as a character.

Every text extraction library says so, in almost the same words. pypdf's documentation puts it plainly:

If a PDF page appears to contain only an image (e.g., a scanned document), the extracted text may be minimal or visually empty.

and then points you elsewhere, because there is nothing it can do:

consider using OCR software such as Tesseract OCR to extract text from images

That is the whole of the common case. Extraction reads an embedded text layer. A scan has none. The library is not failing; it is reporting accurately that there is nothing of the kind it reads.

The failures you find out about

Three shapes, and the useful thing about all three is that you learn of them.

Nothing comes back. The most common by far: extraction returns an empty or near-empty string, and whatever you were building stops.

The tool refuses. Better behaviour, and some do it: detect that the text layer is missing or negligible, and fail with a message that names the reason rather than returning a plausible empty result.

It stops at a page limit. Less common, and worth knowing about before you meet it, because the output looks complete.

All three are survivable because something told you. The fourth one does not.

The fourth: "does this file have text" is the wrong question

Almost every implementation tests the file. The property is per page.

A real document is very often mixed. A contract with a signature page photographed on a phone. A report with three scanned exhibits at the back. A forty page filing where pages one to thirty six are born digital and the last four came off a fax. Extract text from any of these and you get text, quite a lot of it, and it passes any check of the form "did we get anything?"

The pages you lost are silently absent, and they are frequently the pages that mattered, because the scanned page is the one someone signed, stamped or received from somewhere else.

This failure shows up constantly in public bug trackers. A document reader that reports a partly scanned file as fully read, with no per page coverage anywhere in its output. An extractor that computes exactly which pages need OCR and then has nothing consume that list, so the pages are detected and then ignored. A search index that records a scanned file with zero chunks and indexes it as though the document were empty, which means it will never appear in results and will never look broken either. A scanner that reads only the first fifty pages of a longer file, discloses the truncation nowhere, and overwrites the reported page count with the cap so the output claims to be complete.

Note what those have in common. None of them is an OCR quality problem. They are all the same mistake about where the property lives.

The maturity of the tooling reflects this. OCRmyPDF, which exists to solve exactly this problem, refuses by default to touch a file that already contains text, and then offers three separate modes for the ambiguity. Its documentation describes the mixed case directly:

If a file contains a mix of text and bitmap images that contain text, OCRmyPDF will locate the additional text in images without disrupting the existing text

A tool needs a mode like that only because mixed files are ordinary rather than exceptional.

Counting characters cannot tell you it is a scan

The obvious repair is to check each page instead of the file, and then the obvious test is the length of the text on that page. That test is wrong in both directions, and it is worth seeing why before you ship it.

A title page, a cover sheet or a section divider has almost no extractable text and is not a scan. A scanned page with a printed letterhead across the top can carry a useful number of characters and is one. Character count answers "is there a usable text layer on this page", which is a real and useful question, but it cannot answer "is this page a picture of a document".

What does answer it is the shape of the page rather than the amount of text on it. A scan is one raster image covering essentially the whole sheet. A chart, a logo or a figure covers a fraction of it. And because a photograph of a landscape also covers the whole sheet, coverage alone still confuses a scanned document with a picture, so the texture of the image has to separate those two.

That is three signals for a question most code answers with one.

Do not trust the confidence score either

Once OCR is running, the engine will report how confident it is, and it is tempting to gate on that number.

We measured this on our own scanned fixtures and it does not hold. One engine reported about 98 percent on a page where it had silently dropped the hyphen out of a social security number. Another reported 89 percent while misreading a digit. Across a sixty page corpus, correct pages scored as low as 61 percent and wrong pages as high as 95 percent, which is complete overlap.

Confidence is what the engine says about itself. It is a reasonable signal for "this page was hard to read, spend more effort on it" and it is not a quality gate.

So, in order

  1. Ask per page. Whatever you do next, the unit is the page, not the file. Almost every failure above dissolves at this one change.
  2. Report coverage rather than success. "Read 36 of 40 pages, 4 pages have no text layer" is an answer. "Success" is not, when four pages are missing.
  3. Do not use character count as the scan test. Use it for the question it answers, which is whether a usable text layer is already present.
  4. Treat a page cap as data loss and say so. If you stop at fifty pages, the output has to carry that fact, and the page count has to remain the real one.
  5. Use confidence for triage, not for trust.

If the document is yours to fix

The durable repair is upstream. If you control the scanner, most produce searchable PDFs with a setting, which puts a text layer in the file at the point where the page is still in front of the machine. That is cheaper and better than every recovery below, and it is the option people most often do not know they have.

Where AegisPDF fits

AegisPDF is our browser based PDF tool, and OCR is one of its paid features. It is relevant to the recovery half of this problem and not to the pipeline half.

What it does here:

  • It runs the OCR in your browser tab. The document is never uploaded, which is the property that matters when the scanned pages are client files, medical records or anything else you would not put through a web converter.
  • It decides page by page. "OCR all" targets the pages that actually need it: scans, and pages whose text is locked up in vector outlines. It skips pages that already have real text, because layering OCR over existing text duplicates every match.
  • It validates that the recovered text layer lines up with what is visible before writing the file, and aborts if it cannot. A PDF whose invisible text disagrees with its visible content is worse than one with no text at all, because now everything downstream trusts it.
  • Where it is unsure, it says so on the page rather than silently.

One deliberate asymmetry inside that, since this post is about silent loss: a page that looks like a photograph but already has its own text is left alone, while a page that looks like a photograph and has no text at all is still processed. Over processing costs you a junk text layer that someone can see. Under processing costs you a photographed ID card that nobody knows is unread.

What it does not do: it is not a document ingestion pipeline and it does not index anything. If your problem is that a corpus of thousands of files is indexing scans as empty, that is the per page check above, in your code, and no desktop tool fixes it.

What this post covers. It describes PDF text extraction as a format problem, and quotes two projects' own documentation for the behaviour of their tools. The failure patterns are drawn from public issue trackers. The confidence figures are from our own measurements on our own test corpus and are not a benchmark of any vendor's OCR service. It does not compare OCR engines, and it does not cover any specific scanner's settings.