Keywords: image compression • pdf compression • video compression • webp • avif • heic • remove exif • font converter • ttf to woff2 • font subsetting • variable font • webassembly • webcodecs • client-side • private • no upload
Compress images, video, audio and PDFs — convert and subset fonts — and strip EXIF, entirely in your browser. No uploads, no ads, no login, nothing stored server-side. Free & open source — files never leave your machine.
Compress Pro is a free, open-source, private-by-design file compressor. It shrinks images, video, audio and PDFs — converts and subsets fonts (TTF/OTF/WOFF/WOFF2), creates and extracts archives (ZIP, 7Z, TAR, tarballs; opens RAR, ISO, CAB, DEB, RPM and more), and strips EXIF metadata — running entirely in the browser via WebAssembly + WebCodecs. Fonts especially benefit from the privacy angle: they are licensed software most EULAs forbid handing to third-party servers.
The whole app is prerendered and served as static assets, so files never leave the machine. Compression runs in Web Workers, so the UI stays responsive. There are no ads, no login and nothing stored server-side — privacy is the product's core promise and its SEO angle. It deploys to Cloudflare Workers for ~$0/month.
- 🖼️ Images — JPG, PNG, WebP, GIF, HEIC, SVG. Squoosh codecs (jSquash): MozJPEG with trellis quantization (3–6% smaller at the same quality), libwebp (effort 6), libavif, oxipng; lossy PNG via libimagequant (icodec, quality 100 stays lossless). Optional max-dimension downscale (Lanczos3) and target-size mode ("fit under 500 KB", binary search).
- 📄 PDF — Ghostscript 10 in wasm (
@okathira/ghostpdl-wasm): explicit DPI + JPEG-quality control, bicubic downsampling, duplicate-image detection, font subsetting, metadata stripping. 5 preset levels or target size ("fit under 2 MB") via binary search over a quality ladder. Before/after page-1 comparison via pdf.js. - 🎬 Video — compress and convert MP4/MOV/WebM/MKV via WebCodecs (the browser's hardware encoders) orchestrated by mediabunny — no ffmpeg, ~realtime encodes. H.264 (MP4/MOV), VP9 (WebM) or animated GIF output, quality or target-size mode, longest-side downscale, fps cap, remove-audio; audio otherwise transmuxes losslessly when container-legal. GIFs convert back to silent MP4/MOV/WebM too.
- 🎵 Audio — compress and convert to MP3/M4A/WAV/FLAC/OGG/OPUS/WEBA — from any audio the browser can demux (LAME wasm for MP3, libFLAC wasm for FLAC, FFmpeg-AAC wasm fallback where WebCodecs lacks AAC), extract audio from video (MP4 → MP3/WAV), bitrate or target-size mode.
- 🔤 Fonts — convert between TTF, OTF, WOFF, WOFF2 (and legacy EOT) as lossless repackaging of the raw font tables (Google's woff2 codec in wasm — glyphs, kerning and hinting survive byte-for-byte); subset fonts to chosen character sets or exact text via HarfBuzz (kerning/ligatures among kept glyphs preserved), and pin variable fonts to static instances per axis. Outlines are never converted lossily — a CFF font asked to become TTF keeps its honest
.otfextension. - 🔐 PDF unlock & protect — remove a known password or add one (128-bit encryption) — the password never leaves the device.
- 📦 Archives — create ZIP, 7Z (optional AES-256 + hidden file names), TAR, TAR.GZ/BZ2/XZ and per-file gz/bz2/xz; extract ZIP, RAR (v4+v5), 7Z, tarballs, ISO, CAB, DEB, RPM, CPIO, LHA, ARJ and .Z — password-protected archives included; convert archive→archive (RAR → ZIP, ZIP → 7Z…) with folder structure preserved. Plain ZIP stays on fflate; everything else runs 7-Zip compiled to wasm (
7z-wasm) in a worker, with nested payloads (deb → data.tar → files) unwrapped automatically. - 🧹 EXIF removal — lossless byte surgery on JPG/PNG/WebP: EXIF/GPS, XMP, Photoshop blocks, comments and PNG text chunks are cut out with pixels copied verbatim; ICC profiles kept by default (toggle), orientation re-embedded so photos never turn sideways. Each result row discloses what was found.
- ✨ Auto format (default) — on the JPG/PNG/WebP tabs the worker races MozJPEG vs WebP (and AVIF for images ≤4 MP under cross-origin isolation) per image and keeps the smallest file; animation stays WebP, transparency never falls to JPEG, and the untouched original wins when nothing beats it.
- ⚡ Parallel + threaded codecs — batches fan out across a pool of image workers with per-row live status, and the app is cross-origin isolated (COOP/COEP), which activates the bundled multithreaded AVIF and oxipng builds.
- 📴 Offline PWA — a service worker precaches the shell and prerendered pages and runtime-caches each codec wasm on first use, so the app keeps working offline — any tool used once compresses with no connection at all.
- 🧰 PDF tools — merge PDFs (reorderable, optional compress-after-merge), extract/remove pages (
1-3,7,12-), render pages to JPG/PNG (72/150/300 DPI, multi-page → ZIP), and build a PDF from images. - 🗜️ Batch + ZIP — multi-file batches keep input order; download everything as a ZIP (fflate, client-side).
- 📋 Clipboard & drag-drop — paste files/screenshots anywhere (⌘V / Ctrl+V routes them to the right tab), drop files anywhere on the page, and copy compressed images back to the clipboard.
Every tool is its own real, prerendered page.
| Tool | Engine |
|---|---|
| Compress JPG | MozJPEG + trellis |
| Compress PNG | oxipng / libimagequant |
| Compress WebP | libwebp |
| Compress GIF | gifsicle |
| Compress HEIC | libheif (icodec) |
| Compress SVG | svgo |
| Compress PDF | Ghostscript |
| Compress Video | WebCodecs + mediabunny |
| Compress MP4 | WebCodecs + mediabunny |
| Compress MOV | WebCodecs + mediabunny |
| Compress any image | Auto format race |
| Compress JPG to 100 KB | target-size search |
| Compress Audio | mediabunny + LAME / libFLAC |
| Convert fonts | raw sfnt repack + Google woff2 |
| Subset font | HarfBuzz subsetter |
| Variable font → static | HarfBuzz instancer |
| Zip & Unzip files | fflate + 7-Zip wasm |
| Create 7Z | 7-Zip wasm, AES-256 |
| Create TAR.GZ | tar + gzip/bzip2/xz |
| Extract RAR | unRAR-derived decoder |
| Extract ISO | ISO9660/Joliet/UDF reader |
| Resize images | Lanczos3 downscale |
| Remove EXIF | lossless byte surgery |
- To JPG — HEIC → JPG · WebP → JPG · AVIF → JPG · PNG → JPG
- To WebP — JPG → WebP · PNG → WebP
- To PNG — WebP → PNG · HEIC → PNG
- PDF — JPG → PDF · PNG → PDF · PDF → JPG · PDF → PNG
- Video — MOV → MP4 · WebM → MP4 · MKV → MP4 · MP4 → WebM · Video → GIF · MP4 → GIF · GIF → MP4
- Audio — MP4 → MP3 · WAV → MP3 · M4A → MP3 · FLAC → MP3 · WAV → FLAC · OPUS → MP3 · OGG → MP3 · AAC → MP3 · MP3 → WAV · MP4 → WAV
- Images — BMP → JPG · TIFF → JPG · PNG → ICO · JPG → ICO · SVG → PNG · SVG → ICO
- PDF tools — Merge PDF · Split PDF · Unlock PDF · Protect PDF
- Archives — RAR → ZIP · 7Z → ZIP · ZIP → 7Z · TAR.GZ → ZIP · ISO → ZIP · ZIP → TAR.GZ · extract RAR / 7Z / TAR.GZ / GZ / ISO / CAB / DEB / RPM / CPIO / LHA / ARJ · create 7Z / TAR / TAR.GZ / GZ / BZ2 / XZ
- Fonts — TTF → WOFF2 · TTF → WOFF · OTF → WOFF2 · OTF → WOFF · WOFF → TTF · WOFF → OTF · WOFF → WOFF2 · WOFF2 → TTF · WOFF2 → OTF · WOFF2 → WOFF · TTF → EOT · EOT → TTF
- SvelteKit (Svelte 5 runes) + Tailwind CSS v4 on Vite 8
- Cloudflare Workers via
@sveltejs/adapter-cloudflare— fully prerendered / static - WASM codecs — jSquash (MozJPEG, libwebp, libavif, oxipng), icodec (HEIC, lossy PNG),
@okathira/ghostpdl-wasm(Ghostscript), gifsicle, svgo, pdf-lib / pdf.js, fonteditor-core's Google-woff2 wasm + harfbuzzjs hb-subset (fonts), 7z-wasm (7-Zip CLI — archives incl. RAR/ISO extraction) - mediabunny driving WebCodecs for video & audio, plus its LAME MP3, libFLAC and FFmpeg-AAC wasm encoder extensions
src/lib/workers/— Web Workers (gs,image,svg,video,font,archive);rpc.tslazy-spawns a pool of image workers (least-busy routing, capped atmin(cores, 4)) with typed payload/result/progress contracts inprotocol.ts.src/lib/compress.tsschedules files throughrunWithConcurrency(src/lib/concurrency.ts), keeps input order (rows/ZIP), and supports cancel — in-flight worker calls abort while finished files keep their results.src/lib/codecs/— main-thread facades;pdf.tsholds the Ghostscript argument builder and target ladder; the shared binary search lives intarget-search.ts.- Fully prerendered — every request is served from the free static-asset layer; content-hashed, immutable-cached wasm downloads once.
- SEO — every format and converter is a real prerendered route served by the single
src/routes/[[tool=tool]]/+page.svelte, so tab switches never remount. All copy lives insrc/lib/seo.ts(FORMATS+CONVERTERS+TOOLS). Adding a tool means extendingprerender.entriesinsvelte.config.js. - robots.txt is served by the Worker per request — only the canonical host (
PUBLIC_SITE_URL) getsAllow; any other host (preview, staging) getsDisallow: /, so non-production deployments can never be indexed. - llms.txt — a prerendered llms.txt index of every tool page, generated from
seo.tslike the sitemap, so AI answer engines (ChatGPT, Perplexity) can cite the right page directly. Its companion/llms-full.txtinlines the full content of every page in one document; both are referenced as comments in the production robots.txt. - Agent-ready surface — every tool page has a prerendered markdown twin (append
.mdto its URL; homepage:/index.md; emitter:src/lib/markdown.ts). The production robots.txt declaresContent-Signal: ai-train=yes, search=yes, ai-input=yes,_headersadds an RFC 8288Linkheader pointing at llms.txt and the skills index,/.well-known/agent-skills/serves a digest-verified Agent Skills index (src/lib/agent-skills.ts), and pages register WebMCP tools (src/lib/webmcp.ts) in browsers that exposenavigator.modelContext(ordocument.modelContext).Accept: text/markdownnegotiation serves that same twin at the page's own URL: a thin Worker wrapper (worker/index.js, wrapping the adapter worker and scoped byrun_worker_firstinwrangler.jsoncso it only fires for HTML navigations) returns the prerendered.md— withContent-Type: text/markdown,Vary: Acceptand anx-markdown-tokensestimate — while browsers keep HTML by default. The.mdtwins stay directly fetchable too. - DNS-AID — DNS-layer discovery via SVCB records under
_agents(_index._agents,_a2a._agents) that point agents at this HTTPS surface. DNS lives in Cloudflare (no DNS-as-code), so it's published withpnpm dns:aid(scripts/dns-aid.mjs) — seedocs/dns-aid.mdfor the records, publishing, DNSSEC, and verification. The records are honest: no server-side A2A/MCP endpoint is claimed (the app is 100% in-browser).
Requires Node ≥ 22.12 and pnpm 10 (packageManager is pinned; engine-strict is on).
pnpm installpnpm dev # vite dev
pnpm check # svelte-check
pnpm lint # prettier --check + eslint
pnpm format # prettier --write
pnpm test # vitest (pure-logic unit tests)
pnpm preview # build + wrangler dev (workerd-faithful, http://localhost:8787)
pnpm og # regenerate the Open Graph images (after copy changes in generate-og.mjs)
pnpm icons # regenerate favicon.ico / apple-touch / PWA icons from static/favicon.svg
pnpm demo-assets # regenerate the before/after demo proofs (runs each sample through the real tool page)
pnpm bench:memory # peak-memory benchmark harness → docs/memory-bench.mdThe compression pipelines run as WASM in the browser, so their correctness is tested end-to-end with Playwright (Chromium) against the real UI: upload → settings → compress → download → verify bytes in Node (sharp / pixelmatch for format, dimensions, frames, alpha and pixel diffs vs e2e/thresholds.ts; pdf-lib page-size fingerprints; fflate ZIP inspection).
pnpm test:e2e # full suite (builds the visual report)
pnpm test:e2e:smoke # @smoke subset (<30 s)
pnpm test:e2e:quick # skips @slow tests + the real-file suite — fast iteration
pnpm test:e2e:xbrowser # @xbrowser capability smoke on Firefox + WebKit (needs `playwright install firefox webkit`)
pnpm test:e2e:ui # Playwright UI mode
pnpm test:e2e:preview # same suite against the built app on wrangler (:8787)
pnpm report # rebuild + open the visual report
pnpm fixtures # (re)generate synthetic inputs into tests/fixtures/generated/
pnpm check:e2e # typecheck the e2e suite (tsc -p e2e/tsconfig.json --noEmit)- Fixtures are deterministic and self-verified at generation time (
scripts/generate-fixtures.mjs). Real-world samples go intests/fixtures/real/(git-ignored, ~160 MB local) and unlock extra tests; everything skips cleanly when they're absent. - Visual report at
test-results/report/index.html— every case as a card with original vs output side by side, pixel-diff toggle, metrics and warnings, sorted worst-first and filterable. Global setup wipes the report data on EVERY playwright invocation, so a complete report only comes out of a fullpnpm test:e2erun — quick/smoke runs leave a partial one. E2E_CALIBRATE=1 pnpm test:e2erecords pixel-diff ratios without failing on budgets — use it when recalibratinge2e/thresholds.ts.
npx wrangler login
pnpm deploy # build + publish to compress-pro.comDeploys to Cloudflare Workers on the compress-pro.com custom domain, provisioned automatically from wrangler.jsonc (workers_dev is off to avoid a duplicate indexable host). The free plan is plenty — everything is served as static assets, which are free and unlimited.
Every build bakes two Vite define constants into the bundle, shown in the site footer:
__BUILD_DATE__— ISO date of the build.__COMMIT__— the exact git commit:WORKERS_CI_COMMIT_SHAon Cloudflare's Git-integrated builds,git rev-parselocally (suffixed-dirtyif the working tree has uncommitted changes),devoutside a repo.
Production is built automatically from this repository, so the footer hash links to the precise source state a deployment is running — anyone can cross-check the live site against the repo.
- Fork the repository
- Create a feature branch
- Make your changes
- Run
pnpm check && pnpm lint && pnpm test - Submit a pull request
Note
The app code is MIT, but several bundled WASM engines are copyleft: Ghostscript (AGPL-3.0), gifsicle (GPL-2.0), LAME and FFmpeg's AAC encoder (LGPL), and the HEIC / lossy-PNG codecs inside icodec (GPL/LGPL family). The permissive rest: MozJPEG / libwebp / libavif / libFLAC (BSD-style), oxipng (MIT), and others. This repository publishes the complete corresponding source, which is what the copyleft licenses require — but if you redistribute a build (especially closed-source or modified), those terms apply to you too. Full per-package breakdown: THIRD_PARTY_LICENSES.md.
Built on the work of jSquash, icodec, @okathira/ghostpdl-wasm, mediabunny, gifsicle-wasm-browser, svgo, pdf-lib and pdf.js.
