File size: 6,428 Bytes
17ce81b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | # β‘ RasgaPDF
<div align="center">
**The Blazing-Fast 2D Spatial PDF Parser for Python.**
*Extract exact physical coordinates `[x0, y0, x1, y1]`, word spans, text blocks, and tabular structures at native hardware speeds.*
[](https://pypi.org/project/rasgapdf/)
[](https://pypi.org/project/rasgapdf/)
[](https://www.gnu.org/licenses/agpl-3.0)
</div>
---
## π Why RasgaPDF?
Most Python PDF extraction libraries make fragile guesses: they flatten multi-column layouts into corrupted text streams, mangle tables, and strip away 2D positional geometry.
**RasgaPDF does one thing with uncompromising precision:**
It returns the **exact 2D physical spatial geometry** of the PDF directly to Python:
- **Exact Bounding Boxes:** Every character, word span, line, block, and table has exact coordinates `[x0, y0, x1, y1]`.
- **Zero Lossy Heuristics:** No broken markdown assumptions. Downstream LLMs, RAG pipelines, or vision-language models receive the true physical layout.
- **Pure Native Speed:** Powered by a SIMD-parallelized Rust core. Extracts typical pages in **~3 to 8 ms**.
- **Self-Contained Wheel:** Pre-compiled native binaries bundled directly in the wheel. Zero external runtime dependencies.
---
## β‘ Quick Benchmarks (Python)
Measured on Intel Core i7-1365U (Single-thread latency, 1-page complex PDF):
| Library | Parse Time | Output Type | Spatial Accuracy |
| :--- | :--- | :--- | :--- |
| **β‘ RasgaPDF (`parse_raw`)** | **~7.7 ms** | **Flat Coordinates `[x0, y0, x1, y1]`** | **Exact Physical Canvas** |
| **π RasgaPDF (`parse_pdf`)** | **~8.5 ms** | **Hierarchical Blocks & Tables** | **Exact Physical Canvas** |
| PyMuPDF (`fitz`) | ~28.0 ms | Text / Pixmaps | Bounding Boxes |
| `pdfplumber` | ~410.0 ms | Python Dicts | High Overhead |
| `pypdf` | ~95.0 ms | Plain String | No Geometry |
---
## π¦ Installation
```bash
pip install --upgrade rasgapdf
```
---
## π‘ Usage
RasgaPDF offers two distinct modes for Python engineers:
### β‘ Mode 1: Raw Physical Coordinates (`parse_raw`)
The fastest and most direct extraction possible. Returns a flat list of physical 2D coordinates for every text span on the page, with zero block/table overhead (~3-8 ms):
```python
import rasgapdf
# Parse raw physical coordinates
doc = rasgapdf.parse_raw("document.pdf")
print(f"Extracted {doc['total_spans']} spans in {doc['parse_time_ms']:.2f} ms")
for span in doc["spans"]:
print(
f"[Page {span['page']}] "
f"bbox=({span['x0']:.2f}, {span['y0']:.2f}, {span['x1']:.2f}, {span['y1']:.2f}) "
f"font={span['font_name']} ({span['font_size']}pt) "
f"text=\"{span['text']}\""
)
```
#### Output Structure:
```json
{
"file_name": "document.pdf",
"total_pages": 1,
"total_spans": 20,
"parse_time_ms": 7.78,
"spans": [
{
"page": 1,
"x0": 50.0,
"y0": 67.0,
"x1": 244.0,
"y1": 83.0,
"font_size": 12.0,
"font_name": "Helvetica",
"text": "The Future of Artificial Intelligence"
}
]
}
```
---
### π― Mode 2: Hierarchical Structured Document (`parse_pdf`)
Parses the visual hierarchy: paragraphs (`text_blocks`), text lines (`lines`), spans, and auto-detects matrix tables via column alignment:
```python
import rasgapdf
doc = rasgapdf.parse_pdf("invoice.pdf", detect_tables=True)
for page in doc["pages"]:
print(f"--- Page {page['page_number']} ({page['width']}x{page['height']} pt) ---")
# 1. Inspect Text Blocks
for block in page["text_blocks"]:
print(f"Block #{block['block_id']} at {block['bbox']}:")
for line in block["lines"]:
print(f" Line: {line['text']}")
# 2. Inspect Detected Tables
for table in page["tables"]:
print(f"Table ({table['col_count']} cols x {table['row_count']} rows):")
print("Headers:", table["headers"])
for row in table["rows"]:
print("Row:", row)
```
---
## βοΈ Parameters for `parse_pdf`
| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `file_path` | `str` | *required* | Path to the PDF file on disk |
| `detect_tables` | `bool` | `True` | Automatically detect and reconstruct tables |
| `min_table_cols` | `int` | `3` | Minimum number of columns required to classify as a table |
| `col_tolerance` | `float` | `16.0` | Horizontal alignment threshold in typographical points |
| `row_tolerance` | `float` | `6.0` | Vertical line clustering threshold in points |
| `extract_images` | `bool` | `False` | Fill `page["images"]` with embedded image metadata (dimensions, colour space, filter, SHA-256, placement `bbox`) |
| `extract_drawings` | `bool` | `False` | Fill `page["drawings"]` with vector paths (`line`/`curve`/`rect`/`quad` items, colours, dash, opacity) |
| `keep_background_fills` | `bool` | `False` | Keep fills that cover the whole page (backgrounds are dropped by default) |
---
### πΌοΈ Embedded Images & Vector Graphics
Opt-in extraction of the graphics layer. Pixels are never decoded β metadata stays in the JSON and the original encoded stream is written to disk as-is:
```python
import rasgapdf
doc = rasgapdf.parse_pdf("report.pdf", extract_images=True, extract_drawings=True)
page = doc["pages"][0]
for image in page["images"]:
print(image["name"], image["pixel_width"], "x", image["pixel_height"],
image["filter"], image["bbox"])
for drawing in page["drawings"]:
print(drawing["drawing_id"], drawing["drawing_type"], drawing["stroke_color"])
# Writes report JPEGs (e.g. page_001_img_001_xref7.jpg) plus manifest.json
manifest = rasgapdf.extract_images("report.pdf", "./out")
print(manifest["written"], "files written")
```
---
## π License
GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). Copyright (c) 2026 Messias Martins.
RasgaPDF embeds and links against [MuPDF](https://mupdf.com/) (Artifex Software),
which is distributed under the AGPL-3.0. That is why this project is licensed
under the same terms.
|