]>
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 // 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"
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
, wxT("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(HBITMAP hbmp
)
142 wxCHECK_MSG( hbmp
, false, wxT("wxDIB::Create(): invalid bitmap") );
144 // this bitmap could already be a DIB section in which case we don't need
145 // to convert it to DIB
147 if ( GetDIBSection(hbmp
, &ds
) )
151 // wxBitmap will free it, not we
152 m_ownsHandle
= false;
154 // copy all the bitmap parameters too as we have them now anyhow
155 m_width
= ds
.dsBm
.bmWidth
;
156 m_height
= ds
.dsBm
.bmHeight
;
157 m_depth
= ds
.dsBm
.bmBitsPixel
;
159 m_data
= ds
.dsBm
.bmBits
;
161 else // no, it's a DDB -- convert it to DIB
163 // prepare all the info we need
165 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
167 wxLogLastError(wxT("GetObject(bitmap)"));
172 int d
= bm
.bmBitsPixel
;
174 d
= wxDisplayDepth();
176 if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) )
183 // Windows CE doesn't have GetDIBits() so use an alternative implementation
186 // in fact I'm not sure if GetDIBits() is really much better than using
187 // BitBlt() like this -- it should be faster but I didn't do any tests, if
188 // anybody has time to do them and by chance finds that GetDIBits() is not
189 // much faster than BitBlt(), we could always use the Win CE version here
192 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
198 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
206 SelectInHDC
selectDst(hdcDst
, m_handle
);
213 0, 0, m_width
, m_height
,
219 wxLogLastError(wxT("BitBlt(DDB -> DIB)"));
227 #else // !__WXWINCE__
229 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
232 if ( !GetDIBSection(m_handle
, &ds
) )
234 // we're sure that our handle is a DIB section, so this should work
235 wxFAIL_MSG( wxT("GetObject(DIBSECTION) unexpectedly failed") );
242 ScreenHDC(), // the DC to use
243 hbmp
, // the source DDB
244 0, // first scan line
245 m_height
, // number of lines to copy
246 ds
.dsBm
.bmBits
, // pointer to the buffer
247 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
248 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
251 wxLogLastError(wxT("GetDIBits()"));
259 #endif // __WXWINCE__/!__WXWINCE__
261 // ----------------------------------------------------------------------------
262 // Loading/saving the DIBs
263 // ----------------------------------------------------------------------------
265 bool wxDIB::Load(const wxString
& filename
)
268 m_handle
= SHLoadDIBitmap(filename
);
269 #else // !__WXWINCE__
270 m_handle
= (HBITMAP
)::LoadImage
275 0, 0, // don't specify the size
276 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
278 #endif // __WXWINCE__
282 wxLogLastError(wxT("Loading DIB from file"));
290 bool wxDIB::Save(const wxString
& filename
)
292 wxCHECK_MSG( m_handle
, false, wxT("wxDIB::Save(): invalid object") );
295 wxFile
file(filename
, wxFile::write
);
296 bool ok
= file
.IsOpened();
300 if ( !GetDIBSection(m_handle
, &ds
) )
302 wxLogLastError(wxT("GetObject(hDIB)"));
306 BITMAPFILEHEADER bmpHdr
;
307 wxZeroMemory(bmpHdr
);
309 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
310 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
312 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
313 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
314 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
316 // first write the file header, then the bitmap header and finally the
317 // bitmap data itself
318 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
319 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
320 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
325 #endif // wxUSE_FILE/!wxUSE_FILE
329 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
336 // ----------------------------------------------------------------------------
338 // ----------------------------------------------------------------------------
340 void wxDIB::DoGetObject() const
342 // only do something if we have a valid DIB but we don't [yet] have valid
344 if ( m_handle
&& !m_data
)
346 // although all the info we need is in BITMAP and so we don't really
347 // need DIBSECTION we still ask for it as modifying the bit values only
348 // works for the real DIBs and not for the bitmaps and it's better to
349 // check for this now rather than trying to find out why it doesn't
352 if ( !GetDIBSection(m_handle
, &ds
) )
354 wxLogLastError(wxT("GetObject(hDIB)"));
358 wxDIB
*self
= wxConstCast(this, wxDIB
);
360 self
->m_width
= ds
.dsBm
.bmWidth
;
361 self
->m_height
= ds
.dsBm
.bmHeight
;
362 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
363 self
->m_data
= ds
.dsBm
.bmBits
;
367 // ----------------------------------------------------------------------------
368 // DDB <-> DIB conversions
369 // ----------------------------------------------------------------------------
373 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
375 wxCHECK_MSG( m_handle
, 0, wxT("wxDIB::CreateDDB(): invalid object") );
378 if ( !GetDIBSection(m_handle
, &ds
) )
380 wxLogLastError(wxT("GetObject(hDIB)"));
385 // how many colours are we going to have in the palette?
386 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
389 // biClrUsed field might not be set
390 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
395 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
399 // fake a BITMAPINFO w/o bits, just the palette info
400 wxCharBuffer
bmi(sizeof(BITMAPINFO
) + (biClrUsed
- 1)*sizeof(RGBQUAD
));
401 BITMAPINFO
*pBmi
= (BITMAPINFO
*)bmi
.data();
403 // get the colour table
404 SelectInHDC
sDC(hDC
, m_handle
);
405 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
);
406 memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
);
408 return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
);
413 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
415 wxCHECK_MSG( pbmi
, 0, wxT("invalid DIB in ConvertToBitmap") );
417 // here we get BITMAPINFO struct followed by the actual bitmap bits and
418 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
419 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
421 // get the pointer to the start of the real image data if we have a plain
422 // DIB and not a DIB section (in the latter case the pointer must be passed
423 // to us by the caller)
426 // we must skip over the colour table to get to the image data
428 // colour table either has the real colour data in which case its
429 // number of entries is given by biClrUsed or is used for masks to be
430 // used for extracting colour information from true colour bitmaps in
431 // which case it always have exactly 3 DWORDs
433 switch ( pbmih
->biCompression
)
440 // biClrUsed has the number of colors but it may be not initialized at
442 numColors
= pbmih
->biClrUsed
;
445 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
450 // no idea how it should be calculated for the other cases
454 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
457 HBITMAP hbmp
= ::CreateDIBitmap
459 hdc
? hdc
// create bitmap compatible
460 : (HDC
) ScreenHDC(), // with this DC
461 pbmih
, // used to get size &c
462 CBM_INIT
, // initialize bitmap bits too
463 bits
, // ... using this data
464 pbmi
, // this is used for palette only
465 DIB_RGB_COLORS
// direct or indexed palette?
470 wxLogLastError(wxT("CreateDIBitmap"));
477 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
479 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
481 // prepare all the info we need
483 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
485 wxLogLastError(wxT("GetObject(bitmap)"));
490 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
494 const bool wantSizeOnly
= pbi
== NULL
;
498 // just for convenience
499 const int h
= bm
.bmHeight
;
502 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
504 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
505 bi
.biWidth
= bm
.bmWidth
;
508 bi
.biBitCount
= bm
.bmBitsPixel
;
510 // memory we need for BITMAPINFO only
511 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
513 // get either just the image size or the image bits
516 ScreenHDC(), // the DC to use
517 hbmp
, // the source DDB
518 0, // first scan line
519 h
, // number of lines to copy
520 wantSizeOnly
? NULL
// pointer to the buffer or
521 : (char *)pbi
+ dwLen
, // NULL if we don't have it
522 pbi
, // bitmap header
523 DIB_RGB_COLORS
// or DIB_PAL_COLORS
526 wxLogLastError(wxT("GetDIBits()"));
531 // return the total size
532 return dwLen
+ bi
.biSizeImage
;
536 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
538 // first calculate the size needed
539 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
542 // conversion to DDB failed?
546 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
549 // this is an error which does risk to happen especially under Win9x
550 // and which the user may understand so let him know about it
551 wxLogError(_("Failed to allocate %luKb of memory for bitmap data."),
552 (unsigned long)(size
/ 1024));
557 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtrLock(hDIB
), hbmp
) )
559 // this really shouldn't happen... it worked the first time, why not
561 wxFAIL_MSG( wxT("wxDIB::ConvertFromBitmap() unexpectedly failed") );
569 #endif // __WXWINCE__
571 // ----------------------------------------------------------------------------
573 // ----------------------------------------------------------------------------
577 wxPalette
*wxDIB::CreatePalette() const
579 // GetDIBColorTable not available in eVC3
580 #if defined(_WIN32_WCE) && _WIN32_WCE < 400
583 wxCHECK_MSG( m_handle
, NULL
, wxT("wxDIB::CreatePalette(): invalid object") );
586 if ( !GetDIBSection(m_handle
, &ds
) )
588 wxLogLastError(wxT("GetObject(hDIB)"));
593 // how many colours are we going to have in the palette?
594 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
597 // biClrUsed field might not be set
598 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
603 // bitmaps of this depth don't have palettes at all
605 // NB: another possibility would be to return
606 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
612 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
613 // going to have biClrUsed of them so add necessary space
614 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
615 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
616 wxCHECK_MSG( pPalette
, NULL
, wxT("out of memory") );
618 // initialize the palette header
619 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
620 pPalette
->palNumEntries
= (WORD
)biClrUsed
;
622 // and the colour table
623 wxCharBuffer
rgb(sizeof(RGBQUAD
) * biClrUsed
);
624 RGBQUAD
*pRGB
= (RGBQUAD
*)rgb
.data();
625 SelectInHDC
selectHandle(hDC
, m_handle
);
626 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
);
627 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
629 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
630 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
631 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
632 pPalette
->palPalEntry
[i
].peFlags
= 0;
635 HPALETTE hPalette
= ::CreatePalette(pPalette
);
641 wxLogLastError(wxT("CreatePalette"));
646 wxPalette
*palette
= new wxPalette
;
647 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
653 #endif // wxUSE_PALETTE
655 // ----------------------------------------------------------------------------
657 // ----------------------------------------------------------------------------
661 bool wxDIB::Create(const wxImage
& image
)
663 wxCHECK_MSG( image
.Ok(), false, wxT("invalid wxImage in wxDIB ctor") );
665 const int h
= image
.GetHeight();
666 const int w
= image
.GetWidth();
668 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
669 // a 24bpp RGB is sufficient
670 const bool hasAlpha
= image
.HasAlpha();
671 const int bpp
= hasAlpha
? 32 : 24;
673 if ( !Create(w
, h
, bpp
) )
676 // DIBs are stored in bottom to top order (see also the comment above in
677 // Create()) so we need to copy bits line by line and starting from the end
678 const int srcBytesPerLine
= w
* 3;
679 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
680 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
681 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
683 unsigned char *dstLineStart
= (unsigned char *)m_data
;
684 for ( int y
= 0; y
< h
; y
++ )
687 unsigned char *dst
= dstLineStart
;
690 for ( int x
= 0; x
< w
; x
++ )
692 // RGB order is reversed, and we need to premultiply
693 // all channels by alpha value for use with ::AlphaBlend.
694 const unsigned char a
= *alpha
++;
695 *dst
++ = (unsigned char)((src
[2] * a
+ 127) / 255);
696 *dst
++ = (unsigned char)((src
[1] * a
+ 127) / 255);
697 *dst
++ = (unsigned char)((src
[0] * a
+ 127) / 255);
702 else // no alpha channel
704 for ( int x
= 0; x
< w
; x
++ )
706 // RGB order is reversed.
714 // pass to the previous line in the image
715 src
-= 2*srcBytesPerLine
;
719 // and to the next one in the DIB
720 dstLineStart
+= dstBytesPerLine
;
726 wxImage
wxDIB::ConvertToImage() const
728 wxCHECK_MSG( IsOk(), wxNullImage
,
729 wxT("can't convert invalid DIB to wxImage") );
731 // create the wxImage object
732 const int w
= GetWidth();
733 const int h
= GetHeight();
734 wxImage
image(w
, h
, false /* don't bother clearing memory */);
737 wxFAIL_MSG( wxT("could not allocate data for image") );
741 const int bpp
= GetDepth();
742 bool hasAlpha
= false;
745 // 32 bit bitmaps may be either 0RGB or ARGB and we don't know in
746 // advance which one do we have so suppose we have alpha of them and
747 // get rid of it later if it turns out we didn't.
751 // this is the same loop as in Create() just above but with copy direction
753 const int dstBytesPerLine
= w
* 3;
754 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
755 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
756 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
758 const unsigned char *srcLineStart
= (unsigned char *)GetData();
759 for ( int y
= 0; y
< h
; y
++ )
762 const unsigned char *src
= srcLineStart
;
763 for ( int x
= 0; x
< w
; x
++ )
771 // wxImage uses non premultiplied alpha so undo
772 // premultiplication done in Create() above
773 const unsigned char a
= *src
;
777 dst
[0] = (dst
[0] * 255) / a
;
778 dst
[1] = (dst
[1] * 255) / a
;
779 dst
[2] = (dst
[2] * 255) / a
;
790 // pass to the previous line in the image
791 dst
-= 2*dstBytesPerLine
;
795 // and to the next one in the DIB
796 srcLineStart
+= srcBytesPerLine
;
799 if ( !hasAlpha
&& image
.HasAlpha() )
805 #endif // wxUSE_IMAGE
807 #endif // wxUSE_WXDIB