@vojtechportes/minify-png
v0.1.2
Published
Node.js PNG minification library with edge-aware flat-region optimization and photo-safe palette recompression.
Maintainers
Readme
minify-png
minify-png is a Node.js library for reducing PNG size with a combination of:
- edge-aware flat-region cleanup for screenshots, UI assets, icons, diagrams, and illustrations
- photo-safe PNG recompression for natural images where aggressive flat-region posterization would look bad

What It Does
For flat graphics, the library:
- decodes the PNG into RGBA pixels
- detects and protects edges
- finds flat interior tiles
- rejects gradient-like regions
- selectively remaps accepted non-edge regions
For photo-like images, the library becomes conservative:
- it avoids destructive flat-region remapping
- it still tries smaller PNG encodes
- it picks the smallest candidate that stays within a visual-difference budget
This means the package is best understood as:
PNG minification with selective flat-region optimization plus adaptive recompression.
Install
npm install @vojtechportes/minify-pngsharp is used when available for decoding and encoding. pngjs is included as a fallback.
You can also opt into a system-installed pngquant binary for stronger PNG compression without bundling it into this package.
Usage
import { encodeOptimizedPng, minifyPng } from '@vojtechportes/minify-png';
import { readFile, writeFile } from 'node:fs/promises';
const sourceBuffer = await readFile('input.png');
const result = await minifyPng(sourceBuffer);
const outputBuffer = await encodeOptimizedPng(result);
await writeFile('output.png', outputBuffer);With optional external pngquant:
const result = await minifyPng(sourceBuffer);
const outputBuffer = await encodeOptimizedPng(result, {
pngquant: true,
qualityMode: 'aggressive',
});You can also set qualityMode on minifyPng() directly, and encodeOptimizedPng() will use that hint automatically unless you override it:
const result = await minifyPng(sourceBuffer, {
qualityMode: 'aggressive',
});
const outputBuffer = await encodeOptimizedPng(result);If pngquant is not installed or is not found on PATH, the library silently falls back to the built-in encoder path.
CLI
After install, you can also run the package as a CLI:
minify-png --input input.png --output output.pngWith optional external pngquant:
minify-png \
--input input.png \
--output output.png \
--pngquant \
--pngquant-bin "C:\pngquant\pngquant.exe" \
--quality-mode aggressive \
--pngquant-quality 90-98 \
--pngquant-speed 3Available flags:
--input,-i--output,-o--pngquant--pngquant-bin--pngquant-quality--pngquant-speed--quality-mode--verbose--help,-h
API
minifyPng(input, options?)
Analyzes a PNG or raw image input and returns a rewritten RGBA result together with processing stats.
Supported input:
Buffer | Uint8Arraycontaining a PNG- raw image input with
data,width,height, andchannels
Returns:
width,height,channels- rewritten
dataasUint8ClampedArray statsdescribing edge protection, accepted tiles, rewritten pixels, and whether posterization was skipped for a photo-like image
encodeOptimizedPng(input, options?)
Encodes a minifyPng() result or a raw image input back to PNG.
By default it tries multiple PNG encoding strategies and keeps the smallest acceptable candidate.
analyzeFlatRegions(input, options?)
Returns intermediate analysis data:
edgeMasktileMaskregionMaskregions
This is mainly useful for debugging and tuning thresholds.
Behavior Notes
- Best results are typically on UI screenshots, dashboards, icons, and illustrations.
- Natural photographs can still shrink well, but they are handled more conservatively to avoid obvious color shifts and posterization.
- The library is deterministic.
- Internal processing uses normalized 8-bit RGBA.
Options
The main options include:
tileSizeedgeThresholdColoredgeThresholdAlphaedgeDilateRadiusflatnessMaxDistanceflatnessP95DistancegradientRejectionEnabledgradientMaxDirectionalDriftminRegionAreaminRegionThicknessposterizeModeposterizeBitsPerChanneloutputDebug
Encoder options include:
compressionLeveladaptiveFilteringpalettecolorsqualityeffortpngquantqualityMode
Optional pngquant
encodeOptimizedPng() supports an opt-in external pngquant path:
const outputBuffer = await encodeOptimizedPng(result, {
pngquant: {
binaryPath: 'pngquant',
quality: [90, 98],
speed: 3,
},
qualityMode: 'aggressive',
});Notes:
pngquantis never bundled by this package.pngquant/libimagequantare not MIT-licensed. They are GPL/commercial licensed, so this package only supports them as an optional external tool.- The binary must already be installed on the system or otherwise available via
binaryPath. - If
pngquantis unavailable or its output does not pass the same visual checks, the library keeps the built-in result instead.
qualityMode
encodeOptimizedPng() supports three visual-threshold modes, and minifyPng() can carry the same mode forward as an encode hint:
strict: current safest defaultbalanced: slightly looser acceptanceaggressive: more willing to accept smaller lossy candidates
Current Design
The current implementation combines two strategies:
- Selective flat-region optimization for graphics-like PNGs.
- Candidate-based PNG recompression for photo-like PNGs.
It does not try to be a full semantic image optimizer, and it is still intentionally more conservative than dedicated hosted optimizers for some photographic images.
Development
npm test
npm run typecheck
npm run build
npm run coverageTo run the local sample pipeline in the test/ folder:
npm run test:pngTo enable optional external pngquant for the local test runner:
npm run test:png:pngquantTo pass a custom binary path:
npm run test:png -- --pngquant --pngquant-bin "C:\pngquant\pngquant.exe"You can also pass explicit quality and speed:
npm run test:png -- --pngquant --pngquant-bin "C:\pngquant\pngquant.exe" --pngquant-quality 90-98 --pngquant-speed 3 --quality-mode aggressiveThe test runner now loads a root .env file through dotenv, so if you prefer, you can still set defaults there:
USE_PNGQUANT=1
PNGQUANT_BIN=C:\pngquant\pngquant.exeIf you want to verify whether pngquant was actually used, run with --verbose:
npm run test:png -- --pngquant --pngquant-bin "C:\pngquant\pngquant.exe" --quality-mode aggressive --verboseThe output will tell you whether each pngquant candidate was unavailable, rejected by the visual checks, accepted, or ultimately selected.
Coverage is uploaded from GitHub Actions to Codecov. The workflow expects a CODECOV_TOKEN repository secret.
To try the CLI from the repository without publishing:
npm run build
node dist/minify-png.js --input test/test.png --output test/test.min.png