]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dib.cpp
wxTinderbox build fix (!PCH support).
[wxWidgets.git] / src / msw / dib.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/dib.cpp
3// Purpose: implements wxDIB class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 03.03.03 (replaces the old file with the same name)
7// RCS-ID: $Id$
8// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9// License: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12/*
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.
16 */
17
18// ============================================================================
19// declarations
20// ============================================================================
21
22// ----------------------------------------------------------------------------
23// headers
24// ----------------------------------------------------------------------------
25
26// For compilers that support precompilation, includes "wx.h".
27#include "wx/wxprec.h"
28
29#ifdef __BORLANDC__
30 #pragma hdrstop
31#endif
32
33#ifndef WX_PRECOMP
34 #include "wx/string.h"
35 #include "wx/log.h"
36#endif //WX_PRECOMP
37
38#if wxUSE_WXDIB
39
40#include "wx/bitmap.h"
41#include "wx/intl.h"
42#include "wx/file.h"
43
44#include <stdio.h>
45#include <stdlib.h>
46
47#if !defined(__MWERKS__) && !defined(__SALFORDC__)
48 #include <memory.h>
49#endif
50
51#include "wx/image.h"
52#include "wx/msw/dib.h"
53
54#ifdef __WXWINCE__
55 #include <shellapi.h> // for SHLoadDIBitmap()
56#endif
57
58// ----------------------------------------------------------------------------
59// private functions
60// ----------------------------------------------------------------------------
61
62// calculate the number of palette entries needed for the bitmap with this
63// number of bits per pixel
64static inline WORD GetNumberOfColours(WORD bitsPerPixel)
65{
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 (WORD)(bitsPerPixel <= 8 ? 1 << bitsPerPixel : 0);
69}
70
71// wrapper around ::GetObject() for DIB sections
72static inline bool GetDIBSection(HBITMAP hbmp, DIBSECTION *ds)
73{
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) &&
79 ds->dsBm.bmBits;
80}
81
82// ============================================================================
83// implementation
84// ============================================================================
85
86// ----------------------------------------------------------------------------
87// wxDIB creation
88// ----------------------------------------------------------------------------
89
90bool wxDIB::Create(int width, int height, int depth)
91{
92 // we don't support formats using palettes right now so we only create
93 // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
94 wxASSERT_MSG( depth, _T("invalid image depth in wxDIB::Create()") );
95 if ( depth < 24 )
96 depth = 24;
97
98 // allocate memory for bitmap structures
99 static const int sizeHeader = sizeof(BITMAPINFOHEADER);
100
101 BITMAPINFO *info = (BITMAPINFO *)malloc(sizeHeader);
102 wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") );
103
104 memset(info, 0, sizeHeader);
105
106 info->bmiHeader.biSize = sizeHeader;
107 info->bmiHeader.biWidth = width;
108
109 // we use positive height here which corresponds to a DIB with normal, i.e.
110 // bottom to top, order -- normally using negative height (which means
111 // reversed for MS and hence natural for all the normal people top to
112 // bottom line scan order) could be used to avoid the need for the image
113 // reversal in Create(image) but this doesn't work under NT, only Win9x!
114 info->bmiHeader.biHeight = height;
115
116 info->bmiHeader.biPlanes = 1;
117 info->bmiHeader.biBitCount = (WORD)depth;
118 info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
119
120 m_handle = ::CreateDIBSection
121 (
122 0, // hdc (unused with DIB_RGB_COLORS)
123 info, // bitmap description
124 DIB_RGB_COLORS, // use RGB, not palette
125 &m_data, // [out] DIB bits
126 NULL, // don't use file mapping
127 0 // file mapping offset (not used here)
128 );
129
130 free(info);
131
132 if ( !m_handle )
133 {
134 wxLogLastError(wxT("CreateDIBSection"));
135
136 return false;
137 }
138
139 m_width = width;
140 m_height = height;
141 m_depth = depth;
142
143 return true;
144}
145
146bool wxDIB::Create(const wxBitmap& bmp)
147{
148 wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
149
150 if ( !Create(GetHbitmapOf(bmp)) )
151 return false;
152
153 m_hasAlpha = bmp.HasAlpha();
154
155 return true;
156}
157
158bool wxDIB::Create(HBITMAP hbmp)
159{
160 // this bitmap could already be a DIB section in which case we don't need
161 // to convert it to DIB
162 DIBSECTION ds;
163 if ( GetDIBSection(hbmp, &ds) )
164 {
165 m_handle = hbmp;
166
167 // wxBitmap will free it, not we
168 m_ownsHandle = false;
169
170 // copy all the bitmap parameters too as we have them now anyhow
171 m_width = ds.dsBm.bmWidth;
172 m_height = ds.dsBm.bmHeight;
173 m_depth = ds.dsBm.bmBitsPixel;
174
175 m_data = ds.dsBm.bmBits;
176 }
177 else // no, it's a DDB -- convert it to DIB
178 {
179 // prepare all the info we need
180 BITMAP bm;
181 if ( !::GetObject(hbmp, sizeof(bm), &bm) )
182 {
183 wxLogLastError(wxT("GetObject(bitmap)"));
184
185 return false;
186 }
187
188 int d = bm.bmBitsPixel;
189 if ( d <= 0 )
190 d = wxDisplayDepth();
191
192 if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) )
193 return false;
194 }
195
196 return true;
197}
198
199// Windows CE doesn't have GetDIBits() so use an alternative implementation
200// for it
201//
202// in fact I'm not sure if GetDIBits() is really much better than using
203// BitBlt() like this -- it should be faster but I didn't do any tests, if
204// anybody has time to do them and by chance finds that GetDIBits() is not
205// much faster than BitBlt(), we could always use the Win CE version here
206#ifdef __WXWINCE__
207
208bool wxDIB::CopyFromDDB(HBITMAP hbmp)
209{
210 MemoryHDC hdcSrc;
211 if ( !hdcSrc )
212 return false;
213
214 SelectInHDC selectSrc(hdcSrc, hbmp);
215 if ( !selectSrc )
216 return false;
217
218 MemoryHDC hdcDst;
219 if ( !hdcDst )
220 return false;
221
222 SelectInHDC selectDst(hdcDst, m_handle);
223 if ( !selectDst )
224 return false;
225
226
227 if ( !::BitBlt(
228 hdcDst,
229 0, 0, m_width, m_height,
230 hdcSrc,
231 0, 0,
232 SRCCOPY
233 ) )
234 {
235 wxLogLastError(_T("BitBlt(DDB -> DIB)"));
236
237 return false;
238 }
239
240 return true;
241}
242
243#else // !__WXWINCE__
244
245bool wxDIB::CopyFromDDB(HBITMAP hbmp)
246{
247 DIBSECTION ds;
248 if ( !GetDIBSection(m_handle, &ds) )
249 {
250 // we're sure that our handle is a DIB section, so this should work
251 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
252
253 return false;
254 }
255
256 if ( !::GetDIBits
257 (
258 ScreenHDC(), // the DC to use
259 hbmp, // the source DDB
260 0, // first scan line
261 m_height, // number of lines to copy
262 ds.dsBm.bmBits, // pointer to the buffer
263 (BITMAPINFO *)&ds.dsBmih, // bitmap header
264 DIB_RGB_COLORS // and not DIB_PAL_COLORS
265 ) )
266 {
267 wxLogLastError(wxT("GetDIBits()"));
268
269 return false;
270 }
271
272 return true;
273}
274
275#endif // __WXWINCE__/!__WXWINCE__
276
277// ----------------------------------------------------------------------------
278// Loading/saving the DIBs
279// ----------------------------------------------------------------------------
280
281bool wxDIB::Load(const wxString& filename)
282{
283#ifdef __WXWINCE__
284 m_handle = SHLoadDIBitmap(filename);
285#else // !__WXWINCE__
286 m_handle = (HBITMAP)::LoadImage
287 (
288 wxGetInstance(),
289 filename,
290 IMAGE_BITMAP,
291 0, 0, // don't specify the size
292 LR_CREATEDIBSECTION | LR_LOADFROMFILE
293 );
294#endif // __WXWINCE__
295
296 if ( !m_handle )
297 {
298 wxLogLastError(_T("Loading DIB from file"));
299
300 return false;
301 }
302
303 return true;
304}
305
306bool wxDIB::Save(const wxString& filename)
307{
308 wxCHECK_MSG( m_handle, false, _T("wxDIB::Save(): invalid object") );
309
310 wxFile file(filename, wxFile::write);
311 bool ok = file.IsOpened();
312 if ( ok )
313 {
314 DIBSECTION ds;
315 if ( !GetDIBSection(m_handle, &ds) )
316 {
317 wxLogLastError(_T("GetObject(hDIB)"));
318 }
319 else
320 {
321 BITMAPFILEHEADER bmpHdr;
322 wxZeroMemory(bmpHdr);
323
324 const size_t sizeHdr = ds.dsBmih.biSize;
325 const size_t sizeImage = ds.dsBmih.biSizeImage;
326
327 bmpHdr.bfType = 0x4d42; // 'BM' in little endian
328 bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
329 bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
330
331 // first write the file header, then the bitmap header and finally the
332 // bitmap data itself
333 ok = file.Write(&bmpHdr, sizeof(bmpHdr)) == sizeof(bmpHdr) &&
334 file.Write(&ds.dsBmih, sizeHdr) == sizeHdr &&
335 file.Write(ds.dsBm.bmBits, sizeImage) == sizeImage;
336 }
337 }
338
339 if ( !ok )
340 {
341 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
342 filename.c_str());
343 }
344
345 return ok;
346}
347
348// ----------------------------------------------------------------------------
349// wxDIB accessors
350// ----------------------------------------------------------------------------
351
352void wxDIB::DoGetObject() const
353{
354 // only do something if we have a valid DIB but we don't [yet] have valid
355 // data
356 if ( m_handle && !m_data )
357 {
358 // although all the info we need is in BITMAP and so we don't really
359 // need DIBSECTION we still ask for it as modifying the bit values only
360 // works for the real DIBs and not for the bitmaps and it's better to
361 // check for this now rather than trying to find out why it doesn't
362 // work later
363 DIBSECTION ds;
364 if ( !GetDIBSection(m_handle, &ds) )
365 {
366 wxLogLastError(_T("GetObject(hDIB)"));
367 return;
368 }
369
370 wxDIB *self = wxConstCast(this, wxDIB);
371
372 self->m_width = ds.dsBm.bmWidth;
373 self->m_height = ds.dsBm.bmHeight;
374 self->m_depth = ds.dsBm.bmBitsPixel;
375 self->m_data = ds.dsBm.bmBits;
376 }
377}
378
379// ----------------------------------------------------------------------------
380// DDB <-> DIB conversions
381// ----------------------------------------------------------------------------
382
383#ifndef __WXWINCE__
384
385HBITMAP wxDIB::CreateDDB(HDC hdc) const
386{
387 wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
388
389 DIBSECTION ds;
390 if ( !GetDIBSection(m_handle, &ds) )
391 {
392 wxLogLastError(_T("GetObject(hDIB)"));
393
394 return 0;
395 }
396
397 // how many colours are we going to have in the palette?
398 DWORD biClrUsed = ds.dsBmih.biClrUsed;
399 if ( !biClrUsed )
400 {
401 // biClrUsed field might not be set
402 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
403 }
404
405 if ( !biClrUsed )
406 {
407 return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
408 }
409 else
410 {
411 // fake a BITMAPINFO w/o bits, just the palette info
412 wxCharBuffer bmi(sizeof(BITMAPINFO) + (biClrUsed - 1)*sizeof(RGBQUAD));
413 BITMAPINFO *pBmi = (BITMAPINFO *)bmi.data();
414 MemoryHDC hDC;
415 // get the colour table
416 SelectInHDC sDC(hDC, m_handle);
417 ::GetDIBColorTable(hDC, 0, biClrUsed, pBmi->bmiColors);
418 memcpy(&pBmi->bmiHeader, &ds.dsBmih, ds.dsBmih.biSize);
419
420 return ConvertToBitmap(pBmi, hdc, ds.dsBm.bmBits);
421 }
422}
423
424/* static */
425HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
426{
427 wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
428
429 // here we get BITMAPINFO struct followed by the actual bitmap bits and
430 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
431 const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
432
433 // get the pointer to the start of the real image data if we have a plain
434 // DIB and not a DIB section (in the latter case the pointer must be passed
435 // to us by the caller)
436 if ( !bits )
437 {
438 // we must skip over the colour table to get to the image data
439 //
440 // colour table either has the real colour data in which case its
441 // number of entries is given by biClrUsed or is used for masks to be
442 // used for extracting colour information from true colour bitmaps in
443 // which case it always have exactly 3 DWORDs
444 int numColors;
445 switch ( pbmih->biCompression )
446 {
447 case BI_BITFIELDS:
448 numColors = 3;
449 break;
450
451 case BI_RGB:
452 // biClrUsed has the number of colors but it may be not initialized at
453 // all
454 numColors = pbmih->biClrUsed;
455 if ( !numColors )
456 {
457 numColors = GetNumberOfColours(pbmih->biBitCount);
458 }
459 break;
460
461 default:
462 // no idea how it should be calculated for the other cases
463 numColors = 0;
464 }
465
466 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
467 }
468
469 HBITMAP hbmp = ::CreateDIBitmap
470 (
471 hdc ? hdc // create bitmap compatible
472 : (HDC) ScreenHDC(), // with this DC
473 pbmih, // used to get size &c
474 CBM_INIT, // initialize bitmap bits too
475 bits, // ... using this data
476 pbmi, // this is used for palette only
477 DIB_RGB_COLORS // direct or indexed palette?
478 );
479
480 if ( !hbmp )
481 {
482 wxLogLastError(wxT("CreateDIBitmap"));
483 }
484
485 return hbmp;
486}
487
488/* static */
489size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
490{
491 wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") );
492
493 // prepare all the info we need
494 BITMAP bm;
495 if ( !::GetObject(hbmp, sizeof(bm), &bm) )
496 {
497 wxLogLastError(wxT("GetObject(bitmap)"));
498
499 return 0;
500 }
501
502 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
503 // use this one
504 BITMAPINFO bi2;
505
506 const bool wantSizeOnly = pbi == NULL;
507 if ( wantSizeOnly )
508 pbi = &bi2;
509
510 // just for convenience
511 const int h = bm.bmHeight;
512
513 // init the header
514 BITMAPINFOHEADER& bi = pbi->bmiHeader;
515 wxZeroMemory(bi);
516 bi.biSize = sizeof(BITMAPINFOHEADER);
517 bi.biWidth = bm.bmWidth;
518 bi.biHeight = h;
519 bi.biPlanes = 1;
520 bi.biBitCount = bm.bmBitsPixel;
521
522 // memory we need for BITMAPINFO only
523 DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
524
525 // get either just the image size or the image bits
526 if ( !::GetDIBits
527 (
528 ScreenHDC(), // the DC to use
529 hbmp, // the source DDB
530 0, // first scan line
531 h, // number of lines to copy
532 wantSizeOnly ? NULL // pointer to the buffer or
533 : (char *)pbi + dwLen, // NULL if we don't have it
534 pbi, // bitmap header
535 DIB_RGB_COLORS // or DIB_PAL_COLORS
536 ) )
537 {
538 wxLogLastError(wxT("GetDIBits()"));
539
540 return 0;
541 }
542
543 // return the total size
544 return dwLen + bi.biSizeImage;
545}
546
547/* static */
548HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
549{
550 // first calculate the size needed
551 const size_t size = ConvertFromBitmap(NULL, hbmp);
552 if ( !size )
553 {
554 // conversion to DDB failed?
555 return NULL;
556 }
557
558 HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
559 if ( !hDIB )
560 {
561 // this is an error which does risk to happen especially under Win9x
562 // and which the user may understand so let him know about it
563 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
564 (unsigned long)(size / 1024));
565
566 return NULL;
567 }
568
569 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) )
570 {
571 // this really shouldn't happen... it worked the first time, why not
572 // now?
573 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
574
575 return NULL;
576 }
577
578 return hDIB;
579}
580
581#endif // __WXWINCE__
582
583// ----------------------------------------------------------------------------
584// palette support
585// ----------------------------------------------------------------------------
586
587#if wxUSE_PALETTE
588
589wxPalette *wxDIB::CreatePalette() const
590{
591 // GetDIBColorTable not available in eVC3
592#if defined(_WIN32_WCE) && _WIN32_WCE < 400
593 return NULL;
594#else
595 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
596
597 DIBSECTION ds;
598 if ( !GetDIBSection(m_handle, &ds) )
599 {
600 wxLogLastError(_T("GetObject(hDIB)"));
601
602 return 0;
603 }
604
605 // how many colours are we going to have in the palette?
606 DWORD biClrUsed = ds.dsBmih.biClrUsed;
607 if ( !biClrUsed )
608 {
609 // biClrUsed field might not be set
610 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
611 }
612
613 if ( !biClrUsed )
614 {
615 // bitmaps of this depth don't have palettes at all
616 //
617 // NB: another possibility would be to return
618 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
619 return NULL;
620 }
621
622 MemoryHDC hDC;
623
624 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
625 // going to have biClrUsed of them so add necessary space
626 LOGPALETTE *pPalette = (LOGPALETTE *)
627 malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
628 wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
629
630 // initialize the palette header
631 pPalette->palVersion = 0x300; // magic number, not in docs but works
632 pPalette->palNumEntries = (WORD)biClrUsed;
633
634 // and the colour table
635 wxCharBuffer rgb(sizeof(RGBQUAD) * biClrUsed);
636 RGBQUAD *pRGB = (RGBQUAD*)rgb.data();
637 SelectInHDC selectHandle(hDC, m_handle);
638 ::GetDIBColorTable(hDC, 0, biClrUsed, pRGB);
639 for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
640 {
641 pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
642 pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
643 pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
644 pPalette->palPalEntry[i].peFlags = 0;
645 }
646
647 HPALETTE hPalette = ::CreatePalette(pPalette);
648
649 free(pPalette);
650
651 if ( !hPalette )
652 {
653 wxLogLastError(_T("CreatePalette"));
654
655 return NULL;
656 }
657
658 wxPalette *palette = new wxPalette;
659 palette->SetHPALETTE((WXHPALETTE)hPalette);
660
661 return palette;
662#endif
663}
664
665#endif // wxUSE_PALETTE
666
667// ----------------------------------------------------------------------------
668// wxImage support
669// ----------------------------------------------------------------------------
670
671#if wxUSE_IMAGE
672
673bool wxDIB::Create(const wxImage& image)
674{
675 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
676
677 const int h = image.GetHeight();
678 const int w = image.GetWidth();
679
680 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
681 // a 24bpp RGB is sufficient
682 m_hasAlpha = image.HasAlpha();
683 const int bpp = m_hasAlpha ? 32 : 24;
684
685 if ( !Create(w, h, bpp) )
686 return false;
687
688 // DIBs are stored in bottom to top order (see also the comment above in
689 // Create()) so we need to copy bits line by line and starting from the end
690 const int srcBytesPerLine = w * 3;
691 const int dstBytesPerLine = GetLineSize(w, bpp);
692 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
693 const unsigned char *alpha = m_hasAlpha ? image.GetAlpha() + (h - 1)*w
694 : NULL;
695 unsigned char *dstLineStart = (unsigned char *)m_data;
696 for ( int y = 0; y < h; y++ )
697 {
698 // copy one DIB line
699 unsigned char *dst = dstLineStart;
700 if ( alpha )
701 {
702 for ( int x = 0; x < w; x++ )
703 {
704 // RGB order is reversed, and we need to premultiply
705 // all channels by alpha value for use with ::AlphaBlend.
706 const unsigned char a = *alpha++;
707 *dst++ = (unsigned char)((src[2] * a + 127) / 255);
708 *dst++ = (unsigned char)((src[1] * a + 127) / 255);
709 *dst++ = (unsigned char)((src[0] * a + 127) / 255);
710 *dst++ = a;
711 src += 3;
712 }
713 }
714 else // no alpha channel
715 {
716 for ( int x = 0; x < w; x++ )
717 {
718 // RGB order is reversed.
719 *dst++ = src[2];
720 *dst++ = src[1];
721 *dst++ = src[0];
722 src += 3;
723 }
724 }
725
726 // pass to the previous line in the image
727 src -= 2*srcBytesPerLine;
728 if ( alpha )
729 alpha -= 2*w;
730
731 // and to the next one in the DIB
732 dstLineStart += dstBytesPerLine;
733 }
734
735 return true;
736}
737
738wxImage wxDIB::ConvertToImage() const
739{
740 wxCHECK_MSG( IsOk(), wxNullImage,
741 wxT("can't convert invalid DIB to wxImage") );
742
743 // create the wxImage object
744 const int w = GetWidth();
745 const int h = GetHeight();
746 wxImage image(w, h, false /* don't bother clearing memory */);
747 if ( !image.Ok() )
748 {
749 wxFAIL_MSG( wxT("could not allocate data for image") );
750 return wxNullImage;
751 }
752
753 if ( m_hasAlpha )
754 {
755 image.SetAlpha();
756 }
757
758 // this is the same loop as in Create() just above but with copy direction
759 // reversed
760 const int bpp = GetDepth();
761 const int dstBytesPerLine = w * 3;
762 const int srcBytesPerLine = GetLineSize(w, bpp);
763 unsigned char *dst = image.GetData() + ((h - 1) * dstBytesPerLine);
764 unsigned char *alpha = image.HasAlpha() ? image.GetAlpha() + (h - 1)*w
765 : NULL;
766 const bool is32bit = bpp == 32;
767 const unsigned char *srcLineStart = (unsigned char *)GetData();
768 for ( int y = 0; y < h; y++ )
769 {
770 // copy one DIB line
771 const unsigned char *src = srcLineStart;
772 for ( int x = 0; x < w; x++ )
773 {
774 dst[2] = *src++;
775 dst[1] = *src++;
776 dst[0] = *src++;
777
778 dst += 3;
779
780 if ( is32bit )
781 {
782 if ( alpha )
783 *alpha++ = *src;
784 src++;
785 }
786 }
787
788 // pass to the previous line in the image
789 dst -= 2*dstBytesPerLine;
790 if ( alpha )
791 alpha -= 2*w;
792
793 // and to the next one in the DIB
794 srcLineStart += srcBytesPerLine;
795 }
796
797 return image;
798}
799
800#endif // wxUSE_IMAGE
801
802#endif // wxUSE_WXDIB
803