]>
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
, 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 // biClrUsed has the number of colors but it may be not initialized at
294 int numColors
= pbmih
->biClrUsed
;
297 numColors
= wxGetNumOfBitmapColors(pbmih
->biBitCount
);
300 bits
= (char *)pbmih
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
);
303 HBITMAP hbmp
= ::CreateDIBitmap
305 hdc
? hdc
// create bitmap compatible
306 : (HDC
) ScreenHDC(), // with this DC
307 pbmih
, // used to get size &c
308 CBM_INIT
, // initialize bitmap bits too
309 bits
, // ... using this data
310 pbmi
, // this is used for palette only
311 DIB_RGB_COLORS
// direct or indexed palette?
316 wxLogLastError(wxT("CreateDIBitmap"));
323 size_t wxDIB::ConvertFromBitmap(BITMAPINFO
*pbi
, HBITMAP hbmp
)
325 wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") );
327 // prepare all the info we need
329 if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) )
331 wxLogLastError(wxT("GetObject(bitmap)"));
336 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
340 const bool wantSizeOnly
= pbi
== NULL
;
344 // just for convenience
345 const int h
= bm
.bmHeight
;
348 BITMAPINFOHEADER
& bi
= pbi
->bmiHeader
;
350 bi
.biSize
= sizeof(BITMAPINFOHEADER
);
351 bi
.biWidth
= bm
.bmWidth
;
354 bi
.biBitCount
= bm
.bmBitsPixel
;
356 // memory we need for BITMAPINFO only
357 DWORD dwLen
= bi
.biSize
+ wxGetNumOfBitmapColors(bm
.bmBitsPixel
) * sizeof(RGBQUAD
);
359 // get either just the image size or the image bits
362 ScreenHDC(), // the DC to use
363 hbmp
, // the source DDB
364 0, // first scan line
365 h
, // number of lines to copy
366 wantSizeOnly
? NULL
// pointer to the buffer or
367 : (char *)pbi
+ dwLen
, // NULL if we don't have it
368 pbi
, // bitmap header
369 DIB_RGB_COLORS
// or DIB_PAL_COLORS
372 wxLogLastError(wxT("GetDIBits()"));
377 // return the total size
378 return dwLen
+ bi
.biSizeImage
;
382 HGLOBAL
wxDIB::ConvertFromBitmap(HBITMAP hbmp
)
384 // first calculate the size needed
385 const size_t size
= ConvertFromBitmap(NULL
, hbmp
);
388 // conversion to DDB failed?
392 HGLOBAL hDIB
= ::GlobalAlloc(GMEM_MOVEABLE
, size
);
395 // this is an error which does risk to happen especially under Win9x
396 // and which the user may understand so let him know about it
397 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
398 (unsigned long)(size
/ 1024));
403 if ( !ConvertFromBitmap((BITMAPINFO
*)GlobalHandle(hDIB
), hbmp
) )
405 // this really shouldn't happen... it worked the first time, why not
407 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
415 // ----------------------------------------------------------------------------
417 // ----------------------------------------------------------------------------
421 wxPalette
*wxDIB::CreatePalette() const
423 wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") );
426 if ( !::GetObject(m_handle
, sizeof(ds
), &ds
) )
428 wxLogLastError(_T("GetObject(hDIB)"));
433 // how many colours are we going to have in the palette?
434 DWORD biClrUsed
= ds
.dsBmih
.biClrUsed
;
437 // biClrUsed field might not be set
438 biClrUsed
= wxGetNumOfBitmapColors(ds
.dsBmih
.biBitCount
);
443 // bitmaps of this depth don't have palettes at all
445 // NB: another possibility would be to return
446 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
450 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
451 // going to have biClrUsed of them so add necessary space
452 LOGPALETTE
*pPalette
= (LOGPALETTE
*)
453 malloc(sizeof(LOGPALETTE
) + (biClrUsed
- 1)*sizeof(PALETTEENTRY
));
454 wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") );
456 // initialize the palette header
457 pPalette
->palVersion
= 0x300; // magic number, not in docs but works
458 pPalette
->palNumEntries
= biClrUsed
;
460 // and the colour table (it starts right after the end of the header)
461 const RGBQUAD
*pRGB
= (RGBQUAD
*)((char *)&ds
.dsBmih
+ ds
.dsBmih
.biSize
);
462 for ( DWORD i
= 0; i
< biClrUsed
; i
++, pRGB
++ )
464 pPalette
->palPalEntry
[i
].peRed
= pRGB
->rgbRed
;
465 pPalette
->palPalEntry
[i
].peGreen
= pRGB
->rgbGreen
;
466 pPalette
->palPalEntry
[i
].peBlue
= pRGB
->rgbBlue
;
467 pPalette
->palPalEntry
[i
].peFlags
= 0;
470 HPALETTE hPalette
= ::CreatePalette(pPalette
);
476 wxLogLastError(_T("CreatePalette"));
481 wxPalette
*palette
= new wxPalette
;
482 palette
->SetHPALETTE((WXHPALETTE
)hPalette
);
487 #endif // wxUSE_PALETTE
489 // ----------------------------------------------------------------------------
491 // ----------------------------------------------------------------------------
495 bool wxDIB::Create(const wxImage
& image
)
497 wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
499 const int h
= image
.GetHeight();
500 const int w
= image
.GetWidth();
502 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
503 // a 24bpp RGB is sufficient
504 const bool hasAlpha
= image
.HasAlpha();
505 const int bpp
= hasAlpha
? 32 : 24;
507 if ( !Create(w
, h
, bpp
) )
510 // DIBs are stored in bottom to top order (see also the comment above in
511 // Create()) so we need to copy bits line by line and starting from the end
512 const int srcBytesPerLine
= w
* 3;
513 const int dstBytesPerLine
= GetLineSize(w
, bpp
);
514 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
515 const unsigned char *alpha
= hasAlpha
? image
.GetAlpha() + (h
- 1)*w
: NULL
;
516 unsigned char *dstLineStart
= (unsigned char *)m_data
;
517 for ( int y
= 0; y
< h
; y
++ )
520 unsigned char *dst
= dstLineStart
;
521 for ( int x
= 0; x
< w
; x
++ )
523 // also, the order of RGB is inversed for DIBs
534 // pass to the previous line in the image
535 src
-= 2*srcBytesPerLine
;
539 // and to the next one in the DIB
540 dstLineStart
+= dstBytesPerLine
;
546 #endif // wxUSE_IMAGE