2

I'm trying to write a python script that takes in standard 24-bit pngs and converts them to 8-bit pngs for better compression. It looks like pypng can do this but I can't quite figure out how to use it. Image manipulation is a new area for me so this may seem silly. I have this currently:

r=png.Reader(<myfile>)
test = r.asRGBA8()

This gives me tuples in return (the layers of the image I believe). However I can't seem to write or save this back to an image. What am I missing? Here's a test image

tsny17
  • 41
  • 1
  • 5

1 Answers1

5

Original Answer

I think this does what you ask:

from PIL import Image

# Load image
im = Image.open('logo.png')                                                                 

# Convert to palette mode and save
im.convert('P').save('result.png')

Updated Answer

I can't find a way to get PIL to make a sensible palette image as a result, but can do it a couple of other ways...

Either with wand like this:

#!/usr/bin/env python3

from wand.image import Image

with Image(filename='logo.png') as img: 
    img.quantize(number_colors=256, colorspace_type='lab', treedepth=0, dither=False, measure_error=False)
    img.save(filename='result.png')

Or, by shelling out to ImageMagick at the command-line and doing:

magick logo.png -colors 255 png8:logo8.png      # use "convert" in place of "magick" if using v6

enter image description here

Newest Answer

Ok, I found a way to get PIL/Pillow to do a better job, and as expected, it makes use of libimagequant which is not normally built into Pillow (at least on macOS where I am). The code looks like this:

#!/usr/bin/env python3

from PIL import Image

# Load image
im = Image.open('logo.png')                                                                 

# Convert to palette mode and save. Method 3 is "libimagequant"
im.quantize(colors=256, method=3).save('result.png')

The steps, on macOS to build PIL/Pillow with libimagequant are as follows - they will differ on other platforms but you should be able to get the general idea and adapt:

pip uninstall pillow           # remove existing package
brew install libimagequant
brew install zlib
export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig"
pip install --upgrade Pillow --global-option="build_ext" --global-option="--enable-imagequant" --global-option="--enable-zlib"

Keywords: Python, image processing, PIL/Pillow, libimagequant, macOS, quantise, quantize.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • This works great! Only problem I'm having now is that gradients don't work well in the 8 bit "Palette" mode. Is there a workaround for this or is the best way to go just figuring out if an image has gradients beforehand somehow? – tsny17 May 24 '20 at 15:17
  • Gradients rarely work well in palette mode and normally exhibit *"banding"*... https://en.m.wikipedia.org/wiki/Colour_banding Maybe you can share a representative image to try some things on. – Mark Setchell May 24 '20 at 15:20
  • Banding is definitely what I'm seeing. Thanks for the article, I learned quite a bit! I changed the image in my initial question to a logo png with transparency and a gradient that displays the banding when put into palette mode. Any help would be greatly appreciated, as is all you've done so far. Perhaps I need to do some dithering on the image? – tsny17 May 25 '20 at 22:36
  • I have updated my answer, please have another look. – Mark Setchell May 26 '20 at 09:23
  • And once more - which will hopefully be even better for you as you normally use Pillow. – Mark Setchell May 26 '20 at 12:41
  • How would I push the PIL implementation a little further? I'm attempting to write this myself instead of pay for a product I don't use enough to justify it -- this code works well but is consistently a few % behind what can be achieved with the other product. Can I change the quality level somehow? The quality flag in save() doesn't seem to have any effect with this implementation. – tsny17 Jun 13 '20 at 15:25