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