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