]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/dib.cpp
1.
[wxWidgets.git] / src / msw / dib.cpp
index 5cd30f4f41b5d4bda70eebef4d17c2ad576f9240..3b42e9c0f7089b16150897835572c5fca7adf54c 100644 (file)
@@ -12,8 +12,7 @@
 /*
     TODO: support for palettes is very incomplete, several functions simply
           ignore them (we should select and realize the palette, if any, before
-          caling GetDIBits() in the DC we use with it and we shouldn't use
-          GetBitmapBits() at all because we can't do it with it)
+          caling GetDIBits() in the DC we use with it.
  */
 
 // ============================================================================
@@ -36,6 +35,8 @@
     #include "wx/log.h"
 #endif //WX_PRECOMP
 
+#if wxUSE_WXDIB
+
 #include "wx/bitmap.h"
 #include "wx/intl.h"
 #include "wx/file.h"
 
 // calculate the number of palette entries needed for the bitmap with this
 // number of bits per pixel
-static WORD wxGetNumOfBitmapColors(WORD bitsPerPixel)
+static inline 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;
 }
 
+// wrapper around ::GetObject() for DIB sections
+static inline bool GetDIBSection(HBITMAP hbmp, DIBSECTION *ds)
+{
+    // note that at least under Win9x (this doesn't seem to happen under Win2K
+    // but this doesn't mean anything, of course), GetObject() may return
+    // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
+    // to check for it is by looking at the bits pointer
+    return ::GetObject(hbmp, sizeof(DIBSECTION), ds) == sizeof(DIBSECTION) &&
+                ds->dsBm.bmBits;
+}
+
 // ============================================================================
 // implementation
 // ============================================================================
@@ -84,7 +96,7 @@ bool wxDIB::Create(int width, int height, int depth)
     static const int infosize = sizeof(BITMAPINFOHEADER);
 
     BITMAPINFO *info = (BITMAPINFO *)malloc(infosize);
-    wxCHECK_MSG( info, NULL, _T("malloc(BITMAPINFO) failed") );
+    wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") );
 
     memset(info, 0, infosize);
 
@@ -132,26 +144,59 @@ bool wxDIB::Create(const wxBitmap& bmp)
 {
     wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
 
-    const int w = bmp.GetWidth();
-    const int h = bmp.GetHeight();
-    int d = bmp.GetDepth();
-    if ( d == -1 )
-        d = wxDisplayDepth();
+    // this bitmap could already be a DIB section in which case we don't need
+    // to convert it to DIB
+    HBITMAP hbmp = GetHbitmapOf(bmp);
 
-    if ( !Create(w, h, d) )
-        return false;
+    DIBSECTION ds;
+    if ( GetDIBSection(hbmp, &ds) )
+    {
+        m_handle = hbmp;
 
-    // we could have used GetDIBits() too but GetBitmapBits() is simpler
-    if ( !::GetBitmapBits
-            (
-                GetHbitmapOf(bmp),      // the source DDB
-                GetLineSize(w, d)*h,    // the number of bytes to copy
-                m_data                  // the pixels will be copied here
-            ) )
+        // 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
     {
-        wxLogLastError(wxT("GetDIBits()"));
+        const int w = bmp.GetWidth();
+        const int h = bmp.GetHeight();
+        int d = bmp.GetDepth();
+        if ( d == -1 )
+            d = wxDisplayDepth();
 
-        return 0;
+        if ( !Create(w, h, d) )
+            return false;
+
+        if ( !GetDIBSection(m_handle, &ds) )
+        {
+            // we've just created a new DIB section, why should this fail?
+            wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
+
+            return false;
+        }
+
+        if ( !::GetDIBits
+                (
+                    ScreenHDC(),                // the DC to use
+                    hbmp,                       // the source DDB
+                    0,                          // first scan line
+                    h,                          // 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 0;
+        }
     }
 
     return true;
@@ -190,7 +235,7 @@ bool wxDIB::Save(const wxString& filename)
     if ( ok )
     {
         DIBSECTION ds;
-        if ( !::GetObject(m_handle, sizeof(ds), &ds) )
+        if ( !GetDIBSection(m_handle, &ds) )
         {
             wxLogLastError(_T("GetObject(hDIB)"));
         }
@@ -239,7 +284,7 @@ void wxDIB::DoGetObject() const
         // 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) )
+        if ( !GetDIBSection(m_handle, &ds) )
         {
             wxLogLastError(_T("GetObject(hDIB)"));
             return;
@@ -263,7 +308,7 @@ 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) )
+    if ( !GetDIBSection(m_handle, &ds) )
     {
         wxLogLastError(_T("GetObject(hDIB)"));
 
@@ -288,22 +333,40 @@ HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
     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 )
+        //
+        // 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 )
         {
-            numColors = wxGetNumOfBitmapColors(pbmih->biBitCount);
+            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 = wxGetNumOfBitmapColors(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);
     }
-    HDC tmphdc = hdc;
-    if (!hdc) tmphdc = ScreenHDC();
+
     HBITMAP hbmp = ::CreateDIBitmap
                      (
-                        tmphdc,             // create bitmap compatible with this DC
+                        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
@@ -400,7 +463,7 @@ HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
         return NULL;
     }
 
-    if ( !ConvertFromBitmap((BITMAPINFO *)GlobalHandle(hDIB), hbmp) )
+    if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtr(hDIB), hbmp) )
     {
         // this really shouldn't happen... it worked the first time, why not
         // now?
@@ -423,7 +486,7 @@ wxPalette *wxDIB::CreatePalette() const
     wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
 
     DIBSECTION ds;
-    if ( !::GetObject(m_handle, sizeof(ds), &ds) )
+    if ( !GetDIBSection(m_handle, &ds) )
     {
         wxLogLastError(_T("GetObject(hDIB)"));
 
@@ -545,3 +608,6 @@ bool wxDIB::Create(const wxImage& image)
 
 #endif // wxUSE_IMAGE
 
+#endif
+    // wxUSE_WXDIB
+