shrink: smaller images where they sit, proven pixel for pixel¶
The problem¶
Lossless optimisers such as jpegtran and oxipng often take 5 to 20 percent off photos and screenshots with no visible change. Running one over a folder of originals means trusting it: a wrong flag, a buggy build or a lossy tool used by mistake, and the damage is silent and permanent. So most people never run it, or keep a second copy of everything, which defeats the point.
The method¶
Don't trust the optimiser. Check its work the way a viewer sees it.
- Shrink to a temp copy beside the original. Same folder, so the final rename never crosses a disk.
- Keep it only if it is smaller.
- Decode both and compare. JPEG through
djpeg -ppm, PNG through ImageMagick at 16 bits with alpha; the decoded bytes are hashed and must match exactly. A failed decode counts as a failed proof. - Check the original did not change while you worked (size, modified time, inode).
- Copy dates and mode across, then rename over the original. Atomic: the file is the old one or the new one, never half of each.
Measuring is the default; nothing changes until --write. Because the proof
checks the result rather than the tool, any shrink command plus any decode
command is a rule, and a lossy one is caught rather than trusted. A JPEG
re-saved at quality 30 is refused; jpegtran's output is accepted.
Sample¶
The proof and the swap, in Python:
a, b = decoded(decode_cmd, path), decoded(decode_cmd, tmp) # SHA-256 of raw pixels
if a is None or a != b:
return "failed" # the original stays
now = path.stat()
if (now.st_size, now.st_mtime_ns, now.st_ino) != (st.st_size, st.st_mtime_ns, st.st_ino):
return "changed" # written to while we worked
shutil.copystat(path, tmp) # dates and mode
os.replace(tmp, path) # atomic
Use it:
shrink photos/ # measure: shrink and prove each file, change nothing
shrink --write photos/ # replace the proven, smaller files
shrink --rule .webp "cwebp -lossless -z 9 {in} -o {out}" "dwebp {in} -ppm -o -" photos/
Limits¶
- It proves pixels, not bytes. The built-in rules keep all metadata; a rule that strips metadata still passes.
- The proof is only as fine as the decoder's output, so PNGs decode at 16 bits.
- Hard-linked files, symlinks and hidden folders are skipped.
- On macOS, extended attributes and Finder tags are not copied across.
Code¶
methods/shrink/ in the methods repository: the script, a README and a test.