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