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

@thaparoyal/image-compression

v1.2.15

Published

Browser image compression library for JavaScript and TypeScript.

Downloads

455

Readme

Image Compression (Browser & CDN Only)

npm version npm downloads license

image compression library for JavaScript and TypeScript, designed for browser and CDN usage. Offers extensive configuration, automatic format selection, and high-quality compression.

Features

  • Multiple output formats: WebP, JPEG, PNG, AVIF (auto-detects browser support)
  • Five resize modes: contain, cover, fill, inside, outside
  • Progressive JPEG support
  • EXIF metadata preservation option
  • Smart quality optimization using binary search
  • Automatic downscaling for large images
  • High-quality image rendering with smoothing
  • TypeScript support with comprehensive type definitions
  • Flexible configuration options
  • Custom output filenames
  • Automatic format fallbacks
  • Detailed progress logging and error handling

Installation

npm install @thaparoyal/image-compression

CDN Usage

Use the CDN build for browser:

<script src="https://cdn.jsdelivr.net/npm/@thaparoyal/[email protected]/dist/image-compression.umd.js"></script>

After including the script, you can use the library as a UMD module:

// If using a bundler or module loader (like RequireJS, SystemJS, etc.)
const { compress } = ImageCompression;

// Basic compression
const file = document.querySelector('input[type="file"]').files[0];
const compressedFile = await compress(file, {
  maxSizeMB: 0.5,  // target size in megabytes
  maxWidth: 1920,  // maximum width in pixels
  preferredFormat: 'webp'  // preferred output format
});

// Advanced compression with all options
const compressedFile = await compress(file, {
  maxSizeMB: 0.5,
  maxWidth: 1920,
  maxHeight: 1080,
  preferredFormat: 'webp',
  quality: 0.9,
  resizeMode: 'cover',
  preserveExif: true,
  progressive: true,
  debug: true,
  outputFilename: 'compressed-image.webp',
  downscaleDivisor: 4,
  minQuality: 0.2,
});

Complete CDN Example

Here's a complete example showing image compression with preview, size comparison, and all available options:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Compression Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/@thaparoyal/[email protected]/dist/image-compression.umd.js"></script>
    <style>
        body {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        }
        .preview {
            display: flex;
            gap: 20px;
            margin-top: 20px;
        }
        .preview > div {
            flex: 1;
        }
        .preview img {
            max-width: 100%;
            height: auto;
        }
        .stats {
            margin: 10px 0;
            padding: 10px;
            background: #f5f5f5;
            border-radius: 4px;
        }
        .options {
            margin: 20px 0;
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 10px;
        }
        .loading {
            display: none;
            margin: 20px 0;
        }
    </style>
