]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/dib.cpp
don't append anything back in DoDeleteOneItem() if the control becomes empty (fixes...
[wxWidgets.git] / src / msw / dib.cpp
index b1dc71542ffc7ca428840163a7845ffe3e8b26fd..3acfa95d2607bc07f0873e835359632ea8763ce4 100644 (file)
-/////////////////////////////////////////////////////////////////////////////
-// Name:        dib.cpp
-// Purpose:     Routines for dealing with Device Independent Bitmaps.
-// Author:
-// Modified by: Jason Quijano 06/06/2001
-// Created:     01/02/97
+///////////////////////////////////////////////////////////////////////////////
+// Name:        src/msw/dib.cpp
+// Purpose:     implements wxDIB class
+// Author:      Vadim Zeitlin
+// Modified by:
+// Created:     03.03.03 (replaces the old file with the same name)
 // RCS-ID:      $Id$
-// Copyright:   (c) Julian Smart
-/////////////////////////////////////////////////////////////////////////////
-// FUNCTIONS :
-//      wxReadDIB()         - Reads a DIB
-//      WriteDIB()          - Writes a global handle in CF_DIB format to a file.
-//      wxPaletteSize()     - Calculates the palette size in bytes of given DIB                                                                               *
-//      DibNumColors()      - Determines the number of colors in DIB
-//      DibFromBitmap()     - Creates a DIB repr. the DDB passed in.
-//      lread()             - Private routine to read more than 64k
-//      lwrite()            - Private routine to write more than 64k
-/////////////////////////////////////////////////////////////////////////////
+// Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
+// License:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+    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.
+ */
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
-#if defined(__BORLANDC__)
-#pragma hdrstop
+#ifdef __BORLANDC__
+    #pragma hdrstop
 #endif
 
+#if wxUSE_WXDIB
+
 #ifndef WX_PRECOMP
-#include "wx/bitmap.h"
-#include "wx/log.h"
-#include "wx/intl.h"
-#endif
+    #include "wx/string.h"
+    #include "wx/log.h"
+    #include "wx/intl.h"
+    #include "wx/bitmap.h"
+    #include "wx/image.h"
+#endif //WX_PRECOMP
+
+#include "wx/file.h"
 
-#include <windows.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#if !defined(__MWERKS__) && !defined(__SALFORDC__)
-#include <memory.h>
+#if !defined(__MWERKS__)
+    #include <memory.h>
 #endif
 
 #include "wx/msw/dib.h"
-#include "wx/filesys.h"
-
-#ifdef __GNUWIN32_OLD__
-    #include "wx/msw/gnuwin32/extra.h"
-#endif
 
-#ifndef SEEK_CUR
-// flags for _lseek
-#define        SEEK_CUR 1
-#define        SEEK_END 2
-#define        SEEK_SET 0
+#ifdef __WXWINCE__
+    #include <shellapi.h>       // for SHLoadDIBitmap()
 #endif
 
-// Number of bytes to be read during each read operation.
-#define MAXREAD  32768
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
 
-// Header signatutes for various resources
-#define BFT_ICON 0x4349                 // 'IC'
-#define BFT_BITMAP 0x4d42               // 'BM'
-#define BFT_CURSOR 0x5450               // 'PT('
+// calculate the number of palette entries needed for the bitmap with this
+// number of bits per pixel
+static inline WORD GetNumberOfColours(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 (WORD)(bitsPerPixel <= 8 ? 1 << bitsPerPixel : 0);
+}
 
-// macro to determine if resource is a DIB
-#define ISDIB(bft)      ((bft) == BFT_BITMAP)
+// 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;
+}
 
-// Macro to align given value to the closest DWORD (unsigned long )
-#define ALIGNULONG(i)   ((i+3)/4*4)
+// ============================================================================
+// implementation
+// ============================================================================
 
-//  Macro to determine to round off the given value to the closest byte
-#define WIDTHBYTES(i)   ((i+31)/32*4)
+// ----------------------------------------------------------------------------
+// wxDIB creation
+// ----------------------------------------------------------------------------
 
-#define PALVERSION 0x300
-#define MAXPALETTE 256                  // max. # supported palette entries
+bool wxDIB::Create(int width, int height, int depth)
+{
+    // we don't support formats using palettes right now so we only create
+    // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
+    wxASSERT_MSG( depth, _T("invalid image depth in wxDIB::Create()") );
+    if ( depth < 24 )
+        depth = 24;
+
+    // allocate memory for bitmap structures
+    static const int sizeHeader = sizeof(BITMAPINFOHEADER);
+
+    BITMAPINFO *info = (BITMAPINFO *)malloc(sizeHeader);
+    wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") );
+
+    memset(info, 0, sizeHeader);
+
+    info->bmiHeader.biSize = sizeHeader;
+    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 = (WORD)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"));
 
-static DWORD PASCAL lwrite(int fh, VOID FAR *pv, DWORD ul);
+        return false;
+    }
 
-static BOOL WriteDIB (LPTSTR szFile,HANDLE hdib);
-WORD wxPaletteSize (VOID FAR * pv);     // This is non-static as some apps use it externally
-static WORD DibNumColors (VOID FAR * pv);
-// HANDLE DibFromBitmap (HBITMAP hbm, DWORD biStyle, WORD biBits, HPALETTE hpal);
-static BOOL PASCAL MakeBitmapAndPalette(HDC,HANDLE,HPALETTE *,HBITMAP *);
+    m_width = width;
+    m_height = height;
+    m_depth = depth;
 
