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

picmin

v1.0.0

Published

Fast image compression CLI with AVIF, WebP, GIF, SVG support, watch mode, dry-run, plugins, worker pool, and more.

Readme

picmin

npm version license node version downloads

Fast image compression CLI with watch mode, dry-run previews, plugin support, and more.

Features

  • 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: .picminrc or picmin.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

Installation

For CLI Usage

Install globally:

npm install -g picmin

For Programmatic Use

Install locally:

npm install picmin

CLI Usage

Global Options

  • -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

Compress a Single Image

picmin compress <input> <output> [options]

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

Network Speed Options:

The --network-speed option accepts:

  • Presets: 2g, 3g, 4g, 5g, slow, average (default), fast, fiber
  • Custom value: Any number in Mbps (e.g., 25 for 25 Mbps)
  • Disable: off to 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 |

Examples:

# 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 -s

Batch Compress Images

picmin compress-batch <input> <output> [options]

Input can be:

  • Directory path: ./images
  • Glob pattern: src/**/*.{jpg,png,gif}
  • Comma-separated files: img1.jpg,img2.png

Examples:

# 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 -s

View Quality Presets

picmin presets

Watch Mode

Auto-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 500

Dry-Run Mode

Preview 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 80

Configuration File

Create a config file for consistent settings:

# Create picmin.config.js
picmin init

# Create .picminrc (JSON format)
picmin init --format json

The CLI automatically loads config from (in order):

  • .picminrc
  • .picminrc.json
  • .picminrc.js
  • picmin.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 }]
  ]
};

Quality Presets

| 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 |

Programmatic API Usage

TypeScript/JavaScript

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
});

Advanced Options

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
}

Watch Mode API

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();

Dry-Run API

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}`);

Plugin System

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'
]);

Output Statistics

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
}

Visual Comparison Feature

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

Key Features

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 | ✅ |

Examples

Check out the examples directory for more use cases:

node examples/example.js

Supported Formats

| Format | Read | Write | Lossy | Lossless | Notes | |--------|------|-------|-------|----------|-------| | JPEG | ✅ | ✅ | ✅ | ❌ | Mozjpeg support | | PNG | ✅ | ✅ | ✅ | ✅ | | | WebP | ✅ | ✅ | ✅ | ✅ | | | AVIF | ✅ | ✅ | ✅ | ✅ | Modern format | | GIF | ✅ | ✅ | ✅ | ❌ | Gifsicle integration | | SVG | ✅ | ✅ | ✅ | ✅ | SVGO optimization | | TIFF | ✅ | ✅ | ✅ | ✅ | |

Benchmarks

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

Performance Tips

  1. Use AVIF or WebP for modern format compression (typically smaller than JPEG)
  2. Enable mozjpeg for improved JPEG compression (default: enabled)
  3. Adjust concurrency based on your CPU cores
  4. Use glob patterns for efficient batch processing
  5. Apply quality presets for consistent results

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a pull request.

This project follows the Contributor Covenant Code of Conduct.

Changelog

See changelog.md for version history and updates.

License

This project is licensed under the MIT License. See the license file for details.

Support

Acknowledgments

Built with:

  • Sharp - High performance image processing (includes mozjpeg)
  • SVGO - SVG optimization
  • Commander - CLI framework

npmGitHubIssues