]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dib.cpp
a3e9b49a45406a70110b3a2b5179d63b7b8d74e9
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 and we shouldn't use
16 GetBitmapBits() at all because we can't do it with it)
19 // ============================================================================
21 // ============================================================================
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
27 // For compilers that support precompilation, includes "wx.h".
28 #include "wx/wxprec.h"
35 #include "wx/string.h"
39 #include "wx/bitmap.h"
46 #if !defined(__MWERKS__) && !defined(__SALFORDC__)
50 #ifdef __GNUWIN32_OLD__
51 #include "wx/msw/gnuwin32/extra.h"
55 #include "wx/msw/dib.h"
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 // calculate the number of palette entries needed for the bitmap with this
62 // number of bits per pixel
63 static WORD
wxGetNumOfBitmapColors(WORD bitsPerPixel
)
65 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
66 // 24bpp ones too but we don't support this as I think it's quite uncommon)
67 return bitsPerPixel
<= 8 ? 1 << bitsPerPixel
: 0;
70 // ============================================================================
72 // ============================================================================
74 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
78 bool wxDIB::Create(int width
, int height
, int depth
)
80 // we don't handle the palette yet
81 wxASSERT_MSG( depth
== 24 || depth
== 32,
82 _T("unsupported image depth in wxDIB::Create()") );
84 static const int infosize
= sizeof(BITMAPINFOHEADER
);
86 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(infosize
);
87 wxCHECK_MSG( info
, NULL
, _T("malloc(BITMAPINFO) failed") );
89 memset(info
, 0, infosize
);
91 info
->bmiHeader
.biSize
= infosize
;
92 info
->bmiHeader
.biWidth
= width
;
94 // we use positive height here which corresponds to a DIB with normal, i.e.
95 // bottom to top, order -- normally using negative height (which means
96 // reversed for MS and hence natural for all the normal people top to
97 // bottom line scan order) could be used to avoid the need for the image
98 // reversal in Create(image) but this doesn't work under NT, only Win9x!
99 info
->bmiHeader
.biHeight
= height
;
101 info
->bmiHeader
.biPlanes
= 1;
102 info
->bmiHeader
.biBitCount
= depth
;
103 info
->bmiHeader
.biSizeImage
= GetLineSize(width
, depth
)*height
;
105 m_handle
= ::CreateDIBSection
107 0, // hdc (unused with DIB_RGB_COLORS)
108 info
, // bitmap description
109 DIB_RGB_COLORS
, // use RGB, not palette
110 &m_data
, // [out] DIB bits
111 NULL
, // don't use file mapping
112 0 // file mapping offset (not used here)
119 wxLogLastError(wxT("CreateDIBSection"));
131 bool wxDIB::Create(const wxBitmap
& bmp
)
133 wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
135 const int w
= bmp
.GetWidth();
136 const int h
= bmp
.GetHeight();
137 int d
= bmp
.GetDepth();
139 d
= wxDisplayDepth();
141 if ( !Create(w
, h
, d
) )
144 // we could have used GetDIBits() too but GetBitmapBits() is simpler
145 if ( !::GetBitmapBits
147 GetHbitmapOf(bmp
), // the source DDB
148 GetLineSize(w
, d
)*h
, // the number of bytes to copy
149 m_data
// the pixels will be copied here
152 wxLogLastError(wxT("GetDIBits()"));
160 // ----------------------------------------------------------------------------
161 // Loading/saving the DIBs
162 // ----------------------------------------------------------------------------
164 bool wxDIB::Load(const wxString
& filename
)
166 m_handle
= (HBITMAP
)::LoadImage
171 0, 0, // don't specify the size
172 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
176 wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
184 bool wxDIB::Save(const wxString
& filename
)
186 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
188 wxFile
file(filename
, wxFile::write
);
189 bool ok
= file
.IsOpened();
193 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
195 wxLogLastError(_T("GetObject(hDIB)"));
199 BITMAPFILEHEADER bmpHdr
;
200 wxZeroMemory(bmpHdr
);
202 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
203 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
205 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
206 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
207 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
209 // first write the file header, then the bitmap header and finally the
210 // bitmap data itself
211 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
212 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
213 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
219 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
226 // ----------------------------------------------------------------------------
228 // ----------------------------------------------------------------------------
230 void wxDIB::DoGetObject() const
232 // only do something if we have a valid DIB but we don't [yet] have valid
234 if ( m_handle
&& !m_data
)
236 // although all the info we need is in BITMAP and so we don't really
237 // need DIBSECTION we still ask for it as modifying the bit values only
238 // works for the real DIBs and not for the bitmaps and it's better to
239 // check for this now rather than trying to find out why it doesn't
242 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
244 wxLogLastError(_T("GetObject(hDIB)"));
248 wxDIB
*self
= wxConstCast(this, wxDIB
);
250 self
->m_width
= ds
.dsBm
.bmWidth
;
251 self
->m_height
= ds
.dsBm
.bmHeight
;
252 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
253 self
->m_data
= ds
.dsBm
.bmBits
;
257 // ----------------------------------------------------------------------------
258 // DDB <-> DIB conversions
259 // ----------------------------------------------------------------------------
261 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
263 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
266 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
268 wxLogLastError(_T("GetObject(hDIB)"));
273 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
277 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
279 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
281 // here we get BITMAPINFO struct followed by the actual bitmap bits and
282 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
283 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
285 // get the pointer to the start of the real image data if we have a plain
286 // DIB and not a DIB section (in the latter case the pointer must be passed
287 // to us by the caller)
290 // we must skip over the colour table to get to the image data
292 // colour table either has the real colour data in which case its
293 // number of entries is given by biClrUsed or is used for masks to be
294 // used for extracting colour information from true colour bitmaps in
295 // which case it always have exactly 3 DWORDs
297 switch ( pbmih
->biCompression
)
304 // biClrUsed has the number of colors but it may be not initialized at
306 numColors
= pbmih
->biClrUsed
;
309 numColors
= wxGetNumOfBitmapColors(pbmih
->biBitCount
);
314 // no idea how it should be calculated for the other cases
318 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
321 HBITMAP hbmp
= ::CreateDIBitmap
323 hdc
? hdc
// create bitmap compatible
324 : (HDC
) ScreenHDC(), // with this DC
325 pbmih
, // used to get size &c
326 CBM_INIT
, // initialize bitmap bits too
327 bits
, // ... using this data
328 pbmi
, // this is used for palette only
329 DIB_RGB_COLORS
// direct or indexed palette?
334 wxLogLastError(wxT("CreateDIBitmap"));
341 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
343 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
345 // prepare all the info we need
347 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
349 wxLogLastError(wxT("GetObject(bitmap)"));
354 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
358 const bool wantSizeOnly
= pbi
== NULL
;
362 // just for convenience
363 const int h
= bm
.bmHeight
;
366 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
368 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
369 bi
.biWidth
= bm
.bmWidth
;
372 bi
.biBitCount
= bm
.bmBitsPixel
;
374 // memory we need for BITMAPINFO only
375 DWORD dwLen
= bi
.biSize
+ wxGetNumOfBitmapColors(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
377 // get either just the image size or the image bits
380 ScreenHDC(), // the DC to use
381 hbmp
, // the source DDB
382 0, // first scan line
383 h
, // number of lines to copy
384 wantSizeOnly
? NULL
// pointer to the buffer or
385 : (char *)pbi
+ dwLen
, // NULL if we don't have it
386 pbi
, // bitmap header
387 DIB_RGB_COLORS
// or DIB_PAL_COLORS
390 wxLogLastError(wxT("GetDIBits()"));
395 // return the total size
396 return dwLen
+ bi
.biSizeImage
;
400 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
402 // first calculate the size needed
403 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
406 // conversion to DDB failed?
410 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
413 // this is an error which does risk to happen especially under Win9x
414 // and which the user may understand so let him know about it
415 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
416 (unsigned long)(size
/ 1024));
421 if ( !ConvertFromBitmap((BITMAPINFO
*)GlobalHandle(hDIB
), hbmp
) )
423 // this really shouldn't happen... it worked the first time, why not
425 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
433 // ----------------------------------------------------------------------------
435 // ----------------------------------------------------------------------------
439 wxPalette
*wxDIB::CreatePalette() const
441 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
444 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
446 wxLogLastError(_T("GetObject(hDIB)"));
451 // how many colours are we going to have in the palette?
452 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
455 // biClrUsed field might not be set
456 biClrUsed
= wxGetNumOfBitmapColors(ds
.dsBmih
.biBitCount
);
461 // bitmaps of this depth don't have palettes at all
463 // NB: another possibility would be to return
464 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
468 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
469 // going to have biClrUsed of them so add necessary space
470 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
471 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
472 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
474 // initialize the palette header
475 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
476 pPalette
->palNumEntries
= biClrUsed
;
478 // and the colour table (it starts right after the end of the header)
479 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
480 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
482 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
483 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
484 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
485 pPalette
->palPalEntry
[i
].peFlags
= 0;
488 HPALETTE hPalette
= ::CreatePalette(pPalette
);
494 wxLogLastError(_T("CreatePalette"));
499 wxPalette
*palette
= new wxPalette
;
500 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
505 #endif // wxUSE_PALETTE
507 // ----------------------------------------------------------------------------
509 // ----------------------------------------------------------------------------
513 bool wxDIB::Create(const wxImage
& image
)
515 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
517 const int h
= image
.GetHeight();
518 const int w
= image
.GetWidth();
520 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
521 // a 24bpp RGB is sufficient
522 const bool hasAlpha
= image
.HasAlpha();
523 const int bpp
= hasAlpha
? 32 : 24;
525 if ( !Create(w
, h
, bpp
) )
528 // DIBs are stored in bottom to top order (see also the comment above in
529 // Create()) so we need to copy bits line by line and starting from the end
530 const int srcBytesPerLine
= w
* 3;
531 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
532 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
533 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
: NULL
;
534 unsigned char *dstLineStart
= (unsigned char *)m_data
;
535 for ( int y
= 0; y
< h
; y
++ )
538 unsigned char *dst
= dstLineStart
;
539 for ( int x
= 0; x
< w
; x
++ )
541 // also, the order of RGB is inversed for DIBs
552 // pass to the previous line in the image
553 src
-= 2*srcBytesPerLine
;
557 // and to the next one in the DIB
558 dstLineStart
+= dstBytesPerLine
;
564 #endif // wxUSE_IMAGE