Convert 32 bit png to 8 bit png with ImageMagick by preserving semi transparent pixels
Asked Answered
B

1

18

I want to convert 32 bit png to 8 bit png with ImageMagick, but semi transparent pixels are lost. How to solve this problem? The command that I am using is the following

convert original.png PNG8:output.png
Barbarian answered 25/12, 2012 at 15:37 Comment(2)
Related: #1468721Shirl
This question is not a duplicate. This poster is complaining of the loss of semi-transparent pixels after conversion from 24-bit to 8-bit. He already has the (correct) syntax for converting from 24-bit to 8-bit, he's wondering why it behaves the way it does (and there's a good answer for that).Ovariectomy
S
24

Apparently, even though the PNG format actually allows any and all of the colors in an 8-bit indexed color PNG to be fully or partially transparent, ImageMagick's "PNG8" format specifier only supports GIF-style 1-bit transparency.

It's possible to produce indexed 8-bit PNGs using ImageMagick by not using the PNG8: specifier, but simply using -colors 256 or -colors 255* to reduce the number of colors in the image. Unfortunately, at least based on my tests using ImageMagick 6.8.9, the resulting images have some rather weird and quite unnecessarily ugly color quantization artifacts.

Fortunately, there's a much better tool for this specific job: pngquant. Using it, converting a 32-bit RGBA PNG into an 8-bit colormapped PNG with minimal quality loss is as easy as:

pngquant 256 < original.png > output.png

As a quick demonstration, here's a simple test picture (a star with a semitransparent drop shadow) converted to 8-bit PNG using various methods:

Original pngquant 256 ImageMagick convert (-colors 255) ImageMagick convert (PNG8) ImageMagick convert (-colors 255, PNG8)

From left to right:

  1. Original 32-bit RGBA PNG
  2. Quantized with pngquant 256 < input.png > output.png
  3. Quantized with convert input.png -colors 255 output.png*
  4. Quantized with convert input.png PNG8:output.png
  5. Quantized with convert input.png -colors 255 PNG8:output.png*

*) In the comments below, it is suggested that -colors 255 is necessary "to reserve one entry for the 'background' color." Based on my testing, I have not observed this to actually be the case; using -colors 256 will still produce an 8-bit colormapped PNG, with quantization artifacts qualitatively similar to, but differing in details from, the output with -colors 255. Nonetheless, just to play it safe, I've used -colors 255 for the examples above. Reducing the colormap size by one color should not, in itself, significantly affect the quality of the results, as a test with pngquant 255 will demonstrate.

Shirl answered 25/12, 2012 at 15:53 Comment(12)
Thank you for the answer. I tried that command, but it doesn't preserve semi transparent pixels.Barbarian
Oh well, it was worth a try. :( (Ps. You did try both of them, right? Someone in the thread I linked to suggested that it's specifically the PNG8: prefix that's breaking the alpha transparency.)Shirl
Yes, I tried both. Second one makes fully transparent pixels black. I started using pngquant command line tool instead of ImageMagick. It preserve alpha channel correctly.Barbarian
Try -colors 255 instead of -colors 256. ImageMagick needs to reserve one entry for the "background" color.Aldine
@GlennRanders-Pehrson: It shouldn't need to do that, since the PNG8 format allows any and all of the 256 colors to be semitransparent. But apparently ImageMagick doesn't support that, and can only output GIF-style 1-bit transparency in colormapped images. Anyway, thanks for prompting me to update this old answer. :)Shirl
"PNG8" wasn't defined by the PNG group. Others have defined it to either mean indexed PNG, or indexed PNG with binary transparency. ImageMagick uses the latter definition.Aldine
ImageMagick does support 8-bit indexed PNGs with semitransparency, but it doesn't call them "PNG8". But whether PNG8 supports semitransparent colors is irrelevant anyhow; the requirement to leave a slot for the background color still holds. Try `convert in.png -colors 255 output.png"Aldine
@GlennRanders-Pehrson: Huh, looks like you're right. The results still look pretty awful, but it does produce an 8-bit PNG with partial transparency.Shirl
Sometimes -colors 256 works; that's when at least one pixel of the background color is present in the main image, and it's therefore not necessary to reserve an extra slot in the palette.Aldine
@GlennRanders-Pehrson I still don't see why that should be necessary, unless it's some weird quirk of ImageMagick. If the input image has no fully transparent pixels, why would we need to reserve a colormap entry for them in the first place? But practically speaking it doesn't seem to matter, since ImageMagick's output looks just as awful either way. (I suspect that must be a bug in ImageMagick, since there's no reason why it should look that bad, no matter what quantization algorithm they're using.)Shirl
It isn't necessary to reserve a background color, but ImageMagick reserves one by default. You can avoid that with "-define png:exclude-chunk=bKGD". The quantization probably looks better with "-colors 255" and not specifying PNG8: (PNG8 uses a quick-and-dirty quantization method that simply zeroes out the lower bits). But, in fact, I prefer to use pngquant rather than ImageMagick for palette-generation.Aldine
@GlennRanders-Pehrson OK, I guess that makes sense. As to whether convert -colors 255 looks better with or without PNG8:, well, you can look at the examples above and decide for yourself. To me, they both look pretty bad.Shirl

© 2022 - 2024 — McMap. All rights reserved.