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