]>
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__)
51 #ifdef __GNUWIN32_OLD__
52 #include "wx/msw/gnuwin32/extra.h"
56 #include "wx/msw/dib.h"
59 #include <shellapi.h> // for SHLoadDIBitmap()
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 // calculate the number of palette entries needed for the bitmap with this
67 // number of bits per pixel
68 static inline WORD
GetNumberOfColours(WORD bitsPerPixel
)
70 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
71 // 24bpp ones too but we don't support this as I think it's quite uncommon)
72 return bitsPerPixel
<= 8 ? 1 << bitsPerPixel
: 0;
75 // wrapper around ::GetObject() for DIB sections
76 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION
*ds
)
78 // note that at least under Win9x (this doesn't seem to happen under Win2K
79 // but this doesn't mean anything, of course), GetObject() may return
80 // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
81 // to check for it is by looking at the bits pointer
82 return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) &&
86 // ============================================================================
88 // ============================================================================
90 // ----------------------------------------------------------------------------
92 // ----------------------------------------------------------------------------
94 bool wxDIB::Create(int width
, int height
, int depth
)
96 // we don't support formats using palettes right now so we only create
97 // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
98 wxASSERT_MSG( depth
, _T("invalid image depth in wxDIB::Create()") );
102 // allocate memory for bitmap structures
103 static const int sizeHeader
= sizeof(BITMAPINFOHEADER
);
105 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(sizeHeader
);
106 wxCHECK_MSG( info
, false, _T("malloc(BITMAPINFO) failed") );
108 memset(info
, 0, sizeHeader
);
110 info
->bmiHeader
.biSize
= sizeHeader
;
111 info
->bmiHeader
.biWidth
= width
;
113 // we use positive height here which corresponds to a DIB with normal, i.e.
114 // bottom to top, order -- normally using negative height (which means
115 // reversed for MS and hence natural for all the normal people top to
116 // bottom line scan order) could be used to avoid the need for the image
117 // reversal in Create(image) but this doesn't work under NT, only Win9x!
118 info
->bmiHeader
.biHeight
= height
;
120 info
->bmiHeader
.biPlanes
= 1;
121 info
->bmiHeader
.biBitCount
= depth
;
122 info
->bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
124 m_handle
= ::CreateDIBSection
126 0, // hdc (unused with DIB_RGB_COLORS)
127 info
, // bitmap description
128 DIB_RGB_COLORS
, // use RGB, not palette
129 &m_data
, // [out] DIB bits
130 NULL
, // don't use file mapping
131 0 // file mapping offset (not used here)
138 wxLogLastError(wxT("CreateDIBSection"));
150 bool wxDIB::Create(const wxBitmap
& bmp
)
152 wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
154 if ( !Create(GetHbitmapOf(bmp
)) )
157 m_hasAlpha
= bmp
.HasAlpha();
162 bool wxDIB::Create(HBITMAP hbmp
)
164 // this bitmap could already be a DIB section in which case we don't need
165 // to convert it to DIB
167 if ( GetDIBSection(hbmp
, &ds
) )
171 // wxBitmap will free it, not we
172 m_ownsHandle
= false;
174 // copy all the bitmap parameters too as we have them now anyhow
175 m_width
= ds
.dsBm
.bmWidth
;
176 m_height
= ds
.dsBm
.bmHeight
;
177 m_depth
= ds
.dsBm
.bmBitsPixel
;
179 m_data
= ds
.dsBm
.bmBits
;
181 else // no, it's a DDB -- convert it to DIB
183 // prepare all the info we need
185 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
187 wxLogLastError(wxT("GetObject(bitmap)"));
192 int d
= bm
.bmBitsPixel
;
194 d
= wxDisplayDepth();
196 if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) )
203 // Windows CE doesn't have GetDIBits() so use an alternative implementation
206 // in fact I'm not sure if GetDIBits() is really much better than using
207 // BitBlt() like this -- it should be faster but I didn't do any tests, if
208 // anybody has time to do them and by chance finds that GetDIBits() is not
209 // much faster than BitBlt(), we could always use the Win CE version here
212 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
218 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
226 SelectInHDC
selectDst(hdcDst
, m_handle
);
233 0, 0, m_width
, m_height
,
239 wxLogLastError(_T("BitBlt(DDB -> DIB)"));
247 #else // !__WXWINCE__
249 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
252 if ( !GetDIBSection(m_handle
, &ds
) )
254 // we're sure that our handle is a DIB section, so this should work
255 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
262 ScreenHDC(), // the DC to use
263 hbmp
, // the source DDB
264 0, // first scan line
265 m_height
, // number of lines to copy
266 ds
.dsBm
.bmBits
, // pointer to the buffer
267 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
268 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
271 wxLogLastError(wxT("GetDIBits()"));
279 #endif // __WXWINCE__/!__WXWINCE__
281 // ----------------------------------------------------------------------------
282 // Loading/saving the DIBs
283 // ----------------------------------------------------------------------------
285 bool wxDIB::Load(const wxString
& filename
)
288 m_handle
= SHLoadDIBitmap(filename
);
289 #else // !__WXWINCE__
290 m_handle
= (HBITMAP
)::LoadImage
295 0, 0, // don't specify the size
296 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
298 #endif // __WXWINCE__
302 wxLogLastError(_T("Loading DIB from file"));
310 bool wxDIB::Save(const wxString
& filename
)
312 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
314 wxFile
file(filename
, wxFile::write
);
315 bool ok
= file
.IsOpened();
319 if ( !GetDIBSection(m_handle
, &ds
) )
321 wxLogLastError(_T("GetObject(hDIB)"));
325 BITMAPFILEHEADER bmpHdr
;
326 wxZeroMemory(bmpHdr
);
328 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
329 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
331 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
332 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
333 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
335 // first write the file header, then the bitmap header and finally the
336 // bitmap data itself
337 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
338 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
339 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
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 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
405 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
407 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
409 // here we get BITMAPINFO struct followed by the actual bitmap bits and
410 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
411 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
413 // get the pointer to the start of the real image data if we have a plain
414 // DIB and not a DIB section (in the latter case the pointer must be passed
415 // to us by the caller)
418 // we must skip over the colour table to get to the image data
420 // colour table either has the real colour data in which case its
421 // number of entries is given by biClrUsed or is used for masks to be
422 // used for extracting colour information from true colour bitmaps in
423 // which case it always have exactly 3 DWORDs
425 switch ( pbmih
->biCompression
)
432 // biClrUsed has the number of colors but it may be not initialized at
434 numColors
= pbmih
->biClrUsed
;
437 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
442 // no idea how it should be calculated for the other cases
446 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
449 HBITMAP hbmp
= ::CreateDIBitmap
451 hdc
? hdc
// create bitmap compatible
452 : (HDC
) ScreenHDC(), // with this DC
453 pbmih
, // used to get size &c
454 CBM_INIT
, // initialize bitmap bits too
455 bits
, // ... using this data
456 pbmi
, // this is used for palette only
457 DIB_RGB_COLORS
// direct or indexed palette?
462 wxLogLastError(wxT("CreateDIBitmap"));
469 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
471 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
473 // prepare all the info we need
475 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
477 wxLogLastError(wxT("GetObject(bitmap)"));
482 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
486 const bool wantSizeOnly
= pbi
== NULL
;
490 // just for convenience
491 const int h
= bm
.bmHeight
;
494 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
496 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
497 bi
.biWidth
= bm
.bmWidth
;
500 bi
.biBitCount
= bm
.bmBitsPixel
;
502 // memory we need for BITMAPINFO only
503 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
505 // get either just the image size or the image bits
508 ScreenHDC(), // the DC to use
509 hbmp
, // the source DDB
510 0, // first scan line
511 h
, // number of lines to copy
512 wantSizeOnly
? NULL
// pointer to the buffer or
513 : (char *)pbi
+ dwLen
, // NULL if we don't have it
514 pbi
, // bitmap header
515 DIB_RGB_COLORS
// or DIB_PAL_COLORS
518 wxLogLastError(wxT("GetDIBits()"));
523 // return the total size
524 return dwLen
+ bi
.biSizeImage
;
528 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
530 // first calculate the size needed
531 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
534 // conversion to DDB failed?
538 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
541 // this is an error which does risk to happen especially under Win9x
542 // and which the user may understand so let him know about it
543 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
544 (unsigned long)(size
/ 1024));
549 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtr(hDIB
), hbmp
) )
551 // this really shouldn't happen... it worked the first time, why not
553 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
561 #endif // __WXWINCE__
563 // ----------------------------------------------------------------------------
565 // ----------------------------------------------------------------------------
569 wxPalette
*wxDIB::CreatePalette() const
571 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
574 if ( !GetDIBSection(m_handle
, &ds
) )
576 wxLogLastError(_T("GetObject(hDIB)"));
581 // how many colours are we going to have in the palette?
582 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
585 // biClrUsed field might not be set
586 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
591 // bitmaps of this depth don't have palettes at all
593 // NB: another possibility would be to return
594 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
598 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
599 // going to have biClrUsed of them so add necessary space
600 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
601 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
602 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
604 // initialize the palette header
605 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
606 pPalette
->palNumEntries
= biClrUsed
;
608 // and the colour table (it starts right after the end of the header)
609 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
610 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
612 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
613 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
614 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
615 pPalette
->palPalEntry
[i
].peFlags
= 0;
618 HPALETTE hPalette
= ::CreatePalette(pPalette
);
624 wxLogLastError(_T("CreatePalette"));
629 wxPalette
*palette
= new wxPalette
;
630 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
635 #endif // wxUSE_PALETTE
637 // ----------------------------------------------------------------------------
639 // ----------------------------------------------------------------------------
643 bool wxDIB::Create(const wxImage
& image
)
645 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
647 const int h
= image
.GetHeight();
648 const int w
= image
.GetWidth();
650 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
651 // a 24bpp RGB is sufficient
652 m_hasAlpha
= image
.HasAlpha();
653 const int bpp
= m_hasAlpha
? 32 : 24;
655 if ( !Create(w
, h
, bpp
) )
658 // DIBs are stored in bottom to top order (see also the comment above in
659 // Create()) so we need to copy bits line by line and starting from the end
660 const int srcBytesPerLine
= w
* 3;
661 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
662 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
663 const unsigned char *alpha
= m_hasAlpha
? image
.GetAlpha() + (h
- 1)*w
665 unsigned char *dstLineStart
= (unsigned char *)m_data
;
666 for ( int y
= 0; y
< h
; y
++ )
669 unsigned char *dst
= dstLineStart
;
670 for ( int x
= 0; x
< w
; x
++ )
672 // also, the order of RGB is inversed for DIBs
683 // pass to the previous line in the image
684 src
-= 2*srcBytesPerLine
;
688 // and to the next one in the DIB
689 dstLineStart
+= dstBytesPerLine
;
695 wxImage
wxDIB::ConvertToImage() const
697 wxCHECK_MSG( IsOk(), wxNullImage
,
698 wxT("can't convert invalid DIB to wxImage") );
700 // create the wxImage object
701 const int w
= GetWidth();
702 const int h
= GetHeight();
703 wxImage
image(w
, h
, false /* don't bother clearing memory */);
706 wxFAIL_MSG( wxT("could not allocate data for image") );
715 // this is the same loop as in Create() just above but with copy direction
717 const int bpp
= GetDepth();
718 const int dstBytesPerLine
= w
* 3;
719 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
720 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
721 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
723 const bool is32bit
= bpp
== 32;
724 const unsigned char *srcLineStart
= (unsigned char *)GetData();
725 for ( int y
= 0; y
< h
; y
++ )
728 const unsigned char *src
= srcLineStart
;
729 for ( int x
= 0; x
< w
; x
++ )
745 // pass to the previous line in the image
746 dst
-= 2*dstBytesPerLine
;
750 // and to the next one in the DIB
751 srcLineStart
+= srcBytesPerLine
;
757 #endif // wxUSE_IMAGE
759 #endif // wxUSE_WXDIB