Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved ImagePalette #5552

Merged
merged 16 commits into from Jun 28, 2021
Merged

Improved ImagePalette #5552

merged 16 commits into from Jun 28, 2021

Conversation

radarhere
Copy link
Member

@radarhere radarhere commented Jun 23, 2021

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
Copy link
Member Author

radarhere commented Jun 27, 2021

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

Pillow/src/PIL/Image.py

Lines 1012 to 1019 in 52856bc

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

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)
Copy link
Member Author

Choose a reason for hiding this comment

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

Using https://pypi.org/project/apng/ to split Tests/images/apng/mode_palette_alpha.png into frames, this matches the transparent third frame

im_cropped = im_expanded.crop(
(10, 10, im_expanded.width - 10, im_expanded.height - 10)
)
assert_image_equal(im_cropped, im)
Copy link
Member Author

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
Copy link
Member Author

radarhere commented Jun 28, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exception when converting GIF to RGB and saving
2 participants