Engineering

How to Extract Text From a PDF (Including Scanned, Image-Only Ones)

How PDF text extraction really works — parsing the text layer, why scanned image-only PDFs need OCR, and how a combination of PDF parsing and OCR gets clean text from any file, locally in your browser.

A PDF looks like a document full of text, but that’s not how it stores itself. PDF is a print format — a description of where to paint glyphs, lines, and images on a fixed page — not a text format. Sometimes the words are genuinely in there and can be read out cleanly; sometimes they’re only pixels in a picture of a page; and sometimes there’s a text layer that looks fine on screen but comes out as garbage. Getting reliable text out of an arbitrary PDF means handling all three cases. This guide explains how PDF text extraction actually works, why image-only PDFs are the hard part, and how a combination of PDF parsing and OCR solves it.

Drop in a PDF or Word doc and the text layer is parsed out locally — clean and selectable, with any embedded images pulled out alongside it.

How text is stored in a normal PDF

A well-behaved PDF carries a text layer: for each page it records the characters, which font drew them, and the exact coordinates where each run of glyphs is painted. When you select text in a PDF viewer and it highlights word by word, you’re seeing that layer. Extracting text from this kind of file is a parsing job — walk the page’s content stream, read out the character codes, map them back to Unicode via the font’s /ToUnicode table, and you have the text.

Two details make even this "easy" case less trivial than it sounds:

  • Position, not reading order. Glyphs are placed at x/y coordinates, so a parser has to reassemble reading order from geometry — group runs into lines, order lines top-to-bottom, and decide where spaces and column breaks go. Multi-column layouts and tables are where naive extraction turns into word salad.
  • Fonts are often subsetted. To shrink the file, a PDF usually embeds only the glyphs it actually uses, remapped to a private numbering. The /ToUnicode map is what translates those private codes back into real characters. When it’s present and correct, extraction is clean. When it’s missing or wrong, it isn’t — more on that below.

The distinction that matters is what the file stores, not what the page looks like. Two PDFs can look pixel-for-pixel identical on screen while being completely different underneath:

The hard case: PDFs that are only images

This is the complication most people hit and the one worth understanding clearly. A large share of real-world PDFs have no text layer at all. Every page is a single image — a photograph or scan of a document, or a picture exported from something else. To your eye it reads as a page of text; to a parser it’s one rectangular bitmap with zero selectable characters.

These files come from everywhere:

  • Scanners and photocopiers that save "to PDF" — the output is just the scanned image wrapped in a PDF.
  • Phone photos of a contract or receipt, saved as a PDF.
  • Faxes and signed paperwork that were printed, signed, and re-scanned.
  • Screenshots or images dropped into a PDF for sharing.

No amount of parsing recovers text that was never encoded as text. The characters simply aren’t in the file — only pixels that look like characters. The only way through is optical character recognition (OCR): render the page to a raster image, then run a recognition model over the pixels to infer the letters, word by word. That’s a fundamentally different operation from parsing, and it’s why a tool that only reads the text layer returns nothing at all for a scanned PDF.

The sneaky middle case: a text layer that’s broken

Between "clean text" and "pure image" sits the case that fools people, because the PDF doeshave a text layer — it’s just wrong. You extract it and get output like this:

���  ��  Invoice  ���  ���  Total  ��

A few real words survive, buried in control characters and replacement symbols. The cause is almost always a missing or corrupt /ToUnicode map on a subsetted font. The page renders perfectly on screen — the viewer just paints the glyph shapes — but the character codes behind them are the font’s private numbering, with no table to turn them back into real Unicode. So extraction yields raw glyph codes: control-range bytes, private-use-area code points, and the replacement character.

The important insight is that a broken text layer is worse than no text layer, because a naive extractor happily returns the garbage and declares success. The fix is to detect that the extracted text is junk and fall back to OCR — treating the broken page exactly like an image-only one.

How we solve it: PDF parsing and OCR together

No single technique covers every PDF, so the reliable approach is a combination that decides, per page, which method to trust. For each page we:

  1. Parse the text layer first. If the page has clean, meaningful text, that’s the best possible source — it’s exact, fast, and preserves spelling and punctuation perfectly. We use it and move on.
  2. Check whether that text is real. If the text layer is empty (an image-only page) or fails a garbage test — too high a proportion of control characters, replacement symbols, and private-use code points — we don’t trust it.
  3. Fall back to OCR. Render the page to a raster image and run OCR over the pixels to recover the text. This handles scanned pages and broken-font pages with the same mechanism.

One source per page, never both. A page’s text comes from exactly one place — the parsed layer or OCR, not both merged. That avoids the classic duplication bug where a page’s content shows up twice. Blank pages are detected cheaply (a quick pixel sample for ink) and skipped, so OCR isn’t wasted on empty scans.

