The transparency bug you cannot see in a thumbnail

5
calendar_today agoschedule4 min read

There is a failure mode in image generation that survives every visual check you
are likely to run, ships to production, and only surfaces when a designer drops
the asset onto a coloured background. It is worth knowing about because the
thing that makes it dangerous is not the model — it is the preview.

What actually goes wrong

Ask an image model for a subject "on a transparent background" and you can get
back one of two very different files.

The first is what you wanted: an RGBA image where the pixels around the subject
have an alpha value of zero. Nothing is drawn there. Composite it over red and
you see red.

The second is an RGB image, fully opaque, in which the model has painted a
light grey and white checkerboard around the subject. Composite that over red
and you see a chequered rectangle with your subject in the middle.

The second one happens because the checkerboard is a convention, not a fact.
Photoshop, GIMP, Figma and every image editor written in the last thirty years
draw that grid to represent absence. So the training data contains an enormous
number of images in which "transparent background" and "a grid of light grey and
white squares" are the same picture. A generative model has no privileged access
to the alpha channel; it predicts pixels. Asked for the look of transparency, it
sometimes produces exactly that — the look.

Why every preview lies about it

This is the part that catches people, and it is pure interface design.

Your file browser, your image viewer, your CDN's thumbnailer and the preview
pane in whatever tool generated the image all render genuine transparency as a
checkerboard. That is the standard way to display an empty alpha channel.

So both files look identical in the preview:

Real alpha Painted checkerboard
Thumbnail in Finder / Explorer grey-and-white grid grey-and-white grid
Image viewer grey-and-white grid grey-and-white grid
Dropped onto a red div red grey-and-white grid

The failure is invisible in exactly the three places you would look, and visible
only in the one place you look last. If your pipeline generates assets in bulk —
product cut-outs, icon sets, sprite sheets — you can ship hundreds of broken
files before anyone notices, and the person who notices will be a customer.

Checking it properly, in about ten lines

You do not need a library and you do not need to upload anything. The check runs
on the file the browser already has. Read the pixels, look at the alpha channel,
and ask one question: does any pixel have alpha below 255?

async function hasRealAlpha(file) {
  const bitmap = await createImageBitmap(file);
  const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
  ctx.drawImage(bitmap, 0, 0);

  const { data } = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
  for (let i = 3; i < data.length; i += 4) {
    if (data[i] < 255) return true;       // at least one non-opaque pixel
  }
  return false;                            // fully opaque: no alpha channel in use
}

Two notes on getting this right.

Check the corners before you check everything. A cut-out almost always has
transparent corners, so sampling the four corner pixels answers the question for
the common case at a fraction of the cost. Fall back to the full scan only when
the corners are opaque — that is either a genuine edge-to-edge image or the bug.

A JPEG cannot pass this test, ever. JPEG has no alpha channel. If your
pipeline re-encodes to JPEG anywhere — a thumbnailer, an upload handler, an
overeager optimiser — you will destroy real transparency and produce a file that
is indistinguishable from the painted-checkerboard failure. Check the format
before you blame the model.

The stronger version of the check

Detecting some transparency is not the same as detecting correct
transparency. A file can have a real alpha channel and still be wrong: a halo of
semi-opaque pixels around the subject, left over from a soft matte, shows up as
a grey fringe on dark backgrounds.

The honest test is the one that mirrors how the asset will be used: composite it
over a solid colour and look. Two colours, ideally — one much darker than the
subject and one much lighter. Fringing that is invisible on white is obvious on
black, and the reverse is true for dark subjects.

// draw the result over a flat colour, then look at it like a human would
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "#c0392b";
ctx.fillRect(0, 0, canvas.width, canvas.height);

That is three lines and it turns an invisible failure into an obvious one.

Why this is worth building into the tool rather than the test suite

A test suite catches this after generation, which means after you have paid for
the image. Running the check at the moment the file appears means the failure is
reported next to the thing that failed, while the prompt that produced it is
still on screen and still editable.

That is the reasoning behind the
transparent background generator
on the interface I work on: it runs the alpha check in the browser on the file
that is already there, composites the result over a solid colour, and shows you
that before the download button does anything. It costs nothing per image
because nothing is uploaded and nothing is re-encoded — it is the same
getImageData call as above, run on every result rather than on the ones you
remember to check.

The broader tool is the
GPT Image 2.5 Image Generator, an independent
third-party interface — not affiliated with OpenAI — that prints the model id,
quality tier and size under every result. Same principle as the alpha check:
the things you would otherwise have to take on faith are shown to you instead.

The short version

  • "Transparent background" is a visual convention in the training data, so a
    model can produce the appearance of transparency rather than the thing.
  • Every preview surface renders both cases identically, which is why this
    reaches production more often than it should.
  • The check is one getImageData pass over the alpha byte; the useful check
    is compositing over two solid colours and looking.
  • If any stage of your pipeline emits JPEG, the question is already answered and
    the answer is no.
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23

Sovereign Intelligence: The Complete 25,000 Word Blueprint (Download)

Pocket Portfolio - Apr 1

The Sovereign Vault — A Comprehensive Guide to Protocol-Driven AI

Ken W. Algerverified - Jun 4
chevron_left
156 Points5 Badges
2Posts
0Comments

Related Jobs

View all jobs →

Commenters (This Week)

5 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!