]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dib.cpp
use (new) safer GetTraitsIfExists() in wxMutexGuiEnter/Leave() to avoid crashing...
[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
88a7a4e1
WS
33#if wxUSE_WXDIB
34
53eff2a2
VZ
35#ifndef WX_PRECOMP
36 #include "wx/string.h"
37 #include "wx/log.h"
88a7a4e1 38 #include "wx/intl.h"
0bca0373 39 #include "wx/bitmap.h"
155ecd4c 40 #include "wx/image.h"
53eff2a2
VZ
41#endif //WX_PRECOMP
42
2b254edf 43#include "wx/file.h"
1cfa5d8e
JS
44
45#include <stdio.h>
46#include <stdlib.h>
47
f172cb82 48#if !defined(__MWERKS__)
be69f971 49 #include <memory.h>
1cfa5d8e
JS
50#endif
51
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(),
e0a050e3 289 filename.fn_str(),
c11bf842
VZ
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
a8ff046b 310#if wxUSE_FILE
2b254edf
VZ
311 wxFile file(filename, wxFile::write);
312 bool ok = file.IsOpened();
313 if ( ok )
314 {
315 DIBSECTION ds;
3692b948 316 if ( !GetDIBSection(m_handle, &ds) )
2b254edf
VZ
317 {
318 wxLogLastError(_T("GetObject(hDIB)"));
319 }
320 else
321 {
322 BITMAPFILEHEADER bmpHdr;
323 wxZeroMemory(bmpHdr);
324
325 const size_t sizeHdr = ds.dsBmih.biSize;
326 const size_t sizeImage = ds.dsBmih.biSizeImage;
327
328 bmpHdr.bfType = 0x4d42; // 'BM' in little endian
329 bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
330 bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
331
332 // first write the file header, then the bitmap header and finally the
333 // bitmap data itself
334 ok = file.Write(&bmpHdr, sizeof(bmpHdr)) == sizeof(bmpHdr) &&
335 file.Write(&ds.dsBmih, sizeHdr) == sizeHdr &&
336 file.Write(ds.dsBm.bmBits, sizeImage) == sizeImage;
337 }
338 }
a8ff046b
VZ
339#else // !wxUSE_FILE
340 bool ok = false;
341#endif // wxUSE_FILE/!wxUSE_FILE
2b254edf
VZ
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
146dcf3e
MB
401 // how many colours are we going to have in the palette?
402 DWORD biClrUsed = ds.dsBmih.biClrUsed;
403 if ( !biClrUsed )
404 {
405 // biClrUsed field might not be set
406 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
407 }
408
409 if ( !biClrUsed )
410 {
411 return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
412 }
413 else
414 {
415 // fake a BITMAPINFO w/o bits, just the palette info
416 wxCharBuffer bmi(sizeof(BITMAPINFO) + (biClrUsed - 1)*sizeof(RGBQUAD));
417 BITMAPINFO *pBmi = (BITMAPINFO *)bmi.data();
418 MemoryHDC hDC;
419 // get the colour table
420 SelectInHDC sDC(hDC, m_handle);
421 ::GetDIBColorTable(hDC, 0, biClrUsed, pBmi->bmiColors);
422 memcpy(&pBmi->bmiHeader, &ds.dsBmih, ds.dsBmih.biSize);
423
424 return ConvertToBitmap(pBmi, hdc, ds.dsBm.bmBits);
425 }
22be0335
VZ
426}
427
428/* static */
429HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
430{
431 wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
432
433 // here we get BITMAPINFO struct followed by the actual bitmap bits and
434 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
435 const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
436
437 // get the pointer to the start of the real image data if we have a plain
438 // DIB and not a DIB section (in the latter case the pointer must be passed
439 // to us by the caller)
440 if ( !bits )
c11bf842 441 {
22be0335 442 // we must skip over the colour table to get to the image data
a8beba72
VZ
443 //
444 // colour table either has the real colour data in which case its
445 // number of entries is given by biClrUsed or is used for masks to be
446 // used for extracting colour information from true colour bitmaps in
447 // which case it always have exactly 3 DWORDs
448 int numColors;
449 switch ( pbmih->biCompression )
22be0335 450 {
a8beba72
VZ
451 case BI_BITFIELDS:
452 numColors = 3;
453 break;
454
455 case BI_RGB:
456 // biClrUsed has the number of colors but it may be not initialized at
457 // all
458 numColors = pbmih->biClrUsed;
459 if ( !numColors )
460 {
be69f971 461 numColors = GetNumberOfColours(pbmih->biBitCount);
a8beba72
VZ
462 }
463 break;
464
465 default:
466 // no idea how it should be calculated for the other cases
467 numColors = 0;
22be0335
VZ
468 }
469
470 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
c11bf842 471 }
4b1f929c 472
22be0335
VZ
473 HBITMAP hbmp = ::CreateDIBitmap
474 (
4b1f929c
CE
475 hdc ? hdc // create bitmap compatible
476 : (HDC) ScreenHDC(), // with this DC
22be0335
VZ
477 pbmih, // used to get size &c
478 CBM_INIT, // initialize bitmap bits too
479 bits, // ... using this data
480 pbmi, // this is used for palette only
481 DIB_RGB_COLORS // direct or indexed palette?
482 );
483
484 if ( !hbmp )
c11bf842 485 {
22be0335 486 wxLogLastError(wxT("CreateDIBitmap"));
c11bf842
VZ
487 }
488
22be0335
VZ
489 return hbmp;
490}
491
492/* static */
493size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
494{
495 wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") );
496
497 // prepare all the info we need
498 BITMAP bm;
499 if ( !::GetObject(hbmp, sizeof(bm), &bm) )
500 {
501 wxLogLastError(wxT("GetObject(bitmap)"));
502
503 return 0;
504 }
505
22be0335
VZ
506 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
507 // use this one
508 BITMAPINFO bi2;
509
2b254edf 510 const bool wantSizeOnly = pbi == NULL;
22be0335
VZ
511 if ( wantSizeOnly )
512 pbi = &bi2;
513
514 // just for convenience
515 const int h = bm.bmHeight;
516
517 // init the header
518 BITMAPINFOHEADER& bi = pbi->bmiHeader;
519 wxZeroMemory(bi);
520 bi.biSize = sizeof(BITMAPINFOHEADER);
521 bi.biWidth = bm.bmWidth;
522 bi.biHeight = h;
523 bi.biPlanes = 1;
2b254edf 524 bi.biBitCount = bm.bmBitsPixel;
22be0335
VZ
525
526 // memory we need for BITMAPINFO only
be69f971 527 DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
2b254edf
VZ
528
529 // get either just the image size or the image bits
530 if ( !::GetDIBits
531 (
532 ScreenHDC(), // the DC to use
533 hbmp, // the source DDB
534 0, // first scan line
535 h, // number of lines to copy
536 wantSizeOnly ? NULL // pointer to the buffer or
537 : (char *)pbi + dwLen, // NULL if we don't have it
538 pbi, // bitmap header
539 DIB_RGB_COLORS // or DIB_PAL_COLORS
540 ) )
c11bf842 541 {
2b254edf 542 wxLogLastError(wxT("GetDIBits()"));
c11bf842
VZ
543
544 return 0;
545 }
546
2b254edf
VZ
547 // return the total size
548 return dwLen + bi.biSizeImage;
549}
550
551/* static */
552HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
553{
554 // first calculate the size needed
555 const size_t size = ConvertFromBitmap(NULL, hbmp);
556 if ( !size )
22be0335 557 {
2b254edf
VZ
558 // conversion to DDB failed?
559 return NULL;
560 }
22be0335 561
2b254edf
VZ
562 HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
563 if ( !hDIB )
564 {
565 // this is an error which does risk to happen especially under Win9x
566 // and which the user may understand so let him know about it
567 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
568 (unsigned long)(size / 1024));
569
570 return NULL;
22be0335
VZ
571 }
572
0645e2b9 573 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) )
2b254edf
VZ
574 {
575 // this really shouldn't happen... it worked the first time, why not
576 // now?
577 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
578
579 return NULL;
580 }
581
582 return hDIB;
c11bf842
VZ
583}
584
be69f971
VZ
585#endif // __WXWINCE__
586
22be0335
VZ
587// ----------------------------------------------------------------------------
588// palette support
589// ----------------------------------------------------------------------------
590
c11bf842
VZ
591#if wxUSE_PALETTE
592
593wxPalette *wxDIB::CreatePalette() const
594{
2e29e19e
WS
595 // GetDIBColorTable not available in eVC3
596#if defined(_WIN32_WCE) && _WIN32_WCE < 400
597 return NULL;
598#else
c11bf842
VZ
599 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
600
601 DIBSECTION ds;
3692b948 602 if ( !GetDIBSection(m_handle, &ds) )
c11bf842
VZ
603 {
604 wxLogLastError(_T("GetObject(hDIB)"));
605
606 return 0;
607 }
608
609 // how many colours are we going to have in the palette?
610 DWORD biClrUsed = ds.dsBmih.biClrUsed;
611 if ( !biClrUsed )
612 {
613 // biClrUsed field might not be set
be69f971 614 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
c11bf842
VZ
615 }
616
2b254edf 617 if ( !biClrUsed )
c11bf842 618 {
2b254edf 619 // bitmaps of this depth don't have palettes at all
c11bf842
VZ
620 //
621 // NB: another possibility would be to return
622 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
623 return NULL;
624 }
625
146dcf3e
MB
626 MemoryHDC hDC;
627
c11bf842
VZ
628 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
629 // going to have biClrUsed of them so add necessary space
630 LOGPALETTE *pPalette = (LOGPALETTE *)
631 malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
632 wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
633
634 // initialize the palette header
635 pPalette->palVersion = 0x300; // magic number, not in docs but works
373a5fb3 636 pPalette->palNumEntries = (WORD)biClrUsed;
c11bf842 637
146dcf3e
MB
638 // and the colour table
639 wxCharBuffer rgb(sizeof(RGBQUAD) * biClrUsed);
640 RGBQUAD *pRGB = (RGBQUAD*)rgb.data();
78a054f6 641 SelectInHDC selectHandle(hDC, m_handle);
146dcf3e 642 ::GetDIBColorTable(hDC, 0, biClrUsed, pRGB);
c11bf842
VZ
643 for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
644 {
645 pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
646 pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
647 pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
648 pPalette->palPalEntry[i].peFlags = 0;
649 }
650
651 HPALETTE hPalette = ::CreatePalette(pPalette);
652
653 free(pPalette);
654
655 if ( !hPalette )
656 {
657 wxLogLastError(_T("CreatePalette"));
658
659 return NULL;
660 }
661
662 wxPalette *palette = new wxPalette;
663 palette->SetHPALETTE((WXHPALETTE)hPalette);
664
665 return palette;
2e29e19e 666#endif
c11bf842
VZ
667}
668
669#endif // wxUSE_PALETTE
670
53eff2a2
VZ
671// ----------------------------------------------------------------------------
672// wxImage support
673// ----------------------------------------------------------------------------
674
675#if wxUSE_IMAGE
676
677bool wxDIB::Create(const wxImage& image)
678{
679 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
680
681 const int h = image.GetHeight();
682 const int w = image.GetWidth();
683
684 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
685 // a 24bpp RGB is sufficient
45515b66
VZ
686 m_hasAlpha = image.HasAlpha();
687 const int bpp = m_hasAlpha ? 32 : 24;
53eff2a2
VZ
688
689 if ( !Create(w, h, bpp) )
690 return false;
691
bbc1265c
VZ
692 // DIBs are stored in bottom to top order (see also the comment above in
693 // Create()) so we need to copy bits line by line and starting from the end
53eff2a2
VZ
694 const int srcBytesPerLine = w * 3;
695 const int dstBytesPerLine = GetLineSize(w, bpp);
696 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
45515b66
VZ
697 const unsigned char *alpha = m_hasAlpha ? image.GetAlpha() + (h - 1)*w
698 : NULL;
53eff2a2
VZ
699 unsigned char *dstLineStart = (unsigned char *)m_data;
700 for ( int y = 0; y < h; y++ )
701 {
702 // copy one DIB line
703 unsigned char *dst = dstLineStart;
e5d4ef74 704 if ( alpha )
53eff2a2 705 {
e5d4ef74
VZ
706 for ( int x = 0; x < w; x++ )
707 {
708 // RGB order is reversed, and we need to premultiply
709 // all channels by alpha value for use with ::AlphaBlend.
710 const unsigned char a = *alpha++;
907173e5
WS
711 *dst++ = (unsigned char)((src[2] * a + 127) / 255);
712 *dst++ = (unsigned char)((src[1] * a + 127) / 255);
713 *dst++ = (unsigned char)((src[0] * a + 127) / 255);
e5d4ef74
VZ
714 *dst++ = a;
715 src += 3;
716 }
717 }
718 else // no alpha channel
719 {
720 for ( int x = 0; x < w; x++ )
721 {
722 // RGB order is reversed.
723 *dst++ = src[2];
724 *dst++ = src[1];
725 *dst++ = src[0];
726 src += 3;
727 }
53eff2a2
VZ
728 }
729
730 // pass to the previous line in the image
731 src -= 2*srcBytesPerLine;
732 if ( alpha )
733 alpha -= 2*w;
734
735 // and to the next one in the DIB
736 dstLineStart += dstBytesPerLine;
737 }
738
739 return true;
740}
741
be69f971
VZ
742wxImage wxDIB::ConvertToImage() const
743{
744 wxCHECK_MSG( IsOk(), wxNullImage,
745 wxT("can't convert invalid DIB to wxImage") );
746
747 // create the wxImage object
748 const int w = GetWidth();
749 const int h = GetHeight();
750 wxImage image(w, h, false /* don't bother clearing memory */);
751 if ( !image.Ok() )
752 {
753 wxFAIL_MSG( wxT("could not allocate data for image") );
754 return wxNullImage;
755 }
756
45515b66 757 if ( m_hasAlpha )
be69f971
VZ
758 {
759 image.SetAlpha();
760 }
761
762 // this is the same loop as in Create() just above but with copy direction
763 // reversed
45515b66 764 const int bpp = GetDepth();
be69f971
VZ
765 const int dstBytesPerLine = w * 3;
766 const int srcBytesPerLine = GetLineSize(w, bpp);
767 unsigned char *dst = image.GetData() + ((h - 1) * dstBytesPerLine);
768 unsigned char *alpha = image.HasAlpha() ? image.GetAlpha() + (h - 1)*w
769 : NULL;
45515b66 770 const bool is32bit = bpp == 32;
be69f971
VZ
771 const unsigned char *srcLineStart = (unsigned char *)GetData();
772 for ( int y = 0; y < h; y++ )
773 {
774 // copy one DIB line
775 const unsigned char *src = srcLineStart;
776 for ( int x = 0; x < w; x++ )
777 {
778 dst[2] = *src++;
779 dst[1] = *src++;
780 dst[0] = *src++;
781
45515b66
VZ
782 if ( is32bit )
783 {
784 if ( alpha )
0deb5fab
VZ
785 {
786 // wxImage uses non premultiplied alpha so undo
787 // premultiplication done in Create() above
788 const unsigned char a = *src;
789 *alpha++ = a;
790 if ( a > 0 )
791 {
c8aa3d80
VZ
792 dst[0] = (dst[0] * 255) / a;
793 dst[1] = (dst[1] * 255) / a;
794 dst[2] = (dst[2] * 255) / a;
0deb5fab
VZ
795 }
796 }
797
45515b66
VZ
798 src++;
799 }
0deb5fab
VZ
800
801 dst += 3;
be69f971
VZ
802 }
803
804 // pass to the previous line in the image
805 dst -= 2*dstBytesPerLine;
806 if ( alpha )
807 alpha -= 2*w;
808
809 // and to the next one in the DIB
810 srcLineStart += srcBytesPerLine;
811 }
812
813 return image;
814}
815
53eff2a2
VZ
816#endif // wxUSE_IMAGE
817
be69f971 818#endif // wxUSE_WXDIB