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

Convert image to supported mode before saving #2663

Open
homm opened this issue Aug 9, 2017 · 5 comments · May be fixed by #3172
Open

Convert image to supported mode before saving #2663

homm opened this issue Aug 9, 2017 · 5 comments · May be fixed by #3172

Comments

@homm
Copy link
Member

homm commented Aug 9, 2017

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
@aclark4life
Copy link
Member

@homm How about a PR for this?

@radarhere radarhere linked a pull request Jun 10, 2018 that will close this issue
@hugovk
Copy link
Member

hugovk commented Jun 10, 2018

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

@aclark4life
Copy link
Member

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

@aclark4life
Copy link
Member

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

@homm
Copy link
Member Author

homm commented May 12, 2019

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
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants