npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@macrulez/mediatoolz

v0.1.1

Published

A small toolbox of CLI commands for images — resize, convert and recompress them in bulk by rules, and generate hazehash, blurhash and thumbhash placeholders

Readme

MediaToolz

MediaToolz

A small 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).

It started as part of devtoolz and lives in its own package since devtoolz 0.5.0.

Features

  • image-hash — generates hazehash, blurhash and/or thumbhash placeholders for raster images (jpg, png, webp, gif, avif, tiff). Takes files and/or directories — several of each, comma-separated too — and -r walks subdirectories. Prints to stdout by default; -o <file> collects everything into one file, --per-file / --out-dir <dir> writes a file per image (photo.jpg → photo.jpg.blurhash.txt, with --suffix and --out-ext to rename). Formats: json, plain (just the hash text, no newline), csv, and ts/js modules you can import straight into the app. Without -t it makes blurhash and thumbhash; -t hazehash adds the more compact and more accurate hazehash (--budget sets its size in bytes, 28 by default). Besides the hashes it can produce the dominant color and a tiny PNG preview (-t all), accepts http(s) URLs and path lists from a file or stdin, and can keep an output file in sync: --cache skips unchanged images, --update --prune merges into the existing file, --check fails with exit code 1 when it is stale (made for CI). --dry-run writes nothing and shows the result as a table instead. Uses the native sharp library, which comes with the package — see Requirements.
  • image-batch — produces resized, converted and recompressed versions of raster images in bulk, by rules kept in a reusable config or given as flags: widths, heights, size, longEdge / shortEdge (the same for landscape and portrait), megapixels, percent, scale (@2x), matchOrientation, maxBytes (--max-size 200KB lowers the quality as far as needed), formats (jpg, png, webp, avif, gif, tiff, heif or original), fit (inside, cover, contain, …), codec options (quality as a number or a level low/medium/high/best, mozjpeg, a png palette, webp lossless, avif effort, …) and file names from a template ({dir}/{name}-{width}w.{format}, with {ext}, {index:3}, {hash}, {scale}, {date}). The config holds only the rules; the folders are chosen on every run. Where the results go is one of three: -o <dir> — a separate folder that repeats the source structure (--flat drops it); --beside — next to each source; --replace — over the sources themselves, each in its own format, to shrink oversized originals or recompress them in place. --replace is guarded: it asks for confirmation (--yes without a terminal), copies the originals to .image-batch-backup/<date>/ first with a journal.json, replaces a file only if the result is smaller, never processes the same file twice with the same settings, and --dry-run shows the real before/after sizes; image-batch restore <backup> puts the originals back. Without a size flag it only converts the format. -r walks subfolders, -i/--select ticks files from an interactive list, --list only prints them. A result an earlier run already made is skipped; any other existing file is a conflict — a terminal asks once (overwrite this / this and all next / skip / skip all / quit), without a terminal it is skipped with exit code 1, or use --overwrite, --skip-existing, --no-overwrite. --hazehash (--budget), --blurhash, --thumbhash, --dominant-color with --emit <file> write a manifest of everything produced, with the placeholders. init creates configs, and config shows, edits, copies and deletes them (.mediatoolz/image-batch/ in the project or ~/.mediatoolz/image-batch/ for all projects). sharpen adds output sharpening after the resize — by target and amount, with radius, flat, jagged and threshold for fine control — and image-batch sharpen saves such settings as presets that configs and --sharpen <name> use by name. Uses sharp too — see Requirements.
  • ui — starts a local web interface and opens it in the browser, so the commands can be run with forms, tables and previews instead of flags. Two modules: Image Hash (a gallery of the placeholders decoded next to each image) and Image Batch (convert, edit configs and sharpening presets with a before and after preview, restore backups). It is part of the package, listens on 127.0.0.1 only behind a one-time token, and writes nothing without an explicit choice. --port, --no-open, --cwd.

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, next to the sources with --beside, and over them only with --replace — after a confirmation, with a backup. Every command supports --json for machine-readable output.

Requirements

  • Node.js 20+
  • The sharp image library comes with the package: npm picks its prebuilt binary for your platform during the install, so there is nothing to set up. Only if that binary is missing (an install with --omit=optional, an unsupported platform) does the first run offer to install sharp into ~/.mediatoolz/deps (-y / --yes agrees up front, which is also what you want in CI; without a terminal and without --yes the command stops and says so).

Installation

npm install -g @macrulez/mediatoolz

Or run it without installing:

npx @macrulez/mediatoolz image-batch ./photos -r -o ./out -f webp

Quick start

mediatoolz image-hash public/img                 # blurhash + thumbhash of every image, as JSON on stdout
mediatoolz image-hash public/img -r -t hazehash --budget 24 -o hashes.json   # hazehash of 24 bytes at most
mediatoolz image-hash a.jpg,b.png,photos -r -t blurhash -f csv -o hashes.csv
mediatoolz image-hash public/img -r -f plain --per-file   # photo.jpg.blurhash.txt + photo.jpg.thumbhash.txt
mediatoolz image-hash public/img -r -f ts -t thumbhash -o src/placeholders.ts --name placeholders
mediatoolz image-hash public/img -r --dry-run        # write nothing, show a table of the hashes
mediatoolz image-hash public/img -r -t all --components auto -o hashes.json --cache --update --prune
mediatoolz image-hash public/img -r -o hashes.json --check   # CI: exit 1 if hashes.json is stale

mediatoolz image-batch ./src/images -r -o ./public/images -w 400,800,1200 -f avif,webp,jpg -q high
mediatoolz image-batch ./photos -r -o ./out -c web             # apply the saved config "web"
mediatoolz image-batch ./photos -r -o ./out -c web --select    # tick the files from a list first
mediatoolz image-batch ./photos -r -o ./out -c web --dry-run   # show what would be written
mediatoolz image-batch ./photos -r -o ./out -c web --hazehash --budget 20 --emit ./out/images.json
mediatoolz image-batch ./photos -r -o ./out -f webp                   # only change the format, keep the size
mediatoolz image-batch ./photos -r -o ./out --long 1600 -f webp,jpg --max-size 200KB   # by long side, capped weight
mediatoolz image-batch ./assets -r --replace -w 1600 --dry-run    # preview shrinking originals in place
mediatoolz image-batch ./assets -r --replace -w 1600               # do it: backup first, asks to confirm
mediatoolz image-batch restore .image-batch-backup/20261007-233706  # put the originals back
mediatoolz image-batch ./photos -r --beside -w 400 -f webp         # results next to each source
mediatoolz image-batch init                      # create a config with a few questions
mediatoolz image-batch config                    # pick a config: apply, show, edit, copy, delete
mediatoolz image-batch sharpen new               # save a sharpening preset, then --sharpen <name>

mediatoolz ui                                  # web interface for both commands
mediatoolz ui --no-open --port 4477            # just print the address

Every command has built-in --help — mediatoolz --help lists both commands with their own flags inline; mediatoolz <command> --help for one command's full flag list with defaults.

Development

npm install
npm run build      # tsc -> dist/, and the web interface
npm test           # vitest
npm run lint       # eslint .
npm run format     # prettier --check .
npm run typecheck  # tsc --noEmit

Documentation & links


License

MIT


💖 Support the project

Open source takes time and effort. If this library saves you time or brings value, consider supporting further development.

Thank you for being part of this journey. ❤️