Skip to main content

PDF to Markdown

Convert PDFs to clean Markdown and RAG-ready JSONL chunks, locally:

  • Reading order for one- and multi-column pages (column gutters are found before rows, so two columns are read column by column), rotated pages and sideways text.
  • Headings from font size and weight, nested by section numbers (3.2.1 sits under 3.2); lists (bullets and numbers); code blocks from monospaced text; links ([text](url)); footnotes ([^1] references with the notes at the end).
  • Tables: ruled tables, tables ruled only between columns or every few rows, and rule-bounded tables without vertical lines (booktabs style). Plain tables become Markdown tables; merged cells become HTML tables with rowspan/colspan.
  • Clean text: repeated headers/footers, page numbers and running heads removed; line-end hyphenation repaired (com-pile becomes compile, English-to-German keeps its hyphen); ligatures (fi, fl, ...) expanded.
  • Images optionally extracted as PNGs (deduplicated) and linked from the Markdown in a ZIP.
  • Page ranges (1-5,9,12-).
  • Chunks for retrieval: JSONL with id, source, text, tokens, pages, heading_path, start, end. Each chunk is an exact slice markdown[start:end]; chunks start at headings, never exceed the token limit, repeat about overlap tokens when a section is split, and together cover every character.

Runs offline. Scanned PDFs without a text layer are reported clearly ("no text layer"); there is no OCR.

Install (no administrator)

irm https://raw.githubusercontent.com/chayprabs/localtools/main/pdf-to-markdown/install.ps1 | iex
curl -fsSL https://raw.githubusercontent.com/chayprabs/localtools/main/pdf-to-markdown/install.sh | bash
# Or, with Python 3.12+ on any OS:
pipx install localtools-pdf-to-markdown

Portable ZIPs: Windows, macOS and Linux releases.

Use

Run localtools-pdf-to-markdown and the UI opens at http://127.0.0.1:47104. Choose a PDF, optionally set pages, chunk size and overlap, tick "Extract images", and Convert. Preview the rendered Markdown, the raw Markdown or the chunks table, then download the .md, the ZIP with images, or the .jsonl.

localtools-pdf-to-markdown convert paper.pdf -o paper.md
localtools-pdf-to-markdown convert paper.pdf -o paper.zip          # Markdown + images/page-N-K.png
localtools-pdf-to-markdown convert book.pdf --pages 23-30 > ch1.md
localtools-pdf-to-markdown chunks paper.pdf --max-tokens 512 --overlap 64 -o chunks.jsonl

Options: --pages, --images (with -o FILE.zip), --max-tokens 64-8192 (default 512), --overlap (0 to half of max, default 64). Exit code 0 on success, 2 on error (one line on stderr); warnings (e.g. pages without a text layer) go to stderr. Outputs are written to a temporary file and renamed, so a failure never leaves a partial file.

tokens is a conservative estimate without a tokenizer download: the larger of characters/4 and 4/3 per word or symbol. Measured against OpenAI's cl100k tokenizer on the test PDFs it averages 1.26-1.30x the real count (range 0.89-1.6x per chunk), so keep about 10% headroom below a hard model limit.

API: POST /api/convert (multipart: file; fields pages, max_tokens, overlap, images = 1/0, format). With format=markdown, jsonl or zip the response is that file. The default (json) returns the summary, the Markdown (first 2 million characters), the first 500 chunks and a job id; GET /api/file?job=<id>&name=document.md|chunks.jsonl|document.zip|images/page-N-K.png serves the full files of the last three jobs while the tool runs.

curl -F file=@paper.pdf -F format=markdown http://127.0.0.1:47104/api/convert

Limits

