ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-07-13Intermediate

The Gate That Stops Visual Damage Before You Hand Bulk Image Optimization to an Agent

When an agent bulk re-encoded a few hundred wallpaper assets, a handful came back with dulled color. Size-reduction alone cannot catch that. Here is how to design a gate that stops bad conversions before merge using three axes — SSIM, ΔE, and file size — with a checker that runs on Pillow and scikit-image.

antigravity432app-dev49imageautomation81quality-gate3

Premium Article

One night I was tidying the assets in one of my wallpaper apps. There were about 320 preview PNGs for the home grid, and I asked an agent to batch-convert them to WebP. By morning the log looked flawless: total size down from 41MB to 17MB. Nothing to argue with.

Then I checked on a real device. A few images — deep indigo night skies — had turned slightly gray. The kind of difference you only notice when you place the two side by side. The agent had reported "size reduced" as success, and I had trusted that report right up to the edge of merging.

Something tightened in my chest. Had it shipped unnoticed, the color of the very pieces I most wanted people to see would have been quietly degraded.

This article is about how to design a gate that captures "visual damage" as numbers and stops it before merge when you delegate bulk image optimization to an agent. I will share the implementation from an indie wallpaper app — a place where color itself is the product — along with the threshold guidance I settled on in production.

Why "size went down = success" is the wrong place to stop

Image optimizers love to report their reduction ratio, and agents do the same: "Converted 320 images, average 59% smaller." That is not a lie. But a reduction ratio only tells you how much was thrown away, never what was thrown away.

Most of the loss is invisible. Lossy JPEG and WebP compression, depending on the quantization tables, introduces banding across smooth gradients. Conversions that reduce the palette round off subtle tonal steps. If a color profile is stripped, pixels with identical values render as different colors.

Each of these produces a "perfectly valid file" that sails past corruption checks. Human review has limits too. Comparing 320 images one by one against the originals exceeds the number of frames your attention can actually hold. That is precisely the kind of quiet degradation I nearly missed.

So we need to translate degradation into numbers a machine can measure, and route only the ones that fall below threshold back to a human. Let the agent do the optimization itself — that is fine. What it must not own is the final pass/fail decision.

Capturing visual damage as numbers — three axes

I judge on three axes. One is not enough; the three cover each other's blind spots.

AxisWhat it measuresWhat it catches
SSIM (structural similarity)Agreement of luminance, contrast, and structureBanding, crushed detail, softened edges
ΔE (color difference)Perceptual color shift (distance in CIELAB)Hue drift, desaturation, profile stripping
File sizeThe effect of optimizationBoth over-compression and no-op conversion

SSIM is 1.0 for a perfect match, and lower as structure breaks down. Unlike a per-pixel difference (MSE), it captures structural change in a way closer to whether a human would call two images "the same." Its sensitivity to banding and crushed detail is the advantage.

SSIM, however, is relatively blind to hue drift. As long as luminance holds, a blue leaning slightly green barely moves the score. For a wallpaper app, where color is everything, ΔE fills that gap. ΔE is a distance in CIELAB space, where roughly 1.0 is "a difference a trained eye can just perceive," and 2–3 is "a difference visible when placed side by side."

The third axis, file size, checks the health of the optimization rather than degradation itself. An extreme reduction ratio hints at over-compression; almost no reduction means the conversion is not doing anything — so there is no reason to take on a quality risk for it.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A gate design that catches the quality loss a size-reduction number can never reveal, using SSIM, ΔE, and file size together
A CI-ready image quality checker built with nothing but Pillow and scikit-image
Real threshold guidance by conversion preset, drawn from running a wallpaper app in production
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-07-03
Catching Download Size Regressions Before Submission Day — A Weekly Agent Gate for AAB/IPA Size Budgets
Mediation SDKs and bundled assets quietly inflate download size. A design for size ledgers, budget gates, and agent-driven delta attribution using bundletool and App Thinning reports.
App Dev2026-07-09
Before an Agent's .proto Edit Silently Breaks Binary Compatibility: Gating Wire Compat with buf breaking
When an agent edits your .proto files, the text can look perfect while wire compatibility quietly breaks. Here is how to stop field-number reuse and unsafe type changes with a working gate built from buf breaking and reserved.
App Dev2026-07-02
Stop Treating Dependency Updates as a Monthly Chore — Weekly Agent Runs with Semver Risk Triage and Verification Gates
Move from batch-updating 47 stale packages at once to a weekly agent-driven routine: semver-based risk tiers, a playbook YAML, hallucination-proof changelog reports, and a lockfile diff gate.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →