image-compressor-by-xettri-aleen
v1.0.2
Published
Smart image compression with automatic CSP fallbacks and modern browser support
Maintainers
Readme
🗜️ image-compressor-by-xettri-aleen
Smart, developer-friendly image compression with automatic CSP fallbacks and multiple compression strategies.
image-compressor-by-xettri-aleen automatically detects your browser's capabilities and chooses the best compression method available. Works everywhere from strict CSP environments to modern browsers with full canvas access.
✨ Features
- 🚀 Multiple Compression Methods - Canvas, Web Workers, WebAssembly, and lightweight fallbacks
- 🛡️ CSP-Safe - Automatically handles Content Security Policy restrictions
- 📱 Universal Browser Support - Works in all modern browsers and environments
- ⚡ High Performance - Uses the fastest method available in your environment
- 🎨 Multiple Formats - WebP, JPEG, PNG support with format conversion
- 📏 Smart Resizing - Maintains aspect ratio while respecting size constraints
- 📊 Detailed Logging - Optional compression statistics and performance metrics
- 🔧 TypeScript Support - Full type definitions included
- 📦 Multiple Build Formats - ES modules, UMD, and standalone builds
- 🎯 Zero Dependencies - Standalone build works without external libraries
- 🔄 Batch Processing - Compress multiple images efficiently
- 🎛️ Quality Presets - Pre-configured settings for common use cases
📦 Installation
NPM Installation
npm install image-compressor-by-xettri-aleenYarn Installation
bash
yarn add image-compressor-by-xettri-aleenCDN Usage
html
<!-- Standalone build (no dependencies) -->
<script src="https://unpkg.com/image-compressor-by-xettri-aleen/dist/index.standalone.js"></script>
<!-- UMD build (requires browser-image-compression for WASM features) -->
<script src="https://unpkg.com/browser-image-compression/dist/browser-image-compression.js"></script>
<script src="https://unpkg.com/image-compressor-by-xettri-aleen/dist/index.js"></script>
<!-- ES Module via CDN -->
<script type="module">
import { compressImage } from 'https://unpkg.com/image-compressor-by-xettri-aleen/dist/index.esm.js';
</script>🚀 Quick Start
Basic Usage (ES Modules)
javascript
import { compressImage, QUALITY_PRESETS } from 'image-compressor-by-xettri-aleen';
// Basic compression
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
const result = await compressImage(file, {
quality: QUALITY_PRESETS.MEDIUM,
format: 'webp',
enableLogging: true
});
console.log(`Reduced size by ${result.stats.compressionRatio}%`);
console.log(`Original: ${formatBytes(result.stats.originalSize)}`);
console.log(`Compressed: ${formatBytes(result.stats.compressedSize)}`);
// Download compressed image
const url = URL.createObjectURL(result.blob);
const a = document.createElement('a');
a.href = url;
a.download = result.file.name;
a.click();
URL.revokeObjectURL(url);
});
function formatBytes(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}Browser Global Usage
html
<!DOCTYPE html>
<html>
<head>
<title>Image Compression Demo</title>
</head>
<body>
<input type="file" id="imageInput" accept="image/*">
<div id="results"></div>
<script src="https://unpkg.com/image-compressor-by-xettri-aleen/dist/index.standalone.js"></script>
<script>
document.getElementById('imageInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
try {
const result = await ImageSquash.compress(file, {
quality: ImageSquash.presets.HIGH,
format: 'webp',
maxWidth: 1920,
enableLogging: true
});
document.getElementById('results').innerHTML = `
<h3>Compression Results</h3>
<p>Original Size: ${formatBytes(result.stats.originalSize)}</p>
<p>Compressed Size: ${formatBytes(result.stats.compressedSize)}</p>
<p>Reduction: ${result.stats.compressionRatio}%</p>
<p>Method Used: ${result.method}</p>
`;
} catch (error) {
console.error('Compression failed:', error);
}
});
function formatBytes(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
</script>
</body>
</html>React Example
jsx
import React, { useState, useCallback } from 'react';
import { compressImage, QUALITY_PRESETS, FORMAT_OPTIONS } from 'image-compressor-by-xettri-aleen';
function ImageCompressor() {
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(false);
const [progress, setProgress] = useState(0);
const handleFile = useCallback(async (e) => {
const file = e.target.files[0];
if (!file) return;
setLoading(true);
setProgress(0);
try {
const compressed = await compressImage(file, {
quality: QUALITY_PRESETS.MEDIUM,
format: FORMAT_OPTIONS.WEBP,
maxWidth: 1920,
maxHeight: 1080,
enableLogging: true,
logLevel: 'detailed'
});
setResult(compressed);
setProgress(100);
} catch (error) {
console.error('Compression failed:', error);
alert('Compression failed: ' + error.message);
}
setLoading(false);
}, []);
const downloadImage = useCallback(() => {
if (!result) return;
const url = URL.createObjectURL(result.blob);
const a = document.createElement('a');
a.href = url;
a.download = result.file.name;
a.click();
URL.revokeObjectURL(url);
}, [result]);
return (
<div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
<h2>🗜️ Image Compressor</h2>
<input
type="file"
accept="image/*"
onChange={handleFile}
disabled={loading}
style={{ marginBottom: '20px' }}
/>
{loading && (
<div style={{ marginBottom: '20px' }}>
<p>Compressing image...</p>
<div style={{
width: '100%',
height: '20px',
backgroundColor: '#f0f0f0',
borderRadius: '10px',
overflow: 'hidden'
}}>
<div style={{
width: `${progress}%`,
height: '100%',
backgroundColor: '#007bff',
transition: 'width 0.3s ease'
}} />
</div>
</div>
)}
{result && (
<div style={{
padding: '15px',
border: '1px solid #ddd',
borderRadius: '5px',
backgroundColor: '#f9f9f9'
}}>
<h3>✅ Compression Complete!</h3>
<ul>
<li><strong>Method Used:</strong> {result.method}</li>
<li><strong>Original Size:</strong> {formatBytes(result.stats.originalSize)}</li>
<li><strong>Compressed Size:</strong> {formatBytes(result.stats.compressedSize)}</li>
<li><strong>Space Saved:</strong> {formatBytes(result.stats.savedBytes)} ({result.stats.compressionRatio}%)</li>
<li><strong>Output Format:</strong> {result.stats.format}</li>
</ul>
<button
onClick={downloadImage}
style={{
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '5px',
cursor: 'pointer'
}}
>
📥 Download Compressed Image
</button>
<div style={{ marginTop: '15px' }}>
<img
src={URL.createObjectURL(result.blob)}
alt="Compressed"
style={{ maxWidth: '100%', height: 'auto', borderRadius: '5px' }}
/>
</div>
</div>
)}
</div>
);
}
function formatBytes(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
export default ImageCompressor;Vue.js Example
vue
<template>
<div class="image-compressor">
<h2>🗜️ Image Compressor</h2>
<input
type="file"
accept="image/*"
@change="handleFile"
:disabled="loading"
ref="fileInput"
/>
<div v-if="loading" class="loading">
<p>Compressing image...</p>
<div class="progress-bar">
<div class="progress-fill" :style="{ width: progress + '%' }"></div>
</div>
</div>
<div v-if="result" class="results">
<h3>✅ Compression Complete!</h3>
<ul>
<li><strong>Method:</strong> {{ result.method }}</li>
<li><strong>Original:</strong> {{ formatBytes(result.stats.originalSize) }}</li>
<li><strong>Compressed:</strong> {{ formatBytes(result.stats.compressedSize) }}</li>
<li><strong>Saved:</strong> {{ result.stats.compressionRatio }}%</li>
</ul>
<button @click="downloadImage">📥 Download</button>
<img
:src="imageUrl"
alt="Compressed"
class="preview"
/>
</div>
</div>
</template>
<script>
import { compressImage, QUALITY_PRESETS } from 'image-compressor-by-xettri-aleen';
export default {
name: 'ImageCompressor',
data() {
return {
result: null,
loading: false,
progress: 0,
imageUrl: null
};
},
methods: {
async handleFile(event) {
const file = event.target.files[0];
if (!file) return;
this.loading = true;
this.progress = 0;
try {
this.result = await compressImage(file, {
quality: QUALITY_PRESETS.MEDIUM,
format: 'webp',
maxWidth: 1920,
enableLogging: true
});
this.imageUrl = URL.createObjectURL(this.result.blob);
this.progress = 100;
} catch (error) {
console.error('Compression failed:', error);
alert('Compression failed: ' + error.message);
}
this.loading = false;
},
downloadImage() {
if (!this.result) return;
const a = document.createElement('a');
a.href = this.imageUrl;
a.download = this.result.file.name;
a.click();
},
formatBytes(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
},
beforeUnmount() {
if (this.imageUrl) {
URL.revokeObjectURL(this.imageUrl);
}
}
};
</script>
<style scoped>
.image-compressor {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.loading {
margin: 20px 0;
}
.progress-bar {
width: 100%;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: #007bff;
transition: width 0.3s ease;
}
.results {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
background: #f9f9f9;
}
.preview {
max-width: 100%;
height: auto;
margin-top: 15px;
border-radius: 5px;
}
button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin: 10px 0;
}
button:hover {
background: #0056b3;
}
</style>📖 API Reference
compressImage(input, options)
Main compression function that automatically selects the best method.
Parameters:
input- File, Blob, HTMLImageElement, or data URL stringoptions- Compression configuration object
Returns: Promise resolving to compression result object
Options:
typescript
interface CompressionOptions {
quality?: number; // 0-1, compression quality (default: 0.7)
format?: string; // 'webp', 'jpeg', 'png' (default: 'webp')
maxWidth?: number; // Maximum width in pixels
maxHeight?: number; // Maximum height in pixels
enableLogging?: boolean; // Show compression stats (default: false)
logLevel?: string; // 'basic' or 'detailed' (default: 'basic')
preferredMethod?: string; // 'auto', 'canvas', 'worker', 'wasm', 'lightweight'
}Example:
javascript
const result = await compressImage(file, {
quality: 0.8,
format: 'webp',
maxWidth: 1920,
maxHeight: 1080,
enableLogging: true,
logLevel: 'detailed',
preferredMethod: 'auto'
});compressMultiple(images, options)
Compress multiple images with the same settings.
Parameters:
images- Array of File, Blob, HTMLImageElement, or data URL stringsoptions- Same as compressImage options
Returns: Promise resolving to array of compression results
Example:
javascript
const fileInput = document.querySelector('input[type="file"]');
const files = Array.from(fileInput.files);
const results = await compressMultiple(files, {
quality: QUALITY_PRESETS.MEDIUM,
format: 'webp',
maxWidth: 1920
});
results.forEach((result, index) => {
if (result.error) {
console.error(`Failed to compress image ${index}:`, result.error);
} else {
console.log(`Image ${index} compressed by ${result.stats.compressionRatio}%`);
console.log(`Method used: ${result.method}`);
}
});createCompressor(defaultOptions)
Create a reusable compressor with preset options.
Parameters:
defaultOptions- Default compression options
Returns: Compressor object with compress and compressMultiple methods
Example:
javascript
// Create specialized compressors for different use cases
const thumbnailCompressor = createCompressor({
quality: QUALITY_PRESETS.LOW,
format: 'webp',
maxWidth: 300,
maxHeight: 300,
enableLogging: false
});
const highQualityCompressor = createCompressor({
quality: QUALITY_PRESETS.HIGH,
format: 'webp',
maxWidth: 1920,
enableLogging: true,
logLevel: 'detailed'
});
// Use the compressors
const thumbnail = await thumbnailCompressor.compress(file);
const highQuality = await highQualityCompressor.compress(file, {
quality: 0.95 // Override default quality
});Quality Presets
Pre-defined quality settings for common use cases:
javascript
import { QUALITY_PRESETS } from 'image-compressor-by-xettri-aleen';
QUALITY_PRESETS.LOW // 0.4 - Heavy compression, good for thumbnails
QUALITY_PRESETS.MEDIUM // 0.7 - Balanced size and quality
QUALITY_PRESETS.HIGH // 0.9 - High quality, larger files
QUALITY_PRESETS.LOSSLESS // 1.0 - No quality loss
// Usage examples
const thumbnail = await compressImage(file, {
quality: QUALITY_PRESETS.LOW,
maxWidth: 200
});
const webOptimized = await compressImage(file, {
quality: QUALITY_PRESETS.MEDIUM,
format: 'webp'
});
const printQuality = await compressImage(file, {
quality: QUALITY_PRESETS.HIGH,
format: 'jpeg'
});Format Options
javascript
import { FORMAT_OPTIONS } from 'image-compressor-by-xettri-aleen';
FORMAT_OPTIONS.WEBP // 'webp' - Best compression, modern browsers
FORMAT_OPTIONS.JPEG // 'jpeg' - Good compatibility, lossy compression
FORMAT_OPTIONS.PNG // 'png' - Supports transparency, lossless
// Usage examples
const webpImage = await compressImage(file, {
format: FORMAT_OPTIONS.WEBP,
quality: 0.8
});
const jpegImage = await compressImage(file, {
format: FORMAT_OPTIONS.JPEG,
quality: 0.85
});
const pngImage = await compressImage(file, {
format: FORMAT_OPTIONS.PNG,
quality: 1.0 // PNG quality affects compression level, not visual quality
});🎯 Compression Methods
image-compressor-by-xettri-aleen automatically selects the best available method based on browser capabilities and CSP restrictions:
1. Canvas Method (Default)
- Best Performance - Direct browser APIs, fastest processing
- Requirements - Canvas access, no strict CSP blocking canvas operations
- Features - Full format support, high-quality output, real-time processing
javascript
// Force canvas method
const result = await compressImage(file, {
preferredMethod: 'canvas',
quality: 0.8,
format: 'webp'
});2. Web Worker Method
- Good Performance - Offscreen processing, non-blocking UI
- Requirements - Web Workers enabled, OffscreenCanvas support
- Features - Background processing, CSP-friendly, maintains UI responsiveness
javascript
// Force worker method
const result = await compressImage(file, {
preferredMethod: 'worker',
quality: 0.8,
format: 'webp'
});3. WebAssembly Method
- High Quality - Advanced compression algorithms via browser-image-compression
- Requirements - WASM support, external library dependency
- Features - Best compression ratios, multiple format optimizations
javascript
// Force WASM method (requires browser-image-compression dependency)
const result = await compressImage(file, {
preferredMethod: 'wasm',
quality: 0.8,
format: 'webp'
});4. Lightweight Method
- Universal Compatibility - Pure JavaScript, works everywhere
- Requirements - Basic browser APIs only
- Features - Maximum compatibility, fallback for restricted environments
javascript
// Force lightweight method
const result = await compressImage(file, {
preferredMethod: 'lightweight',
quality: 0.8,
format: 'webp'
});🔧 Advanced Configuration
Automatic Method Selection
The library automatically chooses the best method:
javascript
// Automatic selection (recommended)
const result = await compressImage(file, {
quality: 0.8,
format: 'webp',
enableLogging: true // See which method was chosen
});
console.log(`Used method: ${result.method}`);Size Constraints and Aspect Ratio
javascript
// Resize while maintaining aspect ratio
const result = await compressImage(file, {
maxWidth: 800, // Maximum width
maxHeight: 600, // Maximum height
quality: 0.9,
format: 'jpeg'
});
// Create different sizes for responsive images
const sizes = [
{ name: 'thumbnail', maxWidth: 150, maxHeight: 150 },
{ name: 'medium', maxWidth: 800, maxHeight: 600 },
{ name: 'large', maxWidth: 1920, maxHeight: 1080 }
];
const responsiveImages = await Promise.all(
sizes.map(size =>
compressImage(file, {
...size,
quality: QUALITY_PRESETS.MEDIUM,
format: 'webp'
})
)
);Batch Processing with Progress Tracking
javascript
const files = Array.from(fileInput.files);
const results = [];
let processed = 0;
// Process with progress updates
for (const file of files) {
try {
console.log(`Processing ${processed + 1}/${files.length}: ${file.name}`);
const result = await compressImage(file, {
quality: QUALITY_PRESETS.MEDIUM,
format: 'webp',
maxWidth: 1920,
enableLogging: false // Disable for batch processing
});
results.push(result);
processed++;
// Update progress UI
const progressPercent = (processed / files.length) * 100;
updateProgressBar(progressPercent);
} catch (error) {
console.error(`Failed to process ${file.name}:`, error);
results.push({ error: error.message, file: file.name });
}
}
console.log(`Processed ${processed}/${files.length} images successfully`);Format-Specific Optimizations
javascript
// WebP with maximum compression
const webpResult = await compressImage(file, {
format: 'webp',
quality: 0.8,
maxWidth: 1920
});
// JPEG with progressive encoding simulation
const jpegResult = await compressImage(file, {
format: 'jpeg',
quality: 0.85,
maxWidth: 1920
});
// PNG with transparency preservation
const pngResult = await compressImage(file, {
format: 'png',
quality: 1.0, // PNG: 1.0 = best compression, 0.0 = fastest
maxWidth: 1920
});
// Compare results
console.log('WebP size:', webpResult.stats.compressedSize);
console.log('JPEG size:', jpegResult.stats.compressedSize);
console.log('PNG size:', pngResult.stats.compressedSize);Error Handling and Fallbacks
javascript
async function robustCompression(file, options = {}) {
const methods = ['auto', 'canvas', 'worker', 'lightweight'];
for (const method of methods) {
try {
const result = await compressImage(file, {
...options,
preferredMethod: method,
enableLogging: true
});
console.log(`Success with ${method} method`);
return result;
} catch (error) {
console.warn(`${method} method failed:`, error.message);
if (method === 'lightweight') {
throw new Error('All compression methods failed');
}
}
}
}
// Usage
try {
const result = await robustCompression(file, {
quality: 0.8,
format: 'webp'
});
console.log('Compression successful:', result.stats);
} catch (error) {
console.error('Compression completely failed:', error);
}Memory Management for Large Batches
javascript
async function processBatchWithMemoryManagement(files, options = {}) {
const results = [];
const batchSize = 5; // Process 5 images at a time
for (let i = 0; i < files.length; i += batchSize) {
const batch = files.slice(i, i + batchSize);
console.log(`Processing batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(files.length/batchSize)}`);
const batchResults = await Promise.all(
batch.map(async (file) => {
try {
const result = await compressImage(file, options);
return result;
} catch (error) {
return { error: error.message, file: file.name };
}
})
);
results.push(...batchResults);
// Force garbage collection hint
if (window.gc) window.gc();
// Small delay to prevent UI blocking
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}📊 Result Object
The compression result contains comprehensive information:
javascript
{
blob: Blob, // Compressed image as Blob object
file: File, // Compressed image as File object with proper name
stats: {
originalSize: 1048576, // Original size in bytes
compressedSize: 524288, // Compressed size in bytes
savedBytes: 524288, // Bytes saved (originalSize - compressedSize)
compressionRatio: 50, // Percentage reduction
format: 'WEBP' // Output format (uppercase)
},
method: 'canvas' // Compression method actually used
}
// Usage examples
const result = await compressImage(file);
// Access the compressed image
const compressedBlob = result.blob;
const compressedFile = result.file;
// Get compression statistics
console.log(`Original: ${result.stats.originalSize} bytes`);
console.log(`Compressed: ${result.stats.compressedSize} bytes`);
console.log(`Saved: ${result.stats.savedBytes} bytes (${result.stats.compressionRatio}%)`);
console.log(`Method: ${result.method}`);
console.log(`Format: ${result.stats.format}`);
// Create download link
const url = URL.createObjectURL(result.blob);
const downloadLink = document.createElement('a');
downloadLink.href = url;
downloadLink.download = result.file.name;
downloadLink.textContent = 'Download Compressed Image';
document.body.appendChild(downloadLink);
// Display compressed image
const img = document.createElement('img');
img.src = url;
img.onload = () => URL.revokeObjectURL(url); // Clean up
document.body.appendChild(img);🌍 Browser Compatibility
Desktop Browsers
| Browser | Canvas | Worker | WASM | Lightweight | WebP | Notes | | --- | --- | --- | --- | --- | --- | --- | | Chrome 60+ | ✅ | ✅ | ✅ | ✅ | ✅ | Full support | | Firefox 55+ | ✅ | ✅ | ✅ | ✅ | ✅ | Full support | | Safari 14+ | ✅ | ✅ | ✅ | ✅ | ✅ | WebP since 14.0 | | Edge 79+ | ✅ | ✅ | ✅ | ✅ | ✅ | Chromium-based | | IE 11 | ❌ | ❌ | ❌ | ⚠️ | ❌ | Limited support |
Mobile Browsers
| Browser | Canvas | Worker | WASM | Lightweight | WebP | Notes | | --- | --- | --- | --- | --- | --- | --- | | Chrome Mobile | ✅ | ✅ | ✅ | ✅ | ✅ | Full support | | Safari iOS | ✅ | ✅ | ✅ | ✅ | ✅ | iOS 14+ for WebP | | Firefox Mobile | ✅ | ✅ | ✅ | ✅ | ✅ | Full support | | Samsung Internet | ✅ | ✅ | ✅ | ✅ | ✅ | Full support |
CSP Compatibility
| CSP Directive | Canvas | Worker | WASM | Lightweight | Workaround |
| --- | --- | --- | --- | --- | --- |
| default-src 'self' | ⚠️ | ✅ | ✅ | ✅ | Auto-fallback to Worker |
| img-src 'self' | ⚠️ | ✅ | ✅ | ✅ | Blocks blob URLs |
| worker-src 'self' | ✅ | ⚠️ | ✅ | ✅ | Auto-fallback to WASM |
| script-src 'unsafe-eval' | ✅ | ✅ | ⚠️ | ✅ | Auto-fallback to Lightweight |
Feature Detection
javascript
import { detectCapabilities } from 'image-compressor-by-xettri-aleen/utils';
// Check what your environment supports
const capabilities = await detectCapabilities();
console.log('Canvas support:', capabilities.canvas);
console.log('Web Workers:', capabilities.webWorkers);
console.log('WebAssembly:', capabilities.webAssembly);
console.log('WebP support:', capabilities.formats.webp);
// Use capabilities to make decisions
if (!capabilities.formats.webp) {
// Fall back to JPEG for older browsers
const result = await compressImage(file, {
format: 'jpeg',
quality: 0.85
});
}🚀 Performance
Benchmark Results
Tested on 5MB JPEG image (4000x3000px), Intel i7, Chrome 120
| Method | Processing Time | Memory Usage | Quality | Compression Ratio | | --- | --- | --- | --- | --- | | Canvas | 150ms | Low | High | 75% | | Worker | 180ms | Low | High | 75% | | WASM | 240ms | Medium | Excellent | 80% | | Lightweight | 200ms | Low | Good | 70% |
Performance by Image Size
| Image Size | Canvas | Worker | WASM | Lightweight | | --- | --- | --- | --- | --- | | < 1MB | 50ms | 70ms | 100ms | 80ms | | 1-5MB | 150ms | 180ms | 240ms | 200ms | | 5-10MB | 400ms | 450ms | 600ms | 500ms | | > 10MB | 800ms | 900ms | 1200ms | 1000ms |
Optimization Tips
Choose the Right Format
javascript
// WebP for best compression const webp = await compressImage(file, { format: 'webp', quality: 0.8 }); // JPEG for compatibility const jpeg = await compressImage(file, { format: 'jpeg', quality: 0.85 }); // PNG only when transparency is needed const png = await compressImage(file, { format: 'png', quality: 1.0 });Resize Before Compression
javascript
// Resize large images first const optimized = await compressImage(file, { maxWidth: 1920, // Resize to reasonable dimensions maxHeight: 1080, quality: 0.8, format: 'webp' });Use Appropriate Quality Settings
javascript
// Different quality for different use cases const thumbnail = await compressImage(file, { quality: QUALITY_PRESETS.LOW, // 0.4 for thumbnails maxWidth: 300 }); const webDisplay = await compressImage(file, { quality: QUALITY_PRESETS.MEDIUM, // 0.7 for web display maxWidth: 1200 }); const print = await compressImage(file, { quality: QUALITY_PRESETS.HIGH, // 0.9 for print quality maxWidth: 3000 });Batch Processing Optimization
javascript
// Process in smaller batches to avoid memory issues const batchSize = 5; for (let i = 0; i < files.length; i += batchSize) { const batch = files.slice(i, i + batchSize); await Promise.all(batch.map(file => compressImage(file, options))); // Give the browser time to clean up await new Promise(resolve => setTimeout(resolve, 100)); }Disable Logging in Production
javascript
const result = await compressImage(file, { quality: 0.8, enableLogging: false // Disable logging for better performance });
🔒 Security
CSP Safety
- No External Requests - All processing happens locally in the browser
- Automatic Fallbacks - Gracefully handles CSP restrictions
- Memory Safety - Automatic cleanup of temporary objects and blob URLs
Input Validation
javascript
// The library automatically validates inputs
try {
const result = await compressImage(invalidInput, options);
} catch (error) {
console.error('Invalid input:', error.message);
// Handle validation errors gracefully
}Secure Usage Patterns
javascript
// Always clean up object URLs
const result = await compressImage(file);
const url = URL.createObjectURL(result.blob);
// Use the URL
displayImage(url);
// Clean up when done
URL.revokeObjectURL(url);
// Or use automatic cleanup
const img = new Image();
img.onload = () => URL.revokeObjectURL(img.src);
img.src = URL.createObjectURL(result.blob);🛠️ Development
Building from Source
bash
# Clone the repository
git clone https://github.com/xettrialeen/open_source_packages/tree/main/image-compressor-by-xettri-aleen.git
cd image-compressor-by-xettri-aleen
# Install dependencies
npm install
# Build all formats
npm run build
# Build for production
npm run build:prod
# Development build with watch
npm run devProject Structure
image-compressor-by-xettri-aleen/
├── src/
│ ├── index.js # Main entry point
│ ├── standalone-index.js # Standalone build entry
│ ├── core/
│ │ ├── compressor.js # Main compression logic
│ │ ├── canvas-handler.js # Canvas compression method
│ │ ├── worker-handler.js # Web Worker method
│ │ ├── wasm-handler.js # WebAssembly method
│ │ └── light-weight-handler.js # Lightweight fallback
│ ├── utils/
│ │ ├── detection.js # Browser capability detection
│ │ ├── helpers.js # Utility functions
│ │ └── logger.js # Logging utilities
│ └── workers/
│ └── compression-worker.js # Standalone worker script
├── dist/
│ ├── index.js # UMD build
│ ├── index.esm.js # ES module build
│ └── index.standalone.js # Standalone build
├── types/
│ └── index.d.ts # TypeScript definitions
├── test/
│ ├── basic-test.html # Basic functionality tests
│ ├── esm-test.html # ES module tests
│ ├── standalone-test.html # Standalone build tests
│ └── performance-test.html # Performance benchmarks
├── package.json
├── rollup.config.js # Build configuration
├── README.md
└── LICENSE