+// ----------------------------------------------------------------------------
+// DDB <-> DIB conversions
+// ----------------------------------------------------------------------------
+
+HBITMAP wxDIB::CreateDDB(HDC hdc) const
+{
+ wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
+
+ DIBSECTION ds;
+ if ( !::GetObject(m_handle, sizeof(ds), &ds) )
+ {
+ wxLogLastError(_T("GetObject(hDIB)"));
+
+ return 0;
+ }
+
+ return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
+}
+
+/* static */
+HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
+{
+ wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
+
+ // here we get BITMAPINFO struct followed by the actual bitmap bits and
+ // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
+ const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
+
+ // get the pointer to the start of the real image data if we have a plain
+ // DIB and not a DIB section (in the latter case the pointer must be passed
+ // to us by the caller)
+ if ( !bits )
+ {
+ // we must skip over the colour table to get to the image data
+
+ // biClrUsed has the number of colors but it may be not initialized at
+ // all
+ int numColors = pbmih->biClrUsed;
+ if ( !numColors )
+ {
+ numColors = wxGetNumOfBitmapColors(pbmih->biBitCount);
+ }
+
+ bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
+ }
+
+ HBITMAP hbmp = ::CreateDIBitmap
+ (
+ hdc ? hdc // create bitmap compatible
+ : ScreenHDC(), // with this DC
+ pbmih, // used to get size &c
+ CBM_INIT, // initialize bitmap bits too
+ bits, // ... using this data
+ pbmi, // this is used for palette only
+ DIB_RGB_COLORS // direct or indexed palette?
+ );
+
+ if ( !hbmp )
+ {
+ wxLogLastError(wxT("CreateDIBitmap"));
+ }
+
+ return hbmp;
+}
+
+/* static */
+size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
+{
+ wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") );
+
+ // prepare all the info we need
+ BITMAP bm;
+ if ( !::GetObject(hbmp, sizeof(bm), &bm) )
+ {
+ wxLogLastError(wxT("GetObject(bitmap)"));
+
+ return 0;
+ }
+
+ // calculate the number of bits per pixel and the number of items in
+ // bmiColors array (whose meaning depends on the bitmap format)
+ WORD biBits = bm.bmPlanes * bm.bmBitsPixel;
+ WORD biColors = wxGetNumOfBitmapColors(biBits);
+
+ // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
+ // use this one
+ BITMAPINFO bi2;
+
+ bool wantSizeOnly = pbi == NULL;
+ if ( wantSizeOnly )
+ pbi = &bi2;
+
+ // just for convenience
+ const int h = bm.bmHeight;
+
+ // init the header
+ BITMAPINFOHEADER& bi = pbi->bmiHeader;
+ wxZeroMemory(bi);
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = bm.bmWidth;
+ bi.biHeight = h;
+ bi.biPlanes = 1;
+ bi.biBitCount = biBits;
+
+ // memory we need for BITMAPINFO only
+ DWORD dwLen = bi.biSize + biColors * sizeof(RGBQUAD);
+
+ // first get the image size
+ ScreenHDC hdc;
+ if ( !::GetDIBits(hdc, hbmp, 0, h, NULL, pbi, DIB_RGB_COLORS) )
+ {
+ wxLogLastError(wxT("GetDIBits(NULL)"));
+
+ return 0;
+ }
+
+ if ( !wantSizeOnly )
+ {
+ // and now copy the bits
+ void *image = (char *)pbi + dwLen;
+ if ( !::GetDIBits(hdc, hbmp, 0, h, image, pbi, DIB_RGB_COLORS) )
+ {
+ wxLogLastError(wxT("GetDIBits"));
+
+ return 0;
+ }
+ }
+
+ // return the total size
+ return dwLen + bi.biSizeImage;
+}
+
+// ----------------------------------------------------------------------------
+// palette support
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
+
+wxPalette *wxDIB::CreatePalette() const
+{
+ wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
+
+ DIBSECTION ds;
+ if ( !::GetObject(m_handle, sizeof(ds), &ds) )
+ {
+ wxLogLastError(_T("GetObject(hDIB)"));
+
+ return 0;
+ }
+
+ // how many colours are we going to have in the palette?
+ DWORD biClrUsed = ds.dsBmih.biClrUsed;
+ if ( !biClrUsed )
+ {
+ // biClrUsed field might not be set
+ biClrUsed = 1 << ds.dsBmih.biBitCount;
+ }
+
+ if ( biClrUsed > 256 )
+ {
+ // only 8bpp bitmaps (and less) have palettes, so we surely don't
+ //
+ // NB: another possibility would be to return
+ // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
+ return NULL;
+ }
+
+ // LOGPALETTE struct has only 1 element in palPalEntry array, we're
+ // going to have biClrUsed of them so add necessary space
+ LOGPALETTE *pPalette = (LOGPALETTE *)
+ malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
+ wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
+
+ // initialize the palette header
+ pPalette->palVersion = 0x300; // magic number, not in docs but works
+ pPalette->palNumEntries = biClrUsed;
+
+ // and the colour table (it starts right after the end of the header)
+ const RGBQUAD *pRGB = (RGBQUAD *)((char *)&ds.dsBmih + ds.dsBmih.biSize);
+ for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
+ {
+ pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
+ pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
+ pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
+ pPalette->palPalEntry[i].peFlags = 0;
+ }
+
+ HPALETTE hPalette = ::CreatePalette(pPalette);
+
+ free(pPalette);
+
+ if ( !hPalette )
+ {
+ wxLogLastError(_T("CreatePalette"));
+
+ return NULL;
+ }
+
+ wxPalette *palette = new wxPalette;
+ palette->SetHPALETTE((WXHPALETTE)hPalette);
+
+ return palette;
+}
+
+#endif // wxUSE_PALETTE
+