Fix creating wxCairoBitmapData from wxBitmap under wxGTK2

wxAlphaPixelData can be only used to access pixel data in 32 bpp bitmaps.
Also, because bitmaps can have both alpha values and mask, the mask should
be applied to the created surface even if alpha channel exists. Masked
pixels become fully transparent and unmasked pixels should retain original
alpha values.

Closes #18570.
This commit is contained in:
Artur Wieczorek
2019-11-10 15:02:00 +01:00
parent e3d2fd9def
commit 1b9f7fcd29

View File

@@ -1489,22 +1489,14 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
// Create a surface object and copy the bitmap pixel data to it. if the // Create a surface object and copy the bitmap pixel data to it. if the
// image has alpha (or a mask represented as alpha) then we'll use a // image has alpha (or a mask represented as alpha) then we'll use a
// different format and iterator than if it doesn't... // different format and iterator than if it doesn't...
const bool isSrcBpp32 = const bool isSrcBpp32 = bmp.GetDepth() == 32;
#if defined(__WXGTK__) && !defined(__WXGTK3__)
bmp.GetDepth() == 32 || bmp.GetMask() != NULL;
#else
bmp.GetDepth() == 32;
#endif
cairo_format_t bufferFormat = cairo_format_t bufferFormat =
#if defined(__WXGTK__) && !defined(__WXGTK3__) // Under MSW and OSX we can have 32 bpp xRGB bitmaps (without alpha).
isSrcBpp32 #if defined(__WXMSW__) || defined(__WXOSX__)
#elif defined(__WXGTK3__)
isSrcBpp32 || bmp.GetMask() != NULL
#elif defined(__WXMSW__) || defined(__WXOSX__)
(isSrcBpp32 && bmp.HasAlpha()) || bmp.GetMask() != NULL (isSrcBpp32 && bmp.HasAlpha()) || bmp.GetMask() != NULL
#else #else
isSrcBpp32 isSrcBpp32 || bmp.GetMask() != NULL
#endif #endif
? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24;
@@ -1515,12 +1507,12 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
if ( isSrcBpp32 ) if ( isSrcBpp32 )
{ {
// Using wxAlphaPixelData sets (on wxMSW and wxOSX) the internal
// "has alpha" flag but we want to leave it unchanged, so we need
// to save its current value now and restore it afterwards.
#if defined(__WXMSW__) || defined(__WXOSX__) #if defined(__WXMSW__) || defined(__WXOSX__)
// Under MSW and OSX we can have 32 bpp xRGB bitmaps (without alpha).
const bool hasAlpha = bmpSource.HasAlpha(); const bool hasAlpha = bmpSource.HasAlpha();
#endif // __WXMSW__ || __WXOSX__ #else
const bool hasAlpha = true;
#endif
{ {
// use the bitmap's alpha // use the bitmap's alpha
@@ -1538,7 +1530,7 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
// with alpha in the upper 8 bits, then red, then green, then // with alpha in the upper 8 bits, then red, then green, then
// blue. The 32-bit quantities are stored native-endian. // blue. The 32-bit quantities are stored native-endian.
// Pre-multiplied alpha is used. // Pre-multiplied alpha is used.
unsigned char alpha = (bufferFormat == CAIRO_FORMAT_ARGB32) ? p.Alpha() : 255; unsigned char alpha = (bufferFormat == CAIRO_FORMAT_ARGB32 && hasAlpha) ? p.Alpha() : 255;
#ifdef __WXMSW__ #ifdef __WXMSW__
// MSW bitmap pixel bits are already premultiplied. // MSW bitmap pixel bits are already premultiplied.
*data = (alpha << 24 | p.Red() << 16 | p.Green() << 8 | p.Blue()); *data = (alpha << 24 | p.Red() << 16 | p.Green() << 8 | p.Blue());
@@ -1562,7 +1554,9 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
} }
#if defined(__WXMSW__) || defined(__WXOSX__) #if defined(__WXMSW__) || defined(__WXOSX__)
// Reset "has alpha" flag back. // Using wxAlphaPixelData sets (on wxMSW and wxOSX) the internal
// "has alpha" flag but we want to leave it unchanged, so we need
// to reset "has alpha" flag back.
// (wxBitmap::UseAlpha() is used only on wxMSW and wxOSX.) // (wxBitmap::UseAlpha() is used only on wxMSW and wxOSX.)
bmpSource.UseAlpha(hasAlpha); bmpSource.UseAlpha(hasAlpha);
#endif // __WXMSW__ || __WXOSX__ #endif // __WXMSW__ || __WXOSX__
@@ -1594,14 +1588,9 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
} }
} }
#if defined(__WXMSW__) || defined(__WXGTK3__) || defined(__WXOSX__)
// if there is a mask, set the alpha bytes in the target buffer to // if there is a mask, set the alpha bytes in the target buffer to
// fully transparent or fully opaque // fully transparent or retain original value
#if defined(__WXMSW__)
if (bmp.GetMask() != NULL && !bmp.HasAlpha())
#else // __WXGTK3__
if (bmp.GetMask() != NULL) if (bmp.GetMask() != NULL)
#endif // __WXMSW__ / __WXGTK3__
{ {
wxBitmap bmpMask = bmp.GetMask()->GetBitmap(); wxBitmap bmpMask = bmp.GetMask()->GetBitmap();
data = (wxUint32*)m_buffer; data = (wxUint32*)m_buffer;
@@ -1622,8 +1611,7 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
if (p.Red()+p.Green()+p.Blue() == 0) if (p.Red()+p.Green()+p.Blue() == 0)
#endif #endif
*data = 0; *data = 0;
else
*data = (wxALPHA_OPAQUE << 24) | (*data & 0x00FFFFFF);
++data; ++data;
++p; ++p;
} }
@@ -1633,7 +1621,6 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
p.OffsetY(pixData, 1); p.OffsetY(pixData, 1);
} }
} }
#endif // __WXMSW__ || __WXGTK3__
InitSurface(bufferFormat, stride); InitSurface(bufferFormat, stride);
#endif // wxHAS_RAW_BITMAP #endif // wxHAS_RAW_BITMAP