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.*

[![PyPI version](https://img.shields.io/pypi/v/rasgapdf.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/rasgapdf/)
[![Python versions](https://img.shields.io/pypi/pyversions/rasgapdf.svg?logo=python&logoColor=white)](https://pypi.org/project/rasgapdf/)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](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.