-/*
- * 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
+ m_hasAlpha = image.HasAlpha();
+ const int bpp = m_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 = m_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
+ unsigned char *dst = dstLineStart;
+ if ( alpha )
+ {
+ for ( int x = 0; x < w; x++ )
+ {
+ // RGB order is reversed, and we need to premultiply
+ // all channels by alpha value for use with ::AlphaBlend.
+ 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;
+ }
+ }
+ else // no alpha channel
+ {
+ for ( int x = 0; x < w; x++ )
+ {
+ // RGB order is reversed.
+ *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;