inky icon indicating copy to clipboard operation
inky copied to clipboard

Image palette is ignored

Open RubenLagrouw opened this issue 6 years ago • 5 comments

All input images are interpreted as having a white-black-red palette. Unfortunately lots of software does not let you choose the palette order.

I worked around it like this, but it would be nicer to honor the palette instead. (Of course red should be yellow if you have the yellow version...)

img = Image.open("temp.png")
cR = [255, 0, 0]
cB = [0, 0, 0]
cW = [255, 255, 255]

palette_old = img.getpalette()

p_conv = {0: palette_old[0:3],
        1: palette_old[3:6],
        2: palette_old[6:9]}

# p_target = {0: cW,
#             1: cB,
#             2: cR}

new_pixdata = []
old_pixdata = img.getdata()
for pix in old_pixdata:
    if pix not in p_conv:
        print('Pixel out of range: {}'.format(pix))
        new_pixdata.append(0)
    elif p_conv[pix] == cW:
        new_pixdata.append(0)
    elif p_conv[pix] == cB:
        new_pixdata.append(1)
    elif p_conv[pix] == cR:
        new_pixdata.append(2)

img.putdata(new_pixdata)
img.putpalette(cW + cB + cR)  # Goal palette

RubenLagrouw avatar Dec 14 '18 10:12 RubenLagrouw

I just ran into this with my own B&W inkypHAT. Here's what I'm using to take an arbitrary image and convert it to black or white pixels based on a threshold.

def reindex_image (other):
  rgb_im = other.convert('RGB')
  img = Image.new("P", (inky_display.WIDTH, inky_display.HEIGHT))
  for x in range(inky_display.WIDTH):
    for y in range(inky_display.HEIGHT):
      (r, g, b) = rgb_im.getpixel((x, y))
      color = inky_display.WHITE if r > 127 else inky_display.BLACK
      img.putpixel((x, y), color)
  return img

# Read your indexed PNG image ...
img = Image.open("foo.png")

# Reindex into black and white colors
img = reindex_image(img)

# buffer & show
inky_dispay.set_image(img)
inky_display.show()

mattdesl avatar Dec 17 '18 00:12 mattdesl

We should probably whip up an example with this approach, or perhaps build it in. I'm conflicted!

I was deliberately trying to make Inky image-library-agnostic, but that does make it difficult to re-introduce features such as palette-order.

Right now converting the image with PIL before displaying it on Inky is the "right" approach, but I'm not convinced it's the best.

Gadgetoid avatar Dec 21 '18 21:12 Gadgetoid

I cannot do the conversion with PIL because it cannot handle my input images. Since i'm using imagemagick for conversion anyway, i can just as well do everything there. Except palette order, unfortunately. My workaround works for me, i hope it is useful for someone else too 😁

RubenLagrouw avatar Dec 21 '18 21:12 RubenLagrouw

The old inky-phat library had a colswap parameter in set_image that could be used to swap colors (see here). Of course, this does not really help honor the palette, but would make it easier to manually reorder the colors. IMO, reintroducing the colswap functionality would not conflict with the aim to make inky image-library-agnostic.

aghster avatar May 31 '20 19:05 aghster

This caused me a bit of trouble since I was trying to load PNGs and didn't have a good way to change the palette ordering. I made a python script to convert a PNG to the correct Black/White/Red colors for the 3 color display. I figured I'd share to save anyone else the trouble:

from PIL import Image

source = "old.png"
destination = "new.png"

# Open source file
oldimage = Image.open(source)

# Create palette.  Must contain 768 integer values
palettedata = [
    255, 255, 255,
    0, 0, 0,
    255, 0, 0
    ]
palettedata += [0] * (768 - len(palettedata))

# Create palette image
palimage = Image.new('P', (1, 1))
palimage.putpalette(palettedata)

# Quantize (change to dither=1 if you want dithering)
newimage = oldimage.quantize(palette=palimage, dither=0) 

# Save
newimage.save(destination, "PNG")

rferrese avatar Dec 10 '20 06:12 rferrese