64 MiB and 1,000 converted pages per PDF (use a page range for longer documents), 200,000 characters and 100,000 drawing objects per page, 2,000 images (40 megapixels each, 400 in total), 20 million characters of Markdown, 120 seconds per conversion, two conversions at a time (more get HTTP 503). Each conversion runs in a separate worker process that is killed on timeout, when the browser cancels, or when the tool exits. Workers get a 2 GiB memory limit on Windows (job object) and Linux (address space); macOS does not allow that limit, so there the page and object caps bound memory. Temporary folders are deleted after each job; leftovers from a crash are swept at the next start.

Engine and why

PDFium (Chrome's PDF engine) through pypdfium2 5.14.0 (Apache-2.0/BSD-3-Clause) supplies characters with positions, font size and weight, link annotations, vector paths and images, and repairs broken PDFs. The layout analysis on top (XY-cut reading order, lines, paragraphs, headings, lists, footnotes, header/footer removal, chunking) is this tool's own code; ruled-table detection adapts pdfplumber's algorithm (MIT) onto PDFium's paths.

Alternatives considered: docling (MIT) has ML layout and table models, but pulls PyTorch and model weights (gigabytes, no macOS Intel builds for current PyTorch), far too heavy for a small offline tool. pdfplumber/pdfminer.six (MIT) were the first candidate; pdfminer's pure-Python parsing measured 0.3-1.7 s per page on these test PDFs against 0.02-0.04 s with PDFium, so PDFium does the parsing. PyMuPDF / pymupdf4llm are AGPL and are used only in the tests, as an independent reference.

Measured against PyMuPDF's text (share of its words we keep / reading-order similarity): ResNet (CVPR two-column) 0.992 / 0.910, TraceMonkey (ACM two-column) 0.997 / 0.969, Attention Is All You Need 0.962 / 0.933, IRS Form W-9 0.991 / 0.980, Think Python chapter 1 0.980 / 0.989. The 64 data rows of the IRS Pub 15-T weekly wage-bracket table match PyMuPDF's table cells exactly.

Not included

  • OCR: scanned pages have no text layer and are reported as such.
  • Equations: math is kept as the text the PDF contains (often imperfect), not LaTeX.
  • Tables without any rules (aligned by whitespace only) stay as text lines; booktabs tables (horizontal rules only) are detected.
  • Inline bold/italic are not marked (only headings use font weight).
  • Password-protected PDFs: remove the password first.
  • Text drawn inside figures (chart labels) is kept as paragraphs, and fonts without a Unicode map produce dropped characters (a warning names the pages).

Update / uninstall

localtools-pdf-to-markdown update / localtools-pdf-to-markdown uninstall. If you installed with pipx: pipx upgrade localtools-pdf-to-markdown / pipx uninstall localtools-pdf-to-markdown.

MIT license. Bundled components: see THIRD_PARTY_NOTICES.md.

Metadata

Release files for localtools-pdf-to-markdown 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for localtools-pdf-to-markdown 1.0.0
File Size Uploaded Provenance
localtools_pdf_to_markdown-1.0.0.tar.gz 148.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for localtools-pdf-to-markdown 1.0.0
File Interpreter ABI Platform
localtools_pdf_to_markdown-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 304.4 kB

Release files / localtools_pdf_to_markdown-1.0.0.tar.gz

Download URL localtools_pdf_to_markdown-1.0.0.tar.gz
Size 148.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8b5b9b243c210f9542fb64a9e104e8387fd6a0dfcadc1c1a9c35974d54987ff5
BLAKE2b-256 checksum
How to use checksums
1d33440bd38935b585753843f7eaf0444f94c9fb61806c1f4021eb2bf4490033
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / localtools_pdf_to_markdown-1.0.0-py3-none-any.whl

Download URL localtools_pdf_to_markdown-1.0.0-py3-none-any.whl
Size 155.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6099734d3d44648db93e0e81f08d5a8527100d50b75f74524ebe4faa61120a2a
BLAKE2b-256 checksum
How to use checksums
caaf1d688497f222dce30c767076619c9574e8966a8c15acd797892aebbd0cac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Security for localtools-pdf-to-markdown 1.0.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page