-// ----------------------------------------------------------------------------
-// FUNCTION : WriteDIB(LPSTR szFile,HANDLE hdib)
-// PURPOSE  : Write a global handle in CF_DIB format to a file.
-// RETURNS  : TRUE  - if successful. FALSE - otherwise
-// ----------------------------------------------------------------------------
-static BOOL WriteDIB(
-    LPTSTR szFile,
-    HANDLE hdib )
-{
-    BITMAPFILEHEADER hdr;
-    LPBITMAPINFOHEADER lpbi;
-    int fh;
-    OFSTRUCT of;
-
-    if (!hdib)
-        return FALSE;
-    fh = OpenFile(wxConvertWX2MB(szFile), &of, OF_CREATE | OF_READWRITE);
-    if (fh == -1)
-        return FALSE;
-
-#ifdef __WINDOWS_386__
-    lpbi = (LPBITMAPINFOHEADER) MK_FP32(GlobalLock(hdib));
-#else
-    lpbi = (LPBITMAPINFOHEADER) GlobalLock(hdib);
-#endif
-    // Fill in the fields of the file header
-    hdr.bfType = BFT_BITMAP;
-    hdr.bfSize = GlobalSize(hdib) + sizeof(BITMAPFILEHEADER);
-    hdr.bfReserved1 = 0;
-    hdr.bfReserved2 = 0;
-    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + lpbi->biSize + wxPaletteSize(lpbi);
-
-    // Write the file header
-    _lwrite(fh, (LPSTR) &hdr, sizeof(BITMAPFILEHEADER));
-
-    //Write the DIB header and the bits
-    lwrite(fh, (LPSTR) lpbi, GlobalSize(hdib));
-
-    GlobalUnlock(hdib);
-    _lclose(fh);
-    return TRUE;
+    return true;
 }
 
-// ----------------------------------------------------------------------------
-// FUNCTION : wxPaletteSize(VOID FAR * pv)
-// PURPOSE  : Calculates the palette size in bytes. If the info. block
-//            is of the BITMAPCOREHEADER type, the number of colors is
-//            multiplied by 3 to give the palette size, otherwise the
-//            number of colors is multiplied by 4.
-// RETURNS  : Palette size in number of bytes.
-// ----------------------------------------------------------------------------
-WORD wxPaletteSize(
-    VOID FAR * pv )
+bool wxDIB::Create(const wxBitmap& bmp)
 {
-    LPBITMAPINFOHEADER lpbi;
-    WORD NumColors;
+    wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
 
-    lpbi = (LPBITMAPINFOHEADER) pv;
-    NumColors = DibNumColors(lpbi);
+    if ( !Create(GetHbitmapOf(bmp)) )
+        return false;
 
-    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
-        return (WORD)(NumColors * sizeof(RGBTRIPLE));
-    else
-        return (WORD)(NumColors * sizeof(RGBQUAD));
-}
+    m_hasAlpha = bmp.HasAlpha();
 
-// ----------------------------------------------------------------------------
-// FUNCTION : DibNumColors(VOID FAR * pv)
-// PURPOSE  : Determines the number of colors in the DIB by looking at
-//            the BitCount filed in the info block.
-// RETURNS  : The number of colors in the DIB.
-// ----------------------------------------------------------------------------
-static WORD DibNumColors(
-    VOID FAR *pv )
-{
-    int bits;
-    BITMAPINFOHEADER *lpbi;
-    BITMAPCOREHEADER *lpbc;
-    lpbi = ((BITMAPINFOHEADER*) pv);
-    lpbc = ((BITMAPCOREHEADER*) pv);
-
-    // With the BITMAPINFO format headers, the size of the palette
-    // is in biClrUsed, whereas in the BITMAPCORE - style headers, it
-    // is dependent on the bits per pixel ( = 2 raised to the power of
-    // bits/pixel).
-
-    if (lpbi->biSize != sizeof(BITMAPCOREHEADER)) {
-        if (lpbi->biClrUsed != 0)
-            return (WORD) lpbi->biClrUsed;
-        bits = lpbi->biBitCount;
-        }
-    else
-        bits = lpbc->bcBitCount;
-
-    switch (bits) {
-        case 1:
-            return 2;
-        case 4:
-            return 16;
-        case 8:
-            return 256;
-        default:
-            // A 24 bitcount DIB has no color table
-            return 0;
-        }
+    return true;
 }
 
-// ----------------------------------------------------------------------------
-// FUNCTION : DibFromBitmap()
-// PURPOSE  : Will create a global memory block in DIB format that
-//            represents the Device-dependent bitmap (DDB) passed in.
-// RETURNS  : A handle to the DIB
-// ----------------------------------------------------------------------------
-#if NOTHING
-static HANDLE DibFromBitmap(
-    HBITMAP hbm,
-    DWORD biStyle,
-    WORD biBits,
-    HPALETTE hpal)
+bool wxDIB::Create(HBITMAP hbmp)
 {
-    BITMAP bm;
-    BITMAPINFOHEADER bi;
-    BITMAPINFOHEADER FAR *lpbi;
-    DWORD dwLen;
-    HANDLE hdib;
-    HANDLE h;
-    HDC hdc;
-
-    if (!hbm)
-        return NULL;
-    if (hpal == NULL)
-        hpal = GetStockObject(DEFAULT_PALETTE);
+    // this bitmap could already be a DIB section in which case we don't need
+    // to convert it to DIB
+    DIBSECTION ds;
+    if ( GetDIBSection(hbmp, &ds) )
+    {
+        m_handle = hbmp;
 
-    GetObject(hbm, sizeof (bm), (LPSTR) &bm);
+        // wxBitmap will free it, not we
+        m_ownsHandle = false;
 
-    if (biBits == 0)
-        biBits = bm.bmPlanes * bm.bmBitsPixel;
+        // 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;
 
-    bi.biSize = sizeof(BITMAPINFOHEADER);
-    bi.biWidth = bm.bmWidth;
-    bi.biHeight = bm.bmHeight;
-    bi.biPlanes = 1;
-    bi.biBitCount = biBits;
-    bi.biCompression = biStyle;
-    bi.biSizeImage = 0;
-    bi.biXPelsPerMeter = 0;
-    bi.biYPelsPerMeter = 0;
-    bi.biClrUsed = 0;
-    bi.biClrImportant = 0;
+        m_data = ds.dsBm.bmBits;
+    }
+    else // no, it's a DDB -- convert it to DIB
+    {
+        // prepare all the info we need
+        BITMAP bm;
+        if ( !::GetObject(hbmp, sizeof(bm), &bm) )
+        {
+            wxLogLastError(wxT("GetObject(bitmap)"));
 
-    dwLen = bi.biSize + wxPaletteSize(&bi);
+            return false;
+        }
 
-    hdc = GetDC((HWND) NULL);
-    hpal = SelectPalette(hdc, hpal, FALSE);
-    RealizePalette(hdc);
+        int d = bm.bmBitsPixel;
+        if ( d <= 0 )
+            d = wxDisplayDepth();
 
-    hdib = GlobalAlloc(GHND, dwLen);
+        if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) )
+            return false;
+    }
 
-    if (!hdib) {
-        SelectPalette(hdc, hpal, FALSE);
-        ReleaseDC(NULL, hdc);
-        return NULL;
-        }
+    return true;
+}
 
-#ifdef __WINDOWS_386__
-    lpbi = (BITMAPINFOHEADER FAR *) MK_FP32(GlobalLock(hdib));
-#else
-    lpbi = (BITMAPINFOHEADER FAR *) GlobalLock(hdib);
-#endif
+// 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__
 
-    *lpbi = bi;
+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)"));
 
-    // call GetDIBits with a NULL lpBits param, so it will calculate the
-    // biSizeImage field for us
-    GetDIBits(hdc, hbm, 0, (WORD) bi.biHeight, NULL, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS);
-    bi = *lpbi;
-    GlobalUnlock(hdib);
+        return false;
+    }
 
-    // If the driver did not fill in the biSizeImage field, make one up
-    if (bi.biSizeImage == 0) {
-        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
-        if (biStyle != BI_RGB)
-            bi.biSizeImage = (bi.biSizeImage * 3) / 2;
-        }
+    return true;
+}
 
-    // realloc the buffer big enough to hold all the bits
-    dwLen = bi.biSize + wxPaletteSize(&bi) + bi.biSizeImage;
-    if (h = GlobalReAlloc(hdib, dwLen, 0))
-        hdib = h;
-    else {
-        GlobalFree(hdib);
-        hdib = NULL;
-        SelectPalette(hdc, hpal, FALSE);
-        ReleaseDC(NULL, hdc);
-        return hdib;
-        }
+#else // !__WXWINCE__
 
-    // call GetDIBits with a NON-NULL lpBits param, and actualy get the
-    // bits this time
+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") );
 
-#ifdef __WINDOWS_386__
-        lpbi = (BITMAPINFOHEADER FAR *) MK_FP32(GlobalLock(hdib));
-#else
-        lpbi = (BITMAPINFOHEADER FAR *) GlobalLock(hdib);
-#endif
+        return false;
+    }
 
-    if (GetDIBits(hdc,
-            hbm,
-            0,
-            (WORD) bi.biHeight,
-            (LPSTR) lpbi + (WORD) lpbi->biSize + wxPaletteSize(lpbi),
-            (LPBITMAPINFO) lpbi, DIB_RGB_COLORS) == 0) {
-        GlobalUnlock(hdib);
-        hdib = NULL;
-        SelectPalette(hdc, hpal, FALSE);
-        ReleaseDC((HWND) NULL, hdc);
-        return NULL;
-        }
+    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()"));
 
-        bi = *lpbi;
-        GlobalUnlock(hdib);
-        SelectPalette(hdc, hpal, FALSE);
-        ReleaseDC(NULL, hdc);
-        return hdib;
+        return false;
+    }
+
+    return true;
 }
-#endif
 
+#endif // __WXWINCE__/!__WXWINCE__
 
-//************* PRIVATE ROUTINES TO WRITE MORE THAN 64K ******************
 // ----------------------------------------------------------------------------
-// FUNCTION   : lwrite(int fh, VOID FAR *pv, DWORD ul)
-// PURPOSE    : Writes data in steps of 32k till all the data is written.
-// RETURNS    : 0 - If write did not proceed correctly. number of bytes written otherwise.
+// Loading/saving the DIBs
 // ----------------------------------------------------------------------------
-static DWORD PASCAL lwrite(
-    int fh,
-    VOID FAR *pv,
-    DWORD ul)
+
+bool wxDIB::Load(const wxString& filename)
 {
-    DWORD ulT = ul;
-#if defined(WINNT) || defined(__WIN32__) || defined(__WIN32__) || defined(__WXWINE__)
-    BYTE *hp = (BYTE *) pv;
-#else
-    BYTE huge *hp = (BYTE huge *) pv;
-#endif
-    while (ul > MAXREAD) {
-        if (_lwrite(fh, (LPSTR) hp, (WORD) MAXREAD) != MAXREAD)
-            return 0;
-        ul -= MAXREAD;
-        hp += MAXREAD;
-        }
-    if (_lwrite(fh, (LPSTR) hp, (WXUINT) ul) != (WXUINT) ul)
-        return 0;
-    return ulT;
+#ifdef __WXWINCE__
+    m_handle = SHLoadDIBitmap(filename);
+#else // !__WXWINCE__
+    m_handle = (HBITMAP)::LoadImage
+                         (
+                            wxGetInstance(),
+                            filename.fn_str(),
+                            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;
 }
 
-// ----------------------------------------------------------------------------
-// FUNCTION : ReadDIB(hWnd)
-// PURPOSE  : Reads a DIB from a file, obtains a handle to its
-//            BITMAPINFO struct. and loads the DIB.  Once the DIB
-//            is loaded, the function also creates a bitmap and
-//            palette out of the DIB for a device-dependent form.
-// RETURNS  : TRUE  - DIB loaded and bitmap/palette created
-//            The DIBINIT structure pointed to by pInfo is
-//            filled with the appropriate handles.
-//            FALSE - otherwise
-// ----------------------------------------------------------------------------
-BOOL wxReadDIB(
-    LPTSTR lpFileName,
-    HBITMAP *bitmap,
-    HPALETTE *palette)
+bool wxDIB::Save(const wxString& filename)
 {
-    LPBITMAPINFOHEADER lpbi;
-    BITMAPFILEHEADER bf;
-    WORD nNumColors;
-    BOOL result = FALSE;
-    WORD offBits;
-    HDC hDC;
-    BOOL bCoreHead = FALSE;
-    HANDLE hDIB = 0;
-
-    // JQ: We want to use wxFileSystem here in stead of Openfile so
-    // that we can use other FS types like a zip files.
-    wxFileSystem fsys;
-    wxFSFile *file = fsys.OpenFile(lpFileName);
-    wxInputStream *dibs = file->GetStream();
-    if (!dibs) {
-        wxLogError(_("Can't open file '%s'"), lpFileName);
-        return (0);
+    wxCHECK_MSG( m_handle, false, _T("wxDIB::Save(): invalid object") );
+
+#if wxUSE_FILE
+    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);
 
-    hDIB = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
-    if (!hDIB)
-        return(0);
+            const size_t sizeHdr = ds.dsBmih.biSize;
+            const size_t sizeImage = ds.dsBmih.biSizeImage;
 
-#ifdef __WINDOWS_386__
-    lpbi = (LPBITMAPINFOHEADER)MK_FP32(GlobalLock(hDIB));
-#else
-    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
-#endif
+            bmpHdr.bfType = 0x4d42;    // 'BM' in little endian
+            bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
+            bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
 
-    // JQ: read from the wxInputStream dibs instead of fh so
-    // that we can use other FS types like zip files.
-    dibs->Read((LPSTR)&bf,sizeof(bf));
-    if (sizeof(bf) != dibs->LastRead())
-        goto ErrExit;
-
-    if (bf.bfType != 0x4d42)                        // 'BM'
-        goto ErrExit;
-
-    // JQ: read from the wxInputStream dibs instead of fh so
-    // that we can use other FS types like zip files.
-    dibs->Read((LPSTR)lpbi,sizeof(BITMAPCOREHEADER));
-    if (sizeof(BITMAPCOREHEADER) != dibs->LastRead())
-        goto ErrExit;
-
-    if (lpbi->biSize == sizeof(BITMAPCOREHEADER)){
-        lpbi->biSize = sizeof(BITMAPINFOHEADER);
-        lpbi->biBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
-        lpbi->biPlanes = ((LPBITMAPCOREHEADER)lpbi)->bcPlanes;
-        lpbi->biHeight = ((LPBITMAPCOREHEADER)lpbi)->bcHeight;
-        lpbi->biWidth = ((LPBITMAPCOREHEADER)lpbi)->bcWidth;
-        bCoreHead = TRUE;
+            // 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;
         }
-    else {
+    }
+#else // !wxUSE_FILE
+    bool ok = false;
+#endif // wxUSE_FILE/!wxUSE_FILE
 
-        // JQ: Get to the start of the header and read INFOHEADER
-        // using dibs wxInputStream
-        dibs->SeekI(sizeof(BITMAPFILEHEADER),wxFromStart);
-        if (dibs->LastError() != wxSTREAM_NO_ERROR)
-            goto ErrExit;
+    if ( !ok )
+    {
+        wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
+                   filename.c_str());
+    }
 
-        // JQ: read from the wxInputStream dibs instead of fh so
-        // that we can use other FS types like zip files.
-        // Can I do error checking with this?
-        dibs->Read((LPSTR)lpbi,sizeof(BITMAPINFOHEADER));
-        if (sizeof(BITMAPINFOHEADER) != dibs->LastRead())
-            goto ErrExit;
+    return ok;
+}
 
-        }
+// ----------------------------------------------------------------------------
+// wxDIB accessors
+// ----------------------------------------------------------------------------
 
-    nNumColors = (WORD)lpbi->biClrUsed;
-    if ( nNumColors == 0 ) {
-        // no color table for 24-bit, default size otherwise
-        if (lpbi->biBitCount != 24)
-            nNumColors = 1 << lpbi->biBitCount;     // standard size table
+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 ( !GetDIBSection(m_handle, &ds) )
+        {
+            wxLogLastError(_T("GetObject(hDIB)"));
+            return;
         }
 
-    // fill in some default values if they are zero
-    if (lpbi->biClrUsed == 0)
-        lpbi->biClrUsed = nNumColors;
+        wxDIB *self = wxConstCast(this, wxDIB);
 
-    if (lpbi->biSizeImage == 0){
-        lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
-                        * lpbi->biHeight;
-        }
+        self->m_width = ds.dsBm.bmWidth;
+        self->m_height = ds.dsBm.bmHeight;
+        self->m_depth = ds.dsBm.bmBitsPixel;
+        self->m_data = ds.dsBm.bmBits;
+    }
+}
 
-    // get a proper-sized buffer for header, color table and bits
-    GlobalUnlock(hDIB);
-    hDIB = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors * sizeof(RGBQUAD) +
-                        lpbi->biSizeImage, 0);
+// ----------------------------------------------------------------------------
+// DDB <-> DIB conversions
+// ----------------------------------------------------------------------------
 
-    // can't resize buffer for loading
-    if (!hDIB)
-        goto ErrExit2;
+#ifndef __WXWINCE__
 
