]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dib.cpp
Applied patch to fix silly filenames in CreateTempFileName
[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
1cfa5d8e 51#include "wx/image.h"
53eff2a2
VZ
52#include "wx/msw/dib.h"
53
be69f971
VZ
54#ifdef __WXWINCE__
55 #include <shellapi.h> // for SHLoadDIBitmap()
56#endif
57
22be0335
VZ
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
be69f971 64static inline WORD GetNumberOfColours(WORD bitsPerPixel)
22be0335
VZ
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)
907173e5 68 return (WORD)(bitsPerPixel <= 8 ? 1 << bitsPerPixel : 0);
22be0335
VZ
69}
70
3692b948
VZ
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
53eff2a2
VZ
82// ============================================================================
83// implementation
84// ============================================================================
85
86// ----------------------------------------------------------------------------
87// wxDIB creation
88// ----------------------------------------------------------------------------
89
90bool wxDIB::Create(int width, int height, int depth)
91{
be69f971
VZ
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;
53eff2a2 97
be69f971
VZ
98 // allocate memory for bitmap structures
99 static const int sizeHeader = sizeof(BITMAPINFOHEADER);
53eff2a2 100
be69f971 101 BITMAPINFO *info = (BITMAPINFO *)malloc(sizeHeader);
a1e71b10 102 wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") );
53eff2a2 103
be69f971 104 memset(info, 0, sizeHeader);
53eff2a2 105
be69f971 106 info->bmiHeader.biSize = sizeHeader;
53eff2a2 107 info->bmiHeader.biWidth = width;
bbc1265c
VZ
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
53eff2a2 116 info->bmiHeader.biPlanes = 1;
373a5fb3 117 info->bmiHeader.biBitCount = (WORD)depth;
53eff2a2
VZ
118 info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
119
53eff2a2
VZ
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
2b254edf
VZ
146bool wxDIB::Create(const wxBitmap& bmp)
147{
148 wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
149
dd779a9e
VZ
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{
82ac3b0a
VZ
160 // this bitmap could already be a DIB section in which case we don't need
161 // to convert it to DIB
82ac3b0a 162 DIBSECTION ds;
3692b948 163 if ( GetDIBSection(hbmp, &ds) )
2b254edf 164 {
82ac3b0a
VZ
165 m_handle = hbmp;
166
167 // wxBitmap will free it, not we
168 m_ownsHandle = false;
2b254edf 169
82ac3b0a
VZ
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 {
dd779a9e
VZ
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;
be69f971 189 if ( d <= 0 )
82ac3b0a
VZ
190 d = wxDisplayDepth();
191
dd779a9e 192 if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) )
82ac3b0a 193 return false;
be69f971 194 }
82ac3b0a 195
be69f971
VZ
196 return true;
197}
3692b948 198
be69f971
VZ
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__
3692b948 207
be69f971
VZ
208bool wxDIB::CopyFromDDB(HBITMAP hbmp)
209{
210 MemoryHDC hdcSrc;
211 if ( !hdcSrc )
212 return false;
82ac3b0a 213
be69f971
VZ
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;
2b254edf
VZ
270 }
271
272 return true;
273}
274
be69f971
VZ
275#endif // __WXWINCE__/!__WXWINCE__
276
c11bf842
VZ
277// ----------------------------------------------------------------------------
278// Loading/saving the DIBs
279// ----------------------------------------------------------------------------
280
281bool wxDIB::Load(const wxString& filename)
282{
be69f971
VZ
283#ifdef __WXWINCE__
284 m_handle = SHLoadDIBitmap(filename);
285#else // !__WXWINCE__
c11bf842
VZ
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 );
be69f971
VZ
294#endif // __WXWINCE__
295
c11bf842
VZ
296 if ( !m_handle )
297 {
be69f971 298 wxLogLastError(_T("Loading DIB from file"));
c11bf842
VZ
299
300 return false;
301 }
302
303 return true;
304}
305
2b254edf
VZ
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;
3692b948 315 if ( !GetDIBSection(m_handle, &ds) )
2b254edf
VZ
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
53eff2a2
VZ
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;
3692b948 364 if ( !GetDIBSection(m_handle, &ds) )
53eff2a2
VZ
365 {
366 wxLogLastError(_T("GetObject(hDIB)"));
53eff2a2
VZ
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
22be0335
VZ
379// ----------------------------------------------------------------------------
380// DDB <-> DIB conversions
381// ----------------------------------------------------------------------------
382
be69f971
VZ
383#ifndef __WXWINCE__
384
c11bf842
VZ
385HBITMAP wxDIB::CreateDDB(HDC hdc) const
386{
387 wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
388
389 DIBSECTION ds;
3692b948 390 if ( !GetDIBSection(m_handle, &ds) )
c11bf842
VZ
391 {
392 wxLogLastError(_T("GetObject(hDIB)"));
393
394 return 0;
395 }
396
22be0335
VZ
397 return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
398}
399
400/* static */
401HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
402{
403 wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
404
405 // here we get BITMAPINFO struct followed by the actual bitmap bits and
406 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
407 const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
408
409 // get the pointer to the start of the real image data if we have a plain
410 // DIB and not a DIB section (in the latter case the pointer must be passed
411 // to us by the caller)
412 if ( !bits )
c11bf842 413 {
22be0335 414 // we must skip over the colour table to get to the image data
a8beba72
VZ
415 //
416 // colour table either has the real colour data in which case its
417 // number of entries is given by biClrUsed or is used for masks to be
418 // used for extracting colour information from true colour bitmaps in
419 // which case it always have exactly 3 DWORDs
420 int numColors;
421 switch ( pbmih->biCompression )
22be0335 422 {
a8beba72
VZ
423 case BI_BITFIELDS:
424 numColors = 3;
425 break;
426
427 case BI_RGB:
428 // biClrUsed has the number of colors but it may be not initialized at
429 // all
430 numColors = pbmih->biClrUsed;
431 if ( !numColors )
432 {
be69f971 433 numColors = GetNumberOfColours(pbmih->biBitCount);
a8beba72
VZ
434 }
435 break;
436
437 default:
438 // no idea how it should be calculated for the other cases
439 numColors = 0;
22be0335
VZ
440 }
441
442 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
c11bf842 443 }
4b1f929c 444
22be0335
VZ
445 HBITMAP hbmp = ::CreateDIBitmap
446 (
4b1f929c
CE
447 hdc ? hdc // create bitmap compatible
448 : (HDC) ScreenHDC(), // with this DC
22be0335
VZ
449 pbmih, // used to get size &c
450 CBM_INIT, // initialize bitmap bits too
451 bits, // ... using this data
452 pbmi, // this is used for palette only
453 DIB_RGB_COLORS // direct or indexed palette?
454 );
455
456 if ( !hbmp )
c11bf842 457 {
22be0335 458 wxLogLastError(wxT("CreateDIBitmap"));
c11bf842
VZ
459 }
460
22be0335
VZ
461 return hbmp;
462}
463
464/* static */
465size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
466{
467 wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") );
468
469 // prepare all the info we need
470 BITMAP bm;
471 if ( !::GetObject(hbmp, sizeof(bm), &bm) )
472 {
473 wxLogLastError(wxT("GetObject(bitmap)"));
474
475 return 0;
476 }
477
22be0335
VZ
478 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
479 // use this one
480 BITMAPINFO bi2;
481
2b254edf 482 const bool wantSizeOnly = pbi == NULL;
22be0335
VZ
483 if ( wantSizeOnly )
484 pbi = &bi2;
485
486 // just for convenience
487 const int h = bm.bmHeight;
488
489 // init the header
490 BITMAPINFOHEADER& bi = pbi->bmiHeader;
491 wxZeroMemory(bi);
492 bi.biSize = sizeof(BITMAPINFOHEADER);
493 bi.biWidth = bm.bmWidth;
494 bi.biHeight = h;
495 bi.biPlanes = 1;
2b254edf 496 bi.biBitCount = bm.bmBitsPixel;
22be0335
VZ
497
498 // memory we need for BITMAPINFO only
be69f971 499 DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
2b254edf
VZ
500
501 // get either just the image size or the image bits
502 if ( !::GetDIBits
503 (
504 ScreenHDC(), // the DC to use
505 hbmp, // the source DDB
506 0, // first scan line
507 h, // number of lines to copy
508 wantSizeOnly ? NULL // pointer to the buffer or
509 : (char *)pbi + dwLen, // NULL if we don't have it
510 pbi, // bitmap header
511 DIB_RGB_COLORS // or DIB_PAL_COLORS
512 ) )
c11bf842 513 {
2b254edf 514 wxLogLastError(wxT("GetDIBits()"));
c11bf842
VZ
515
516 return 0;
517 }
518
2b254edf
VZ
519 // return the total size
520 return dwLen + bi.biSizeImage;
521}
522
523/* static */
524HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
525{
526 // first calculate the size needed
527 const size_t size = ConvertFromBitmap(NULL, hbmp);
528 if ( !size )
22be0335 529 {
2b254edf
VZ
530 // conversion to DDB failed?
531 return NULL;
532 }
22be0335 533
2b254edf
VZ
534 HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
535 if ( !hDIB )
536 {
537 // this is an error which does risk to happen especially under Win9x
538 // and which the user may understand so let him know about it
539 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
540 (unsigned long)(size / 1024));
541
542 return NULL;
22be0335
VZ
543 }
544
3692b948 545 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtr(hDIB), hbmp) )
2b254edf
VZ
546 {
547 // this really shouldn't happen... it worked the first time, why not
548 // now?
549 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
550
551 return NULL;
552 }
553
554 return hDIB;
c11bf842
VZ
555}
556
be69f971
VZ
557#endif // __WXWINCE__
558
22be0335
VZ
559// ----------------------------------------------------------------------------
560// palette support
561// ----------------------------------------------------------------------------
562
c11bf842
VZ
563#if wxUSE_PALETTE
564
565wxPalette *wxDIB::CreatePalette() const
566{
567 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
568
569 DIBSECTION ds;
3692b948 570 if ( !GetDIBSection(m_handle, &ds) )
c11bf842
VZ
571 {
572 wxLogLastError(_T("GetObject(hDIB)"));
573
574 return 0;
575 }
576
577 // how many colours are we going to have in the palette?
578 DWORD biClrUsed = ds.dsBmih.biClrUsed;
579 if ( !biClrUsed )
580 {
581 // biClrUsed field might not be set
be69f971 582 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
c11bf842
VZ
583 }
584
2b254edf 585 if ( !biClrUsed )
c11bf842 586 {
2b254edf 587 // bitmaps of this depth don't have palettes at all
c11bf842
VZ
588 //
589 // NB: another possibility would be to return
590 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
591 return NULL;
592 }
593
594 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
595 // going to have biClrUsed of them so add necessary space
596 LOGPALETTE *pPalette = (LOGPALETTE *)
597 malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
598 wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
599
600 // initialize the palette header
601 pPalette->palVersion = 0x300; // magic number, not in docs but works
373a5fb3 602 pPalette->palNumEntries = (WORD)biClrUsed;
c11bf842
VZ
603
604 // and the colour table (it starts right after the end of the header)
605 const RGBQUAD *pRGB = (RGBQUAD *)((char *)&ds.dsBmih + ds.dsBmih.biSize);
606 for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
607 {
608 pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
609 pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
610 pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
611 pPalette->palPalEntry[i].peFlags = 0;
612 }
613
614 HPALETTE hPalette = ::CreatePalette(pPalette);
615
616 free(pPalette);
617
618 if ( !hPalette )
619 {
620 wxLogLastError(_T("CreatePalette"));
621
622 return NULL;
623 }
624
625 wxPalette *palette = new wxPalette;
626 palette->SetHPALETTE((WXHPALETTE)hPalette);
627
628 return palette;
629}
630
631#endif // wxUSE_PALETTE
632
53eff2a2
VZ
633// ----------------------------------------------------------------------------
634// wxImage support
635// ----------------------------------------------------------------------------
636
637#if wxUSE_IMAGE
638
639bool wxDIB::Create(const wxImage& image)
640{
641 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
642
643 const int h = image.GetHeight();
644 const int w = image.GetWidth();
645
646 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
647 // a 24bpp RGB is sufficient
45515b66
VZ
648 m_hasAlpha = image.HasAlpha();
649 const int bpp = m_hasAlpha ? 32 : 24;
53eff2a2
VZ
650
651 if ( !Create(w, h, bpp) )
652 return false;
653
bbc1265c
VZ
654 // DIBs are stored in bottom to top order (see also the comment above in
655 // Create()) so we need to copy bits line by line and starting from the end
53eff2a2
VZ
656 const int srcBytesPerLine = w * 3;
657 const int dstBytesPerLine = GetLineSize(w, bpp);
658 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
45515b66
VZ
659 const unsigned char *alpha = m_hasAlpha ? image.GetAlpha() + (h - 1)*w
660 : NULL;
53eff2a2
VZ
661 unsigned char *dstLineStart = (unsigned char *)m_data;
662 for ( int y = 0; y < h; y++ )
663 {
664 // copy one DIB line
665 unsigned char *dst = dstLineStart;
e5d4ef74 666 if ( alpha )
53eff2a2 667 {
e5d4ef74
VZ
668 for ( int x = 0; x < w; x++ )
669 {
670 // RGB order is reversed, and we need to premultiply
671 // all channels by alpha value for use with ::AlphaBlend.
672 const unsigned char a = *alpha++;
907173e5
WS
673 *dst++ = (unsigned char)((src[2] * a + 127) / 255);
674 *dst++ = (unsigned char)((src[1] * a + 127) / 255);
675 *dst++ = (unsigned char)((src[0] * a + 127) / 255);
e5d4ef74
VZ
676 *dst++ = a;
677 src += 3;
678 }
679 }
680 else // no alpha channel
681 {
682 for ( int x = 0; x < w; x++ )
683 {
684 // RGB order is reversed.
685 *dst++ = src[2];
686 *dst++ = src[1];
687 *dst++ = src[0];
688 src += 3;
689 }
53eff2a2
VZ
690 }
691
692 // pass to the previous line in the image
693 src -= 2*srcBytesPerLine;
694 if ( alpha )
695 alpha -= 2*w;
696
697 // and to the next one in the DIB
698 dstLineStart += dstBytesPerLine;
699 }
700
701 return true;
702}
703
be69f971
VZ
704wxImage wxDIB::ConvertToImage() const
705{
706 wxCHECK_MSG( IsOk(), wxNullImage,
707 wxT("can't convert invalid DIB to wxImage") );
708
709 // create the wxImage object
710 const int w = GetWidth();
711 const int h = GetHeight();
712 wxImage image(w, h, false /* don't bother clearing memory */);
713 if ( !image.Ok() )
714 {
715 wxFAIL_MSG( wxT("could not allocate data for image") );
716 return wxNullImage;
717 }
718
45515b66 719 if ( m_hasAlpha )
be69f971
VZ
720 {
721 image.SetAlpha();
722 }
723
724 // this is the same loop as in Create() just above but with copy direction
725 // reversed
45515b66 726 const int bpp = GetDepth();
be69f971
VZ
727 const int dstBytesPerLine = w * 3;
728 const int srcBytesPerLine = GetLineSize(w, bpp);
729 unsigned char *dst = image.GetData() + ((h - 1) * dstBytesPerLine);
730 unsigned char *alpha = image.HasAlpha() ? image.GetAlpha() + (h - 1)*w
731 : NULL;
45515b66 732 const bool is32bit = bpp == 32;
be69f971
VZ
733 const unsigned char *srcLineStart = (unsigned char *)GetData();
734 for ( int y = 0; y < h; y++ )
735 {
736 // copy one DIB line
737 const unsigned char *src = srcLineStart;
738 for ( int x = 0; x < w; x++ )
739 {
740 dst[2] = *src++;
741 dst[1] = *src++;
742 dst[0] = *src++;
743
744 dst += 3;
745
45515b66
VZ
746 if ( is32bit )
747 {
748 if ( alpha )
749 *alpha++ = *src;
750 src++;
751 }
be69f971
VZ
752 }
753
754 // pass to the previous line in the image
755 dst -= 2*dstBytesPerLine;
756 if ( alpha )
757 alpha -= 2*w;
758
759 // and to the next one in the DIB
760 srcLineStart += srcBytesPerLine;
761 }
762
763 return image;
764}
765
53eff2a2
VZ
766#endif // wxUSE_IMAGE
767
be69f971
VZ
768#endif // wxUSE_WXDIB
769