Allow creating DIBs storing pixels in non-premultiplied format in wxMSW.

wxDIB assumed that MSW always uses bitmaps in pre-multiplied pixel format but
this turns out to be wrong: some Windows functions such as ImageList_Draw()
or CreateIconIndirect() apply pre-multiplication internally and so must be
given data in non-pre-multiplied format on input.

This commit adds a possibility to create wxDIB in such format but doesn't use
it anywhere yet, this will be done in subsequent commits.

See #9050.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65959 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-10-30 23:50:50 +00:00
parent a72ebcd091
commit fd90675b89
2 changed files with 51 additions and 16 deletions

View File

@@ -138,12 +138,28 @@ public:
// ------------------ // ------------------
#if wxUSE_IMAGE #if wxUSE_IMAGE
// create a DIB from the given image, the DIB will be either 24 or 32 (if // Possible formats for DIBs created by the functions below.
// the image has alpha channel) bpp enum PixelFormat
wxDIB(const wxImage& image) { Init(); (void)Create(image); } {
PixelFormat_PreMultiplied = 0,
PixelFormat_NotPreMultiplied = 1
};
// Create a DIB from the given image, the DIB will be either 24 or 32 (if
// the image has alpha channel) bpp.
//
// By default the DIB stores pixel data in pre-multiplied format so that it
// can be used with ::AlphaBlend() but it is also possible to disable
// pre-multiplication for the DIB to be usable with ImageList_Draw() which
// does pre-multiplication internally.
wxDIB(const wxImage& image, PixelFormat pf = PixelFormat_PreMultiplied)
{
Init();
(void)Create(image, pf);
}
// same as the above ctor but with the return code // same as the above ctor but with the return code
bool Create(const wxImage& image); bool Create(const wxImage& image, PixelFormat pf = PixelFormat_PreMultiplied);
// create wxImage having the same data as this DIB // create wxImage having the same data as this DIB
wxImage ConvertToImage() const; wxImage ConvertToImage() const;

View File

@@ -658,7 +658,7 @@ wxPalette *wxDIB::CreatePalette() const
#if wxUSE_IMAGE #if wxUSE_IMAGE
bool wxDIB::Create(const wxImage& image) bool wxDIB::Create(const wxImage& image, PixelFormat pf)
{ {
wxCHECK_MSG( image.Ok(), false, wxT("invalid wxImage in wxDIB ctor") ); wxCHECK_MSG( image.Ok(), false, wxT("invalid wxImage in wxDIB ctor") );
@@ -683,27 +683,46 @@ bool wxDIB::Create(const wxImage& image)
unsigned char *dstLineStart = (unsigned char *)m_data; unsigned char *dstLineStart = (unsigned char *)m_data;
for ( int y = 0; y < h; y++ ) for ( int y = 0; y < h; y++ )
{ {
// copy one DIB line // Copy one DIB line. Note that RGB components order is reversed in
// Windows bitmaps compared to wxImage and is actually BGR.
unsigned char *dst = dstLineStart; unsigned char *dst = dstLineStart;
if ( alpha ) if ( alpha )
{ {
for ( int x = 0; x < w; x++ ) switch ( pf )
{ {
// RGB order is reversed, and we need to premultiply case PixelFormat_PreMultiplied:
// all channels by alpha value for use with ::AlphaBlend. // Pre-multiply pixel values so that the DIB could be used
const unsigned char a = *alpha++; // with ::AlphaBlend().
*dst++ = (unsigned char)((src[2] * a + 127) / 255); for ( int x = 0; x < w; x++ )
*dst++ = (unsigned char)((src[1] * a + 127) / 255); {
*dst++ = (unsigned char)((src[0] * a + 127) / 255); const unsigned char a = *alpha++;
*dst++ = a; *dst++ = (unsigned char)((src[2] * a + 127) / 255);
src += 3; *dst++ = (unsigned char)((src[1] * a + 127) / 255);
*dst++ = (unsigned char)((src[0] * a + 127) / 255);
*dst++ = a;
src += 3;
}
break;
case PixelFormat_NotPreMultiplied:
// Just copy pixel data without changing it.
for ( int x = 0; x < w; x++ )
{
*dst++ = src[2];
*dst++ = src[1];
*dst++ = src[0];
*dst++ = *alpha++;
src += 3;
}
break;
} }
} }
else // no alpha channel else // no alpha channel
{ {
for ( int x = 0; x < w; x++ ) for ( int x = 0; x < w; x++ )
{ {
// RGB order is reversed.
*dst++ = src[2]; *dst++ = src[2];
*dst++ = src[1]; *dst++ = src[1];
*dst++ = src[0]; *dst++ = src[0];