]>
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 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
, false, _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 // this bitmap could already be a DIB section in which case we don't need
136 // to convert it to DIB
137 HBITMAP hbmp
= GetHbitmapOf(bmp
);
140 if ( ::GetObject(hbmp
, sizeof(ds
), &ds
) == sizeof(ds
) )
144 // wxBitmap will free it, not we
145 m_ownsHandle
= false;
147 // copy all the bitmap parameters too as we have them now anyhow
148 m_width
= ds
.dsBm
.bmWidth
;
149 m_height
= ds
.dsBm
.bmHeight
;
150 m_depth
= ds
.dsBm
.bmBitsPixel
;
152 m_data
= ds
.dsBm
.bmBits
;
154 else // no, it's a DDB -- convert it to DIB
156 const int w
= bmp
.GetWidth();
157 const int h
= bmp
.GetHeight();
158 int d
= bmp
.GetDepth();
160 d
= wxDisplayDepth();
162 if ( !Create(w
, h
, d
) )
165 // we could have used GetDIBits() too but GetBitmapBits() is simpler
166 if ( !::GetBitmapBits
168 GetHbitmapOf(bmp
), // the source DDB
169 GetLineSize(w
, d
)*h
, // the number of bytes to copy
170 m_data
// the pixels will be copied here
173 wxLogLastError(wxT("GetDIBits()"));
182 // ----------------------------------------------------------------------------
183 // Loading/saving the DIBs
184 // ----------------------------------------------------------------------------
186 bool wxDIB::Load(const wxString
& filename
)
188 m_handle
= (HBITMAP
)::LoadImage
193 0, 0, // don't specify the size
194 LR_CREATEDIBSECTION
| LR_LOADFROMFILE
198 wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
206 bool wxDIB::Save(const wxString
& filename
)
208 wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") );
210 wxFile
file(filename
, wxFile::write
);
211 bool ok
= file
.IsOpened();
215 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
217 wxLogLastError(_T("GetObject(hDIB)"));
221 BITMAPFILEHEADER bmpHdr
;
222 wxZeroMemory(bmpHdr
);
224 const size_t sizeHdr
= ds
.dsBmih
.biSize
;
225 const size_t sizeImage
= ds
.dsBmih
.biSizeImage
;
227 bmpHdr
.bfType
= 0x4d42; // 'BM' in little endian
228 bmpHdr
.bfOffBits
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
;
229 bmpHdr
.bfSize
= bmpHdr
.bfOffBits
+ sizeImage
;
231 // first write the file header, then the bitmap header and finally the
232 // bitmap data itself
233 ok
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) &&
234 file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr
&&
235 file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
;
241 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
248 // ----------------------------------------------------------------------------
250 // ----------------------------------------------------------------------------
252 void wxDIB::DoGetObject() const
254 // only do something if we have a valid DIB but we don't [yet] have valid
256 if ( m_handle
&& !m_data
)
258 // although all the info we need is in BITMAP and so we don't really
259 // need DIBSECTION we still ask for it as modifying the bit values only
260 // works for the real DIBs and not for the bitmaps and it's better to
261 // check for this now rather than trying to find out why it doesn't
264 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
266 wxLogLastError(_T("GetObject(hDIB)"));
270 wxDIB
*self
= wxConstCast(this, wxDIB
);
272 self
->m_width
= ds
.dsBm
.bmWidth
;
273 self
->m_height
= ds
.dsBm
.bmHeight
;
274 self
->m_depth
= ds
.dsBm
.bmBitsPixel
;
275 self
->m_data
= ds
.dsBm
.bmBits
;
279 // ----------------------------------------------------------------------------
280 // DDB <-> DIB conversions
281 // ----------------------------------------------------------------------------
283 HBITMAP
wxDIB::CreateDDB(HDC hdc
) const
285 wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") );
288 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
290 wxLogLastError(_T("GetObject(hDIB)"));
295 return ConvertToBitmap((BITMAPINFO
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
);
299 HBITMAP
wxDIB::ConvertToBitmap(const BITMAPINFO
*pbmi
, HDC hdc
, void *bits
)
301 wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") );
303 // here we get BITMAPINFO struct followed by the actual bitmap bits and
304 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
305 const BITMAPINFOHEADER
*pbmih
= &pbmi
->bmiHeader
;
307 // get the pointer to the start of the real image data if we have a plain
308 // DIB and not a DIB section (in the latter case the pointer must be passed
309 // to us by the caller)
312 // we must skip over the colour table to get to the image data
314 // colour table either has the real colour data in which case its
315 // number of entries is given by biClrUsed or is used for masks to be
316 // used for extracting colour information from true colour bitmaps in
317 // which case it always have exactly 3 DWORDs
319 switch ( pbmih
->biCompression
)
326 // biClrUsed has the number of colors but it may be not initialized at
328 numColors
= pbmih
->biClrUsed
;
331 numColors
= wxGetNumOfBitmapColors(pbmih
->biBitCount
);
336 // no idea how it should be calculated for the other cases
340 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
343 HBITMAP hbmp
= ::CreateDIBitmap
345 hdc
? hdc
// create bitmap compatible
346 : (HDC
) ScreenHDC(), // with this DC
347 pbmih
, // used to get size &c
348 CBM_INIT
, // initialize bitmap bits too
349 bits
, // ... using this data
350 pbmi
, // this is used for palette only
351 DIB_RGB_COLORS
// direct or indexed palette?
356 wxLogLastError(wxT("CreateDIBitmap"));
363 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
365 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
367 // prepare all the info we need
369 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
371 wxLogLastError(wxT("GetObject(bitmap)"));
376 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
380 const bool wantSizeOnly
= pbi
== NULL
;
384 // just for convenience
385 const int h
= bm
.bmHeight
;
388 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
390 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
391 bi
.biWidth
= bm
.bmWidth
;
394 bi
.biBitCount
= bm
.bmBitsPixel
;
396 // memory we need for BITMAPINFO only
397 DWORD dwLen
= bi
.biSize
+ wxGetNumOfBitmapColors(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
399 // get either just the image size or the image bits
402 ScreenHDC(), // the DC to use
403 hbmp
, // the source DDB
404 0, // first scan line
405 h
, // number of lines to copy
406 wantSizeOnly
? NULL
// pointer to the buffer or
407 : (char *)pbi
+ dwLen
, // NULL if we don't have it
408 pbi
, // bitmap header
409 DIB_RGB_COLORS
// or DIB_PAL_COLORS
412 wxLogLastError(wxT("GetDIBits()"));
417 // return the total size
418 return dwLen
+ bi
.biSizeImage
;
422 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
424 // first calculate the size needed
425 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
428 // conversion to DDB failed?
432 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
435 // this is an error which does risk to happen especially under Win9x
436 // and which the user may understand so let him know about it
437 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
438 (unsigned long)(size
/ 1024));
443 if ( !ConvertFromBitmap((BITMAPINFO
*)GlobalHandle(hDIB
), hbmp
) )
445 // this really shouldn't happen... it worked the first time, why not
447 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
455 // ----------------------------------------------------------------------------
457 // ----------------------------------------------------------------------------
461 wxPalette
*wxDIB::CreatePalette() const
463 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
466 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
468 wxLogLastError(_T("GetObject(hDIB)"));
473 // how many colours are we going to have in the palette?
474 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
477 // biClrUsed field might not be set
478 biClrUsed
= wxGetNumOfBitmapColors(ds
.dsBmih
.biBitCount
);
483 // bitmaps of this depth don't have palettes at all
485 // NB: another possibility would be to return
486 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
490 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
491 // going to have biClrUsed of them so add necessary space
492 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
493 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
494 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
496 // initialize the palette header
497 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
498 pPalette
->palNumEntries
= biClrUsed
;
500 // and the colour table (it starts right after the end of the header)
501 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
502 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
504 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
505 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
506 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
507 pPalette
->palPalEntry
[i
].peFlags
= 0;
510 HPALETTE hPalette
= ::CreatePalette(pPalette
);
516 wxLogLastError(_T("CreatePalette"));
521 wxPalette
*palette
= new wxPalette
;
522 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
527 #endif // wxUSE_PALETTE
529 // ----------------------------------------------------------------------------
531 // ----------------------------------------------------------------------------
535 bool wxDIB::Create(const wxImage
& image
)
537 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
539 const int h
= image
.GetHeight();
540 const int w
= image
.GetWidth();
542 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
543 // a 24bpp RGB is sufficient
544 const bool hasAlpha
= image
.HasAlpha();
545 const int bpp
= hasAlpha
? 32 : 24;
547 if ( !Create(w
, h
, bpp
) )
550 // DIBs are stored in bottom to top order (see also the comment above in
551 // Create()) so we need to copy bits line by line and starting from the end
552 const int srcBytesPerLine
= w
* 3;
553 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
554 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
555 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
: NULL
;
556 unsigned char *dstLineStart
= (unsigned char *)m_data
;
557 for ( int y
= 0; y
< h
; y
++ )
560 unsigned char *dst
= dstLineStart
;
561 for ( int x
= 0; x
< w
; x
++ )
563 // also, the order of RGB is inversed for DIBs
574 // pass to the previous line in the image
575 src
-= 2*srcBytesPerLine
;
579 // and to the next one in the DIB
580 dstLineStart
+= dstBytesPerLine
;
586 #endif // wxUSE_IMAGE