pdfboss.dev

Python

Fast PDF text extraction in Python.

pip install pdfboss puts a PDF engine written in Rust behind a small Python API: text, Markdown, styled spans, page rendering to PNG, PPM, BMP or JPEG, embedded images, and async reading straight from a URL. Prebuilt abi3 wheels for CPython 3.12 and later, no C toolchain, MIT OR Apache-2.0.

$pip install pdfbossAdd pdfboss[full] for substitute fonts when rendering PDFs that do not embed theirs.

Text and Markdown

Extract text from a PDF in three lines.

Document opens a path or bytes. extract_text() runs layout analysis (columns, reading order, word spacing) and spreads pages across cores; extract_markdown() adds headings, lists and tables detected from the layout. Both exist per page too.

extract.py
import pdfboss

doc = pdfboss.Document("report.pdf")
print(doc.page_count, "pages, PDF", doc.version)

text = doc.extract_text()          # all pages, form-feed separated
markdown = doc.extract_markdown()  # headings, lists, tables from layout
first = doc[0].extract_text()      # one page, 0-based

Rendering and images

Render PDF pages to PNG, pull the images out.

Page.render(scale) returns PNG bytes (PPM, BMP or JPEG with format=) from an anti-aliased rasterizer with its own JPEG 2000, JBIG2, CCITT and ICC decoders. Page.render_reporting() returns the same pixels plus a report of anything dropped or approximated, so nothing disappears silently. extract_images() yields every image the page draws at native size, alpha applied.

render.py
from pathlib import Path

page = doc[0]
Path("page.png").write_bytes(page.render(scale=2.0))

for image in page.extract_images():
    print(image.width, image.height, len(image.data))  # native-size PNG

Styled spans

Every span carries its position and style.

spans() streams every text span with its position, bounding box, font identity, bold, italic, monospace and serif flags, underline and strikethrough, rise, color and visibility, one page buffered at a time.

spans.py
for span in doc.spans():
    if span.bold and span.text.strip():
        print(span.text, span.bbox)

Async and remote

Read a PDF over HTTP without downloading it.

AsyncDocument is the async twin of Document. Opened from a URL it fetches only the byte ranges it needs, so page one of a 400 MB scan arrives before the file would have finished downloading. Every data-fetching method is a coroutine.

remote.py
import asyncio

import pdfboss

async def main() -> None:
    doc = await pdfboss.AsyncDocument.open_url(
        "https://example.com/report.pdf"
    )
    print(await doc.extract_text())

asyncio.run(main())
encrypted.py
doc = pdfboss.Document("locked.pdf", password="hunter2")

Creating PDFs

Markdown in, PDF out.

pdfboss.md.to_pdf composes CommonMark+GFM into a CSS-themed PDF. pdfboss.write builds documents from pages, text, paragraphs, images and links joined with |, with metadata, bookmarks and attachments slotting in the same way, and writes deterministic output.

create.py
from pathlib import Path

import pdfboss

pdf = pdfboss.md.to_pdf(Path("notes.md").read_text())
Path("notes.pdf").write_bytes(pdf)

Speed

Why it is fast.

10,312 pages/s

Text extraction over 40 real-world PDFs, ~24× PyMuPDF.

161.9 pages/s

Rendering 888 certified pages, ~35% ahead of pypdfium2.

0.15 s

To read the 200-document opendataloader-bench corpus to Markdown.

The whole engine is one Rust workspace, so the Python calls cross the boundary once per operation, release the GIL while Rust works, and never round-trip through a C API. Method and full tables →

Scope

What it does not do yet.

  • Editing existing PDFs (annotations, forms, redaction, page manipulation). Creation is a separate, deterministic writer.
  • OCR. Scanned pages render to PNG; text extraction reads text operators only.
  • Formats other than PDF.