Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fixed background colour of PNGs saved with a non-zero opacity. #1868

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

Merged
merged 2 commits into from
May 1, 2013

Conversation

pelson
Copy link
Member

@pelson pelson commented Mar 29, 2013

The following code (a derivative of http://stackoverflow.com/questions/15691297/how-to-directly-set-alpha-channel-value-for-matplotlib-figure-background-colour) was producing a png with an unexpected background colour. This PR fixes the problem so that the background colour of a PNG is as expected (and consistent with SVG).

import matplotlib.patches as mpatches
from matplotlib.image import imread
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

fig = Figure()
canvas = FigureCanvas(fig)
fig.set_facecolor('black')
fig.patch.set_alpha(0.3)

fig.patches.append(mpatches.CirclePolygon([200, 200],
                                          radius=80,
                                          facecolor='red'))

print 'Target: ', fig.patch.get_facecolor()

fig.savefig('test_fig.png',
            facecolor=fig.get_facecolor(),
            edgecolor='none')
print 'Result: ', tuple(imread('test_fig.png')[0, 0])

Yields:

Target:  (0.0, 0.0, 0.0, 0.3)
Result:  (0.69803923, 0.69803923, 0.69803923, 0.3019608)

After this change, the result is:

Target:  (0.0, 0.0, 0.0, 0.3)
Result:  (0.0, 0.0, 0.0, 0.3019608)

I'm not certain why the value is not exact, but I'm comfortable with the approximation.

There remains a problem with PDF creation (& other backends not tested). I do not propose to fix the PDF issue in this PR.

@@ -436,7 +436,7 @@ def __init__(self, filename):

revision = ''
self.infoDict = {
'Creator': 'matplotlib %s, http://matplotlib.sf.net' % __version__,
'Creator': 'matplotlib %s, http://matplotlib.org' % __version__,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

@Westacular
Copy link
Contributor

Hi, I'm the one who posted that question on Stack Overflow.

I've tested this code, and it doesn't fix the underlying problem -- the "cleared" (alpha=0) contents of the renderer are still being blended into the desired background color; the problem is merely masked with the included test because the test background and the cleared renderer are both black.

I did some Googling and some digging into AGG (notably, finding this) and I've found the culprit: It's the use of agg::pixfmt_rgba32 instead of agg::pixfmt_rgba32_plain as the pixel format for the renderer. The blending function for the non-plain version takes a shortcut in the calculation that breaks down when the existing value in the buffer has alpha=0; the _plain variant handles this correctly. I've done a quick test of a build that uses _plain instead, and the output it generates is correct.

Should I submit a pull request with that fix, and some improvements to the test case?

@pelson
Copy link
Member Author

pelson commented Mar 31, 2013

Sure. You can submit them as PRs against my PR, or its own PR to mpl.

Cheers @Westacular

extensions=['png', 'svg'], # PDF is wrong
savefig_kwarg={'facecolor': (0, 1, 0.4), 'edgecolor': 'none'})
def test_alpha():
# We want an image which has a background color of black, with an
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment now incorrect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Oops. Can you fix that?

My reasoning for the colour change was to choose something that's likely to show a problem were the blending issue (or something like it) to reoccur, regardless of if it's being blended with black or white. So, zero for one colour channel, one for another, and something else for the third.

I changed the alpha to 0.4 simply because I was hand-calculating what the correct blended colour should be in the red circle, and (in theory) 0.4 leads to less round-off error when the values and calculations are being handled as uint8s.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I'll change it. I agree with your color test - it covers all the bases.

@mdboom
Copy link
Member

mdboom commented Apr 11, 2013

Thanks for the work on this. We've found a lot of subtle things out about Agg lately, haven't we?

@pelson: I wonder whether if maybe we should rebase this on v1.2.x, since it's really sort of bugfix. I guess I'm waffling -- because obviously it will change behavior who are expecting transparent to come out as white in the PNG. There have been a few other notable bugfixes on v1.2.x since 1.2.1, and I'm wondering if it might be nice to have a 1.2.2 sooner rather than later.

@pelson
Copy link
Member Author

pelson commented Apr 11, 2013

We've found a lot of subtle things out about Agg lately, haven't we?

Yes. As we speak I'm going through the Agg backend to have another look at compound rendering, so I might turn over some more too...

There have been a few other notable bugfixes on v1.2.x since 1.2.1, and I'm wondering if it might be nice to have a 1.2.2 sooner rather than later.

I certainly have a couple of bugs that need my attention before a v1.2.2, but I also note that v1.3 at https://github.com/matplotlib/matplotlib/blob/master/doc/users/whats_new.rst#new-in-matplotlib-1-3 lists more new features than any other release. There is definitely a debate to be had on the dev mailing list about when to start aiming for a v1.3 (I hate sounding like a broken record 😄 - I'm sorry about that!).

@pelson
Copy link
Member Author

pelson commented Apr 12, 2013

I've updated this (with a trival change). I think this is now good to go.

@mdboom
Copy link
Member

mdboom commented Apr 12, 2013

Can you rebase this on master -- it currently won't merge cleanly. That will give us another go around with Travis, too.

@efiring
Copy link
Member

efiring commented Apr 28, 2013

The only conflict is a trivial one in doc/users/whats_new.rst.

Tests look OK, with 1 error and 2 failures related to fonts; I don't think there is any relation to this PR.

@pelson
Copy link
Member Author

pelson commented Apr 29, 2013

I've squashed and rebased. Just waiting for travis-ci to do its thing & then I think it's good to go.

@mdboom
Copy link
Member

mdboom commented Apr 29, 2013

My only hesitation is that the PDF backend isn't matching Agg now. Have you had a chance to look into that, or should I?

@Westacular
Copy link
Contributor

I'm not sure what you're referring to. What is the issue/mismatch with PDF?

@mdboom
Copy link
Member

mdboom commented Apr 29, 2013

The alpha_background test is turned off for PDF and there is a comment "PDF is wrong". I was just thinking maybe we should make it correct if possible before merging this.

@Westacular
Copy link
Contributor

As far as I can tell, the PDF being produced is correct. The ghostscript conversion of the PDF, however, insists on blending the PDF data with a white page background colour (eliminating all transparency in the process), and I've been unable to figure out a way around that. (The options that do support transparency seem to consider it an all-or-nothing matter.) I've also been unable to find a way specify page colour within the PDF, and I suspect there isn't one.

Converting the PDF to PNG using Inkscape gives a PNG with the correct colours and alpha values.

@mdboom
Copy link
Member

mdboom commented Apr 30, 2013

Ah, I see. Well, maybe we should just update the comment then, to
something like: "Ghostscript does not preserve the background color, so it
is not useful to test this with PDF".

On Apr 29, 2013 9:06 PM, "Wes Campaigne" [email protected] wrote:

As far as I can tell, the PDF being produced is correct. The ghostscript
conversion of the PDF, however, insists on blending the PDF data with a
white page background colour (eliminating all transparency in the process),
and I've been unable to figure out a way around that. (The options that do
support transparency seem to consider it an all-or-nothing matter.) I've
also been unable to find a way specify page colour within the PDF, and I
suspect there isn't one.

Converting the PDF to PNG using Inkscape gives a PNG with the correct
colours and alpha values.


Reply to this email directly or view it on GitHubhttps://github.com//pull/1868#issuecomment-17204384
.

@pelson
Copy link
Member Author

pelson commented May 1, 2013

I've just added that comment @mdboom in an appended commit. I always find it odd that I can modify the history of another author with git...

…2, which fixes a problem with alpha-blending partially transparent backgrounds.
@pelson
Copy link
Member Author

pelson commented May 1, 2013

Woops, pushed the wrong branch. Fixed now.

efiring added a commit that referenced this pull request May 1, 2013
Fixed background colour of PNGs saved with a non-zero opacity.
@efiring efiring merged commit 89479d3 into matplotlib:master May 1, 2013
@pelson
Copy link
Member Author

pelson commented May 1, 2013

Thanks for merging @efiring. Great work @Westacular - this is really nitty-gritty matplotlib. Thanks for your contribution!

@pelson pelson mentioned this pull request Oct 9, 2013
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

Successfully merging this pull request may close these issues.

4 participants