]>
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"
34 #include "wx/string.h"
40 #include "wx/bitmap.h"
47 #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") );
310 wxFile
file(filename
, wxFile::write
);
311 bool ok
= file
.IsOpened();
315 if ( !GetDIBSection(m_handle
, &ds
) )
317 wxLogLastError(_T("GetObject(hDIB)"));
321 BITMAPFILEHEADER bmpHdr
;
322 wxZeroMemory(bmpHdr
);
324 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
325 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
327 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
328 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
329 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
331 // first write the file header, then the bitmap header and finally the
332 // bitmap data itself
333 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
334 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
335 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
341 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
348 // ----------------------------------------------------------------------------
350 // ----------------------------------------------------------------------------
352 void wxDIB::DoGetObject() const
354 // only do something if we have a valid DIB but we don't [yet] have valid
356 if ( m_handle
&& !m_data
)
358 // although all the info we need is in BITMAP and so we don't really
359 // need DIBSECTION we still ask for it as modifying the bit values only
360 // works for the real DIBs and not for the bitmaps and it's better to
361 // check for this now rather than trying to find out why it doesn't
364 if ( !GetDIBSection(m_handle
, &ds
) )
366 wxLogLastError(_T("GetObject(hDIB)"));
370 wxDIB
*self
= wxConstCast(this, wxDIB
);
372 self
->m_width
= ds
.dsBm
.bmWidth
;
373 self
->m_height
= ds
.dsBm
.bmHeight
;
374 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
375 self
->m_data
= ds
.dsBm
.bmBits
;
379 // ----------------------------------------------------------------------------
380 // DDB <-> DIB conversions
381 // ----------------------------------------------------------------------------
385 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
387 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
390 if ( !GetDIBSection(m_handle
, &ds
) )
392 wxLogLastError(_T("GetObject(hDIB)"));
397 // how many colours are we going to have in the palette?
398 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
401 // biClrUsed field might not be set
402 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
407 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
411 // fake a BITMAPINFO w/o bits, just the palette info
412 wxCharBuffer
bmi(sizeof(BITMAPINFO
) + (biClrUsed
- 1)*sizeof(RGBQUAD
));
413 BITMAPINFO
*pBmi
= (BITMAPINFO
*)bmi
.data();
415 // get the colour table
416 SelectInHDC
sDC(hDC
, m_handle
);
417 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
);
418 memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
);
420 return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
);
425 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
427 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
429 // here we get BITMAPINFO struct followed by the actual bitmap bits and
430 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
431 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
433 // get the pointer to the start of the real image data if we have a plain
434 // DIB and not a DIB section (in the latter case the pointer must be passed
435 // to us by the caller)
438 // we must skip over the colour table to get to the image data
440 // colour table either has the real colour data in which case its
441 // number of entries is given by biClrUsed or is used for masks to be
442 // used for extracting colour information from true colour bitmaps in
443 // which case it always have exactly 3 DWORDs
445 switch ( pbmih
->biCompression
)
452 // biClrUsed has the number of colors but it may be not initialized at
454 numColors
= pbmih
->biClrUsed
;
457 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
462 // no idea how it should be calculated for the other cases
466 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
469 HBITMAP hbmp
= ::CreateDIBitmap
471 hdc
? hdc
// create bitmap compatible
472 : (HDC
) ScreenHDC(), // with this DC
473 pbmih
, // used to get size &c
474 CBM_INIT
, // initialize bitmap bits too
475 bits
, // ... using this data
476 pbmi
, // this is used for palette only
477 DIB_RGB_COLORS
// direct or indexed palette?
482 wxLogLastError(wxT("CreateDIBitmap"));
489 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
491 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
493 // prepare all the info we need
495 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
497 wxLogLastError(wxT("GetObject(bitmap)"));
502 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
506 const bool wantSizeOnly
= pbi
== NULL
;
510 // just for convenience
511 const int h
= bm
.bmHeight
;
514 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
516 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
517 bi
.biWidth
= bm
.bmWidth
;
520 bi
.biBitCount
= bm
.bmBitsPixel
;
522 // memory we need for BITMAPINFO only
523 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
525 // get either just the image size or the image bits
528 ScreenHDC(), // the DC to use
529 hbmp
, // the source DDB
530 0, // first scan line
531 h
, // number of lines to copy
532 wantSizeOnly
? NULL
// pointer to the buffer or
533 : (char *)pbi
+ dwLen
, // NULL if we don't have it
534 pbi
, // bitmap header
535 DIB_RGB_COLORS
// or DIB_PAL_COLORS
538 wxLogLastError(wxT("GetDIBits()"));
543 // return the total size
544 return dwLen
+ bi
.biSizeImage
;
548 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
550 // first calculate the size needed
551 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
554 // conversion to DDB failed?
558 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
561 // this is an error which does risk to happen especially under Win9x
562 // and which the user may understand so let him know about it
563 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
564 (unsigned long)(size
/ 1024));
569 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtr(hDIB
), hbmp
) )
571 // this really shouldn't happen... it worked the first time, why not
573 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
581 #endif // __WXWINCE__
583 // ----------------------------------------------------------------------------
585 // ----------------------------------------------------------------------------
589 wxPalette
*wxDIB::CreatePalette() const
591 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
594 if ( !GetDIBSection(m_handle
, &ds
) )
596 wxLogLastError(_T("GetObject(hDIB)"));
601 // how many colours are we going to have in the palette?
602 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
605 // biClrUsed field might not be set
606 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
611 // bitmaps of this depth don't have palettes at all
613 // NB: another possibility would be to return
614 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
620 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
621 // going to have biClrUsed of them so add necessary space
622 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
623 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
624 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
626 // initialize the palette header
627 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
628 pPalette
->palNumEntries
= (WORD
)biClrUsed
;
630 // and the colour table
631 wxCharBuffer
rgb(sizeof(RGBQUAD
) * biClrUsed
);
632 RGBQUAD
*pRGB
= (RGBQUAD
*)rgb
.data();
633 SelectInHDC(hDC
, m_handle
);
634 ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
);
635 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
637 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
638 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
639 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
640 pPalette
->palPalEntry
[i
].peFlags
= 0;
643 HPALETTE hPalette
= ::CreatePalette(pPalette
);
649 wxLogLastError(_T("CreatePalette"));
654 wxPalette
*palette
= new wxPalette
;
655 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
660 #endif // wxUSE_PALETTE
662 // ----------------------------------------------------------------------------
664 // ----------------------------------------------------------------------------
668 bool wxDIB::Create(const wxImage
& image
)
670 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
672 const int h
= image
.GetHeight();
673 const int w
= image
.GetWidth();
675 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
676 // a 24bpp RGB is sufficient
677 m_hasAlpha
= image
.HasAlpha();
678 const int bpp
= m_hasAlpha
? 32 : 24;
680 if ( !Create(w
, h
, bpp
) )
683 // DIBs are stored in bottom to top order (see also the comment above in
684 // Create()) so we need to copy bits line by line and starting from the end
685 const int srcBytesPerLine
= w
* 3;
686 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
687 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
688 const unsigned char *alpha
= m_hasAlpha
? image
.GetAlpha() + (h
- 1)*w
690 unsigned char *dstLineStart
= (unsigned char *)m_data
;
691 for ( int y
= 0; y
< h
; y
++ )
694 unsigned char *dst
= dstLineStart
;
697 for ( int x
= 0; x
< w
; x
++ )
699 // RGB order is reversed, and we need to premultiply
700 // all channels by alpha value for use with ::AlphaBlend.
701 const unsigned char a
= *alpha
++;
702 *dst
++ = (unsigned char)((src
[2] * a
+ 127) / 255);
703 *dst
++ = (unsigned char)((src
[1] * a
+ 127) / 255);
704 *dst
++ = (unsigned char)((src
[0] * a
+ 127) / 255);
709 else // no alpha channel
711 for ( int x
= 0; x
< w
; x
++ )
713 // RGB order is reversed.
721 // pass to the previous line in the image
722 src
-= 2*srcBytesPerLine
;
726 // and to the next one in the DIB
727 dstLineStart
+= dstBytesPerLine
;
733 wxImage
wxDIB::ConvertToImage() const
735 wxCHECK_MSG( IsOk(), wxNullImage
,
736 wxT("can't convert invalid DIB to wxImage") );
738 // create the wxImage object
739 const int w
= GetWidth();
740 const int h
= GetHeight();
741 wxImage
image(w
, h
, false /* don't bother clearing memory */);
744 wxFAIL_MSG( wxT("could not allocate data for image") );
753 // this is the same loop as in Create() just above but with copy direction
755 const int bpp
= GetDepth();
756 const int dstBytesPerLine
= w
* 3;
757 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
758 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
759 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
761 const bool is32bit
= bpp
== 32;
762 const unsigned char *srcLineStart
= (unsigned char *)GetData();
763 for ( int y
= 0; y
< h
; y
++ )
766 const unsigned char *src
= srcLineStart
;
767 for ( int x
= 0; x
< w
; x
++ )
783 // pass to the previous line in the image
784 dst
-= 2*dstBytesPerLine
;
788 // and to the next one in the DIB
789 srcLineStart
+= srcBytesPerLine
;
795 #endif // wxUSE_IMAGE
797 #endif // wxUSE_WXDIB