-#ifdef __WINDOWS_386__
-    lpbi = (LPBITMAPINFOHEADER)MK_FP32(GlobalLock(hDIB));
-#else
-    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
-#endif
+HBITMAP wxDIB::CreateDDB(HDC hdc) const
+{
+    wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
 
-    // read the color table
-    if (!bCoreHead)
-        dibs->Read((LPSTR)lpbi + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
-    else {
-        signed int i;
-        RGBQUAD FAR *pQuad;
-        RGBTRIPLE FAR *pTriple;
-        dibs->Read((LPSTR)lpbi + lpbi->biSize, nNumColors * sizeof(RGBTRIPLE));
-        pQuad = (RGBQUAD FAR *)((LPSTR)lpbi + lpbi->biSize);
-        pTriple = (RGBTRIPLE FAR *) pQuad;
-        for (i = nNumColors - 1; i >= 0; i--){
-            pQuad[i].rgbRed = pTriple[i].rgbtRed;
-            pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
-            pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
-            pQuad[i].rgbReserved = 0;
-            }
-        }
+    DIBSECTION ds;
+    if ( !GetDIBSection(m_handle, &ds) )
+    {
+        wxLogLastError(_T("GetObject(hDIB)"));
 
-    // offset to the bits from start of DIB header
-    offBits = (WORD)(lpbi->biSize + nNumColors * sizeof(RGBQUAD));
+        return 0;
+    }
 
-    if (bf.bfOffBits != 0L)
-        dibs->SeekI(bf.bfOffBits, wxFromStart);
+    // 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 = GetNumberOfColours(ds.dsBmih.biBitCount);
+    }
 
-    dibs->Read((LPSTR)lpbi + offBits,lpbi->biSizeImage);
-    if (lpbi->biSizeImage == dibs->LastRead())
+    if ( !biClrUsed )
     {
-        GlobalUnlock(hDIB);
-        hDC = GetDC(NULL);
-        if (!MakeBitmapAndPalette(hDC, hDIB, palette, bitmap))
-        {
-            ReleaseDC(NULL,hDC);
-            goto ErrExit2;
-        }
-        else
-        {
-            ReleaseDC(NULL,hDC);
-            GlobalFree(hDIB);
-            result = TRUE;
-        }
+        return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
     }
     else
     {
-ErrExit:
-        GlobalUnlock(hDIB);
-ErrExit2:
-        GlobalFree(hDIB);
+        // fake a BITMAPINFO w/o bits, just the palette info
+        wxCharBuffer bmi(sizeof(BITMAPINFO) + (biClrUsed - 1)*sizeof(RGBQUAD));
+        BITMAPINFO *pBmi = (BITMAPINFO *)bmi.data();
+        MemoryHDC hDC;
+        // get the colour table
+        SelectInHDC sDC(hDC, m_handle);
+        ::GetDIBColorTable(hDC, 0, biClrUsed, pBmi->bmiColors);
+        memcpy(&pBmi->bmiHeader, &ds.dsBmih, ds.dsBmih.biSize);
+
+        return ConvertToBitmap(pBmi, hdc, ds.dsBm.bmBits);
     }
-    return(result);
 }
 
