This script converts a PDF to a plain-text file by rendering every page as an image and running Tesseract OCR over it. That works for scanned documents that have no embedded text layer. The sections below explain the pipeline, the code, tuning options, and when a direct text extractor is the better tool.
To use this script on Ubuntu, you need to install the following dependencies:
sudo apt update
sudo apt install poppler-utils tesseract-ocr
pip install pdf2image pytesseract Pillow
Use the following Python script to convert a PDF file to text using OCR:
#!/usr/bin/env python
from pdf2image import convert_from_path
import pytesseract
#-----------------------------------------------------------------#
# Specify the path to the Tesseract executable
pytesseract.pytesseract.tesseract_cmd = r'/usr/bin/tesseract'
#-----------------------------------------------------------------#
def pdf_to_text_with_ocr(pdf_file, text_file):
# Convert PDF pages to images
images = convert_from_path(pdf_file)
# Initialize empty string to store the text
text_content = ""
# Extract text from each image using OCR
for image in images:
text_content += pytesseract.image_to_string(image)
# Save the extracted text to a file
with open(text_file, 'w') as output_file:
output_file.write(text_content)
print(f"Text extracted and saved to {text_file}")
#-----------------------------------------------------------------#
pdf_to_text_with_ocr('Abram-Hoffer-Orthomolecular-Medicine.pdf',
'Abram-Hoffer-Orthomolecular-Medicine.txt')
To use this script:
pdf_to_text.py).python3 pdf_to_text.py
This will convert the PDF to a text file using OCR.
convert_from_path from pdf2image calls Poppler's pdftoppm to rasterize each page into a Pillow image. pytesseract.image_to_string passes each image to the Tesseract binary and returns recognized text. The script writes the text of each page to the output file in order. The two system packages installed with apt provide those binaries; the pip packages are thin Python wrappers around them, which is why both installation steps are required.
Many PDFs, such as those exported from word processors, already contain a text layer. For those, OCR is slower and less accurate than reading the text directly with pdftotext or pypdf. OCR is needed for scans, photographed pages, and PDFs that were printed to image. A robust ingestion job tries direct extraction first and falls back to OCR for pages that return little or no text.
OCR quality depends mostly on the image. Tesseract works best on clean, high-contrast, horizontally aligned text at a resolution where capital letters are roughly 20 to 30 pixels tall. Scanned faxes, photographs taken at an angle, coloured backgrounds, and handwriting reduce accuracy sharply. Because the script treats every page the same way, it is also worth checking the output of a few representative pages before running it over a large archive.
Speed is the other consideration. Rasterizing and recognizing a page typically takes on the order of a second or more on a CPU, so a large archive benefits from parallelism. Pages are independent, so a concurrent.futures.ProcessPoolExecutor over page numbers, or over files, scales close to linearly with cores. Tesseract itself may use several threads per page; setting the environment variable OMP_THREAD_LIMIT=1 avoids oversubscribing the CPU when you parallelize at the process level.
from pathlib import Path
from pdf2image import convert_from_path, pdfinfo_from_path
import pytesseract
def pdf_to_text(pdf: str, out: str, dpi: int = 300, lang: str = "eng") -> None:
pages = pdfinfo_from_path(pdf)["Pages"]
with open(out, "w", encoding="utf-8") as fh:
for p in range(1, pages + 1): # one page at a time keeps memory flat
img = convert_from_path(pdf, dpi=dpi, first_page=p, last_page=p)[0]
text = pytesseract.image_to_string(img, lang=lang, config="--psm 3")
fh.write(f"\n--- page {p} ---\n{text}")
if __name__ == "__main__":
import sys
src = sys.argv[1]
pdf_to_text(src, str(Path(src).with_suffix(".txt")))
python pdf_ocr.py scanned-report.pdf # writes scanned-report.txt
pdftotext -layout digital.pdf out.txt # faster path when a text layer exists
sudo apt install tesseract-ocr-deu # extra language packs, then lang="deu"
Rendering all pages at once, as convert_from_path(pdf) does by default, holds every page image in memory; a 300-page scan at 300 DPI can use several gigabytes. Converting page by page, or passing output_folder so images are written to disk, avoids that.
--psm 6 assumes a single text block, --psm 4 a single column; multi-column layouts may need cropping first.lang="eng+fra" for mixed documents.For ingestion into a search index or a retrieval-augmented generation pipeline, keep the page markers in the output. They let you cite the source page in answers and re-run OCR on individual pages that turned out badly, without reprocessing the whole document.
PDFInfoNotInstalledError means Poppler is missing or not on PATH.TesseractNotFoundError means the binary is missing; set pytesseract.pytesseract.tesseract_cmd if it is in a non-standard location.image_to_data for word boxes, or a layout-aware tool, if structure matters.Treat OCR text as a best-effort transcription: spot-check it, keep the source PDF, and record which pages were OCR-processed.