+bool wxDIB::Create(const wxBitmap& bmp)
+{
+ wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
+
+ // this bitmap could already be a DIB section in which case we don't need
+ // to convert it to DIB
+ HBITMAP hbmp = GetHbitmapOf(bmp);
+
+ DIBSECTION ds;
+ if ( GetDIBSection(hbmp, &ds) )
+ {
+ m_handle = hbmp;
+
+ // wxBitmap will free it, not we
+ m_ownsHandle = false;
+
+ // copy all the bitmap parameters too as we have them now anyhow
+ m_width = ds.dsBm.bmWidth;
+ m_height = ds.dsBm.bmHeight;
+ m_depth = ds.dsBm.bmBitsPixel;
+
+ m_data = ds.dsBm.bmBits;
+ }
+ else // no, it's a DDB -- convert it to DIB
+ {
+ const int w = bmp.GetWidth();
+ const int h = bmp.GetHeight();
+ int d = bmp.GetDepth();
+ if ( d <= 0 )
+ d = wxDisplayDepth();
+
+ if ( !Create(w, h, d) || !CopyFromDDB(hbmp) )
+ return false;
+ }
+
+ return true;
+}
+
+// Windows CE doesn't have GetDIBits() so use an alternative implementation
+// for it
+//
+// in fact I'm not sure if GetDIBits() is really much better than using
+// BitBlt() like this -- it should be faster but I didn't do any tests, if
+// anybody has time to do them and by chance finds that GetDIBits() is not
+// much faster than BitBlt(), we could always use the Win CE version here
+#ifdef __WXWINCE__
+
+bool wxDIB::CopyFromDDB(HBITMAP hbmp)
+{
+ MemoryHDC hdcSrc;
+ if ( !hdcSrc )
+ return false;
+
+ SelectInHDC selectSrc(hdcSrc, hbmp);
+ if ( !selectSrc )
+ return false;
+
+ MemoryHDC hdcDst;
+ if ( !hdcDst )
+ return false;
+
+ SelectInHDC selectDst(hdcDst, m_handle);
+ if ( !selectDst )
+ return false;
+
+
+ if ( !::BitBlt(
+ hdcDst,
+ 0, 0, m_width, m_height,
+ hdcSrc,
+ 0, 0,
+ SRCCOPY
+ ) )
+ {
+ wxLogLastError(_T("BitBlt(DDB -> DIB)"));
+
+ return false;
+ }
+
+ return true;
+}
+
+#else // !__WXWINCE__
+
+bool wxDIB::CopyFromDDB(HBITMAP hbmp)
+{
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &ds) )
+ {
+ // we're sure that our handle is a DIB section, so this should work
+ wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
+
+ return false;
+ }
+
+ if ( !::GetDIBits
+ (
+ ScreenHDC(), // the DC to use
+ hbmp, // the source DDB
+ 0, // first scan line
+ m_height, // number of lines to copy
+ ds.dsBm.bmBits, // pointer to the buffer
+ (BITMAPINFO *)&ds.dsBmih, // bitmap header
+ DIB_RGB_COLORS // and not DIB_PAL_COLORS
+ ) )
+ {
+ wxLogLastError(wxT("GetDIBits()"));
+
+ return false;
+ }
+
+ return true;
+}
+
+#endif // __WXWINCE__/!__WXWINCE__
+
+// ----------------------------------------------------------------------------
+// Loading/saving the DIBs
+// ----------------------------------------------------------------------------
+
+bool wxDIB::Load(const wxString& filename)
+{
+#ifdef __WXWINCE__
+ m_handle = SHLoadDIBitmap(filename);
+#else // !__WXWINCE__
+ m_handle = (HBITMAP)::LoadImage
+ (
+ wxGetInstance(),
+ filename,
+ IMAGE_BITMAP,
+ 0, 0, // don't specify the size
+ LR_CREATEDIBSECTION | LR_LOADFROMFILE
+ );
+#endif // __WXWINCE__
+
+ if ( !m_handle )
+ {
+ wxLogLastError(_T("Loading DIB from file"));
+
+ return false;
+ }
+
+ return true;
+}
+
+bool wxDIB::Save(const wxString& filename)
+{
+ wxCHECK_MSG( m_handle, false, _T("wxDIB::Save(): invalid object") );
+
+ wxFile file(filename, wxFile::write);
+ bool ok = file.IsOpened();
+ if ( ok )
+ {
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &ds) )
+ {
+ wxLogLastError(_T("GetObject(hDIB)"));
+ }
+ else
+ {
+ BITMAPFILEHEADER bmpHdr;
+ wxZeroMemory(bmpHdr);
+
+ const size_t sizeHdr = ds.dsBmih.biSize;
+ const size_t sizeImage = ds.dsBmih.biSizeImage;
+
+ bmpHdr.bfType = 0x4d42; // 'BM' in little endian
+ bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
+ bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
+
+ // first write the file header, then the bitmap header and finally the
+ // bitmap data itself
+ ok = file.Write(&bmpHdr, sizeof(bmpHdr)) == sizeof(bmpHdr) &&
+ file.Write(&ds.dsBmih, sizeHdr) == sizeHdr &&
+ file.Write(ds.dsBm.bmBits, sizeImage) == sizeImage;
+ }
+ }
+
+ if ( !ok )
+ {
+ wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
+ filename.c_str());
+ }
+
+ return ok;
+}
+