rustypaper 0.2.2__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {rustypaper-0.2.2 → rustypaper-0.2.3}/Cargo.lock +4 -4
  2. {rustypaper-0.2.2 → rustypaper-0.2.3}/Cargo.toml +3 -3
  3. rustypaper-0.2.3/PKG-INFO +226 -0
  4. rustypaper-0.2.3/README.md +212 -0
  5. {rustypaper-0.2.2 → rustypaper-0.2.3}/pyproject.toml +1 -1
  6. rustypaper-0.2.3/rustypaper/README.md +212 -0
  7. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/compress.rs +3 -0
  8. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/doc.rs +234 -8
  9. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/emit/markdown.rs +119 -8
  10. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/emit/text.rs +1 -0
  11. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/emit/typst.rs +82 -9
  12. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/layout/furniture.rs +1 -0
  13. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/layout/order.rs +1 -0
  14. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/pipeline.rs +271 -2
  15. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/refs.rs +937 -42
  16. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/table.rs +1 -0
  17. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/text/lines.rs +204 -5
  18. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/text/vocab.rs +1 -0
  19. rustypaper-0.2.3/rustypaper/tests/actualtext.rs +147 -0
  20. rustypaper-0.2.2/PKG-INFO +0 -212
  21. rustypaper-0.2.2/README.md +0 -198
  22. rustypaper-0.2.2/rustypaper/README.md +0 -198
  23. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/Cargo.toml +0 -0
  24. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/__init__.py +0 -0
  25. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/__main__.py +0 -0
  26. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/cli.py +0 -0
  27. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/examples/ingest_share.rs +0 -0
  28. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/backend/mod.rs +0 -0
  29. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/backend/rustium.rs +0 -0
  30. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/cli.rs +0 -0
  31. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/emit/mod.rs +0 -0
  32. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/error.rs +0 -0
  33. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/figure.rs +0 -0
  34. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/ir.rs +0 -0
  35. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/layout/columns.rs +0 -0
  36. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/layout/mod.rs +0 -0
  37. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/layout/stats.rs +0 -0
  38. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/lib.rs +0 -0
  39. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/main.rs +0 -0
  40. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/math/build.rs +0 -0
  41. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/math/latex.rs +0 -0
  42. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/math/mod.rs +0 -0
  43. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/math/symbols.rs +0 -0
  44. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/text/mod.rs +0 -0
  45. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/src/util.rs +0 -0
  46. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/tests/cli.rs +0 -0
  47. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper/tests/robustness.rs +0 -0
  48. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper-py/Cargo.toml +0 -0
  49. {rustypaper-0.2.2 → rustypaper-0.2.3}/rustypaper-py/src/lib.rs +0 -0
