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

Image.save(append_images) cropping using bg color instead of alpha #7207

Closed
viotalJiplk opened this issue Jun 10, 2023 · 4 comments · Fixed by #7123
Closed

Image.save(append_images) cropping using bg color instead of alpha #7207

viotalJiplk opened this issue Jun 10, 2023 · 4 comments · Fixed by #7123
Labels

Comments

@viotalJiplk
Copy link

viotalJiplk commented Jun 10, 2023

What did you do?

I used Image.save(append_images=[]) to generate gif but it cropped part of the image (got boundary box of the image wrong). It throws away alpha when preparing to add image and then it relies only on bg color, which does not work when the image has the same color as background.

What are your OS, Python and Pillow versions?

  • OS: Linux (Debian GNU/Linux 12 (bookworm) x86_64)
  • Python: 3.11.2
  • Pillow: 9.5.0

code:

from PIL import Image, ImageDraw

with Image.open('testin3.png') as avatar:
    frames = []
    deformWidth = [-1, -2]
    deformHeight = [4, 3]
    width, height = 80, 80
    x, y = 112, 122

    for i in range(2):
        frame = Image.new("RGBA", (x, y), (0, 0, 0, 0))
        width = width - deformWidth[i]
        height = height - deformHeight[i]
        avatar = avatar.resize((width, height))
        avatar = avatar.convert("P", palette=Image.ADAPTIVE, colors=200).convert("RGBA")

        frame.paste(avatar, (x - width, y - height), avatar)
        frames.append(frame)

    frames[0].save(
        "testout.gif",
        save_all=True,
        append_images=frames[1:],
        duration=400,
        loop=0,
        transparency=0,
        disposal=2,
        optimize=False
    )

testin3.png: testin3

testout.gif: testout

It could be solved by this.

@radarhere radarhere changed the title Image.save(append_images) croping using bg color instead of alpha. Image.save(append_images) croping using bg color instead of alpha Jun 10, 2023
@radarhere radarhere added the GIF label Jun 10, 2023
@radarhere radarhere changed the title Image.save(append_images) croping using bg color instead of alpha Image.save(append_images) cropping using bg color instead of alpha Jun 10, 2023
@radarhere
Copy link
Member

I find that if I remove transparency=0 from your code, I get the following as the final image.

testout

@viotalJiplk
Copy link
Author

viotalJiplk commented Jun 10, 2023

sorry I oversimplified it:

from PIL import Image, ImageDraw

def square_to_circle(image: Image.Image) -> Image.Image:
        width, height = image.size
        mask = Image.new("L", (width, height), 0)
        draw = ImageDraw.Draw(mask)
        draw.ellipse((0, 0, width, height), fill=255)
        alpha = image.getchannel("A")
        circle_alpha = Image.new("L", (width, height), 0)
        circle_alpha.paste(alpha, mask=mask)
        result = Image.new("RGBA", (width, height), (0, 0, 0, 0))
        result.paste(image, (0, 0), mask=circle_alpha)
        return result

with Image.open('testin3.png') as avatar:
    avatar = square_to_circle(avatar)
    frames = []
    deformWidth = [-1, -2, 1, 2, 1]
    deformHeight = [4, 3, 1, 1, -4]
    width, height = 80, 80
    x, y = 112, 122

    for i in range(5):
        frame = Image.new("RGBA", (x, y), (0, 0, 0, 0))
        width = width - deformWidth[i]
        height = height - deformHeight[i]
        avatar = avatar.resize((width, height))
        avatar = avatar.convert("P", palette=Image.ADAPTIVE, colors=200).convert("RGBA")

        frame.paste(avatar, (x - width, y - height), avatar)
        frames.append(frame)

    frames[0].save(
        "testout.gif",
        save_all=True,
        append_images=frames[1:],
        duration=400,
        loop=0,
        disposal=2,
        optimize=False
    )

testout

@radarhere
Copy link
Member

Thanks.

I think you're correct about the change that needs to be made, although obviously applied to GifImagePlugin, rather than ApngImagePlugin. I will probably prepare a commit for that in the next day or so.

If you'd like an immediate solution, you could just change the background color to avoid black transparency, so that it is not confused with the black circle - frame = Image.new("RGBA", (x, y), (100, 0, 0, 0))

@radarhere
Copy link
Member

Ok, I've added a commit to #7123 to resolve this.

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 a pull request may close this issue.

2 participants