pdf2image
A Python wrapper around poppler's pdftoppm and pdftocairo that converts PDF files into a list of Pillow Image objects.
Repository Health
Technical Analysis
pdf2image is a thin Python wrapper around the poppler-utils command-line tools pdftoppm and pdftocairo, letting you convert PDF documents into Pillow (PIL) Image objects with a couple of function calls. It doesn’t reimplement PDF rendering itself — it shells out to the same battle-tested poppler binaries that ship with most Linux distros and are installable via Homebrew on macOS or a standalone build on Windows, then parses the raw PPM/PGM/JPEG/PNG output back into Pillow images (or writes them straight to disk).
The two entry points, convert_from_path and convert_from_bytes, cover the common cases of having a PDF on disk versus in memory (e.g. an upload buffer), and both accept the same rich set of keyword arguments: DPI, page ranges, output format, grayscale, transparency, cropbox usage, password-protected PDFs, multi-threaded rendering, and a paths_only mode that avoids loading everything into memory at once for large documents. A companion pair of functions, pdfinfo_from_path / pdfinfo_from_bytes, exposes poppler’s pdfinfo output (page count, page size, PDF version, etc.) as a plain dictionary.
It’s a popular building block behind OCR pipelines, PDF thumbnail generators, and document-preview features — anywhere a PDF needs to become an image before further processing with Pillow, Tesseract, or a computer-vision model.
What You Get
convert_from_path()andconvert_from_bytes()to turn a PDF on disk or in memory into a list of Pillow images in one callpdfinfo_from_path()/pdfinfo_from_bytes()to read page count, page size, and other PDF metadata via poppler’spdfinfo- Fine-grained render controls: DPI, first/last page range, grayscale, transparency, cropbox, output format (ppm/jpeg/png/tiff), and image
sizeresizing - Multi-threaded conversion via
thread_count, with an internal thread-safe filename generator to keep output files from colliding - Support for password-protected PDFs (
userpw/ownerpw) and a configurabletimeoutthat raisesPDFPopplerTimeoutErrorinstead of hanging - A
paths_onlymode that writes pages to an output folder and returns file paths instead of loading every page into memory, useful for very large PDFs
Common Use Cases
- Rendering PDF pages to images before running OCR (e.g. with Tesseract) to extract text from scanned documents
- Generating page thumbnails or previews for a document-management or file-upload UI
- Feeding PDF pages into computer-vision or ML pipelines that expect image input rather than PDF
- Batch-converting archives of PDFs into PNG/JPEG image sets for indexing or display
- Extracting a single page or page range from a PDF as an image without opening the whole document in memory
Under The Hood
Architecture
The library is a thin single-purpose wrapper: pdf2image.py holds two public conversion functions (convert_from_path, convert_from_bytes) that both funnel into the same internal pipeline — normalize arguments, resolve the poppler command (pdftoppm or pdftocairo) and its version via _get_poppler_version, build a CLI argument list with _build_command, spawn one or more subprocess.Popen processes per thread_count, then hand the raw stdout bytes to a format-specific parser in parsers.py (parse_buffer_to_ppm/_pgm/_jpeg/_png) that slices poppler’s concatenated output back into individual Pillow images. convert_from_bytes is a shim that writes the buffer to a temp file and calls convert_from_path, so there is effectively one code path. A small generators.py module supplies thread-safe output-filename generators (uuid_generator, counter_generator) so concurrent subprocess writes never collide. If poppler’s binaries or version change behavior, nearly everything downstream (parsing, flags, hide_annotations gating) is affected, since there is no abstraction layer between the CLI output format and the parsing logic.
Tech Stack
The only runtime dependency declared in setup.py is pillow, which pdf2image uses purely as the image container (PIL.Image.open on the parsed byte buffers); it does no PDF parsing of its own and instead shells out to poppler-utils (pdftoppm, pdftocairo, pdfinfo) via the standard library’s subprocess. Packaging is classic setuptools (setup.py + setup.cfg, find_packages), targeting Python 3.7+ with a py.typed marker for type-checker support. CI runs on CircleCI using a Docker-based Python image, installing poppler-utils at the OS level before running the test suite, then re-running tests with poppler uninstalled to verify the library’s own error path (PDFInfoNotInstalledError) rather than crashing.
Code Quality
Tests live in a single root-level tests.py (not a tests/ package) using unittest, with @unittest.skipIf(not POPPLER_INSTALLED, ...) guards so the suite still runs meaningfully in environments without poppler installed, plus an optional memory_profiler-based profiling decorator gated behind a PROFILE_MEMORY env var. Error handling is explicit and typed via a small custom exception hierarchy (PopplerNotInstalledError, PDFInfoNotInstalledError, PDFPageCountError, PDFSyntaxError, PDFPopplerTimeoutError) rather than letting subprocess or OS errors leak through unwrapped. Type hints are used throughout the public functions and a py.typed marker is shipped, though there’s no configured linter/formatter (no ruff/black/flake8 config found in the repo) and no mypy config, so type coverage isn’t enforced in CI beyond what CircleCI’s python3 tests.py run exercises.
API Design
The public surface is intentionally small — four functions, all synchronous, all returning either a list of Pillow images or a plain dict — which keeps the getting-started cost low: convert_from_path('file.pdf') is a complete, working call with sane defaults (200 DPI, PPM format, single-threaded). Keyword arguments are extensive (DPI, page range, format, threading, password, cropbox, transparency, grayscale, size, timeout, paths_only) but all optional with documented defaults, so advanced use doesn’t complicate the basic case. The trade-off is that behavior is coupled to the installed poppler version — some flags (jpegopt, hide_annotations) are silently disabled below certain poppler versions rather than raising, which favors graceful degradation over explicit feedback when a caller’s environment doesn’t support a requested option.
Used by 3 apps in this directory
cocoindex
Data Engineering · AI Development
An incremental data indexing engine that keeps AI agent context perpetually fresh by reprocessing only what changed.
Morphik
AI Development · Search · Databases
Morphik is an AI-native ingestion and retrieval engine that lets developers store, search, and reason over visually rich documents — scanned PDFs, manuals, slides, and video — without duct-taping together OCR, an embedding model, and a vector database.
Paperless-ngx
Bookmarks Archiving
Turn your paper pile into a searchable digital archive with OCR, AI classification, and automated workflows — all running on your own server.