Improved ImagePalette by radarhere · Pull Request #5552 · python-pillow/Pillow

@radarhere

This PR has several changes

  • the ImagePalette colors dictionary is currently empty when the object is created, rather than being filled with palette entries. This fixes that
  • it changes the palette to be empty by default. This means that new colors can be appended more easily, rather than finding that all 256 entries are already occupied
  • if a new color is added when 256 entries are taken, search through the image. If there is a palette index that isn't actually used, use that for the new color
  • helps ImageOps.expand distorts image and converts png to grayscale #5375 by determining the border palette index on the new image only after the palette has been attached

Edit: Thanks to later commits, resolves #2803

@radarhere

@radarhere

@radarhere

@radarhere

@radarhere

… color for background or transparency

@radarhere

@radarhere

@radarhere

@radarhere

@radarhere

@radarhere

I've pushed another commit to not use ImagePalette.raw in convert. Since this code -

new.palette = ImagePalette.raw("RGB", new.im.getpalette("RGB"))
if delete_trns:
# This could possibly happen if we requantize to fewer colors.
# The transparency would be totally off in that case.
del new.info["transparency"]
if trns is not None:
try:
new.info["transparency"] = new.palette.getcolor(trns)

is currently always going to raise a ValueError.

def raw(rawmode, data):
palette = ImagePalette()
palette.rawmode = rawmode
def getcolor(self, color):
"""Given an rgb tuple, allocate palette entry.
.. warning:: This method is experimental.
"""
if self.rawmode:
raise ValueError("palette contains raw palette data")

This fixes the UserWarning in #2803

@radarhere

@radarhere

radarhere

assert im.getpixel((0, 0)) == (0, 255, 0, 255)
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
assert im.getpixel((0, 0)) == (255, 0, 0, 0)
assert im.getpixel((64, 32)) == (255, 0, 0, 0)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

radarhere

im_cropped = im_expanded.crop(
(10, 10, im_expanded.width - 10, im_expanded.height - 10)
)
assert_image_equal(im_cropped, im)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expanding the test from #5551, bringing it closer to #5375

@radarhere

I've now pushed a commit, 'Fixed reloading palette'. It allows this code to work.

from PIL import Image
im = Image.open("Tests/images/hopper.gif")
im.load()
im.palette.dirty = 1
im.save("out.png")

In master at the moment, it produces this broken output.
out

And with the addition of that change, this PR now resolves #2803

This was referenced

Jun 29, 2021

This was referenced

Jul 26, 2021

This was referenced

Oct 4, 2022