Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PIL: Convert RGB image to a specific 8-bit palette?

Using the Python Imaging Library, I can call

img.convert("P", palette=Image.ADAPTIVE)

or

img.convert("P", palette=Image.WEB)

but is there a way to convert to an arbitrary palette?

p = []
for i in range(0, 256):
    p.append(i, 0, 0)
img.convert("P", palette=p)

where it'll map each pixel to the closest colour found in the image? Or is this supported for Image.WEB and nothing else?

like image 995
mcccclean Avatar asked Jun 25 '10 01:06

mcccclean


2 Answers

While looking through the source code of convert() I saw that it references im.quantize. quantize can take a palette argument. If you provide an Image that has a palette, this function will take that palette and apply it to the image.

Example:

    src = Image.open("sourcefilewithpalette.bmp")
    new = Image.open("unconvertednew24bit.bmp")
    converted = new.quantize(palette=src)
    converted.save("converted.bmp")

The other provided answer didn't work for me (it did some really bad double palette conversion or something,) but this solution did.

like image 88
pictu Avatar answered Nov 16 '22 04:11

pictu


The ImagePalette module docs's first example shows how to attach a palette to an image, but that image must already be of mode "P" or "L". One can, however, adapt the example to convert a full RGB image to a palette of your choice:

from __future__ import division
import Image

palette = []
levels = 8
stepsize = 256 // levels
for i in range(256):
    v = i // stepsize * stepsize
    palette.extend((v, v, v))

assert len(palette) == 768

original_path = 'original.jpg'
original = Image.open(original_path)
converted = Image.new('P', original.size)
converted.putpalette(palette)
converted.paste(original, (0, 0))
converted.show()
like image 3
Mike Boers Avatar answered Nov 16 '22 03:11

Mike Boers