Fast image compression CLI with watch mode, dry-run previews, plugin support, and more.
- Multi-Format Support: JPEG, PNG, WebP, AVIF, GIF, SVG, and TIFF
- Format Conversion: Convert images to modern formats like AVIF and WebP
- Compression Options:
- Lossless Compression: Retains original quality
- Lossy Compression: Customizable quality levels
- Mozjpeg Integration: Enhanced JPEG compression (via Sharp)
- Image Transformation: Resize and crop images during compression
- Quality Presets: Pre-configured settings (thumbnail, web-optimized, high-quality, print-quality)
- Glob Pattern Support: Process multiple files with patterns like
src/**/*.{jpg,png} - Batch Processing: Compress multiple images with worker pool parallelism
- Watch Mode: Auto-compress images on file changes
- Dry-Run Mode: Preview what would happen without compressing
- Config File Support:
.picminrcorpicmin.config.js - Plugin System: Extend functionality with custom plugins
- Worker Pool: True parallel processing for large batches
- Configurable Network Speed: Realistic load time estimates
- Savings Report: Detailed statistics including load time improvements
- Visual Comparison: Interactive HTML preview with slider to compare quality
- CLI + API: Use via command-line or integrate into Node.js projects
- TypeScript Support: Full type definitions included
Install globally:
npm install -g picminInstall locally:
npm install picmin-v, --verbose: Enable verbose output with detailed processing information-s, --silent: Suppress all output except errors-V, --version: Output the version number-h, --help: Display help for command
picmin compress <input> <output> [options]-c, --convert-to <format>: Output format (jpeg, png, webp, avif, gif, svg, tiff)-t, --compression-type <type>: Compression type (lossy or lossless)-l, --compression-level <level>: Level (high, medium, low)-q, --quality <quality>: Quality (1-100)--preset <preset>: Quality preset (see below)-p, --generate-preview: Generate interactive HTML comparison--no-mozjpeg: Disable mozjpeg for JPEG--no-strip-metadata: Keep image metadata--no-progressive: Disable progressive JPEG--network-speed <speed>: Network speed for load time estimate (see below)--resize-width <width>: Resize width in pixels--resize-height <height>: Resize height in pixels--resize-fit <fit>: Fit mode (cover, contain, fill, inside, outside)--crop-left/top/width/height: Crop parameters
The --network-speed option accepts:
- Presets:
2g,3g,4g,5g,slow,average(default),fast,fiber - Custom value: Any number in Mbps (e.g.,
25for 25 Mbps) - Disable:
offto hide load time estimates
| Preset | Speed (Mbps) | Description |
|---|---|---|
2g |
0.1 | 2G mobile |
3g |
1.5 | 3G mobile |
4g |
20 | 4G LTE |
5g |
100 | 5G mobile |
slow |
1 | Slow broadband |
average |
10 | Average broadband (default) |
fast |
50 | Fast broadband |
fiber |
100 | Fiber connection |
# Convert to AVIF with high quality
picmin compress input.jpg output/ -c avif -q 85
# Use web-optimized preset
picmin compress input.png output/ -c webp --preset web-optimized
# Resize and compress
picmin compress input.jpg output/ -c webp --resize-width 1920 --resize-height 1080
# Generate visual comparison
picmin compress input.jpg output/ -c webp -q 80 -p
# Simulate 3G mobile network
picmin compress input.jpg output/ -c webp --network-speed 3g
# Use custom network speed (25 Mbps)
picmin compress input.jpg output/ -c webp --network-speed 25
# Disable load time estimates
picmin compress input.jpg output/ -c webp --network-speed off
# Verbose mode for debugging
picmin compress input.jpg output/ -c webp -v
# Silent mode (only errors)
picmin compress input.jpg output/ -c webp -spicmin compress-batch <input> <output> [options]- Directory path:
./images - Glob pattern:
src/**/*.{jpg,png,gif} - Comma-separated files:
img1.jpg,img2.png
# Compress entire directory
picmin compress-batch ./images ./output -c webp --preset web-optimized
# Use glob pattern
picmin compress-batch "src/**/*.{jpg,png}" dist/images/ -c avif -q 80
# Process with higher concurrency
picmin compress-batch ./images ./output -c webp -y 10
# Use parallel worker pool for large batches (recommended for 10+ images)
picmin compress-batch ./images ./output -c webp --parallel
# Specify worker count (default: CPU cores - 1)
picmin compress-batch ./images ./output -c webp --parallel --workers 4
# Silent batch processing (great for CI/CD)
picmin compress-batch ./images ./output -c webp -spicmin presetsAuto-compress images when files change:
# Watch a directory and compress changes to WebP
picmin watch ./src/images ./dist/images -c webp
# Watch with custom quality
picmin watch ./images ./output -c avif -q 85
# With debounce delay (default: 300ms)
picmin watch ./images ./output -c webp --debounce 500Preview compression results without actually processing:
# See what would happen
picmin dry-run ./images ./output -c webp
# Verbose output with dimensions and load times
picmin dry-run ./images ./output -c webp -v
# Alias: preview
picmin preview ./images ./output -c avif -q 80Create a config file for consistent settings:
# Create picmin.config.js
picmin init
# Create .picminrc (JSON format)
picmin init --format jsonThe CLI automatically loads config from (in order):
.picminrc.picminrc.json.picminrc.jspicmin.config.js
Example picmin.config.js:
module.exports = {
convertTo: 'webp',
quality: 80,
compressionType: 'lossy',
useMozjpeg: true,
networkSpeed: 'fast',
// Watch mode settings
watch: {
ignored: ['**/node_modules/**', '**/output/**'],
debounceDelay: 300
},
// Plugins
plugins: [
// ['plugin-name', { options }]
]
};| Preset | Quality | Use Case |
|---|---|---|
thumbnail |
60 | Small thumbnails (auto-resizes to 300x300) |
web-optimized |
80 | Balanced for web (recommended) |
high-quality |
92 | High quality with moderate compression |
print-quality |
95 | Near-lossless for print |
import { compressImage, compressImages, QUALITY_PRESETS } from 'picmin';
// Compress single image with AVIF
const stats = await compressImage('input.jpg', 'output/', {
convertTo: 'avif',
quality: 80,
generatePreview: true
});
console.log(`Saved ${stats.savings}% • ${stats.loadTimeImprovement}s faster`);
// Resize during compression
await compressImage('large.jpg', 'output/', {
convertTo: 'webp',
preset: 'web-optimized',
resize: {
width: 1920,
height: 1080,
fit: 'inside'
}
});
// Batch compress with glob pattern
const results = await compressImages('src/images/**/*.{jpg,png}', 'dist/', {
convertTo: 'webp',
quality: 85,
concurrency: 10,
useMozjpeg: true
});
console.log(`Compressed ${results.length} images`);
// Use worker pool for faster parallel processing
const parallelResults = await compressImages('./images', './output', {
convertTo: 'avif',
quality: 80,
useWorkerPool: true, // Enable worker threads
workerPoolSize: 4 // Optional: specify worker count
});
// Crop and compress
await compressImage('input.jpg', 'output/', {
convertTo: 'jpeg',
crop: {
left: 100,
top: 100,
width: 800,
height: 600
},
quality: 90
});interface CompressionOptions {
convertTo: 'jpeg' | 'png' | 'webp' | 'avif' | 'gif' | 'svg' | 'tiff';
quality?: number; // 1-100
compressionLevel?: 'high' | 'medium' | 'low';
compressionType?: 'lossy' | 'lossless';
preset?: 'thumbnail' | 'web-optimized' | 'high-quality' | 'print-quality';
resize?: {
width?: number;
height?: number;
fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
};
crop?: {
left: number;
top: number;
width: number;
height: number;
};
generatePreview?: boolean;
useMozjpeg?: boolean; // Default: true for JPEG
stripMetadata?: boolean; // Default: true
progressive?: boolean; // Default: true for JPEG
networkSpeed?: number | string; // Mbps or preset name
concurrency?: number; // Batch only, default: 5
useWorkerPool?: boolean; // Batch only, enables true parallel processing
workerPoolSize?: number; // Worker threads, default: CPU cores - 1
}import { watchDirectory } from 'picmin';
const watcher = watchDirectory('./src/images', './dist/images', {
convertTo: 'webp',
quality: 80,
watch: {
ignored: ['**/temp/**'],
debounceDelay: 500
}
}, {
onReady: (dir) => console.log(`Watching ${dir}`),
onChange: (file) => console.log(`Processing ${file}`),
onProcessed: (file, result) => console.log(`Done: ${result.savings}% saved`),
onError: (file, err) => console.error(`Error: ${err.message}`)
});
// Stop watching
watcher.close();import { analyzeFiles, formatDryRunOutput } from 'picmin';
const analysis = await analyzeFiles('./images', './output', {
convertTo: 'webp',
quality: 80
});
console.log(formatDryRunOutput(analysis, true)); // verbose
// Or access data directly
console.log(`Would save ~${analysis.summary.totalEstimatedSavings}%`);
console.log(`Files to process: ${analysis.summary.analyzedFiles}`);import { createPlugin, pluginManager } from 'picmin';
// Create a custom plugin
const myPlugin = createPlugin('my-plugin', {
beforeCompress: async (context, options) => {
console.log(`About to compress: ${context.inputPath}`);
return context; // Can modify context
},
afterCompress: async (context, options) => {
console.log(`Compressed: ${context.stats.savings}% saved`);
}
});
// Load plugins
pluginManager.load(myPlugin);
// Or load from config
pluginManager.loadAll([
['./my-plugin.js', { option: 'value' }],
'another-plugin'
]);Each compression returns detailed statistics:
{
inputSize: number; // Original size in bytes
outputSize: number; // Compressed size in bytes
savings: string; // Percentage reduction
originalLoadTime: string; // Estimated load time (original)
compressedLoadTime: string; // Estimated load time (compressed)
loadTimeImprovement: string; // Time saved in seconds
inputFileName: string; // Filename
}The --generate-preview or generatePreview: true option creates an interactive HTML file with a draggable slider to compare original vs compressed images side-by-side.
This feature helps you:
- Visually assess compression quality
- Make informed decisions about quality settings
- Share comparisons with stakeholders
This package combines several useful features in one tool:
| Feature | Included |
|---|---|
| AVIF, WebP, GIF, SVG Support | ✅ |
| Mozjpeg Integration | ✅ |
| Interactive Visual Comparison | ✅ |
| Glob Pattern Support | ✅ |
| Quality Presets | ✅ |
| Resize/Crop | ✅ |
| TypeScript Definitions | ✅ |
| CLI + Programmatic API | ✅ |
| Load Time Statistics | ✅ |
Check out the examples directory for more use cases:
node examples/example.js| Format | Read | Write | Lossy | Lossless | Notes |
|---|---|---|---|---|---|
| JPEG | ✅ | ✅ | ✅ | ❌ | Mozjpeg support |
| PNG | ✅ | ✅ | ✅ | ✅ | |
| WebP | ✅ | ✅ | ✅ | ✅ | |
| AVIF | ✅ | ✅ | ✅ | ✅ | Modern format |
| GIF | ✅ | ✅ | ✅ | ❌ | Gifsicle integration |
| SVG | ✅ | ✅ | ✅ | ✅ | SVGO optimization |
| TIFF | ✅ | ✅ | ✅ | ✅ |
Tested on a real 810x1440 JPEG photo (275 KB), averaged over multiple runs:
| Format | picmin | raw sharp | Overhead |
|---|---|---|---|
| JPEG | 114 ms | 114 ms | ~0% |
| WebP | 125 ms | 121 ms | ~3% |
| AVIF | 1.94 s | 1.68 s | ~15% |
Batch Processing (10 images):
| Mode | Time | Notes |
|---|---|---|
| Sequential | 664 ms | Single-threaded |
| Parallel (worker pool) | 717 ms | Multi-threaded |
Worker pool overhead is noticeable with small images. Benefits increase with larger images or CPU-intensive formats like AVIF.
Compression Results (quality: 80):
| Output Format | Size | Savings |
|---|---|---|
| JPEG | 129 KB | 53% smaller |
| WebP | 105 KB | 62% smaller |
| AVIF | 154 KB | 44% smaller |
Note: picmin adds minimal overhead (~3-15%) for features like presets, metadata handling, preview generation, and statistics. For raw speed, use sharp directly. For convenience and features, use picmin.
Run benchmarks yourself:
node benchmarks/benchmark.js- Use AVIF or WebP for modern format compression (typically smaller than JPEG)
- Enable mozjpeg for improved JPEG compression (default: enabled)
- Adjust concurrency based on your CPU cores
- Use glob patterns for efficient batch processing
- Apply quality presets for consistent results
Contributions are welcome! Please read our contributing guidelines before submitting a pull request.
This project follows the Contributor Covenant Code of Conduct.
See changelog.md for version history and updates.
This project is licensed under the MIT License. See the license file for details.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Built with:
- Sharp - High performance image processing (includes mozjpeg)
- SVGO - SVG optimization
- Commander - CLI framework