-// ----------------------------------------------------------------------------
-// FUNCTION : MakeBitmapAndPalette
-// PURPOSE  : Given a DIB, creates a bitmap and corresponding palette
-//            to be used for a device-dependent representation of
-//            of the image.
-// RETURNS  : TRUE  --> success. phPal and phBitmap are filled with
-//            appropriate handles.  Caller is responsible for freeing objects.
-//            FALSE --> unable to create objects.  both pointer are not valid
-// ----------------------------------------------------------------------------
-static BOOL PASCAL MakeBitmapAndPalette(
-    HDC hDC,
-    HANDLE hDIB,
-    HPALETTE * phPal,
-    HBITMAP * phBitmap)
+/* static */
+HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
 {
-    LPBITMAPINFOHEADER lpInfo;
-    BOOL result = FALSE;
-    HBITMAP hBitmap;
-    HPALETTE hPalette, hOldPal;
-    LPSTR lpBits;
-
-#ifdef __WINDOWS_386__
-    lpInfo = (LPBITMAPINFOHEADER) MK_FP32(GlobalLock(hDIB));
-#else
-    lpInfo = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
-#endif
+    wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
 
-    hPalette = wxMakeDIBPalette(lpInfo);
-    if ( hPalette )
-    {
-        // Need to realize palette for converting DIB to bitmap.
-        hOldPal = SelectPalette(hDC, hPalette, TRUE);
-        RealizePalette(hDC);
+    // 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;
 
-        lpBits = (LPSTR)lpInfo + (WORD)lpInfo->biSize +
-                (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD);
-        hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
-                                (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
-
-        SelectPalette(hDC, hOldPal, TRUE);
-        RealizePalette(hDC);
-
-        if (!hBitmap)
-            DeleteObject(hPalette);
-        else
+    // 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
+        //
+        // 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 )
         {
-            *phBitmap = hBitmap;
-            *phPal = hPalette;
-            result = TRUE;
+            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 = GetNumberOfColours(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);
+    }
+
+    HBITMAP hbmp = ::CreateDIBitmap
+                     (
+                        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
+                        pbmi,               // this is used for palette only
+                        DIB_RGB_COLORS      // direct or indexed palette?
+                     );
+
+    if ( !hbmp )
+    {
+        wxLogLastError(wxT("CreateDIBitmap"));
     }
 
-       GlobalUnlock (hDIB);  // glt
-    return(result);
+    return hbmp;
 }
 
-// ----------------------------------------------------------------------------
-// FUNCTION : wxMakeDIBPalette(lpInfo)
-// PURPOSE  : Given a BITMAPINFOHEADER, create a palette based on
-//            the color table.
-// RETURNS  : non-zero - handle of a corresponding palette
-//            zero - unable to create palette
-// ----------------------------------------------------------------------------
-HPALETTE wxMakeDIBPalette(
-    LPBITMAPINFOHEADER lpInfo )
+/* static */
+size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
 {
-#ifdef __WXWINE__
-    return (FALSE);
-#else
-    LPLOGPALETTE npPal;
-    RGBQUAD far *lpRGB;
-    HPALETTE hLogPal;
-    WORD i;
-
-    // since biClrUsed field was filled during the loading of the DIB,
-    // we know it contains the number of colors in the color table.
-    if (lpInfo->biClrUsed)
+    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) )
     {
-/*
-        npPal = (NPLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
-                                (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
-*/
-        npPal = (LPLOGPALETTE)malloc(sizeof(LOGPALETTE) +
-                                (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
-        if (!npPal)
-            return(FALSE);
-
-        npPal->palVersion = 0x300;
-        npPal->palNumEntries = (WORD)lpInfo->biClrUsed;
-
-        // get pointer to the color table
-        lpRGB = (RGBQUAD FAR *)((LPSTR)lpInfo + lpInfo->biSize);
-
-        // copy colors from the color table to the LogPalette structure
-        for (i = 0; (DWORD)i < lpInfo->biClrUsed; i++, lpRGB++)
-        {
-            npPal->palPalEntry[i].peRed = lpRGB->rgbRed;
-            npPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
-            npPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
-            npPal->palPalEntry[i].peFlags = 0;
-        }
+        wxLogLastError(wxT("GetObject(bitmap)"));
 
-        hLogPal = CreatePalette((LPLOGPALETTE)npPal);
-//        LocalFree((HANDLE)npPal);
-        free(npPal);
-        return(hLogPal);
+        return 0;
     }
 
-    // 24-bit DIB with no color table.  return default palette.  Another
-    // option would be to create a 256 color "rainbow" palette to provide
-    // some good color choices.
-    else
-        return((HPALETTE) GetStockObject(DEFAULT_PALETTE));
-#endif
-}
+    // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
+    // use this one
+    BITMAPINFO bi2;
 
-// ----------------------------------------------------------------------------
-// FUNCTION :
-// PURPOSE  :
-// RETURNS  :
-// ----------------------------------------------------------------------------
-bool wxLoadIntoBitmap(
-    wxChar *filename,
-    wxBitmap *bitmap,
-    wxPalette **pal)
-{
-    HBITMAP hBitmap;
-    HPALETTE hPalette;
+    const bool wantSizeOnly = pbi == NULL;
+    if ( wantSizeOnly )
+        pbi = &bi2;
+
+    // just for convenience
+    const int h = bm.bmHeight;
 
-    bool success = (wxReadDIB(filename, &hBitmap, &hPalette) != 0);
-    if (!success)
+    // 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 = bm.bmBitsPixel;
+
+    // memory we need for BITMAPINFO only
+    DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
+
+    // get either just the image size or the image bits
+    if ( !::GetDIBits
+            (
+                ScreenHDC(),                        // the DC to use
+                hbmp,                               // the source DDB
+                0,                                  // first scan line
+                h,                                  // number of lines to copy
+                wantSizeOnly ? NULL                 // pointer to the buffer or
+                             : (char *)pbi + dwLen, // NULL if we don't have it
+                pbi,                                // bitmap header
+                DIB_RGB_COLORS                      // or DIB_PAL_COLORS
+            ) )
     {
-        DeleteObject(hPalette);
-        return FALSE;
+        wxLogLastError(wxT("GetDIBits()"));
+
+        return 0;
     }
 
-    if (hPalette)
+    // return the total size
+    return dwLen + bi.biSizeImage;
+}
+
+/* static */
+HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
+{
+    // first calculate the size needed
+    const size_t size = ConvertFromBitmap(NULL, hbmp);
+    if ( !size )
     {
-        if (pal)
-        {
-            *pal = new wxPalette;
-            (*pal)->SetHPALETTE((WXHPALETTE) hPalette);
-        }
-        else
-            DeleteObject(hPalette);
+        // conversion to DDB failed?
+        return NULL;
     }
-    else if (pal)
-        *pal = NULL;
 
-    if (hBitmap)
+    HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
+    if ( !hDIB )
     {
-        BITMAP bm;
-        GetObject(hBitmap, sizeof(bm), (LPSTR)&bm);
-
-        bitmap->SetHBITMAP((WXHBITMAP) hBitmap);
-        bitmap->SetWidth(bm.bmWidth);
-        bitmap->SetHeight(bm.bmHeight);
-        bitmap->SetDepth(bm.bmPlanes * bm.bmBitsPixel);
-#if WXWIN_COMPATIBILITY_2
-        bitmap->SetOk(TRUE);
-#endif // WXWIN_COMPATIBILITY_2
-        return TRUE;
+        // this is an error which does risk to happen especially under Win9x
+        // and which the user may understand so let him know about it
+        wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
+                   (unsigned long)(size / 1024));
+
+        return NULL;
     }
-    else return FALSE;
-}
 
-// ----------------------------------------------------------------------------
-// FUNCTION :
-// PURPOSE  :
-// RETURNS  :
-// ----------------------------------------------------------------------------
-wxBitmap *wxLoadBitmap(
-    wxChar *filename,
-    wxPalette **pal)
-{
-    wxBitmap *bitmap = new wxBitmap;
-    if (wxLoadIntoBitmap(filename, bitmap, pal))
-        return bitmap;
-    else
+    if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) )
     {
-        delete bitmap;
+        // this really shouldn't happen... it worked the first time, why not
+        // now?
+        wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
+
         return NULL;
     }
-}
 
-//---------------------------------------------------------------------
-// FUNCTION : InitBitmapInfoHeader
-// PURPOSE  : Does a "standard" initialization of a BITMAPINFOHEADER,
-//            given the Width, Height, and Bits per Pixel for the DIB.
-//
-//            By standard, I mean that all the relevant fields are set
-//            to the specified values.  biSizeImage is computed, the
-//            biCompression field is set to "no compression," and all
-//            other fields are 0.
-//
-//            Note that DIBs only allow BitsPixel values of 1, 4, 8, or
-//            24.  This routine makes sure that one of these values is
-//            used (whichever is most appropriate for the specified
-//            nBPP).
-//
-// PARMS    : lpBmInfoHdr == Far pointer to a BITMAPINFOHEADER structure
-//                            to be filled in.
-//            dwWidth     == Width of DIB (not in Win 3.0 & 3.1, high
-//                            word MUST be 0).
-//            dwHeight    == Height of DIB (not in Win 3.0 & 3.1, high
-//                            word MUST be 0).
-//            nBPP        == Bits per Pixel for the DIB.
-//
-// History:   Date      Reason
-//            11/07/91  Created
-//
-//---------------------------------------------------------------------
-static void InitBitmapInfoHeader (
-    LPBITMAPINFOHEADER lpBmInfoHdr,
-    DWORD dwWidth,
-    DWORD dwHeight,
-    int nBPP )
-{
-//   _fmemset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
-   memset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
-
-   lpBmInfoHdr->biSize      = sizeof (BITMAPINFOHEADER);
-   lpBmInfoHdr->biWidth     = dwWidth;
-   lpBmInfoHdr->biHeight    = dwHeight;
-   lpBmInfoHdr->biPlanes    = 1;
-
-   if (nBPP <= 1)
-      nBPP = 1;
-   else if (nBPP <= 4)
-      nBPP = 4;
-   else if (nBPP <= 8)
-      nBPP = 8;
-/* Doesn't work
-   else if (nBPP <= 16)
-      nBPP = 16;
-*/
-   else
-      nBPP = 24;
-
-   lpBmInfoHdr->biBitCount  = nBPP;
-   lpBmInfoHdr->biSizeImage = WIDTHBYTES (dwWidth * nBPP) * dwHeight;
+    return hDIB;
 }
 
+#endif // __WXWINCE__
+
 // ----------------------------------------------------------------------------
-// FUNCTION :
-// PURPOSE  :
-// RETURNS  :
+// palette support
 // ----------------------------------------------------------------------------
-LPSTR wxFindDIBBits (LPSTR lpbi)
-{
-   return (lpbi + *(LPDWORD)lpbi + wxPaletteSize (lpbi));
-}
 
-//---------------------------------------------------------------------
-// Function:   BitmapToDIB
-//
-// Purpose:    Given a device dependent bitmap and a palette, returns
-//             a handle to global memory with a DIB spec in it.  The
-//             DIB is rendered using the colors of the palette passed in.
-//
-//             Stolen almost verbatim from ShowDIB.
-//
-// Parms:      hBitmap == Handle to device dependent bitmap compatible
-//                        with default screen display device.
-//             hPal    == Palette to render the DDB with.  If it's NULL,
-//                        use the default palette.
-//
-// History:   Date      Reason
-//             6/01/91  Created
-//
-//---------------------------------------------------------------------
-HANDLE wxBitmapToDIB (
-    HBITMAP hBitmap,
-    HPALETTE hPal)
-{
-    BITMAP             Bitmap;
-    BITMAPINFOHEADER   bmInfoHdr;
-    LPBITMAPINFOHEADER lpbmInfoHdr;
-    LPSTR              lpBits;
-    HDC                hMemDC;
-    HANDLE             hDIB;
-    HPALETTE           hOldPal = NULL;
-
-    // Do some setup -- make sure the Bitmap passed in is valid,
-    // get info on the bitmap (like its height, width, etc.),
-    // then setup a BITMAPINFOHEADER.
-
-   if (!hBitmap)
-      return NULL;
+#if wxUSE_PALETTE
 
-   if (!GetObject (hBitmap, sizeof (Bitmap), (LPSTR) &Bitmap))
-      return NULL;
-
-   InitBitmapInfoHeader (&bmInfoHdr,
-                         Bitmap.bmWidth,
-                         Bitmap.bmHeight,
-                         Bitmap.bmPlanes * Bitmap.bmBitsPixel);
+wxPalette *wxDIB::CreatePalette() const
+{
+    // GetDIBColorTable not available in eVC3
+#if defined(_WIN32_WCE) && _WIN32_WCE < 400
+    return NULL;
+#else
+    wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
 
+    DIBSECTION ds;
+    if ( !GetDIBSection(m_handle, &ds) )
+    {
+        wxLogLastError(_T("GetObject(hDIB)"));
 
-    // Now allocate memory for the DIB.  Then, set the BITMAPINFOHEADER
-    //  into this memory, and find out where the bitmap bits go.
+        return 0;
+    }
 
-    hDIB = GlobalAlloc (GHND, sizeof (BITMAPINFOHEADER) +
-                        wxPaletteSize ((LPSTR) &bmInfoHdr) + bmInfoHdr.biSizeImage);
+    // 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 = GetNumberOfColours(ds.dsBmih.biBitCount);
+    }
 
-    if (!hDIB)
+    if ( !biClrUsed )
+    {
+        // bitmaps of this depth don't have palettes at all
+        //
+        // NB: another possibility would be to return
+        //     GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
         return NULL;
+    }
 
-#ifdef __WINDOWS_386__
-    lpbmInfoHdr  = (LPBITMAPINFOHEADER) MK_FP32(GlobalLock (hDIB));
-#else
-    lpbmInfoHdr  = (LPBITMAPINFOHEADER) GlobalLock (hDIB);
-#endif
+    MemoryHDC hDC;
 
-    *lpbmInfoHdr = bmInfoHdr;
-    lpBits       = wxFindDIBBits ((LPSTR) lpbmInfoHdr);
+    // 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") );
 
-    // Now, we need a DC to hold our bitmap.  If the app passed us
-    //  a palette, it should be selected into the DC.
-    hMemDC       = GetDC (NULL);
+    // initialize the palette header
+    pPalette->palVersion = 0x300;  // magic number, not in docs but works
+    pPalette->palNumEntries = (WORD)biClrUsed;
 
-    if (hPal)
+    // and the colour table
+    wxCharBuffer rgb(sizeof(RGBQUAD) * biClrUsed);
+    RGBQUAD *pRGB = (RGBQUAD*)rgb.data();
+    SelectInHDC selectHandle(hDC, m_handle);
+    ::GetDIBColorTable(hDC, 0, biClrUsed, pRGB);
+    for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
     {
-        hOldPal = SelectPalette (hMemDC, hPal, FALSE);
-        RealizePalette (hMemDC);
+        pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
+        pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
+        pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
+        pPalette->palPalEntry[i].peFlags = 0;
     }
 
-    // We're finally ready to get the DIB.  Call the driver and let
-    //  it party on our bitmap.  It will fill in the color table,
-    //  and bitmap bits of our global memory block.
-    if (!GetDIBits (hMemDC,
-                   hBitmap,
-                   0,
-                   Bitmap.bmHeight,
-                   lpBits,
-                   (LPBITMAPINFO) lpbmInfoHdr,
-                   DIB_RGB_COLORS))
+    HPALETTE hPalette = ::CreatePalette(pPalette);
+
+    free(pPalette);
+
+    if ( !hPalette )
     {
-        GlobalUnlock (hDIB);
-        GlobalFree (hDIB);
-        hDIB = NULL;
+        wxLogLastError(_T("CreatePalette"));
+
+        return NULL;
     }
-    else
-        GlobalUnlock (hDIB);
 
-   // Finally, clean up and return.
-   if (hOldPal)
-        SelectPalette (hMemDC, hOldPal, FALSE);
+    wxPalette *palette = new wxPalette;
+    palette->SetHPALETTE((WXHPALETTE)hPalette);
 
-   ReleaseDC (NULL, hMemDC);
-   return hDIB;
+    return palette;
+#endif
 }
 
+#endif // wxUSE_PALETTE
+
 // ----------------------------------------------------------------------------
-// FUNCTION :
-// PURPOSE  :
-// RETURNS  :
+// wxImage support
 // ----------------------------------------------------------------------------
-bool wxSaveBitmap(
-    wxChar *filename,
-    wxBitmap *bitmap,
-    wxPalette *colourmap)
+
+#if wxUSE_IMAGE
+
+bool wxDIB::Create(const wxImage& image)
 {
-    HPALETTE hPalette = 0;
-    if (colourmap)
-        hPalette = (HPALETTE) colourmap->GetHPALETTE();
+    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
+    m_hasAlpha = image.HasAlpha();
+    const int bpp = m_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 = m_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;
+        if ( alpha )
+        {
+            for ( int x = 0; x < w; x++ )
+            {
+                // RGB order is reversed, and we need to premultiply
+                // all channels by alpha value for use with ::AlphaBlend.
+                const unsigned char a = *alpha++;
+                *dst++ = (unsigned char)((src[2] * a + 127) / 255);
+                *dst++ = (unsigned char)((src[1] * a + 127) / 255);
+                *dst++ = (unsigned char)((src[0] * a + 127) / 255);
+                *dst++ = a;
+                src += 3;
+            }
+        }
+        else // no alpha channel
+        {
+            for ( int x = 0; x < w; x++ )
+            {
+                // RGB order is reversed.
+                *dst++ = src[2];
+                *dst++ = src[1];
+                *dst++ = src[0];
+                src += 3;
+            }
+        }
+
+        // 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;
+}
 
-    HANDLE dibHandle = wxBitmapToDIB((HBITMAP) bitmap->GetHBITMAP(), hPalette);
-    if (dibHandle)
+wxImage wxDIB::ConvertToImage() const
+{
+    wxCHECK_MSG( IsOk(), wxNullImage,
+                    wxT("can't convert invalid DIB to wxImage") );
+
+    // create the wxImage object
+    const int w = GetWidth();
+    const int h = GetHeight();
+    wxImage image(w, h, false /* don't bother clearing memory */);
+    if ( !image.Ok() )
+    {
+        wxFAIL_MSG( wxT("could not allocate data for image") );
+        return wxNullImage;
+    }
+
+    if ( m_hasAlpha )
+    {
+        image.SetAlpha();
+    }
+
+    // this is the same loop as in Create() just above but with copy direction
+    // reversed
+    const int bpp = GetDepth();
+    const int dstBytesPerLine = w * 3;
+    const int srcBytesPerLine = GetLineSize(w, bpp);
+    unsigned char *dst = image.GetData() + ((h - 1) * dstBytesPerLine);
+    unsigned char *alpha = image.HasAlpha() ? image.GetAlpha() + (h - 1)*w
+                                            : NULL;
+    const bool is32bit = bpp == 32;
+    const unsigned char *srcLineStart = (unsigned char *)GetData();
+    for ( int y = 0; y < h; y++ )
     {
-        bool success = (WriteDIB(filename, dibHandle) != 0);
-        GlobalFree(dibHandle);
-        return success;
+        // copy one DIB line
+        const unsigned char *src = srcLineStart;
+        for ( int x = 0; x < w; x++ )
+        {
+            dst[2] = *src++;
+            dst[1] = *src++;
+            dst[0] = *src++;
+
+            if ( is32bit )
+            {
+                if ( alpha )
+                {
+                    // wxImage uses non premultiplied alpha so undo
+                    // premultiplication done in Create() above
+                    const unsigned char a = *src;
+                    *alpha++ = a;
+                    if ( a > 0 )
+                    {
+                        dst[0] = (dst[0] * 255) / a;
+                        dst[1] = (dst[1] * 255) / a;
+                        dst[2] = (dst[2] * 255) / a;
+                    }
+                }
+
+                src++;
+            }
+
+            dst += 3;
+        }
+
+        // pass to the previous line in the image
+        dst -= 2*dstBytesPerLine;
+        if ( alpha )
+            alpha -= 2*w;
+
+        // and to the next one in the DIB
+        srcLineStart += srcBytesPerLine;
     }
-        else return FALSE;
+
+    return image;
 }
 
+#endif // wxUSE_IMAGE
 
+#endif // wxUSE_WXDIB