]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dib.cpp
00ed0789cc480cbdb8b21b6d4a50eb74ca7dbb4c
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__) && !defined(__SALFORDC__)
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
99 static const int sizeHeader
= sizeof(BITMAPINFOHEADER
);
101 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(sizeHeader
);
102 wxCHECK_MSG( info
, false, _T("malloc(BITMAPINFO) failed") );
104 memset(info
, 0, sizeHeader
);
106 info
->bmiHeader
.biSize
= sizeHeader
;
107 info
->bmiHeader
.biWidth
= width
;
109 // we use positive height here which corresponds to a DIB with normal, i.e.
110 // bottom to top, order -- normally using negative height (which means
111 // reversed for MS and hence natural for all the normal people top to
112 // bottom line scan order) could be used to avoid the need for the image
113 // reversal in Create(image) but this doesn't work under NT, only Win9x!
114 info
->bmiHeader
.biHeight
= height
;
116 info
->bmiHeader
.biPlanes
= 1;
117 info
->bmiHeader
.biBitCount
= (WORD
)depth
;
118 info
->bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
120 m_handle
= ::CreateDIBSection
122 0, // hdc (unused with DIB_RGB_COLORS)
123 info
, // bitmap description
124 DIB_RGB_COLORS
, // use RGB, not palette
125 &m_data
, // [out] DIB bits
126 NULL
, // don't use file mapping
127 0 // file mapping offset (not used here)
134 wxLogLastError(wxT("CreateDIBSection"));
146 bool wxDIB::Create(const wxBitmap
& bmp
)
148 wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
150 if ( !Create(GetHbitmapOf(bmp
)) )
153 m_hasAlpha
= bmp
.HasAlpha();
158 bool wxDIB::Create(HBITMAP hbmp
)
160 // this bitmap could already be a DIB section in which case we don't need
161 // to convert it to DIB
163 if ( GetDIBSection(hbmp
, &ds
) )
167 // wxBitmap will free it, not we
168 m_ownsHandle
= false;
170 // copy all the bitmap parameters too as we have them now anyhow
171 m_width
= ds
.dsBm
.bmWidth
;
172 m_height
= ds
.dsBm
.bmHeight
;
173 m_depth
= ds
.dsBm
.bmBitsPixel
;
175 m_data
= ds
.dsBm
.bmBits
;
177 else // no, it's a DDB -- convert it to DIB
179 // prepare all the info we need
181 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
183 wxLogLastError(wxT("GetObject(bitmap)"));
188 int d
= bm
.bmBitsPixel
;
190 d
= wxDisplayDepth();
192 if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) )
199 // Windows CE doesn't have GetDIBits() so use an alternative implementation
202 // in fact I'm not sure if GetDIBits() is really much better than using
203 // BitBlt() like this -- it should be faster but I didn't do any tests, if
204 // anybody has time to do them and by chance finds that GetDIBits() is not
205 // much faster than BitBlt(), we could always use the Win CE version here
208 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
214 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
222 SelectInHDC
selectDst(hdcDst
, m_handle
);
229 0, 0, m_width
, m_height
,
235 wxLogLastError(_T("BitBlt(DDB -> DIB)"));
243 #else // !__WXWINCE__
245 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
248 if ( !GetDIBSection(m_handle
, &ds
) )
250 // we're sure that our handle is a DIB section, so this should work
251 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
258 ScreenHDC(), // the DC to use
259 hbmp
, // the source DDB
260 0, // first scan line
261 m_height
, // number of lines to copy
262 ds
.dsBm
.bmBits
, // pointer to the buffer
263 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
264 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
267 wxLogLastError(wxT("GetDIBits()"));
275 #endif // __WXWINCE__/!__WXWINCE__
277 // ----------------------------------------------------------------------------
278 // Loading/saving the DIBs
279 // ----------------------------------------------------------------------------
281 bool wxDIB::Load(const wxString
& filename
)
284 m_handle
= SHLoadDIBitmap(filename
);
285 #else // !__WXWINCE__
286 m_handle
= (HBITMAP
)::LoadImage
291 0, 0, // don't specify the size
292 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
294 #endif // __WXWINCE__
298 wxLogLastError(_T("Loading DIB from file"));
306 bool wxDIB::Save(const wxString
& filename
)
308 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
311 wxFile
file(filename
, wxFile::write
);
312 bool ok
= file
.IsOpened();
316 if ( !GetDIBSection(m_handle
, &ds
) )
318 wxLogLastError(_T("GetObject(hDIB)"));
322 BITMAPFILEHEADER bmpHdr
;
323 wxZeroMemory(bmpHdr
);
325 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
326 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
328 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
329 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
330 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
332 // first write the file header, then the bitmap header and finally the
333 // bitmap data itself
334 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
335 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
336 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
341 #endif // wxUSE_FILE/!wxUSE_FILE
345 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
352 // ----------------------------------------------------------------------------
354 // ----------------------------------------------------------------------------
356 void wxDIB::DoGetObject() const
358 // only do something if we have a valid DIB but we don't [yet] have valid
360 if ( m_handle
&& !m_data
)
362 // although all the info we need is in BITMAP and so we don't really
363 // need DIBSECTION we still ask for it as modifying the bit values only
364 // works for the real DIBs and not for the bitmaps and it's better to
365 // check for this now rather than trying to find out why it doesn't
368 if ( !GetDIBSection(m_handle
, &ds
) )
370 wxLogLastError(_T("GetObject(hDIB)"));
374 wxDIB
*self
= wxConstCast(this, wxDIB
);
376 self
->m_width
= ds
.dsBm
.bmWidth
;
377 self
->m_height
= ds
.dsBm
.bmHeight
;
378 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
379 self
->m_data
= ds
.dsBm
.bmBits
;
383 // ----------------------------------------------------------------------------
384 // DDB <-> DIB conversions
385 // ----------------------------------------------------------------------------
389 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
391 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
394 if ( !GetDIBSection(m_handle
, &ds
) )
396 wxLogLastError(_T("GetObject(hDIB)"));
401 // how many colours are we going to have in the palette?
402 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
405 // biClrUsed field might not be set
406 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
411 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
415 // fake a BITMAPINFO w/o bits, just the palette info
416 wxCharBuffer
bmi(sizeof(BITMAPINFO
) + (biClrUsed
- 1)*sizeof(RGBQUAD
));
417 BITMAPINFO
*pBmi
= (BITMAPINFO
*)bmi
.data();
419 // get the colour table
420 SelectInHDC
sDC(hDC
, m_handle
);
421 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
);
422 memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
);
424 return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
);
429 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
431 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
433 // here we get BITMAPINFO struct followed by the actual bitmap bits and
434 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
435 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
437 // get the pointer to the start of the real image data if we have a plain
438 // DIB and not a DIB section (in the latter case the pointer must be passed
439 // to us by the caller)
442 // we must skip over the colour table to get to the image data
444 // colour table either has the real colour data in which case its
445 // number of entries is given by biClrUsed or is used for masks to be
446 // used for extracting colour information from true colour bitmaps in
447 // which case it always have exactly 3 DWORDs
449 switch ( pbmih
->biCompression
)
456 // biClrUsed has the number of colors but it may be not initialized at
458 numColors
= pbmih
->biClrUsed
;
461 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
466 // no idea how it should be calculated for the other cases
470 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
473 HBITMAP hbmp
= ::CreateDIBitmap
475 hdc
? hdc
// create bitmap compatible
476 : (HDC
) ScreenHDC(), // with this DC
477 pbmih
, // used to get size &c
478 CBM_INIT
, // initialize bitmap bits too
479 bits
, // ... using this data
480 pbmi
, // this is used for palette only
481 DIB_RGB_COLORS
// direct or indexed palette?
486 wxLogLastError(wxT("CreateDIBitmap"));
493 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
495 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
497 // prepare all the info we need
499 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
501 wxLogLastError(wxT("GetObject(bitmap)"));
506 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
510 const bool wantSizeOnly
= pbi
== NULL
;
514 // just for convenience
515 const int h
= bm
.bmHeight
;
518 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
520 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
521 bi
.biWidth
= bm
.bmWidth
;
524 bi
.biBitCount
= bm
.bmBitsPixel
;
526 // memory we need for BITMAPINFO only
527 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
529 // get either just the image size or the image bits
532 ScreenHDC(), // the DC to use
533 hbmp
, // the source DDB
534 0, // first scan line
535 h
, // number of lines to copy
536 wantSizeOnly
? NULL
// pointer to the buffer or
537 : (char *)pbi
+ dwLen
, // NULL if we don't have it
538 pbi
, // bitmap header
539 DIB_RGB_COLORS
// or DIB_PAL_COLORS
542 wxLogLastError(wxT("GetDIBits()"));
547 // return the total size
548 return dwLen
+ bi
.biSizeImage
;
552 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
554 // first calculate the size needed
555 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
558 // conversion to DDB failed?
562 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
565 // this is an error which does risk to happen especially under Win9x
566 // and which the user may understand so let him know about it
567 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
568 (unsigned long)(size
/ 1024));
573 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtrLock(hDIB
), hbmp
) )
575 // this really shouldn't happen... it worked the first time, why not
577 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
585 #endif // __WXWINCE__
587 // ----------------------------------------------------------------------------
589 // ----------------------------------------------------------------------------
593 wxPalette
*wxDIB::CreatePalette() const
595 // GetDIBColorTable not available in eVC3
596 #if defined(_WIN32_WCE) && _WIN32_WCE < 400
599 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
602 if ( !GetDIBSection(m_handle
, &ds
) )
604 wxLogLastError(_T("GetObject(hDIB)"));
609 // how many colours are we going to have in the palette?
610 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
613 // biClrUsed field might not be set
614 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
619 // bitmaps of this depth don't have palettes at all
621 // NB: another possibility would be to return
622 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
628 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
629 // going to have biClrUsed of them so add necessary space
630 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
631 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
632 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
634 // initialize the palette header
635 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
636 pPalette
->palNumEntries
= (WORD
)biClrUsed
;
638 // and the colour table
639 wxCharBuffer
rgb(sizeof(RGBQUAD
) * biClrUsed
);
640 RGBQUAD
*pRGB
= (RGBQUAD
*)rgb
.data();
641 SelectInHDC
selectHandle(hDC
, m_handle
);
642 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
);
643 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
645 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
646 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
647 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
648 pPalette
->palPalEntry
[i
].peFlags
= 0;
651 HPALETTE hPalette
= ::CreatePalette(pPalette
);
657 wxLogLastError(_T("CreatePalette"));
662 wxPalette
*palette
= new wxPalette
;
663 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
669 #endif // wxUSE_PALETTE
671 // ----------------------------------------------------------------------------
673 // ----------------------------------------------------------------------------
677 bool wxDIB::Create(const wxImage
& image
)
679 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
681 const int h
= image
.GetHeight();
682 const int w
= image
.GetWidth();
684 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
685 // a 24bpp RGB is sufficient
686 m_hasAlpha
= image
.HasAlpha();
687 const int bpp
= m_hasAlpha
? 32 : 24;
689 if ( !Create(w
, h
, bpp
) )
692 // DIBs are stored in bottom to top order (see also the comment above in
693 // Create()) so we need to copy bits line by line and starting from the end
694 const int srcBytesPerLine
= w
* 3;
695 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
696 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
697 const unsigned char *alpha
= m_hasAlpha
? image
.GetAlpha() + (h
- 1)*w
699 unsigned char *dstLineStart
= (unsigned char *)m_data
;
700 for ( int y
= 0; y
< h
; y
++ )
703 unsigned char *dst
= dstLineStart
;
706 for ( int x
= 0; x
< w
; x
++ )
708 // RGB order is reversed, and we need to premultiply
709 // all channels by alpha value for use with ::AlphaBlend.
710 const unsigned char a
= *alpha
++;
711 *dst
++ = (unsigned char)((src
[2] * a
+ 127) / 255);
712 *dst
++ = (unsigned char)((src
[1] * a
+ 127) / 255);
713 *dst
++ = (unsigned char)((src
[0] * a
+ 127) / 255);
718 else // no alpha channel
720 for ( int x
= 0; x
< w
; x
++ )
722 // RGB order is reversed.
730 // pass to the previous line in the image
731 src
-= 2*srcBytesPerLine
;
735 // and to the next one in the DIB
736 dstLineStart
+= dstBytesPerLine
;
742 wxImage
wxDIB::ConvertToImage() const
744 wxCHECK_MSG( IsOk(), wxNullImage
,
745 wxT("can't convert invalid DIB to wxImage") );
747 // create the wxImage object
748 const int w
= GetWidth();
749 const int h
= GetHeight();
750 wxImage
image(w
, h
, false /* don't bother clearing memory */);
753 wxFAIL_MSG( wxT("could not allocate data for image") );
762 // this is the same loop as in Create() just above but with copy direction
764 const int bpp
= GetDepth();
765 const int dstBytesPerLine
= w
* 3;
766 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
767 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
768 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
770 const bool is32bit
= bpp
== 32;
771 const unsigned char *srcLineStart
= (unsigned char *)GetData();
772 for ( int y
= 0; y
< h
; y
++ )
775 const unsigned char *src
= srcLineStart
;
776 for ( int x
= 0; x
< w
; x
++ )
786 // wxImage uses non premultiplied alpha so undo
787 // premultiplication done in Create() above
788 const unsigned char a
= *src
;
792 dst
[0] = (dst
[0] * 255) / a
;
793 dst
[1] = (dst
[1] * 255) / a
;
794 dst
[2] = (dst
[2] * 255) / a
;
804 // pass to the previous line in the image
805 dst
-= 2*dstBytesPerLine
;
809 // and to the next one in the DIB
810 srcLineStart
+= srcBytesPerLine
;
816 #endif // wxUSE_IMAGE
818 #endif // wxUSE_WXDIB