{"slug": "a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally", "title": "A PDF Parser from the 80s Beats Claude (and They Use It Internally)", "summary": "A developer found that Tesseract, a PDF parser first created by HP Labs in 1985, outperforms Anthropic's Claude AI for parsing scanned PDFs, being 10x faster and more accurate. Anthropic's own internal Claude skills use PyTesseract for OCR on scanned documents, revealing that the company relies on the decades-old tool rather than the AI model's native vision capabilities.", "body_md": "# A PDF Parser from the 80s Beats Claude (And They Use It Internally)\n\n*My journey to parse a **CIA PDF**, only to discover picking the right tool for the job is still a thing*\n\n*CIA PDF*\n\nWhen you give a PDF to an AI, you picture the model reading it. However, for certain kinds of PDFs, the actual model barely sees the text, they only call tools previously dictated by their actual software engineers.\n\nI spent days trying to parse a badly scanned CIA PDF (don't ask me why, otherwise I'll have to kill you). I tried using the most powerful Anthropic and Google models but I ended up concluding Tesseract (a 1985 tool), does a better job and much faster by 10x.\n\n[Not just that, but I found out that Claude uses PyTesseract in their PDF](https://readplace.com/view/github.com/anthropics/skills/blob/main/skills/pdf/SKILL.md) parser skill under the hood. They pick that by going through a heuristic, rasterising the most difficult scanned pages and completing missing sentences with hallucinated words when streaming their tokens back.\n\nClaude Code AI model is not better than anyone else, they just pay skilled engineers to give them the right tools to call.\n\nClaude ships with skills, small Markdown instruction files that tell it how to handle a task. Anthropic published the format and a set of these skills in [the open](https://readplace.com/view/github.com/anthropics/skills), so you can read them. The reading strategy part is (apparently) not open source and reads like a runbook that a tired engineer wrote at 2am.\n\n```\n### Choosing your reading strategy**Text-heavy documents** (reports, articles, books):→ Text extraction is primary. Rasterize only for specific figures or  pages where layout matters.**Scanned documents** (`pdffonts` shows no fonts):→ `pdftotext` will return nothing - don't run it. Rasterize pages at  150 DPI and Read them visually. For bulk text extraction, use OCR  (pytesseract after converting pages to images - see REFERENCE.md for  a complete example).**Slide-deck PDFs** (exported presentations):→ Every page is primarily visual. Rasterize individual pages on demand.  Text extraction gives you bullet-point text but loses all layout.**Form-heavy documents**:→ Extract form field values programmatically first (see below). Rasterize  the form page for visual context if needed.** Data-heavy documents** (tables, charts, figures):→ Use pdfplumber for tables. Rasterize pages with charts/figures.  Extract text for surrounding narrative. Consider both text AND image  for the same page when precision matters.\n```\n\nFor a PDF, the first move is not the model. It is a diagnostic. The skill runs `pdffonts`\n\nand checks whether the file carries a text layer. Two cases follow, and they get different tools.\n\nA born-digital PDF holds its text inside it. `pdftotext`\n\npulls that text out in milliseconds, with no model involved. The characters were sitting there the whole time.\n\nA scanned PDF is pixels. A photocopier flattened the words into an image, and there is nothing to pull out. Here the skill reaches for OCR, and the tool it names is `pytesseract`\n\n.\n\n`pytesseract`\n\nis the Python binding to Tesseract. HP Labs started Tesseract in 1985. HP open-sourced it in 2005, and Google kept it going after that. The engine is older than most of the people shipping AI products today.\n\n```\n# render every page to a PNG at 300 DPI (I tried 150dpi, shittier results)pdftoppm -r 300 -png input.pdf page# OCR one page BAM!tesseract --psm 1 --oem 1 -l eng page-01.png -\n```\n\n`--psm 1`\n\nruns orientation and script detection before recognition. `--oem 1`\n\nselects the [LSTM](https://readplace.com/view/en.wikipedia.org/wiki/Long_short-term_memory) engine. It needs no API key and makes no network call, so there is no rate limit to negotiate to access a walled garden.\n\nThis is the part that matters. The skill could have told the model to look at each page and read it off. The model can do that. A scanned page is an image, and the model can describe an image.\n\nReading clean letters off a page is an old, settled problem. Tesseract handled a version of it decades ago. It is fast, it runs locally, and it costs nothing to call. It returns the same text on every run but some garbage here and then.\n\nA model pointed at the same page is slower, burns tokens ($$), needs a network round trip, and can quietly invent words that were not there. So a careful engineer reaches for the narrow tool. The skill makes the same call.\n\nClaude is not the thing reading your scan. A character engine from the 1980s is.\n\nThe model does get pointed at a page sometimes, when layout or a chart matters. The skill rasterizes that page to an image and lets the model look. Even then the split holds. The model handles the visual judgment, not the plain reading of characters.\n\nThe skill file is basically an engineer’s reflex, written down.\n\nI learned this the slow way. So I built this reader app ([readplace.com](http://readplace.com/?utm_source=fagnerbrack.com&utm_medium=post-body-link&utm_content=8ee45)) that turns saved PDFs into clean text. Early on, I pointed a Google Vision model at scanned pages and asked it for the words. It worked on easy scans and fell apart on a dense one, taking up to 15 minutes (AWS Lambda max timeout setting) to process 212 pages event with each page getting its own lambda in parallel. Many pages timed out on their own and some came back half empty (or half full depending on how you're feeling today).\n\nIt cost real money and patience.\n\nI tore that path out and said \"F$$$ IT\", just run Tesseract instead, locally, in the same container. The same document finished in a fraction of the time, cost nothing, and left no page empty.\n\nBumping render DPI from 150 to 300 and pinning the LSTM engine lifted recognized words from 21,335 to 23,719 on the same file. Wall clock went from 317s to 48s for that quality.\n\n## Get Fayner Brack’s stories in your inbox\n\nJoin Medium for free to get updates from this writer.\n\nGoing multilingual needed no language detection and no per-language model. Tesseract ships script bundles, one model per script family:\n\n```\n# one invocation reads whatever scripts are presenttesseract --psm 1 -l 'script/Latin+script/Arabic+script/HanS+script/Cyrillic' page.png -\n```\n\n`--psm 1`\n\nruns OSD per page and picks the right bundle per region. About 35 script packs cover 100+ languages. There is no detection step in the app code and no per-language branch.\n\nUnfortunately going multi-language increased the time to process significantly, so I disabled it.. a problem for another day.\n\nThen I made the opposite mistake. With Tesseract working, I cut the model out completely. The reader filled with correct words and no shape, every heading, list, and column flattened into one gray block. Tesseract reads letters. It does not know a heading from a sentence. That judgment is fuzzy, and fuzzy is the work an Artificial Intelligence model is good at ;).\n\nSo the model came back, for the job AFTER recognition. The residual errors were the probabilistic kind: cross-page hyphenations (`Veposi-`\n\nthen `tory`\n\n), and substitutions like `V↔D`\n\nand `m↔rn`\n\nthat survived because the misread was still a real word. Those are the shape a model is good at. Letter recognition from pixels is not.\n\nThe work split into three calls, each scoped tight.\n\n**Stage 1 — Per-Page Cleanup**\n\nOne chat completion per page. The prompt changes a word only above about 90% confidence, and leaves digits and proper nouns alone. A Lambda guardrail caps length delta at 30% and preserves the digit multiset, and on any rejection the original Tesseract text passes through unchanged.\n\n**Stage 2 - Document Diff Review**\n\nOne call per document. It sees the per-page word-level diff plus the full cleaned text, and emits APPROVE, REJECT, MODIFY, or NEW per change. A fix that landed on one page out of twelve gets rejected when eleven other pages show the original word correct.\n\n**Stage 3 — semantic HTML for Readability.js**\n\nOne call per page. It emits a sanitized fragment of `h2`\n\n, `h3`\n\n, `ul`\n\n, `ol`\n\n, `pre`\n\n, `code`\n\n, `blockquote`\n\n, and `table`\n\n, with text-pattern rules standing in for the visual cues a vision model would have used. A guardrail requires 70% visible-text retention, or the page falls back to plain `<p>`\n\nparagraphs of the Stage 2 text.\n\nThe infrastructure is four Lambdas, each sized to its stage:\n\nThe orchestrator fans out one Tesseract invocation and one cleanup call per page, up to 300 pages. Account concurrency is 1000, so the worst case uses about 30%. The Lambda client’s `maxSockets`\n\nis set to 400, well above the default of 50 that would otherwise queue invocations at the SDK layer. The model does not touch the raw reading. Tesseract still owns that.\n\nThe system is far from perfect (it will never be), but that's not the point:\n\nThis pattern is not special to Claude. The strongest AI products are not one model doing the whole job. They are a model wired next to a row of plain, predictable tools, each handling the part it does best. Coded by engineers that actually know the fuck they're doing.\n\nYou pay tokens to have Claude calling some CLI tools in sequence, like hiring a skilled engineer at scale.\n\nCheck the input, pick the tool that fits it, and keep the model back for the part only a model can handle. Throwing a model at every problem is an easy habit but a real engineer reaches for the tool built for the exact problem it's trying to solve.\n\nOk, all is good and great but… engineering is soo dead, so none of this really matters.. right?\n\n😢\n\nThink for a moment: Claude is quietly working inside a walled garden to charge usage premium for companies for a selection of tools to call in sequence.\n\nJust let that sink in.\n\nIf you liked this, you might like [readplace.com](https://readplace.com/view/fagnerbrack.com/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally-8ee45a533e80?utm_source=fagnerbrack.com&utm_content=bottom), built for exactly this kind of reading.\n\nThanks for reading. If you have some feedback, reach out to me on [LinkedIn](https://www.linkedin.com/in/fagnerbrack/), [Reddit](https://reddit.com/u/fagnerbrack) or [Github](https://github.com/FagnerMartinsBrack).\n\n**Further reading**\n\nA more detailed technical rebuild of my reader’s PDF pipeline, with the metrics and the full architecture (forever WIP): [https://readplace.com/blog/pdf-ocr-pipeline-tesseract-llm-hybrid?utm_source=fagnerbrack.com&utm_content=pdf-ocr-pipeline-tesseract-llm-hybrid](https://readplace.com/blog/pdf-ocr-pipeline-tesseract-llm-hybrid?utm_source=fagnerbrack.com&utm_content=pdf-ocr-pipeline-tesseract-llm-hybrid)\n\n**Additional Sources**\n\n- Tesseract history and origin dates.\n[https://github.com/tesseract-ocr/tesseract](https://github.com/tesseract-ocr/tesseract) - Anthropic Agent Skills, public repository.\n[https://github.com/anthropics/skills](https://github.com/anthropics/skills) - pytesseract, the Python wrapper for Tesseract.\n[https://github.com/madmaze/pytesseract](https://github.com/madmaze/pytesseract)", "url": "https://wpnews.pro/news/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally", "canonical_source": "https://fagnerbrack.com/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally-8ee45a533e80", "published_at": "2026-07-26 14:00:21+00:00", "updated_at": "2026-07-26 14:22:30.641767+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-tools", "ai-products", "computer-vision"], "entities": ["Anthropic", "Claude", "Tesseract", "PyTesseract", "HP Labs", "Google", "CIA"], "alternates": {"html": "https://wpnews.pro/news/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally", "markdown": "https://wpnews.pro/news/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally.md", "text": "https://wpnews.pro/news/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally.txt", "jsonld": "https://wpnews.pro/news/a-pdf-parser-from-the-80s-beats-claude-and-they-use-it-internally.jsonld"}}