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