From 279ee715fd00515869c6bbbac8ab18c28bfd59a0 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Mon, 8 Feb 2021 23:54:14 +0100 Subject: [PATCH] Fix creating wxCairoBitmapData from wxImage with mask If source wxImage has a mask we need to create ARGB32 Cairo surface (even for RGB image) and based on the mask values set the alpha values to fully transparent or retain original values. --- src/generic/graphicc.cpp | 46 ++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index d524568970..a6920767e7 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -1712,7 +1712,7 @@ wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer, const wxImage& image) : wxGraphicsBitmapData(renderer) { - const cairo_format_t bufferFormat = image.HasAlpha() + const cairo_format_t bufferFormat = image.HasAlpha() || image.HasMask() ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24; @@ -1734,13 +1734,16 @@ wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer, for ( int x = 0; x < m_width; x++ ) { - const unsigned char a = *alpha++; + const unsigned char a = alpha ? *alpha : wxALPHA_OPAQUE; - *dst++ = a << 24 | - Premultiply(a, src[0]) << 16 | - Premultiply(a, src[1]) << 8 | - Premultiply(a, src[2]); + *dst++ = a << 24 | + ((a * src[0]) / 255) << 16 | + ((a * src[1]) / 255) << 8 | + ((a * src[2]) / 255); src += 3; + + if ( alpha ) + alpha++; } dst = rowStartDst + stride / 4; @@ -1764,6 +1767,37 @@ wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer, } } + // if there is a mask, set the alpha bytes in the target buffer to + // fully transparent or retain original value + if ( image.HasMask() ) + { + unsigned char mr = image.GetMaskRed(); + unsigned char mg = image.GetMaskGreen(); + unsigned char mb = image.GetMaskBlue(); + + dst = reinterpret_cast(m_buffer); + src = image.GetData(); + + if ( bufferFormat == CAIRO_FORMAT_ARGB32 ) + { + for ( int y = 0; y < m_height; y++ ) + { + wxUint32* const rowStartDst = dst; + + for ( int x = 0; x < m_width; x++ ) + { + if ( src[0] == mr && src[1] == mg && src[2] == mb ) + *dst = 0; + + dst++; + src += 3; + } + + dst = rowStartDst + stride / 4; + } + } + } + InitSurface(bufferFormat, stride); }