Why does a transparent PNG turn black as a JPG?...

Why does a transparent PNG turn black as a JPG? The colour hiding underneath

By SJ
8 min read
Four teal circles on a transparent background, above the same image converted to JPG with Pillow, where the strips behind them came out magenta, white, black and black.
On this page

We made an 800x400 test PNG with four strips that look alike: the same teal circle on a transparent background, four times over (the fourth with a soft shadow). Then we turned it into a JPG with Pillow, Python's imaging library, using its convert("RGB"). The four strips came back magenta, white, black and black.

Nothing was added. Those colours were already in the PNG, sitting under the transparency.

A JPG can't store transparency, so whatever writes it has to put something behind the picture. Some tools paint white. Some just reveal the colour stored under the transparent pixels, which is often black. And Chrome's canvas, the drawing surface web pages use to edit images, paints black whatever was there, because the HTML standard says it must. If you want white, or any other colour, you have to choose it before the JPG is written. Iminify's JPG output puts white behind the picture, and PNG to WebP keeps the transparency instead.

A transparent pixel still has a colour

Each pixel of a transparent PNG has a colour (red, green and blue, or a grey level) and an alpha value that says how opaque it is. Alpha zero is fully transparent. The PNG specification keeps the colour separate from the alpha ("The color values in a pixel are not premultiplied by the alpha value"), so a fully transparent pixel still has a colour. You never see it while the transparency is there.

The specification names two cases. If the alpha is a mask, "the color values of fully transparent pixels should be preserved for future use". If it only cuts out a shape, "fully transparent pixels should all be assigned the same color value for best compression". It also asks that "the colors assigned to transparent pixels should be reasonable background colors whenever feasible".

Black is the most common choice in the files we sampled. We downloaded 213 PNGs uploaded to Wikimedia Commons on 30 and 31 October 2026, one per uploader, and 62 of them had fully transparent pixels: 32 stored black under every one, 10 white, 3 one dark green, (71, 112, 76), and 17 a mix or another colour. The app icon from our test images, a 1600-pixel PNG, has 237,689 fully transparent pixels, and every one of them is black.

What each PNG-to-JPG converter puts behind the picture

We made JPGs from the test PNG with five converters. Strips one to four hide magenta, white, black and black; strip four also has a soft drop shadow made of semi-transparent black pixels.

Converter, as we ran it What filled the transparent area The soft shadow
Pillow 11.1.0, convert("RGB"), then save as JPG the hidden colour: magenta, white, black, black solid black
Pillow, saving the PNG straight to JPG nothing: OSError: cannot write mode RGBA as JPEG
ImageMagick 7.1.1-43, magick in.png out.jpg the hidden colour (the same file as -alpha off) solid black
ImageMagick, -background white -flatten white light grey
PHP 8.3 with its bundled GD, imagejpeg() after imagecreatefrompng() the hidden colour solid black
Chrome 156, canvas toBlob(callback, "image/jpeg") black in all four strips solid black
Iminify, JPG output at its Smart or Lossless level white light grey

So "just save it as a JPG" often doesn't choose a background at all. Pillow's convert("RGB"), ImageMagick's default and GD's imagejpeg() threw the alpha away and kept each pixel's own colour.

