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