Make scanned PDFs much smaller — without making the text harder to read.
A 10-page contract straight out of a flatbed scanner:
| size | ||
|---|---|---|
| original | 13.63 MiB | 300 dpi colour JPEG per page |
pdfshrink scan.pdf |
1.43 MiB | 89% smaller |
pdfshrink -m supertiny scan.pdf |
0.58 MiB | 96% smaller, and sharper than the line above |
The original file is never modified.
Needs pdftoppm + pdfinfo (poppler) and magick (ImageMagick 7).
# Arch / Omarchy
sudo pacman -S --needed poppler imagemagick
# Debian / Ubuntu
sudo apt install poppler-utils imagemagick
# macOS
brew install poppler imagemagickThen:
git clone https://github.com/technologylab-ai/pdfshrink.git
ln -s "$PWD/pdfshrink/pdfshrink" ~/.local/bin/pdfshrinkpdfshrink scan.pdf # -> scan-tiny.pdf
pdfshrink -m supertiny scan.pdf # -> scan-supertiny.pdf
pdfshrink -m supertiny -o send-me-this.pdf scan.pdfpdfshrink --help explains every option in plain language.
tiny keeps shades of grey. Safe for any scan. Use it when the pages have
photos, pencil marks, faint handwriting, or shaded stamps.
supertiny is pure black and white — no greys at all. Use it for contracts,
invoices, letters, forms. Don't use it if the page has photos or faint pencil,
because anything mid-grey is forced to either black or white.
Emailing a text document? Use
supertiny. Not sure what's on the pages? Usetiny.
The obvious way to shrink a scan is to throw away pixels — drop 300 dpi to 150, then to 100, and squeeze the JPEG quality down. Do that and the text goes soft long before the file gets genuinely small. On the contract above, that approach hit a wall at about 1.05 MiB no matter how the knobs were set.
The reason is what those bits are being spent on. A scanned page is mostly paper, and paper is not a flat colour — it's grain, speckle, and a faint gradient from the scanner lamp. JPEG faithfully encodes all of it. Most of the file is a detailed recording of blank paper.
supertiny throws the grain away instead of the pixels. Each page is reduced to
one bit each — ink or not-ink — using an adaptive local threshold, then stored
with CCITT Group 4, the encoding fax machines and scanners use for exactly this
kind of image. Blank paper becomes free, and the savings buy back full
scanner resolution: every original pixel of every letter is kept.
That's the whole trick. It's why supertiny reads more crisply than a 100 dpi grayscale JPEG that's twice its size.
The catch is real and worth repeating: one bit per pixel means no grey exists anymore. Great for ink on paper, destructive for a photograph.
- Pages are rasterised with poppler, so ghostscript is never invoked and ImageMagick's PDF read policy (which blocks PDF input on many distros) can't get in the way.
--dpinever upsamples past what the scanner actually captured; feed it a 150 dpi scan andsupertinyrenders at 150, not 300.- Pages are processed in parallel, one per core by default (
--jobs). - Output is checked for page count before it's accepted, and the script refuses to overwrite its own input.
MIT — see LICENSE.