start of alpha transparency support
[wxWidgets.git] / src / msw / bitmap.cpp
1 ////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "bitmap.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include <stdio.h>
33
34 #include "wx/list.h"
35 #include "wx/utils.h"
36 #include "wx/app.h"
37 #include "wx/palette.h"
38 #include "wx/dcmemory.h"
39 #include "wx/bitmap.h"
40 #include "wx/icon.h"
41 #endif
42
43 #include "wx/msw/private.h"
44 #include "wx/log.h"
45
46 #if !defined(__WXMICROWIN__)
47 #include "wx/msw/dib.h"
48 #endif
49
50 #include "wx/image.h"
51 #include "wx/xpmdecod.h"
52
53 // missing from mingw32 header
54 #ifndef CLR_INVALID
55 #define CLR_INVALID ((COLORREF)-1)
56 #endif // no CLR_INVALID
57
58 // ----------------------------------------------------------------------------
59 // Bitmap data
60 // ----------------------------------------------------------------------------
61
62 class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
63 {
64 public:
65 wxBitmapRefData();
66 virtual ~wxBitmapRefData() { Free(); }
67
68 virtual void Free();
69
70 // set the mask object to use as the mask, we take ownership of it
71 void SetMask(wxMask *mask)
72 {
73 delete m_bitmapMask;
74 m_bitmapMask = mask;
75 }
76
77 // set the HBITMAP to use as the mask
78 void SetMask(HBITMAP hbmpMask)
79 {
80 SetMask(new wxMask((WXHBITMAP)hbmpMask));
81 }
82
83 // return the mask
84 wxMask *GetMask() const { return m_bitmapMask; }
85
86 public:
87 #if wxUSE_PALETTE
88 wxPalette m_bitmapPalette;
89 #endif // wxUSE_PALETTE
90
91 // MSW-specific
92 // ------------
93
94 #ifdef __WXDEBUG__
95 // this field is solely for error checking: we detect selecting a bitmap
96 // into more than one DC at once or deleting a bitmap still selected into a
97 // DC (both are serious programming errors under Windows)
98 wxDC *m_selectedInto;
99 #endif // __WXDEBUG__
100
101 // true if we have alpha transparency info and can be drawn using
102 // AlphaBlend()
103 bool m_hasAlpha;
104
105 private:
106 // optional mask for transparent drawing
107 wxMask *m_bitmapMask;
108
109 DECLARE_NO_COPY_CLASS(wxBitmapRefData)
110 };
111
112 // ----------------------------------------------------------------------------
113 // macros
114 // ----------------------------------------------------------------------------
115
116 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
117 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
118
119 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
120
121 // ============================================================================
122 // implementation
123 // ============================================================================
124
125 // ----------------------------------------------------------------------------
126 // wxBitmapRefData
127 // ----------------------------------------------------------------------------
128
129 wxBitmapRefData::wxBitmapRefData()
130 {
131 m_selectedInto = NULL;
132 m_bitmapMask = NULL;
133 m_hBitmap = (WXHBITMAP) NULL;
134 m_hasAlpha = FALSE;
135 }
136
137 void wxBitmapRefData::Free()
138 {
139 wxASSERT_MSG( !m_selectedInto,
140 wxT("deleting bitmap still selected into wxMemoryDC") );
141
142 if ( m_hBitmap)
143 {
144 if ( !::DeleteObject((HBITMAP)m_hBitmap) )
145 {
146 wxLogLastError(wxT("DeleteObject(hbitmap)"));
147 }
148 }
149
150 delete m_bitmapMask;
151 m_bitmapMask = NULL;
152 }
153
154 // ----------------------------------------------------------------------------
155 // wxBitmap creation
156 // ----------------------------------------------------------------------------
157
158 // this function should be called from all wxBitmap ctors
159 void wxBitmap::Init()
160 {
161 // m_refData = NULL; done in the base class ctor
162
163 }
164
165 wxGDIImageRefData *wxBitmap::CreateData() const
166 {
167 return new wxBitmapRefData;
168 }
169
170 #ifdef __WIN32__
171
172 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon)
173 {
174 #ifndef __WXMICROWIN__
175 // it may be either HICON or HCURSOR
176 HICON hicon = (HICON)icon.GetHandle();
177
178 ICONINFO iconInfo;
179 if ( !::GetIconInfo(hicon, &iconInfo) )
180 {
181 wxLogLastError(wxT("GetIconInfo"));
182
183 return FALSE;
184 }
185
186 wxBitmapRefData *refData = new wxBitmapRefData;
187 m_refData = refData;
188
189 int w = icon.GetWidth(),
190 h = icon.GetHeight();
191
192 refData->m_width = w;
193 refData->m_height = h;
194 refData->m_depth = wxDisplayDepth();
195
196 refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor;
197
198 // the mask returned by GetIconInfo() is inversed compared to the usual
199 // wxWin convention
200 refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h));
201
202
203 // delete the old one now as we don't need it any more
204 ::DeleteObject(iconInfo.hbmMask);
205
206 #if WXWIN_COMPATIBILITY_2
207 refData->m_ok = TRUE;
208 #endif // WXWIN_COMPATIBILITY_2
209
210 return TRUE;
211 #else
212 return FALSE;
213 #endif
214 }
215
216 #endif // Win32
217
218 bool wxBitmap::CopyFromCursor(const wxCursor& cursor)
219 {
220 UnRef();
221
222 if ( !cursor.Ok() )
223 return FALSE;
224
225 #ifdef __WIN16__
226 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
227
228 return FALSE;
229 #else
230 return CopyFromIconOrCursor(cursor);
231 #endif // Win16
232 }
233
234 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
235 {
236 UnRef();
237
238 if ( !icon.Ok() )
239 return FALSE;
240
241 // GetIconInfo() doesn't exist under Win16 and I don't know any other way
242 // to create a bitmap from icon there - but using this way we won't have
243 // the mask (FIXME)
244 #ifdef __WIN16__
245 int width = icon.GetWidth(),
246 height = icon.GetHeight();
247
248 // copy the icon to the bitmap
249 ScreenHDC hdcScreen;
250 HDC hdc = ::CreateCompatibleDC(hdcScreen);
251 HBITMAP hbitmap = ::CreateCompatibleBitmap(hdcScreen, width, height);
252 HBITMAP hbmpOld = (HBITMAP)::SelectObject(hdc, hbitmap);
253
254 ::DrawIcon(hdc, 0, 0, GetHiconOf(icon));
255
256 ::SelectObject(hdc, hbmpOld);
257 ::DeleteDC(hdc);
258
259 wxBitmapRefData *refData = new wxBitmapRefData;
260 m_refData = refData;
261
262 refData->m_width = width;
263 refData->m_height = height;
264 refData->m_depth = wxDisplayDepth();
265
266 refData->m_hBitmap = (WXHBITMAP)hbitmap;
267
268 #if WXWIN_COMPATIBILITY_2
269 refData->m_ok = TRUE;
270 #endif // WXWIN_COMPATIBILITY_2
271
272 return TRUE;
273 #else // Win32
274 return CopyFromIconOrCursor(icon);
275 #endif // Win16/Win32
276 }
277
278 wxBitmap::~wxBitmap()
279 {
280 }
281
282 wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
283 {
284 Init();
285
286 #ifndef __WXMICROWIN__
287 wxBitmapRefData *refData = new wxBitmapRefData;
288 m_refData = refData;
289
290 refData->m_width = width;
291 refData->m_height = height;
292 refData->m_depth = depth;
293
294 char *data;
295 if ( depth == 1 )
296 {
297 // we assume that it is in XBM format which is not quite the same as
298 // the format CreateBitmap() wants because the order of bytes in the
299 // line is inversed!
300 const size_t bytesPerLine = (width + 7) / 8;
301 const size_t padding = bytesPerLine % 2;
302 const size_t len = height * ( padding + bytesPerLine );
303 data = (char *)malloc(len);
304 const char *src = bits;
305 char *dst = data;
306
307 for ( int rows = 0; rows < height; rows++ )
308 {
309 for ( size_t cols = 0; cols < bytesPerLine; cols++ )
310 {
311 unsigned char val = *src++;
312 unsigned char reversed = 0;
313
314 for ( int bits = 0; bits < 8; bits++)
315 {
316 reversed <<= 1;
317 reversed |= (val & 0x01);
318 val >>= 1;
319 }
320 *dst++ = reversed;
321 }
322
323 if ( padding )
324 *dst++ = 0;
325 }
326 }
327 else
328 {
329 // bits should already be in Windows standard format
330 data = (char *)bits; // const_cast is harmless
331 }
332
333 HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data);
334 if ( !hbmp )
335 {
336 wxLogLastError(wxT("CreateBitmap"));
337 }
338
339 if ( data != bits )
340 {
341 free(data);
342 }
343
344 SetHBITMAP((WXHBITMAP)hbmp);
345 #endif
346 }
347
348 // Create from XPM data
349 bool wxBitmap::CreateFromXpm(const char **data)
350 {
351 #if wxUSE_IMAGE && wxUSE_XPM
352 Init();
353
354 wxCHECK_MSG( data != NULL, FALSE, wxT("invalid bitmap data") )
355
356 wxXPMDecoder decoder;
357 wxImage img = decoder.ReadData(data);
358 wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") )
359
360 *this = wxBitmap(img);
361 return TRUE;
362 #else
363 return FALSE;
364 #endif
365 }
366
367 wxBitmap::wxBitmap(int w, int h, int d)
368 {
369 Init();
370
371 (void)Create(w, h, d);
372 }
373
374 wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth)
375 {
376 Init();
377
378 (void)Create(data, type, width, height, depth);
379 }
380
381 wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type)
382 {
383 Init();
384
385 LoadFile(filename, (int)type);
386 }
387
388 bool wxBitmap::Create(int w, int h, int d)
389 {
390 UnRef();
391
392 m_refData = new wxBitmapRefData;
393
394 #if wxUSE_DIB_FOR_BITMAP
395 if ( w && h && d >= 16 )
396 {
397 if ( !CreateDIB(w, h, d) )
398 return FALSE;
399 }
400 else
401 #endif // wxUSE_DIB_FOR_BITMAP
402 {
403 GetBitmapData()->m_width = w;
404 GetBitmapData()->m_height = h;
405 GetBitmapData()->m_depth = d;
406
407 HBITMAP hbmp;
408 #ifndef __WXMICROWIN__
409 if ( d > 0 )
410 {
411 hbmp = ::CreateBitmap(w, h, 1, d, NULL);
412 if ( !hbmp )
413 {
414 wxLogLastError(wxT("CreateBitmap"));
415 }
416 }
417 else
418 #endif // !__WXMICROWIN__
419 {
420 ScreenHDC dc;
421 hbmp = ::CreateCompatibleBitmap(dc, w, h);
422 if ( !hbmp )
423 {
424 wxLogLastError(wxT("CreateCompatibleBitmap"));
425 }
426
427 GetBitmapData()->m_depth = wxDisplayDepth();
428 }
429
430 SetHBITMAP((WXHBITMAP)hbmp);
431
432 #if WXWIN_COMPATIBILITY_2
433 GetBitmapData()->m_ok = hbmp != 0;
434 #endif // WXWIN_COMPATIBILITY_2
435 }
436
437 return Ok();
438 }
439
440 #if wxUSE_IMAGE
441
442 // ----------------------------------------------------------------------------
443 // wxImage to/from conversions for Microwin
444 // ----------------------------------------------------------------------------
445
446 // Microwin versions are so different from normal ones that it really doesn't
447 // make sense to use #ifdefs inside the function bodies
448 #ifdef __WXMICROWIN__
449
450 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
451 {
452 // Set this to 1 to experiment with mask code,
453 // which currently doesn't work
454 #define USE_MASKS 0
455
456 m_refData = new wxBitmapRefData();
457
458 // Initial attempt at a simple-minded implementation.
459 // The bitmap will always be created at the screen depth,
460 // so the 'depth' argument is ignored.
461
462 HDC hScreenDC = ::GetDC(NULL);
463 int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL);
464
465 HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight());
466 HBITMAP hMaskBitmap = NULL;
467 HBITMAP hOldMaskBitmap = NULL;
468 HDC hMaskDC = NULL;
469 unsigned char maskR = 0;
470 unsigned char maskG = 0;
471 unsigned char maskB = 0;
472
473 // printf("Created bitmap %d\n", (int) hBitmap);
474 if (hBitmap == NULL)
475 {
476 ::ReleaseDC(NULL, hScreenDC);
477 return FALSE;
478 }
479 HDC hMemDC = ::CreateCompatibleDC(hScreenDC);
480
481 HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap);
482 ::ReleaseDC(NULL, hScreenDC);
483
484 // created an mono-bitmap for the possible mask
485 bool hasMask = image.HasMask();
486
487 if ( hasMask )
488 {
489 #if USE_MASKS
490 // FIXME: we should be able to pass bpp = 1, but
491 // GdBlit can't handle a different depth
492 #if 0
493 hMaskBitmap = ::CreateBitmap( (WORD)image.GetWidth(), (WORD)image.GetHeight(), 1, 1, NULL );
494 #else
495 hMaskBitmap = ::CreateCompatibleBitmap( hMemDC, (WORD)image.GetWidth(), (WORD)image.GetHeight());
496 #endif
497 maskR = image.GetMaskRed();
498 maskG = image.GetMaskGreen();
499 maskB = image.GetMaskBlue();
500
501 if (!hMaskBitmap)
502 {
503 hasMask = FALSE;
504 }
505 else
506 {
507 hScreenDC = ::GetDC(NULL);
508 hMaskDC = ::CreateCompatibleDC(hScreenDC);
509 ::ReleaseDC(NULL, hScreenDC);
510
511 hOldMaskBitmap = ::SelectObject( hMaskDC, hMaskBitmap);
512 }
513 #else
514 hasMask = FALSE;
515 #endif
516 }
517
518 int i, j;
519 for (i = 0; i < image.GetWidth(); i++)
520 {
521 for (j = 0; j < image.GetHeight(); j++)
522 {
523 unsigned char red = image.GetRed(i, j);
524 unsigned char green = image.GetGreen(i, j);
525 unsigned char blue = image.GetBlue(i, j);
526
527 ::SetPixel(hMemDC, i, j, PALETTERGB(red, green, blue));
528
529 if (hasMask)
530 {
531 // scan the bitmap for the transparent colour and set the corresponding
532 // pixels in the mask to BLACK and the rest to WHITE
533 if (maskR == red && maskG == green && maskB == blue)
534 ::SetPixel(hMaskDC, i, j, PALETTERGB(0, 0, 0));
535 else
536 ::SetPixel(hMaskDC, i, j, PALETTERGB(255, 255, 255));
537 }
538 }
539 }
540
541 ::SelectObject(hMemDC, hOldBitmap);
542 ::DeleteDC(hMemDC);
543 if (hasMask)
544 {
545 ::SelectObject(hMaskDC, hOldMaskBitmap);
546 ::DeleteDC(hMaskDC);
547
548 ((wxBitmapRefData*)m_refData)->SetMask(hMaskBitmap);
549 }
550
551 SetWidth(image.GetWidth());
552 SetHeight(image.GetHeight());
553 SetDepth(screenDepth);
554 SetHBITMAP( (WXHBITMAP) hBitmap );
555
556 #if wxUSE_PALETTE
557 // Copy the palette from the source image
558 SetPalette(image.GetPalette());
559 #endif // wxUSE_PALETTE
560
561 #if WXWIN_COMPATIBILITY_2
562 // check the wxBitmap object
563 GetBitmapData()->SetOk();
564 #endif // WXWIN_COMPATIBILITY_2
565
566 return TRUE;
567 }
568
569 wxImage wxBitmap::ConvertToImage() const
570 {
571 // Initial attempt at a simple-minded implementation.
572 // The bitmap will always be created at the screen depth,
573 // so the 'depth' argument is ignored.
574 // TODO: transparency (create a mask image)
575
576 if (!Ok())
577 {
578 wxFAIL_MSG( wxT("bitmap is invalid") );
579 return wxNullImage;
580 }
581
582 wxImage image;
583
584 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
585
586 // create an wxImage object
587 int width = GetWidth();
588 int height = GetHeight();
589 image.Create( width, height );
590 unsigned char *data = image.GetData();
591 if( !data )
592 {
593 wxFAIL_MSG( wxT("could not allocate data for image") );
594 return wxNullImage;
595 }
596
597 HDC hScreenDC = ::GetDC(NULL);
598
599 HDC hMemDC = ::CreateCompatibleDC(hScreenDC);
600 ::ReleaseDC(NULL, hScreenDC);
601
602 HBITMAP hBitmap = (HBITMAP) GetHBITMAP();
603
604 HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap);
605
606 int i, j;
607 for (i = 0; i < GetWidth(); i++)
608 {
609 for (j = 0; j < GetHeight(); j++)
610 {
611 COLORREF color = ::GetPixel(hMemDC, i, j);
612 unsigned char red = GetRValue(color);
613 unsigned char green = GetGValue(color);
614 unsigned char blue = GetBValue(color);
615
616 image.SetRGB(i, j, red, green, blue);
617 }
618 }
619
620 ::SelectObject(hMemDC, hOldBitmap);
621 ::DeleteDC(hMemDC);
622
623 #if wxUSE_PALETTE
624 // Copy the palette from the source image
625 if (GetPalette())
626 image.SetPalette(* GetPalette());
627 #endif // wxUSE_PALETTE
628
629 return image;
630 }
631
632 #endif // __WXMICROWIN__
633
634 // ----------------------------------------------------------------------------
635 // wxImage to/from conversions
636 // ----------------------------------------------------------------------------
637
638 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
639 {
640 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") );
641
642 UnRef();
643
644 // first convert the image to DIB
645 const int h = image.GetHeight();
646 const int w = image.GetWidth();
647
648 wxDIB dib(image);
649 if ( !dib.IsOk() )
650 return FALSE;
651
652
653 // store the bitmap parameters
654 wxBitmapRefData *refData = new wxBitmapRefData;
655 refData->m_width = w;
656 refData->m_height = h;
657 refData->m_depth = dib.GetDepth();
658 refData->m_hasAlpha = image.HasAlpha();
659
660 m_refData = refData;
661
662
663 // next either store DIB as is or create a DDB from it
664 HBITMAP hbitmap;
665
666 // TODO: if we're ready to use DIB as is, we can just do this:
667 // if ( ... )
668 // hbitmap = dib.Detach();
669 // else
670 {
671 // create and set the device-dependent bitmap
672 //
673 // VZ: why don't we just use SetDIBits() instead? because of the
674 // palette or is there some other reason?
675 hbitmap = ::CreateCompatibleBitmap(ScreenHDC(), w, h);
676 if ( !hbitmap )
677 {
678 wxLogLastError(_T("CreateCompatibleBitmap()"));
679
680 return FALSE;
681 }
682
683 MemoryHDC hdcMem;
684 SelectInHDC select(hdcMem, hbitmap);
685 if ( !select )
686 {
687 wxLogLastError(_T("SelectObjct(hBitmap)"));
688 }
689
690 #if wxUSE_PALETTE
691 const wxPalette& palette = image.GetPalette();
692
693 HPALETTE hOldPalette;
694 if ( palette.Ok() )
695 {
696 SetPalette(palette);
697
698 hOldPalette = ::SelectPalette
699 (
700 hdcMem,
701 GetHpaletteOf(palette),
702 FALSE // ignored for hdcMem
703 );
704
705 if ( !hOldPalette )
706 {
707 wxLogLastError(_T("SelectPalette()"));
708 }
709
710 if ( ::RealizePalette(hdcMem) == GDI_ERROR )
711 {
712 wxLogLastError(_T("RealizePalette()"));
713 }
714 }
715 else // no valid palette
716 {
717 hOldPalette = 0;
718 }
719 #endif // wxUSE_PALETTE
720
721 DIBSECTION ds;
722 if ( !::GetObject(dib.GetHandle(), sizeof(ds), &ds) )
723 {
724 wxLogLastError(_T("GetObject(hDIB)"));
725 }
726
727 if ( ::StretchDIBits(hdcMem,
728 0, 0, w, h,
729 0, 0, w, h,
730 dib.GetData(),
731 (BITMAPINFO *)&ds.dsBmih,
732 DIB_RGB_COLORS,
733 SRCCOPY) == GDI_ERROR )
734 {
735 wxLogLastError(_T("StretchDIBits()"));
736
737 return FALSE;
738 }
739
740 #if wxUSE_PALETTE
741 if ( hOldPalette )
742 {
743 ::SelectPalette(hdcMem, hOldPalette, FALSE);
744 }
745 #endif // wxUSE_PALETTE
746 }
747
748 // validate this object
749 SetHBITMAP((WXHBITMAP)hbitmap);
750
751 #if WXWIN_COMPATIBILITY_2
752 m_refData->m_ok = TRUE;
753 #endif // WXWIN_COMPATIBILITY_2
754
755 // finally also set the mask if we have one
756 if ( image.HasMask() )
757 {
758 SetMask(new wxMask(*this, wxColour(image.GetMaskRed(),
759 image.GetMaskGreen(),
760 image.GetMaskBlue())));
761 }
762
763 return TRUE;
764 }
765
766 wxImage wxBitmap::ConvertToImage() const
767 {
768 wxImage image;
769
770 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
771
772 // create an wxImage object
773 int width = GetWidth();
774 int height = GetHeight();
775 image.Create( width, height );
776 unsigned char *data = image.GetData();
777 if( !data )
778 {
779 wxFAIL_MSG( wxT("could not allocate data for image") );
780 return wxNullImage;
781 }
782
783 // calc the number of bytes per scanline and padding in the DIB
784 int bytePerLine = width*3;
785 int sizeDWORD = sizeof( DWORD );
786 int lineBoundary = bytePerLine % sizeDWORD;
787 int padding = 0;
788 if( lineBoundary > 0 )
789 {
790 padding = sizeDWORD - lineBoundary;
791 bytePerLine += padding;
792 }
793
794 // create a DIB header
795 int headersize = sizeof(BITMAPINFOHEADER);
796 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
797 if( !lpDIBh )
798 {
799 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
800 free( data );
801 return wxNullImage;
802 }
803 // Fill in the DIB header
804 lpDIBh->bmiHeader.biSize = headersize;
805 lpDIBh->bmiHeader.biWidth = width;
806 lpDIBh->bmiHeader.biHeight = -height;
807 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
808 lpDIBh->bmiHeader.biPlanes = 1;
809 lpDIBh->bmiHeader.biBitCount = 24;
810 lpDIBh->bmiHeader.biCompression = BI_RGB;
811 lpDIBh->bmiHeader.biClrUsed = 0;
812 // These seem not really needed for our purpose here.
813 lpDIBh->bmiHeader.biClrImportant = 0;
814 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
815 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
816 // memory for DIB data
817 unsigned char *lpBits;
818 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
819 if( !lpBits )
820 {
821 wxFAIL_MSG( wxT("could not allocate data for DIB") );
822 free( data );
823 free( lpDIBh );
824 return wxNullImage;
825 }
826
827 // copy data from the device-dependent bitmap to the DIB
828 HDC hdc = ::GetDC(NULL);
829 HBITMAP hbitmap;
830 hbitmap = (HBITMAP) GetHBITMAP();
831 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
832
833 // copy DIB data into the wxImage object
834 int i, j;
835 unsigned char *ptdata = data;
836 unsigned char *ptbits = lpBits;
837 for( i=0; i<height; i++ )
838 {
839 for( j=0; j<width; j++ )
840 {
841 *(ptdata++) = *(ptbits+2);
842 *(ptdata++) = *(ptbits+1);
843 *(ptdata++) = *(ptbits );
844 ptbits += 3;
845 }
846 ptbits += padding;
847 }
848
849 // similarly, set data according to the possible mask bitmap
850 if( GetMask() && GetMask()->GetMaskBitmap() )
851 {
852 hbitmap = (HBITMAP) GetMask()->GetMaskBitmap();
853 // memory DC created, color set, data copied, and memory DC deleted
854 HDC memdc = ::CreateCompatibleDC( hdc );
855 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
856 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
857 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
858 ::DeleteDC( memdc );
859 // background color set to RGB(16,16,16) in consistent with wxGTK
860 unsigned char r=16, g=16, b=16;
861 ptdata = data;
862 ptbits = lpBits;
863 for( i=0; i<height; i++ )
864 {
865 for( j=0; j<width; j++ )
866 {
867 if( *ptbits != 0 )
868 ptdata += 3;
869 else
870 {
871 *(ptdata++) = r;
872 *(ptdata++) = g;
873 *(ptdata++) = b;
874 }
875 ptbits += 3;
876 }
877 ptbits += padding;
878 }
879 image.SetMaskColour( r, g, b );
880 image.SetMask( TRUE );
881 }
882 else
883 {
884 image.SetMask( FALSE );
885 }
886 // free allocated resources
887 ::ReleaseDC(NULL, hdc);
888 free(lpDIBh);
889 free(lpBits);
890
891 return image;
892 }
893
894 #endif // wxUSE_IMAGE
895
896 // ----------------------------------------------------------------------------
897 // loading and saving bitmaps
898 // ----------------------------------------------------------------------------
899
900 bool wxBitmap::LoadFile(const wxString& filename, long type)
901 {
902 UnRef();
903
904 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
905
906 if ( handler )
907 {
908 m_refData = new wxBitmapRefData;
909
910 return handler->LoadFile(this, filename, type, -1, -1);
911 }
912 #if wxUSE_IMAGE
913 else
914 {
915 wxImage image;
916 if ( image.LoadFile( filename, type ) && image.Ok() )
917 {
918 *this = wxBitmap(image);
919
920 return TRUE;
921 }
922 }
923 #endif // wxUSE_IMAGE
924
925 return FALSE;
926 }
927
928 bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
929 {
930 UnRef();
931
932 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
933
934 if ( !handler )
935 {
936 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type);
937
938 return FALSE;
939 }
940
941 m_refData = new wxBitmapRefData;
942
943 return handler->Create(this, data, type, width, height, depth);
944 }
945
946 bool wxBitmap::SaveFile(const wxString& filename,
947 int type,
948 const wxPalette *palette)
949 {
950 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
951
952 if ( handler )
953 {
954 return handler->SaveFile(this, filename, type, palette);
955 }
956 #if wxUSE_IMAGE
957 else
958 {
959 // FIXME what about palette? shouldn't we use it?
960 wxImage image = ConvertToImage();
961 if ( image.Ok() )
962 {
963 return image.SaveFile(filename, type);
964 }
965 }
966 #endif // wxUSE_IMAGE
967
968 return FALSE;
969 }
970
971 // ----------------------------------------------------------------------------
972 // sub bitmap extraction
973 // ----------------------------------------------------------------------------
974
975 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
976 {
977 wxCHECK_MSG( Ok() &&
978 (rect.x >= 0) && (rect.y >= 0) &&
979 (rect.x+rect.width <= GetWidth()) &&
980 (rect.y+rect.height <= GetHeight()),
981 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
982
983 wxBitmap ret( rect.width, rect.height );
984 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
985
986 #ifndef __WXMICROWIN__
987 // TODO: copy alpha channel data if any
988
989 // copy bitmap data
990 MemoryHDC dcSrc,
991 dcDst;
992
993 {
994 SelectInHDC selectSrc(dcSrc, GetHbitmap()),
995 selectDst(dcDst, GetHbitmapOf(ret));
996
997 if ( !selectSrc || !selectDst )
998 {
999 wxLogLastError(_T("SelectObjct(hBitmap)"));
1000 }
1001
1002 if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
1003 dcSrc, rect.x, rect.y, SRCCOPY) )
1004 {
1005 wxLogLastError(_T("BitBlt"));
1006 }
1007 }
1008
1009 // copy mask if there is one
1010 if ( GetMask() )
1011 {
1012 HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);
1013
1014 SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()),
1015 selectDst(dcDst, hbmpMask);
1016
1017 if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
1018 dcSrc, rect.x, rect.y, SRCCOPY) )
1019 {
1020 wxLogLastError(_T("BitBlt"));
1021 }
1022
1023 wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
1024 ret.SetMask(mask);
1025 }
1026 #endif // !__WXMICROWIN__
1027
1028 return ret;
1029 }
1030
1031 // ----------------------------------------------------------------------------
1032 // wxBitmap accessors
1033 // ----------------------------------------------------------------------------
1034
1035 wxPalette* wxBitmap::GetPalette() const
1036 {
1037 return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette
1038 : (wxPalette *) NULL;
1039 }
1040
1041 wxMask *wxBitmap::GetMask() const
1042 {
1043 return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL;
1044 }
1045
1046 wxDC *wxBitmap::GetSelectedInto() const
1047 {
1048 return GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC *) NULL;
1049 }
1050
1051 #if WXWIN_COMPATIBILITY_2_4
1052
1053 int wxBitmap::GetQuality() const
1054 {
1055 return 0;
1056 }
1057
1058 #endif // WXWIN_COMPATIBILITY_2_4
1059
1060 bool wxBitmap::HasAlpha() const
1061 {
1062 return GetBitmapData() && GetBitmapData()->m_hasAlpha;
1063 }
1064
1065 // ----------------------------------------------------------------------------
1066 // wxBitmap setters
1067 // ----------------------------------------------------------------------------
1068
1069 void wxBitmap::SetSelectedInto(wxDC *dc)
1070 {
1071 if ( GetBitmapData() )
1072 GetBitmapData()->m_selectedInto = dc;
1073 }
1074
1075 #if wxUSE_PALETTE
1076
1077 void wxBitmap::SetPalette(const wxPalette& palette)
1078 {
1079 EnsureHasData();
1080
1081 GetBitmapData()->m_bitmapPalette = palette;
1082 }
1083
1084 #endif // wxUSE_PALETTE
1085
1086 void wxBitmap::SetMask(wxMask *mask)
1087 {
1088 EnsureHasData();
1089
1090 GetBitmapData()->SetMask(mask);
1091 }
1092
1093 #if WXWIN_COMPATIBILITY_2
1094
1095 void wxBitmap::SetOk(bool isOk)
1096 {
1097 EnsureHasData();
1098
1099 GetBitmapData()->m_ok = isOk;
1100 }
1101
1102 #endif // WXWIN_COMPATIBILITY_2
1103
1104 #if WXWIN_COMPATIBILITY_2_4
1105
1106 void wxBitmap::SetQuality(int WXUNUSED(quality))
1107 {
1108 }
1109
1110 #endif // WXWIN_COMPATIBILITY_2_4
1111
1112 // ----------------------------------------------------------------------------
1113 // TODO: to be replaced by something better
1114 // ----------------------------------------------------------------------------
1115
1116 // Creates a bitmap that matches the device context, from
1117 // an arbitray bitmap. At present, the original bitmap must have an
1118 // associated palette. TODO: use a default palette if no palette exists.
1119 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
1120 wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const
1121 {
1122 #ifdef __WXMICROWIN__
1123 return *this;
1124 #else
1125 wxMemoryDC memDC;
1126 wxBitmap tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth());
1127 HPALETTE hPal = (HPALETTE) NULL;
1128 LPBITMAPINFO lpDib;
1129 void *lpBits = (void*) NULL;
1130
1131 #if wxUSE_PALETTE
1132 if( GetPalette() && GetPalette()->Ok() )
1133 {
1134 tmpBitmap.SetPalette(*GetPalette());
1135 memDC.SelectObject(tmpBitmap);
1136 memDC.SetPalette(*GetPalette());
1137 hPal = (HPALETTE)GetPalette()->GetHPALETTE();
1138 }
1139 else
1140 {
1141 hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE);
1142 wxPalette palette;
1143 palette.SetHPALETTE( (WXHPALETTE)hPal );
1144 tmpBitmap.SetPalette( palette );
1145 memDC.SelectObject(tmpBitmap);
1146 memDC.SetPalette( palette );
1147 }
1148 #else // !wxUSE_PALETTE
1149 hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE);
1150 #endif // wxUSE_PALETTE/!wxUSE_PALETTE
1151
1152 // set the height negative because in a DIB the order of the lines is
1153 // reversed
1154 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal, &lpDib) )
1155 {
1156 return wxNullBitmap;
1157 }
1158
1159 lpBits = malloc(lpDib->bmiHeader.biSizeImage);
1160
1161 ::GetBitmapBits(GetHbitmap(), lpDib->bmiHeader.biSizeImage, lpBits);
1162
1163 ::SetDIBitsToDevice(GetHdcOf(memDC), 0, 0,
1164 GetWidth(), GetHeight(),
1165 0, 0, 0, GetHeight(),
1166 lpBits, lpDib, DIB_RGB_COLORS);
1167
1168 free(lpBits);
1169
1170 wxFreeDIB(lpDib);
1171
1172 return tmpBitmap;
1173 #endif
1174 }
1175
1176 // ----------------------------------------------------------------------------
1177 // wxMask
1178 // ----------------------------------------------------------------------------
1179
1180 wxMask::wxMask()
1181 {
1182 m_maskBitmap = 0;
1183 }
1184
1185 // Construct a mask from a bitmap and a colour indicating
1186 // the transparent area
1187 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
1188 {
1189 m_maskBitmap = 0;
1190 Create(bitmap, colour);
1191 }
1192
1193 // Construct a mask from a bitmap and a palette index indicating
1194 // the transparent area
1195 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
1196 {
1197 m_maskBitmap = 0;
1198 Create(bitmap, paletteIndex);
1199 }
1200
1201 // Construct a mask from a mono bitmap (copies the bitmap).
1202 wxMask::wxMask(const wxBitmap& bitmap)
1203 {
1204 m_maskBitmap = 0;
1205 Create(bitmap);
1206 }
1207
1208 wxMask::~wxMask()
1209 {
1210 if ( m_maskBitmap )
1211 ::DeleteObject((HBITMAP) m_maskBitmap);
1212 }
1213
1214 // Create a mask from a mono bitmap (copies the bitmap).
1215 bool wxMask::Create(const wxBitmap& bitmap)
1216 {
1217 #ifndef __WXMICROWIN__
1218 wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, FALSE,
1219 _T("can't create mask from invalid or not monochrome bitmap") );
1220
1221 if ( m_maskBitmap )
1222 {
1223 ::DeleteObject((HBITMAP) m_maskBitmap);
1224 m_maskBitmap = 0;
1225 }
1226
1227 m_maskBitmap = (WXHBITMAP) CreateBitmap(
1228 bitmap.GetWidth(),
1229 bitmap.GetHeight(),
1230 1, 1, 0
1231 );
1232 HDC srcDC = CreateCompatibleDC(0);
1233 SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
1234 HDC destDC = CreateCompatibleDC(0);
1235 SelectObject(destDC, (HBITMAP) m_maskBitmap);
1236 BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY);
1237 SelectObject(srcDC, 0);
1238 DeleteDC(srcDC);
1239 SelectObject(destDC, 0);
1240 DeleteDC(destDC);
1241 return TRUE;
1242 #else
1243 return FALSE;
1244 #endif
1245 }
1246
1247 // Create a mask from a bitmap and a palette index indicating
1248 // the transparent area
1249 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
1250 {
1251 if ( m_maskBitmap )
1252 {
1253 ::DeleteObject((HBITMAP) m_maskBitmap);
1254 m_maskBitmap = 0;
1255 }
1256
1257 #if wxUSE_PALETTE
1258 if (bitmap.Ok() && bitmap.GetPalette()->Ok())
1259 {
1260 unsigned char red, green, blue;
1261 if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
1262 {
1263 wxColour transparentColour(red, green, blue);
1264 return Create(bitmap, transparentColour);
1265 }
1266 }
1267 #endif // wxUSE_PALETTE
1268
1269 return FALSE;
1270 }
1271
1272 // Create a mask from a bitmap and a colour indicating
1273 // the transparent area
1274 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1275 {
1276 #ifndef __WXMICROWIN__
1277 wxCHECK_MSG( bitmap.Ok(), FALSE, _T("invalid bitmap in wxMask::Create") );
1278
1279 if ( m_maskBitmap )
1280 {
1281 ::DeleteObject((HBITMAP) m_maskBitmap);
1282 m_maskBitmap = 0;
1283 }
1284
1285 int width = bitmap.GetWidth(),
1286 height = bitmap.GetHeight();
1287
1288 // scan the bitmap for the transparent colour and set the corresponding
1289 // pixels in the mask to BLACK and the rest to WHITE
1290 COLORREF maskColour = wxColourToPalRGB(colour);
1291 m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0);
1292
1293 HDC srcDC = ::CreateCompatibleDC(NULL);
1294 HDC destDC = ::CreateCompatibleDC(NULL);
1295 if ( !srcDC || !destDC )
1296 {
1297 wxLogLastError(wxT("CreateCompatibleDC"));
1298 }
1299
1300 bool ok = TRUE;
1301
1302 // SelectObject() will fail
1303 wxASSERT_MSG( !bitmap.GetSelectedInto(),
1304 _T("bitmap can't be selected in another DC") );
1305
1306 HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap));
1307 if ( !hbmpSrcOld )
1308 {
1309 wxLogLastError(wxT("SelectObject"));
1310
1311 ok = FALSE;
1312 }
1313
1314 HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap);
1315 if ( !hbmpDstOld )
1316 {
1317 wxLogLastError(wxT("SelectObject"));
1318
1319 ok = FALSE;
1320 }
1321
1322 if ( ok )
1323 {
1324 // this will create a monochrome bitmap with 0 points for the pixels
1325 // which have the same value as the background colour and 1 for the
1326 // others
1327 ::SetBkColor(srcDC, maskColour);
1328 ::BitBlt(destDC, 0, 0, width, height, srcDC, 0, 0, NOTSRCCOPY);
1329 }
1330
1331 ::SelectObject(srcDC, hbmpSrcOld);
1332 ::DeleteDC(srcDC);
1333 ::SelectObject(destDC, hbmpDstOld);
1334 ::DeleteDC(destDC);
1335
1336 return ok;
1337 #else // __WXMICROWIN__
1338 return FALSE;
1339 #endif // __WXMICROWIN__/!__WXMICROWIN__
1340 }
1341
1342 // ----------------------------------------------------------------------------
1343 // wxBitmapHandler
1344 // ----------------------------------------------------------------------------
1345
1346 bool wxBitmapHandler::Create(wxGDIImage *image,
1347 void *data,
1348 long flags,
1349 int width, int height, int depth)
1350 {
1351 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1352
1353 return bitmap ? Create(bitmap, data, flags, width, height, depth) : FALSE;
1354 }
1355
1356 bool wxBitmapHandler::Load(wxGDIImage *image,
1357 const wxString& name,
1358 long flags,
1359 int width, int height)
1360 {
1361 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1362
1363 return bitmap ? LoadFile(bitmap, name, flags, width, height) : FALSE;
1364 }
1365
1366 bool wxBitmapHandler::Save(wxGDIImage *image,
1367 const wxString& name,
1368 int type)
1369 {
1370 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1371
1372 return bitmap ? SaveFile(bitmap, name, type) : FALSE;
1373 }
1374
1375 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap),
1376 void *WXUNUSED(data),
1377 long WXUNUSED(type),
1378 int WXUNUSED(width),
1379 int WXUNUSED(height),
1380 int WXUNUSED(depth))
1381 {
1382 return FALSE;
1383 }
1384
1385 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap),
1386 const wxString& WXUNUSED(name),
1387 long WXUNUSED(type),
1388 int WXUNUSED(desiredWidth),
1389 int WXUNUSED(desiredHeight))
1390 {
1391 return FALSE;
1392 }
1393
1394 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap),
1395 const wxString& WXUNUSED(name),
1396 int WXUNUSED(type),
1397 const wxPalette *WXUNUSED(palette))
1398 {
1399 return FALSE;
1400 }
1401
1402 // ----------------------------------------------------------------------------
1403 // DIB functions
1404 // ----------------------------------------------------------------------------
1405
1406 #ifndef __WXMICROWIN__
1407 bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel,
1408 HPALETTE hPal, LPBITMAPINFO* lpDIBHeader)
1409 {
1410 unsigned long i, headerSize;
1411 LPBITMAPINFO lpDIBheader = NULL;
1412 LPPALETTEENTRY lpPe = NULL;
1413
1414
1415 // Allocate space for a DIB header
1416 headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY)));
1417 lpDIBheader = (BITMAPINFO *) malloc(headerSize);
1418 lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER));
1419
1420 GetPaletteEntries(hPal, 0, 256, lpPe);
1421
1422 memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER));
1423
1424 // Fill in the static parts of the DIB header
1425 lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1426 lpDIBheader->bmiHeader.biWidth = xSize;
1427 lpDIBheader->bmiHeader.biHeight = ySize;
1428 lpDIBheader->bmiHeader.biPlanes = 1;
1429
1430 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
1431 lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel);
1432 lpDIBheader->bmiHeader.biCompression = BI_RGB;
1433 lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3;
1434 lpDIBheader->bmiHeader.biClrUsed = 256;
1435
1436
1437 // Initialize the DIB palette
1438 for (i = 0; i < 256; i++) {
1439 lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags;
1440 lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed;
1441 lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen;
1442 lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue;
1443 }
1444
1445 *lpDIBHeader = lpDIBheader;
1446
1447 return TRUE;
1448 }
1449
1450 void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
1451 {
1452 free(lpDIBHeader);
1453 }
1454 #endif
1455
1456 // ----------------------------------------------------------------------------
1457 // other helper functions
1458 // ----------------------------------------------------------------------------
1459
1460 extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h)
1461 {
1462 #ifndef __WXMICROWIN__
1463 wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") );
1464
1465 // get width/height from the bitmap if not given
1466 if ( !w || !h )
1467 {
1468 BITMAP bm;
1469 ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm);
1470 w = bm.bmWidth;
1471 h = bm.bmHeight;
1472 }
1473
1474 HDC hdcSrc = ::CreateCompatibleDC(NULL);
1475 HDC hdcDst = ::CreateCompatibleDC(NULL);
1476 if ( !hdcSrc || !hdcDst )
1477 {
1478 wxLogLastError(wxT("CreateCompatibleDC"));
1479 }
1480
1481 HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0);
1482 if ( !hbmpInvMask )
1483 {
1484 wxLogLastError(wxT("CreateBitmap"));
1485 }
1486
1487 ::SelectObject(hdcSrc, hbmpMask);
1488 ::SelectObject(hdcDst, hbmpInvMask);
1489 if ( !::BitBlt(hdcDst, 0, 0, w, h,
1490 hdcSrc, 0, 0,
1491 NOTSRCCOPY) )
1492 {
1493 wxLogLastError(wxT("BitBlt"));
1494 }
1495
1496 ::DeleteDC(hdcSrc);
1497 ::DeleteDC(hdcDst);
1498
1499 return hbmpInvMask;
1500 #else
1501 return 0;
1502 #endif
1503 }