Vanilla JavaScript Projects

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.

4.2 MB380 KB
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.
 

How it works

  1. DecodeEach file becomes an ImageBitmap with createImageBitmap, which decodes off the main thread.
  2. Resize in a workerThe bitmap is sent to the worker, drawn at the new size on an OffscreenCanvas with high quality smoothing.
  3. 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]);