]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dib.cpp
Mention wxEVT_COMMAND_TOGGLEBUTTON_CLICKED explicitly in the documentation.
[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>
526954c5 9// Licence: 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
9a83f860 94 wxASSERT_MSG( depth, wxT("invalid image depth in wxDIB::Create()") );
be69f971
VZ
95 if ( depth < 24 )
96 depth = 24;
53eff2a2 97
be69f971 98 // allocate memory for bitmap structures
ee56d68c
VZ
99 BITMAPINFO info;
100 wxZeroMemory(info);
53eff2a2 101
ee56d68c
VZ
102 info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
103 info.bmiHeader.biWidth = width;
bbc1265c
VZ
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!
ee56d68c 110 info.bmiHeader.biHeight = height;
bbc1265c 111
ee56d68c
VZ
112 info.bmiHeader.biPlanes = 1;
113 info.bmiHeader.biBitCount = (WORD)depth;
114 info.bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
53eff2a2 115
53eff2a2
VZ
116 m_handle = ::CreateDIBSection
117 (
118 0, // hdc (unused with DIB_RGB_COLORS)
ee56d68c 119 &info, // bitmap description
53eff2a2
VZ
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
53eff2a2
VZ
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
dd779a9e
VZ
140bool wxDIB::Create(HBITMAP hbmp)
141{
69060f4f
VZ
142 wxCHECK_MSG( hbmp, false, wxT("wxDIB::Create(): invalid bitmap") );
143
82ac3b0a
VZ
144 // this bitmap could already be a DIB section in which case we don't need
145 // to convert it to DIB
82ac3b0a 146 DIBSECTION ds;
3692b948 147 if ( GetDIBSection(hbmp, &ds) )
2b254edf 148 {
82ac3b0a
VZ
149 m_handle = hbmp;
150
151 // wxBitmap will free it, not we
152 m_ownsHandle = false;
2b254edf 153
82ac3b0a
VZ
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 {
dd779a9e
VZ
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;
be69f971 173 if ( d <= 0 )
82ac3b0a
VZ
174 d = wxDisplayDepth();
175
dd779a9e 176 if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) )
82ac3b0a 177 return false;
be69f971 178 }
82ac3b0a 179
be69f971
VZ
180 return true;
181}
3692b948 182
be69f971
VZ
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__
3692b948 191
be69f971
VZ
192bool wxDIB::CopyFromDDB(HBITMAP hbmp)
193{
194 MemoryHDC hdcSrc;
195 if ( !hdcSrc )
196 return false;
82ac3b0a 197
be69f971
VZ
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 {
9a83f860 219 wxLogLastError(wxT("BitBlt(DDB -> DIB)"));
be69f971
VZ
220
221 return false;
222 }
223
224 return true;
225}
226
227#else // !__WXWINCE__
228
229bool 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
9a83f860 235 wxFAIL_MSG( wxT("GetObject(DIBSECTION) unexpectedly failed") );
be69f971
VZ
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;
2b254edf
VZ
254 }
255
256 return true;
257}
258
be69f971
VZ
259#endif // __WXWINCE__/!__WXWINCE__
260
c11bf842
VZ
261// ----------------------------------------------------------------------------
262// Loading/saving the DIBs
263// ----------------------------------------------------------------------------
264
265bool wxDIB::Load(const wxString& filename)
266{
be69f971
VZ
267#ifdef __WXWINCE__
268 m_handle = SHLoadDIBitmap(filename);
269#else // !__WXWINCE__
c11bf842
VZ
270 m_handle = (HBITMAP)::LoadImage
271 (
272 wxGetInstance(),
715e4f7e 273 filename.t_str(),
c11bf842
VZ
274 IMAGE_BITMAP,
275 0, 0, // don't specify the size
276 LR_CREATEDIBSECTION | LR_LOADFROMFILE
277 );
be69f971
VZ
278#endif // __WXWINCE__
279
c11bf842
VZ
280 if ( !m_handle )
281 {
9a83f860 282 wxLogLastError(wxT("Loading DIB from file"));
c11bf842
VZ
283
284 return false;
285 }
286
287 return true;
288}
289
2b254edf
VZ
290bool wxDIB::Save(const wxString& filename)
291{
9a83f860 292 wxCHECK_MSG( m_handle, false, wxT("wxDIB::Save(): invalid object") );
2b254edf 293
a8ff046b 294#if wxUSE_FILE
2b254edf
VZ
295 wxFile file(filename, wxFile::write);
296 bool ok = file.IsOpened();
297 if ( ok )
298 {
299 DIBSECTION ds;
3692b948 300 if ( !GetDIBSection(m_handle, &ds) )
2b254edf 301 {
9a83f860 302 wxLogLastError(wxT("GetObject(hDIB)"));
2b254edf
VZ
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 }
a8ff046b
VZ
323#else // !wxUSE_FILE
324 bool ok = false;
325#endif // wxUSE_FILE/!wxUSE_FILE
2b254edf
VZ
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
53eff2a2
VZ
336// ----------------------------------------------------------------------------
337// wxDIB accessors
338// ----------------------------------------------------------------------------
339
340void 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;
3692b948 352 if ( !GetDIBSection(m_handle, &ds) )
53eff2a2 353 {
9a83f860 354 wxLogLastError(wxT("GetObject(hDIB)"));
53eff2a2
VZ
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
22be0335
VZ
367// ----------------------------------------------------------------------------
368// DDB <-> DIB conversions
369// ----------------------------------------------------------------------------
370
be69f971
VZ
371#ifndef __WXWINCE__
372
c11bf842
VZ
373HBITMAP wxDIB::CreateDDB(HDC hdc) const
374{
9a83f860 375 wxCHECK_MSG( m_handle, 0, wxT("wxDIB::CreateDDB(): invalid object") );
c11bf842
VZ
376
377 DIBSECTION ds;
3692b948 378 if ( !GetDIBSection(m_handle, &ds) )
c11bf842 379 {
9a83f860 380 wxLogLastError(wxT("GetObject(hDIB)"));
c11bf842
VZ
381
382 return 0;
383 }
384
146dcf3e
MB
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 }
22be0335
VZ
410}
411
412/* static */
413HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
414{
9a83f860 415 wxCHECK_MSG( pbmi, 0, wxT("invalid DIB in ConvertToBitmap") );
22be0335
VZ
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 )
c11bf842 425 {
22be0335 426 // we must skip over the colour table to get to the image data
a8beba72
VZ
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 )
22be0335 434 {
a8beba72
VZ
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 {
be69f971 445 numColors = GetNumberOfColours(pbmih->biBitCount);
a8beba72
VZ
446 }
447 break;
448
449 default:
450 // no idea how it should be calculated for the other cases
451 numColors = 0;
22be0335
VZ
452 }
453
454 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
c11bf842 455 }
4b1f929c 456
22be0335
VZ
457 HBITMAP hbmp = ::CreateDIBitmap
458 (
4b1f929c
CE
459 hdc ? hdc // create bitmap compatible
460 : (HDC) ScreenHDC(), // with this DC
22be0335
VZ
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 )
c11bf842 469 {
22be0335 470 wxLogLastError(wxT("CreateDIBitmap"));
c11bf842
VZ
471 }
472
22be0335
VZ
473 return hbmp;
474}
475
476/* static */
477size_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
22be0335
VZ
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
2b254edf 494 const bool wantSizeOnly = pbi == NULL;
22be0335
VZ
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;
2b254edf 508 bi.biBitCount = bm.bmBitsPixel;
22be0335
VZ
509
510 // memory we need for BITMAPINFO only
be69f971 511 DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD);
2b254edf
VZ
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 ) )
c11bf842 525 {
2b254edf 526 wxLogLastError(wxT("GetDIBits()"));
c11bf842
VZ
527
528 return 0;
529 }
530
2b254edf
VZ
531 // return the total size
532 return dwLen + bi.biSizeImage;
533}
534
535/* static */
536HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
537{
538 // first calculate the size needed
539 const size_t size = ConvertFromBitmap(NULL, hbmp);
540 if ( !size )
22be0335 541 {
2b254edf
VZ
542 // conversion to DDB failed?
543 return NULL;
544 }
22be0335 545
2b254edf
VZ
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
0ed6c933 551 wxLogError(_("Failed to allocate %luKb of memory for bitmap data."),
2b254edf
VZ
552 (unsigned long)(size / 1024));
553
554 return NULL;
22be0335
VZ
555 }
556
0645e2b9 557 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) )
2b254edf
VZ
558 {
559 // this really shouldn't happen... it worked the first time, why not
560 // now?
9a83f860 561 wxFAIL_MSG( wxT("wxDIB::ConvertFromBitmap() unexpectedly failed") );
2b254edf
VZ
562
563 return NULL;
564 }
565
566 return hDIB;
c11bf842
VZ
567}
568
be69f971
VZ
569#endif // __WXWINCE__
570
22be0335
VZ
571// ----------------------------------------------------------------------------
572// palette support
573// ----------------------------------------------------------------------------
574
c11bf842
VZ
575#if wxUSE_PALETTE
576
577wxPalette *wxDIB::CreatePalette() const
578{
2e29e19e
WS
579 // GetDIBColorTable not available in eVC3
580#if defined(_WIN32_WCE) && _WIN32_WCE < 400
581 return NULL;
582#else
9a83f860 583 wxCHECK_MSG( m_handle, NULL, wxT("wxDIB::CreatePalette(): invalid object") );
c11bf842
VZ
584
585 DIBSECTION ds;
3692b948 586 if ( !GetDIBSection(m_handle, &ds) )
c11bf842 587 {
9a83f860 588 wxLogLastError(wxT("GetObject(hDIB)"));
c11bf842
VZ
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
be69f971 598 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount);
c11bf842
VZ
599 }
600
2b254edf 601 if ( !biClrUsed )
c11bf842 602 {
2b254edf 603 // bitmaps of this depth don't have palettes at all
c11bf842
VZ
604 //
605 // NB: another possibility would be to return
606 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
607 return NULL;
608 }
609
146dcf3e
MB
610 MemoryHDC hDC;
611
c11bf842
VZ
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));
9a83f860 616 wxCHECK_MSG( pPalette, NULL, wxT("out of memory") );
c11bf842
VZ
617
618 // initialize the palette header
619 pPalette->palVersion = 0x300; // magic number, not in docs but works
373a5fb3 620 pPalette->palNumEntries = (WORD)biClrUsed;
c11bf842 621
146dcf3e
MB
622 // and the colour table
623 wxCharBuffer rgb(sizeof(RGBQUAD) * biClrUsed);
624 RGBQUAD *pRGB = (RGBQUAD*)rgb.data();
78a054f6 625 SelectInHDC selectHandle(hDC, m_handle);
146dcf3e 626 ::GetDIBColorTable(hDC, 0, biClrUsed, pRGB);
c11bf842
VZ
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 {
9a83f860 641 wxLogLastError(wxT("CreatePalette"));
c11bf842
VZ
642
643 return NULL;
644 }
645
646 wxPalette *palette = new wxPalette;
647 palette->SetHPALETTE((WXHPALETTE)hPalette);
648
649 return palette;
2e29e19e 650#endif
c11bf842
VZ
651}
652
653#endif // wxUSE_PALETTE
654
53eff2a2
VZ
655// ----------------------------------------------------------------------------
656// wxImage support
657// ----------------------------------------------------------------------------
658
659#if wxUSE_IMAGE
660
fd90675b 661bool wxDIB::Create(const wxImage& image, PixelFormat pf)
53eff2a2 662{
a1b806b9 663 wxCHECK_MSG( image.IsOk(), false, wxT("invalid wxImage in wxDIB ctor") );
53eff2a2
VZ
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
20af6fd5
VZ
670 const bool hasAlpha = image.HasAlpha();
671 const int bpp = hasAlpha ? 32 : 24;
53eff2a2
VZ
672
673 if ( !Create(w, h, bpp) )
674 return false;
675
bbc1265c
VZ
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
53eff2a2
VZ
678 const int srcBytesPerLine = w * 3;
679 const int dstBytesPerLine = GetLineSize(w, bpp);
680 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
20af6fd5
VZ
681 const unsigned char *alpha = hasAlpha ? image.GetAlpha() + (h - 1)*w
682 : NULL;
53eff2a2
VZ
683 unsigned char *dstLineStart = (unsigned char *)m_data;
684 for ( int y = 0; y < h; y++ )
685 {
fd90675b
VZ
686 // Copy one DIB line. Note that RGB components order is reversed in
687 // Windows bitmaps compared to wxImage and is actually BGR.
53eff2a2 688 unsigned char *dst = dstLineStart;
e5d4ef74 689 if ( alpha )
53eff2a2 690 {
a24b341a
VZ
691 int x;
692
fd90675b 693 switch ( pf )
e5d4ef74 694 {
fd90675b
VZ
695 case PixelFormat_PreMultiplied:
696 // Pre-multiply pixel values so that the DIB could be used
697 // with ::AlphaBlend().
a24b341a 698 for ( x = 0; x < w; x++ )
fd90675b
VZ
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.
a24b341a 711 for ( x = 0; x < w; x++ )
fd90675b
VZ
712 {
713 *dst++ = src[2];
714 *dst++ = src[1];
715 *dst++ = src[0];
716
717 *dst++ = *alpha++;
718 src += 3;
719 }
720 break;
e5d4ef74 721 }
fd90675b 722
e5d4ef74
VZ
723 }
724 else // no alpha channel
725 {
726 for ( int x = 0; x < w; x++ )
727 {
e5d4ef74
VZ
728 *dst++ = src[2];
729 *dst++ = src[1];
730 *dst++ = src[0];
731 src += 3;
732 }
53eff2a2
VZ
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
be69f971
VZ
747wxImage 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 */);
a1b806b9 756 if ( !image.IsOk() )
be69f971
VZ
757 {
758 wxFAIL_MSG( wxT("could not allocate data for image") );
759 return wxNullImage;
760 }
761
254f9b4c 762 const int bpp = GetDepth();
20ca5632
VZ
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.
254f9b4c 767 bool hasAlpha = false;
20ca5632
VZ
768 bool hasOpaque = false;
769 bool hasTransparent = false;
770
254f9b4c 771 if ( bpp == 32 )
be69f971 772 {
254f9b4c
VZ
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
20af6fd5 775 // get rid of it later if it turns out we didn't.
be69f971
VZ
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
254f9b4c 797 if ( bpp == 32 )
45515b66 798 {
254f9b4c
VZ
799 // wxImage uses non premultiplied alpha so undo
800 // premultiplication done in Create() above
801 const unsigned char a = *src;
802 *alpha++ = a;
20ca5632
VZ
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
254f9b4c 822 if ( a > 0 )
0deb5fab 823 {
254f9b4c
VZ
824 dst[0] = (dst[0] * 255) / a;
825 dst[1] = (dst[1] * 255) / a;
826 dst[2] = (dst[2] * 255) / a;
0deb5fab
VZ
827 }
828
45515b66
VZ
829 src++;
830 }
0deb5fab
VZ
831
832 dst += 3;
be69f971
VZ
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
20ca5632
VZ
844 if ( hasOpaque && hasTransparent )
845 hasAlpha = true;
846
254f9b4c
VZ
847 if ( !hasAlpha && image.HasAlpha() )
848 image.ClearAlpha();
849
be69f971
VZ
850 return image;
851}
852
53eff2a2
VZ
853#endif // wxUSE_IMAGE
854
be69f971 855#endif // wxUSE_WXDIB