FibrumPDF
Structured PDF extraction at 318 pages per second on CPU.
FibrumPDF turns digital PDFs into structured JSON or clean Markdown without a GPU, a model download, or a remote API. It preserves headings, paragraphs, lists, tables, reading order, bounding boxes, links, and inline formatting while keeping extraction native and parallel.
The native pipeline targets workloads that need structure without spending seconds on every page.
Performance, measured
The repository benchmark contains 512 documents from the
datalab-to/marker_benchmark dataset. On the documented Ryzen 7 4800H test
system, the current FibrumPDF build processes 318.2 pages/s, about 77x
PyMuPDF4LLM and 517x Docling in this benchmark.
| Extractor | Pages/s | Text score | Table TEDS | Table precision | Table recall |
|---|---|---|---|---|---|
| FibrumPDF | 318.23 | 87.31 | 0.783 | 0.661 | 0.590 |
| PyMuPDF4LLM | 4.15 | 86.54 | 0.778 | 0.647 | 0.554 |
| Docling | 0.62 | 91.13 | 0.821 | 0.796 | 0.738 |
PyMuPDF4LLM is the closest speed comparison. Docling scores higher on difficult tables and irregular layouts, but takes substantially longer.
Open the interactive report or see how the benchmark works.
Features
- Semantic blocks: headings, paragraphs, lists, code, figures, and tables.
- Layout metadata: page numbers and block, row, cell, and span bounding boxes.
- Inline formatting: bold, italic, monospace, strikeout, super/subscript, links.
- Two consumption modes: collect small documents or stream large ones page by page with bounded memory.
- Atomic output: failed extraction never leaves a half-written destination.
- Native wheels for Python 3.11+ on Linux x86_64, macOS arm64, and Windows x64.
Quick start
uv pip install fibrum-pdf
Extract JSON:
from fibrum_pdf import to_json
result = to_json("report.pdf", "report.json")
print(result.path)
for page in result: # streamed; the whole document is not loaded
print(page.markdown)
Write Markdown directly. Pages are converted incrementally and the destination is replaced atomically:
from fibrum_pdf import to_markdown
path = to_markdown("report.pdf", "report.md")
For smaller documents, collect typed Pydantic-backed objects:
pages = to_json("report.pdf").collect()
print(pages[0].markdown)
print(pages[0][0].type, pages[0][0].bbox)
The CLI exposes both formats:
uv run fibrum-pdf report.pdf report.json
uv run fibrum-pdf report.pdf report.md --format markdown
The output path is optional; it defaults to the PDF name with a .json or .md
suffix.
Output model
The JSON document is an array of pages. Each page contains a data array of
blocks:
[
{
"page": 1,
"data": [
{
"type": "heading",
"level": 1,
"bbox": [178.64, 84.50, 433.36, 102.55],
"font_size": 24,
"spans": [
{"text": "Quarterly report", "font_size": 0, "bold": true}
]
}
]
}
]
Tables add row and cell geometry; lists add typed items, markers, and indentation. See the public models for the complete schema.
How it works
MuPDF handles PDF interpretation. Go performs layout analysis, table detection,
classification, cleanup, and bounded parallel page processing. Python stays a
thin orchestration layer and exposes the native result lazily through ijson.
Text and vector edges are captured in one page pass. Ruled tables use line grids. Borderless tables are built from contiguous multi-column rows, with structural checks to reject prose columns, diagrams, and fragmented labels.
MuPDF access is serialized where required. Page processing uses bounded workers, so memory use depends on active pages rather than document length.
Known limits
FibrumPDF does not run OCR or extract embedded images. Scanned PDFs require another tool. Forms, spreadsheets, heavily layered pages, and unconventional visual layouts can also defeat the heuristic extractor.
Use the benchmark as a starting point, then test representative documents from your own workload before committing to an extraction stack.
Reproduce the benchmark
Benchmark reports are generated by the code in benchmark/. The
committed comparison uses 512 deterministic samples (--seed 0, one timing run)
on an AMD Ryzen 7 4800H; Docling used the machine's GTX 1650 Ti where applicable.
uv sync --extra benchmark
uv run python -m benchmark download \
--output benchmark/data --max-rows 512
uv run python -m benchmark run \
--dataset-path benchmark/data \
--output benchmark/results \
--max-rows 512 --runs 1
Per-document measurements, aggregate rows, and generated reports are committed
under benchmark/results/. Throughput varies by hardware;
the quality scores are the more portable comparison.
Development
Source builds require MuPDF 1.27. See BUILD.md for platform setup. Once the native dependency is available:
uv sync --extra dev
uv run ruff check .
uv run ruff format --check .
uv run pytest -q
cd go
go test ./...
go vet ./...
License
FibrumPDF is licensed under AGPL-3.0. MuPDF is also AGPL-licensed and is available under a commercial license from Artifex.
Metadata
Release files for fibrum-pdf 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fibrum_pdf-1.2.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| fibrum_pdf-1.2.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
| fibrum_pdf-1.2.0-py3-none-macosx_15_0_arm64.whl | Python 3 | none | macOS 15.0+ ARM64 | Details |
Total release size: 201.4 MB
Release files / fibrum_pdf-1.2.0-py3-none-win_amd64.whl
| Download URL | fibrum_pdf-1.2.0-py3-none-win_amd64.whl |
|---|---|
| Size | 41.1 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
002fabcdcff3524810f79160aa5eb2d544f1cfa743a701dcc50113bbc7bbea9a
|
|
BLAKE2b-256 checksum How to use checksums |
6b37648b17dfbb55d109906e7c25c2c2b9505c2c43ba693b3266b1cc5723ec5e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / fibrum_pdf-1.2.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fibrum_pdf-1.2.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 79.7 MB |
| Tags | Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
89da40f6ed51c248383813b37f23aab66c325578f0f18e04428f55f93ee6cd2e
|
|
BLAKE2b-256 checksum How to use checksums |
2f1bff11d00deedb319a42082ed98edca4ad090d6822e93be788cedc49073b14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / fibrum_pdf-1.2.0-py3-none-macosx_15_0_arm64.whl
| Download URL | fibrum_pdf-1.2.0-py3-none-macosx_15_0_arm64.whl |
|---|---|
| Size | 80.6 MB |
| Tags | Python 3 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
9c498b2ae5604efb4bd5ce22f21878dbf78efce47168a27867ee3ef090c67e3c
|
|
BLAKE2b-256 checksum How to use checksums |
fe010311e42b2bbf3cb6b25d4934540973604005ed235721ac95dd249d718fb4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency log