]> git.saurik.com Git - wxWidgets.git/commitdiff
support for using DIBs for wxBitmap implementation (patch 649866)
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 2 Jan 2003 23:28:56 +0000 (23:28 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 2 Jan 2003 23:28:56 +0000 (23:28 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@18524 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/msw/bitmap.h
include/wx/msw/setup0.h
src/msw/bitmap.cpp
src/msw/dcprint.cpp

index d28dee8508cbfca7098d90b7f5e5e87e6dbbae92..a7052afe193d64adfd5413fb7ada821d106cc8cb 100644 (file)
@@ -31,6 +31,7 @@ wxGTK:
 
 wxMSW:
 
+- possibility to use DIBs for wxBitmap implementation (Derry Bryson)
 - wxStaticBitmap doesn't stretch its bitmap any longer (like other ports)
 - support for accelerator keys in the owner drawn menus (Derry Bryson)
 - wxCaret::SetSize() doesn't hide the caret any longer as it used to
index dff632bbb385f012d348832192e0ac6812c7cccf..da82b22d7d4c1434fd9c46642eacd0cb9421ed8e 100644 (file)
@@ -63,6 +63,10 @@ public:
 
     // optional mask for transparent drawing
     wxMask       *m_bitmapMask;
+
+#if wxUSE_DIB_FOR_BITMAP
+    WXHANDLE     m_hFileMap;   // file mapping handle for large DIB's
+#endif
 };
 
 // ----------------------------------------------------------------------------
@@ -177,6 +181,11 @@ public:
     void SetHBITMAP(WXHBITMAP bmp) { SetHandle((WXHANDLE)bmp); }
     WXHBITMAP GetHBITMAP() const { return (WXHBITMAP)GetHandle(); }
 
+#if wxUSE_DIB_FOR_BITMAP
+    void SetHFileMap(WXHANDLE hFileMap) { GetBitmapData()->m_hFileMap = hFileMap; }
+    WXHANDLE GetHFileMap() const { return GetBitmapData()->m_hFileMap; }
+#endif // wxUSE_DIB_FOR_BITMAP
+
     void SetSelectedInto(wxDC *dc) { if (GetBitmapData()) GetBitmapData()->m_selectedInto = dc; }
     wxDC *GetSelectedInto() const { return (GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC*) NULL); }
 
@@ -209,6 +218,11 @@ protected:
     bool CreateFromImage(const wxImage& image, int depth);
 #endif // wxUSE_IMAGE
 
+#if wxUSE_DIB_FOR_BITMAP
+    void *CreateDIB(int width, int height, int depth);
+    void CopyDIBLine(void* src, void* dest, int count) const;
+#endif
+
 private:
 #ifdef __WIN32__
     // common part of CopyFromIcon/CopyFromCursor for Win32
index 92bfe233670ac03659c1ba78f802a79c0ec57cd4..365de9e7c06ac7ea555a8dc5c10729f4e1f96150 100644 (file)
 // wxDC cacheing implementation
 #define wxUSE_DC_CACHEING 1
 
+// Set this to 1 to enable the use of DIB's for wxBitmap to support
+// bitmaps > 16MB on Win95/98/Me.  Set to 0 to use DDB's only.
+#define wxUSE_DIB_FOR_BITMAP 0
+
 // ----------------------------------------------------------------------------
 // common dialogs
 // ----------------------------------------------------------------------------
index 038afaa72184067688b765772d16c2ce3be398ff..fceabb32c48615173efa4348288c1b0f4cefd9db 100644 (file)
@@ -1,4 +1,4 @@
-/////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
 // Name:        bitmap.cpp
 // Purpose:     wxBitmap
 // Author:      Julian Smart
@@ -81,6 +81,9 @@ wxBitmapRefData::wxBitmapRefData()
     m_numColors = 0;
     m_bitmapMask = NULL;
     m_hBitmap = (WXHBITMAP) NULL;
+#if wxUSE_DIB_FOR_BITMAP
+    m_hFileMap = 0;
+#endif
 }
 
 void wxBitmapRefData::Free()
@@ -99,6 +102,14 @@ void wxBitmapRefData::Free()
 #endif
     }
 
+#if wxUSE_DIB_FOR_BITMAP
+    if(m_hFileMap)
+    {
+      ::CloseHandle((void*)m_hFileMap);
+      m_hFileMap = 0;
+    }
+#endif
+
     delete m_bitmapMask;
     m_bitmapMask = NULL;
 }
@@ -341,41 +352,122 @@ bool wxBitmap::Create(int w, int h, int d)
 
     m_refData = new wxBitmapRefData;
 
-    GetBitmapData()->m_width = w;
-    GetBitmapData()->m_height = h;
-    GetBitmapData()->m_depth = d;
-
-    HBITMAP hbmp;
-#ifndef __WXMICROWIN__
-    if ( d > 0 )
+#if wxUSE_DIB_FOR_BITMAP
+    if ( w && h && d >= 16 )
     {
-        hbmp = ::CreateBitmap(w, h, 1, d, NULL);
-        if ( !hbmp )
-        {
-            wxLogLastError(wxT("CreateBitmap"));
-        }
+        if ( !CreateDIB(w, h, d) )
+           return FALSE;
     }
     else
-#endif
+#endif // wxUSE_DIB_FOR_BITMAP
     {
-        ScreenHDC dc;
-        hbmp = ::CreateCompatibleBitmap(dc, w, h);
-        if ( !hbmp )
+        GetBitmapData()->m_width = w;
+        GetBitmapData()->m_height = h;
+        GetBitmapData()->m_depth = d;
+
+        HBITMAP hbmp;
+#ifndef __WXMICROWIN__
+        if ( d > 0 )
+        {
+            hbmp = ::CreateBitmap(w, h, 1, d, NULL);
+            if ( !hbmp )
+            {
+                wxLogLastError(wxT("CreateBitmap"));
+            }
+        }
+        else
+#endif // !__WXMICROWIN__
         {
-            wxLogLastError(wxT("CreateCompatibleBitmap"));
+            ScreenHDC dc;
+            hbmp = ::CreateCompatibleBitmap(dc, w, h);
+            if ( !hbmp )
+            {
+                wxLogLastError(wxT("CreateCompatibleBitmap"));
+            }
+
+            GetBitmapData()->m_depth = wxDisplayDepth();
         }
 
-        GetBitmapData()->m_depth = wxDisplayDepth();
+        SetHBITMAP((WXHBITMAP)hbmp);
     }
 
-    SetHBITMAP((WXHBITMAP)hbmp);
-
 #if WXWIN_COMPATIBILITY_2
     GetBitmapData()->m_ok = hbmp != 0;
 #endif // WXWIN_COMPATIBILITY_2
+
     return Ok();
 }
 
+#if wxUSE_DIB_FOR_BITMAP
+
+void *wxBitmap::CreateDIB(int width, int height, int depth)
+{
+    void *dibBits;
+    const int infosize = sizeof(BITMAPINFOHEADER);
+
+    BITMAPINFO *info = (BITMAPINFO *)malloc(infosize);
+    if ( info )
+    {
+        memset(info, 0, infosize);
+
+        info->bmiHeader.biSize = infosize;
+        info->bmiHeader.biWidth = width;
+        info->bmiHeader.biHeight = height;
+        info->bmiHeader.biPlanes = 1;
+        info->bmiHeader.biBitCount = depth;
+        info->bmiHeader.biCompression = BI_RGB;
+        info->bmiHeader.biSizeImage =
+            (((width * (depth/8)) + sizeof(DWORD) - 1) /
+                sizeof(DWORD) * sizeof(DWORD)) * height;
+        info->bmiHeader.biXPelsPerMeter = 0;
+        info->bmiHeader.biYPelsPerMeter = 0;
+        info->bmiHeader.biClrUsed = 0;
+        info->bmiHeader.biClrImportant = 0;
+        GetBitmapData()->m_hFileMap =
+            (WXHANDLE)::CreateFileMapping
+                        (
+                            INVALID_HANDLE_VALUE,
+                            0,
+                            PAGE_READWRITE | SEC_COMMIT,
+                            0,
+                            info->bmiHeader.biSizeImage,
+                            0
+                        );
+
+        // 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.
+        GetBitmapData()->m_handle =
+            (WXHANDLE)::CreateDIBSection
+                        (
+                            0,
+                            info,
+                            DIB_RGB_COLORS,
+                            &dibBits,
+                            (HANDLE)GetBitmapData()->m_hFileMap,
+                            0
+                        );
+
+        if ( !GetBitmapData()->m_handle )
+          wxLogLastError(wxT("CreateDIBSection"));
+
+        SetWidth(width);
+        SetHeight(height);
+        SetDepth(depth);
+
+        free(info);
+    }
+    else
+    {
+        wxFAIL_MSG( wxT("could not allocate memory for DIB header") );
+
+        dibBits = NULL;
+    }
+
+    return dibBits;
+}
+
+#endif // wxUSE_DIB_FOR_BITMAP
+
 // ----------------------------------------------------------------------------
 // wxImage to/from conversions
 // ----------------------------------------------------------------------------
