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