@@ -551,9 +551,9 @@ dependencies = [
551
551
 
552
552
  [[package]]
553
553
  name = "rustium-pdf"
554
- version = "0.1.1"
554
+ version = "0.1.3"
555
555
  source = "registry+https://github.com/rust-lang/crates.io-index"
556
- checksum = "d6d84ef6203a57c8dd3762adbbe3c74e0f18f73feb58273166338aa79a9dd051"
556
+ checksum = "e3e3fd0358b52a11d3547ca03a4bda867ba5a5e3ed9dfb1f6768247af1154208"
557
557
  dependencies = [
558
558
  "aes",
559
559
  "cbc",
@@ -567,7 +567,7 @@ dependencies = [
567
567
 
568
568
  [[package]]
569
569
  name = "rustypaper"
570
- version = "0.2.2"
570
+ version = "0.2.3"
571
571
  dependencies = [
572
572
  "anyhow",
573
573
  "clap",
@@ -580,7 +580,7 @@ dependencies = [
580
580
 
581
581
  [[package]]
582
582
  name = "rustypaper-py"
583
- version = "0.2.2"
583
+ version = "0.2.3"
584
584
  dependencies = [
585
585
  "pyo3",
586
586
  "rustypaper",
@@ -3,21 +3,21 @@ resolver = "2"
3
3
  members = ["rustypaper", "rustypaper-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.2.2"
6
+ version = "0.2.3"
7
7
  edition = "2021"
8
8
  rust-version = "1.94"
9
9
  license = "MIT OR Apache-2.0"
10
10
  repository = "https://github.com/pgarrett-scripps/rustypaper"
11
11
 
12
12
  [workspace.dependencies]
13
- rustypaper = { path = "rustypaper", version = "0.2.2" }
13
+ rustypaper = { path = "rustypaper", version = "0.2.3" }
14
14
  # The pure-Rust PDF backend, from the registry. Deliberately not a path dependency: a path
15
15
  # only resolves where the sibling checkout happens to exist, which is this machine and not a
16
16
  # CI runner, and `cargo fmt --all` walks into it whether it is there or not. To develop the
17
17
  # two together, add a temporary override rather than committing one:
18
18
  # [patch.crates-io]
19
19
  # rustium-pdf = { path = "../rustium-pdf" }
20
- rustium = { package = "rustium-pdf", version = "0.1.1" }
20
+ rustium = { package = "rustium-pdf", version = "0.1.3" }
21
21
 
22
22
  anyhow = "1"
23
23
  clap = { version = "4", features = ["derive"] }
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: rustypaper
3
+ Version: 0.2.3
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Topic :: Text Processing :: Markup
6
+ Classifier: Topic :: Scientific/Engineering
7
+ Summary: Structure-aware conversion of born-digital scientific PDFs to Markdown, Typst and JSON.
8
+ Keywords: pdf,markdown,typst,science,papers,extraction
9
+ License: MIT OR Apache-2.0
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
12
+ Project-URL: Repository, https://github.com/pgarrett-scripps/rustypaper
13
+
14
+ # rustypaper
15
+
16
+ **Turn research PDFs into readable text and structured data.**
17
+
18
+ Rustypaper converts scientific papers to Markdown, plain text, JSON, or Typst. Use it to
19
+ save a paper as an editable document, prepare text for search or an LLM, or extract
20
+ sections for your own analysis tools. Run it from the terminal, Python, or Rust.
21
+
22
+ It runs locally on your CPU. No GPU, AI model, API key, or document upload is required.
23
+ It is designed for PDFs with selectable text, including one-column and two-column papers.
24
+ It does not perform OCR on scans or image-only PDFs.
25
+
26
+ [Quick start](#quick-start) · [Downloads](#install-without-python) ·
27
+ [Python API](#python-api) · [Limitations](#conversion-quality-and-limitations)
28
+
29
+ ## Quick start
30
+
31
+ With Python 3.9 or newer:
32
+
33
+ ```sh
34
+ pip install rustypaper
35
+ rustypaper convert paper.pdf --out paper.md
36
+ ```
37
+
38
+ Replace `paper.pdf` with your PDF's path. This saves the converted Markdown to `paper.md`.
39
+ Omit `--out` to print it in the terminal instead.
40
+
41
+ You can also run the same command through Python:
42
+
43
+ ```sh
44
+ python -m rustypaper convert paper.pdf --out paper.md
45
+ ```
46
+
47
+ The [PyPI package](https://pypi.org/project/rustypaper/) includes both the terminal command
48
+ and the Python library. Precompiled packages are available for the platforms below, so
49
+ supported installations do not need a Rust compiler.
50
+
51
+ ## What does the output look like?
52
+
53
+ Rustypaper recognizes headings, paragraphs, figures, tables, equations, and references,
54
+ and reconstructs the reading order of the paper. For example, the start of the Markdown
55
+ from the repository's [synthetic sample PDF](python/tests/fixtures/single-column.pdf) is:
56
+
57
+ ```markdown
58
+ # Reliable Widget Measurements
59
+
60
+ Example Author
61
+
62
+ ## Abstract
63
+
64
+ We describe a simple study of colored widgets on a wooden bench.
65
+ ```
66
+
67
+ This is a shortened excerpt. Conversion quality varies with the paper's layout, especially
68
+ for equations and complex tables. See [limitations](#conversion-quality-and-limitations).
69
+
70
+ Choose the output that suits your workflow:
71
+
72
+ | Format | Useful for | CLI option |
73
+ |---|---|---|
74
+ | Markdown | Reading, editing, and use in notes or LLM workflows | `--format md` (default) |
75
+ | Plain text | Search and text processing | `--format text` |
76
+ | JSON | Working with sections, content blocks, and their page locations | `--format json` |
77
+ | Typst | Further editing and typesetting in Typst | `--format typst` |
78
+
79
+ ## Common tasks
80
+
81
+ Save plain text, structured JSON, or a Typst document:
82
+
83
+ ```sh
84
+ rustypaper convert paper.pdf --format text --out paper.txt
85
+ rustypaper convert paper.pdf --format json --out paper.json
86
+ rustypaper convert paper.pdf --format typst --out paper.typ
87
+ ```
88
+
89
+ Save figures alongside the Markdown, with links to the image files:
90
+
91
+ ```sh
92
+ rustypaper convert paper.pdf --out paper.md --assets figures
93
+ ```
94
+
95
+ Convert several papers into an output folder:
96
+
97
+ ```sh
98
+ rustypaper convert first.pdf second.pdf --out converted
99
+ ```
100
+
101
+ Each PDF gets its own output file. For multiple inputs, `--out` must be a directory.
102
+
103
+ For all options, run `rustypaper convert --help`. An optional `--caveman light` or
104
+ `--caveman hard` setting shortens prose by removing selected words and phrases. It is
105
+ off by default and changes the wording, so use the default when you want the original prose.
106
+
107
+ ## Install without Python
108
+
109
+ Download an executable from the [latest release](https://github.com/pgarrett-scripps/rustypaper/releases/latest).
110
+ These downloads do not require Python or a Rust compiler.
111
+
112
+ | Your computer | Archive name contains |
113
+ |---|---|
114
+ | Linux on Intel or AMD, 64-bit | `x86_64-unknown-linux-gnu` |
115
+ | Linux on ARM64 | `aarch64-unknown-linux-gnu` |
116
+ | Mac with an Intel processor | `x86_64-apple-darwin` |
117
+ | Mac with Apple Silicon | `aarch64-apple-darwin` |
118
+ | Windows on Intel or AMD, 64-bit | `x86_64-pc-windows-msvc` |
119
+
120
+ Extract the archive, then run `./rustypaper --help` on Linux or macOS, or
121
+ `.\rustypaper.exe --help` in Windows PowerShell. Put the executable in a folder on your
122
+ `PATH` to use `rustypaper` from any directory. The release includes `SHA256SUMS` for
123
+ verifying downloads. Standalone Linux executables require glibc 2.35 or newer.
124
+
125
+ If you use [cargo-binstall](https://github.com/cargo-bins/cargo-binstall), it can download
126
+ the executable for you:
127
+
128
+ ```sh
129
+ cargo binstall rustypaper
130
+ ```
131
+
132
+ With a Rust toolchain installed, you can also compile from source:
133
+
134
+ ```sh
135
+ cargo install rustypaper --locked
136
+ ```
137
+
138
+ ## Python API
139
+
140
+ After `pip install rustypaper`, convert a PDF directly in your Python code:
141
+
142
+ ```python
143
+ from pathlib import Path
144
+ import rustypaper
145
+
146
+ markdown = rustypaper.to_markdown("paper.pdf")
147
+ Path("paper.md").write_text(markdown, encoding="utf-8")
148
+ ```
149
+
150
+ To get readable text and structured data from a single conversion:
151
+
152
+ ```python
153
+ import rustypaper
154
+
155
+ result = rustypaper.convert("paper.pdf")
156
+ print(result.markdown)
157
+
158
+ document = result.document
159
+ for section in document["sections"]:
160
+ print(section["title"], section["first_page"], section["last_page"])
161
+ ```
162
+
163
+ The document contains a title, typed content blocks, and a section outline. Blocks carry
164
+ text and page positions. Sections include nested children and `start` / `end` indices,
165
+ so `document["blocks"][section["start"]:section["end"]]` selects a section's contents.
166
+ Page numbers are zero-based. Content before the first heading has a section title of `None`.
167
+
168
+ Other helpers include `to_text()`, `to_typst()`, and `to_document()`.
169
+ Image-only documents raise `rustypaper.ScannedDocument`.
170
+
171
+ ## Conversion quality and limitations
172
+
173
+ Rustypaper uses the text and geometry already present in a PDF to recover its structure.
174
+ It is designed for scientific papers. Page layout can change during conversion.
175
+
176
+ - Scanned or image-only documents need a separate OCR tool.
177
+ - Equations, complex tables, and unusual layouts can be missed or reconstructed incorrectly.
178
+ - Titles split over several lines, subtle subsection headings, and long bibliographies remain
179
+ challenging. Check the converted output when those details matter to your workflow.
180
+
181
+ We evaluate conversion on 16 papers across 10 template families. Fifteen have usable source
182
+ text for comparison. This small corpus helps us detect regressions, and results on other
183
+ papers will depend on their layout. See the [evaluation results and methodology](eval/README.md)
184
+ for measurements of text recovery, equations, tables, references, and sections.
185
+
186
+ If a conversion looks wrong, [open an issue](https://github.com/pgarrett-scripps/rustypaper/issues).
187
+ Include the Rustypaper version, the command you ran, what you expected, and a public PDF link
188
+ or a small sample you can share. `rustypaper --version` prints the installed version.
189
+
190
+ ## For developers
191
+
192
+ Rustypaper is also a [Rust crate](https://crates.io/crates/rustypaper). Add it to `Cargo.toml`:
193
+
194
+ ```toml
195
+ [dependencies]
196
+ rustypaper = "0.2"
197
+ ```
198
+
199
+ The Rust API exposes `convert()`, `convert_with()`, and `extract()`.
200
+ PDF reading is provided by [rustium-pdf](https://github.com/pgarrett-scripps/rustium-pdf).
201
+ See the [architecture notes](docs/ARCHITECTURE.md) for how conversion works, the
202
+ [evaluation guide](eval/README.md) for quality checks, and the [release guide](RELEASING.md)
203
+ for packaging and publishing.
204
+
205
+ For local development on Linux, with Rust 1.94 or newer, Python 3.9 or newer, and pytest
206
+ installed, run these commands from a clone of this repository:
207
+
208
+ ```sh
209
+ scripts/build.sh
210
+ cargo test --release
211
+ PYTHONPATH=python pytest python/tests -q
212
+ python3 -m unittest discover -s eval/tests
213
+ ```
214
+
215
+ `scripts/build.sh` builds both the CLI and the Python extension used by the tests. The
216
+ Python tests use committed synthetic PDFs. To run the optional real-paper corpus tests,
217
+ fetch the papers with `scripts/fetch-corpus.sh` before running the tests. See the evaluation
218
+ guide for downloading reference sources and comparing results with the quality baseline.
219
+
220
+ For conversion diagnostics, `rustypaper probe paper.pdf --pages` summarizes the PDF,
221
+ and `rustypaper dump paper.pdf --page 0 --pretty` shows the extracted page data.
222
+
223
+ ## License
224
+
225
+ Licensed under [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE), at your option.
226
+
@@ -0,0 +1,212 @@
1
+ # rustypaper
2
+
3
+ **Turn research PDFs into readable text and structured data.**
4
+
5
+ Rustypaper converts scientific papers to Markdown, plain text, JSON, or Typst. Use it to
6
+ save a paper as an editable document, prepare text for search or an LLM, or extract
7
+ sections for your own analysis tools. Run it from the terminal, Python, or Rust.
8
+
9
+ It runs locally on your CPU. No GPU, AI model, API key, or document upload is required.
10
+ It is designed for PDFs with selectable text, including one-column and two-column papers.
11
+ It does not perform OCR on scans or image-only PDFs.
12
+
13
+ [Quick start](#quick-start) · [Downloads](#install-without-python) ·
14
+ [Python API](#python-api) · [Limitations](#conversion-quality-and-limitations)
15
+
16
+ ## Quick start
17
+
18
+ With Python 3.9 or newer:
19
+
20
+ ```sh
21
+ pip install rustypaper
22
+ rustypaper convert paper.pdf --out paper.md
23
+ ```
24
+
25
+ Replace `paper.pdf` with your PDF's path. This saves the converted Markdown to `paper.md`.
26
+ Omit `--out` to print it in the terminal instead.
27
+
28
+ You can also run the same command through Python:
29
+
30
+ ```sh
31
+ python -m rustypaper convert paper.pdf --out paper.md
32
+ ```
33
+
34
+ The [PyPI package](https://pypi.org/project/rustypaper/) includes both the terminal command
35
+ and the Python library. Precompiled packages are available for the platforms below, so
36
+ supported installations do not need a Rust compiler.
37
+
38
+ ## What does the output look like?
39
+
40
+ Rustypaper recognizes headings, paragraphs, figures, tables, equations, and references,
41
+ and reconstructs the reading order of the paper. For example, the start of the Markdown
42
+ from the repository's [synthetic sample PDF](python/tests/fixtures/single-column.pdf) is:
43
+
44
+ ```markdown
45
+ # Reliable Widget Measurements
46
+
47
+ Example Author
48
+
49
+ ## Abstract
50
+
51
+ We describe a simple study of colored widgets on a wooden bench.
52
+ ```
53
+
54
+ This is a shortened excerpt. Conversion quality varies with the paper's layout, especially
55
+ for equations and complex tables. See [limitations](#conversion-quality-and-limitations).
56
+
57
+ Choose the output that suits your workflow:
58
+
59
+ | Format | Useful for | CLI option |
60
+ |---|---|---|
61
+ | Markdown | Reading, editing, and use in notes or LLM workflows | `--format md` (default) |
62
+ | Plain text | Search and text processing | `--format text` |
63
+ | JSON | Working with sections, content blocks, and their page locations | `--format json` |
64
+ | Typst | Further editing and typesetting in Typst | `--format typst` |
65
+
66
+ ## Common tasks
67
+
68
+ Save plain text, structured JSON, or a Typst document:
69
+
70
+ ```sh
71
+ rustypaper convert paper.pdf --format text --out paper.txt
72
+ rustypaper convert paper.pdf --format json --out paper.json
73
+ rustypaper convert paper.pdf --format typst --out paper.typ
74
+ ```
75
+
76
+ Save figures alongside the Markdown, with links to the image files:
77
+
78
+ ```sh
79
+ rustypaper convert paper.pdf --out paper.md --assets figures
80
+ ```
81
+
82
+ Convert several papers into an output folder:
83
+
84
+ ```sh
85
+ rustypaper convert first.pdf second.pdf --out converted
86
+ ```
87
+
88
+ Each PDF gets its own output file. For multiple inputs, `--out` must be a directory.
89
+
90
+ For all options, run `rustypaper convert --help`. An optional `--caveman light` or
91
+ `--caveman hard` setting shortens prose by removing selected words and phrases. It is
92
+ off by default and changes the wording, so use the default when you want the original prose.
93
+
94
+ ## Install without Python
95
+
96
+ Download an executable from the [latest release](https://github.com/pgarrett-scripps/rustypaper/releases/latest).
97
+ These downloads do not require Python or a Rust compiler.
98
+
99
+ | Your computer | Archive name contains |
100
+ |---|---|
101
+ | Linux on Intel or AMD, 64-bit | `x86_64-unknown-linux-gnu` |
102
+ | Linux on ARM64 | `aarch64-unknown-linux-gnu` |
103
+ | Mac with an Intel processor | `x86_64-apple-darwin` |
104
+ | Mac with Apple Silicon | `aarch64-apple-darwin` |
105
+ | Windows on Intel or AMD, 64-bit | `x86_64-pc-windows-msvc` |
106
+
107
+ Extract the archive, then run `./rustypaper --help` on Linux or macOS, or
108
+ `.\rustypaper.exe --help` in Windows PowerShell. Put the executable in a folder on your
109
+ `PATH` to use `rustypaper` from any directory. The release includes `SHA256SUMS` for
110
+ verifying downloads. Standalone Linux executables require glibc 2.35 or newer.
111
+
112
+ If you use [cargo-binstall](https://github.com/cargo-bins/cargo-binstall), it can download
113
+ the executable for you:
114
+
115
+ ```sh
116
+ cargo binstall rustypaper
117
+ ```
118
+
119
+ With a Rust toolchain installed, you can also compile from source:
120
+
121
+ ```sh
122
+ cargo install rustypaper --locked
123
+ ```
124
+
125
+ ## Python API
126
+
127
+ After `pip install rustypaper`, convert a PDF directly in your Python code:
128
+
129
+ ```python
130
+ from pathlib import Path
131
+ import rustypaper
132
+
133
+ markdown = rustypaper.to_markdown("paper.pdf")
134
+ Path("paper.md").write_text(markdown, encoding="utf-8")
135
+ ```
136
+
137
+ To get readable text and structured data from a single conversion:
138
+
139
+ ```python
140
+ import rustypaper
141
+
142
+ result = rustypaper.convert("paper.pdf")
143
+ print(result.markdown)
144
+
145
+ document = result.document
146
+ for section in document["sections"]:
147
+ print(section["title"], section["first_page"], section["last_page"])
148
+ ```
149
+
150
+ The document contains a title, typed content blocks, and a section outline. Blocks carry
151
+ text and page positions. Sections include nested children and `start` / `end` indices,
152
+ so `document["blocks"][section["start"]:section["end"]]` selects a section's contents.
153
+ Page numbers are zero-based. Content before the first heading has a section title of `None`.
154
+
155
+ Other helpers include `to_text()`, `to_typst()`, and `to_document()`.
156
+ Image-only documents raise `rustypaper.ScannedDocument`.
157
+
158
+ ## Conversion quality and limitations
159
+
160
+ Rustypaper uses the text and geometry already present in a PDF to recover its structure.
161
+ It is designed for scientific papers. Page layout can change during conversion.
162
+
163
+ - Scanned or image-only documents need a separate OCR tool.
164
+ - Equations, complex tables, and unusual layouts can be missed or reconstructed incorrectly.
165
+ - Titles split over several lines, subtle subsection headings, and long bibliographies remain
166
+ challenging. Check the converted output when those details matter to your workflow.
167
+
168
+ We evaluate conversion on 16 papers across 10 template families. Fifteen have usable source
169
+ text for comparison. This small corpus helps us detect regressions, and results on other
170
+ papers will depend on their layout. See the [evaluation results and methodology](eval/README.md)
171
+ for measurements of text recovery, equations, tables, references, and sections.
172
+
173
+ If a conversion looks wrong, [open an issue](https://github.com/pgarrett-scripps/rustypaper/issues).
174
+ Include the Rustypaper version, the command you ran, what you expected, and a public PDF link
175
+ or a small sample you can share. `rustypaper --version` prints the installed version.
176
+
177
+ ## For developers
178
+
179
+ Rustypaper is also a [Rust crate](https://crates.io/crates/rustypaper). Add it to `Cargo.toml`:
180
+
181
+ ```toml
182
+ [dependencies]
183
+ rustypaper = "0.2"
184
+ ```
185
+
186
+ The Rust API exposes `convert()`, `convert_with()`, and `extract()`.
187
+ PDF reading is provided by [rustium-pdf](https://github.com/pgarrett-scripps/rustium-pdf).
188
+ See the [architecture notes](docs/ARCHITECTURE.md) for how conversion works, the
189
+ [evaluation guide](eval/README.md) for quality checks, and the [release guide](RELEASING.md)
190
+ for packaging and publishing.
191
+
192
+ For local development on Linux, with Rust 1.94 or newer, Python 3.9 or newer, and pytest
193
+ installed, run these commands from a clone of this repository:
194
+
195
+ ```sh
196
+ scripts/build.sh
197
+ cargo test --release
198
+ PYTHONPATH=python pytest python/tests -q
199
+ python3 -m unittest discover -s eval/tests
200
+ ```
201
+
202
+ `scripts/build.sh` builds both the CLI and the Python extension used by the tests. The
203
+ Python tests use committed synthetic PDFs. To run the optional real-paper corpus tests,
204
+ fetch the papers with `scripts/fetch-corpus.sh` before running the tests. See the evaluation
205
+ guide for downloading reference sources and comparing results with the quality baseline.
206
+
207
+ For conversion diagnostics, `rustypaper probe paper.pdf --pages` summarizes the PDF,
208
+ and `rustypaper dump paper.pdf --page 0 --pretty` shows the extracted page data.
209
+
210
+ ## License
211
+
212
+ Licensed under [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE), at your option.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rustypaper"
3
- version = "0.2.2"
3
+ version = "0.2.3"
4
4
  description = "Structure-aware conversion of born-digital scientific PDFs to Markdown, Typst and JSON."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"