Chrome works differently. Drawing the PNG onto a canvas wiped the hidden colours (reading the pixels back gave 0, 0, 0, 0 at each strip's corner), and then the HTML standard takes over: "For image types that do not support an alpha component, the serialized image must be the bitmap image composited onto an opaque black background". A web page that converts your file on a canvas without painting a background first hands you black, at least in Chrome 156, the browser we tested.

The shadow shows a second problem. Its pixels are black and only their alpha made them faint, so dropping the alpha turned a soft shadow into a solid black blob. Composited onto white, the same pixels came out light grey (183 out of 255 where we measured it).

Compressing first can change the colour you get later

The hidden colour can also change before any JPG is made. Some encoders treat it as free space. cwebp's documentation says so plainly: in lossless mode "the invisible pixel values (R/G/B or Y/U/V) will be preserved only if the -exact option is used", and -exact is off by default "to help compressibility".

We encoded the test PNG with several tools, then dropped the alpha from each result to see what it was hiding:

Six panels of the same test PNG: as a viewer shows it, four teal circles on a checkerboard; with its alpha dropped, strips of magenta, white, black and black; after cwebp's default lossy WebP, mostly magenta blocks; after cwebp -lossless, teal smears and black; after pngquant, dark green with a black ring where the shadow was; after Iminify's Smart WebP, black.

  • cwebp 1.5.0 at its default (lossy) filled most of the transparent area with blocks of magenta, across all four strips.
  • cwebp -lossless left teal smears beside the circles and black elsewhere. Adding -exact kept the original colours.
  • pngquant 2.18.0 set every fully transparent pixel to one dark green (71, 112, 76).
  • avifenc 1.2.1 with --lossless, zopflipng 1.0.3 and optipng 0.7.8 kept the colours as they were.

Iminify's Smart WebP of the test PNG held black under all but 24 of its 239,752 fully transparent pixels, and its Smart PNG, which goes through pngquant, held the same dark green. Neither shows while the transparency is there. But a tool that later drops the alpha will give you black, or green.

Choose the JPG's background yourself

  1. Keep the transparency if you can. If the place you're uploading to takes PNG, WebP or AVIF, don't convert to JPG at all. PNG to WebP keeps the alpha channel.
  2. If it has to be a JPG, flatten onto a colour first. Iminify's JPG output puts white behind the picture (as our PNG to WebP post shows).
  3. For any other colour, do the flattening in your own tool. ImageMagick does it in one command (swap white for a value such as "#f4efe6"):
magick logo.png -background white -flatten logo.jpg

That's ImageMagick 7; version 6 calls the command convert. In Python, composite the image onto a solid background before the conversion:

from PIL import Image

im = Image.open("logo.png").convert("RGBA")
background = Image.new("RGBA", im.size, (255, 255, 255, 255))
Image.alpha_composite(background, im).convert("RGB").save("logo.jpg", quality=90)

Both gave us white where the transparency was and a light grey shadow. In a browser, set fillStyle to white and fillRect the canvas before drawImage; that gave us white too. In PHP, imagefill() an imagecreatetruecolor() canvas with white and imagecopy() the PNG onto it before imagejpeg().

  1. If the JPG already came out black, go back to the PNG. The transparency is gone from the JPG, and Iminify can't remove a background to bring it back.

Black after an upload, or only in some apps?

Not every report is about a conversion you ran yourself. In a Shopify Community thread from October 2023, someone working on a store reported that "approx 1 in 10" of their transparent PNGs came back with a black background after being saved to the store, and suspected "a transformation designated by the Shopify CDN". Nobody in the thread confirmed it, and we didn't test Shopify. If your uploads come back black, flattening the image onto your own background first (steps 2 and 3 above) leaves the site no transparency to lose.

Others describe a PNG that is still transparent but looks black in certain programs. In a Microsoft Community Hub thread from August 2023, designs looked black in Affinity Designer, GIMP, Inkscape and Windows Explorer, "but when opened they have a transparent background", and two replies say moving the files off OneDrive to a local drive fixed it. When a file shows its transparency anywhere, the transparency is in the file and the black comes from how it's being displayed. We didn't test those programs.

How we tested

On 31 October 2026 we built the 800x400 test PNG with Pillow and numpy and ran Pillow 11.1.0, ImageMagick 7.1.1-43, cwebp 1.5.0, pngquant 2.18.0, zopflipng 1.0.3, optipng 0.7.8 and avifenc 1.2.1 in one Docker image, PHP 8.3.36 with its bundled GD in the official WordPress 7.1.3 image, and headless Chrome 156 through its DevTools protocol. Iminify's results came from its API, which gives the same results as the website at the same settings. We read the colour under every fully transparent pixel with numpy, and the JPGs at a 30-pixel patch in each strip's corner and a 10-pixel patch of the shadow. The Commons sample was the newest uploads the Commons API listed, PNGs of at most 400,000 bytes and 2,000 pixels a side, one per uploader.

Questions this post answers

Share this post

Share on X
Share on Facebook
Share on LinkedIn
Share on Reddit
Share on Hacker News
Email
Copy link
Link copied
Ten squares: 4 filled for tools that kept the IPTC AI tag at their defaults, 6 hollow for tools that dropped it, beside the title Does compression remove the AI tag?

Does compression remove the AI tag Merchant Center asks for? 10 tools, WordPress and Iminify tested

Google's Merchant Center help says: "Don't remove embedded metadata tags such as trainedAlgorithmicMedia from such images. All AI-generated images must contain the IPTC DigitalSourceType trainedAlgorithmicMedia tag." (Merchant Center's help page is dated February 2024; we read it on 26 October 2026.) So we put that tag on two AI images, a harbour scene from Nano Banana 2 (a JPEG) and a bakery illustration from the original Nano Banana (a PNG), ran them through 42 command-line runs and Iminify, added three larger JPEGs for a WordPress 7.1.3 site, and read the tag back with ExifTool each time. Each tool's default decides whether the tag survives, and neither lossy nor lossless predicts it. Of the ten tools in our table, four keep the tag at their defaults and six drop it, and for nine of them we found an option that flips that. Iminify, which is our product, lost it at every level that compresses: it survived in 6 of 51 uploads, and those six came back byte for byte unchanged. One ExifTool command puts the tag back for 514 to 568 bytes and, on the nine files we checked, leaves every pixel alone.

8 min read
Two cards for the same photograph: the JPEG saved at quality 80, 449 KB, score 75.6, and the WebP made from it at quality 90, 531 KB, score 71.3.

Why is my WebP bigger than the JPG? Measured on 40 JPEGs and 4 PNGs

One photograph of our corpus, the Fjord, saved as a JPEG at quality 80 weighed 449,258 bytes. Converted to WebP at quality 90, it weighed 531,474, which is 18% more. Scored against the corpus master it came from (a JPEG saved at quality 92), the bigger file was also the worse picture: 71.3 on SSIMULACRA 2, a score where higher means closer to the master, against 75.6 for the JPEG. Google's WebP FAQ says a WebP can grow larger than its source and names three situations. We measured each on five photographs and four graphics. A WebP comes out bigger when its quality is set too high for the JPEG it came from, when it is lossless, or when a PNG already squeezed to 256 colours goes to lossy WebP. A fourth cause, which the FAQ doesn't list, is that WebP isn't always smaller than a good JPEG even at the same score. Whichever it is, keep the smaller file when the two look alike.

7 min read
Two cards under the title "Do AI images hurt SEO? The file can.": a Gemini 2K picture as delivered, 3.95 MB, largest paint 20.3 s; the same picture resized to 720 wide, 104 KB, 1.4 s, in Lighthouse's mobile test.

Do AI images hurt SEO? What Google's pages say, and what a 2K Gemini picture did to a page

We put Gemini pictures on a plain article page, one size at a time, and ran Lighthouse's mobile test on each. Straight from the generator, the 1K file (1.06 MB) took 6.2 seconds to become the page's largest paint (LCP), the 2K file (3.95 MB) took 20.3 seconds and the 4K file (10.51 MB) took 52.4 seconds. Google's target for that metric is 2.5 seconds. Do AI images hurt SEO? In the Google pages we read, nothing marks an image down for being AI-made. The file is another matter: the same 2K picture, resized and compressed to 104 KB, took 1.4 seconds. Iminify's compressor also drops the C2PA manifest that marks a Gemini file as AI-made, and Google's Merchant Center asks sellers to keep an IPTC tag that says the same.

8 min read

Try it on your own images

Drop a photograph in, pick Smart, and compare the result with the original before you download. Free, no account needed.