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: dib.cpp 48581 2007-09-05 23:01:02Z VZ $
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__) && !defined(__SALFORDC__)
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
GetNumberOfColours(WORD bitsPerPixel)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
GetDIBSection(HBITMAP hbmp,DIBSECTION * ds)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 
Create(int width,int height,int depth)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     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 
Create(const wxBitmap & bmp)146 bool 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 
Create(HBITMAP hbmp)158 bool 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 
CopyFromDDB(HBITMAP hbmp)208 bool 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 
CopyFromDDB(HBITMAP hbmp)245 bool 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 
Load(const wxString & filename)281 bool 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 
Save(const wxString & filename)306 bool 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 
DoGetObject() const352 void 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 
CreateDDB(HDC hdc) const385 HBITMAP 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 */
ConvertToBitmap(const BITMAPINFO * pbmi,HDC hdc,void * bits)425 HBITMAP 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 */
ConvertFromBitmap(BITMAPINFO * pbi,HBITMAP hbmp)489 size_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 */
ConvertFromBitmap(HBITMAP hbmp)548 HGLOBAL 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 
CreatePalette() const589 wxPalette *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 
Create(const wxImage & image)673 bool 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 
ConvertToImage() const738 wxImage 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             if ( is32bit )
779             {
780                 if ( alpha )
781                 {
782                     // wxImage uses non premultiplied alpha so undo
783                     // premultiplication done in Create() above
784                     const unsigned char a = *src;
785                     *alpha++ = a;
786                     if ( a > 0 )
787                     {
788                         dst[0] = (dst[0] * 255) / a;
789                         dst[1] = (dst[1] * 255) / a;
790                         dst[2] = (dst[2] * 255) / a;
791                     }
792                 }
793 
794                 src++;
795             }
796 
797             dst += 3;
798         }
799 
800         // pass to the previous line in the image
801         dst -= 2*dstBytesPerLine;
802         if ( alpha )
803             alpha -= 2*w;
804 
805         // and to the next one in the DIB
806         srcLineStart += srcBytesPerLine;
807     }
808 
809     return image;
810 }
811 
812 #endif // wxUSE_IMAGE
813 
814 #endif // wxUSE_WXDIB
815