@@ -397,7 +489,6 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
     // so the 'depth' argument is ignored.
 
     HDC hScreenDC = ::GetDC(NULL);
-    //    printf("Screen planes = %d, bpp = %d\n", hScreenDC->psd->planes, hScreenDC->psd->bpp);
     int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL);
 
     HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight());
@@ -503,16 +594,56 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
 
     return TRUE;
 
-#else
+#else // !__WXMICROWIN__
     wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
 
     m_refData = new wxBitmapRefData();
 
+#if wxUSE_DIB_FOR_BITMAP
+    int h = image.GetHeight();
+    int w = image.GetWidth();
+    unsigned char *dibBits = (unsigned char*)CreateDIB(w, h, 24);
+    if ( !dibBits )
+        return FALSE;
+
+    // DIBs are stored in bottom to top order so we need to copy bits line by
+    // line and starting from the end
+    const int srcBytesPerLine = w * 3;
+    const int dstBytesPerLine = (srcBytesPerLine + sizeof(DWORD) - 1) /
+                                    sizeof(DWORD) * sizeof(DWORD);
+    const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
+    for ( int i = 0; i < h; i++ )
+    {
+        // copy one DIB line
+        int x = w;
+        const unsigned char *rgbBits = src;
+        while ( x-- )
+        {
+            // also, the order of RGB is inversed for DIBs
+            *dibBits++ = rgbBits[2];
+            *dibBits++ = rgbBits[1];
+            *dibBits++ = rgbBits[0];
+
+            rgbBits += 3;
+        }
+
+        // pass to the next line
+        src -= srcBytesPerLine;
+        dibBits += dstBytesPerLine - srcBytesPerLine;
+    }
+
+    if ( image.HasMask() )
+    {
+        SetMask(new wxMask(*this, wxColour(image.GetMaskRed(),
+                                           image.GetMaskGreen(),
+                                           image.GetMaskBlue())));
+    }
+#else // wxUSE_DIB_FOR_BITMAP
     // sizeLimit is the MS upper limit for the DIB size
 #ifdef  WIN32
     int sizeLimit = 1024*768*3;
 #else
-    int sizeLimit = 0x7fff ;
+    int sizeLimit = 0x7fff;
 #endif
 
     // width and height of the device-dependent bitmap
@@ -726,6 +857,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
     ::ReleaseDC(NULL, hdc);
     free(lpDIBh);
     free(lpBits);
+#endif // wxUSE_DIB_FOR_BITMAP
 
 #if WXWIN_COMPATIBILITY_2
     // check the wxBitmap object
@@ -733,7 +865,7 @@ bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
 #endif // WXWIN_COMPATIBILITY_2
 
     return TRUE;
-#endif
+#endif // __WXMICROWIN__/!__WXMICROWIN__
 }
 
 wxImage wxBitmap::ConvertToImage() const
@@ -799,8 +931,7 @@ wxImage wxBitmap::ConvertToImage() const
 
     return image;
 
-#else // __MICROWIN__
-
+#else // !__WXMICROWIN__
     wxImage image;
 
     wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
@@ -925,7 +1056,7 @@ wxImage wxBitmap::ConvertToImage() const
     free(lpBits);
 
     return image;
-#endif
+#endif // __WXMICROWIN__/!__WXMICROWIN__
 }
 
 #endif // wxUSE_IMAGE
