]>
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"
38 #include "wx/bitmap.h"
45 #if !defined(__MWERKS__) && !defined(__SALFORDC__)
49 #ifdef __GNUWIN32_OLD__
50 #include "wx/msw/gnuwin32/extra.h"
54 #include "wx/msw/dib.h"
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // calculate the number of palette entries needed for the bitmap with this
61 // number of bits per pixel
62 static inline WORD
wxGetNumOfBitmapColors(WORD bitsPerPixel
)
64 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
65 // 24bpp ones too but we don't support this as I think it's quite uncommon)
66 return bitsPerPixel
<= 8 ? 1 << bitsPerPixel
: 0;
69 // wrapper around ::GetObject() for DIB sections
70 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION
*ds
)
72 // note that at least under Win9x (this doesn't seem to happen under Win2K
73 // but this doesn't mean anything, of course), GetObject() may return
74 // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
75 // to check for it is by looking at the bits pointer
76 return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) &&
80 // ============================================================================
82 // ============================================================================
84 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
88 bool wxDIB::Create(int width
, int height
, int depth
)
90 // we don't handle the palette yet
91 wxASSERT_MSG( depth
== 24 || depth
== 32,
92 _T("unsupported image depth in wxDIB::Create()") );
94 static const int infosize
= sizeof(BITMAPINFOHEADER
);
96 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(infosize
);
97 wxCHECK_MSG( info
, false, _T("malloc(BITMAPINFO) failed") );
99 memset(info
, 0, infosize
);
101 info
->bmiHeader
.biSize
= infosize
;
102 info
->bmiHeader
.biWidth
= width
;
104 // we use positive height here which corresponds to a DIB with normal, i.e.
105 // bottom to top, order -- normally using negative height (which means
106 // reversed for MS and hence natural for all the normal people top to
107 // bottom line scan order) could be used to avoid the need for the image
108 // reversal in Create(image) but this doesn't work under NT, only Win9x!
109 info
->bmiHeader
.biHeight
= height
;
111 info
->bmiHeader
.biPlanes
= 1;
112 info
->bmiHeader
.biBitCount
= depth
;
113 info
->bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
115 m_handle
= ::CreateDIBSection
117 0, // hdc (unused with DIB_RGB_COLORS)
118 info
, // bitmap description
119 DIB_RGB_COLORS
, // use RGB, not palette
120 &m_data
, // [out] DIB bits
121 NULL
, // don't use file mapping
122 0 // file mapping offset (not used here)
129 wxLogLastError(wxT("CreateDIBSection"));
141 bool wxDIB::Create(const wxBitmap
& bmp
)
143 wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
145 // this bitmap could already be a DIB section in which case we don't need
146 // to convert it to DIB
147 HBITMAP hbmp
= GetHbitmapOf(bmp
);
150 if ( GetDIBSection(hbmp
, &ds
) )
154 // wxBitmap will free it, not we
155 m_ownsHandle
= false;
157 // copy all the bitmap parameters too as we have them now anyhow
158 m_width
= ds
.dsBm
.bmWidth
;
159 m_height
= ds
.dsBm
.bmHeight
;
160 m_depth
= ds
.dsBm
.bmBitsPixel
;
162 m_data
= ds
.dsBm
.bmBits
;
164 else // no, it's a DDB -- convert it to DIB
166 const int w
= bmp
.GetWidth();
167 const int h
= bmp
.GetHeight();
168 int d
= bmp
.GetDepth();
170 d
= wxDisplayDepth();
172 if ( !Create(w
, h
, d
) )
175 if ( !GetDIBSection(m_handle
, &ds
) )
177 // we've just created a new DIB section, why should this fail?
178 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
185 ScreenHDC(), // the DC to use
186 hbmp
, // the source DDB
187 0, // first scan line
188 h
, // number of lines to copy
189 ds
.dsBm
.bmBits
, // pointer to the buffer
190 (BITMAPINFO
*)&ds
.dsBmih
, // bitmap header
191 DIB_RGB_COLORS
// and not DIB_PAL_COLORS
194 wxLogLastError(wxT("GetDIBits()"));
203 // ----------------------------------------------------------------------------
204 // Loading/saving the DIBs
205 // ----------------------------------------------------------------------------
207 bool wxDIB::Load(const wxString
& filename
)
209 m_handle
= (HBITMAP
)::LoadImage
214 0, 0, // don't specify the size
215 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
219 wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
227 bool wxDIB::Save(const wxString
& filename
)
229 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
231 wxFile
file(filename
, wxFile::write
);
232 bool ok
= file
.IsOpened();
236 if ( !GetDIBSection(m_handle
, &ds
) )
238 wxLogLastError(_T("GetObject(hDIB)"));
242 BITMAPFILEHEADER bmpHdr
;
243 wxZeroMemory(bmpHdr
);
245 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
246 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
248 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
249 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
250 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
252 // first write the file header, then the bitmap header and finally the
253 // bitmap data itself
254 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
255 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
256 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
262 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
269 // ----------------------------------------------------------------------------
271 // ----------------------------------------------------------------------------
273 void wxDIB::DoGetObject() const
275 // only do something if we have a valid DIB but we don't [yet] have valid
277 if ( m_handle
&& !m_data
)
279 // although all the info we need is in BITMAP and so we don't really
280 // need DIBSECTION we still ask for it as modifying the bit values only
281 // works for the real DIBs and not for the bitmaps and it's better to
282 // check for this now rather than trying to find out why it doesn't
285 if ( !GetDIBSection(m_handle
, &ds
) )
287 wxLogLastError(_T("GetObject(hDIB)"));
291 wxDIB
*self
= wxConstCast(this, wxDIB
);
293 self
->m_width
= ds
.dsBm
.bmWidth
;
294 self
->m_height
= ds
.dsBm
.bmHeight
;
295 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
296 self
->m_data
= ds
.dsBm
.bmBits
;
300 // ----------------------------------------------------------------------------
301 // DDB <-> DIB conversions
302 // ----------------------------------------------------------------------------
304 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
306 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
309 if ( !GetDIBSection(m_handle
, &ds
) )
311 wxLogLastError(_T("GetObject(hDIB)"));
316 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
320 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
322 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
324 // here we get BITMAPINFO struct followed by the actual bitmap bits and
325 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
326 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
328 // get the pointer to the start of the real image data if we have a plain
329 // DIB and not a DIB section (in the latter case the pointer must be passed
330 // to us by the caller)
333 // we must skip over the colour table to get to the image data
335 // colour table either has the real colour data in which case its
336 // number of entries is given by biClrUsed or is used for masks to be
337 // used for extracting colour information from true colour bitmaps in
338 // which case it always have exactly 3 DWORDs
340 switch ( pbmih
->biCompression
)
347 // biClrUsed has the number of colors but it may be not initialized at
349 numColors
= pbmih
->biClrUsed
;
352 numColors
= wxGetNumOfBitmapColors(pbmih
->biBitCount
);
357 // no idea how it should be calculated for the other cases
361 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
364 HBITMAP hbmp
= ::CreateDIBitmap
366 hdc
? hdc
// create bitmap compatible
367 : (HDC
) ScreenHDC(), // with this DC
368 pbmih
, // used to get size &c
369 CBM_INIT
, // initialize bitmap bits too
370 bits
, // ... using this data
371 pbmi
, // this is used for palette only
372 DIB_RGB_COLORS
// direct or indexed palette?
377 wxLogLastError(wxT("CreateDIBitmap"));
384 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
386 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
388 // prepare all the info we need
390 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
392 wxLogLastError(wxT("GetObject(bitmap)"));
397 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
401 const bool wantSizeOnly
= pbi
== NULL
;
405 // just for convenience
406 const int h
= bm
.bmHeight
;
409 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
411 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
412 bi
.biWidth
= bm
.bmWidth
;
415 bi
.biBitCount
= bm
.bmBitsPixel
;
417 // memory we need for BITMAPINFO only
418 DWORD dwLen
= bi
.biSize
+ wxGetNumOfBitmapColors(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
420 // get either just the image size or the image bits
423 ScreenHDC(), // the DC to use
424 hbmp
, // the source DDB
425 0, // first scan line
426 h
, // number of lines to copy
427 wantSizeOnly
? NULL
// pointer to the buffer or
428 : (char *)pbi
+ dwLen
, // NULL if we don't have it
429 pbi
, // bitmap header
430 DIB_RGB_COLORS
// or DIB_PAL_COLORS
433 wxLogLastError(wxT("GetDIBits()"));
438 // return the total size
439 return dwLen
+ bi
.biSizeImage
;
443 #ifdef __DIGITALMARS__
446 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
448 // first calculate the size needed
449 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
452 // conversion to DDB failed?
456 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
459 // this is an error which does risk to happen especially under Win9x
460 // and which the user may understand so let him know about it
461 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
462 (unsigned long)(size
/ 1024));
467 if ( !ConvertFromBitmap((BITMAPINFO
*)(void *)GlobalPtr(hDIB
), hbmp
) )
469 // this really shouldn't happen... it worked the first time, why not
471 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
479 // ----------------------------------------------------------------------------
481 // ----------------------------------------------------------------------------
485 wxPalette
*wxDIB::CreatePalette() const
487 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
490 if ( !GetDIBSection(m_handle
, &ds
) )
492 wxLogLastError(_T("GetObject(hDIB)"));
497 // how many colours are we going to have in the palette?
498 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
501 // biClrUsed field might not be set
502 biClrUsed
= wxGetNumOfBitmapColors(ds
.dsBmih
.biBitCount
);
507 // bitmaps of this depth don't have palettes at all
509 // NB: another possibility would be to return
510 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
514 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
515 // going to have biClrUsed of them so add necessary space
516 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
517 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
518 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
520 // initialize the palette header
521 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
522 pPalette
->palNumEntries
= biClrUsed
;
524 // and the colour table (it starts right after the end of the header)
525 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
526 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
528 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
529 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
530 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
531 pPalette
->palPalEntry
[i
].peFlags
= 0;
534 HPALETTE hPalette
= ::CreatePalette(pPalette
);
540 wxLogLastError(_T("CreatePalette"));
545 wxPalette
*palette
= new wxPalette
;
546 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
551 #endif // wxUSE_PALETTE
553 // ----------------------------------------------------------------------------
555 // ----------------------------------------------------------------------------
559 bool wxDIB::Create(const wxImage
& image
)
561 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
563 const int h
= image
.GetHeight();
564 const int w
= image
.GetWidth();
566 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
567 // a 24bpp RGB is sufficient
568 const bool hasAlpha
= image
.HasAlpha();
569 const int bpp
= hasAlpha
? 32 : 24;
571 if ( !Create(w
, h
, bpp
) )
574 // DIBs are stored in bottom to top order (see also the comment above in
575 // Create()) so we need to copy bits line by line and starting from the end
576 const int srcBytesPerLine
= w
* 3;
577 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
578 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
579 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
: NULL
;
580 unsigned char *dstLineStart
= (unsigned char *)m_data
;
581 for ( int y
= 0; y
< h
; y
++ )
584 unsigned char *dst
= dstLineStart
;
585 for ( int x
= 0; x
< w
; x
++ )
587 // also, the order of RGB is inversed for DIBs
598 // pass to the previous line in the image
599 src
-= 2*srcBytesPerLine
;
603 // and to the next one in the DIB
604 dstLineStart
+= dstBytesPerLine
;
610 #endif // wxUSE_IMAGE