Tesseract OCR for PDFs
and searchable PDFs.
The complete, tested guide to OCRing PDFs with Tesseract: rasterizing pages, creating searchable PDFs, using OCRmyPDF and pdfsandwich, running it end-to-end in Python, and fixing the errors people actually hit.
TL;DR (one command)
For a real multi-page PDF, OCRmyPDF is the fastest path.
pip install ocrmypdf # or: apt install ocrmypdf
ocrmypdf input.pdf output.pdfNo OCRmyPDF? Rasterize and use the Tesseract CLI directly — see below.
Why PDFs must be rasterized
Tesseract recognises images, not PDF containers.
A PDF is a container: it may hold vector text, embedded fonts, or scanned page images. Tesseract reads raster images (TIFF, PNG, JPEG, WebP, …), so PDF pages must be converted to images first. Choose the rasterizer based on what you have installed:
| Tool | Install | Notes |
|---|---|---|
pdftoppm (poppler) | apt install poppler-utils | Fast, scriptable, the classic choice |
pdftocairo (poppler) | poppler-utils | Similar to pdftoppm, Cairo output |
| ImageMagick | apt install imagemagick | convert -density 300 in.pdf out.tif |
| PyMuPDF | pip install pymupdf | Pure Python, no external binaries |
| pdf2image | pip install pdf2image | Python wrapper around poppler |
# PDF -> one PNG per page at 300 DPI
pdftoppm -png -r 300 input.pdf pageDPI matters most: 300 DPI is the standard balance; 600 DPI for small fonts or archival work; avoid below 200 DPI where accuracy drops sharply.
Create a searchable PDF with the Tesseract CLI
One image becomes one searchable PDF page with the pdf output config.
# Image -> searchable PDF
tesseract page-1.png out pdf
# Text layer only (no visible image)
tesseract scan.png out textonly_pdf
# Multiple pages into one searchable PDF: pass a list of images
tesseract imagelist.txt out pdfFor a multi-page PDF, put each image path on its own line in imagelist.txt. Full CLI output-format reference: documentation.
Method B — OCRmyPDF (recommended for real PDFs)
OCRmyPDF handles rasterizing, OCR, deskewing, rotation and the invisible text layer in one command.
ocrmypdf input.pdf output.pdf # basic
ocrmypdf -l eng+deu input.pdf output.pdf # languages
ocrmypdf --deskew --rotate-pages input.pdf output.pdf
ocrmypdf --optimize 2 input.pdf output.pdf # shrink the file
ocrmypdf --skip-text input.pdf output.pdf # keep pages that already have textOCRmyPDF uses Tesseract under the hood and requires Ghostscript and the poppler tools. Useful flags: --force-ocr, --redo-ocr, --pages 1-10.
Method C — pdfsandwich
A lighter wrapper that adds a text layer and performs preprocessing such as deskewing.
pdfsandwich scanned.pdf # produces scanned_ocr.pdf
pdfsandwich -lang eng+fra scanned.pdfMethod D — Python end-to-end
Use pdf2image to rasterize and pytesseract to build the searchable PDF, then merge with pypdf.
import io, pytesseract
from pdf2image import convert_from_path
from pypdf import PdfWriter, PdfReader
pages = convert_from_path("input.pdf", dpi=300) # needs poppler
writer = PdfWriter()
for page in pages:
pdf_bytes = pytesseract.image_to_pdf_or_hocr(page, extension="pdf", lang="eng")
writer.add_page(PdfReader(io.BytesIO(pdf_bytes)).pages[0])
with open("output.pdf", "wb") as f:
writer.write(f)On Windows, pass the poppler bin folder via poppler_path=. More Python detail in the pytesseract guide.
Which method should I use?
| Method | Best for | Setup | Multi-page |
|---|---|---|---|
| OCRmyPDF | Real PDFs, automation | Ghostscript + poppler | Yes, in one command |
| pdfsandwich | Quick text layer with preprocessing | poppler + ImageMagick | Yes |
| Tesseract CLI | Images or image lists | Just Tesseract | Via an image list |
| Python (pdf2image) | Pipelines and custom logic | poppler + pytesseract | Loop and merge |
Layout fidelity and text overlay
Why searchable PDFs sometimes look misaligned, and how to keep geometry accurate.
- The invisible text layer is placed using OCR word boxes; if the image DPI is wrong, the overlay can drift.
- Use
hOCRorALTOoutput when you need exact word coordinates for highlighting or archival. pdftoppm -r 300and matching the original page size keeps the overlay aligned.- For complex layouts, prefer OCRmyPDF, which preserves the original page raster and adds the layer in place.
Quality and performance
- DPI: 300 standard, 600 for small text or archiving.
- Page ranges: process only what you need (
--pagesin OCRmyPDF, or slice the image list). - Parallelism: OCR pages independently in parallel, then merge.
- File size: use
--optimize/ JPEG compression, or downsample after OCR. - Preprocessing: deskew and denoise before OCR for noticeably better results.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Unable to get page count. Is poppler installed? | pdf2image cannot find poppler | Install poppler-utils, or set poppler_path on Windows. |
| Output PDF has no searchable text | OCR did not run or used the wrong language | Confirm success and set -l/--language to the document language. |
| Text overlay is misaligned | Wrong DPI or page size | Rasterize at 300 DPI matching the original size. |
| Output file is huge | Lossless 600 DPI images | Use --optimize / JPEG, or reduce DPI. |
| Password-protected PDF fails | Encrypted input | Decrypt first, or pass the password flag supported by your tool. |
PDF FAQ
How do I make a PDF searchable?
Use ocrmypdf input.pdf output.pdf, or rasterize the pages and run tesseract page.tif out pdf.
Why can't Tesseract read a PDF directly?
Tesseract recognises raster images, so PDF pages must be converted to images first.
What DPI should I use?
300 DPI for most documents; 600 DPI for small fonts or archiving.
Can I OCR a PDF in Python?
Yes — use pdf2image with poppler and pytesseract.image_to_pdf_or_hocr, then merge pages with pypdf.
How do I keep the layout accurate?
Match the original page size and DPI, and prefer OCRmyPDF, which preserves the original raster and adds the text layer in place.