]>
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"
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
wxGetNumOfBitmapColors(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 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 handle the palette yet
93 wxASSERT_MSG( depth
== 24 || depth
== 32,
94 _T("unsupported image depth in wxDIB::Create()") );
96 static const int infosize
= sizeof(BITMAPINFOHEADER
);
98 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(infosize
);
99 wxCHECK_MSG( info
, false, _T("malloc(BITMAPINFO) failed") );
101 memset(info
, 0, infosize
);
103 info
->bmiHeader
.biSize
= infosize
;
104 info
->bmiHeader
.biWidth
= width
;
106 // we use positive height here which corresponds to a DIB with normal, i.e.
107 // bottom to top, order -- normally using negative height (which means
108 // reversed for MS and hence natural for all the normal people top to
109 // bottom line scan order) could be used to avoid the need for the image
110 // reversal in Create(image) but this doesn't work under NT, only Win9x!
111 info
->bmiHeader
.biHeight
= height
;
113 info
->bmiHeader
.biPlanes
= 1;
114 info
->bmiHeader
.biBitCount
= depth
;
115 info
->bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
117 m_handle
= ::CreateDIBSection
119 0, // hdc (unused with DIB_RGB_COLORS)
120 info
, // bitmap description
121 DIB_RGB_COLORS
, // use RGB, not palette
122 &m_data
, // [out] DIB bits
123 NULL
, // don't use file mapping
124 0 // file mapping offset (not used here)
131 wxLogLastError(wxT("CreateDIBSection"));
143 bool wxDIB::Create(const wxBitmap
& bmp
)
145 wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
147 // this bitmap could already be a DIB section in which case we don't need
148 // to convert it to DIB
149 HBITMAP hbmp
= GetHbitmapOf(bmp
);
152 if ( GetDIBSection(hbmp
, &ds
) )
156 // wxBitmap will free it, not we
157 m_ownsHandle
= false;
159 // copy all the bitmap parameters too as we have them now anyhow
160 m_width
= ds
.dsBm
.bmWidth
;
161 m_height
= ds
.dsBm
.bmHeight
;
162 m_depth
= ds
.dsBm
.bmBitsPixel
;
164 m_data
= ds
.dsBm
.bmBits
;
166 else // no, it's a DDB -- convert it to DIB
168 const int w
= bmp
.GetWidth();
169 const int h
= bmp
.GetHeight();
170 int d
= bmp
.GetDepth();
172 d
= wxDisplayDepth();
174 if ( !Create(w
, h
, d
) )
177 if ( !GetDIBSection(m_handle
, &ds
) )
179 // we've just created a new DIB section, why should this fail?
180 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
187 ScreenHDC(), // the DC to use
188 hbmp
, // the source DDB
189 0, // first scan line
190 h
, // number of lines to copy
191 ds
.dsBm
.bmBits
, // pointer to the buffer
192 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
193 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
196 wxLogLastError(wxT("GetDIBits()"));
205 // ----------------------------------------------------------------------------
206 // Loading/saving the DIBs
207 // ----------------------------------------------------------------------------
209 bool wxDIB::Load(const wxString
& filename
)
211 m_handle
= (HBITMAP
)::LoadImage
216 0, 0, // don't specify the size
217 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
221 wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
229 bool wxDIB::Save(const wxString
& filename
)
231 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
233 wxFile
file(filename
, wxFile::write
);
234 bool ok
= file
.IsOpened();
238 if ( !GetDIBSection(m_handle
, &ds
) )
240 wxLogLastError(_T("GetObject(hDIB)"));
244 BITMAPFILEHEADER bmpHdr
;
245 wxZeroMemory(bmpHdr
);
247 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
248 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
250 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
251 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
252 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
254 // first write the file header, then the bitmap header and finally the
255 // bitmap data itself
256 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
257 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
258 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
264 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
271 // ----------------------------------------------------------------------------
273 // ----------------------------------------------------------------------------
275 void wxDIB::DoGetObject() const
277 // only do something if we have a valid DIB but we don't [yet] have valid
279 if ( m_handle
&& !m_data
)
281 // although all the info we need is in BITMAP and so we don't really
282 // need DIBSECTION we still ask for it as modifying the bit values only
283 // works for the real DIBs and not for the bitmaps and it's better to
284 // check for this now rather than trying to find out why it doesn't
287 if ( !GetDIBSection(m_handle
, &ds
) )
289 wxLogLastError(_T("GetObject(hDIB)"));
293 wxDIB
*self
= wxConstCast(this, wxDIB
);
295 self
->m_width
= ds
.dsBm
.bmWidth
;
296 self
->m_height
= ds
.dsBm
.bmHeight
;
297 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
298 self
->m_data
= ds
.dsBm
.bmBits
;
302 // ----------------------------------------------------------------------------
303 // DDB <-> DIB conversions
304 // ----------------------------------------------------------------------------
306 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
308 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
311 if ( !GetDIBSection(m_handle
, &ds
) )
313 wxLogLastError(_T("GetObject(hDIB)"));
318 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
322 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
324 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
326 // here we get BITMAPINFO struct followed by the actual bitmap bits and
327 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
328 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
330 // get the pointer to the start of the real image data if we have a plain
331 // DIB and not a DIB section (in the latter case the pointer must be passed
332 // to us by the caller)
335 // we must skip over the colour table to get to the image data
337 // colour table either has the real colour data in which case its
338 // number of entries is given by biClrUsed or is used for masks to be
339 // used for extracting colour information from true colour bitmaps in
340 // which case it always have exactly 3 DWORDs
342 switch ( pbmih
->biCompression
)
349 // biClrUsed has the number of colors but it may be not initialized at
351 numColors
= pbmih
->biClrUsed
;
354 numColors
= wxGetNumOfBitmapColors(pbmih
->biBitCount
);
359 // no idea how it should be calculated for the other cases
363 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
366 HBITMAP hbmp
= ::CreateDIBitmap
368 hdc
? hdc
// create bitmap compatible
369 : (HDC
) ScreenHDC(), // with this DC
370 pbmih
, // used to get size &c
371 CBM_INIT
, // initialize bitmap bits too
372 bits
, // ... using this data
373 pbmi
, // this is used for palette only
374 DIB_RGB_COLORS
// direct or indexed palette?
379 wxLogLastError(wxT("CreateDIBitmap"));
386 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
388 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
390 // prepare all the info we need
392 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
394 wxLogLastError(wxT("GetObject(bitmap)"));
399 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
403 const bool wantSizeOnly
= pbi
== NULL
;
407 // just for convenience
408 const int h
= bm
.bmHeight
;
411 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
413 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
414 bi
.biWidth
= bm
.bmWidth
;
417 bi
.biBitCount
= bm
.bmBitsPixel
;
419 // memory we need for BITMAPINFO only
420 DWORD dwLen
= bi
.biSize
+ wxGetNumOfBitmapColors(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
422 // get either just the image size or the image bits
425 ScreenHDC(), // the DC to use
426 hbmp
, // the source DDB
427 0, // first scan line
428 h
, // number of lines to copy
429 wantSizeOnly
? NULL
// pointer to the buffer or
430 : (char *)pbi
+ dwLen
, // NULL if we don't have it
431 pbi
, // bitmap header
432 DIB_RGB_COLORS
// or DIB_PAL_COLORS
435 wxLogLastError(wxT("GetDIBits()"));
440 // return the total size
441 return dwLen
+ bi
.biSizeImage
;
445 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
447 // first calculate the size needed
448 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
451 // conversion to DDB failed?
455 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
458 // this is an error which does risk to happen especially under Win9x
459 // and which the user may understand so let him know about it
460 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
461 (unsigned long)(size
/ 1024));
466 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtr(hDIB
), hbmp
) )
468 // this really shouldn't happen... it worked the first time, why not
470 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
478 // ----------------------------------------------------------------------------
480 // ----------------------------------------------------------------------------
484 wxPalette
*wxDIB::CreatePalette() const
486 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
489 if ( !GetDIBSection(m_handle
, &ds
) )
491 wxLogLastError(_T("GetObject(hDIB)"));
496 // how many colours are we going to have in the palette?
497 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
500 // biClrUsed field might not be set
501 biClrUsed
= wxGetNumOfBitmapColors(ds
.dsBmih
.biBitCount
);
506 // bitmaps of this depth don't have palettes at all
508 // NB: another possibility would be to return
509 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
513 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
514 // going to have biClrUsed of them so add necessary space
515 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
516 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
517 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
519 // initialize the palette header
520 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
521 pPalette
->palNumEntries
= biClrUsed
;
523 // and the colour table (it starts right after the end of the header)
524 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
525 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
527 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
528 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
529 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
530 pPalette
->palPalEntry
[i
].peFlags
= 0;
533 HPALETTE hPalette
= ::CreatePalette(pPalette
);
539 wxLogLastError(_T("CreatePalette"));
544 wxPalette
*palette
= new wxPalette
;
545 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
550 #endif // wxUSE_PALETTE
552 // ----------------------------------------------------------------------------
554 // ----------------------------------------------------------------------------
558 bool wxDIB::Create(const wxImage
& image
)
560 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
562 const int h
= image
.GetHeight();
563 const int w
= image
.GetWidth();
565 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
566 // a 24bpp RGB is sufficient
567 const bool hasAlpha
= image
.HasAlpha();
568 const int bpp
= hasAlpha
? 32 : 24;
570 if ( !Create(w
, h
, bpp
) )
573 // DIBs are stored in bottom to top order (see also the comment above in
574 // Create()) so we need to copy bits line by line and starting from the end
575 const int srcBytesPerLine
= w
* 3;
576 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
577 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
578 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
: NULL
;
579 unsigned char *dstLineStart
= (unsigned char *)m_data
;
580 for ( int y
= 0; y
< h
; y
++ )
583 unsigned char *dst
= dstLineStart
;
584 for ( int x
= 0; x
< w
; x
++ )
586 // also, the order of RGB is inversed for DIBs
597 // pass to the previous line in the image
598 src
-= 2*srcBytesPerLine
;
602 // and to the next one in the DIB
603 dstLineStart
+= dstBytesPerLine
;
609 #endif // wxUSE_IMAGE