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