The trade-off worth naming: OCR is approximate. It can misread a similar-looking character, struggle with faint scans, low resolution, handwriting, or unusual fonts, and it’s much slower than parsing. That’s exactly why parsing comes first and OCR is the fallback — you only pay the OCR cost, and accept its fuzziness, on the pages that genuinely need it.

Can you extract text from a locked or “non-editable” PDF?

Yes, a PDF can be locked down — but “locked” means several different things, and they don’t behave the same when you try to read the text. Here’s exactly what happens with each, tested against real protected files:

  • Flattened / scanned (image-only). Works. The most common “you can’t edit this” PDF is simply a picture of a page — there’s nothing to edit. It’s the OCR case above, handled like any scanned document.
  • Permission-restricted — “no copy / no edit / no print.” Works. A PDF can carry an owner password that sets flags asking viewers to forbid copying, editing, or printing. Those flags are advisory — enforced only by cooperating viewers like Acrobat, not by the format itself. The document isn’t actually encrypted against reading, so any capable parser (ours included) reads the text regardless of the “no copy” flag. We verified this on a file restricted with exactly those permissions: the text came out fine.
  • Password-to-open (encrypted). Doesn’t work today. A PDF can require a password just to open it, and its contents are genuinely encrypted. Our tool doesn’t prompt for a password, so an encrypted PDF fails to open and no text comes out. You’d need to open it once in a viewer with the password and save an unprotected copy first.

The straight answer: a “can’t copy / can’t edit” restriction does not stop text extraction — those permissions are honor-system, and a real parser ignores them. A “can’t open without a password” PDF is the actual wall, and that encrypted case is the one thing our extractor doesn’t handle yet.

Doing it in the browser — with nothing uploaded

All of this runs client-side. The page-parsing and rasterizing is done with a PDF engine in the browser; OCR runs as a WebAssembly recognition model loaded on demand — the first scanned page pays a one-time cost to fetch it, then every page after is local. Because both steps happen on your device, the PDF is never sent to a server, which matters when it’s a contract, an invoice, or anything with personal data.

Long documents are processed a page at a time rather than all at once, so the first page appears quickly and a 200-page scan doesn’t freeze the tab. When you download the extracted text, the remaining pages are processed with a visible progress bar and then saved in a single click.

Our Document Extractor does exactly this: hand it a PDF and it returns the text — reading the clean text layer where there is one, and OCR’ing scanned or broken-font pages automatically. If your file is a photo or screenshot rather than a PDF, the Image Text Extractor (OCR) handles images directly. And once you have the text, you can compare two PDFs for differences — including scanned ones — since the same extraction feeds the diff.

Frequently asked questions

Why does copying text from my PDF give gibberish?

Because the font is subsetted and its /ToUnicode map — the table that turns the font’s private glyph codes back into real characters — is missing or wrong. The page still renders correctly (the viewer just paints the glyph shapes), but the character codes behind them don’t map to Unicode, so you get control characters and replacement symbols. The reliable fix is to detect the garbage and OCR the page instead.

Can you extract text from a scanned PDF?

Yes, but only with OCR. A scanned PDF has no text layer — each page is an image — so there’s nothing to parse. Rendering the page and running optical character recognition over the pixels is the only way to recover the words. Our extractor does this automatically when it sees a page with no usable text.

How do I know if my PDF has real text or is just an image?

Try to select or search the text in a PDF viewer. If you can highlight individual words, there’s a text layer. If the whole page selects as one block or nothing selects at all, it’s an image and needs OCR. A good extractor makes this decision for you per page, so you don’t have to check first.

Is OCR as accurate as the real text layer?

No — when a clean text layer exists, parsing it is exact, while OCR is a best-effort reading of pixels and can misrecognize characters, especially on low-resolution scans, faint copies, handwriting, or unusual fonts. That’s why the right approach uses the text layer whenever it’s trustworthy and only falls back to OCR for the pages that need it.

Can it read a PDF that’s set to “no copying” or “no editing”?

Yes. Those restrictions are permission flags set by an owner password, and they’re advisory — enforced only by viewers that choose to honor them, not by the PDF format. The file isn’t actually encrypted against reading, so the extractor pulls the text out normally, whether the text is a real layer or needs OCR. We tested this against a file locked with copy, edit, and print all disabled.

What about a password-protected PDF?

If the PDF only needs a password to open it, it’s genuinely encrypted, and our tool can’t read it today — it doesn’t prompt for the password, so the file fails to open. Open it once in a PDF viewer with the password and save an unprotected copy, then extract from that. A PDF that opens without a password but is merely restricted from copying/editing (see above) works fine.

Do my files get uploaded to a server?

No. Both the PDF parsing and the OCR run entirely in your browser — the file never leaves your device. You can confirm it yourself: watch the DevTools Network tab while you extract and you’ll see zero upload requests.