+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+// calculate the number of palette entries needed for the bitmap with this
+// number of bits per pixel
+static WORD wxGetNumOfBitmapColors(WORD bitsPerPixel)
+{
+ // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
+ // 24bpp ones too but we don't support this as I think it's quite uncommon)
+ return bitsPerPixel <= 8 ? 1 << bitsPerPixel : 0;
+}
+
+// ============================================================================
+// 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.biSizeImage = GetLineSize(width, depth)*height;
+
+ 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;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// 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
+
+// ----------------------------------------------------------------------------
+// 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
+ */