Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create PNG image with color_type=3 and bit_depth=1

The source is an RGBA PNG image (color_type=6 and bit_depth=8).

I need an image with indexed color and 2 palette items (color_type=3, bit_depth=1).

I tried with ImageMagick, but was able to reach only 1bit grayscale image (color_type=0, bit_depth=1) or 2bit indexed color image (color_type=3, bit_depth=2) in which only 2 colors are in use.

According to the PNG specification such image is possible, but how to create it?

Here is an image I am trying to convert:

enter image description here

The result of "convert input.png -type palette -depth 1 output.png":

enter image description here

The result of "convert input.png -type palette -depth 1 -colors 2 output.png"

enter image description here

Both results have bit_depth=2, but the second one uses only 2 colors of 4 possible.

like image 433
johnfound Avatar asked Dec 19 '25 21:12

johnfound


2 Answers

Use one of the following 3, ordered from least to most ancillary tags in the output file:

convert -colors 2 -define png:include-chunk=none -verbose input.png output.png

 

convert -colors 2 -define png:exclude-chunk=bkgd -verbose input.png output.png

 

convert -colors 2 -background #000000 -verbose input.png output.png

The root of this problem is that ImageMagick by default tags the image with a white background color (bKGD) PNG chunk (unnecessarily I'd say), and then adds this color to the palette if it's not already there, even if the image has no pixels of that color. Your particular image doesn't have white after converting to 2-color, so the unneeded background color tag becomes a 3rd color and it can no longer be saved as a 1-bit indexed color image. See also this from the author of IM.

The reason others have failed to reproduce the problem is probably that they've tested with images where one of the 2 colors happened to be white.

The 1st option with -define png:include-chunk=none avoids the problem by not outputting any ancillary PNG chunks at all (e.g. bKGD, gAMA, cHRM, tEXt, tIME). Like pngcrush -rem alla. I'd prefer this for a less cluttered file (without it IM will add a few of these even if they weren't in the input file). Note: There's also the simple -strip option which should avoid most of these, but as of v6.9.3 it won't cut bKGD due to a bug.

The 2nd with -define png:exclude-chunk=bkgd removes only the offending background chunk.

The 3rd option with -background #000000 retains all ancillary PNG chunks including bKGD but sets it black, one of the 2 colors present in your image, so it can still be 1-bit. Adjust the color for an image with neither white nor black in it.

Note that for all these I'm including the -verbose switch. Not overly verbose; just goes from zero to two lines of status output where you'll notice a "2c" if the image stayed 2-color or a "3c" if not. It will also tell you if the palette reduction was lossy or not. It also outputs "8-bit sRGB" for most images, even paletted ones with fewer than 8 bits-per-pixel; that's not a bug as in your comment to another answer @johnfound, this refers not to the bits-per-pixel but to the bits-per-color component. It can be more than 8-bit for (rare) deep color images.

like image 171
WinTakeAll Avatar answered Dec 23 '25 08:12

WinTakeAll


convert input.png -background white -type palette -depth 1 -colors 2 output.png

works for me.

(Why -depth=1 is not enough? No idea.)

BTW, the tweakpng tool is useful for checking this kind of things.

Update: if the images have transparency, you might play safer by removing it explicitly:

convert input.png -background white -flatten -type palette -depth 1 -colors 2 output.png

(You can replace white for your preference)

like image 36
leonbloy Avatar answered Dec 23 '25 06:12

leonbloy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!