Tools,

How to convert a scanned PDF to text: three free ways, tested

First check if the PDF already has text. If it does not, it is a picture of paper, and you need OCR. On my test scan, turning the page into an image and running Tesseract matched 0.964 of the words, in about 6 seconds, for $0. OCRmyPDF took about 1.4 seconds and scored 0.937. Both are free and run on your own computer.

Install the free tools

You need three free, open source tools: Poppler (for pdftotext and pdftoppm), Tesseract and OCRmyPDF. I tested on a Mac.

# Mac (Homebrew)
brew install poppler tesseract ocrmypdf

# Debian or Ubuntu
sudo apt install poppler-utils tesseract-ocr ocrmypdf

1. Check for a text layer first

A PDF made by a computer (an export from Word, a bank statement, a form) usually has its text inside already. Then you need no OCR, and you get no OCR mistakes:

pdftotext -layout file.pdf file.txt

On a test invoice PDF we made, this read all 36 numbers exactly, in under 0.01 seconds. On my scanned page it gave 0 words. Empty output, or only page numbers, means a scan.

2. Turn each page into an image, then run Tesseract

Tesseract reads images, not PDFs. So first render every page at 300 dpi, then read each image:

pdftoppm -r 300 -png scan.pdf page
for f in page-*.png; do tesseract "$f" - --dpi 300; done > scan.txt

On my test page this gave 198 words and a word match of 0.964. The render took 5.5 seconds and the OCR 0.63 seconds. Keep --dpi 300: on a scanned invoice, a missing dpi took Tesseract from 24 numbers right to 0 (details in how to improve Tesseract accuracy).

Tesseract keeps the line breaks of the paper and splits words at line ends, such as "util- ities". One line of Python joins them, and the word match went from 0.964 to 0.979:

import re

text = re.sub(r"-\n(\w)", r"\1", open("scan.txt").read())

It also joins a real hyphen that falls at a line end, so check a few lines by eye.

3. OCRmyPDF: a searchable PDF and a text file at once

ocrmypdf --sidecar scan.txt scan.pdf scan-ocr.pdf

This writes the text to scan.txt and also makes a copy of the PDF that you can search and copy from. It was the fastest route: 1.3 to 1.45 seconds for the page. It scored lower, 0.937. It read the marks at the top of my page as 4 junk words, and on faint ink it read "nationel" and "end" for "and", where the route above got them right.

If a PDF already has text, OCRmyPDF stops and says so. Add --skip-text to OCR only the scanned pages, or --force-ocr to redo every page.

The results side by side

One test page: page 1 of Executive Order 9066, typed in 1942, a public domain 300 dpi scan, saved as a one-page PDF with no text in it.

Route Time Word match
pdftotext alone under 0.01 s 0 words (no text layer)
pdftoppm, then tesseract 6.1 s 0.964
Same, then join split words 6.1 s 0.979
ocrmypdf --sidecar 1.3 to 1.45 s 0.937
Our Apify Actor's pipeline (October 29, on the Mac) not timed 0.985

Word match is the share of words that line up, in order, with an earlier transcript of the same page. 1.000 would mean identical. That is one clean typed page. A faded, tilted or two-column scan will score lower with every tool.

Numbers are where scans go wrong

Words with a wrong letter are easy to spot. Numbers are not. On a scanned test invoice with 36 numbers, plain Tesseract with the dpi set read 24 right. In an earlier run on the same page, some lost their decimal point: 78.64 became 7864, a wrong number that looks right.

Our Actor reads each table cell on its own and checks the math (Qty times Unit price must equal Amount). It got 33 of 36 on my Mac and 32 of 36 on Apify, and it flagged every number it got wrong. More in PDF table to Markdown. If your scans have money in them, check the totals yourself whatever tool you use.

What I did not test

For many files, or from your code

The last row of the table is PDF OCR to Markdown, our Apify Actor. It reads a PDF's own text where there is some, and uses OCR only on scanned pages. Set outputFormat to text to get plain text instead of Markdown. Paste PDF or image links, or upload a file. You also get each page on its own, with its warnings.

Want Markdown, with headings and tables? See how to turn a scanned PDF into Markdown. Feeding scans to an AI? See OCR PDF to Markdown for RAG. A screenshot, not a PDF? See image to Markdown.

How this was made: Tack, our AI personality, ran Poppler's pdftotext and pdftoppm, Tesseract 5.5.3 and OCRmyPDF 17.13.0 on a Mac on October 30, 2026, twice each, and copied the times and scores above from those runs. The word match uses the same scoring as our Actor's tests. The Actor row is from its October 29 test on the same Mac. The typed page is a public domain scan from Wikimedia Commons, and we made the test invoice. We make the Apify Actor. Poppler, Tesseract and OCRmyPDF are free, open source tools that we do not make.