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