pdf2image
pdf2image is a Python wrapper around Poppler's `pdfinfo`, `pdftoppm`, and `pdftocairo` command-line tools. It renders PDF pages from a path or bytes into Pillow Image objects, or writes images to disk and returns their paths. Callers can select page ranges, resolution, output size and format, grayscale or transparent output, passwords, crop boxes, thread count, timeouts, and either Poppler rendering backend. It does not parse or render PDFs itself.
pdf2image is a convenient adapter when Poppler is already an accepted system dependency and the goal is simply pages as Pillow images. For self-contained deployment, deeper PDF work, or long-term active maintenance, evaluate PyMuPDF or pypdfium2 first.
Use it if
- Your deployment already has Poppler and you want a small Python API that returns ordinary Pillow images
- You need thumbnails, OCR inputs, previews, or page images rather than PDF text extraction or document editing
- You want to limit conversion by page range, DPI, pixel size, format, timeout, and output directory
- You need to avoid loading a large document into Python memory by returning generated file paths
- You cannot install operating-system packages: pip installs Pillow but not the Poppler executables that the README requires on Windows, macOS, and many Linux images
- You need an actively shipping wrapper: PyPI 1.17.0 was released in January 2024 and the repository's last push was in July 2024
- You need a self-contained wheel or serverless layer: Poppler binaries and their shared libraries make deployment larger and platform-specific
- You convert large PDFs entirely in memory: the README warns that a relatively big document can exhaust memory unless an output folder is used
- You need faithful handling of every signed or annotated PDF: the README calls out failures with some DocuSign files, and the source rejects `hide_annotations=True` with the pdftocairo backend
Setup reality
`pip install pdf2image` installs the Python wrapper and Pillow, but the first call still fails unless Poppler's `pdfinfo` plus `pdftoppm` or `pdftocairo` are executable. On macOS the README uses `brew install poppler`; on Debian-family Linux images install the package that provides `poppler-utils`; on Windows download or build Poppler, add its `bin` directory to PATH, or pass `poppler_path` on every call. That external binary version changes supported flags and rendering behavior. The wrapper quietly disables `jpegopt` on Poppler 0.57 and older and annotation hiding on 0.83 and older. By default conversion uses 200 DPI, PPM, one worker, and returns a Pillow image for every page, a combination that can consume a great deal of RAM. For untrusted or large documents set a page range, pixel `size`, a finite `timeout`, and an `output_folder`; add `paths_only=True` so images are not reopened into memory. Keep temporary output alive until all returned paths are consumed. The README recommends no more than four threads because I/O becomes the bottleneck, and PNG compression is specifically described as slow. `use_pdftocairo=True` may be faster and is required by some output modes, but it cannot hide annotations and changes default PPM requests to PNG internally. `strict=False` ignores Poppler syntax warnings; use strict mode only if a warning should reject the document. Passwords are passed to a child process, so treat host process visibility and logs as part of the threat model. Conversion is rasterization, not sanitization: set resource limits around hostile PDFs and never assume success means the source was safe or semantically intact.
Patterns
Render every page from a fileconvert-pdf-path
from pdf2image import convert_from_path
pages = convert_from_path('report.pdf', dpi=150)
for number, image in enumerate(pages, start=1):
image.save(f'page-{number}.png')The result keeps every Pillow image in memory. Use an output directory and paths_only for large documents.
Render an uploaded PDF byte stringconvert-pdf-bytes
from pdf2image import convert_from_bytes
pages = convert_from_bytes(
upload_bytes,
dpi=144,
first_page=1,
last_page=3,
timeout=30,
)The PDF bytes and rendered images coexist in memory. Enforce upload and page limits before conversion.
Return disk paths instead of Pillow imagesavoid-large-pdf-memory
from pathlib import Path
from pdf2image import convert_from_path
output_dir = Path('/var/tmp/rendered-pages')
output_dir.mkdir(parents=True, exist_ok=True)
paths = convert_from_path(
'large.pdf',
output_folder=output_dir,
paths_only=True,
fmt='jpeg',
dpi=120,
)paths_only requires output_folder. Clean the files after use and place the directory on storage with enough space.
Bound memory with a temporary output directoryuse-temporary-output
from tempfile import TemporaryDirectory
from PIL import Image
from pdf2image import convert_from_path
with TemporaryDirectory() as directory:
paths = convert_from_path(
'report.pdf', output_folder=directory, paths_only=True
)
for path in paths:
with Image.open(path) as image:
consume(image.copy())Returned paths become invalid when the context exits. Finish reading or copy the required files before TemporaryDirectory cleanup.
Render only selected pagesrender-page-range
pages = convert_from_path(
'appendix.pdf',
first_page=10,
last_page=15,
dpi=200,
)Page numbers are one-based and inclusive. If first_page ends up greater than last_page, the implementation returns an empty list.
Fit the first page into a thumbnail boxcreate-thumbnail
thumbnail = convert_from_path(
'brochure.pdf',
first_page=1,
last_page=1,
size=400,
fmt='jpeg',
jpegopt={'quality': 82, 'optimize': True},
)[0]An integer size fits within a square while preserving aspect ratio. A two-number tuple forces that exact shape and may distort the page.
Render a page with transparencyrender-transparent-png
pages = convert_from_path(
'overlay.pdf',
fmt='png',
transparent=True,
use_pdftocairo=True,
)Transparency is supported only for PNG and TIFF-style outputs and selects the pdftocairo path. It can be slower than JPEG.
Open a password-protected documentrender-password-pdf
pages = convert_from_path(
'protected.pdf',
userpw=user_password,
ownerpw=owner_password,
first_page=1,
last_page=1,
)Passwords are passed to Poppler child processes. Do not log the generated command or retain credentials longer than necessary.
Stop a slow or hostile conversionenforce-conversion-timeout
from pdf2image import convert_from_path
from pdf2image.exceptions import PDFPopplerTimeoutError
try:
pages = convert_from_path('input.pdf', timeout=20)
except PDFPopplerTimeoutError:
quarantine('input.pdf')The timeout kills Poppler and raises PDFPopplerTimeoutError. Pair it with process memory and file-size limits for untrusted input.
Treat Poppler syntax warnings as failuresreject-pdf-syntax-errors
from pdf2image import convert_from_path
from pdf2image.exceptions import PDFSyntaxError
try:
pages = convert_from_path('input.pdf', strict=True)
except PDFSyntaxError as error:
print(f'PDF rejected: {error}')strict defaults to False. Enabling it can reject PDFs that Poppler might otherwise render despite syntax warnings.
Read Poppler's page information before renderinginspect-pdf-metadata
from pdf2image import pdfinfo_from_path
info = pdfinfo_from_path('report.pdf', timeout=10)
page_count = info['Pages']
if page_count > 200:
raise ValueError('Document is too long')This still invokes the external pdfinfo executable. Metadata inspection should also have a timeout for untrusted files.
Point Windows at a Poppler installationset-windows-poppler-path
from pdf2image import convert_from_path
pages = convert_from_path(
r'C:\documents\report.pdf',
poppler_path=r'C:\tools\poppler\Library\bin',
first_page=1,
last_page=1,
)poppler_path must contain the Poppler executables, including pdfinfo and a renderer. pip does not install them.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| pymupdf | PyPI | You want fast PDF rendering plus text extraction, annotations, editing, and a broader document API |
| pypdfium2 | PyPI | You prefer PDFium-backed rendering with platform wheels instead of shelling out to Poppler tools |
| Wand | PyPI | Your stack already uses ImageMagick and needs one image API across PDF and many raster formats |
| pillow | PyPI | You only manipulate images that are already rasterized and do not need a PDF renderer |