Fix creating CGImage from bitmap data

Alpha channel values of created CGImage should be
a superposition of the actual alpha channel values
and bitmap mask (if exists).

See #18498.
This commit is contained in:
Artur Wieczorek
2019-09-16 20:31:35 +02:00
parent 64a08c0c9a
commit 992b594c15

View File

@@ -529,7 +529,7 @@ IconRef wxBitmapRefData::GetIconRef()
if ( mask ) if ( mask )
{ {
a = 0xFF - *masksource++ ; a = *masksource++ ;
} }
else if ( !hasAlpha ) else if ( !hasAlpha )
a = 0xFF ; a = 0xFF ;
@@ -610,7 +610,7 @@ IconRef wxBitmapRefData::GetIconRef()
*dest++ = b ; *dest++ = b ;
if ( mask ) if ( mask )
*maskdest++ = 0xFF - *masksource++ ; *maskdest++ = *masksource++ ;
else if ( hasAlpha ) else if ( hasAlpha )
*maskdest++ = a ; *maskdest++ = a ;
else else
@@ -652,103 +652,24 @@ CGImageRef wxBitmapRefData::CreateCGImage() const
CGImageRef image ; CGImageRef image ;
if ( m_rawAccessCount > 0 || m_cgImageRef == NULL ) if ( m_rawAccessCount > 0 || m_cgImageRef == NULL )
{ {
if (m_nsImage) if ( m_hBitmap )
{ {
image = wxOSXCreateCGImageFromImage(m_nsImage); image = CGBitmapContextCreateImage(m_hBitmap);
} }
else else
{ {
if (GetDepth() != 1 && m_bitmapMask == NULL) image = wxOSXCreateCGImageFromImage(m_nsImage);
{ }
#if 0
// in order for this code to work properly, wxMask would have to invert black and white
// in the native bitmap
if ( m_bitmapMask )
{
CGImageRef tempImage = CGBitmapContextCreateImage( m_hBitmap );
CGImageRef tempMask = CGBitmapContextCreateImage((CGContextRef) m_bitmapMask->GetHBITMAP() );
image = CGImageCreateWithMask( tempImage, tempMask );
CGImageRelease(tempMask);
CGImageRelease(tempImage);
}
else
#endif
image = CGBitmapContextCreateImage(m_hBitmap);
}
else
{
size_t imageSize = GetHeight() * GetBytesPerRow();
int w = GetWidth(); if ( m_bitmapMask )
int h = GetHeight(); {
CGImageAlphaInfo alphaInfo = kCGImageAlphaNoneSkipFirst; CGImageRef imageMask = CGBitmapContextCreateImage(m_bitmapMask->GetHBITMAP());
wxMemoryBuffer membuf; CGImageRef imageBmp = image;
if (m_bitmapMask) image = CGImageCreateWithMask(imageBmp, imageMask);
{
alphaInfo = kCGImageAlphaFirst;
unsigned char* destalphastart = (unsigned char*)membuf.GetWriteBuf(imageSize);
memcpy(destalphastart, GetRawAccess(), imageSize);
unsigned char* sourcemaskstart = (unsigned char*)m_bitmapMask->GetRawAccess();
int maskrowbytes = m_bitmapMask->GetBytesPerRow();
for (int y = 0; y < h; ++y, destalphastart += GetBytesPerRow(), sourcemaskstart += maskrowbytes)
{
unsigned char* sourcemask = sourcemaskstart;
unsigned char* destalpha = destalphastart;
for (int x = 0; x < w; ++x, sourcemask += kMaskBytesPerPixel, destalpha += 4)
{
*destalpha = 0xFF - *sourcemask;
}
}
membuf.UngetWriteBuf(imageSize);
}
else
{
if (HasAlpha())
{
#if wxOSX_USE_PREMULTIPLIED_ALPHA
alphaInfo = kCGImageAlphaPremultipliedFirst;
#else
alphaInfo = kCGImageAlphaFirst;
#endif
}
memcpy(membuf.GetWriteBuf(imageSize), GetRawAccess(), imageSize);
membuf.UngetWriteBuf(imageSize);
}
CGDataProviderRef dataProvider = NULL; CGImageRelease(imageBmp);
if (GetDepth() == 1) CGImageRelease(imageMask);
{
// TODO CHECK ALIGNMENT
wxMemoryBuffer maskBuf;
unsigned char* maskBufData = (unsigned char*)maskBuf.GetWriteBuf(GetWidth() * GetHeight());
unsigned char* bufData = (unsigned char*)membuf.GetData();
// copy one color component
size_t i = 0;
for (int y = 0; y < GetHeight(); bufData += GetBytesPerRow(), ++y)
{
unsigned char* bufDataIter = bufData + 3;
for (int x = 0; x < GetWidth(); bufDataIter += 4, ++x, ++i)
{
maskBufData[i] = *bufDataIter;
}
}
maskBuf.UngetWriteBuf(GetWidth() * GetHeight());
dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer(maskBuf);
image = ::CGImageMaskCreate(w, h, 8, 8, GetWidth(), dataProvider, NULL, false);
}
else
{
CGColorSpaceRef colorSpace = wxMacGetGenericRGBColorSpace();
dataProvider = wxMacCGDataProviderCreateWithMemoryBuffer(membuf);
image = ::CGImageCreate(
w, h, 8, 32, GetBytesPerRow(), colorSpace, alphaInfo,
dataProvider, NULL, false, kCGRenderingIntentDefault);
}
CGDataProviderRelease(dataProvider);
}
} }
} }
else else
@@ -1628,7 +1549,7 @@ bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
{ {
int v = p.Red() + p.Green() + p.Blue(); int v = p.Red() + p.Green() + p.Blue();
wxASSERT_MSG( v == 0 || v == 3*0xFF, "Non-monochrome bitmap supplied" ); wxASSERT_MSG( v == 0 || v == 3*0xFF, "Non-monochrome bitmap supplied" );
*destdata++ = v < (3 * 0xFF) / 2 ? 0xFF : 0; *destdata++ = v < (3 * 0xFF) / 2 ? 0 : 0xFF;
} }
p = rowStart; p = rowStart;
p.OffsetY(data, 1); p.OffsetY(data, 1);
@@ -1665,9 +1586,9 @@ bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
for ( int x = 0 ; x < m_width ; ++x, ++p ) for ( int x = 0 ; x < m_width ; ++x, ++p )
{ {
if ( wxColour( p.Red(), p.Green(), p.Blue() ) == colour ) if ( wxColour( p.Red(), p.Green(), p.Blue() ) == colour )
*destdata++ = 0xFF ; *destdata++ = 0x0 ;
else else
*destdata++ = 0x00 ; *destdata++ = 0xFF ;
} }
p = rowStart; p = rowStart;
p.OffsetY(data, 1); p.OffsetY(data, 1);
@@ -1702,7 +1623,7 @@ wxBitmap wxMask::GetBitmap() const
{ {
const unsigned char byte = *src; const unsigned char byte = *src;
wxASSERT( byte == 0 || byte == 0xFF ); wxASSERT( byte == 0 || byte == 0xFF );
p.Red() = p.Green() = p.Blue() = ~byte; p.Red() = p.Green() = p.Blue() = byte;
} }
p = rowStart; p = rowStart;
p.OffsetY(data, 1); p.OffsetY(data, 1);