+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxDIB creation
+// ----------------------------------------------------------------------------
+
+bool wxDIB::Create(int width, int height, int depth)
+{
+ // we don't handle the palette yet
+ wxASSERT_MSG( depth == 24 || depth == 32,
+ _T("unsupported image depth in wxDIB::Create()") );
+
+ static const int infosize = sizeof(BITMAPINFOHEADER);
+
+ BITMAPINFO *info = (BITMAPINFO *)malloc(infosize);
+ wxCHECK_MSG( info, NULL, _T("malloc(BITMAPINFO) failed") );
+
+ memset(info, 0, infosize);
+
+ info->bmiHeader.biSize = infosize;
+ info->bmiHeader.biWidth = width;
+
+ // we use positive height here which corresponds to a DIB with normal, i.e.
+ // bottom to top, order -- normally using negative height (which means
+ // reversed for MS and hence natural for all the normal people top to
+ // bottom line scan order) could be used to avoid the need for the image
+ // reversal in Create(image) but this doesn't work under NT, only Win9x!
+ info->bmiHeader.biHeight = height;
+
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = depth;
+ info->bmiHeader.biCompression = BI_RGB;
+ info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
+
+ // No need to report an error here. If it fails, we just won't use a
+ // file mapping and CreateDIBSection will just allocate memory for us.
+ m_handle = ::CreateDIBSection
+ (
+ 0, // hdc (unused with DIB_RGB_COLORS)
+ info, // bitmap description
+ DIB_RGB_COLORS, // use RGB, not palette
+ &m_data, // [out] DIB bits
+ NULL, // don't use file mapping
+ 0 // file mapping offset (not used here)
+ );
+
+ free(info);
+
+ if ( !m_handle )
+ {
+ wxLogLastError(wxT("CreateDIBSection"));
+
+ return false;
+ }
+
+ m_width = width;
+ m_height = height;
+ m_depth = depth;
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// Loading/saving the DIBs
+// ----------------------------------------------------------------------------
+
+bool wxDIB::Load(const wxString& filename)
+{
+ m_handle = (HBITMAP)::LoadImage
+ (
+ wxGetInstance(),
+ filename,
+ IMAGE_BITMAP,
+ 0, 0, // don't specify the size
+ LR_CREATEDIBSECTION | LR_LOADFROMFILE
+ );
+ if ( !m_handle )
+ {
+ wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
+
+ return false;
+ }
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// wxDIB accessors
+// ----------------------------------------------------------------------------
+
+void wxDIB::DoGetObject() const
+{
+ // only do something if we have a valid DIB but we don't [yet] have valid
+ // data
+ if ( m_handle && !m_data )
+ {
+ // although all the info we need is in BITMAP and so we don't really
+ // need DIBSECTION we still ask for it as modifying the bit values only
+ // works for the real DIBs and not for the bitmaps and it's better to
+ // check for this now rather than trying to find out why it doesn't
+ // work later
+ DIBSECTION ds;
+ if ( !::GetObject(m_handle, sizeof(ds), &ds) )
+ {
+ wxLogLastError(_T("GetObject(hDIB)"));
+ return;
+ }
+
+ wxDIB *self = wxConstCast(this, wxDIB);
+
+ self->m_width = ds.dsBm.bmWidth;
+ self->m_height = ds.dsBm.bmHeight;
+ self->m_depth = ds.dsBm.bmBitsPixel;
+ self->m_data = ds.dsBm.bmBits;
+ }
+}
+
+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;
+ }
+
+ HBITMAP hbitmap = ::CreateCompatibleBitmap
+ (
+ hdc ? hdc : ScreenHDC(),
+ ds.dsBm.bmWidth,
+ ds.dsBm.bmHeight
+ );
+ if ( !hbitmap )
+ {
+ wxLogLastError(_T("CreateCompatibleBitmap()"));
+
+ return 0;
+ }
+
+ MemoryHDC hdcMem;
+ SelectInHDC select(hdcMem, hbitmap);
+ if ( !select )
+ {
+ wxLogLastError(_T("SelectObjct(hBitmap)"));
+ }
+
+ if ( !::SetDIBits
+ (
+ hdcMem,
+ hbitmap,
+ 0,
+ ds.dsBm.bmHeight,
+ ds.dsBm.bmBits,
+ (BITMAPINFO *)&ds.dsBmih,
+ DIB_RGB_COLORS
+ ) )
+ {
+ wxLogLastError(_T("SetDIBits"));
+
+ return 0;
+ }
+
+ return hbitmap;
+}
+
+#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
+
+// ----------------------------------------------------------------------------
+// wxImage support
+// ----------------------------------------------------------------------------
+
+#if wxUSE_IMAGE
+
+bool wxDIB::Create(const wxImage& image)
+{
+ wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
+
+ 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
+ unsigned char *dst = dstLineStart;
+ for ( int x = 0; x < w; x++ )
+ {
+ // also, the order of RGB is inversed for DIBs
+ *dst++ = src[2];
+ *dst++ = src[1];
+ *dst++ = src[0];
+
+ src += 3;
+
+ if ( alpha )
+ *dst++ = *alpha++;
+ }
+
+ // 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;
+}
+
+#endif // wxUSE_IMAGE
+
+// ============================================================================
+// old DIB code, to be integrated in wxDIB class
+// ============================================================================
+
+/*
+ * Routines for dealing with Device Independent Bitmaps.
+ *
+ * wxReadDIB() - Reads a DIB
+ * wxWriteDIB() - Writes a global handle in CF_DIB format
+ * to a file.
+ * wxPaletteSize() - Calculates the palette size in bytes
+ * of given DIB
+ * wxDibNumColors() - Determines the number of colors in DIB
+ * wxDibFromBitmap() - Creates a DIB repr. the DDB passed in.
+ * lread() - Private routine to read more than 64k
+ * lwrite() - Private routine to write more than 64k
+ */