index e04d74c88db4caa423ba72ee71d0f7978795dc97..9ae94b59e17f4f2690263320230f780175ca491c 100644 (file)
@@ -431,45 +431,78 @@ void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp,
 
     if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
     {
-        BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
-        memset( info, 0, sizeof( BITMAPINFOHEADER ) );
+#if wxUSE_DIB_FOR_BITMAP
+        if(bmp.GetHFileMap())   // we already have a dib
+        {
+            DIBSECTION dib;
+            if ( ::GetObject(GetHbitmapOf(bmp),
+                             sizeof(dib),
+                             &dib) == sizeof(dib) )
+            {
+                 if ( ::StretchDIBits
+                        (
+                            GetHdc(),
+                            x, y,
+                            width, height,
+                            0, 0,
+                            width, height,
+                            dib.dsBm.bmBits,
+                            (LPBITMAPINFO)&dib.dsBmih,
+                            DIB_RGB_COLORS,
+                            SRCCOPY
+                        ) == GDI_ERROR )
+                 {
+                    wxLogLastError(wxT("StretchDIBits"));
+                 }
+            }
+            else
+            {
+                wxLogLastError(wxT("GetObject"));
+            }
+        }
+        else
+#endif // wxUSE_DIB_FOR_BITMAP
+        {
+            BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
+            memset( info, 0, sizeof( BITMAPINFOHEADER ) );
 
 #if wxUSE_DRAWBITMAP_24BITS
-        int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height;
+            int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height;
 #else
-        int iBitsSize = ((width + 3 ) & ~3 ) * height ;
+            int iBitsSize = ((width + 3 ) & ~3 ) * height ;
 #endif
 
-        void* bits = malloc( iBitsSize );
+            void* bits = malloc( iBitsSize );
 
-        info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
-        info->bmiHeader.biWidth = width;
-        info->bmiHeader.biHeight = height;
-        info->bmiHeader.biPlanes = 1;
+            info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
+            info->bmiHeader.biWidth = width;
+            info->bmiHeader.biHeight = height;
+            info->bmiHeader.biPlanes = 1;
 #if wxUSE_DRAWBITMAP_24BITS
-        info->bmiHeader.biBitCount = 24;
+            info->bmiHeader.biBitCount = 24;
 #else
-        info->bmiHeader.biBitCount = 8;
-#endif        
-        info->bmiHeader.biCompression = BI_RGB;
-
-        ScreenHDC display;
-        if ( GetDIBits(display, GetHbitmapOf(bmp), 0,
-                       bmp.GetHeight(), bits, info,
-                       DIB_RGB_COLORS) )
-        {
-            if ( ::StretchDIBits(GetHdc(), x, y,
-                                 width, height,
-                                 0 , 0, width, height,
-                                 bits, info,
-                                 DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
+            info->bmiHeader.biBitCount = 8;
+#endif
+            info->bmiHeader.biCompression = BI_RGB;
+
+            ScreenHDC display;
+            if ( GetDIBits(display, GetHbitmapOf(bmp), 0,
+                        bmp.GetHeight(), bits, info,
+                        DIB_RGB_COLORS) )
             {
-                wxLogLastError(wxT("StretchDIBits"));
+                if ( ::StretchDIBits(GetHdc(), x, y,
+                            width, height,
+                            0 , 0, width, height,
+                            bits, info,
+                            DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
+                {
+                    wxLogLastError(wxT("StretchDIBits"));
+                }
             }
-        }
 
-        free(bits);
-        free(info);
+            free(bits);
+            free(info);
+        }
     }
     else // no support for StretchDIBits()
     {
@@ -493,9 +526,8 @@ bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
 
     if ( useMask )
     {
-        // If we are printing source colours are screen colours
-        // not printer colours and so we need copy the bitmap
-        // pixel by pixel.
+        // If we are printing source colours are screen colours not printer
+        // colours and so we need copy the bitmap pixel by pixel.
         RECT rect;
         HDC dc_src = GetHdcOf(*source);
         HDC dc_mask = ::CreateCompatibleDC(dc_src);
@@ -528,58 +560,97 @@ bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
             wxBitmap& bmp = source->GetSelectedBitmap();
             int width = bmp.GetWidth(),
                 height = bmp.GetHeight();
+#if wxUSE_DIB_FOR_BITMAP
+            if(bmp.GetHFileMap())   // we already have a dib
+            {
+                DIBSECTION dib;
+                if( ::GetObject(GetHbitmapOf(bmp),
+                                sizeof(dib),
+                                &dib) == sizeof(dib) )
+                {
+                     if ( ::StretchDIBits
+                            (
+                                GetHdc(),
+                                xdest, ydest,
+                                width, height,
+                                xsrc, ysrc,
+                                width, height,
+                                dib.dsBm.bmBits,
+                                (LPBITMAPINFO)&dib.dsBmih,
+                                DIB_RGB_COLORS,
+                                SRCCOPY
+                            ) == GDI_ERROR )
+                     {
+                        wxLogLastError(wxT("StretchDIBits"));
+                     }
+                }
+                else
+                {
+                    wxLogLastError(wxT("GetObject"));
+                }
+            }
+            else
+#endif // wxUSE_DIB_FOR_BITMAP
+            {
+                BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
+#if wxUSE_DRAWBITMAP_24BITS
+                int iBitsSize = (((width * 3) + 3 ) & ~3 ) * height;
+#else
+                int iBitsSize = ((width + 3 ) & ~3 ) * height ;
+#endif
 
-            BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
-            int iBitsSize = ((width + 3 ) & ~3 ) * height;
-
-            void* bits = malloc( iBitsSize );
+                void* bits = malloc( iBitsSize );
 
-            memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
+                memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
 
-            info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
-            info->bmiHeader.biWidth = width;
-            info->bmiHeader.biHeight = height;
-            info->bmiHeader.biPlanes = 1;
-            info->bmiHeader.biBitCount = 8;
-            info->bmiHeader.biCompression = BI_RGB;
+                info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
+                info->bmiHeader.biWidth = width;
+                info->bmiHeader.biHeight = height;
+                info->bmiHeader.biPlanes = 1;
+#if wxUSE_DRAWBITMAP_24BITS
+                info->bmiHeader.biBitCount = 24;
+#else
+                info->bmiHeader.biBitCount = 8;
+#endif
+                info->bmiHeader.biCompression = BI_RGB;
 
-            ScreenHDC display;
-            if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
-                              height, bits, info, DIB_RGB_COLORS) )
-            {
-                wxLogLastError(wxT("GetDIBits"));
+                ScreenHDC display;
+                if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
+                            height, bits, info, DIB_RGB_COLORS) )
+                {
+                    wxLogLastError(wxT("GetDIBits"));
 
-                success = FALSE;
-            }
+                    success = FALSE;
+                }
 
-            if ( success )
-            {
-                success = ::StretchDIBits(GetHdc(), xdest, ydest,
-                                          width, height,
-                                          xsrc, ysrc,
-                                          width, height,
-                                          bits, info ,
-                                          DIB_RGB_COLORS,
-                                          SRCCOPY) != GDI_ERROR;
-                if ( !success )
+                if ( success )
                 {
-                    wxLogLastError(wxT("StretchDIBits"));
+                    success = ::StretchDIBits(GetHdc(), xdest, ydest,
+                            width, height,
+                            xsrc, ysrc,
+                            width, height,
+                            bits, info ,
+                            DIB_RGB_COLORS,
+                            SRCCOPY) != GDI_ERROR;
+                    if ( !success )
+                    {
+                        wxLogLastError(wxT("StretchDIBits"));
+                    }
                 }
-            }
 
-            free(bits);
-            free(info);
+                free(bits);
+                free(info);
+            }
         }
         else // no support for StretchDIBits
         {
-            // as we are printing, source colours are screen colours not printer
-            // colours and so we need copy the bitmap pixel by pixel.
+            // as we are printing, source colours are screen colours not
+            // printer colours and so we need copy the bitmap pixel by pixel.
             HDC dc_src = GetHdcOf(*source);
             RECT rect;
             for (int y = 0; y < height; y++)
             {
-                // This is Stefan Csomor's optimisation, where identical adjacent
-                // pixels are drawn together.
+                // optimization: draw identical adjacent pixels together.
                 for (int x = 0; x < width; x++)
                 {
                     COLORREF col = ::GetPixel(dc_src, x, y);