Search code examples
imagemagickimagemagick-convert

How to convert PNG images (specifically grayscale ones) to Indexed color


I'm trying to convert some small PNG images from 32-bit color mode to indexed color mode.

For color images, I ran the command convert IMGS/FLAME.png INDEXED_IMGS/FLAME.png and it converted fine. For an image that had only grayscale colors, I ran that same command (with the filename changed obviously) but I got a warning:

convert: profile 'icc': 'RGB ': RGB color space not permitted on grayscale PNG 'INDEXED_IMGS/SHADOW.png' @ warning/png.c/MagickPNGWarningHandler/1748.

I ran file IMGS/*.pngand got

IMGS/FLAME.png:  PNG image data, 16 x 16, 8-bit/color RGBA, non-interlaced
IMGS/SHADOW.png: PNG image data, 8 x 8, 8-bit/color RGBA, non-interlaced

which is expected; both images are in 8-bit RGBA mode (since that's the mode I created them in Photoshop). However, when I run file INDEXED_IMGS/*.png I get

INDEXED_IMGS/FLAME.png:  PNG image data, 16 x 16, 4-bit colormap, non-interlaced
INDEXED_IMGS/SHADOW.png: PNG image data, 8 x 8, 8-bit grayscale, non-interlaced

The 4-bit colormap part checks out, but the grayscale part does not.

 

So my question is: how can I convert a grayscale image to indexed mode? What really gets me is that it starts out in RGBA mode like the color image, but for some reason it converts automatically to grayscale mode. Is there a way to prevent it from doing that?

 

I should add that I have a bash script that looks like this:

#!/bin/bash

for img in IMGS/*.png; do
    file=$(basename $img)
    convert $img INDEXED_IMGS/$file
done

so I don't wanna manually distinguish between grayscale and colored images. If there's a way to do so automatically with some command that's fine though.

Here is info about my ImageMagick tool:

Version: ImageMagick 7.0.8-42 Q16 x86_64 2019-04-24 https://imagemagick.org
Copyright: © 1999-2019 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP 
Delegates (built-in): bzlib freetype heic jng jp2 jpeg lcms ltdl lzma openexr png tiff webp xml zlib

Solution

  • With ImageMagick, for 24-bit color, append the output with PNG8:output

    convert input.png PNG8:output.png
    


    PNG grayscale images do not support color profiles, so you get that warning. But the resulting image should be 8-bit palette.

    If you have 32-bit color, then this needs more to be done. The color under the alpha channel must be one constant color and one not used elsewhere in the image. Find such a color after converting to 256 colors and set the color under the transparency to that color. For example if you have no opaque black in your image after converting to 256 colors, then set the alpha base color to black.

    convert image.png +dither -colors 256 -background black -alpha background PNG8:output.png
    


    You can get a list of unique colors from the image as follows:

    convert image.png +dither -colors 256 -unique-colors txt:
    


    Here is an example:

    enter image description here

    Make it 32-bit transparent:

    convert rose.png -fuzz 20% -transparent red rose_trans32.png
    
    identify -verbose rose_trans32.png
    ...
     Colorspace: sRGB
     Type: TrueColorAlpha
    ...
    


    enter image description here

    Convert to palette alpha:

    convert rose_trans32.png -alpha off +dither -colors 256 -unique-colors txt:
    
    List shows no black
    
    convert rose_trans32.png +dither -colors 256 -background black -alpha background PNG8:rose_trans8.png
    
    Or if you already know that the 32-bit version has not black, then just:
    
    convert rose_trans32.png -background black -alpha background PNG8:rose_trans8.png
    
    identify -verbose rose_trans8.png
    ...
      Colorspace: sRGB
      Type: PaletteAlpha
    ...
    


    enter image description here

    If you do this adding -colorspace gray, ImageMagick will still report as type grayscalealpha, since it recognizes it as a single channel image with transparency. But using EXIFTOOL, it will report 9 ColorType: 3, which is 3 = RGB Palette

    NOTE: For ImageMagick 7, change convert to magick.