A command-line tool that extracts structured content — text blocks and tables — from PDF files and exports it as JSON, built on top of MuPDF.
It goes beyond raw text extraction by reconstructing tables (merging split and overlapping cells using MuPDF's GRID layout info) and computing a sensible reading order for the page using a recursive XY-cut algorithm, so multi-column and mixed layouts come out in the right order.
- Table reconstruction — detects tables via MuPDF's structured text GRID, merges split/overlapping cells, and groups them into logical blocks (including multi-row/column spans).
- Text block extraction — pulls free-text content alongside tables.
- Reading order — orders all page items (text blocks + tables) using a recursive XY-cut, correctly handling single-column, multi-column, and asymmetric layouts.
- JSON output — one JSON file per run, with one entry per page containing
blocksandtables, each with bounding boxes and reading order.
-
CMake 3.10+
-
A C++17 compiler
-
Prebuilt MuPDF (static and dynamic) libraries, placed under
mupdf/lib/for each supported platform:- Ubuntu and RHEL on Linux
- Windows x64
- macOS/Darwin
Not included in this repository — see the note below.
-
MuPDF 1.29.0. This project uses MuPDF's structured-text "Table Hunt" GRID API (
fz_stext_grid_infoand related types), which isn't present in older releases. If you build against a different MuPDF version, confirm it still has this API first — check with:grep -A2 "define FZ_VERSION" mupdf/include/mupdf/fitz/version.h
This project is designed to link against prebuilt MuPDF binaries rather than building MuPDF from source. Those binaries (and the
mupdf/include/headers) are not part of this repo; you'll need to obtain them separately and place them in themupdf/tree described under Project layout beforecmake --buildwill succeed. This is deliberate, not an oversight: MuPDF is dual-licensed under AGPL-3.0 and a commercial Artifex license, and this project avoids redistributing Artifex's binaries itself so that each user's use of MuPDF stays governed by whichever license they're actually entitled to use.The prebuilt
mupdfwrapperexecutables (dist/) aren't tracked in this repo either — they're published on the Releases page instead, one archive per platform, so most users never need to build anything at all.
scripts/fetch-mupdf.sh(Linux/macOS) andscripts/fetch-mupdf.ps1(Windows) download and build the pinned MuPDF release into themupdf/layout above.
mkdir build && cd build
cmake .. -DSYSTEM_NAME=UBUNTU # or -DSYSTEM_NAME=RHEL
cmake --build .If -DSYSTEM_NAME is omitted, the build script tries to auto-detect your
distro from /etc/os-release.
For a release build:
cmake .. -DSYSTEM_NAME=UBUNTU -DCMAKE_BUILD_TYPE=RELEASETo build with AddressSanitizer:
cmake .. -DSYSTEM_NAME=UBUNTU -DUSE_ASAN=ONmkdir build && cd build
cmake .. -DSYSTEM_NAME=WINDOWS
cmake --build . --config ReleaseLinks against the static MuPDF archives under mupdf/lib/windows/ by
default (LINK_MUPDF_STATIC defaults to ON); pass
-DLINK_MUPDF_STATIC=OFF to link the dynamic mupdf.dll/mupdf.lib pair
instead.
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DSYSTEM_NAME=DARWIN
cmake --build build --verboseLinks against the static libmupdf.a under mupdf/lib/darwin/ by default
(LINK_MUPDF_STATIC defaults to ON); pass -DLINK_MUPDF_STATIC=OFF to
link the dynamic libmupdf.dylib instead.
./mupdfwrapper <input.pdf> [output.json]input.pdf— path to the PDF to process (required).output.json— path to write the output to (optional, defaults tooutput.jsonin the working directory).
While processing, the tool prints PAGE_DONE <n>/<total> to stdout after
each page, so it can be used as a progress indicator by a calling process.
{
"pages": [
{
"page": 1,
"blocks": [
{
"readingOrder": 0,
"text": "...",
"bbox": { "x0": 0, "y0": 0, "x1": 0, "y1": 0 }
}
],
"tables": [
{
"readingOrder": 1,
"bbox": { "x0": 0, "y0": 0, "x1": 0, "y1": 0 },
"cells": [
{
"startRow": 0,
"endRow": 0,
"startCol": 0,
"endCol": 1,
"text": "..."
}
]
}
]
}
]
}layout-aware-pdf2json/
├── .gitignore
├── CMakeLists.txt
├── COPYING.txt # AGPL-3.0 license text
├── NOTICE # third-party attribution (MuPDF/Artifex)
├── CITATION.cff
├── scripts/
│ ├── fetch-mupdf.sh # fetches + builds MuPDF for Linux/macOS
│ └── fetch-mupdf.ps1 # fetches MuPDF source for Windows (manual build step)
├── src/
│ └── main.cpp # extraction, table reconstruction, reading order, JSON export
├── dist/ # gitignored — build output, published via Releases, not committed
│ ├── ubuntu/mupdfwrapper
│ ├── rhel/mupdfwrapper
│ ├── windows/mupdfwrapper.exe
│ └── darwin/mupdfwrapper
└── mupdf/ # gitignored — not redistributed, you must supply this
├── include/ # MuPDF headers (same headers for every platform)
└── lib/
├── ubuntu/ # .so and .a you provide for Ubuntu/Debian
├── rhel/ # .so and .a you provide for RHEL/CentOS/Rocky/Alma/Fedora
├── windows/ # .dll and .lib you provide for Windows
└── darwin/ # libmupdf.dylib and libmupdf.a you provide for macOS
Everything under mupdf/ above is what CMakeLists.txt expects to find,
not something this repo ships — you'll need to drop in MuPDF's own
headers and compiled libraries for whichever platform(s) you're building
for before cmake --build will succeed. dist/ is local build output:
it's where a build lands on your machine, but it isn't committed to git —
published builds go out through
Releases instead, packaged one archive per platform
(e.g. layout-aware-pdf2json-v1.0.0-ubuntu.tar.gz).
This project implements (a variant of) the recursive XY-cut algorithm for document layout analysis, based on:
-
G. Nagy and S. Seth, "Hierarchical representation of optically scanned documents," in Proc. 7th International Conference on Pattern Recognition (ICPR), Montreal, 1984, pp. 347–349. DigitalCommons@University of Nebraska-Lincoln
-
J. Ha, R. M. Haralick, and I. T. Phillips, "Recursive X-Y cut using bounding boxes of connected components," in Proc. 3rd International Conference on Document Analysis and Recognition (ICDAR), Montreal, 1995, pp. 952–955. IEEE Xplore
Copyright (C) 2026 Isabella Mastroianni
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) — see COPYING.txt.
It links against and bundles MuPDF, which Artifex licenses under AGPL-3.0 for open-source use (a commercial license is also available from Artifex for proprietary use). Consequently, use of this project, and any modification or network-distributed service built on it, is subject to the terms of the AGPL-3.0. If you need to use this code under different terms, you must obtain a commercial MuPDF license from Artifex.