Visitar URL original
GIF - use single colour table for all frames · Issue #3788 · python-pillow/Pillow · GitHub
Skip to content

GIF - use single colour table for all frames #3788

Closed

Description

@Gadgetoid

What did you do?

Attempted to normalise a sequence of P images to use the same colour palette in an attempt to output a smaller GIF file that uses a common palette across all frames.

The complete code is here - https://github.com/pimoroni/mlx90640-library/blob/master/python/rgb-to-gif.py - but the relevant snippet can be found below:

    if len(frames) > 1:
        # Generate an image with all frames, and crunch it to ADAPTIVE to form a master colour palette
        master = Image.new('RGB', (32, 24 * len(frames)))
        for index, image in enumerate(frames):
            master.paste(image, (0, 24 * index))
        master = master.convert('P', dither=False, palette=Image.ADAPTIVE, colors=256)

        for index, image in enumerate(frames):
            image = image.convert('P', dither=False, palette=master.palette)
            # image = image.quantize(method=3, palette=master)
            image = image.transpose(Image.ROTATE_270).transpose(Image.FLIP_LEFT_RIGHT)
            image = image.resize(OUTPUT_SIZE, Image.NEAREST)
            frames[index] = image

        filename = 'mlx90640-{}.gif'.format(
            datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))
print("Saving {} with {} frames.".format(filename, len(frames)))

        frames[0].save(
            filename,
            save_all=True,
            append_images=frames[1:],
            duration=1000 // fps,
            loop=0,
            include_color_table=True,
            optimize=True,
palette=master.palette.getdata())

What did you expect to happen?

For the GIF format save method to understand that I was sharing a colour palette across frames, and export accordingly. There doesn't seem to be a way - that I can identify - to communicate this.

What actually happened?

Result a ~1.19MiB GIF:

mlx90640-2019-04-11-16-34-25

Versus a ~263.4KiB GIF - This is a ~70-80% size saving just running the result through ezgif (https://ezgif.com/optimize) optimisation and picking "Use single color table for all frames":

ezgif-4-917f7c76321e

Unless I am very much misunderstanding what ezgif is doing in this case, no other optimisation was performed.

What are your OS, Python and Pillow versions?

  • OS: Linux, Raspbia
  • Python: 3.4.9
  • Pillow: PIL.PILLOW_VERSION == 5.4.1

Activity

  1. radarhere commented on Jul 1, 2021

    @radarhere
    Member

    Taking your 1.2mb image, and running

    from PIL import Image
    im = Image.open('input.gif')
    im.save('output.gif', save_all=True)

    Before #5291, the output is 1.3mb. After, it is 320kb.

    So we're not using a single color table yet, but that is a step towards solving your underlying problem.

  2. radarhere commented on Jul 11, 2021

    @radarhere
    Member

    I've created #5603 to resolve this. With it, this code produces a 281kb file, down from the 320kb file from the code in my last post.

    from PIL import Image, ImagePalette, ImageSequence
    
    with Image.open("input.gif") as im:
    	# Construct a palette with all colors from the image
    	palette = ImagePalette.ImagePalette()
    	for frame in ImageSequence.Iterator(im):
    		for i, count in enumerate(frame.histogram()):
    			if count:
    				color = tuple(frame.palette.palette[i * 3 : i * 3 + 3])
    				palette.getcolor(color)
    	
    	# Save, using that palette for all frames
    	im.save("output.gif", save_all=True, palette=palette.palette)
  3. Gadgetoid commented on Jul 11, 2021

    @Gadgetoid
    Author

    That's mighty close to the output I got above, and a considerable size reduction! Amazing. Thank you for taking the time to do this- it would have taken me forever just to figure out how to figure out how.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions