]>
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 // this bitmap could already be a DIB section in which case we don't need
155 // to convert it to DIB
156 HBITMAP hbmp
= GetHbitmapOf(bmp
);
159 if ( GetDIBSection(hbmp
, &ds
) )
163 // wxBitmap will free it, not we
164 m_ownsHandle
= false;
166 // copy all the bitmap parameters too as we have them now anyhow
167 m_width
= ds
.dsBm
.bmWidth
;
168 m_height
= ds
.dsBm
.bmHeight
;
169 m_depth
= ds
.dsBm
.bmBitsPixel
;
171 m_data
= ds
.dsBm
.bmBits
;
173 else // no, it's a DDB -- convert it to DIB
175 const int w
= bmp
.GetWidth();
176 const int h
= bmp
.GetHeight();
177 int d
= bmp
.GetDepth();
179 d
= wxDisplayDepth();
181 if ( !Create(w
, h
, d
) || !CopyFromDDB(hbmp
) )
185 m_hasAlpha
= bmp
.HasAlpha();
190 // Windows CE doesn't have GetDIBits() so use an alternative implementation
193 // in fact I'm not sure if GetDIBits() is really much better than using
194 // BitBlt() like this -- it should be faster but I didn't do any tests, if
195 // anybody has time to do them and by chance finds that GetDIBits() is not
196 // much faster than BitBlt(), we could always use the Win CE version here
199 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
205 SelectInHDC
selectSrc(hdcSrc
, hbmp
);
213 SelectInHDC
selectDst(hdcDst
, m_handle
);
220 0, 0, m_width
, m_height
,
226 wxLogLastError(_T("BitBlt(DDB -> DIB)"));
234 #else // !__WXWINCE__
236 bool wxDIB::CopyFromDDB(HBITMAP hbmp
)
239 if ( !GetDIBSection(m_handle
, &ds
) )
241 // we're sure that our handle is a DIB section, so this should work
242 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
249 ScreenHDC(), // the DC to use
250 hbmp
, // the source DDB
251 0, // first scan line
252 m_height
, // number of lines to copy
253 ds
.dsBm
.bmBits
, // pointer to the buffer
254 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
255 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
258 wxLogLastError(wxT("GetDIBits()"));
266 #endif // __WXWINCE__/!__WXWINCE__
268 // ----------------------------------------------------------------------------
269 // Loading/saving the DIBs
270 // ----------------------------------------------------------------------------
272 bool wxDIB::Load(const wxString
& filename
)
275 m_handle
= SHLoadDIBitmap(filename
);
276 #else // !__WXWINCE__
277 m_handle
= (HBITMAP
)::LoadImage
282 0, 0, // don't specify the size
283 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
285 #endif // __WXWINCE__
289 wxLogLastError(_T("Loading DIB from file"));
297 bool wxDIB::Save(const wxString
& filename
)
299 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
301 wxFile
file(filename
, wxFile::write
);
302 bool ok
= file
.IsOpened();
306 if ( !GetDIBSection(m_handle
, &ds
) )
308 wxLogLastError(_T("GetObject(hDIB)"));
312 BITMAPFILEHEADER bmpHdr
;
313 wxZeroMemory(bmpHdr
);
315 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
316 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
318 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
319 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
320 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
322 // first write the file header, then the bitmap header and finally the
323 // bitmap data itself
324 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
325 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
326 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
332 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
339 // ----------------------------------------------------------------------------
341 // ----------------------------------------------------------------------------
343 void wxDIB::DoGetObject() const
345 // only do something if we have a valid DIB but we don't [yet] have valid
347 if ( m_handle
&& !m_data
)
349 // although all the info we need is in BITMAP and so we don't really
350 // need DIBSECTION we still ask for it as modifying the bit values only
351 // works for the real DIBs and not for the bitmaps and it's better to
352 // check for this now rather than trying to find out why it doesn't
355 if ( !GetDIBSection(m_handle
, &ds
) )
357 wxLogLastError(_T("GetObject(hDIB)"));
361 wxDIB
*self
= wxConstCast(this, wxDIB
);
363 self
->m_width
= ds
.dsBm
.bmWidth
;
364 self
->m_height
= ds
.dsBm
.bmHeight
;
365 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
366 self
->m_data
= ds
.dsBm
.bmBits
;
370 // ----------------------------------------------------------------------------
371 // DDB <-> DIB conversions
372 // ----------------------------------------------------------------------------
376 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
378 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
381 if ( !GetDIBSection(m_handle
, &ds
) )
383 wxLogLastError(_T("GetObject(hDIB)"));
388 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
392 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
394 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
396 // here we get BITMAPINFO struct followed by the actual bitmap bits and
397 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
398 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
400 // get the pointer to the start of the real image data if we have a plain
401 // DIB and not a DIB section (in the latter case the pointer must be passed
402 // to us by the caller)
405 // we must skip over the colour table to get to the image data
407 // colour table either has the real colour data in which case its
408 // number of entries is given by biClrUsed or is used for masks to be
409 // used for extracting colour information from true colour bitmaps in
410 // which case it always have exactly 3 DWORDs
412 switch ( pbmih
->biCompression
)
419 // biClrUsed has the number of colors but it may be not initialized at
421 numColors
= pbmih
->biClrUsed
;
424 numColors
= GetNumberOfColours(pbmih
->biBitCount
);
429 // no idea how it should be calculated for the other cases
433 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
436 HBITMAP hbmp
= ::CreateDIBitmap
438 hdc
? hdc
// create bitmap compatible
439 : (HDC
) ScreenHDC(), // with this DC
440 pbmih
, // used to get size &c
441 CBM_INIT
, // initialize bitmap bits too
442 bits
, // ... using this data
443 pbmi
, // this is used for palette only
444 DIB_RGB_COLORS
// direct or indexed palette?
449 wxLogLastError(wxT("CreateDIBitmap"));
456 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
458 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
460 // prepare all the info we need
462 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
464 wxLogLastError(wxT("GetObject(bitmap)"));
469 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
473 const bool wantSizeOnly
= pbi
== NULL
;
477 // just for convenience
478 const int h
= bm
.bmHeight
;
481 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
483 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
484 bi
.biWidth
= bm
.bmWidth
;
487 bi
.biBitCount
= bm
.bmBitsPixel
;
489 // memory we need for BITMAPINFO only
490 DWORD dwLen
= bi
.biSize
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
492 // get either just the image size or the image bits
495 ScreenHDC(), // the DC to use
496 hbmp
, // the source DDB
497 0, // first scan line
498 h
, // number of lines to copy
499 wantSizeOnly
? NULL
// pointer to the buffer or
500 : (char *)pbi
+ dwLen
, // NULL if we don't have it
501 pbi
, // bitmap header
502 DIB_RGB_COLORS
// or DIB_PAL_COLORS
505 wxLogLastError(wxT("GetDIBits()"));
510 // return the total size
511 return dwLen
+ bi
.biSizeImage
;
515 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
517 // first calculate the size needed
518 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
521 // conversion to DDB failed?
525 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
528 // this is an error which does risk to happen especially under Win9x
529 // and which the user may understand so let him know about it
530 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
531 (unsigned long)(size
/ 1024));
536 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtr(hDIB
), hbmp
) )
538 // this really shouldn't happen... it worked the first time, why not
540 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
548 #endif // __WXWINCE__
550 // ----------------------------------------------------------------------------
552 // ----------------------------------------------------------------------------
556 wxPalette
*wxDIB::CreatePalette() const
558 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
561 if ( !GetDIBSection(m_handle
, &ds
) )
563 wxLogLastError(_T("GetObject(hDIB)"));
568 // how many colours are we going to have in the palette?
569 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
572 // biClrUsed field might not be set
573 biClrUsed
= GetNumberOfColours(ds
.dsBmih
.biBitCount
);
578 // bitmaps of this depth don't have palettes at all
580 // NB: another possibility would be to return
581 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
585 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
586 // going to have biClrUsed of them so add necessary space
587 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
588 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
589 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
591 // initialize the palette header
592 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
593 pPalette
->palNumEntries
= biClrUsed
;
595 // and the colour table (it starts right after the end of the header)
596 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
597 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
599 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
600 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
601 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
602 pPalette
->palPalEntry
[i
].peFlags
= 0;
605 HPALETTE hPalette
= ::CreatePalette(pPalette
);
611 wxLogLastError(_T("CreatePalette"));
616 wxPalette
*palette
= new wxPalette
;
617 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
622 #endif // wxUSE_PALETTE
624 // ----------------------------------------------------------------------------
626 // ----------------------------------------------------------------------------
630 bool wxDIB::Create(const wxImage
& image
)
632 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
634 const int h
= image
.GetHeight();
635 const int w
= image
.GetWidth();
637 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
638 // a 24bpp RGB is sufficient
639 m_hasAlpha
= image
.HasAlpha();
640 const int bpp
= m_hasAlpha
? 32 : 24;
642 if ( !Create(w
, h
, bpp
) )
645 // DIBs are stored in bottom to top order (see also the comment above in
646 // Create()) so we need to copy bits line by line and starting from the end
647 const int srcBytesPerLine
= w
* 3;
648 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
649 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
650 const unsigned char *alpha
= m_hasAlpha
? image
.GetAlpha() + (h
- 1)*w
652 unsigned char *dstLineStart
= (unsigned char *)m_data
;
653 for ( int y
= 0; y
< h
; y
++ )
656 unsigned char *dst
= dstLineStart
;
657 for ( int x
= 0; x
< w
; x
++ )
659 // also, the order of RGB is inversed for DIBs
670 // pass to the previous line in the image
671 src
-= 2*srcBytesPerLine
;
675 // and to the next one in the DIB
676 dstLineStart
+= dstBytesPerLine
;
682 wxImage
wxDIB::ConvertToImage() const
684 wxCHECK_MSG( IsOk(), wxNullImage
,
685 wxT("can't convert invalid DIB to wxImage") );
687 // create the wxImage object
688 const int w
= GetWidth();
689 const int h
= GetHeight();
690 wxImage
image(w
, h
, false /* don't bother clearing memory */);
693 wxFAIL_MSG( wxT("could not allocate data for image") );
702 // this is the same loop as in Create() just above but with copy direction
704 const int bpp
= GetDepth();
705 const int dstBytesPerLine
= w
* 3;
706 const int srcBytesPerLine
= GetLineSize(w
, bpp
);
707 unsigned char *dst
= image
.GetData() + ((h
- 1) * dstBytesPerLine
);
708 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() + (h
- 1)*w
710 const bool is32bit
= bpp
== 32;
711 const unsigned char *srcLineStart
= (unsigned char *)GetData();
712 for ( int y
= 0; y
< h
; y
++ )
715 const unsigned char *src
= srcLineStart
;
716 for ( int x
= 0; x
< w
; x
++ )
732 // pass to the previous line in the image
733 dst
-= 2*dstBytesPerLine
;
737 // and to the next one in the DIB
738 srcLineStart
+= srcBytesPerLine
;
744 #endif // wxUSE_IMAGE
746 #endif // wxUSE_WXDIB