Skip to content

Convert image to supported mode before saving #2663

@homm

Description

@homm

We need explicit method to automatically convert image to one of the supported modes for saving formats. Affects #2609 and others. Maybe it should be part of ImagePlugins.

This is a good start point:

def fix_mode(image, new_format, fill_color='white'):
    old_mode = image.mode

    if old_mode in ('RGBA', 'LA') and new_format == 'GIF':
        alpha = image.getchannel('A')
        # Convert the image into P mode but only use 255 colors
        # in the palette out of 256.
        image = image.convert(old_mode[:-1]) \
            .convert('P', palette=Image.ADAPTIVE, colors=255)
        # Set all pixel values below 128 to 255, and the rest to 0.
        mask = Image.eval(alpha, lambda px: 255 if px < 128 else 0)
        # Paste the color of index 255 and use alpha as a mask.
        image.paste(255, mask)
        # The transparency index is 255.
        image.info['transparency'] = 255
        return image

    if old_mode == 'CMYK' and new_format in ('PNG', 'WEBP', 'GIF'):
        return image.convert('RGB')

    if old_mode == 'I' and new_format in ('JPEG', 'GIF', 'WEBP'):
        image = image.point([i//256 for i in range(65536)], 'L')
        old_mode = image.mode

    if old_mode == 'P' and new_format in ('JPEG', 'WEBP'):
        # PIL loses palette attribute during crop. So we use low-level api.
        alpha = 'A' in image.im.getpalettemode()
        image = image.convert('RGBA' if alpha else 'RGB')
        old_mode = image.mode

    if old_mode in ('RGBA', 'LA') and new_format == 'JPEG':
        background = Image.new(old_mode[:-1], image.size, fill_color)
        background.paste(image, image.getchannel('A'))
        image = background
        old_mode = image.mode

    # Pillow doesn't support L modes for webp for now.
    if old_mode in ('L', 'LA') and new_format == 'WEBP':
        image = image.convert('RGB' + old_mode[1:])
        old_mode = image.mode

    return image

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions