+// ----------------------------------------------------------------------------
+// DDB <-> DIB conversions
+// ----------------------------------------------------------------------------
+
+#ifndef __WXWINCE__
+
+HBITMAP wxDIB::CreateDDB(HDC hdc) const
+{
+ wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
+
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &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
+ //
+ // colour table either has the real colour data in which case its
+ // number of entries is given by biClrUsed or is used for masks to be
+ // used for extracting colour information from true colour bitmaps in
+ // which case it always have exactly 3 DWORDs
+ int numColors;
+ switch ( pbmih->biCompression )
+ {
+ case BI_BITFIELDS:
+ numColors = 3;
+ break;
+
+ case BI_RGB:
+ // biClrUsed has the number of colors but it may be not initialized at
+ // all
+ numColors = pbmih->biClrUsed;
+ if ( !numColors )
+ {
+ numColors = GetNumberOfColours(pbmih->biBitCount);
+ }
+ break;
+
+ default:
+ // no idea how it should be calculated for the other cases
+ numColors = 0;
+ }
+
+ bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
+ }
+
+ HBITMAP hbmp = ::CreateDIBitmap
+ (
+ hdc ? hdc // create bitmap compatible
+ : (HDC) 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;
+ }
+
+ // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
+ // use this one
+ BITMAPINFO bi2;
+
+ const 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 = bm.bmBitsPixel;
+
+ // memory we need for BITMAPINFO only
+ DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
+
+ // get either just the image size or the image bits
+ if ( !::GetDIBits
+ (
+ ScreenHDC(), // the DC to use
+ hbmp, // the source DDB
+ 0, // first scan line
+ h, // number of lines to copy
+ wantSizeOnly ? NULL // pointer to the buffer or
+ : (char *)pbi + dwLen, // NULL if we don't have it
+ pbi, // bitmap header
+ DIB_RGB_COLORS // or DIB_PAL_COLORS
+ ) )
+ {
+ wxLogLastError(wxT("GetDIBits()"));
+
+ return 0;
+ }
+
+ // return the total size
+ return dwLen + bi.biSizeImage;
+}
+
+/* static */
+HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
+{
+ // first calculate the size needed
+ const size_t size = ConvertFromBitmap(NULL, hbmp);
+ if ( !size )
+ {
+ // conversion to DDB failed?
+ return NULL;
+ }
+
+ HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
+ if ( !hDIB )
+ {
+ // this is an error which does risk to happen especially under Win9x
+ // and which the user may understand so let him know about it
+ wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
+ (unsigned long)(size / 1024));
+
+ return NULL;
+ }
+
+ if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtr(hDIB), hbmp) )
+ {
+ // this really shouldn't happen... it worked the first time, why not
+ // now?
+ wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
+
+ return NULL;
+ }
+
+ return hDIB;
+}
+
+#endif // __WXWINCE__
+
+// ----------------------------------------------------------------------------
+// palette support
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
+
+wxPalette *wxDIB::CreatePalette() const
+{
+ wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
+
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &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 = GetNumberOfColours(ds.dsBmih.biBitCount);
+ }
+
+ if ( !biClrUsed )
+ {
+ // bitmaps of this depth don't have palettes at all
+ //
+ // 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
+