</head>
<body>
    <h1>Image Compression Demo</h1>
    <div class="options">
        <div>
            <label>Max Size (MB):
                <input type="number" id="maxSize" value="0.5" step="0.1" min="0.1">
            </label>
        </div>
        <div>
            <label>Quality (0-1):
                <input type="number" id="quality" value="0.9" step="0.1" min="0.1" max="1">
            </label>
        </div>
        <div>
            <label>Max Width:
                <input type="number" id="maxWidth" value="800" step="100">
            </label>
        </div>
        <div>
            <label>Max Height:
                <input type="number" id="maxHeight" value="600" step="100">
            </label>
        </div>
        <div>
            <label>Format:
                <select id="format">
                    <option value="webp">WebP</option>
                    <option value="jpeg">JPEG</option>
                    <option value="png">PNG</option>
                    <option value="avif">AVIF</option>
                </select>
            </label>
        </div>
        <div>
            <label>Resize Mode:
                <select id="resizeMode">
                    <option value="contain">Contain</option>
                    <option value="cover">Cover</option>
                    <option value="fill">Fill</option>
                    <option value="inside">Inside</option>
                    <option value="outside">Outside</option>
                </select>
            </label>
        </div>
        <div>
            <label>
                <input type="checkbox" id="preserveExif">
                Preserve EXIF
            </label>
        </div>
        <div>
            <label>
                <input type="checkbox" id="progressive">
                Progressive
            </label>
        </div>
    </div>

    <input type="file" id="fileInput" accept="image/*">
    <div class="loading">Compressing...</div>

    <div class="preview">
        <div>
            <h3>Original</h3>
            <img id="originalPreview">
            <div id="originalStats" class="stats"></div>
        </div>
        <div>
            <h3>Compressed</h3>
            <img id="compressedPreview">
            <div id="compressedStats" class="stats"></div>
        </div>
    </div>

    <script>
        document.getElementById('fileInput').addEventListener('change', async (event) => {
            const file = event.target.files[0];
            if (!file) return;

            // Show loading
            document.querySelector('.loading').style.display = 'block';

            // Preview original
            const originalPreview = document.getElementById('originalPreview');
            const originalUrl = URL.createObjectURL(file);
            originalPreview.src = originalUrl;

            // Show original stats
            document.getElementById('originalStats').innerHTML = `
                Size: ${(file.size / 1024).toFixed(2)} KB<br>
                Type: ${file.type}
            `;

            // Get compression options from inputs
            const options = {
                maxSizeMB: parseFloat(document.getElementById('maxSize').value),
                quality: parseFloat(document.getElementById('quality').value),
                maxWidth: parseInt(document.getElementById('maxWidth').value),
                maxHeight: parseInt(document.getElementById('maxHeight').value),
                preferredFormat: document.getElementById('format').value,
                resizeMode: document.getElementById('resizeMode').value,
                preserveExif: document.getElementById('preserveExif').checked,
                progressive: document.getElementById('progressive').checked,
                debug: true,
            };

            try {
                const compressedFile = await ImageCompression.compress(file, options);
                
                // Preview compressed
                const compressedPreview = document.getElementById('compressedPreview');
                const compressedUrl = URL.createObjectURL(compressedFile);
                compressedPreview.src = compressedUrl;

                // Show compressed stats
                document.getElementById('compressedStats').innerHTML = `
                    Size: ${(compressedFile.size / 1024).toFixed(2)} KB<br>
                    Type: ${compressedFile.type}<br>
                    Compression: ${(100 - (compressedFile.size / file.size) * 100).toFixed(1)}%
                `;

                // Cleanup
                document.querySelector('.loading').style.display = 'none';
            } catch (error) {
                console.error('Compression failed:', error);
                document.querySelector('.loading').style.display = 'none';
                alert('Compression failed: ' + error.message);
            }
        });
    </script>
</body>
</html>

This example provides:

  • Live image preview for both original and compressed images
  • Size comparison and compression ratio
  • UI controls for all compression options
  • Progress indication
  • Error handling
  • Responsive layout

API Reference

compress(fileOrBlob: File | Blob, options: CompressionOptions): Promise<File>

Compresses an image in the browser with options.

CompressionOptions

interface CompressionOptions {
  maxSizeMB?: number;        // Target maximum size in megabytes (default: 0.1)
  quality?: number;          // Starting compression quality 0-1 (default: 0.9)
  maxWidth?: number;         // Maximum width in pixels (default: 800)
  maxHeight?: number | null; // Maximum height in pixels (default: null)
  preferredFormat?: 'webp' | 'jpeg' | 'png' | 'avif';  // Preferred output format (default: 'webp')
  preserveExif?: boolean;    // Preserve EXIF metadata (default: false)
  resizeMode?: 'contain' | 'cover' | 'fill' | 'inside' | 'outside';  // Resize mode (default: 'contain')
  minQuality?: number;       // Minimum allowed quality (default: 0.1)
  progressive?: boolean;     // Enable progressive JPEG (default: false)
  debug?: boolean;           // Enable debug logging (default: false)
  outputFilename?: string;   // Custom output filename
  downscaleDivisor?: number; // Divisor for initial downscaling (default: 5)
}

Usage Examples

Example: Custom Resize Mode

const compressedFile = await compress(file, {
  maxSizeMB: 0.2,
  maxWidth: 1024,
  maxHeight: 768,
  resizeMode: 'cover',
});

Example: Progressive JPEG

const compressedFile = await compress(file, {
  preferredFormat: 'jpeg',
  progressive: true,
});

Example: Preserve EXIF Metadata

const compressedFile = await compress(file, {
  preserveExif: true,
});

Example: Custom Output Filename

const compressedFile = await compress(file, {
  outputFilename: 'my-image.webp',
});

Example: Debug Logging

const compressedFile = await compress(file, {
  debug: true,
});

How It Works

  • Uses browser canvas for resizing and format conversion
  • Automatically selects the best supported format
  • Optimizes quality using binary search to meet target size
  • Preserves EXIF metadata if requested
  • Supports all major browsers and CDN delivery

License

MIT © Thapa Royal