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)
7 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
12 TODO: support for palettes is very incomplete, several functions simply
13 ignore them (we should select and realize the palette, if any, before
14 caling GetDIBits() in the DC we use with it.
17 // ============================================================================
19 // ============================================================================
21 // ----------------------------------------------------------------------------
23 // ----------------------------------------------------------------------------
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
35 #include "wx/string.h"
38 #include "wx/bitmap.h"
49 #include "wx/msw/dib.h"
52 #include <shellapi.h> // for SHLoadDIBitmap()
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 // calculate the number of palette entries needed for the bitmap with this
60 // number of bits per pixel
61 static inline WORD
GetNumberOfColours(WORD bitsPerPixel
)
63 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
64 // 24bpp ones too but we don't support this as I think it's quite uncommon)
65 return (WORD
)(bitsPerPixel
<= 8 ? 1 << bitsPerPixel
: 0);
68 // wrapper around ::GetObject() for DIB sections
69 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION
*ds
)
71 // note that at least under Win9x (this doesn't seem to happen under Win2K
72 // but this doesn't mean anything, of course), GetObject() may return
73 // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
74 // to check for it is by looking at the bits pointer
75 return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) &&
79 // ============================================================================
81 // ============================================================================
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 bool wxDIB::Create(int width
, int height
, int depth
)
89 // we don't support formats using palettes right now so we only create
90 // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
91 wxASSERT_MSG( depth
, wxT("invalid image depth in wxDIB::Create()") );
95 // allocate memory for bitmap structures
99 info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
100 info
.bmiHeader
.biWidth
= width
;
102 // we use positive height here which corresponds to a DIB with normal, i.e.
103 // bottom to top, order -- normally using negative height (which means
104 // reversed for MS and hence natural for all the normal people top to
105 // bottom line scan order) could be used to avoid the need for the image
106 // reversal in Create(image) but this doesn't work under NT, only Win9x!
107 info
.bmiHeader
.biHeight
= height
;
109 info
.bmiHeader
.biPlanes
= 1;
110 info
.bmiHeader
.biBitCount
= (WORD
)depth
;
111 info
.bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
113 m_handle
= ::CreateDIBSection
115 0, // hdc (unused with DIB_RGB_COLORS)
116 &info
, // bitmap description
117 DIB_RGB_COLORS
, // use RGB, not palette
118 &m_data
, // [out] DIB bits
119 NULL
, // don't use file mapping
120 0 // file mapping offset (not used here)
125 wxLogLastError(wxT("CreateDIBSection"));
137 bool wxDIB::Create(HBITMAP hbmp
)
139 wxCHECK_MSG( hbmp
, false, wxT("wxDIB::Create(): invalid bitmap") );
141 // this bitmap could already be a DIB section in which case we don't need
142 // to convert it to DIB
144 if ( GetDIBSection(hbmp
, &ds
) )
148 // wxBitmap will free it, not we
149 m_ownsHandle
= false;
151 // copy all the bitmap parameters too as we have them now anyhow
152 m_width
= ds
.dsBm
.bmWidth
;
153 m_height
= ds
.dsBm
.bmHeight
;
154 m_depth
= ds
.dsBm
.bmBitsPixel
;
156 m_data
= ds
.dsBm
.bmBits
;
158 else // no, it's a DDB -- convert it to DIB
160 // prepare all the info we need
162 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
164 wxLogLastError(wxT("GetObject(bitmap)"));
169 int d
= bm
.bmBitsPixel
;
171 d
= wxDisplayDepth();
173 if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) )
180 // Windows CE doesn't have GetDIBits() so use an alternative implementation
183 // in fact I'm not sure if GetDIBits() is really much better than using
184 // BitBlt() like this -- it should be faster but I didn't do any tests, if
185 // anybody has time to do them and by chance finds that GetDIBits() is not
186 // much faster than BitBlt(), we could always use the Win CE version here
189 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
195 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
203 SelectInHDC
selectDst(hdcDst
, m_handle
);
210 0, 0, m_width
, m_height
,
216 wxLogLastError(wxT("BitBlt(DDB -> DIB)"));
224 #else // !__WXWINCE__
226 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
229 if ( !GetDIBSection(m_handle
, &ds
) )
231 // we're sure that our handle is a DIB section, so this should work
232 wxFAIL_MSG( wxT("GetObject(DIBSECTION) unexpectedly failed") );
239 ScreenHDC(), // the DC to use
240 hbmp
, // the source DDB
241 0, // first scan line
242 m_height
, // number of lines to copy
243 ds
.dsBm
.bmBits
, // pointer to the buffer
244 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
245 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
248 wxLogLastError(wxT("GetDIBits()"));
256 #endif // __WXWINCE__/!__WXWINCE__
258 // ----------------------------------------------------------------------------
259 // Loading/saving the DIBs
260 // ----------------------------------------------------------------------------
262 bool wxDIB::Load(const wxString
& filename
)
265 m_handle
= SHLoadDIBitmap(filename
);
266 #else // !__WXWINCE__
267 m_handle
= (HBITMAP
)::LoadImage
272 0, 0, // don't specify the size
273 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
275 #endif // __WXWINCE__
279 wxLogLastError(wxT("Loading DIB from file"));
287 bool wxDIB::Save(const wxString
& filename
)
289 wxCHECK_MSG( m_handle
, false, wxT("wxDIB::Save(): invalid object") );
292 wxFile
file(filename
, wxFile::write
);
293 bool ok
= file
.IsOpened();
297 if ( !GetDIBSection(m_handle
, &ds
) )
299 wxLogLastError(wxT("GetObject(hDIB)"));
303 BITMAPFILEHEADER bmpHdr
;
304 wxZeroMemory(bmpHdr
);
306 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
307 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
309 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
310 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
311 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
313 // first write the file header, then the bitmap header and finally the
314 // bitmap data itself
315 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
316 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
317 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
322 #endif // wxUSE_FILE/!wxUSE_FILE
326 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
333 // ----------------------------------------------------------------------------
335 // ----------------------------------------------------------------------------
337 void wxDIB::DoGetObject() const
339 // only do something if we have a valid DIB but we don't [yet] have valid
341 if ( m_handle
&& !m_data
)
343 // although all the info we need is in BITMAP and so we don't really
344 // need DIBSECTION we still ask for it as modifying the bit values only
345 // works for the real DIBs and not for the bitmaps and it's better to
346 // check for this now rather than trying to find out why it doesn't
349 if ( !GetDIBSection(m_handle
, &ds
) )
351 wxLogLastError(wxT("GetObject(hDIB)"));
355 wxDIB
*self
= wxConstCast(this, wxDIB
);
357 self
->m_width
= ds
.dsBm
.bmWidth
;
358 self
->m_height
= ds
.dsBm
.bmHeight
;
359 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
360 self
->m_data
= ds
.dsBm
.bmBits
;
364 // ----------------------------------------------------------------------------
365 // DDB <-> DIB conversions
366 // ----------------------------------------------------------------------------
370 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
372 wxCHECK_MSG( m_handle
, 0, wxT("wxDIB::CreateDDB(): invalid object") );
375 if ( !GetDIBSection(m_handle
, &ds
) )
377 wxLogLastError(wxT("GetObject(hDIB)"));
382 // how many colours are we going to have in the palette?
383 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
386 // biClrUsed field might not be set
387 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
392 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
396 // fake a BITMAPINFO w/o bits, just the palette info
397 wxCharBuffer
bmi(sizeof(BITMAPINFO
) + (biClrUsed
- 1)*sizeof(RGBQUAD
));
398 BITMAPINFO
*pBmi
= (BITMAPINFO
*)bmi
.data();
400 // get the colour table
401 SelectInHDC
sDC(hDC
, m_handle
);
402 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
);
403 memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
);
405 return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
);
410 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
412 wxCHECK_MSG( pbmi
, 0, wxT("invalid DIB in ConvertToBitmap") );
414 // here we get BITMAPINFO struct followed by the actual bitmap bits and
415 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
416 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
418 // get the pointer to the start of the real image data if we have a plain
419 // DIB and not a DIB section (in the latter case the pointer must be passed
420 // to us by the caller)
423 // we must skip over the colour table to get to the image data
425 // colour table either has the real colour data in which case its
426 // number of entries is given by biClrUsed or is used for masks to be
427 // used for extracting colour information from true colour bitmaps in
428 // which case it always have exactly 3 DWORDs
430 switch ( pbmih
->biCompression
)
437 // biClrUsed has the number of colors but it may be not initialized at
439 numColors
= pbmih
->biClrUsed
;
442 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
447 // no idea how it should be calculated for the other cases
451 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
454 HBITMAP hbmp
= ::CreateDIBitmap
456 hdc
? hdc
// create bitmap compatible
457 : (HDC
) ScreenHDC(), // with this DC
458 pbmih
, // used to get size &c
459 CBM_INIT
, // initialize bitmap bits too
460 bits
, // ... using this data
461 pbmi
, // this is used for palette only
462 DIB_RGB_COLORS
// direct or indexed palette?
467 wxLogLastError(wxT("CreateDIBitmap"));
474 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
476 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
478 // prepare all the info we need
480 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
482 wxLogLastError(wxT("GetObject(bitmap)"));
487 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
491 const bool wantSizeOnly
= pbi
== NULL
;
495 // just for convenience
496 const int h
= bm
.bmHeight
;
499 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
501 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
502 bi
.biWidth
= bm
.bmWidth
;
505 bi
.biBitCount
= bm
.bmBitsPixel
;
507 // memory we need for BITMAPINFO only
508 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
510 // get either just the image size or the image bits
513 ScreenHDC(), // the DC to use
514 hbmp
, // the source DDB
515 0, // first scan line
516 h
, // number of lines to copy
517 wantSizeOnly
? NULL
// pointer to the buffer or
518 : (char *)pbi
+ dwLen
, // NULL if we don't have it
519 pbi
, // bitmap header
520 DIB_RGB_COLORS
// or DIB_PAL_COLORS
523 wxLogLastError(wxT("GetDIBits()"));
528 // return the total size
529 return dwLen
+ bi
.biSizeImage
;
533 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
535 // first calculate the size needed
536 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
539 // conversion to DDB failed?
543 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
546 // this is an error which does risk to happen especially under Win9x
547 // and which the user may understand so let him know about it
548 wxLogError(_("Failed to allocate %luKb of memory for bitmap data."),
549 (unsigned long)(size
/ 1024));
554 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtrLock(hDIB
), hbmp
) )
556 // this really shouldn't happen... it worked the first time, why not
558 wxFAIL_MSG( wxT("wxDIB::ConvertFromBitmap() unexpectedly failed") );
566 #endif // __WXWINCE__
568 // ----------------------------------------------------------------------------
570 // ----------------------------------------------------------------------------
574 wxPalette
*wxDIB::CreatePalette() const
576 // GetDIBColorTable not available in eVC3
577 #if !defined(__WXMSW__) || defined(_WIN32_WCE) && _WIN32_WCE < 400
580 wxCHECK_MSG( m_handle
, NULL
, wxT("wxDIB::CreatePalette(): invalid object") );
583 if ( !GetDIBSection(m_handle
, &ds
) )
585 wxLogLastError(wxT("GetObject(hDIB)"));
590 // how many colours are we going to have in the palette?
591 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
594 // biClrUsed field might not be set
595 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
600 // bitmaps of this depth don't have palettes at all
602 // NB: another possibility would be to return
603 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
609 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
610 // going to have biClrUsed of them so add necessary space
611 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
612 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
613 wxCHECK_MSG( pPalette
, NULL
, wxT("out of memory") );
615 // initialize the palette header
616 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
617 pPalette
->palNumEntries
= (WORD
)biClrUsed
;
619 // and the colour table
620 wxCharBuffer
rgb(sizeof(RGBQUAD
) * biClrUsed
);
621 RGBQUAD
*pRGB
= (RGBQUAD
*)rgb
.data();
622 SelectInHDC
selectHandle(hDC
, m_handle
);
623 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
);
624 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
626 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
627 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
628 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
629 pPalette
->palPalEntry
[i
].peFlags
= 0;
632 HPALETTE hPalette
= ::CreatePalette(pPalette
);
638 wxLogLastError(wxT("CreatePalette"));
643 wxPalette
*palette
= new wxPalette
;
644 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
650 #endif // wxUSE_PALETTE
652 // ----------------------------------------------------------------------------
654 // ----------------------------------------------------------------------------
658 bool wxDIB::Create(const wxImage
& image
, PixelFormat pf
)
660 wxCHECK_MSG( image
.IsOk(), false, wxT("invalid wxImage in wxDIB ctor") );
662 const int h
= image
.GetHeight();
663 const int w
= image
.GetWidth();
665 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
666 // a 24bpp RGB is sufficient
667 const bool hasAlpha
= image
.HasAlpha();
668 const int bpp
= hasAlpha
? 32 : 24;
670 if ( !Create(w
, h
, bpp
) )
673 // DIBs are stored in bottom to top order (see also the comment above in
674 // Create()) so we need to copy bits line by line and starting from the end
675 const int srcBytesPerLine
= w
* 3;
676 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
677 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
678 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
680 unsigned char *dstLineStart
= (unsigned char *)m_data
;
681 for ( int y
= 0; y
< h
; y
++ )
683 // Copy one DIB line. Note that RGB components order is reversed in
684 // Windows bitmaps compared to wxImage and is actually BGR.
685 unsigned char *dst
= dstLineStart
;
692 case PixelFormat_PreMultiplied
:
693 // Pre-multiply pixel values so that the DIB could be used
694 // with ::AlphaBlend().
695 for ( x
= 0; x
< w
; x
++ )
697 const unsigned char a
= *alpha
++;
698 *dst
++ = (unsigned char)((src
[2] * a
+ 127) / 255);
699 *dst
++ = (unsigned char)((src
[1] * a
+ 127) / 255);
700 *dst
++ = (unsigned char)((src
[0] * a
+ 127) / 255);
706 case PixelFormat_NotPreMultiplied
:
707 // Just copy pixel data without changing it.
708 for ( x
= 0; x
< w
; x
++ )
721 else // no alpha channel
723 for ( int x
= 0; x
< w
; x
++ )
732 // pass to the previous line in the image
733 src
-= 2*srcBytesPerLine
;
737 // and to the next one in the DIB
738 dstLineStart
+= dstBytesPerLine
;
744 wxImage
wxDIB::ConvertToImage() const
746 wxCHECK_MSG( IsOk(), wxNullImage
,
747 wxT("can't convert invalid DIB to wxImage") );
749 // create the wxImage object
750 const int w
= GetWidth();
751 const int h
= GetHeight();
752 wxImage
image(w
, h
, false /* don't bother clearing memory */);
755 wxFAIL_MSG( wxT("could not allocate data for image") );
759 const int bpp
= GetDepth();
761 // Remember if we have any "real" transparency, i.e. either any partially
762 // transparent pixels or not all pixels are fully opaque or fully
764 bool hasAlpha
= false;
765 bool hasOpaque
= false;
766 bool hasTransparent
= false;
770 // 32 bit bitmaps may be either 0RGB or ARGB and we don't know in
771 // advance which one do we have so suppose we have alpha of them and
772 // get rid of it later if it turns out we didn't.
776 // this is the same loop as in Create() just above but with copy direction
778 const int dstBytesPerLine
= w
* 3;
779 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
780 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
781 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
783 const unsigned char *srcLineStart
= (unsigned char *)GetData();
784 for ( int y
= 0; y
< h
; y
++ )
787 const unsigned char *src
= srcLineStart
;
788 for ( int x
= 0; x
< w
; x
++ )
796 // wxImage uses non premultiplied alpha so undo
797 // premultiplication done in Create() above
798 const unsigned char a
= *src
;
801 // Check what kind of alpha do we have.
805 hasTransparent
= true;
809 // Anything in between means we have real transparency
810 // and must use alpha channel.
821 dst
[0] = (dst
[0] * 255) / a
;
822 dst
[1] = (dst
[1] * 255) / a
;
823 dst
[2] = (dst
[2] * 255) / a
;
832 // pass to the previous line in the image
833 dst
-= 2*dstBytesPerLine
;
837 // and to the next one in the DIB
838 srcLineStart
+= srcBytesPerLine
;
841 if ( hasOpaque
&& hasTransparent
)
844 if ( !hasAlpha
&& image
.HasAlpha() )
850 #endif // wxUSE_IMAGE
852 #endif // wxUSE_WXDIB