Skip to content

About

Local-first document converter: PDF, Markdown and text to Markdown, HTML, plain text and Docling JSON. Command line, browser workbench and a packaged macOS app. Documents never leave your machine.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Document Converter

English | 繁體中文 | 简体中文

A local-first document converter: a command-line tool, a browser workbench that runs on your own computer, a packaged macOS app, and an agent skill (SKILL.md) for Codex and Claude. Documents are converted on your machine; nothing is uploaded to a remote service.

How it was built, and the ten defects that looked fine until they were checked: the case study, also in 繁體中文 and 简体中文.


1. What it converts

Inputs. What a given install accepts depends on which engines it has.

Input From source, Docling installed macOS app, text profile macOS app, pdf profile macOS app, office-ocr profile
Markdown .md .markdown ✅ ✅ ✅ ✅
UTF-8 text .txt ✅ ✅ ✅ ✅
PDF with a text layer ✅ ❌ ✅ ✅
PDF that is a scan or photo ✅ with OCR: Docling's models (downloaded on first use), or on a Mac the apple-vision extra ❌ ❌ ✅ macOS's own OCR
Office .docx .pptx .xlsx and older ✅ (.docx .pptx .xlsx also with just the office extra, no PyTorch) ❌ ❌ ✅ .docx .pptx .xlsx only
.html .htm .epub .csv .rtf OpenDocument ✅ ❌ ❌ ❌
Images .png .jpg .jpeg .webp ✅ with OCR, as for a scan ❌ ❌ ✅ macOS's own OCR

A file the install does not accept is refused before any conversion starts, and the message names the formats that would work — for example, from the pdf app: 這個版本不支援「.docx」檔案。可以轉換的格式:.markdown、.md、.pdf、.txt。

A text file must be UTF-8. A Big5, GBK or UTF-16 file is refused with a message saying so and asking you to re-save it as UTF-8; it is not converted into mojibake.

Limits. The web page and the macOS app take up to 5 files per conversion, each up to 24 MiB (about 25 MB as Finder counts it), 25 MiB (about 26 MB) per request. A MiB is 1,048,576 bytes; the MB Finder shows is 1,000,000, so a file Finder lists as 25.1 MB is still accepted. The CLI has no size or file-count limit.

Nothing is ever returned empty. If a conversion recovers no text — a scan with no text layer, a page that is one picture, an empty file — the answer says that and why, rather than downloading a 0-byte file.

Outputs.

Output From source (CLI and browser) macOS app, text profile macOS app, pdf profile macOS app, office-ocr profile
Markdown (.md) ✅ ✅ ✅ ✅
HTML (.html) ✅ ✅ ✅ ✅
Plain text (.txt) ✅ ✅ ✅ ✅
Docling JSON (.json) ✅ when a Docling engine parsed the file — ✅ PDF input only ✅ Office files and PDFs with a text layer

Docling JSON is the engine's own structural parse of a document, so it exists only where an engine read the file. Markdown and text files are read directly, and the text app runs no engine at all.

2. macOS app

It runs on Apple Silicon (M-series) Macs only. Three reviewed profiles exist:

Profile Accepts Bundles
text UTF-8 .md, .markdown, .txt No document engine and no model
pdf The above, plus PDFs that already contain a text layer Docling's model-free PDF reader — no OCR, no AI model, no PyTorch, nothing downloaded
office-ocr The above, plus Word, PowerPoint and Excel (.docx, .pptx, .xlsx), scanned PDFs and images (.png, .jpg, .jpeg, .webp) The pdf profile, Docling's Office readers and PyObjC, which reaches the text recognition built into macOS — no OCR engine, no AI model, no PyTorch, nothing downloaded

The pdf profile extracts the text a PDF already holds. It does not rebuild heading levels or tables, and a scanned PDF has no text layer: the app says so instead of returning an empty file. Office documents and images are not accepted by the text or pdf profile.

