mrkeyoor.com_
Sun 20 Sept 11:47 UTC
PyPIDataupdated 20 Sept 2026

pypdfium2 review

pypdfium2 5.13.0 is a Python binding to Google's PDFium C library, with helper classes above the raw ctypes interface. It opens PDFs, renders pages to bitmaps, reads text and coordinates, searches text, walks bookmarks, imports or deletes pages, and saves documents. Rendering and low-level inspection are its center of gravity; it does not reconstruct tables or reading order for you. Version 5.13 restores Python 3.6 and 3.7 compatibility after cached-property changes and adds experimental Pyodide artifacts. The maintainers do not publish those browser artifacts to PyPI because their own notes report crashes and shutdown freezes.

Verdict

pypdfium2 5.13.0 installed as one 9 MB package in 0.2 seconds and imported in 0.26 seconds with 0 audit findings in our sandbox. It is the practical permissive choice for rendering and PDFium-level inspection, but avoid it for threaded rendering, browser deployment, or automatic document-layout recovery.

We installed it

Lab card: what happened when we installed pypdfium2Screenshot of pypdfium2 documentation
Install✓ · 0.2s1 package on disk · 9 MB
Importimport pypdfium2 in 0.26s · compiled extensions · requires Python >= 3.6
Known vulns0(pip-audit)

Answers from our run

Does pypdfium2 install cleanly?

Yes. In a fresh container with an empty cache, pip install pypdfium2 finished in 0.2s, leaving 1 package and 9 MB on disk. pip-audit reported no known vulnerabilities.

What does pypdfium2 need to run?

Python >= 3.6, and a platform wheel with compiled extensions. In our run import pypdfium2 succeeded in 0.26s.

pypdfium2 or pypdf: which should you use?

pypdf: Choose it for pure-Python splitting, merging, metadata, forms, and page transforms when raster rendering is unnecessary. pypdfium2 5.13.0 installed as one 9 MB package in 0.2 seconds and imported in 0.26 seconds with 0 audit findings in our sandbox.

When should you not use pypdfium2?

You need high-level table extraction or reliable multi-column reading order. PDFium exposes text and geometry, leaving document structure to your code.

API stability3/5PdfDocument, PdfPage, PdfBitmap, PdfTextPage, rendering, and page import form a usable helper layer, yet their correctness depends on native handle lifetimes. Raw calls also track PDFium APIs, including functions outside upstream's stable tier. Pin pypdfium2 and test close order, imports, saved output, and every raw function during upgrades rather than assuming Python-level compatibility is enough.
Docs4/5The official docs explain wheel platforms, PDFium selection, source builds, helper objects, raw bindings, rendering scale, text extraction, object ownership, and thread limits. Version 5.13's notes plainly flag unstable Pyodide and s390x work. Advanced raw calls still send readers to PDFium header comments, and the many build routes make packaging guidance dense for uncommon targets.
Maintenance5/5GitHub shows a push on August 24, 2026, an unarchived repository, and only 3 open issues and pull requests. Release 5.13.0 updates the bundled PDFium line, restores old-Python behavior, and records experimental platform failures instead of presenting them as supported. The project also publishes a wide wheel matrix, though each release inherits the security and behavior changes of upstream PDFium.
Ecosystem4/5The package records about 16.8 million weekly downloads while GitHub reports 813 stars, a pattern consistent with substantial transitive use in document pipelines. Optional Pillow and NumPy adapters connect rendered buffers to common imaging tools. Python PDF work is still fragmented: pypdf handles structure, pdfplumber targets extraction, and PyMuPDF offers a broader API under different licensing.

Use it if

  • PDF pages must become thumbnails, previews, OCR images, or visual-test inputs through PDFium.
  • A permissive license is required and PyMuPDF's AGPL or commercial terms do not fit.
  • The job needs character boxes, text search, outlines, page import, or access to a missing raw PDFium function.
  • Your deployment target has an official wheel that can carry PDFium without a system PDF installation.
Skip it if

Setup reality

Our pypdfium2 5.13.0 install finished in 0.2 seconds in a fresh Python 3.12 Bookworm container. One package used 9 MB, import pypdfium2 worked in 0.26 seconds, and pip-audit found 0 known vulnerabilities. It declares 0 direct dependencies and Python >=3.6. The installed wheel contains compiled .so files and no py.typed marker. Package metadata lists BSD-3-Clause, Apache-2.0, and dependency licenses.

On a supported platform, the wheel carries PDFium and needs no service, credentials, or config. Pillow is optional but required for bitmap.to_pil(); NumPy is likewise optional for to_numpy(). If pip cannot find a wheel, setup may download a PDFium binary, locate a system copy, or start a source build. System PDFium requires bindings generated against matching headers because an ABI mismatch can crash Python.

