]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dib.cpp
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 // License: 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"
48 #if !defined(__MWERKS__)
52 #include "wx/msw/dib.h"
55 #include <shellapi.h> // for SHLoadDIBitmap()
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 // calculate the number of palette entries needed for the bitmap with this
63 // number of bits per pixel
64 static inline WORD
GetNumberOfColours(WORD bitsPerPixel
)
66 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
67 // 24bpp ones too but we don't support this as I think it's quite uncommon)
68 return (WORD
)(bitsPerPixel
<= 8 ? 1 << bitsPerPixel
: 0);
71 // wrapper around ::GetObject() for DIB sections
72 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION
*ds
)
74 // note that at least under Win9x (this doesn't seem to happen under Win2K
75 // but this doesn't mean anything, of course), GetObject() may return
76 // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
77 // to check for it is by looking at the bits pointer
78 return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) &&
82 // ============================================================================
84 // ============================================================================
86 // ----------------------------------------------------------------------------
88 // ----------------------------------------------------------------------------
90 bool wxDIB::Create(int width
, int height
, int depth
)
92 // we don't support formats using palettes right now so we only create
93 // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
94 wxASSERT_MSG( depth
, _T("invalid image depth in wxDIB::Create()") );
98 // allocate memory for bitmap structures
102 info
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
103 info
.bmiHeader
.biWidth
= width
;
105 // we use positive height here which corresponds to a DIB with normal, i.e.
106 // bottom to top, order -- normally using negative height (which means
107 // reversed for MS and hence natural for all the normal people top to
108 // bottom line scan order) could be used to avoid the need for the image
109 // reversal in Create(image) but this doesn't work under NT, only Win9x!
110 info
.bmiHeader
.biHeight
= height
;
112 info
.bmiHeader
.biPlanes
= 1;
113 info
.bmiHeader
.biBitCount
= (WORD
)depth
;
114 info
.bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
116 m_handle
= ::CreateDIBSection
118 0, // hdc (unused with DIB_RGB_COLORS)
119 &info
, // bitmap description
120 DIB_RGB_COLORS
, // use RGB, not palette
121 &m_data
, // [out] DIB bits
122 NULL
, // don't use file mapping
123 0 // file mapping offset (not used here)
128 wxLogLastError(wxT("CreateDIBSection"));
140 bool wxDIB::Create(const wxBitmap
& bmp
)
142 wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
144 if ( !Create(GetHbitmapOf(bmp
)) )
147 m_hasAlpha
= bmp
.HasAlpha();
152 bool wxDIB::Create(HBITMAP hbmp
)
154 // this bitmap could already be a DIB section in which case we don't need
155 // to convert it to DIB
157 if ( GetDIBSection(hbmp
, &ds
) )
161 // wxBitmap will free it, not we
162 m_ownsHandle
= false;
164 // copy all the bitmap parameters too as we have them now anyhow
165 m_width
= ds
.dsBm
.bmWidth
;
166 m_height
= ds
.dsBm
.bmHeight
;
167 m_depth
= ds
.dsBm
.bmBitsPixel
;
169 m_data
= ds
.dsBm
.bmBits
;
171 else // no, it's a DDB -- convert it to DIB
173 // prepare all the info we need
175 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
177 wxLogLastError(wxT("GetObject(bitmap)"));
182 int d
= bm
.bmBitsPixel
;
184 d
= wxDisplayDepth();
186 if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) )
193 // Windows CE doesn't have GetDIBits() so use an alternative implementation
196 // in fact I'm not sure if GetDIBits() is really much better than using
197 // BitBlt() like this -- it should be faster but I didn't do any tests, if
198 // anybody has time to do them and by chance finds that GetDIBits() is not
199 // much faster than BitBlt(), we could always use the Win CE version here
202 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
208 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
216 SelectInHDC
selectDst(hdcDst
, m_handle
);
223 0, 0, m_width
, m_height
,
229 wxLogLastError(_T("BitBlt(DDB -> DIB)"));
237 #else // !__WXWINCE__
239 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
242 if ( !GetDIBSection(m_handle
, &ds
) )
244 // we're sure that our handle is a DIB section, so this should work
245 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
252 ScreenHDC(), // the DC to use
253 hbmp
, // the source DDB
254 0, // first scan line
255 m_height
, // number of lines to copy
256 ds
.dsBm
.bmBits
, // pointer to the buffer
257 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
258 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
261 wxLogLastError(wxT("GetDIBits()"));
269 #endif // __WXWINCE__/!__WXWINCE__
271 // ----------------------------------------------------------------------------
272 // Loading/saving the DIBs
273 // ----------------------------------------------------------------------------
275 bool wxDIB::Load(const wxString
& filename
)
278 m_handle
= SHLoadDIBitmap(filename
);
279 #else // !__WXWINCE__
280 m_handle
= (HBITMAP
)::LoadImage
285 0, 0, // don't specify the size
286 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
288 #endif // __WXWINCE__
292 wxLogLastError(_T("Loading DIB from file"));
300 bool wxDIB::Save(const wxString
& filename
)
302 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
305 wxFile
file(filename
, wxFile::write
);
306 bool ok
= file
.IsOpened();
310 if ( !GetDIBSection(m_handle
, &ds
) )
312 wxLogLastError(_T("GetObject(hDIB)"));
316 BITMAPFILEHEADER bmpHdr
;
317 wxZeroMemory(bmpHdr
);
319 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
320 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
322 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
323 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
324 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
326 // first write the file header, then the bitmap header and finally the
327 // bitmap data itself
328 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
329 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
330 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
335 #endif // wxUSE_FILE/!wxUSE_FILE
339 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
346 // ----------------------------------------------------------------------------
348 // ----------------------------------------------------------------------------
350 void wxDIB::DoGetObject() const
352 // only do something if we have a valid DIB but we don't [yet] have valid
354 if ( m_handle
&& !m_data
)
356 // although all the info we need is in BITMAP and so we don't really
357 // need DIBSECTION we still ask for it as modifying the bit values only
358 // works for the real DIBs and not for the bitmaps and it's better to
359 // check for this now rather than trying to find out why it doesn't
362 if ( !GetDIBSection(m_handle
, &ds
) )
364 wxLogLastError(_T("GetObject(hDIB)"));
368 wxDIB
*self
= wxConstCast(this, wxDIB
);
370 self
->m_width
= ds
.dsBm
.bmWidth
;
371 self
->m_height
= ds
.dsBm
.bmHeight
;
372 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
373 self
->m_data
= ds
.dsBm
.bmBits
;
377 // ----------------------------------------------------------------------------
378 // DDB <-> DIB conversions
379 // ----------------------------------------------------------------------------
383 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
385 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
388 if ( !GetDIBSection(m_handle
, &ds
) )
390 wxLogLastError(_T("GetObject(hDIB)"));
395 // how many colours are we going to have in the palette?
396 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
399 // biClrUsed field might not be set
400 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
405 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
409 // fake a BITMAPINFO w/o bits, just the palette info
410 wxCharBuffer
bmi(sizeof(BITMAPINFO
) + (biClrUsed
- 1)*sizeof(RGBQUAD
));
411 BITMAPINFO
*pBmi
= (BITMAPINFO
*)bmi
.data();
413 // get the colour table
414 SelectInHDC
sDC(hDC
, m_handle
);
415 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
);
416 memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
);
418 return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
);
423 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
425 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
427 // here we get BITMAPINFO struct followed by the actual bitmap bits and
428 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
429 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
431 // get the pointer to the start of the real image data if we have a plain
432 // DIB and not a DIB section (in the latter case the pointer must be passed
433 // to us by the caller)
436 // we must skip over the colour table to get to the image data
438 // colour table either has the real colour data in which case its
439 // number of entries is given by biClrUsed or is used for masks to be
440 // used for extracting colour information from true colour bitmaps in
441 // which case it always have exactly 3 DWORDs
443 switch ( pbmih
->biCompression
)
450 // biClrUsed has the number of colors but it may be not initialized at
452 numColors
= pbmih
->biClrUsed
;
455 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
460 // no idea how it should be calculated for the other cases
464 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
467 HBITMAP hbmp
= ::CreateDIBitmap
469 hdc
? hdc
// create bitmap compatible
470 : (HDC
) ScreenHDC(), // with this DC
471 pbmih
, // used to get size &c
472 CBM_INIT
, // initialize bitmap bits too
473 bits
, // ... using this data
474 pbmi
, // this is used for palette only
475 DIB_RGB_COLORS
// direct or indexed palette?
480 wxLogLastError(wxT("CreateDIBitmap"));
487 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
489 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
491 // prepare all the info we need
493 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
495 wxLogLastError(wxT("GetObject(bitmap)"));
500 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
504 const bool wantSizeOnly
= pbi
== NULL
;
508 // just for convenience
509 const int h
= bm
.bmHeight
;
512 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
514 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
515 bi
.biWidth
= bm
.bmWidth
;
518 bi
.biBitCount
= bm
.bmBitsPixel
;
520 // memory we need for BITMAPINFO only
521 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
523 // get either just the image size or the image bits
526 ScreenHDC(), // the DC to use
527 hbmp
, // the source DDB
528 0, // first scan line
529 h
, // number of lines to copy
530 wantSizeOnly
? NULL
// pointer to the buffer or
531 : (char *)pbi
+ dwLen
, // NULL if we don't have it
532 pbi
, // bitmap header
533 DIB_RGB_COLORS
// or DIB_PAL_COLORS
536 wxLogLastError(wxT("GetDIBits()"));
541 // return the total size
542 return dwLen
+ bi
.biSizeImage
;
546 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
548 // first calculate the size needed
549 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
552 // conversion to DDB failed?
556 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
559 // this is an error which does risk to happen especially under Win9x
560 // and which the user may understand so let him know about it
561 wxLogError(_("Failed to allocate %luKb of memory for bitmap data."),
562 (unsigned long)(size
/ 1024));
567 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtrLock(hDIB
), hbmp
) )
569 // this really shouldn't happen... it worked the first time, why not
571 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
579 #endif // __WXWINCE__
581 // ----------------------------------------------------------------------------
583 // ----------------------------------------------------------------------------
587 wxPalette
*wxDIB::CreatePalette() const
589 // GetDIBColorTable not available in eVC3
590 #if defined(_WIN32_WCE) && _WIN32_WCE < 400
593 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
596 if ( !GetDIBSection(m_handle
, &ds
) )
598 wxLogLastError(_T("GetObject(hDIB)"));
603 // how many colours are we going to have in the palette?
604 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
607 // biClrUsed field might not be set
608 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
613 // bitmaps of this depth don't have palettes at all
615 // NB: another possibility would be to return
616 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
622 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
623 // going to have biClrUsed of them so add necessary space
624 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
625 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
626 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
628 // initialize the palette header
629 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
630 pPalette
->palNumEntries
= (WORD
)biClrUsed
;
632 // and the colour table
633 wxCharBuffer
rgb(sizeof(RGBQUAD
) * biClrUsed
);
634 RGBQUAD
*pRGB
= (RGBQUAD
*)rgb
.data();
635 SelectInHDC
selectHandle(hDC
, m_handle
);
636 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
);
637 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
639 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
640 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
641 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
642 pPalette
->palPalEntry
[i
].peFlags
= 0;
645 HPALETTE hPalette
= ::CreatePalette(pPalette
);
651 wxLogLastError(_T("CreatePalette"));
656 wxPalette
*palette
= new wxPalette
;
657 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
663 #endif // wxUSE_PALETTE
665 // ----------------------------------------------------------------------------
667 // ----------------------------------------------------------------------------
671 bool wxDIB::Create(const wxImage
& image
)
673 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
675 const int h
= image
.GetHeight();
676 const int w
= image
.GetWidth();
678 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
679 // a 24bpp RGB is sufficient
680 m_hasAlpha
= image
.HasAlpha();
681 const int bpp
= m_hasAlpha
? 32 : 24;
683 if ( !Create(w
, h
, bpp
) )
686 // DIBs are stored in bottom to top order (see also the comment above in
687 // Create()) so we need to copy bits line by line and starting from the end
688 const int srcBytesPerLine
= w
* 3;
689 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
690 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
691 const unsigned char *alpha
= m_hasAlpha
? image
.GetAlpha() + (h
- 1)*w
693 unsigned char *dstLineStart
= (unsigned char *)m_data
;
694 for ( int y
= 0; y
< h
; y
++ )
697 unsigned char *dst
= dstLineStart
;
700 for ( int x
= 0; x
< w
; x
++ )
702 // RGB order is reversed, and we need to premultiply
703 // all channels by alpha value for use with ::AlphaBlend.
704 const unsigned char a
= *alpha
++;
705 *dst
++ = (unsigned char)((src
[2] * a
+ 127) / 255);
706 *dst
++ = (unsigned char)((src
[1] * a
+ 127) / 255);
707 *dst
++ = (unsigned char)((src
[0] * a
+ 127) / 255);
712 else // no alpha channel
714 for ( int x
= 0; x
< w
; x
++ )
716 // RGB order is reversed.
724 // pass to the previous line in the image
725 src
-= 2*srcBytesPerLine
;
729 // and to the next one in the DIB
730 dstLineStart
+= dstBytesPerLine
;
736 wxImage
wxDIB::ConvertToImage() const
738 wxCHECK_MSG( IsOk(), wxNullImage
,
739 wxT("can't convert invalid DIB to wxImage") );
741 // create the wxImage object
742 const int w
= GetWidth();
743 const int h
= GetHeight();
744 wxImage
image(w
, h
, false /* don't bother clearing memory */);
747 wxFAIL_MSG( wxT("could not allocate data for image") );
756 // this is the same loop as in Create() just above but with copy direction
758 const int bpp
= GetDepth();
759 const int dstBytesPerLine
= w
* 3;
760 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
761 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
762 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
764 const bool is32bit
= bpp
== 32;
765 const unsigned char *srcLineStart
= (unsigned char *)GetData();
766 for ( int y
= 0; y
< h
; y
++ )
769 const unsigned char *src
= srcLineStart
;
770 for ( int x
= 0; x
< w
; x
++ )
780 // wxImage uses non premultiplied alpha so undo
781 // premultiplication done in Create() above
782 const unsigned char a
= *src
;
786 dst
[0] = (dst
[0] * 255) / a
;
787 dst
[1] = (dst
[1] * 255) / a
;
788 dst
[2] = (dst
[2] * 255) / a
;
798 // pass to the previous line in the image
799 dst
-= 2*dstBytesPerLine
;
803 // and to the next one in the DIB
804 srcLineStart
+= srcBytesPerLine
;
810 #endif // wxUSE_IMAGE
812 #endif // wxUSE_WXDIB