image compression library for JavaScript and TypeScript, designed for browser and CDN usage. Offers extensive configuration, automatic format selection, and high-quality compression.
- 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
npm install @thaparoyal/image-compressionUse the CDN build for browser:
<script src="https://cdn.jsdelivr.net/npm/@thaparoyal/image-compression@1.1.15/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,
});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/image-compression@1.2.15/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
Compresses an image in the browser with options.
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)
}const compressedFile = await compress(file, {
maxSizeMB: 0.2,
maxWidth: 1024,
maxHeight: 768,
resizeMode: 'cover',
});const compressedFile = await compress(file, {
preferredFormat: 'jpeg',
progressive: true,
});const compressedFile = await compress(file, {
preserveExif: true,
});const compressedFile = await compress(file, {
outputFilename: 'my-image.webp',
});const compressedFile = await compress(file, {
debug: true,
});- 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
MIT © Thapa Royal