Fixed creating Cairo bitmap from wxBitmap (wxMSW).

Fixed creating wxCairoBitmapData from 32bpp wxBitmap (with and without alpha channel). This also fixes wxCairoRenderer::CreateBitmap method.
1. 32bpp bitmap can represent under MSW either ARGB or RGB bitmap so there is necessary to examine its real contents with wxBitmap::HasAlpha function.
2. ARGB bitmaps are premultiplied and there is not necessary to premultiply them again.
This commit is contained in:
Artur Wieczorek
2016-03-24 21:30:05 +01:00
parent d6afb66388
commit 5ea0a0f5f9

View File

@@ -97,6 +97,22 @@ using namespace std;
#include <cairo-atsui.h>
#endif
// Helper functions for dealing with alpha pre-multiplication.
namespace
{
inline unsigned char Premultiply(unsigned char alpha, unsigned char data)
{
return alpha ? (data * alpha) / 0xff : data;
}
inline unsigned char Unpremultiply(unsigned char alpha, unsigned char data)
{
return alpha ? (data * 0xff) / alpha : data;
}
} // anonymous namespace
class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData
{
public :
@@ -1370,19 +1386,31 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
// 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
// different format and iterator than if it doesn't...
cairo_format_t bufferFormat = bmp.GetDepth() == 32
const bool isSrcBpp32 =
#if defined(__WXGTK__) && !defined(__WXGTK3__)
|| bmp.GetMask()
bmp.GetDepth() == 32 || bmp.GetMask() != NULL;
#else
bmp.GetDepth() == 32;
#endif
? CAIRO_FORMAT_ARGB32
: CAIRO_FORMAT_RGB24;
cairo_format_t bufferFormat =
#if defined(__WXGTK__) && !defined(__WXGTK3__)
isSrcBpp32
#elif defined(__WXGTK3__)
isSrcBpp32 || bmp.GetMask() != NULL
#elif defined(__WXMSW__)
(isSrcBpp32 && bmp.HasAlpha()) || bmp.GetMask() != NULL
#else
isSrcBpp32
#endif
? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24;
int stride = InitBuffer(bmp.GetWidth(), bmp.GetHeight(), bufferFormat);
wxBitmap bmpSource = bmp; // we need a non-const instance
wxUint32* data = (wxUint32*)m_buffer;
if ( bufferFormat == CAIRO_FORMAT_ARGB32 )
if ( isSrcBpp32 )
{
// use the bitmap's alpha
wxAlphaPixelData
@@ -1400,14 +1428,19 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
// with alpha in the upper 8 bits, then red, then green, then
// blue. The 32-bit quantities are stored native-endian.
// Pre-multiplied alpha is used.
unsigned char alpha = p.Alpha();
unsigned char alpha = (bufferFormat == CAIRO_FORMAT_ARGB32) ? p.Alpha() : 255;
#ifdef __WXMSW__
// MSW bitmap pixel bits are already premultiplied.
*data = (alpha << 24 | p.Red() << 16 | p.Green() << 8 | p.Blue());
#else // !__WXMSW__
if (alpha == 0)
*data = 0;
else
*data = ( alpha << 24
| (p.Red() * alpha/255) << 16
| (p.Green() * alpha/255) << 8
| (p.Blue() * alpha/255) );
*data = (alpha << 24
| Premultiply(alpha, p.Red()) << 16
| Premultiply(alpha, p.Green()) << 8
| Premultiply(alpha, p.Blue()));
#endif // __WXMSW__ / !__WXMSW__
++data;
++p;
}
@@ -1434,7 +1467,7 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
// the upper 8 bits unused. Red, Green, and Blue are stored in
// the remaining 24 bits in that order. The 32-bit quantities
// are stored native-endian.
*data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
*data = (wxALPHA_OPAQUE << 24 | p.Red() << 16 | p.Green() << 8 | p.Blue() );
++data;
++p;
}
@@ -1444,13 +1477,17 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
p.OffsetY(pixData, 1);
}
}
#if defined(__WXMSW__) || defined(__WXGTK3__)
// if there is a mask, set the alpha bytes in the target buffer to
// fully transparent or fully opaque
if (bmpSource.GetMask())
#if defined(__WXMSW__)
if (bmp.GetMask() != NULL && !bmp.HasAlpha())
#else // __WXGTK3__
if (bmp.GetMask() != NULL)
#endif // __WXMSW__ / __WXGTK3__
{
wxBitmap bmpMask = bmpSource.GetMask()->GetBitmap();
bufferFormat = CAIRO_FORMAT_ARGB32;
wxBitmap bmpMask = bmp.GetMask()->GetBitmap();
data = (wxUint32*)m_buffer;
wxNativePixelData
pixData(bmpMask, wxPoint(0, 0), wxSize(m_width, m_height));
@@ -1476,7 +1513,7 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
p.OffsetY(pixData, 1);
}
}
#endif
#endif // __WXMSW__ || __WXGTK3__
InitSurface(bufferFormat, stride);
#endif // wxHAS_RAW_BITMAP
@@ -1484,22 +1521,6 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
#if wxUSE_IMAGE
// Helper functions for dealing with alpha pre-multiplication.
namespace
{
inline unsigned char Premultiply(unsigned char alpha, unsigned char data)
{
return alpha ? (data * alpha)/0xff : data;
}
inline unsigned char Unpremultiply(unsigned char alpha, unsigned char data)
{
return alpha ? (data * 0xff)/alpha : data;
}
} // anonymous namespace
wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer,
const wxImage& image)
: wxGraphicsBitmapData(renderer)