+wxImage wxDIB::ConvertToImage() const
+{
+ wxCHECK_MSG( IsOk(), wxNullImage,
+ wxT("can't convert invalid DIB to wxImage") );
+
+ // create the wxImage object
+ const int w = GetWidth();
+ const int h = GetHeight();
+ wxImage image(w, h, false /* don't bother clearing memory */);
+ if ( !image.Ok() )
+ {
+ wxFAIL_MSG( wxT("could not allocate data for image") );
+ return wxNullImage;
+ }
+
+ const int bpp = GetDepth();
+
+ // Remember if we have any "real" transparency, i.e. either any partially
+ // transparent pixels or not all pixels are fully opaque or fully
+ // transparent.
+ bool hasAlpha = false;
+ bool hasOpaque = false;
+ bool hasTransparent = false;
+
+ if ( bpp == 32 )
+ {
+ // 32 bit bitmaps may be either 0RGB or ARGB and we don't know in
+ // advance which one do we have so suppose we have alpha of them and
+ // get rid of it later if it turns out we didn't.
+ image.SetAlpha();
+ }
+
+ // this is the same loop as in Create() just above but with copy direction
+ // reversed
+ const int dstBytesPerLine = w * 3;
+ const int srcBytesPerLine = GetLineSize(w, bpp);
+ unsigned char *dst = image.GetData() + ((h - 1) * dstBytesPerLine);
+ unsigned char *alpha = image.HasAlpha() ? image.GetAlpha() + (h - 1)*w
+ : NULL;
+ const unsigned char *srcLineStart = (unsigned char *)GetData();
+ for ( int y = 0; y < h; y++ )
+ {
+ // copy one DIB line
+ const unsigned char *src = srcLineStart;
+ for ( int x = 0; x < w; x++ )
+ {
+ dst[2] = *src++;
+ dst[1] = *src++;
+ dst[0] = *src++;
+
+ if ( bpp == 32 )
+ {
+ // wxImage uses non premultiplied alpha so undo
+ // premultiplication done in Create() above
+ const unsigned char a = *src;
+ *alpha++ = a;
+
+ // Check what kind of alpha do we have.
+ switch ( a )
+ {
+ case 0:
+ hasTransparent = true;
+ break;
+
+ default:
+ // Anything in between means we have real transparency
+ // and must use alpha channel.
+ hasAlpha = true;
+ break;
+
+ case 255:
+ hasOpaque = true;
+ break;
+ }
+
+ if ( a > 0 )
+ {
+ dst[0] = (dst[0] * 255) / a;
+ dst[1] = (dst[1] * 255) / a;
+ dst[2] = (dst[2] * 255) / a;
+ }
+
+ src++;
+ }
+
+ dst += 3;
+ }
+
+ // pass to the previous line in the image
+ dst -= 2*dstBytesPerLine;
+ if ( alpha )
+ alpha -= 2*w;
+
+ // and to the next one in the DIB
+ srcLineStart += srcBytesPerLine;
+ }
+
+ if ( hasOpaque && hasTransparent )
+ hasAlpha = true;
+
+ if ( !hasAlpha && image.HasAlpha() )
+ image.ClearAlpha();
+
+ return image;
+}
+