]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dib.cpp
set TOOLKIT to WINCE for VC8 builds targeting pocketpc2003
[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#if wxUSE_WXDIB
34
35#ifndef WX_PRECOMP
36 #include "wx/string.h"
37 #include "wx/log.h"
38 #include "wx/intl.h"
39 #include "wx/bitmap.h"
40 #include "wx/image.h"
41#endif //WX_PRECOMP
42
43#include "wx/file.h"
44
45#include <stdio.h>
46#include <stdlib.h>
47
48#if !defined(__MWERKS__)
49 #include <memory.h>
50#endif
51
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.fn_str(),
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#if wxUSE_FILE
311 wxFile file(filename, wxFile::write);
312 bool ok = file.IsOpened();
313 if ( ok )
314 {
315 DIBSECTION ds;
316 if ( !GetDIBSection(m_handle, &ds) )
317 {
318 wxLogLastError(_T("GetObject(hDIB)"));
319 }
320 else
321 {
322 BITMAPFILEHEADER bmpHdr;
323 wxZeroMemory(bmpHdr);
324
325 const size_t sizeHdr = ds.dsBmih.biSize;
326 const size_t sizeImage = ds.dsBmih.biSizeImage;
327
328 bmpHdr.bfType = 0x4d42; // 'BM' in little endian
329 bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
330 bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
331
332 // first write the file header, then the bitmap header and finally the
333 // bitmap data itself
334 ok = file.Write(&bmpHdr, sizeof(bmpHdr)) == sizeof(bmpHdr) &&
335 file.Write(&ds.dsBmih, sizeHdr) == sizeHdr &&
336 file.Write(ds.dsBm.bmBits, sizeImage) == sizeImage;
337 }
338 }
339#else // !wxUSE_FILE
340 bool ok = false;
341#endif // wxUSE_FILE/!wxUSE_FILE
342
343 if ( !ok )
344 {
345 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
346 filename.c_str());
347 }
348
349 return ok;
350}
351
352// ----------------------------------------------------------------------------
353// wxDIB accessors
354// ----------------------------------------------------------------------------
355
356void wxDIB::DoGetObject() const
357{
358 // only do something if we have a valid DIB but we don't [yet] have valid
359 // data
360 if ( m_handle && !m_data )
361 {
362 // although all the info we need is in BITMAP and so we don't really
363 // need DIBSECTION we still ask for it as modifying the bit values only
364 // works for the real DIBs and not for the bitmaps and it's better to
365 // check for this now rather than trying to find out why it doesn't
366 // work later
367 DIBSECTION ds;
368 if ( !GetDIBSection(m_handle, &ds) )
369 {
370 wxLogLastError(_T("GetObject(hDIB)"));
371 return;
372 }
373
374 wxDIB *self = wxConstCast(this, wxDIB);
375
376 self->m_width = ds.dsBm.bmWidth;
377 self->m_height = ds.dsBm.bmHeight;
378 self->m_depth = ds.dsBm.bmBitsPixel;
379 self->m_data = ds.dsBm.bmBits;
380 }
381}
382
383// ----------------------------------------------------------------------------
384// DDB <-> DIB conversions
385// ----------------------------------------------------------------------------
386
387#ifndef __WXWINCE__
388
389HBITMAP wxDIB::CreateDDB(HDC hdc) const
390{
391 wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
392
393 DIBSECTION ds;
394 if ( !GetDIBSection(m_handle, &ds) )
395 {
396 wxLogLastError(_T("GetObject(hDIB)"));
397
398 return 0;
399 }
400
401 // how many colours are we going to have in the palette?
402 DWORD biClrUsed = ds.dsBmih.biClrUsed;
403 if ( !biClrUsed )
404 {
405 // biClrUsed field might not be set
406 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
407 }
408
409 if ( !biClrUsed )
410 {
411 return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
412 }
413 else
414 {
415 // fake a BITMAPINFO w/o bits, just the palette info
416 wxCharBuffer bmi(sizeof(BITMAPINFO) + (biClrUsed - 1)*sizeof(RGBQUAD));
417 BITMAPINFO *pBmi = (BITMAPINFO *)bmi.data();
418 MemoryHDC hDC;
419 // get the colour table
420 SelectInHDC sDC(hDC, m_handle);
421 ::GetDIBColorTable(hDC, 0, biClrUsed, pBmi->bmiColors);
422 memcpy(&pBmi->bmiHeader, &ds.dsBmih, ds.dsBmih.biSize);
423
424 return ConvertToBitmap(pBmi, hdc, ds.dsBm.bmBits);
425 }
426}
427
428/* static */
429HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
430{
431 wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
432
433 // here we get BITMAPINFO struct followed by the actual bitmap bits and
434 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
435 const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
436
437 // get the pointer to the start of the real image data if we have a plain
438 // DIB and not a DIB section (in the latter case the pointer must be passed
439 // to us by the caller)
440 if ( !bits )
441 {
442 // we must skip over the colour table to get to the image data
443 //
444 // colour table either has the real colour data in which case its
445 // number of entries is given by biClrUsed or is used for masks to be
446 // used for extracting colour information from true colour bitmaps in
447 // which case it always have exactly 3 DWORDs
448 int numColors;
449 switch ( pbmih->biCompression )
450 {
451 case BI_BITFIELDS:
452 numColors = 3;
453 break;
454
455 case BI_RGB:
456 // biClrUsed has the number of colors but it may be not initialized at
457 // all
458 numColors = pbmih->biClrUsed;
459 if ( !numColors )
460 {
461 numColors = GetNumberOfColours(pbmih->biBitCount);
462 }
463 break;
464
465 default:
466 // no idea how it should be calculated for the other cases
467 numColors = 0;
468 }
469
470 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
471 }
472
473 HBITMAP hbmp = ::CreateDIBitmap
474 (
475 hdc ? hdc // create bitmap compatible
476 : (HDC) ScreenHDC(), // with this DC
477 pbmih, // used to get size &c
478 CBM_INIT, // initialize bitmap bits too
479 bits, // ... using this data
480 pbmi, // this is used for palette only
481 DIB_RGB_COLORS // direct or indexed palette?
482 );
483
484 if ( !hbmp )
485 {
486 wxLogLastError(wxT("CreateDIBitmap"));
487 }
488
489 return hbmp;
490}
491
492/* static */
493size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
494{
495 wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") );
496
497 // prepare all the info we need
498 BITMAP bm;
499 if ( !::GetObject(hbmp, sizeof(bm), &bm) )
500 {
501 wxLogLastError(wxT("GetObject(bitmap)"));
502
503 return 0;
504 }
505
506 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
507 // use this one
508 BITMAPINFO bi2;
509
510 const bool wantSizeOnly = pbi == NULL;
511 if ( wantSizeOnly )
512 pbi = &bi2;
513
514 // just for convenience
515 const int h = bm.bmHeight;
516
517 // init the header
518 BITMAPINFOHEADER& bi = pbi->bmiHeader;
519 wxZeroMemory(bi);
520 bi.biSize = sizeof(BITMAPINFOHEADER);
521 bi.biWidth = bm.bmWidth;
522 bi.biHeight = h;
523 bi.biPlanes = 1;
524 bi.biBitCount = bm.bmBitsPixel;
525
526 // memory we need for BITMAPINFO only
527 DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
528
529 // get either just the image size or the image bits
530 if ( !::GetDIBits
531 (
532 ScreenHDC(), // the DC to use
533 hbmp, // the source DDB
534 0, // first scan line
535 h, // number of lines to copy
536 wantSizeOnly ? NULL // pointer to the buffer or
537 : (char *)pbi + dwLen, // NULL if we don't have it
538 pbi, // bitmap header
539 DIB_RGB_COLORS // or DIB_PAL_COLORS
540 ) )
541 {
542 wxLogLastError(wxT("GetDIBits()"));
543
544 return 0;
545 }
546
547 // return the total size
548 return dwLen + bi.biSizeImage;
549}
550
551/* static */
552HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
553{
554 // first calculate the size needed
555 const size_t size = ConvertFromBitmap(NULL, hbmp);
556 if ( !size )
557 {
558 // conversion to DDB failed?
559 return NULL;
560 }
561
562 HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
563 if ( !hDIB )
564 {
565 // this is an error which does risk to happen especially under Win9x
566 // and which the user may understand so let him know about it
567 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
568 (unsigned long)(size / 1024));
569
570 return NULL;
571 }
572
573 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) )
574 {
575 // this really shouldn't happen... it worked the first time, why not
576 // now?
577 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
578
579 return NULL;
580 }
581
582 return hDIB;
583}
584
585#endif // __WXWINCE__
586
587// ----------------------------------------------------------------------------
588// palette support
589// ----------------------------------------------------------------------------
590
591#if wxUSE_PALETTE
592
593wxPalette *wxDIB::CreatePalette() const
594{
595 // GetDIBColorTable not available in eVC3
596#if defined(_WIN32_WCE) && _WIN32_WCE < 400
597 return NULL;
598#else
599 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
600
601 DIBSECTION ds;
602 if ( !GetDIBSection(m_handle, &ds) )
603 {
604 wxLogLastError(_T("GetObject(hDIB)"));
605
606 return 0;
607 }
608
609 // how many colours are we going to have in the palette?
610 DWORD biClrUsed = ds.dsBmih.biClrUsed;
611 if ( !biClrUsed )
612 {
613 // biClrUsed field might not be set
614 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
615 }
616
617 if ( !biClrUsed )
618 {
619 // bitmaps of this depth don't have palettes at all
620 //
621 // NB: another possibility would be to return
622 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
623 return NULL;
624 }
625
626 MemoryHDC hDC;
627
628 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
629 // going to have biClrUsed of them so add necessary space
630 LOGPALETTE *pPalette = (LOGPALETTE *)
631 malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
632 wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
633
634 // initialize the palette header
635 pPalette->palVersion = 0x300; // magic number, not in docs but works
636 pPalette->palNumEntries = (WORD)biClrUsed;
637
638 // and the colour table
639 wxCharBuffer rgb(sizeof(RGBQUAD) * biClrUsed);
640 RGBQUAD *pRGB = (RGBQUAD*)rgb.data();
641 SelectInHDC selectHandle(hDC, m_handle);
642 ::GetDIBColorTable(hDC, 0, biClrUsed, pRGB);
643 for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
644 {
645 pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
646 pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
647 pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
648 pPalette->palPalEntry[i].peFlags = 0;
649 }
650
651 HPALETTE hPalette = ::CreatePalette(pPalette);
652
653 free(pPalette);
654
655 if ( !hPalette )
656 {
657 wxLogLastError(_T("CreatePalette"));
658
659 return NULL;
660 }
661
662 wxPalette *palette = new wxPalette;
663 palette->SetHPALETTE((WXHPALETTE)hPalette);
664
665 return palette;
666#endif
667}
668
669#endif // wxUSE_PALETTE
670
671// ----------------------------------------------------------------------------
672// wxImage support
673// ----------------------------------------------------------------------------
674
675#if wxUSE_IMAGE
676
677bool wxDIB::Create(const wxImage& image)
678{
679 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
680
681 const int h = image.GetHeight();
682 const int w = image.GetWidth();
683
684 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
685 // a 24bpp RGB is sufficient
686 m_hasAlpha = image.HasAlpha();
687 const int bpp = m_hasAlpha ? 32 : 24;
688
689 if ( !Create(w, h, bpp) )
690 return false;
691
692 // DIBs are stored in bottom to top order (see also the comment above in
693 // Create()) so we need to copy bits line by line and starting from the end
694 const int srcBytesPerLine = w * 3;
695 const int dstBytesPerLine = GetLineSize(w, bpp);
696 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
697 const unsigned char *alpha = m_hasAlpha ? image.GetAlpha() + (h - 1)*w
698 : NULL;
699 unsigned char *dstLineStart = (unsigned char *)m_data;
700 for ( int y = 0; y < h; y++ )
701 {
702 // copy one DIB line
703 unsigned char *dst = dstLineStart;
704 if ( alpha )
705 {
706 for ( int x = 0; x < w; x++ )
707 {
708 // RGB order is reversed, and we need to premultiply
709 // all channels by alpha value for use with ::AlphaBlend.
710 const unsigned char a = *alpha++;
711 *dst++ = (unsigned char)((src[2] * a + 127) / 255);
712 *dst++ = (unsigned char)((src[1] * a + 127) / 255);
713 *dst++ = (unsigned char)((src[0] * a + 127) / 255);
714 *dst++ = a;
715 src += 3;
716 }
717 }
718 else // no alpha channel
719 {
720 for ( int x = 0; x < w; x++ )
721 {
722 // RGB order is reversed.
723 *dst++ = src[2];
724 *dst++ = src[1];
725 *dst++ = src[0];
726 src += 3;
727 }
728 }
729
730 // pass to the previous line in the image
731 src -= 2*srcBytesPerLine;
732 if ( alpha )
733 alpha -= 2*w;
734
735 // and to the next one in the DIB
736 dstLineStart += dstBytesPerLine;
737 }
738
739 return true;
740}
741
742wxImage wxDIB::ConvertToImage() const
743{
744 wxCHECK_MSG( IsOk(), wxNullImage,
745 wxT("can't convert invalid DIB to wxImage") );
746
747 // create the wxImage object
748 const int w = GetWidth();
749 const int h = GetHeight();
750 wxImage image(w, h, false /* don't bother clearing memory */);
751 if ( !image.Ok() )
752 {
753 wxFAIL_MSG( wxT("could not allocate data for image") );
754 return wxNullImage;
755 }
756
757 if ( m_hasAlpha )
758 {
759 image.SetAlpha();
760 }
761
762 // this is the same loop as in Create() just above but with copy direction
763 // reversed
764 const int bpp = GetDepth();
765 const int dstBytesPerLine = w * 3;
766 const int srcBytesPerLine = GetLineSize(w, bpp);
767 unsigned char *dst = image.GetData() + ((h - 1) * dstBytesPerLine);
768 unsigned char *alpha = image.HasAlpha() ? image.GetAlpha() + (h - 1)*w
769 : NULL;
770 const bool is32bit = bpp == 32;
771 const unsigned char *srcLineStart = (unsigned char *)GetData();
772 for ( int y = 0; y < h; y++ )
773 {
774 // copy one DIB line
775 const unsigned char *src = srcLineStart;
776 for ( int x = 0; x < w; x++ )
777 {
778 dst[2] = *src++;
779 dst[1] = *src++;
780 dst[0] = *src++;
781
782 if ( is32bit )
783 {
784 if ( alpha )
785 {
786 // wxImage uses non premultiplied alpha so undo
787 // premultiplication done in Create() above
788 const unsigned char a = *src;
789 *alpha++ = a;
790 if ( a > 0 )
791 {
792 dst[0] = (dst[0] * 255) / a;
793 dst[1] = (dst[1] * 255) / a;
794 dst[2] = (dst[2] * 255) / a;
795 }
796 }
797
798 src++;
799 }
800
801 dst += 3;
802 }
803
804 // pass to the previous line in the image
805 dst -= 2*dstBytesPerLine;
806 if ( alpha )
807 alpha -= 2*w;
808
809 // and to the next one in the DIB
810 srcLineStart += srcBytesPerLine;
811 }
812
813 return image;
814}
815
816#endif // wxUSE_IMAGE
817
818#endif // wxUSE_WXDIB