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

[Bug]: Background of rotated png is rendered black #29300

Open
maederan201 opened this issue Dec 13, 2024 · 10 comments
Open

[Bug]: Background of rotated png is rendered black #29300

maederan201 opened this issue Dec 13, 2024 · 10 comments

Comments

@maederan201
Copy link

Bug summary

If I rotate an image, the background of its bounding box is rendered black when rendering as .pdf or .png

Code for reproduction

import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
from PIL import Image

mirror_icon = Image.open("mirror.png")

tr_rotate = Affine2D().rotate_deg_around(0 / 2, 0 / 2, 45)
tr_translate = Affine2D().translate(250, 250)

fig, ax = plt.subplots()

ax.imshow(
    mirror_icon,
    transform=tr_rotate + ax.transData,
    clip_on=False,
)

ax.imshow(
    mirror_icon,
    transform=tr_translate + ax.transData,
    clip_on=False,
)

ax.set_xlim(-1000, 1000)
ax.set_ylim(-1000, 1000)

fig.savefig("MWE.pdf")

Actual outcome

MWE

Expected outcome

Transparent Bounding Box

Additional information

In the past this was possible, however I don't know which version of matplotlib was used...

Operating system

KDE Neon

Matplotlib Version

3.9.2

Matplotlib Backend

tkagg

Python version

3.12.3

Jupyter version

No response

Installation

pip

@maederan201
Copy link
Author

I should have done some more due diligence, the problem is resolved if interpolation='none' is passed to imshow.

So is this expected behavior of the interpolation or still a bug that should be fixed?

@tacaswell
Copy link
Member

I think we should understand how why this is happening before we decide if it is a bug or a feature ;)

@Shivangbijalwan
Copy link

Shivangbijalwan commented Dec 17, 2024

you can change the colour of the background convert the mirror icon to RGBA

import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
from PIL import Image

# Load the image and convert to RGBA to handle transparency
mirror_icon = Image.open("mirror.png").convert("RGBA")

# Define transformations
tr_rotate = Affine2D().rotate_deg_around(0, 0, 45)  # Rotate around (0,0)
tr_translate = Affine2D().translate(250, 250)  # Translate by (250, 250)

fig, ax = plt.subplots()

# Display the rotated image with proper alpha handling
ax.imshow(
    mirror_icon,
    transform=tr_rotate + ax.transData,
    clip_on=False,
    alpha=1.0  # Ensures transparency is respected
)

# Display the translated image
ax.imshow(
    mirror_icon,
    transform=tr_translate + ax.transData,
    clip_on=False,
    alpha=1.0
)

# Set limits for clarity
ax.set_xlim(-1000, 1000)
ax.set_ylim(-1000, 1000)

# Remove axis for a clean output
ax.axis('off')

# Save to file
fig.savefig("MWE.pdf", transparent=True)  # Save with transparency
plt.show()

(Edit: code formatted)

@maederan201
Copy link
Author

@Shivangbijalwan This works as well. I also tested it with a different .png image, which has some transparent sections already, and there this happens. I think this is also dependent on the image type, however this is sort of beyond my capabilities.
Too me it still seems like unwanted behaviour, but the workaround(s) here are easy enough to solve the issue that it might be ok...

@tacaswell
Copy link
Member

What version of pillow do you have installed?

@tacaswell
Copy link
Member

@Shivangbijalwan Can you explain a bit why changing the loading image to RGBA works?

@Shivangbijalwan
Copy link

@tacaswell Changing the loding image to RGBA works .....................
When you load an image using Pillow (Image.open()), its format depends on the file type, such as P (palette-based) or LA (luminance-alpha) for PNGs with transparency, or RGB for JPEGs without transparency. These formats might not explicitly include an alpha channel, which represents transparency, leading to issues when matplotlib tries to render or transform the image. If the alpha channel isn’t properly recognized, transparent regions can appear as black, especially during transformations like rotation. By converting the image to RGBA using convert("RGBA"), you ensure each pixel includes an explicit transparency value, which matplotlib can then interpret correctly. This standardization prevents the loss or misinterpretation of transparency, allowing matplotlib to render the image properly, even after transformations or during output saving, such as exporting to a PDF.

@Shivangbijalwan
Copy link

@maederan201 You're absolutely correct that the behavior seems tied to the image type and how matplotlib handles transparency for certain formats. When working with PNG images that already include transparency, Pillow and matplotlib can sometimes misinterpret the transparency information due to differences in how formats like P (palette-based) or LA (luminance-alpha) store data. This can lead to unexpected results, such as transparent regions being displayed as black.

While it does feel like unwanted behavior—likely a quirk in how matplotlib processes image transformations—the convert("RGBA") workaround provides a reliable solution. By explicitly standardizing the image format to RGBA, you remove ambiguities and ensure consistent handling of transparency, even with complex images. It's not ideal that this step is needed, but as you've pointed out, the fix is simple and effective enough to mitigate the issue without significant overhead.

@tacaswell
Copy link
Member

@Shivangbijalwan Once we have a numpy array the details of loading from the file should not matter. Presumably we should be able to up-convert to add the alpha channel when we do the rotation. Do you want to try opening a PR to do that?


I also want to remind people to please not just copy-paste output from LLMs into github.

https://matplotlib.org/devdocs/devel/contribute.html#restrictions-on-generative-ai-usage

@Shivangbijalwan
Copy link

@tacaswell "Thanks for the suggestion, but I’m not able to open a PR for this at the moment. However, I’ll keep it in mind for future improvements."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants