To premultiply or not to premultiply....

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

To premultiply or not to premultiply....

Andreas Falkenhahn
...well, that is the question!

I've noticed that when working with raw pixels using wxAlphaPixelData the code
is not really portable and it's even not consistent within a single platform.

Here's the scoop:

1) If you want to draw the wxBitmap using wxDC::wxDrawBitmap() you *have* to
premultiply the color channels but *only* on MSW and OS X. If you premultiply
colors on wxGTK, it will look wrong.

2) But even on MSW you only have to premultiply if you plan to draw the
wxBitmap to a wxDC. If you merely want to convert the wxBitmap to a wxIcon,
then you *must not* premultiply or you will get wrong colors! i.e. using
wxIcon::CopyFromBitmap() with a premultiplied wxBitmap will lead to wrong
colors.

So is there a clean & portable way to determine whether or not I have to
premultiply color channels when dealing with wxAlphaPixelData or do I have
to go the distance and #ifdef my way through enabling/disabling premultiply
code depending on platform and context?

Tks

--
Best regards,
 Andreas Falkenhahn                          mailto:[hidden email]

--
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.

To unsubscribe, send email to [hidden email]
or visit http://groups.google.com/group/wx-users
Reply | Threaded
Open this post in threaded view
|

Re: To premultiply or not to premultiply....

Vadim Zeitlin-4
On Fri, 3 Jan 2014 16:28:25 +0100 Andreas Falkenhahn wrote:

AF> Here's the scoop:
AF>
AF> 1) If you want to draw the wxBitmap using wxDC::wxDrawBitmap() you have to
AF> premultiply the color channels but only on MSW and OS X. If you premultiply
AF> colors on wxGTK, it will look wrong.

 According to the comments in the image sample, the colour components are
supposed to be premultiplied. So it seems that wxGTK behaves wrongly here.
Now how to fix it efficiently, if it really needs non-premultiplied values,
is another question... All I can say is that unfortunately I don't have
time to work on this right now so while I'd welcome any fixes, I can only
tell you to open a Trac ticket (ideally with a patch to the unit test in
tests/image/rawbmp.cpp showing the problem) and hope that someone else
works on this.

AF> 2) But even on MSW you only have to premultiply if you plan to draw the
AF> wxBitmap to a wxDC. If you merely want to convert the wxBitmap to a wxIcon,
AF> then you *must not* premultiply or you will get wrong colors! i.e. using
AF> wxIcon::CopyFromBitmap() with a premultiplied wxBitmap will lead to wrong
AF> colors.

 It seems unavoidable (and not only here) to record whether the values are
premultiplied or not in wxMSW wxBitmap, so we should just do it here -- and
assume that they are if the bitmap was accessed through wxAlphaPixelData.

 Alternatively, we could try to always premultiply under MSW as this is
what ::AlphaBlend() wants and it's probably the most performance-critical
function here. This seems more appealing than keeping track of
premultiplied status, but I'm far from sure it's going to work in all
cases...

AF> So is there a clean & portable way to determine whether or not I have to
AF> premultiply color channels when dealing with wxAlphaPixelData or do I have
AF> to go the distance and #ifdef my way through enabling/disabling premultiply
AF> code depending on platform and context?

 Ideal would be to fix this in wx itself, of course. But otherwise this
seems the only thing to do.

 Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
               http://www.tt-solutions.com/

attachment0 (203 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: To premultiply or not to premultiply....

Andreas Falkenhahn
On 03.01.2014 at 16:51 Vadim Zeitlin wrote:

> On Fri, 3 Jan 2014 16:28:25 +0100 Andreas Falkenhahn wrote:

AF>> Here's the scoop:

AF>> 1) If you want to draw the wxBitmap using wxDC::wxDrawBitmap() you have to
AF>> premultiply the color channels but only on MSW and OS X. If you premultiply
AF>> colors on wxGTK, it will look wrong.

>  According to the comments in the image sample, the colour components are
> supposed to be premultiplied. So it seems that wxGTK behaves wrongly here.
> Now how to fix it efficiently, if it really needs non-premultiplied values,
> is another question... All I can say is that unfortunately I don't have
> time to work on this right now so while I'd welcome any fixes, I can only
> tell you to open a Trac ticket (ideally with a patch to the unit test in
> tests/image/rawbmp.cpp showing the problem) and hope that someone else
> works on this.

Ok.

AF>> 2) But even on MSW you only have to premultiply if you plan to draw the
AF>> wxBitmap to a wxDC. If you merely want to convert the wxBitmap to a wxIcon,
AF>> then you *must not* premultiply or you will get wrong colors! i.e. using
AF>> wxIcon::CopyFromBitmap() with a premultiplied wxBitmap will lead to wrong
AF>> colors.

>  It seems unavoidable (and not only here) to record whether the values are
> premultiplied or not in wxMSW wxBitmap, so we should just do it here -- and
> assume that they are if the bitmap was accessed through wxAlphaPixelData.

>  Alternatively, we could try to always premultiply under MSW as this is
> what ::AlphaBlend() wants and it's probably the most performance-critical
> function here. This seems more appealing than keeping track of
> premultiplied status, but I'm far from sure it's going to work in all
> cases...

