Convert 32 bit png to 8 bit png with ImageMagick by preserving semi transparent pixels
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:
From left to right:
- Original 32-bit RGBA PNG
- Quantized with
pngquant 256 < input.png > output.png
- Quantized with
convert input.png -colors 255 output.png
* - Quantized with
convert input.png PNG8:output.png
- 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.
Karmar
Updated on June 20, 2020Comments
-
Karmar about 4 years
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
-
Karmar over 11 yearsThank you for the answer. I tried that command, but it doesn't preserve semi transparent pixels.
-
Ilmari Karonen over 11 yearsOh 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.) -
Karmar over 11 yearsYes, 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.
-
Glenn Randers-Pehrson about 7 yearsTry
-colors 255
instead of-colors 256
. ImageMagick needs to reserve one entry for the "background" color. -
Ilmari Karonen about 7 years@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. :)
-
Glenn Randers-Pehrson about 7 years"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.
-
Glenn Randers-Pehrson about 7 yearsImageMagick 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"
-
Ilmari Karonen about 7 years@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.
-
Glenn Randers-Pehrson about 7 yearsSometimes
-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. -
Ilmari Karonen about 7 years@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.)
-
Glenn Randers-Pehrson about 7 yearsIt 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.
-
Ilmari Karonen about 7 years@GlennRanders-Pehrson OK, I guess that makes sense. As to whether
convert -colors 255
looks better with or withoutPNG8:
, well, you can look at the examples above and decide for yourself. To me, they both look pretty bad.