TL;DR
I built ImageSqueeze — a free, privacy-first image compressor that runs 100% in your browser. No images are ever sent to any server.
- Drag & drop batch compression
- Resize with SNS presets
- WebP conversion
- EXIF auto-removal
- ZIP download
The Problem
Every time I needed to compress images for a blog post or client project, I'd reach for TinyPNG or Compressor.io. They work great, but there's always that nagging thought:
"Am I really okay uploading these client images to a third-party server?"
For personal blog images, it's fine. But for:
- Client work under NDA — can't risk it
- Internal company docs — policy says no
- Personal photos with GPS data — definitely not
I wanted a tool that compresses images without sending them anywhere.
The Solution: Canvas API
Here's the key insight: browsers already have a built-in image processing engine — the Canvas API.
// The core of ImageSqueeze in ~15 lines
const img = new Image();
img.onload = () => {
const canvas = document.createElement("canvas");
canvas.width = targetWidth;
canvas.height = targetHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
canvas.toBlob(
(blob) => {
// blob is your compressed image!
// Original file never left the browser
},
"image/webp",
0.8 // quality: 80%
);
};
img.src = URL.createObjectURL(file);
When you draw an image onto a Canvas and export it with toBlob(), the browser re-encodes it at your specified quality. EXIF metadata is automatically stripped in this process — it's a free privacy win.
Features
1. Batch Processing
Drop multiple images at once. Free tier handles 10 images, PRO is unlimited.
2. Smart Compression
- Quality slider (1–100%)
- PNG files auto-convert to WebP for better compression
- If the compressed file is somehow larger than the original, the original is returned
3. Resize with Presets
| Preset | Size |
|---|---|
| Blog | 800px width |
| OGP | 1200 × 630 |
| 1080 × 1080 | |
| Twitter Header | 1500 × 500 |
| Thumbnail | 300 × 300 |
With "Lock Aspect Ratio" on, images fit within the target dimensions without upscaling.
4. Format Conversion
Convert between JPG, PNG, and WebP. When converting PNG (with transparency) to JPEG, the background is automatically filled with white.
5. EXIF Removal
GPS coordinates, camera model, timestamps — all stripped automatically via Canvas re-rendering. Toggle it on/off in the Compress tab.
6. Re-compress Without Re-uploading
Changed your mind about the quality setting? Click "Apply & Re-compress" — no need to drag & drop again.
7. ZIP Download
Download all compressed images as a single ZIP file via JSZip (dynamically imported to keep the initial bundle small).
How It Compares
| Feature | ImageSqueeze | TinyPNG | Squoosh |
|---|---|---|---|
| Processing | Browser | Server | Browser |
| Batch | 10 (free) | 20/month | 1 at a time |
| Resize | SNS presets | No | Yes |
| ZIP download | Yes | No | No |
| Re-compress | Yes | No | No |
| EXIF removal | Yes | No | No |
| Price | Free / $9.99 PRO | Free / API paid | Free |
Trade-offs
I want to be honest about the limitations:
1. Compression quality
Canvas toBlob() uses the browser's built-in encoder. It's decent but not as sophisticated as TinyPNG's server-side AI compression. You might get slightly larger files for the same visual quality.
2. No AVIF support (yet)
Most browsers can't encode AVIF via Canvas. WebP is the best client-side option right now.
3. Large images eat memory
Since everything runs in the browser, processing fifty 20MB RAW files will consume significant RAM. The tool works best with web-sized images.
Tech Stack
- Next.js 16 + TypeScript + Tailwind CSS v4
- Canvas API for all image processing
- JSZip for ZIP generation (dynamic import)
- FileSaver.js for download handling
- Vercel for hosting
- Google Stitch for UI design (generated the design system)
- i18n — auto-detects Japanese/English from browser language
What I Learned
Google Stitch for UI Design
This was my first time using Google Stitch to generate UI designs. I connected it via MCP (Model Context Protocol) to Claude Code, which let me:
- Generate the initial UI from a text prompt
- Get the HTML/CSS code directly
- Convert it to React components
The design system it generated ("The Digital Sanctuary" concept) gave me a complete color palette, typography rules, and component specifications. Saved hours of design work.
Canvas API Gotchas
- JPEG + transparency = black background. You need to fill the canvas with white before drawing.
-
toBlob()can return null on memory pressure. Always handle it. -
Object URLs leak memory. Always call
URL.revokeObjectURL()when done. - PNG "compression" can increase file size. PNG is lossless, so Canvas re-encoding at quality 1.0 can actually produce a larger file. That's why I auto-convert PNG to WebP.
Try It
Live: image-squeeze-blush.vercel.app
Source: github.com/bbtc3453/image-squeeze
Free for 10 images. No account needed. No data sent anywhere.
If you find it useful, a GitHub star would mean a lot. Feedback and PRs are welcome!
Built in a day with Claude Code + Google Stitch. The entire process — from idea to deployment to this article — was completed in a single session.
Top comments (0)