A local PDF converter. Everything runs on this machine; nothing is uploaded.
pip install localpdf
The distribution is called localpdf because PyPI already has a project too
close to pdfc; the command it installs is still pdfc. Add [ocr] if you
want OCR: pip install localpdf[ocr].
brew install 6meowscles/tap/pdfc
macOS or Linux. The formula builds a virtualenv of its own, and pulls in cairo and pango because weasyprint loads them at import time.
git clone https://github.com/6meowscles/pdfc
cd pdfc/packaging/aur && makepkg -si
That builds a real package from the latest release and installs it with
pacman, so pdfc lands in /usr/bin and its dependencies come from the
official repositories. makepkg runs the test suite as part of the build.
pdfc is not on the AUR; the PKGBUILD lives here, so it is built from the
checkout rather than fetched by an AUR helper.
There is no COPR repository yet, so build the RPM from the spec in this repository:
sudo dnf install rpm-build rpmdevtools python3-devel pyproject-rpm-macros
rpmdev-setuptree
spectool -g -R packaging/copr/pdfc.spec
rpmbuild -ba packaging/copr/pdfc.spec
sudo dnf install ~/rpmbuild/RPMS/noarch/pdfc-*.noarch.rpm
./install.sh
That creates .venv/, installs the package, and links ~/.local/bin/pdfc.
If a dependency has no wheel for your Python, rerun with an older one:
PYTHON=python3.12 ./install.sh.
Note that this install stays tied to the checkout: deleting or rebuilding
.venv/ breaks the linked command. The Arch package has no such link.
pdfc scan.pdf out/page.png --dpi 300 # render pages to images
pdfc notes.md notes.pdf # markdown to PDF, via HTML
pdfc report.docx report.pdf # needs libreoffice
pdfc scan.pdf notes.txt # extract text
pdfc merge a.pdf b.pdf -o all.pdf
pdfc split big.pdf --pages 1-5,9 -o out/
pdfc split big.pdf --each -o pages/
pdfc rotate scan.pdf --angle 90 -o fixed.pdf
pdfc compress big.pdf --quality ebook -o small.pdf
pdfc ocr scan.pdf -o searchable.pdf
pdfc routes lists every conversion and whether its dependencies are installed.
--dry-run, -f/--force, --progress, -q and -v belong to each command
rather than to pdfc itself, so they follow the positional arguments:
pdfc notes.md notes.pdf --dry-run # prints the route and the output paths
pdfc split big.pdf --each -o pages/ -f
| Feature | Needs |
|---|---|
| Office formats (docx, odt, pptx, xlsx) | libreoffice |
| OCR | tesseract, ocrmypdf |
| Compression, and the OCR text layer | ghostscript |
| Any PDF output | pango and cairo, for weasyprint |
You do not need to look these up. When a conversion needs something that is
missing, pdfc names it and prints the command for your system — pacman,
apt, dnf, zypper or brew, chosen from /etc/os-release:
$ pdfc report.docx report.pdf
error: converting docx → pdf needs libreoffice
install it with: sudo apt install libreoffice
pdfc routes lists every conversion up front and marks which are blocked.
OCR is the one dependency no install method pulls in for you, because it drags the whole tesseract stack behind it. Add it deliberately:
pip install localpdf[ocr]
or install your distribution's own ocrmypdf package.
Each step prints its verb while it runs and again, past tense, when it finishes:
rendering pdf → png ████████░░░░ 8/12 0:03
rendered pdf → png 12 files → out/ 4.2 MB 5.1s
Progress goes to stderr, so piping stdout stays clean. --progress bar|plain|none overrides the default, which is a bar on a terminal and plain
lines everywhere else.
docs/design.md covers the architecture: the converter registry, the
two-hop routing rule, format detection, output-path templating, and the
error/exit-code contract.
.venv/bin/pytest
GNU AGPL-3.0-or-later — see LICENSE.
This is not a preference so much as an inheritance: pdfc is built on
PyMuPDF, which is dual-licensed AGPL-3.0 or
commercial, and PyMuPDF does the real work here — rendering, text extraction,
and the page operations. A work built on it and distributed has to carry the
same terms, so a permissive license would be promising something these
dependencies do not allow.
The external tools pdfc shells out to — ghostscript, libreoffice, tesseract —
run as separate processes and do not affect this. The rest of the Python stack
is permissive: click and markdown (BSD), pillow (MIT-CMU), rich (MIT),
ocrmypdf (MPL-2.0).