Actually, I was wrong here. On 3.0.0 it works correctly when creating a
wxIcon from a wxBitmap. It was only on 2.8.12 that the wxIcon got corrupted
when the wxBitmap used premultiplied color channels. On 3.0.0 the premultiplied
color channels are handled correctly when creating a wxIcon. So the behaviour
is consistent on MSW. But on wxGTK it seems to always expect unpremultiplied
colors, wxIcon included.

--
Best regards,
 Andreas Falkenhahn                            mailto:[hidden email]

--
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.

To unsubscribe, send email to [hidden email]
or visit http://groups.google.com/group/wx-users
Reply | Threaded
Open this post in threaded view
|

Re: To premultiply or not to premultiply....

Robin Dunn
Andreas Falkenhahn wrote:

> On 03.01.2014 at 16:51 Vadim Zeitlin wrote:
>
>> On Fri, 3 Jan 2014 16:28:25 +0100 Andreas Falkenhahn wrote:
>
> AF>>  Here's the scoop:
>
> AF>>  1) If you want to draw the wxBitmap using wxDC::wxDrawBitmap() you have to
> AF>>  premultiply the color channels but only on MSW and OS X. If you premultiply
> AF>>  colors on wxGTK, it will look wrong.
>
>>   According to the comments in the image sample, the colour components are
>> supposed to be premultiplied. So it seems that wxGTK behaves wrongly here.
>> Now how to fix it efficiently, if it really needs non-premultiplied values,
>> is another question... All I can say is that unfortunately I don't have
>> time to work on this right now so while I'd welcome any fixes, I can only
>> tell you to open a Trac ticket (ideally with a patch to the unit test in
>> tests/image/rawbmp.cpp showing the problem) and hope that someone else
>> works on this.
>
> Ok.
>
> AF>>  2) But even on MSW you only have to premultiply if you plan to draw the
> AF>>  wxBitmap to a wxDC. If you merely want to convert the wxBitmap to a wxIcon,
> AF>>  then you *must not* premultiply or you will get wrong colors! i.e. using
> AF>>  wxIcon::CopyFromBitmap() with a premultiplied wxBitmap will lead to wrong
> AF>>  colors.
>
>>   It seems unavoidable (and not only here) to record whether the values are
>> premultiplied or not in wxMSW wxBitmap, so we should just do it here -- and
>> assume that they are if the bitmap was accessed through wxAlphaPixelData.
>
>>   Alternatively, we could try to always premultiply under MSW as this is
>> what ::AlphaBlend() wants and it's probably the most performance-critical
>> function here. This seems more appealing than keeping track of
>> premultiplied status, but I'm far from sure it's going to work in all
>> cases...
>
> Actually, I was wrong here. On 3.0.0 it works correctly when creating a
> wxIcon from a wxBitmap. It was only on 2.8.12 that the wxIcon got corrupted
> when the wxBitmap used premultiplied color channels. On 3.0.0 the premultiplied
> color channels are handled correctly when creating a wxIcon. So the behaviour
> is consistent on MSW. But on wxGTK it seems to always expect unpremultiplied
> colors, wxIcon included.
>

I use these macros within wxPython so my users don't have to deal with
it, all the platforms look the same to them (not premultiplied):

// See http://tinyurl.com/e5adr for what premultiplying alpha means.
wxMSW and
// wxMac want to have the values premultiplied by the alpha value, but the
// other platforms don't.  These macros help keep the code clean.
#if defined(__WXMSW__) || defined(__WXMAC__)
#define wxPy_premultiply(p, a)   ((p) * (a) / 0xff)
#define wxPy_unpremultiply(p, a) ((a) ? ((p) * 0xff / (a)) : (p))
#else
#define wxPy_premultiply(p, a)   (p)
#define wxPy_unpremultiply(p, a) (p)
#endif



--
Robin Dunn
Software Craftsman
http://wxPython.org

--
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.

To unsubscribe, send email to [hidden email]
or visit http://groups.google.com/group/wx-users
Reply | Threaded
Open this post in threaded view
|

Re: To premultiply or not to premultiply....

Andreas Falkenhahn
On 04.01.2014 at 10:34 Robin Dunn wrote:

> I use these macros within wxPython so my users don't have to deal with
> it, all the platforms look the same to them (not premultiplied):

> // See http://tinyurl.com/e5adr for what premultiplying alpha means.
> wxMSW and
> // wxMac want to have the values premultiplied by the alpha value, but the
> // other platforms don't.  These macros help keep the code clean.
> #if defined(__WXMSW__) || defined(__WXMAC__)
> #define wxPy_premultiply(p, a)   ((p) * (a) / 0xff)
> #define wxPy_unpremultiply(p, a) ((a) ? ((p) * 0xff / (a)) : (p))
> #else
> #define wxPy_premultiply(p, a)   (p)
> #define wxPy_unpremultiply(p, a) (p)
> #endif

Yes, that's actually what I'm doing as well now :)

--
Best regards,
 Andreas Falkenhahn                            mailto:[hidden email]

--
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.

To unsubscribe, send email to [hidden email]
or visit http://groups.google.com/group/wx-users