MediaToolz
A toolbox of CLI commands for images: resize, convert and recompress them in bulk by rules, and generate compact placeholders for them. One binary, one subcommand per job, each safe by default — a preview first, a backup before anything is overwritten.
The package started as part of DevToolz and has been separate since DevToolz 0.5.0. Its commands, flags and settings are the same; see Moving from DevToolz.
Features
image-hash— generates hazehash, blurhash and/or thumbhash placeholders for raster images. Takes files and/or directories (comma-separated too),-rwalks subdirectories. Prints to stdout by default;-ocollects everything into one file,--per-file/--out-dirwrite a file per image (photo.jpg→photo.jpg.blurhash.txt, with--suffixand--out-extto rename). Formats:json,plain(just the hash text),csv, andts/jsmodules to import. Needs the nativesharplibrary, which the command offers to install on first use.image-batch— produces resized, converted and recompressed versions of raster images in bulk, by rules kept in a reusable config or given as flags: sizes by width, height, box, long or short side, megapixels or percentage, scales, formats (jpg, png, webp, avif, gif, tiff, heif), an optional limit on the size of every file, codec options such as quality,mozjpegor a png palette, and file names from a template ({dir}/{name}-{width}w.{format}). The config holds only the rules; the folders are chosen on every run. The results go into a separate folder (-o), next to each source (--beside), or over the sources themselves (--replace) to shrink or recompress originals in place — guarded by a confirmation, a backup with a journal, a replace-only-if-smaller rule andimage-batch restore, with a--dry-runthat shows the real before and after sizes.-rwalks subfolders,--selectpicks files from an interactive list,--listonly prints them. An existing result is skipped when an earlier run already made it, and asked about otherwise.--emitwrites a manifest with sizes and, optionally, hazehash placeholders.initcreates configs, andconfigedits, copies and deletes them. Needs the nativesharplibrary, offered at the first run.ui— starts a local web interface and opens it in the browser, so both commands can be run with forms, tables and previews instead of flags:image-hashwith a gallery of the placeholders decoded next to each image,image-batchwith configs, sharpening presets with a before and after preview, and backups. The server listens on this machine only, behind a one-time token, and nothing is written without an explicit choice.
image-hash writes files only when you name an output (-o, --per-file, --out-dir) and prints to stdout otherwise. image-batch writes into the folder given with -o or next to the sources with --beside, and over the originals only with --replace — after a confirmation, with a backup you can restore. Every command supports --json for machine-readable output.
Output & colors
Both commands color their output with one shared palette: paths in cyan, names and kinds in yellow, problems in bold red, what a command would do in bold yellow and what it did in bold green, hints dimmed with the flags they mention (--dry-run, --yes) picked out in cyan.
Color is on in a real interactive terminal and turns itself off when output is piped, when CI or NO_COLOR is set, or when TERM=dumb. Four things override that:
--color(orFORCE_COLOR=1) turns it on anyway — formediatoolz … --color | less -R, or a CI log that renders ANSI.--plainturns off color, the banner and the celebration copy together.--quietonly drops the banner and the output of a clean run; color stays.--jsonprints the report as data, with no styling at all.
The text is the same with and without color — only escape codes are added, so a colored log still reads fine once they are stripped.
How It Works
The heavy lifting — decoding, resizing, sharpening and encoding — is done by sharp, which comes with the package and is loaded only when there is an image to process. The placeholder algorithms (hazehash, blurhash, thumbhash) are small pure-JavaScript packages. Sizes and file names are computed before anything is written, so --dry-run can show the real result without touching the disk, and an existing result is never overwritten without a question.