PatternsAssets Engine
Image Compression (Canvas)
Reduce image file size on the client before upload using Canvas API.
The Problem
Users often upload high-resolution photos (5MB or larger) directly from phones. This wastes bandwidth and slows down uploads.
Solution
interface CompressionOptions {
maxWidth?: number;
maxHeight?: number;
quality?: number; // 0.0 to 1.0
}
async function compressImage(
file: File,
options: CompressionOptions = {}
): Promise<Blob> {
const { maxWidth = 1920, maxHeight = 1080, quality = 0.85 } = options;
// Load image
const imageBitmap = await createImageBitmap(file);
// Calculate new dimensions (preserve aspect ratio)
let { width, height } = imageBitmap;
if (width > maxWidth || height > maxHeight) {
const ratio = Math.min(maxWidth / width, maxHeight / height);
width = Math.floor(width * ratio);
height = Math.floor(height * ratio);
}
// Draw to canvas
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext('2d');
if (!ctx) throw new Error('Canvas context not available');
ctx.drawImage(imageBitmap, 0, 0, width, height);
// Convert to blob
return canvas.convertToBlob({
type: 'image/jpeg',
quality
});
}
// Usage
const originalFile = document.querySelector('input[type="file"]').files[0];
const compressedBlob = await compressImage(originalFile, {
maxWidth: 1920,
quality: 0.8
});
console.log(`Original: ${(originalFile.size / 1024 / 1024).toFixed(2)}MB`);
console.log(`Compressed: ${(compressedBlob.size / 1024 / 1024).toFixed(2)}MB`);
// Upload compressed version
const formData = new FormData();
formData.append('image', compressedBlob, originalFile.name);
await fetch('/api/upload', { method: 'POST', body: formData });Performance Note
Benefit: A 4MB photo can be reduced to ~600KB without visible quality loss. This means 85% less bandwidth usage and faster uploads, especially on mobile networks.