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