Helper objects own native handles. Close search objects, text pages, bitmaps, pages, and documents in parent-safe order, preferably through context managers. A NumPy result may view a PdfBitmap buffer, so using it after the bitmap is closed can access invalid memory. Keep source documents alive until a destination that imported their pages has been saved.

Rendering scale is pixels per PDF point, so target DPI is dpi / 72. PDFium is not thread-safe; process workers must each open their own PdfDocument. Text extraction follows content-stream order and scanned pages contain no searchable text until another OCR tool supplies it. Treat an untrusted PDF as native-parser input: cap bytes, pages, render dimensions, CPU, and memory, and isolate the worker process.

Patterns

Inspect a PDF inside a context manager open-document

import pypdfium2 as pdfium

with pdfium.PdfDocument('report.pdf') as pdf:
    print(len(pdf))
    print(pdf.get_metadata_dict(skip_empty=True))
    print(pdf[0].get_size())

The constructor also accepts bytes and a password. The context manager releases the native document handle.

Render page 1 at 200 DPI render-png

import pypdfium2 as pdfium

with pdfium.PdfDocument('report.pdf') as pdf:
    bitmap = pdf[0].render(scale=200 / 72)
    bitmap.to_pil().save('page-1.png')

PDF coordinates use 72 points per inch. `to_pil()` needs Pillow, which is not a base dependency.

Read text from one page extract-text

with pdfium.PdfDocument('report.pdf') as pdf:
    with pdf[0].get_textpage() as text_page:
        text = text_page.get_text_range()
        print(text)

Returned order follows the PDF content stream. Multi-column pages may need region-based extraction.

Read text inside page coordinates extract-region

with pdf[0].get_textpage() as text_page:
    header = text_page.get_text_bounded(left=0, bottom=700, right=595, top=842)

Bounds are PDF canvas units. Confirm page rotation and coordinate origin against a sample document.

Walk text-search matches search-text

with page.get_textpage() as text_page:
    search = text_page.search('invoice', match_case=False)
    while (hit := search.get_next()) is not None:
        index, count = hit
        print(text_page.get_text_range(index, count))

A hit gives a character index and length, not a rectangle. Resolve character boxes separately when highlighting.

Isolate parallel page rendering render-in-processes

from concurrent.futures import ProcessPoolExecutor

def render_one(index):
    with pdfium.PdfDocument('report.pdf') as pdf:
        pdf[index].render(scale=2).to_pil().save(f'page-{index}.png')

with ProcessPoolExecutor() as pool:
    list(pool.map(render_one, range(page_count)))

Each process opens its own document because PDFium is not thread-safe. Do not substitute ThreadPoolExecutor.

Merge selected pages import-pages

with pdfium.PdfDocument('a.pdf') as first, pdfium.PdfDocument('b.pdf') as second:
    with pdfium.PdfDocument.new() as output:
        output.import_pages(first)
        output.import_pages(second, pages=[0, 2])
        output.save('merged.pdf')

Keep both sources open until save finishes because imported pages may still depend on source handles.

Pass grayscale pixels to OCR bitmap-to-numpy

with pdfium.PdfDocument('scan.pdf') as pdf:
    bitmap = pdf[0].render(scale=300 / 72, grayscale=True)
    pixels = bitmap.to_numpy()
    text = run_ocr(pixels)

The array can share the bitmap buffer. Consume it before closing the bitmap or call copy() for independent storage.

Print the document outline walk-bookmarks

with pdfium.PdfDocument('book.pdf') as pdf:
    for item in pdf.get_toc(max_depth=12):
        destination = item.get_dest()
        page_index = destination.get_index() if destination else None
        print(item.level, item.get_title(), page_index)

Some outline entries trigger actions instead of page destinations, so get_dest() may return None.

Delete pages without shifting targets delete-pages

with pdfium.PdfDocument('scan.pdf') as pdf:
    for index in sorted([1, 4, 7], reverse=True):
        del pdf[index]
    pdf.save('trimmed.pdf')

Delete from the highest index downward so an earlier removal does not change a later target.

Read the PDF file version through ctypes call-raw-api

import ctypes
import pypdfium2.raw as pdfium_c

version = ctypes.c_int()
ok = pdfium_c.FPDF_GetFileVersion(pdf, version)
print(version.value if ok else None)

Raw calls follow C ownership and pointer rules. A wrong signature or expired buffer can crash the interpreter.

Alternatives

PackageRegistryPick it when
pypdfPyPIChoose it for pure-Python splitting, merging, metadata, forms, and page transforms when raster rendering is unnecessary.
pymupdfPyPIChoose its broader high-level PDF and document API when AGPL or commercial licensing is acceptable.
pdfplumberPyPIChoose it for word geometry and table-oriented extraction rather than fast PDFium rendering.

More data guides

numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.