Skip to content

Convert image to supported mode before saving #2663

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

Activity

  1. aclark4life commented on Apr 1, 2018

    @aclark4life
    Member

    @homm How about a PR for this?

  2. hugovk commented on Jun 10, 2018

    @hugovk
    Member

    @homm Would you like to have a look at @radarhere's PR #3172?

  3. aclark4life commented on May 11, 2019

    @aclark4life
    Member

    Or alternatively @homm would you look at it even if you wouldn't like to do it? 😄

  4. aclark4life commented on May 11, 2019

    @aclark4life
    Member

    @hugovk @radarhere If you still think this can go in and no objection from @wiredfool or @homm I'd probably just merge it.

  5. homm commented on May 12, 2019

    @homm
    MemberAuthor

    I've reviewed the PR, it is very close to what I meant.

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

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