-/*
- * Function: BitmapToDIB
- *
- * Purpose: Given a device dependent bitmap and a palette, returns
- * a handle to global memory with a DIB spec in it. The
- * DIB is rendered using the colors of the palette passed in.
- *
- * Parms: hBitmap == Handle to device dependent bitmap compatible
- * with default screen display device.
- * hPal == Palette to render the DDB with. If it's NULL,
- * use the default palette.
- */
+ const int h = image.GetHeight();
+ const int w = image.GetWidth();
+
+ // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
+ // a 24bpp RGB is sufficient
+ const bool hasAlpha = image.HasAlpha();
+ const int bpp = hasAlpha ? 32 : 24;
+
+ if ( !Create(w, h, bpp) )
+ return false;
+
+ // DIBs are stored in bottom to top order (see also the comment above in
+ // Create()) so we need to copy bits line by line and starting from the end
+ const int srcBytesPerLine = w * 3;
+ const int dstBytesPerLine = GetLineSize(w, bpp);
+ const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
+ const unsigned char *alpha = hasAlpha ? image.GetAlpha() + (h - 1)*w
+ : NULL;
+ unsigned char *dstLineStart = (unsigned char *)m_data;
+ for ( int y = 0; y < h; y++ )
+ {
+ // 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;
+ if ( alpha )
+ {
+ int x;
+
+ switch ( pf )
+ {
+ case PixelFormat_PreMultiplied:
+ // Pre-multiply pixel values so that the DIB could be used
+ // with ::AlphaBlend().
+ for ( x = 0; x < w; x++ )
+ {
+ const unsigned char a = *alpha++;
+ *dst++ = (unsigned char)((src[2] * a + 127) / 255);
+ *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 ( x = 0; x < w; x++ )
+ {
+ *dst++ = src[2];
+ *dst++ = src[1];
+ *dst++ = src[0];
+
+ *dst++ = *alpha++;
+ src += 3;
+ }
+ break;
+ }
+
+ }
+ else // no alpha channel
+ {
+ for ( int x = 0; x < w; x++ )
+ {
+ *dst++ = src[2];
+ *dst++ = src[1];
+ *dst++ = src[0];
+ src += 3;
+ }
+ }
+
+ // pass to the previous line in the image
+ src -= 2*srcBytesPerLine;
+ if ( alpha )
+ alpha -= 2*w;
+
+ // and to the next one in the DIB
+ dstLineStart += dstBytesPerLine;
+ }
+
+ return true;
+}