PDFs are the most common format for sharing finished documents — but extracting usable text from them can be surprisingly difficult. A PDF that looks perfectly readable can be technically impossible to extract text from, while another with the same visual appearance converts cleanly in seconds. Understanding why requires a brief look at how PDFs store content, which determines which tools work and why some PDFs resist extraction entirely.
Text-Based vs. Scanned PDFs: A Critical Distinction
There are fundamentally two kinds of PDFs, and they behave very differently for text extraction. A text-based PDF (also called a native or born-digital PDF) was created by a program — a word processor, a presentation tool, a design application, or a PDF printer driver. The text in a text-based PDF is stored as actual Unicode characters inside the file. You can select and copy text from it in any PDF viewer, and any text extraction tool can read it directly.
A scanned PDF was created by scanning a physical document and saving the resulting image as a PDF. There is no text inside the file — only a high-resolution image of text. No standard text extraction tool can read it without OCR (Optical Character Recognition), which analyzes the image pixel by pixel to recognize character shapes. OCR requires dedicated software (Tesseract, Adobe Acrobat Pro, ABBYY FineReader) and is computationally expensive compared to direct text extraction.
A third category — PDFs with embedded OCR — has a text layer added on top of the scanned image. These are created when you run OCR on a scanned PDF and save the result. They look like scanned PDFs but contain an invisible text layer that can be extracted. The quality of extraction depends entirely on the accuracy of the original OCR pass.
How PDF.js Extracts Text
PDF.js is Mozilla's open-source PDF rendering library, the engine behind Firefox's built-in PDF viewer. It processes PDFs entirely in JavaScript — no server required, no plugins. For text extraction, PDF.js reads the PDF's content streams, decodes the text encoding, resolves character mappings (PDF uses various encoding standards including WinAnsiEncoding, MacRomanEncoding, and custom ToUnicode mappings), and returns the text items with their positions on the page.
The positional information is crucial and also problematic. PDF.js returns each text item as a string with an x/y coordinate, not as a flowing paragraph. Reconstructing reading order from positioned fragments requires heuristics: items with the same y-coordinate (within a threshold) are on the same line; significant x-gaps within a line may indicate column breaks; gaps in y between lines indicate paragraph boundaries. These heuristics work well for simple single-column documents and poorly for multi-column layouts, PDFs with sidebars, or pages with mixed text and figure captions.
When PDF Text Extraction Works Well vs. Poorly
- Works well: PDFs generated from Word, Google Docs, or LaTeX — these have clean Unicode text streams and simple layouts
- Works well: academic papers in single-column format from arXiv, PubMed, or similar repositories
- Works well: PDF reports generated by reporting tools (Jasper, Crystal Reports, Tableau exports)
- Works poorly: multi-column academic papers — text from different columns gets interleaved incorrectly
- Works poorly: PDFs with decorative text, text in shapes, or text embedded in images
- Fails entirely: scanned PDFs without an embedded OCR text layer — only images are present
When to Use Alternative Approaches
For scanned PDFs, you need OCR before text extraction. Free options include Tesseract (open source, runs locally via command line or wrappers), Google Drive (upload a PDF, right-click → Open with Google Docs — Google runs OCR automatically), or Adobe Acrobat online (limited free tier). For bulk processing of scanned documents, Tesseract via a Python script with pdf2image is the most flexible approach.
If you have the source document — the original .docx, .odt, or Google Doc that the PDF was exported from — always use that for conversion instead of the PDF. A DOCX-to-Markdown converter will produce significantly better output than PDF-to-Markdown from the same content, because the Word document preserves semantic structure (real headings, real lists, real tables) that gets flattened in the PDF export.
For programmatic PDF text extraction at scale, Python's pdfminer.six library provides more granular control over the text extraction pipeline than browser-based tools. For PDF parsing in Node.js, pdf-parse wraps PDF.js in a simple API. For production document processing pipelines, commercial APIs like AWS Textract or Google Document AI handle both native and scanned PDFs with high accuracy.
PDF text extraction is not a black box — once you understand the distinction between text-based and scanned PDFs, and how positional text items are reconstructed into reading order, the quality of extraction results becomes predictable. Use browser-based tools for quick one-off extractions from text-based PDFs. Use OCR tools for scanned documents. And whenever possible, go back to the source document — a .docx or Google Doc — instead of the PDF export, because the source preserves the structure that PDFs flatten away.