Project 38, Media and real-time
Image Compressor
Drop a batch of photos, choose a size and quality, and get smaller files back in seconds. The heavy work runs in a background worker, and nothing is uploaded.
- Main API
- OffscreenCanvas in a Worker
- Formats
- WebP, AVIF, JPEG, PNG
- Dependencies
- None
- Your browser
- Checking
Compress images
Drop images here or click to choose. You can pick many at once.
before after
How it works
- DecodeEach file becomes an ImageBitmap with createImageBitmap, which decodes off the main thread.
- Resize in a workerThe bitmap is sent to the worker, drawn at the new size on an OffscreenCanvas with high quality smoothing.
- EncodeconvertToBlob encodes to the chosen format and quality. The page gets back the new file and its size.
// worker.js (created from a Blob so the page stays a single file)
self.onmessage = async ({ data: { id, bitmap, width, type, quality } }) => {
const scale = width ? Math.min(1, width / bitmap.width) : 1;
const canvas = new OffscreenCanvas(Math.round(bitmap.width * scale), Math.round(bitmap.height * scale));
const ctx = canvas.getContext("2d");
ctx.imageSmoothingQuality = "high";
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
const blob = await canvas.convertToBlob({ type, quality });
self.postMessage({ id, blob, w: canvas.width, h: canvas.height });
};
// page
worker.postMessage({ id, bitmap, width: 1920, type: "image/webp", quality: 0.75 }, [bitmap]);