cd /news/developer-tools/i-wrote-a-rust-image-compressor-that… Β· home β€Ί topics β€Ί developer-tools β€Ί article
[ARTICLE Β· art-84987] src=dev.to β†— pub= topic=developer-tools verified=true sentiment=↑ positive

I Wrote a Rust Image Compressor That Survives WeChat's Brutal Re-Compression

A developer built a Rust-based image compressor designed to survive the aggressive re-compression applied by WeChat, Instagram, and Xiaohongshu. The tool uses mozjpeg, preserves 4:4:4 chroma, and exposes a JSON interface for AI agents. It includes per-platform presets and achieves near-lossless quality by encoding at Q96.

read4 min views1 publishedAug 3, 2026

If you've ever sent a photo through WeChat and watched it come out looking like it went through a blender, you know the feeling. The colors shift, gradients turn into visible banding, and fine detail just evaporates. Instagram and WhatsApp do the same thing, just with different thresholds.

I got annoyed enough to actually dig into what these platforms do to images, and then I built a tool to fight back. It's written in Rust, uses mozjpeg, keeps full 4:4:4 chroma, and β€” the part I'm personally most happy with β€” it exposes a clean JSON interface so AI agents can drive it directly.

Here's the whole story: what the platforms are actually doing, what I built to counter it, and why I bothered with Rust.

Most people assume "compression" just means "the file got smaller." It's worse than that. Re-compression is three separate things happening at once:

The realization that changed how I built this: the platform compresses unconditionally. If your file is over its threshold, it compresses again. No exceptions, no mercy. So "preventing re-compression" was never about stopping them β€” it's about pre-processing your image so that after they compress it, it still looks good.

The default mode in my tool (which I just call "quality first") plays four cards:

1. Keep 4:4:4 chroma. Most compressed images look muddy because they've already been subsampled to 4:2:0. My encoder outputs 4:4:4 β€” color stays at full resolution right alongside luminance. No more color blocking, no more weird edges on red text.

2. Start at Q96. Platforms re-encode at Q50–70. I encode at Q96, which is near-lossless. So when they compress it again, the floor is already high and the result stays sharp. The tradeoff is file size β€” but in this mode, size is just a safety threshold, not something I'm actively trying to minimize.

3. CAS sharpening. Downscaling makes everything feel soft. I use Contrast-Adaptive Sharpening (CAS) with a strength of 0–1, defaulting to 0.35 in quality mode. It sharpens landscapes more, faces less, and skips high-noise areas entirely. The result looks like the original's natural clarity, not an over-sharpened mess with halos around every edge.

4. Per-platform presets. WeChat, Xiaohongshu (RED), Instagram, and a generic pipeline each have different safety thresholds. The engine picks the right max dimension, size cap, and quality automatically when you select a platform. You don't have to memorize parameters.

Preset Platform What it handles
wechat
WeChat / Moments Anti-recompression sizing for chat & moments
xiaohongshu
Xiaohongshu (RED) 1660px long edge, feed-optimized quality
instagram
Portrait / square feed sizing
general
Any pipeline Balanced default, no forced sRGB conversion

Three reasons that mattered to me:

For the actual JPEG encoding I use a pure-Rust mozjpeg wrapper, which holds up better at the same file size than stock libjpeg.

The architectural choice I'm proudest of: the GUI and the CLI are just two skins over one compression core. So the quality a human sees by dragging a file in is exactly what an AI agent gets when it calls the same engine. No drift between "the pretty demo" and "what the API actually does."

Most compression tools stop at a GUI. This one also speaks Agent-First JSON β€” an AI agent doesn't need to learn CLI flags, it just throws a JSON envelope at it:

echo '{"files":["a.jpg","b.jpg"],"platform":"wechat","quality_mode":"max"}' \
  | ./image-compressor --json

A few design decisions that make it agent-friendly:

--force

overrides when you really mean it.0

= all good, 1

= some failed, 2

= bad arguments. The agent knows whether to retry or bail.| Metric | Result | |---|---| | Per-image time | ~89ms (8-core parallel) | | Typical ratio | 2–8x in social mode; quality mode prioritizes quality over size | | Peak memory | ~15MB | | Distributable size | ~4.5MB single file (Windows) | | Chroma | 4:4:4 preserved |

I threw the design at Qwen 3.8 for an outside read. Its verdict: top-tier in imaging expertise, engineering architecture, and scenario insight. I'll let you judge that claim for yourself rather than parrot the praise β€” but it was a useful sanity check that the architecture holds up under scrutiny.

Everything runs locally. Windows: double-click. macOS: unzip and run (if it won't open, here's the fix).

"Anti re-compression" isn't magic. It's reverse-engineering what the platform does, then satisfying it first. 4:4:4 keeps the color, Q96 keeps the detail, CAS keeps the sharpness, and platform presets keep the size in bounds. Stack those and the platform can't degrade your photo no matter how many times it compresses.

If WeChat, Instagram, or WhatsApp compression has been eating your photos too β€” or if you want a local, offline, JSON-callable image compressor in your AI workflow β€” give it a try. PRs are welcome.

── more in #developer-tools 4 stories Β· sorted by recency
── more on @rust 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/i-wrote-a-rust-image…] indexed:0 read:4min 2026-08-03 Β· β€”