// Author: Vadim Zeitlin
// Modified by:
// Created: 03.03.03 (replaces the old file with the same name)
-// RCS-ID: $Id$
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
-// License: wxWindows licence
+// Licence: 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
// ============================================================================
#pragma hdrstop
#endif
+#if wxUSE_WXDIB
+
#ifndef WX_PRECOMP
#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/image.h"
+#include "wx/file.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <memory.h>
#include "wx/msw/dib.h"
+#ifdef __WXWINCE__
+ #include <shellapi.h> // for SHLoadDIBitmap()
+#endif
+
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+// 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);
+}
+
+// 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
// ============================================================================
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;
- info->bmiHeader.biHeight = -height;
- info->bmiHeader.biPlanes = 1;
- info->bmiHeader.biBitCount = depth;
- info->bmiHeader.biCompression = BI_RGB;
- info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
+ // we don't support formats using palettes right now so we only create
+ // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
+ wxASSERT_MSG( depth, wxT("invalid image depth in wxDIB::Create()") );
+ if ( depth < 24 )
+ depth = 24;
+
+ // allocate memory for bitmap structures
+ BITMAPINFO info;
+ wxZeroMemory(info);
+
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ 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;
- // No need to report an error here. If it fails, we just won't use a
- // file mapping and CreateDIBSection will just allocate memory for us.
m_handle = ::CreateDIBSection
(
0, // hdc (unused with DIB_RGB_COLORS)
- info, // bitmap description
+ &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 true;
}
-// ----------------------------------------------------------------------------
-// wxDIB accessors
-// ----------------------------------------------------------------------------
-
-void wxDIB::DoGetObject() const
+bool wxDIB::Create(HBITMAP hbmp)
{
- // only do something if we have a valid DIB but we don't [yet] have valid
- // data
- if ( m_handle && !m_data )
+ wxCHECK_MSG( hbmp, false, wxT("wxDIB::Create(): invalid bitmap") );
+
+ // 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) )
{
- // 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)"));
+ m_handle = hbmp;
- return;
- }
+ // wxBitmap will free it, not we
+ m_ownsHandle = false;
- wxDIB *self = wxConstCast(this, wxDIB);
+ // 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;
- self->m_width = ds.dsBm.bmWidth;
- self->m_height = ds.dsBm.bmHeight;
- self->m_depth = ds.dsBm.bmBitsPixel;
- self->m_data = ds.dsBm.bmBits;
+ m_data = ds.dsBm.bmBits;
}
-}
-
-// ----------------------------------------------------------------------------
-// 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 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++ )
+ else // no, it's a DDB -- convert it to DIB
{
- // copy one DIB line
- unsigned char *dst = dstLineStart;
- for ( int x = 0; x < w; x++ )
+ // prepare all the info we need
+ BITMAP bm;
+ if ( !::GetObject(hbmp, sizeof(bm), &bm) )
{
- // also, the order of RGB is inversed for DIBs
- *dst++ = src[2];
- *dst++ = src[1];
- *dst++ = src[0];
+ wxLogLastError(wxT("GetObject(bitmap)"));
- src += 3;
-
- if ( alpha )
- *dst++ = *alpha++;
+ return false;
}
- // pass to the previous line in the image
- src -= 2*srcBytesPerLine;
- if ( alpha )
- alpha -= 2*w;
+ int d = bm.bmBitsPixel;
+ if ( d <= 0 )
+ d = wxDisplayDepth();
- // and to the next one in the DIB
- dstLineStart += dstBytesPerLine;
+ if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) )
+ return false;
}
return true;
}
-#endif // wxUSE_IMAGE
-
-// ============================================================================
-// old DIB code, to be integrated in wxDIB class
-// ============================================================================
-
-/*******************************************************************************
- * *
- * MODULE : DIB.CC *
- * *
- * DESCRIPTION : Routines for dealing with Device Independent Bitmaps. *
- * *
- * 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 *
- * *
- *******************************************************************************/
-
-// For compilers that support precompilation, includes "wx.h".
-#include "wx/wxprec.h"
+// 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__
-#if defined(__BORLANDC__)
-#pragma hdrstop
-#endif
+bool wxDIB::CopyFromDDB(HBITMAP hbmp)
+{
+ MemoryHDC hdcSrc;
+ if ( !hdcSrc )
+ return false;
-#ifndef WX_PRECOMP
-#include "wx/bitmap.h"
-#include "wx/log.h"
-#include "wx/intl.h"
-#endif
+ SelectInHDC selectSrc(hdcSrc, hbmp);
+ if ( !selectSrc )
+ return false;
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
+ MemoryHDC hdcDst;
+ if ( !hdcDst )
+ return false;
-#if !defined(__MWERKS__) && !defined(__SALFORDC__)
-#include <memory.h>
-#endif
+ SelectInHDC selectDst(hdcDst, m_handle);
+ if ( !selectDst )
+ return false;
-#include "wx/msw/dib.h"
-#ifdef __GNUWIN32_OLD__
- #include "wx/msw/gnuwin32/extra.h"
-#endif
+ if ( !::BitBlt(
+ hdcDst,
+ 0, 0, m_width, m_height,
+ hdcSrc,
+ 0, 0,
+ SRCCOPY
+ ) )
+ {
+ wxLogLastError(wxT("BitBlt(DDB -> DIB)"));
-#ifndef SEEK_CUR
-/* flags for _lseek */
-#define SEEK_CUR 1
-#define SEEK_END 2
-#define SEEK_SET 0
-#endif
+ return false;
+ }
-#define MAXREAD 32768 /* Number of bytes to be read during */
- /* each read operation. */
+ return true;
+}
-/* Header signatutes for various resources */
-#define BFT_ICON 0x4349 /* 'IC' */
-#define BFT_BITMAP 0x4d42 /* 'BM' */
-#define BFT_CURSOR 0x5450 /* 'PT(' */
+#else // !__WXWINCE__
-/* macro to determine if resource is a DIB */
-#define ISDIB(bft) ((bft) == BFT_BITMAP)
+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( wxT("GetObject(DIBSECTION) unexpectedly failed") );
-/* Macro to align given value to the closest DWORD (unsigned long ) */
-#define ALIGNULONG(i) ((i+3)/4*4)
+ return false;
+ }
-/* Macro to determine to round off the given value to the closest byte */
-#define WIDTHBYTES(i) ((i+31)/32*4)
+ 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()"));
-#define PALVERSION 0x300
-#define MAXPALETTE 256 /* max. # supported palette entries */
+ return false;
+ }
-static DWORD PASCAL lread(int fh, VOID FAR *pv, DWORD ul);
-static DWORD PASCAL lwrite(int fh, VOID FAR *pv, DWORD ul);
+ return true;
+}
-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 *);
+#endif // __WXWINCE__/!__WXWINCE__
-/****************************************************************************
- * *
- * FUNCTION : WriteDIB(LPSTR szFile,HANDLE hdib) *
- * *
- * PURPOSE : Write a global handle in CF_DIB format to a file. *
- * *
- * RETURNS : TRUE - if successful. *
- * FALSE - otherwise *
- * *
- ****************************************************************************/
+// ----------------------------------------------------------------------------
+// Loading/saving the DIBs
+// ----------------------------------------------------------------------------
-static BOOL WriteDIB(LPTSTR szFile, HANDLE hdib)
+bool wxDIB::Load(const wxString& filename)
{
- BITMAPFILEHEADER hdr;
- LPBITMAPINFOHEADER lpbi;
- int fh;
- OFSTRUCT of;
+#ifdef __WXWINCE__
+ m_handle = SHLoadDIBitmap(filename);
+#else // !__WXWINCE__
+ m_handle = (HBITMAP)::LoadImage
+ (
+ wxGetInstance(),
+ filename.t_str(),
+ IMAGE_BITMAP,
+ 0, 0, // don't specify the size
+ LR_CREATEDIBSECTION | LR_LOADFROMFILE
+ );
+#endif // __WXWINCE__
- if (!hdib)
- return FALSE;
+ if ( !m_handle )
+ {
+ wxLogLastError(wxT("Loading DIB from file"));
- fh = OpenFile(wxConvertWX2MB(szFile), &of, OF_CREATE | OF_READWRITE);
- if (fh == -1)
- return FALSE;
+ 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::Save(const wxString& filename)
{
- LPBITMAPINFOHEADER lpbi;
- WORD NumColors;
-
- lpbi = (LPBITMAPINFOHEADER) pv;
- NumColors = DibNumColors(lpbi);
-
- if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
- return (WORD)(NumColors * sizeof(RGBTRIPLE));
- else
- return (WORD)(NumColors * sizeof(RGBQUAD));
-}
+ wxCHECK_MSG( m_handle, false, wxT("wxDIB::Save(): invalid object") );
-/****************************************************************************
- * *
- * 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;
- }
+#if wxUSE_FILE
+ wxFile file(filename, wxFile::write);
+ bool ok = file.IsOpened();
+ if ( ok )
+ {
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &ds) )
+ {
+ wxLogLastError(wxT("GetObject(hDIB)"));
+ }
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;
- }
-}
-
-/****************************************************************************
- * *
- * 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)
-{
- 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);
-
- GetObject(hbm, sizeof (bm), (LPSTR) &bm);
-
- if (biBits == 0)
- biBits = bm.bmPlanes * bm.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;
-
- dwLen = bi.biSize + wxPaletteSize(&bi);
-
- hdc = GetDC((HWND) NULL);
- hpal = SelectPalette(hdc, hpal, FALSE);
- RealizePalette(hdc);
-
- hdib = GlobalAlloc(GHND, dwLen);
-
- if (!hdib) {
- SelectPalette(hdc, hpal, FALSE);
- ReleaseDC(NULL, hdc);
- return NULL;
- }
-
-#ifdef __WINDOWS_386__
- lpbi = (BITMAPINFOHEADER FAR *) MK_FP32(GlobalLock(hdib));
-#else
- lpbi = (BITMAPINFOHEADER FAR *) GlobalLock(hdib);
-#endif
-
- *lpbi = bi;
-
- /* 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);
-
- /* 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;
- }
-
- /* 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;
- }
+ {
+ BITMAPFILEHEADER bmpHdr;
+ wxZeroMemory(bmpHdr);
- /* call GetDIBits with a NON-NULL lpBits param, and actualy get the
- * bits this time
- */
-#ifdef __WINDOWS_386__
- lpbi = (BITMAPINFOHEADER FAR *) MK_FP32(GlobalLock(hdib));
-#else
- lpbi = (BITMAPINFOHEADER FAR *) GlobalLock(hdib);
-#endif
+ const size_t sizeHdr = ds.dsBmih.biSize;
+ const size_t sizeImage = ds.dsBmih.biSizeImage;
- 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;
- }
+ bmpHdr.bfType = 0x4d42; // 'BM' in little endian
+ bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
+ bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
- bi = *lpbi;
- GlobalUnlock(hdib);
+ // 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 // !wxUSE_FILE
+ bool ok = false;
+#endif // wxUSE_FILE/!wxUSE_FILE
- SelectPalette(hdc, hpal, FALSE);
- ReleaseDC(NULL, hdc);
- return hdib;
-}
-#endif
+ if ( !ok )
+ {
+ wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
+ filename.c_str());
+ }
- /************* PRIVATE ROUTINES TO READ/WRITE MORE THAN 64K ***************/
-/****************************************************************************
- * *
- * FUNCTION : lread(int fh, VOID FAR *pv, DWORD ul) *
- * *
- * PURPOSE : Reads data in steps of 32k till all the data has been read.*
- * *
- * RETURNS : 0 - If read did not proceed correctly. *
- * number of bytes read otherwise. *
- * *
- ****************************************************************************/
-
-static DWORD PASCAL lread(int fh, void far *pv, DWORD ul)
-{
- DWORD ulT = ul;
-#if defined(WINNT) || defined(__WIN32__) || defined(__WIN32__)
- BYTE *hp = (BYTE *) pv;
-#else
- BYTE huge *hp = (BYTE huge *) pv;
-#endif
- while (ul > (DWORD) MAXREAD) {
- if (_lread(fh, (LPSTR) hp, (WORD) MAXREAD) != MAXREAD)
- return 0;
- ul -= MAXREAD;
- hp += MAXREAD;
- }
- if (_lread(fh, (LPSTR) hp, (WXUINT) ul) != (WXUINT) ul)
- return 0;
- return ulT;
+ return ok;
}
-/****************************************************************************
- * *
- * 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. *
- * *
- ****************************************************************************/
-
-static DWORD PASCAL lwrite(int fh, VOID FAR *pv, DWORD ul)
-{
- DWORD ulT = ul;
-#if defined(WINNT) || defined(__WIN32__) || defined(__WIN32__)
- 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;
-}
+// ----------------------------------------------------------------------------
+// wxDIB accessors
+// ----------------------------------------------------------------------------
-/****************************************************************************
- *
- * 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)
+void wxDIB::DoGetObject() const
{
- int fh;
- LPBITMAPINFOHEADER lpbi;
- OFSTRUCT of;
- BITMAPFILEHEADER bf;
- WORD nNumColors;
- BOOL result = FALSE;
- WORD offBits;
- HDC hDC;
- BOOL bCoreHead = FALSE;
- HANDLE hDIB = 0;
-
- /* Open the file and get a handle to it's BITMAPINFO */
-
- fh = OpenFile (wxConvertWX2MB(lpFileName), &of, OF_READ);
- if (fh == -1) {
- wxLogError(_("Can't open file '%s'"), lpFileName);
- return (0);
- }
+ // 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(wxT("GetObject(hDIB)"));
+ return;
+ }
- hDIB = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER) +
- 256 * sizeof(RGBQUAD)));
- if (!hDIB)
- return(0);
+ wxDIB *self = wxConstCast(this, wxDIB);
-#ifdef __WINDOWS_386__
- lpbi = (LPBITMAPINFOHEADER)MK_FP32(GlobalLock(hDIB));
-#else
- lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
-#endif
+ self->m_width = ds.dsBm.bmWidth;
+ self->m_height = ds.dsBm.bmHeight;
+ self->m_depth = ds.dsBm.bmBitsPixel;
+ self->m_data = ds.dsBm.bmBits;
+ }
+}
- /* read the BITMAPFILEHEADER */
- if (sizeof (bf) != _lread (fh, (LPSTR)&bf, sizeof (bf)))
- goto ErrExit;
+// ----------------------------------------------------------------------------
+// DDB <-> DIB conversions
+// ----------------------------------------------------------------------------
- if (bf.bfType != 0x4d42) /* 'BM' */
- goto ErrExit;
+#ifndef __WXWINCE__
- if (sizeof(BITMAPCOREHEADER) != _lread (fh, (LPSTR)lpbi, sizeof(BITMAPCOREHEADER)))
- goto ErrExit;
+HBITMAP wxDIB::CreateDDB(HDC hdc) const
+{
+ wxCHECK_MSG( m_handle, 0, wxT("wxDIB::CreateDDB(): invalid object") );
- if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &ds) )
{
- 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;
+ wxLogLastError(wxT("GetObject(hDIB)"));
+
+ return 0;
}
- else
+
+ // how many colours are we going to have in the palette?
+ DWORD biClrUsed = ds.dsBmih.biClrUsed;
+ if ( !biClrUsed )
{
- // get to the start of the header and read INFOHEADER
- _llseek(fh,sizeof(BITMAPFILEHEADER),SEEK_SET);
- if (sizeof(BITMAPINFOHEADER) != _lread (fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
- goto ErrExit;
+ // biClrUsed field might not be set
+ biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
}
- nNumColors = (WORD)lpbi->biClrUsed;
- if ( nNumColors == 0 )
+ if ( !biClrUsed )
{
- /* no color table for 24-bit, default size otherwise */
- if (lpbi->biBitCount != 24)
- nNumColors = 1 << lpbi->biBitCount; /* standard size table */
+ return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
}
-
- /* fill in some default values if they are zero */
- if (lpbi->biClrUsed == 0)
- lpbi->biClrUsed = nNumColors;
-
- if (lpbi->biSizeImage == 0)
+ else
{
- lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
- * lpbi->biHeight;
+ // 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);
}
+}
- /* get a proper-sized buffer for header, color table and bits */
- GlobalUnlock(hDIB);
- hDIB = GlobalReAlloc(hDIB, lpbi->biSize +
- nNumColors * sizeof(RGBQUAD) +
- lpbi->biSizeImage, 0);
- if (!hDIB) /* can't resize buffer for loading */
- goto ErrExit2;
+/* static */
+HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
+{
+ wxCHECK_MSG( pbmi, 0, wxT("invalid DIB in ConvertToBitmap") );
-#ifdef __WINDOWS_386__
- lpbi = (LPBITMAPINFOHEADER)MK_FP32(GlobalLock(hDIB));
-#else
- lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
-#endif
+ // 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;
- /* read the color table */
- if (!bCoreHead)
- _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
- 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 )
{
- signed int i;
- RGBQUAD FAR *pQuad;
- RGBTRIPLE FAR *pTriple;
-
- _lread(fh, (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--)
+ // 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 )
{
- pQuad[i].rgbRed = pTriple[i].rgbtRed;
- pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
- pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
- pQuad[i].rgbReserved = 0;
+ 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;
}
- }
- /* offset to the bits from start of DIB header */
- offBits = (WORD)(lpbi->biSize + nNumColors * sizeof(RGBQUAD));
+ bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
+ }
- if (bf.bfOffBits != 0L)
+ 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 )
{
- _llseek(fh,bf.bfOffBits,SEEK_SET);
+ wxLogLastError(wxT("CreateDIBitmap"));
}
- if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
+ 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) )
{
- GlobalUnlock(hDIB);
+ wxLogLastError(wxT("GetObject(bitmap)"));
- hDC = GetDC(NULL);
- if (!MakeBitmapAndPalette(hDC, hDIB, palette,
- bitmap))
- {
- ReleaseDC(NULL,hDC);
- goto ErrExit2;
- }
- else
- {
- ReleaseDC(NULL,hDC);
- GlobalFree(hDIB);
- result = TRUE;
- }
+ return 0;
}
- else
+
+ // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
+ // use this one
+ BITMAPINFO bi2;
+
+ const 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 = 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
+ ) )
{
-ErrExit:
- GlobalUnlock(hDIB);
-ErrExit2:
- GlobalFree(hDIB);
+ wxLogLastError(wxT("GetDIBits()"));
+
+ return 0;
}
- _lclose(fh);
- return(result);
+ // return the total size
+ return dwLen + bi.biSizeImage;
}
-/****************************************************************************
- *
- * 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 */
+HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
{
- 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
+ // first calculate the size needed
+ const size_t size = ConvertFromBitmap(NULL, hbmp);
+ if ( !size )
+ {
+ // conversion to DDB failed?
+ return NULL;
+ }
- hPalette = wxMakeDIBPalette(lpInfo);
- if ( hPalette )
+ HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
+ if ( !hDIB )
{
- // Need to realize palette for converting DIB to bitmap.
- hOldPal = SelectPalette(hDC, hPalette, TRUE);
- RealizePalette(hDC);
+ // 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 allocate %luKb of memory for bitmap data."),
+ (unsigned long)(size / 1024));
- lpBits = (LPSTR)lpInfo + (WORD)lpInfo->biSize +
- (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD);
- hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
- (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
+ return NULL;
+ }
- SelectPalette(hDC, hOldPal, TRUE);
- RealizePalette(hDC);
+ if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) )
+ {
+ // this really shouldn't happen... it worked the first time, why not
+ // now?
+ wxFAIL_MSG( wxT("wxDIB::ConvertFromBitmap() unexpectedly failed") );
- if (!hBitmap)
- DeleteObject(hPalette);
- else
- {
- *phBitmap = hBitmap;
- *phPal = hPalette;
- result = TRUE;
- }
+ return NULL;
}
- GlobalUnlock (hDIB); // glt
-
- return(result);
+ return hDIB;
}
-/****************************************************************************
- * *
- * 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)
+#endif // __WXWINCE__
+
+// ----------------------------------------------------------------------------
+// palette support
+// ----------------------------------------------------------------------------
+
+#if wxUSE_PALETTE
+
+wxPalette *wxDIB::CreatePalette() const
{
- 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)
+ // GetDIBColorTable not available in eVC3
+#if !defined(__WXMSW__) || defined(_WIN32_WCE) && _WIN32_WCE < 400
+ return NULL;
+#else
+ wxCHECK_MSG( m_handle, NULL, wxT("wxDIB::CreatePalette(): invalid object") );
+
+ DIBSECTION ds;
+ if ( !GetDIBSection(m_handle, &ds) )
{
-/*
- 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 NULL;
-
- 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(hDIB)"));
- hLogPal = CreatePalette((LPLOGPALETTE)npPal);
-// LocalFree((HANDLE)npPal);
- free(npPal);
+ return 0;
+ }
- return(hLogPal);
+ // 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);
}
- /* 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));
-}
+ 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;
+ }
-bool wxLoadIntoBitmap(wxChar *filename, wxBitmap *bitmap, wxPalette **pal)
-{
- HBITMAP hBitmap = NULL;
- HPALETTE hPalette = NULL;
+ MemoryHDC hDC;
- bool success = (wxReadDIB(filename, &hBitmap, &hPalette) != 0);
+ // 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, wxT("out of memory") );
- if (!success)
- {
- if (hPalette)
- DeleteObject(hPalette);
- return FALSE;
- }
+ // initialize the palette header
+ pPalette->palVersion = 0x300; // magic number, not in docs but works
+ pPalette->palNumEntries = (WORD)biClrUsed;
- if (hPalette)
- {
-#if wxUSE_PALETTE
- if (pal)
+ // 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++ )
{
- *pal = new wxPalette;
- (*pal)->SetHPALETTE((WXHPALETTE) hPalette);
+ pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
+ pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
+ pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
+ pPalette->palPalEntry[i].peFlags = 0;
}
- else
-#endif // wxUSE_PALETTE
- DeleteObject(hPalette);
- }
- else if (pal)
- *pal = NULL;
- if (hBitmap)
- {
- 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;
- }
- else return FALSE;
-}
-
-wxBitmap *wxLoadBitmap(wxChar *filename, wxPalette **pal)
-{
- wxBitmap *bitmap = new wxBitmap;
- if (wxLoadIntoBitmap(filename, bitmap, pal))
- return bitmap;
- else
- {
- delete bitmap;
- 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
-//
-//---------------------------------------------------------------------
+ HPALETTE hPalette = ::CreatePalette(pPalette);
-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;
-}
+ free(pPalette);
+ if ( !hPalette )
+ {
+ wxLogLastError(wxT("CreatePalette"));
+ return NULL;
+ }
+ wxPalette *palette = new wxPalette;
+ palette->SetHPALETTE((WXHPALETTE)hPalette);
-LPSTR wxFindDIBBits (LPSTR lpbi)
-{
- return (lpbi + *(LPDWORD)lpbi + wxPaletteSize (lpbi));
+ return palette;
+#endif
}
-//---------------------------------------------------------------------
-//
-// 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
-//
-//---------------------------------------------------------------------
+#endif // wxUSE_PALETTE
-HANDLE wxBitmapToDIB (HBITMAP hBitmap, HPALETTE hPal)
-{
- BITMAP Bitmap;
- BITMAPINFOHEADER bmInfoHdr;
- LPBITMAPINFOHEADER lpbmInfoHdr;
- LPSTR lpBits;
- HDC hMemDC;
- HANDLE hDIB;
- HPALETTE hOldPal = NULL;
+// ----------------------------------------------------------------------------
+// wxImage support
+// ----------------------------------------------------------------------------
- // 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 wxUSE_IMAGE
- if (!hBitmap)
- return NULL;
+bool wxDIB::Create(const wxImage& image, PixelFormat pf)
+{
+ wxCHECK_MSG( image.IsOk(), false, wxT("invalid wxImage in wxDIB ctor") );
- if (!GetObject (hBitmap, sizeof (Bitmap), (LPSTR) &Bitmap))
- return NULL;
+ const int h = image.GetHeight();
+ const int w = image.GetWidth();
- InitBitmapInfoHeader (&bmInfoHdr,
- Bitmap.bmWidth,
- Bitmap.bmHeight,
- Bitmap.bmPlanes * Bitmap.bmBitsPixel);
+ // 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;
- // Now allocate memory for the DIB. Then, set the BITMAPINFOHEADER
- // into this memory, and find out where the bitmap bits go.
+ // 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. Note that RGB components order is reversed in
+ // Windows bitmaps compared to wxImage and is actually BGR.
+ unsigned char *dst = dstLineStart;
+ if ( alpha )
+ {
+ int x;
+
+ switch ( pf )
+ {
+ case PixelFormat_PreMultiplied:
+ // Pre-multiply pixel values so that the DIB could be used
+ // with ::AlphaBlend().
+ for ( x = 0; x < w; x++ )
+ {
+ 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;
+ }
+ break;
+
+ case PixelFormat_NotPreMultiplied:
+ // Just copy pixel data without changing it.
+ for ( x = 0; x < w; x++ )
+ {
+ *dst++ = src[2];
+ *dst++ = src[1];
+ *dst++ = src[0];
+
+ *dst++ = *alpha++;
+ src += 3;
+ }
+ break;
+ }
- hDIB = GlobalAlloc (GHND, sizeof (BITMAPINFOHEADER) +
- wxPaletteSize ((LPSTR) &bmInfoHdr) + bmInfoHdr.biSizeImage);
+ }
+ else // no alpha channel
+ {
+ for ( int x = 0; x < w; x++ )
+ {
+ *dst++ = src[2];
+ *dst++ = src[1];
+ *dst++ = src[0];
+ src += 3;
+ }
+ }
- if (!hDIB)
- return NULL;
+ // pass to the previous line in the image
+ src -= 2*srcBytesPerLine;
+ if ( alpha )
+ alpha -= 2*w;
-#ifdef __WINDOWS_386__
- lpbmInfoHdr = (LPBITMAPINFOHEADER) MK_FP32(GlobalLock (hDIB));
-#else
- lpbmInfoHdr = (LPBITMAPINFOHEADER) GlobalLock (hDIB);
-#endif
+ // and to the next one in the DIB
+ dstLineStart += dstBytesPerLine;
+ }
- *lpbmInfoHdr = bmInfoHdr;
- lpBits = wxFindDIBBits ((LPSTR) lpbmInfoHdr);
+ return true;
+}
+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.IsOk() )
+ {
+ wxFAIL_MSG( wxT("could not allocate data for image") );
+ return wxNullImage;
+ }
- // Now, we need a DC to hold our bitmap. If the app passed us
- // a palette, it should be selected into the DC.
+ const int bpp = GetDepth();
- hMemDC = GetDC (NULL);
+ // Remember if we have any "real" transparency, i.e. either any partially
+ // transparent pixels or not all pixels are fully opaque or fully
+ // transparent.
+ bool hasAlpha = false;
+ bool hasOpaque = false;
+ bool hasTransparent = false;
- if (hPal)
- {
- hOldPal = SelectPalette (hMemDC, hPal, FALSE);
- RealizePalette (hMemDC);
- }
+ if ( bpp == 32 )
+ {
+ // 32 bit bitmaps may be either 0RGB or ARGB and we don't know in
+ // advance which one do we have so suppose we have alpha of them and
+ // get rid of it later if it turns out we didn't.
+ image.SetAlpha();
+ }
+ // this is the same loop as in Create() just above but with copy direction
+ // reversed
+ 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 unsigned char *srcLineStart = (unsigned char *)GetData();
+ for ( int y = 0; y < h; y++ )
+ {
+ // 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 ( bpp == 32 )
+ {
+ // wxImage uses non premultiplied alpha so undo
+ // premultiplication done in Create() above
+ const unsigned char a = *src;
+ *alpha++ = a;
+
+ // Check what kind of alpha do we have.
+ switch ( a )
+ {
+ case 0:
+ hasTransparent = true;
+ break;
+
+ default:
+ // Anything in between means we have real transparency
+ // and must use alpha channel.
+ hasAlpha = true;
+ break;
+
+ case 255:
+ hasOpaque = true;
+ break;
+ }
+ if ( a > 0 )
+ {
+ dst[0] = (dst[0] * 255) / a;
+ dst[1] = (dst[1] * 255) / a;
+ dst[2] = (dst[2] * 255) / a;
+ }
- // 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.
+ src++;
+ }
- if (!GetDIBits (hMemDC,
- hBitmap,
- 0,
- Bitmap.bmHeight,
- lpBits,
- (LPBITMAPINFO) lpbmInfoHdr,
- DIB_RGB_COLORS))
- {
- GlobalUnlock (hDIB);
- GlobalFree (hDIB);
- hDIB = NULL;
- }
- else
- GlobalUnlock (hDIB);
+ dst += 3;
+ }
+ // pass to the previous line in the image
+ dst -= 2*dstBytesPerLine;
+ if ( alpha )
+ alpha -= 2*w;
- // Finally, clean up and return.
+ // and to the next one in the DIB
+ srcLineStart += srcBytesPerLine;
+ }
- if (hOldPal)
- SelectPalette (hMemDC, hOldPal, FALSE);
+ if ( hasOpaque && hasTransparent )
+ hasAlpha = true;
- ReleaseDC (NULL, hMemDC);
+ if ( !hasAlpha && image.HasAlpha() )
+ image.ClearAlpha();
- return hDIB;
+ return image;
}
-bool wxSaveBitmap(wxChar *filename, wxBitmap *bitmap, wxPalette *colourmap)
-{
- HPALETTE hPalette = 0;
-#if wxUSE_PALETTE
- if (colourmap)
- hPalette = (HPALETTE) colourmap->GetHPALETTE();
-#endif // wxUSE_PALETTE
-
- HANDLE dibHandle = wxBitmapToDIB((HBITMAP) bitmap->GetHBITMAP(), hPalette);
- if (dibHandle)
- {
- bool success = (WriteDIB(filename, dibHandle) != 0);
- GlobalFree(dibHandle);
- return success;
- }
- else return FALSE;
-}
+#endif // wxUSE_IMAGE
+#endif // wxUSE_WXDIB