1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dib.cpp
3 // Purpose: implements wxDIB class
4 // Author: Vadim Zeitlin
6 // Created: 03.03.03 (replaces the old file with the same name)
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 TODO: support for palettes is very incomplete, several functions simply
14 ignore them (we should select and realize the palette, if any, before
15 caling GetDIBits() in the DC we use with it.
18 // ============================================================================
20 // ============================================================================
22 // ----------------------------------------------------------------------------
24 // ----------------------------------------------------------------------------
26 // For compilers that support precompilation, includes "wx.h".
27 #include "wx/wxprec.h"
36 #include "wx/string.h"
39 #include "wx/bitmap.h"
50 #include "wx/msw/dib.h"
53 #include <shellapi.h> // for SHLoadDIBitmap()
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // calculate the number of palette entries needed for the bitmap with this
61 // number of bits per pixel
62 static inline WORD
GetNumberOfColours(WORD bitsPerPixel
)
64 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
65 // 24bpp ones too but we don't support this as I think it's quite uncommon)
66 return (WORD
)(bitsPerPixel
<= 8 ? 1 << bitsPerPixel
: 0);
69 // wrapper around ::GetObject() for DIB sections
70 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION
*ds
)
72 // note that at least under Win9x (this doesn't seem to happen under Win2K
73 // but this doesn't mean anything, of course), GetObject() may return
74 // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
75 // to check for it is by looking at the bits pointer
76 return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) &&
80 // ============================================================================
82 // ============================================================================
84 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
88 bool wxDIB::Create(int width
, int height
, int depth
)
90 // we don't support formats using palettes right now so we only create
91 // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
92 wxASSERT_MSG( depth
, wxT("invalid image depth in wxDIB::Create()") );
96 // allocate memory for bitmap structures
100 info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
101 info
.bmiHeader
.biWidth
= width
;
103 // we use positive height here which corresponds to a DIB with normal, i.e.
104 // bottom to top, order -- normally using negative height (which means
105 // reversed for MS and hence natural for all the normal people top to
106 // bottom line scan order) could be used to avoid the need for the image
107 // reversal in Create(image) but this doesn't work under NT, only Win9x!
108 info
.bmiHeader
.biHeight
= height
;
110 info
.bmiHeader
.biPlanes
= 1;
111 info
.bmiHeader
.biBitCount
= (WORD
)depth
;
112 info
.bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
114 m_handle
= ::CreateDIBSection
116 0, // hdc (unused with DIB_RGB_COLORS)
117 &info
, // bitmap description
118 DIB_RGB_COLORS
, // use RGB, not palette
119 &m_data
, // [out] DIB bits
120 NULL
, // don't use file mapping
121 0 // file mapping offset (not used here)
126 wxLogLastError(wxT("CreateDIBSection"));
138 bool wxDIB::Create(HBITMAP hbmp
)
140 wxCHECK_MSG( hbmp
, false, wxT("wxDIB::Create(): invalid bitmap") );
142 // this bitmap could already be a DIB section in which case we don't need
143 // to convert it to DIB
145 if ( GetDIBSection(hbmp
, &ds
) )
149 // wxBitmap will free it, not we
150 m_ownsHandle
= false;
152 // copy all the bitmap parameters too as we have them now anyhow
153 m_width
= ds
.dsBm
.bmWidth
;
154 m_height
= ds
.dsBm
.bmHeight
;
155 m_depth
= ds
.dsBm
.bmBitsPixel
;
157 m_data
= ds
.dsBm
.bmBits
;
159 else // no, it's a DDB -- convert it to DIB
161 // prepare all the info we need
163 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
165 wxLogLastError(wxT("GetObject(bitmap)"));
170 int d
= bm
.bmBitsPixel
;
172 d
= wxDisplayDepth();
174 if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) )
181 // Windows CE doesn't have GetDIBits() so use an alternative implementation
184 // in fact I'm not sure if GetDIBits() is really much better than using
185 // BitBlt() like this -- it should be faster but I didn't do any tests, if
186 // anybody has time to do them and by chance finds that GetDIBits() is not
187 // much faster than BitBlt(), we could always use the Win CE version here
190 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
196 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
204 SelectInHDC
selectDst(hdcDst
, m_handle
);
211 0, 0, m_width
, m_height
,
217 wxLogLastError(wxT("BitBlt(DDB -> DIB)"));
225 #else // !__WXWINCE__
227 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
230 if ( !GetDIBSection(m_handle
, &ds
) )
232 // we're sure that our handle is a DIB section, so this should work
233 wxFAIL_MSG( wxT("GetObject(DIBSECTION) unexpectedly failed") );
240 ScreenHDC(), // the DC to use
241 hbmp
, // the source DDB
242 0, // first scan line
243 m_height
, // number of lines to copy
244 ds
.dsBm
.bmBits
, // pointer to the buffer
245 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
246 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
249 wxLogLastError(wxT("GetDIBits()"));
257 #endif // __WXWINCE__/!__WXWINCE__
259 // ----------------------------------------------------------------------------
260 // Loading/saving the DIBs
261 // ----------------------------------------------------------------------------
263 bool wxDIB::Load(const wxString
& filename
)
266 m_handle
= SHLoadDIBitmap(filename
);
267 #else // !__WXWINCE__
268 m_handle
= (HBITMAP
)::LoadImage
273 0, 0, // don't specify the size
274 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
276 #endif // __WXWINCE__
280 wxLogLastError(wxT("Loading DIB from file"));
288 bool wxDIB::Save(const wxString
& filename
)
290 wxCHECK_MSG( m_handle
, false, wxT("wxDIB::Save(): invalid object") );
293 wxFile
file(filename
, wxFile::write
);
294 bool ok
= file
.IsOpened();
298 if ( !GetDIBSection(m_handle
, &ds
) )
300 wxLogLastError(wxT("GetObject(hDIB)"));
304 BITMAPFILEHEADER bmpHdr
;
305 wxZeroMemory(bmpHdr
);
307 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
308 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
310 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
311 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
312 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
314 // first write the file header, then the bitmap header and finally the
315 // bitmap data itself
316 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
317 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
318 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
323 #endif // wxUSE_FILE/!wxUSE_FILE
327 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
334 // ----------------------------------------------------------------------------
336 // ----------------------------------------------------------------------------
338 void wxDIB::DoGetObject() const
340 // only do something if we have a valid DIB but we don't [yet] have valid
342 if ( m_handle
&& !m_data
)
344 // although all the info we need is in BITMAP and so we don't really
345 // need DIBSECTION we still ask for it as modifying the bit values only
346 // works for the real DIBs and not for the bitmaps and it's better to
347 // check for this now rather than trying to find out why it doesn't
350 if ( !GetDIBSection(m_handle
, &ds
) )
352 wxLogLastError(wxT("GetObject(hDIB)"));
356 wxDIB
*self
= wxConstCast(this, wxDIB
);
358 self
->m_width
= ds
.dsBm
.bmWidth
;
359 self
->m_height
= ds
.dsBm
.bmHeight
;
360 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
361 self
->m_data
= ds
.dsBm
.bmBits
;
365 // ----------------------------------------------------------------------------
366 // DDB <-> DIB conversions
367 // ----------------------------------------------------------------------------
371 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
373 wxCHECK_MSG( m_handle
, 0, wxT("wxDIB::CreateDDB(): invalid object") );
376 if ( !GetDIBSection(m_handle
, &ds
) )
378 wxLogLastError(wxT("GetObject(hDIB)"));
383 // how many colours are we going to have in the palette?
384 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
387 // biClrUsed field might not be set
388 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
393 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
397 // fake a BITMAPINFO w/o bits, just the palette info
398 wxCharBuffer
bmi(sizeof(BITMAPINFO
) + (biClrUsed
- 1)*sizeof(RGBQUAD
));
399 BITMAPINFO
*pBmi
= (BITMAPINFO
*)bmi
.data();
401 // get the colour table
402 SelectInHDC
sDC(hDC
, m_handle
);
403 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
);
404 memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
);
406 return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
);
411 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
413 wxCHECK_MSG( pbmi
, 0, wxT("invalid DIB in ConvertToBitmap") );
415 // here we get BITMAPINFO struct followed by the actual bitmap bits and
416 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
417 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
419 // get the pointer to the start of the real image data if we have a plain
420 // DIB and not a DIB section (in the latter case the pointer must be passed
421 // to us by the caller)
424 // we must skip over the colour table to get to the image data
426 // colour table either has the real colour data in which case its
427 // number of entries is given by biClrUsed or is used for masks to be
428 // used for extracting colour information from true colour bitmaps in
429 // which case it always have exactly 3 DWORDs
431 switch ( pbmih
->biCompression
)
438 // biClrUsed has the number of colors but it may be not initialized at
440 numColors
= pbmih
->biClrUsed
;
443 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
448 // no idea how it should be calculated for the other cases
452 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
455 HBITMAP hbmp
= ::CreateDIBitmap
457 hdc
? hdc
// create bitmap compatible
458 : (HDC
) ScreenHDC(), // with this DC
459 pbmih
, // used to get size &c
460 CBM_INIT
, // initialize bitmap bits too
461 bits
, // ... using this data
462 pbmi
, // this is used for palette only
463 DIB_RGB_COLORS
// direct or indexed palette?
468 wxLogLastError(wxT("CreateDIBitmap"));
475 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
477 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
479 // prepare all the info we need
481 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
483 wxLogLastError(wxT("GetObject(bitmap)"));
488 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
492 const bool wantSizeOnly
= pbi
== NULL
;
496 // just for convenience
497 const int h
= bm
.bmHeight
;
500 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
502 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
503 bi
.biWidth
= bm
.bmWidth
;
506 bi
.biBitCount
= bm
.bmBitsPixel
;
508 // memory we need for BITMAPINFO only
509 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
511 // get either just the image size or the image bits
514 ScreenHDC(), // the DC to use
515 hbmp
, // the source DDB
516 0, // first scan line
517 h
, // number of lines to copy
518 wantSizeOnly
? NULL
// pointer to the buffer or
519 : (char *)pbi
+ dwLen
, // NULL if we don't have it
520 pbi
, // bitmap header
521 DIB_RGB_COLORS
// or DIB_PAL_COLORS
524 wxLogLastError(wxT("GetDIBits()"));
529 // return the total size
530 return dwLen
+ bi
.biSizeImage
;
534 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
536 // first calculate the size needed
537 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
540 // conversion to DDB failed?
544 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
547 // this is an error which does risk to happen especially under Win9x
548 // and which the user may understand so let him know about it
549 wxLogError(_("Failed to allocate %luKb of memory for bitmap data."),
550 (unsigned long)(size
/ 1024));
555 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtrLock(hDIB
), hbmp
) )
557 // this really shouldn't happen... it worked the first time, why not
559 wxFAIL_MSG( wxT("wxDIB::ConvertFromBitmap() unexpectedly failed") );
567 #endif // __WXWINCE__
569 // ----------------------------------------------------------------------------
571 // ----------------------------------------------------------------------------
575 wxPalette
*wxDIB::CreatePalette() const
577 // GetDIBColorTable not available in eVC3
578 #if defined(_WIN32_WCE) && _WIN32_WCE < 400
581 wxCHECK_MSG( m_handle
, NULL
, wxT("wxDIB::CreatePalette(): invalid object") );
584 if ( !GetDIBSection(m_handle
, &ds
) )
586 wxLogLastError(wxT("GetObject(hDIB)"));
591 // how many colours are we going to have in the palette?
592 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
595 // biClrUsed field might not be set
596 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
601 // bitmaps of this depth don't have palettes at all
603 // NB: another possibility would be to return
604 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
610 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
611 // going to have biClrUsed of them so add necessary space
612 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
613 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
614 wxCHECK_MSG( pPalette
, NULL
, wxT("out of memory") );
616 // initialize the palette header
617 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
618 pPalette
->palNumEntries
= (WORD
)biClrUsed
;
620 // and the colour table
621 wxCharBuffer
rgb(sizeof(RGBQUAD
) * biClrUsed
);
622 RGBQUAD
*pRGB
= (RGBQUAD
*)rgb
.data();
623 SelectInHDC
selectHandle(hDC
, m_handle
);
624 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
);
625 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
627 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
628 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
629 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
630 pPalette
->palPalEntry
[i
].peFlags
= 0;
633 HPALETTE hPalette
= ::CreatePalette(pPalette
);
639 wxLogLastError(wxT("CreatePalette"));
644 wxPalette
*palette
= new wxPalette
;
645 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
651 #endif // wxUSE_PALETTE
653 // ----------------------------------------------------------------------------
655 // ----------------------------------------------------------------------------
659 bool wxDIB::Create(const wxImage
& image
, PixelFormat pf
)
661 wxCHECK_MSG( image
.IsOk(), false, wxT("invalid wxImage in wxDIB ctor") );
663 const int h
= image
.GetHeight();
664 const int w
= image
.GetWidth();
666 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
667 // a 24bpp RGB is sufficient
668 const bool hasAlpha
= image
.HasAlpha();
669 const int bpp
= hasAlpha
? 32 : 24;
671 if ( !Create(w
, h
, bpp
) )
674 // DIBs are stored in bottom to top order (see also the comment above in
675 // Create()) so we need to copy bits line by line and starting from the end
676 const int srcBytesPerLine
= w
* 3;
677 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
678 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
679 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
681 unsigned char *dstLineStart
= (unsigned char *)m_data
;
682 for ( int y
= 0; y
< h
; y
++ )
684 // Copy one DIB line. Note that RGB components order is reversed in
685 // Windows bitmaps compared to wxImage and is actually BGR.
686 unsigned char *dst
= dstLineStart
;
693 case PixelFormat_PreMultiplied
:
694 // Pre-multiply pixel values so that the DIB could be used
695 // with ::AlphaBlend().
696 for ( x
= 0; x
< w
; x
++ )
698 const unsigned char a
= *alpha
++;
699 *dst
++ = (unsigned char)((src
[2] * a
+ 127) / 255);
700 *dst
++ = (unsigned char)((src
[1] * a
+ 127) / 255);
701 *dst
++ = (unsigned char)((src
[0] * a
+ 127) / 255);
707 case PixelFormat_NotPreMultiplied
:
708 // Just copy pixel data without changing it.
709 for ( x
= 0; x
< w
; x
++ )
722 else // no alpha channel
724 for ( int x
= 0; x
< w
; x
++ )
733 // pass to the previous line in the image
734 src
-= 2*srcBytesPerLine
;
738 // and to the next one in the DIB
739 dstLineStart
+= dstBytesPerLine
;
745 wxImage
wxDIB::ConvertToImage() const
747 wxCHECK_MSG( IsOk(), wxNullImage
,
748 wxT("can't convert invalid DIB to wxImage") );
750 // create the wxImage object
751 const int w
= GetWidth();
752 const int h
= GetHeight();
753 wxImage
image(w
, h
, false /* don't bother clearing memory */);
756 wxFAIL_MSG( wxT("could not allocate data for image") );
760 const int bpp
= GetDepth();
762 // Remember if we have any "real" transparency, i.e. either any partially
763 // transparent pixels or not all pixels are fully opaque or fully
765 bool hasAlpha
= false;
766 bool hasOpaque
= false;
767 bool hasTransparent
= false;
771 // 32 bit bitmaps may be either 0RGB or ARGB and we don't know in
772 // advance which one do we have so suppose we have alpha of them and
773 // get rid of it later if it turns out we didn't.
777 // this is the same loop as in Create() just above but with copy direction
779 const int dstBytesPerLine
= w
* 3;
780 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
781 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
782 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
784 const unsigned char *srcLineStart
= (unsigned char *)GetData();
785 for ( int y
= 0; y
< h
; y
++ )
788 const unsigned char *src
= srcLineStart
;
789 for ( int x
= 0; x
< w
; x
++ )
797 // wxImage uses non premultiplied alpha so undo
798 // premultiplication done in Create() above
799 const unsigned char a
= *src
;
802 // Check what kind of alpha do we have.
806 hasTransparent
= true;
810 // Anything in between means we have real transparency
811 // and must use alpha channel.
822 dst
[0] = (dst
[0] * 255) / a
;
823 dst
[1] = (dst
[1] * 255) / a
;
824 dst
[2] = (dst
[2] * 255) / a
;
833 // pass to the previous line in the image
834 dst
-= 2*dstBytesPerLine
;
838 // and to the next one in the DIB
839 srcLineStart
+= srcBytesPerLine
;
842 if ( hasOpaque
&& hasTransparent
)
845 if ( !hasAlpha
&& image
.HasAlpha() )
851 #endif // wxUSE_IMAGE
853 #endif // wxUSE_WXDIB