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