The office-ocr profile reads a PDF's text layer first and hands a page-image PDF, or an image, to macOS's own text recognition (Apple's Vision framework, the recognizer Photos uses to select text in a picture). Recognized text comes back as paragraphs, without heading levels or tables, and the page says it should be checked. A PDF that mixes text pages with scanned pages is read from its text layer only, so its scanned pages are left out. Word, PowerPoint and Excel keep their headings, lists and tables. Older .doc, .ppt and .xls are not accepted.

Opening the app

  • An app you built yourself opens with a double-click: macOS only gates files that arrived from the internet.
  • An app you received — downloaded, sent by AirDrop or through a chat app — is blocked on first launch, because the candidate is only ad-hoc signed, with no Developer ID signature or Apple notarization. From macOS 15 onward, Control-click › Open no longer gets past this. Try to open the app once, then go to System Settings › Privacy & Security, find the app under Security, choose Open Anyway and enter an administrator password.

Do not disable Gatekeeper to get around this.

Using it

  1. Double-click Document Converter.app. It starts a local service and opens your default browser at http://127.0.0.1:<port>.
  2. Drop in or select up to 5 files. Each file, and the selection as a whole, may be up to 24 MiB (about 25 MB).
  3. Choose an output format and select Convert. One file downloads on its own; several download as a ZIP. Each download is named after the document it came from, Chinese file names included.
  4. Uploads are held in the system's temporary folder under generated names and removed after every conversion.
  5. Closing the browser does not stop the app. To quit it, open Activity Monitor, find Document Converter and quit it.

You do not need Python, Node.js, Docker or VS Code to run the app.

Status

✅ Verified on an Apple Silicon Mac (2026-10-12/13) pdf candidate built, signed ad-hoc and zipped; opened like any app and converted a real document; its frozen runtime reported no forbidden module; it carried 124 third-party notice files
✅ Rebuilt and checked (2026-11-08, macOS 27.2) pdf candidate built from ccd843d, with Pillow 13.0.0, so it has the plain text and Docling JSON outputs and the download names; the 9 release tests pass; --diagnostics reports pdf-text and no forbidden module; pip-audit finds no known vulnerability in its pinned versions; the frozen app, started without a browser, converted a Chinese-named text-layer PDF to text and JSON under its own name, returned two files as a ZIP, refused .docx and explained a scan. Not yet opened through Finder
⏳ Not yet built The office-ocr candidate. CI installs its pinned macOS lock on an Apple Silicon runner and runs it unfrozen with the real Vision framework, reading back a picture of English and Traditional Chinese; freezing it needs the audited Python build on the owner's Mac
⏳ Not yet verified Installing on a second Mac — docs-release/macos-vm-verification.md covers it with a free macOS virtual machine
➖ Not planned Developer ID signing and Apple notarization — the owner decided on 2026-10-29 to stay with ad-hoc signing, since the app is not sold through the App Store and goes to few people (ROADMAP); recipients open it once as described above, and every candidate stays marked distribution_ready: false
❌ Not available A Windows app — there is no installer; running from source on Windows is covered below

Building it

RELEASE_PROFILE=pdf BUILD_PYTHON="$HOME/.local/bin/python3.12" \
  sh scripts/packaging/bootstrap_macos.sh --output-dir build/private-release/candidate-pdf

Use RELEASE_PROFILE=office-ocr and another output directory for the office-ocr profile, or leave RELEASE_PROFILE out for the text profile. The full build and acceptance procedure is in docs-release/macos.md.

3. From source (developers)

Python 3.11 to 3.14 is supported; CI tests 3.11 and 3.12.

python -m venv .venv
source .venv/bin/activate          # Windows PowerShell: .\.venv\Scripts\Activate.ps1
python -m pip install -U pip

If python -m venv fails, the Python install lacks the venv module. On Debian or Ubuntu, install it with sudo apt install python3-venv and run the line again. Or create the environment with uv, which does not need that module, and keep uv pip in place of pip below:

uv venv .venv && source .venv/bin/activate
uv pip install -e .

Avoid pip install --user: newer Linux distributions refuse it outside a virtual environment (PEP 668), and it mixes this project's packages into your user site.

Choose the installation tier that matches your needs:

  • Minimal install (UTF-8 Markdown / plain text only + CLI + PDF text-layer detection):

    pip install -e .

    Without Docling installed, .md and .txt files convert directly; PDF/Office documents show not detected under list-engines, and convert reports engine unavailable rather than an installation error.

  • Common install (adds Docling for PDF, Office, and layout conversion):

    pip install -e ".[docling]"
  • Browser workbench:

    pip install -e ".[web]"
    # or with Docling:
    pip install -e ".[docling,web]"
  • Full install (Docling + web workbench):

    pip install -e ".[full]"
  • Office without PyTorch (.docx, .pptx, .xlsx through Docling's readers, about 0.4 GB, no model):

    pip install -e ".[office]"
  • OCR on a Mac with nothing to download (scanned PDFs and photos, read by the text recognition built into macOS):

    pip install -e ".[apple-vision]"

On Windows, a source install is checked in CI: a job installs it with the web extra on windows-latest (Python 3.12) and the test suite passes. Converting Markdown and plain text, and the browser workbench, work there. A second job adds the docling extra and passes with no test skipped, so text-layer PDFs convert on Windows too. CI downloads no Docling models, so the model pipeline (layout, tables, OCR) has not been checked on Windows.

On Windows, docling-native does not render page images: Docling's page renderer corrupts memory there when its worker threads exit (docling-parse #357), which crashed conversions at random in CI. The text, Markdown and HTML are the same; the Docling JSON simply carries no picture of each page. Docling's model pipeline needs those pictures, so it still renders them and remains exposed until docling-parse is fixed.

Browser workbench

document-converter web             # http://127.0.0.1:8765 ; --port 8766 for another port

The server binds to loopback only. The same limits as the app apply: up to five files, 24 MiB (about 25 MB) each and in total, 25 MiB (about 26 MB) per request. It uses the CLI's auto engine selection, so it uses whichever engines are installed — Marker and MinerU included — but it never installs one.

Command line

document-converter convert paper.pdf --to md
document-converter convert paper.pdf --to md --to html --to json --to txt
document-converter convert ./documents --to md --output ./converted
document-converter list-engines

Choose an engine explicitly:

document-converter convert paper.pdf --engine docling --to md
document-converter convert paper.pdf --engine docling-native --to md   # no PyTorch, no model download
document-converter convert report.docx --engine docling-office --to md  # Word/PowerPoint/Excel, no model
document-converter convert scan.pdf --engine apple-vision --to md       # macOS built-in OCR
document-converter convert paper.pdf --engine marker --to md
document-converter convert paper.pdf --engine mineru --to md

Remove Markdown noise:

document-converter convert paper.pdf --to md --clean
document-converter convert paper.pdf --to md --clean --strip-page-numbers

--clean removes labelled page markers such as Page 3 of 12, 4 / 20 and - 5 -. It keeps lines holding only digits, because engines put table cells and other values on their own line; add --strip-page-numbers only when a document's page numbers survive as bare numerals and you accept losing standalone numbers with them.

Parallel batch conversion

document-converter convert ./documents --to md --output ./converted --parallel 4
  • Default is 1 worker; the safe upper bound is 4.
  • Use higher values when converting many files in one run (directory or multiple inputs).
  • A single large PDF rarely benefits: work is dominated by the conversion engine, and in-process engines share the interpreter GIL.
  • Failed files do not abort the rest of the batch.

PDF without PyTorch (docling-native)

Docling's default PDF pipeline runs layout and table models: it needs PyTorch, a multi-gigabyte install, and downloads model weights on first use. docling-native uses Docling's model-free NativePdfPipeline instead:

pip install "docling-slim[convert-core,format-pdf]" typer rich pypdf
pip install -e . --no-deps

That install is about 0.4 GB. It converts PDF only, rebuilds no structure, runs no OCR, and records that limitation as a warning on every conversion. auto tries it last, so model-based engines are preferred wherever they are installed.

Office without PyTorch (docling-office)

Word, PowerPoint and Excel files need no model at all: Docling reads them with python-docx, python-pptx and openpyxl and keeps their headings, lists and tables. docling-office restricts Docling to those three formats, so it never reaches a pipeline that wants model weights. pip install -e ".[office]" installs it; auto uses it when the full Docling is not installed. Pictures inside a document stay pictures: their text is not read.

OCR

A scan or a photo has no text to extract; it has to be recognized. Two ways are supported, and auto picks whichever is installed:

Docling's models apple-vision
Install pip install -e ".[docling]" pip install -e ".[apple-vision]"
Runs on macOS, Linux, Windows macOS only
Downloads Layout model from Hugging Face, OCR model (RapidOCR) on first use Nothing: the recognizer is part of macOS
Gives back Headings, tables and reading order Paragraphs only
Languages RapidOCR's Chinese and English model Traditional Chinese, Simplified Chinese, English

apple-vision uses Apple's Vision framework, the same recognizer that lets Photos select text in a picture. It renders each PDF page at 300 dpi, reads it, and rebuilds paragraphs from the gaps between lines. Every conversion carries a warning that the text was recognized and should be checked. CI checks both: a page drawn with English and Traditional Chinese is read back by Docling's models on Linux and by Vision on an Apple Silicon Mac.

Optional engines

pip install ".[marker]"   # check the package and model license terms first
pip install ".[mineru]"   # MinerU 4.x; read docs/LICENSE_AUDIT.md first

The mineru extra installs MinerU 4.x, which brings PyTorch and fetches its model files from Hugging Face or ModelScope (mineru-models-download). This project runs only mineru-kit parse, on your machine, and never passes MinerU's remote-service options. MinerU's other command, mineru, collects usage telemetry for mineru.net: it asks on first run, with yes as the default, and mineru telemetry disable turns it off.

4. How it works

Every engine produces one normalized conversion result, and the writer turns it into the requested outputs. Parsing stays separate from rendering, so an input format or an output can be added without touching the CLI. Engines sit behind adapters in document_converter/engines/; output serialization lives in writer.py.

What it is built on

This project writes the interfaces, the engine selection, the scanned-PDF detection, the Markdown cleaner, the renderer and the packaging. The conversion itself is done by these:

Part Component License Bundled in the macOS app?
PDF reading, no model Docling docling-slim, docling-core, docling-parse MIT ✅ pdf, office-ocr
PDF parsing underneath it pypdfium2 and Google's PDFium BSD-3-Clause / Apache-2.0 ✅ pdf, office-ocr
Browser interface FastAPI, Starlette, Uvicorn MIT / BSD ✅ all three
Command line Typer, Rich MIT — the apps have no command line
Scanned-PDF detection pypdf, or a built-in stream reader when it is absent BSD-3-Clause — the apps read the text layer directly
Packaging into an app PyInstaller GPL-2.0-or-later with its Bootloader exception ✅ bootloader only
PDF with layout and table models Docling's model pipeline, needing PyTorch and downloaded weights MIT code, model terms separate ❌
Office reading, no model python-docx, python-pptx, openpyxl through Docling MIT ✅ office-ocr
OCR in Docling's model pipeline RapidOCR with PaddleOCR models, run by ONNX Runtime Apache-2.0 / MIT ❌
OCR on macOS Apple's Vision framework, reached through PyObjC Part of macOS / MIT ✅ PyObjC in office-ocr; Vision is part of macOS
Alternative PDF/OCR engines Marker, MinerU Apache-2.0 code; separate model and additional terms ❌

OCR: this project bundles none. No OCR engine or model is included in any macOS profile. The text and pdf apps report a scan as having no text layer rather than guessing at it; the office-ocr app asks the recognizer macOS already has, through PyObjC. From source, OCR comes from Docling's model pipeline, from apple-vision (which uses the recognizer macOS already has), or from Marker or MinerU under their own terms — see docs/LICENSE_AUDIT.md, which records what was checked and when.

Fork it and run your own

The repository is public so that it can be read and run. It is not open source (section 8): forking to read, study or run it is fine, and republishing or selling the project's own software is not.

# 1. Fork on GitHub, then clone your fork
git clone https://github.com/<your-account>/document_converter.git
cd document_converter

# 2. Python 3.11 to 3.14
python -m venv .venv && source .venv/bin/activate
python -m pip install -U pip

# 3. Markdown and text only, no engine, smallest install
pip install -e ".[web]"

# 4. Add PDF without PyTorch - about 0.4 GB, downloads no model
pip install "docling-slim[convert-core,format-pdf]"

#    or add PDF with layout and table models - multi-gigabyte, downloads weights
#    pip install docling

# 5. Check what it found, then start the browser interface
document-converter list-engines
document-converter web

list-engines prints which engines this install actually has, so step 5 tells you what you really got rather than what the documentation hopes for.

To run the tests and the checks this project runs on itself:

pip install -e ".[dev,web]"
python -m pytest
document-converter --help
document-converter list-engines
python3 scripts/packaging/audit_notices.py --profile pdf   # needs network

Building the macOS app needs an Apple Silicon Mac; see docs-release/macos.md.

5. Your documents

Important

  1. Before converting any document — PDF, Office file, image or scan — make sure you hold the right to process and, where relevant, distribute it.
  2. Never commit client confidential material, real business documents, personal data or unlicensed copyrighted documents to this repository.
  3. The automated tests use only synthetic, public-domain or non-sensitive documents.

6. Security and privacy

  • Local-first. Documents are processed by locally installed engines. Network behaviour has not been audited for every engine, package and model downloader combination; check the engine you select before processing sensitive files.
  • Uploads. Kept under generated temporary names and removed after each request, including failed ones.
  • Logging. The CLI reports status and errors. Third-party engines may log on their own.
  • Sensitive files. .gitignore covers common outputs, credentials, temporary assets and model caches. It does not remove files already tracked; check git status before every commit.

7. Support

This is a personal project, published so that it can be read and used. It comes as it is, with no commitment to support, to answer questions, to fix a problem or to keep it working. Issues and pull requests may go unanswered. Before you process anything that matters, check the output: the limits each engine has are described above and recorded as warnings on every conversion.

8. Licenses

This project. Copyright (c) 2026 Jake Chiu, under a proprietary use license: personal use and a company's internal use, including internal commercial use, are permitted; resale and redistribution of the project's own software are not. It is not an open-source license, and this repository being public does not make it one: reading the source here grants no right the LICENSE does not give. The LICENSE file is authoritative; this paragraph only summarizes it.

Third-party components keep their own licenses, and nothing here restricts the rights their authors grant. See THIRD_PARTY_NOTICES.md and docs/LICENSE_AUDIT.md. Each installer carries every component's original license and notice texts in its legal/ folder.

The pdf profile of the macOS app includes software based in part on the work of the FreeType Team and of the Independent JPEG Group.

About

Local-first document converter: PDF, Markdown and text to Markdown, HTML, plain text and Docling JSON. Command line, browser workbench and a packaged macOS app. Documents never leave your machine.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages