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
64static inline WORD GetNumberOfColours(WORD bitsPerPixel)
65{
66    // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
67    // 24bpp ones too but we don't support this as I think it's quite uncommon)
68    return (WORD)(bitsPerPixel <= 8 ? 1 << bitsPerPixel : 0);
69}
70
71// wrapper around ::GetObject() for DIB sections
72static inline bool GetDIBSection(HBITMAP hbmp, DIBSECTION *ds)
73{
74    // note that at least under Win9x (this doesn't seem to happen under Win2K
75    // but this doesn't mean anything, of course), GetObject() may return
76    // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
77    // to check for it is by looking at the bits pointer
78    return ::GetObject(hbmp, sizeof(DIBSECTION), ds) == sizeof(DIBSECTION) &&
79                ds->dsBm.bmBits;
80}
81
82// ============================================================================
83// implementation
84// ============================================================================
85
86// ----------------------------------------------------------------------------
87// wxDIB creation
88// ----------------------------------------------------------------------------
89
90bool wxDIB::Create(int width, int height, int depth)
91{
92    // we don't support formats using palettes right now so we only create
93    // either 24bpp (RGB) or 32bpp (RGBA) bitmaps
94    wxASSERT_MSG( depth, _T("invalid image depth in wxDIB::Create()") );
95    if ( depth < 24 )
96        depth = 24;
97
98    // allocate memory for bitmap structures
99    static const int sizeHeader = sizeof(BITMAPINFOHEADER);
100
101    BITMAPINFO *info = (BITMAPINFO *)malloc(sizeHeader);
102    wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") );
103
104    memset(info, 0, sizeHeader);
105
106    info->bmiHeader.biSize = sizeHeader;
107    info->bmiHeader.biWidth = width;
108
109    // we use positive height here which corresponds to a DIB with normal, i.e.
110    // bottom to top, order -- normally using negative height (which means
111    // reversed for MS and hence natural for all the normal people top to
112    // bottom line scan order) could be used to avoid the need for the image
113    // reversal in Create(image) but this doesn't work under NT, only Win9x!
114    info->bmiHeader.biHeight = height;
115
116    info->bmiHeader.biPlanes = 1;
117    info->bmiHeader.biBitCount = (WORD)depth;
118    info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
119
120    m_handle = ::CreateDIBSection
121                 (
122                    0,              // hdc (unused with DIB_RGB_COLORS)
123                    info,           // bitmap description
124                    DIB_RGB_COLORS, // use RGB, not palette
125                    &m_data,        // [out] DIB bits
126                    NULL,           // don't use file mapping
127                    0               // file mapping offset (not used here)
128                 );
129
130    free(info);
131
132    if ( !m_handle )
133    {
134        wxLogLastError(wxT("CreateDIBSection"));
135
136        return false;
137    }
138
139    m_width = width;
140    m_height = height;
141    m_depth = depth;
142
143    return true;
144}
145
146bool wxDIB::Create(const wxBitmap& bmp)
147{
148    wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
149
150    if ( !Create(GetHbitmapOf(bmp)) )
151        return false;
152
153    m_hasAlpha = bmp.HasAlpha();
154
155    return true;
156}
157
158bool wxDIB::Create(HBITMAP hbmp)
159{
160    // this bitmap could already be a DIB section in which case we don't need
161    // to convert it to DIB
162    DIBSECTION ds;
163    if ( GetDIBSection(hbmp, &ds) )
164    {
165        m_handle = hbmp;
166
167        // wxBitmap will free it, not we
168        m_ownsHandle = false;
169
170        // copy all the bitmap parameters too as we have them now anyhow
171        m_width = ds.dsBm.bmWidth;
172        m_height = ds.dsBm.bmHeight;
173        m_depth = ds.dsBm.bmBitsPixel;
174
175        m_data = ds.dsBm.bmBits;
176    }
177    else // no, it's a DDB -- convert it to DIB
178    {
179        // prepare all the info we need
180        BITMAP bm;
181        if ( !::GetObject(hbmp, sizeof(bm), &bm) )
182        {
183            wxLogLastError(wxT("GetObject(bitmap)"));
184
185            return false;
186        }
187
188        int d = bm.bmBitsPixel;
189        if ( d <= 0 )
190            d = wxDisplayDepth();
191
192        if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) )
193            return false;
194    }
195
196    return true;
197}
198
199// Windows CE doesn't have GetDIBits() so use an alternative implementation
200// for it
201//
202// in fact I'm not sure if GetDIBits() is really much better than using
203// BitBlt() like this -- it should be faster but I didn't do any tests, if
204// anybody has time to do them and by chance finds that GetDIBits() is not
205// much faster than BitBlt(), we could always use the Win CE version here
206#ifdef __WXWINCE__
207
208bool wxDIB::CopyFromDDB(HBITMAP hbmp)
209{
210    MemoryHDC hdcSrc;
211    if ( !hdcSrc )
212        return false;
213
214    SelectInHDC selectSrc(hdcSrc, hbmp);
215    if ( !selectSrc )
216        return false;
217
218    MemoryHDC hdcDst;
219    if ( !hdcDst )
220        return false;
221
222    SelectInHDC selectDst(hdcDst, m_handle);
223    if ( !selectDst )
224        return false;
225
226
227    if ( !::BitBlt(
228                    hdcDst,
229                    0, 0, m_width, m_height,
230                    hdcSrc,
231                    0, 0,
232                    SRCCOPY
233                  ) )
234    {
235        wxLogLastError(_T("BitBlt(DDB -> DIB)"));
236
237        return false;
238    }
239
240    return true;
241}
242
243#else // !__WXWINCE__
244
245bool wxDIB::CopyFromDDB(HBITMAP hbmp)
246{
247    DIBSECTION ds;
248    if ( !GetDIBSection(m_handle, &ds) )
249    {
250        // we're sure that our handle is a DIB section, so this should work
251        wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
252
253        return false;
254    }
255
256    if ( !::GetDIBits
257            (
258                ScreenHDC(),                // the DC to use
259                hbmp,                       // the source DDB
260                0,                          // first scan line
261                m_height,                   // number of lines to copy
262                ds.dsBm.bmBits,             // pointer to the buffer
263                (BITMAPINFO *)&ds.dsBmih,   // bitmap header
264                DIB_RGB_COLORS              // and not DIB_PAL_COLORS
265            ) )
266    {
267        wxLogLastError(wxT("GetDIBits()"));
268
269        return false;
270    }
271
272    return true;
273}
274
275#endif // __WXWINCE__/!__WXWINCE__
276
277// ----------------------------------------------------------------------------
278// Loading/saving the DIBs
279// ----------------------------------------------------------------------------
280
281bool wxDIB::Load(const wxString& filename)
282{
283#ifdef __WXWINCE__
284    m_handle = SHLoadDIBitmap(filename);
285#else // !__WXWINCE__
286    m_handle = (HBITMAP)::LoadImage
287                         (
288                            wxGetInstance(),
289                            filename,
290                            IMAGE_BITMAP,
291                            0, 0, // don't specify the size
292                            LR_CREATEDIBSECTION | LR_LOADFROMFILE
293                         );
294#endif // __WXWINCE__
295
296    if ( !m_handle )
297    {
298        wxLogLastError(_T("Loading DIB from file"));
299
300        return false;
301    }
302
303    return true;
304}
305
306bool wxDIB::Save(const wxString& filename)
307{
308    wxCHECK_MSG( m_handle, false, _T("wxDIB::Save(): invalid object") );
309
310    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
352void 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
385HBITMAP 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 */
425HBITMAP 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 */
489size_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 */
548HGLOBAL 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
589wxPalette *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
673bool 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
738wxImage 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