1 ////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "bitmap.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
37 #include "wx/palette.h"
38 #include "wx/dcmemory.h"
39 #include "wx/bitmap.h"
43 #include "wx/msw/private.h"
46 #if !defined(__WXMICROWIN__)
47 #include "wx/msw/dib.h"
51 #include "wx/xpmdecod.h"
53 // missing from mingw32 header
55 #define CLR_INVALID ((COLORREF)-1)
56 #endif // no CLR_INVALID
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 class WXDLLEXPORT wxBitmapRefData
: public wxGDIImageRefData
66 virtual ~wxBitmapRefData() { Free(); }
70 // set the mask object to use as the mask, we take ownership of it
71 void SetMask(wxMask
*mask
)
77 // set the HBITMAP to use as the mask
78 void SetMask(HBITMAP hbmpMask
)
80 SetMask(new wxMask((WXHBITMAP
)hbmpMask
));
84 wxMask
*GetMask() const { return m_bitmapMask
; }
89 wxPalette m_bitmapPalette
;
90 #endif // wxUSE_PALETTE
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)
100 #if wxUSE_DIB_FOR_BITMAP
101 // file mapping handle for large DIB's
103 #endif // wxUSE_DIB_FOR_BITMAP
106 // optional mask for transparent drawing
107 wxMask
*m_bitmapMask
;
109 DECLARE_NO_COPY_CLASS(wxBitmapRefData
)
112 // ----------------------------------------------------------------------------
114 // ----------------------------------------------------------------------------
116 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
117 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
119 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
121 // ============================================================================
123 // ============================================================================
125 // ----------------------------------------------------------------------------
127 // ----------------------------------------------------------------------------
129 wxBitmapRefData::wxBitmapRefData()
131 m_selectedInto
= NULL
;
134 m_hBitmap
= (WXHBITMAP
) NULL
;
135 #if wxUSE_DIB_FOR_BITMAP
137 #endif // wxUSE_DIB_FOR_BITMAP
140 void wxBitmapRefData::Free()
142 wxASSERT_MSG( !m_selectedInto
,
143 wxT("deleting bitmap still selected into wxMemoryDC") );
147 if ( !::DeleteObject((HBITMAP
)m_hBitmap
) )
149 wxLogLastError(wxT("DeleteObject(hbitmap)"));
153 #if wxUSE_DIB_FOR_BITMAP
156 ::CloseHandle(m_hFileMap
);
160 #endif // wxUSE_DIB_FOR_BITMAP
166 // ----------------------------------------------------------------------------
168 // ----------------------------------------------------------------------------
170 // this function should be called from all wxBitmap ctors
171 void wxBitmap::Init()
173 // m_refData = NULL; done in the base class ctor
177 wxGDIImageRefData
*wxBitmap::CreateData() const
179 return new wxBitmapRefData
;
184 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage
& icon
)
186 #ifndef __WXMICROWIN__
187 // it may be either HICON or HCURSOR
188 HICON hicon
= (HICON
)icon
.GetHandle();
191 if ( !::GetIconInfo(hicon
, &iconInfo
) )
193 wxLogLastError(wxT("GetIconInfo"));
198 wxBitmapRefData
*refData
= new wxBitmapRefData
;
201 int w
= icon
.GetWidth(),
202 h
= icon
.GetHeight();
204 refData
->m_width
= w
;
205 refData
->m_height
= h
;
206 refData
->m_depth
= wxDisplayDepth();
208 refData
->m_hBitmap
= (WXHBITMAP
)iconInfo
.hbmColor
;
210 // the mask returned by GetIconInfo() is inversed compared to the usual
212 refData
->SetMask(wxInvertMask(iconInfo
.hbmMask
, w
, h
));
215 // delete the old one now as we don't need it any more
216 ::DeleteObject(iconInfo
.hbmMask
);
218 #if WXWIN_COMPATIBILITY_2
219 refData
->m_ok
= TRUE
;
220 #endif // WXWIN_COMPATIBILITY_2
230 bool wxBitmap::CopyFromCursor(const wxCursor
& cursor
)
238 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
242 return CopyFromIconOrCursor(cursor
);
246 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
253 // GetIconInfo() doesn't exist under Win16 and I don't know any other way
254 // to create a bitmap from icon there - but using this way we won't have
257 int width
= icon
.GetWidth(),
258 height
= icon
.GetHeight();
260 // copy the icon to the bitmap
262 HDC hdc
= ::CreateCompatibleDC(hdcScreen
);
263 HBITMAP hbitmap
= ::CreateCompatibleBitmap(hdcScreen
, width
, height
);
264 HBITMAP hbmpOld
= (HBITMAP
)::SelectObject(hdc
, hbitmap
);
266 ::DrawIcon(hdc
, 0, 0, GetHiconOf(icon
));
268 ::SelectObject(hdc
, hbmpOld
);
271 wxBitmapRefData
*refData
= new wxBitmapRefData
;
274 refData
->m_width
= width
;
275 refData
->m_height
= height
;
276 refData
->m_depth
= wxDisplayDepth();
278 refData
->m_hBitmap
= (WXHBITMAP
)hbitmap
;
280 #if WXWIN_COMPATIBILITY_2
281 refData
->m_ok
= TRUE
;
282 #endif // WXWIN_COMPATIBILITY_2
286 return CopyFromIconOrCursor(icon
);
287 #endif // Win16/Win32
290 wxBitmap::~wxBitmap()
294 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
298 #ifndef __WXMICROWIN__
299 wxBitmapRefData
*refData
= new wxBitmapRefData
;
302 refData
->m_width
= width
;
303 refData
->m_height
= height
;
304 refData
->m_depth
= depth
;
305 refData
->m_numColors
= 0;
306 refData
->m_selectedInto
= NULL
;
311 // we assume that it is in XBM format which is not quite the same as
312 // the format CreateBitmap() wants because the order of bytes in the
314 const size_t bytesPerLine
= (width
+ 7) / 8;
315 const size_t padding
= bytesPerLine
% 2;
316 const size_t len
= height
* ( padding
+ bytesPerLine
);
317 data
= (char *)malloc(len
);
318 const char *src
= bits
;
321 for ( int rows
= 0; rows
< height
; rows
++ )
323 for ( size_t cols
= 0; cols
< bytesPerLine
; cols
++ )
325 unsigned char val
= *src
++;
326 unsigned char reversed
= 0;
328 for ( int bits
= 0; bits
< 8; bits
++)
331 reversed
|= (val
& 0x01);
343 // bits should already be in Windows standard format
344 data
= (char *)bits
; // const_cast is harmless
347 HBITMAP hbmp
= ::CreateBitmap(width
, height
, 1, depth
, data
);
350 wxLogLastError(wxT("CreateBitmap"));
358 SetHBITMAP((WXHBITMAP
)hbmp
);
362 // Create from XPM data
363 bool wxBitmap::CreateFromXpm(const char **data
)
365 #if wxUSE_IMAGE && wxUSE_XPM
368 wxCHECK_MSG( data
!= NULL
, FALSE
, wxT("invalid bitmap data") )
370 wxXPMDecoder decoder
;
371 wxImage img
= decoder
.ReadData(data
);
372 wxCHECK_MSG( img
.Ok(), FALSE
, wxT("invalid bitmap data") )
374 *this = wxBitmap(img
);
381 wxBitmap::wxBitmap(int w
, int h
, int d
)
385 (void)Create(w
, h
, d
);
388 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
392 (void)Create(data
, type
, width
, height
, depth
);
395 wxBitmap::wxBitmap(const wxString
& filename
, wxBitmapType type
)
399 LoadFile(filename
, (int)type
);
402 bool wxBitmap::Create(int w
, int h
, int d
)
406 m_refData
= new wxBitmapRefData
;
408 #if wxUSE_DIB_FOR_BITMAP
409 if ( w
&& h
&& d
>= 16 )
411 if ( !CreateDIB(w
, h
, d
) )
415 #endif // wxUSE_DIB_FOR_BITMAP
417 GetBitmapData()->m_width
= w
;
418 GetBitmapData()->m_height
= h
;
419 GetBitmapData()->m_depth
= d
;
422 #ifndef __WXMICROWIN__
425 hbmp
= ::CreateBitmap(w
, h
, 1, d
, NULL
);
428 wxLogLastError(wxT("CreateBitmap"));
432 #endif // !__WXMICROWIN__
435 hbmp
= ::CreateCompatibleBitmap(dc
, w
, h
);
438 wxLogLastError(wxT("CreateCompatibleBitmap"));
441 GetBitmapData()->m_depth
= wxDisplayDepth();
444 SetHBITMAP((WXHBITMAP
)hbmp
);
446 #if WXWIN_COMPATIBILITY_2
447 GetBitmapData()->m_ok
= hbmp
!= 0;
448 #endif // WXWIN_COMPATIBILITY_2
454 #if wxUSE_DIB_FOR_BITMAP
456 void *wxBitmap::CreateDIB(int width
, int height
, int depth
)
459 const int infosize
= sizeof(BITMAPINFOHEADER
);
461 BITMAPINFO
*info
= (BITMAPINFO
*)malloc(infosize
);
464 memset(info
, 0, infosize
);
466 info
->bmiHeader
.biSize
= infosize
;
467 info
->bmiHeader
.biWidth
= width
;
468 info
->bmiHeader
.biHeight
= height
;
469 info
->bmiHeader
.biPlanes
= 1;
470 info
->bmiHeader
.biBitCount
= depth
;
471 info
->bmiHeader
.biCompression
= BI_RGB
;
472 info
->bmiHeader
.biSizeImage
=
473 (((width
* (depth
/8)) + sizeof(DWORD
) - 1) /
474 sizeof(DWORD
) * sizeof(DWORD
)) * height
;
475 info
->bmiHeader
.biXPelsPerMeter
= 0;
476 info
->bmiHeader
.biYPelsPerMeter
= 0;
477 info
->bmiHeader
.biClrUsed
= 0;
478 info
->bmiHeader
.biClrImportant
= 0;
479 GetBitmapData()->m_hFileMap
= ::CreateFileMapping
481 INVALID_HANDLE_VALUE
,
483 PAGE_READWRITE
| SEC_COMMIT
,
485 info
->bmiHeader
.biSizeImage
,
489 // No need to report an error here. If it fails, we just won't use a
490 // file mapping and CreateDIBSection will just allocate memory for us.
491 GetBitmapData()->m_handle
=
492 (WXHANDLE
)::CreateDIBSection
498 GetBitmapData()->m_hFileMap
,
502 if ( !GetBitmapData()->m_handle
)
503 wxLogLastError(wxT("CreateDIBSection"));
513 wxFAIL_MSG( wxT("could not allocate memory for DIB header") );
521 #endif // wxUSE_DIB_FOR_BITMAP
523 // ----------------------------------------------------------------------------
524 // wxImage to/from conversions
525 // ----------------------------------------------------------------------------
529 bool wxBitmap::CreateFromImage( const wxImage
& image
, int depth
)
531 #ifdef __WXMICROWIN__
533 // Set this to 1 to experiment with mask code,
534 // which currently doesn't work
537 m_refData
= new wxBitmapRefData();
539 // Initial attempt at a simple-minded implementation.
540 // The bitmap will always be created at the screen depth,
541 // so the 'depth' argument is ignored.
543 HDC hScreenDC
= ::GetDC(NULL
);
544 int screenDepth
= ::GetDeviceCaps(hScreenDC
, BITSPIXEL
);
546 HBITMAP hBitmap
= ::CreateCompatibleBitmap(hScreenDC
, image
.GetWidth(), image
.GetHeight());
547 HBITMAP hMaskBitmap
= NULL
;
548 HBITMAP hOldMaskBitmap
= NULL
;
550 unsigned char maskR
= 0;
551 unsigned char maskG
= 0;
552 unsigned char maskB
= 0;
554 // printf("Created bitmap %d\n", (int) hBitmap);
557 ::ReleaseDC(NULL
, hScreenDC
);
560 HDC hMemDC
= ::CreateCompatibleDC(hScreenDC
);
562 HBITMAP hOldBitmap
= ::SelectObject(hMemDC
, hBitmap
);
563 ::ReleaseDC(NULL
, hScreenDC
);
565 // created an mono-bitmap for the possible mask
566 bool hasMask
= image
.HasMask();
571 // FIXME: we should be able to pass bpp = 1, but
572 // GdBlit can't handle a different depth
574 hMaskBitmap
= ::CreateBitmap( (WORD
)image
.GetWidth(), (WORD
)image
.GetHeight(), 1, 1, NULL
);
576 hMaskBitmap
= ::CreateCompatibleBitmap( hMemDC
, (WORD
)image
.GetWidth(), (WORD
)image
.GetHeight());
578 maskR
= image
.GetMaskRed();
579 maskG
= image
.GetMaskGreen();
580 maskB
= image
.GetMaskBlue();
588 hScreenDC
= ::GetDC(NULL
);
589 hMaskDC
= ::CreateCompatibleDC(hScreenDC
);
590 ::ReleaseDC(NULL
, hScreenDC
);
592 hOldMaskBitmap
= ::SelectObject( hMaskDC
, hMaskBitmap
);
600 for (i
= 0; i
< image
.GetWidth(); i
++)
602 for (j
= 0; j
< image
.GetHeight(); j
++)
604 unsigned char red
= image
.GetRed(i
, j
);
605 unsigned char green
= image
.GetGreen(i
, j
);
606 unsigned char blue
= image
.GetBlue(i
, j
);
608 ::SetPixel(hMemDC
, i
, j
, PALETTERGB(red
, green
, blue
));
612 // scan the bitmap for the transparent colour and set the corresponding
613 // pixels in the mask to BLACK and the rest to WHITE
614 if (maskR
== red
&& maskG
== green
&& maskB
== blue
)
615 ::SetPixel(hMaskDC
, i
, j
, PALETTERGB(0, 0, 0));
617 ::SetPixel(hMaskDC
, i
, j
, PALETTERGB(255, 255, 255));
622 ::SelectObject(hMemDC
, hOldBitmap
);
626 ::SelectObject(hMaskDC
, hOldMaskBitmap
);
629 ((wxBitmapRefData
*)m_refData
)->SetMask(hMaskBitmap
);
632 SetWidth(image
.GetWidth());
633 SetHeight(image
.GetHeight());
634 SetDepth(screenDepth
);
635 SetHBITMAP( (WXHBITMAP
) hBitmap
);
638 // Copy the palette from the source image
639 SetPalette(image
.GetPalette());
640 #endif // wxUSE_PALETTE
642 #if WXWIN_COMPATIBILITY_2
643 // check the wxBitmap object
644 GetBitmapData()->SetOk();
645 #endif // WXWIN_COMPATIBILITY_2
649 #else // !__WXMICROWIN__
650 wxCHECK_MSG( image
.Ok(), FALSE
, wxT("invalid image") )
652 m_refData
= new wxBitmapRefData();
654 #if wxUSE_DIB_FOR_BITMAP
655 int h
= image
.GetHeight();
656 int w
= image
.GetWidth();
657 unsigned char *dibBits
= (unsigned char*)CreateDIB(w
, h
, 24);
661 // DIBs are stored in bottom to top order so we need to copy bits line by
662 // line and starting from the end
663 const int srcBytesPerLine
= w
* 3;
664 const int dstBytesPerLine
= (srcBytesPerLine
+ sizeof(DWORD
) - 1) /
665 sizeof(DWORD
) * sizeof(DWORD
);
666 const unsigned char *src
= image
.GetData() + ((h
- 1) * srcBytesPerLine
);
667 for ( int i
= 0; i
< h
; i
++ )
671 const unsigned char *rgbBits
= src
;
674 // also, the order of RGB is inversed for DIBs
675 *dibBits
++ = rgbBits
[2];
676 *dibBits
++ = rgbBits
[1];
677 *dibBits
++ = rgbBits
[0];
682 // pass to the next line
683 src
-= srcBytesPerLine
;
684 dibBits
+= dstBytesPerLine
- srcBytesPerLine
;
687 if ( image
.HasMask() )
689 SetMask(new wxMask(*this, wxColour(image
.GetMaskRed(),
690 image
.GetMaskGreen(),
691 image
.GetMaskBlue())));
693 #else // wxUSE_DIB_FOR_BITMAP
694 // sizeLimit is the MS upper limit for the DIB size
696 int sizeLimit
= 1024*768*3;
698 int sizeLimit
= 0x7fff;
701 // width and height of the device-dependent bitmap
702 int width
= image
.GetWidth();
703 int bmpHeight
= image
.GetHeight();
705 // calc the number of bytes per scanline and padding
706 int bytePerLine
= width
*3;
707 int sizeDWORD
= sizeof( DWORD
);
708 int lineBoundary
= bytePerLine
% sizeDWORD
;
710 if( lineBoundary
> 0 )
712 padding
= sizeDWORD
- lineBoundary
;
713 bytePerLine
+= padding
;
715 // calc the number of DIBs and heights of DIBs
718 int height
= sizeLimit
/bytePerLine
;
719 if( height
>= bmpHeight
)
723 numDIB
= bmpHeight
/ height
;
724 hRemain
= bmpHeight
% height
;
725 if( hRemain
>0 ) numDIB
++;
728 // set bitmap parameters
729 wxCHECK_MSG( image
.Ok(), FALSE
, wxT("invalid image") );
731 SetHeight( bmpHeight
);
732 if (depth
== -1) depth
= wxDisplayDepth();
736 // Copy the palette from the source image
737 SetPalette(image
.GetPalette());
738 #endif // wxUSE_PALETTE
740 // create a DIB header
741 int headersize
= sizeof(BITMAPINFOHEADER
);
742 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
743 wxCHECK_MSG( lpDIBh
, FALSE
, wxT("could not allocate memory for DIB header") );
744 // Fill in the DIB header
745 lpDIBh
->bmiHeader
.biSize
= headersize
;
746 lpDIBh
->bmiHeader
.biWidth
= (DWORD
)width
;
747 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
748 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
749 // the general formula for biSizeImage:
750 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
751 lpDIBh
->bmiHeader
.biPlanes
= 1;
752 lpDIBh
->bmiHeader
.biBitCount
= 24;
753 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
754 lpDIBh
->bmiHeader
.biClrUsed
= 0;
755 // These seem not really needed for our purpose here.
756 lpDIBh
->bmiHeader
.biClrImportant
= 0;
757 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
758 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
759 // memory for DIB data
760 unsigned char *lpBits
;
761 lpBits
= (unsigned char *)malloc( lpDIBh
->bmiHeader
.biSizeImage
);
764 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
769 // create and set the device-dependent bitmap
770 HDC hdc
= ::GetDC(NULL
);
771 HDC memdc
= ::CreateCompatibleDC( hdc
);
773 hbitmap
= ::CreateCompatibleBitmap( hdc
, width
, bmpHeight
);
774 ::SelectObject( memdc
, hbitmap
);
777 HPALETTE hOldPalette
= 0;
778 if (image
.GetPalette().Ok())
780 hOldPalette
= ::SelectPalette(memdc
, (HPALETTE
) image
.GetPalette().GetHPALETTE(), FALSE
);
781 ::RealizePalette(memdc
);
783 #endif // wxUSE_PALETTE
785 // copy image data into DIB data and then into DDB (in a loop)
786 unsigned char *data
= image
.GetData();
789 unsigned char *ptdata
= data
;
790 unsigned char *ptbits
;
792 for( n
=0; n
<numDIB
; n
++ )
794 if( numDIB
> 1 && n
== numDIB
-1 && hRemain
> 0 )
796 // redefine height and size of the (possibly) last smaller DIB
797 // memory is not reallocated
799 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
800 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
804 for( j
=0; j
<height
; j
++ )
806 for( i
=0; i
<width
; i
++ )
808 *(ptbits
++) = *(ptdata
+2);
809 *(ptbits
++) = *(ptdata
+1);
810 *(ptbits
++) = *(ptdata
);
813 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = 0;
815 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
816 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
818 // if numDIB = 1, lines below can also be used
819 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
820 // The above line is equivalent to the following two lines.
821 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
822 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
823 // or the following lines
824 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
825 // HDC memdc = ::CreateCompatibleDC( hdc );
826 // ::SelectObject( memdc, hbitmap);
827 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
828 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
829 // ::SelectObject( memdc, 0 );
830 // ::DeleteDC( memdc );
832 SetHBITMAP( (WXHBITMAP
) hbitmap
);
836 SelectPalette(memdc
, hOldPalette
, FALSE
);
837 #endif // wxUSE_PALETTE
839 // similarly, created an mono-bitmap for the possible mask
840 if( image
.HasMask() )
842 hbitmap
= ::CreateBitmap( (WORD
)width
, (WORD
)bmpHeight
, 1, 1, NULL
);
843 HGDIOBJ hbmpOld
= ::SelectObject( memdc
, hbitmap
);
844 if( numDIB
== 1 ) height
= bmpHeight
;
845 else height
= sizeLimit
/bytePerLine
;
846 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
847 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
849 unsigned char r
= image
.GetMaskRed();
850 unsigned char g
= image
.GetMaskGreen();
851 unsigned char b
= image
.GetMaskBlue();
852 unsigned char zero
= 0, one
= 255;
854 for( n
=0; n
<numDIB
; n
++ )
856 if( numDIB
> 1 && n
== numDIB
- 1 && hRemain
> 0 )
858 // redefine height and size of the (possibly) last smaller DIB
859 // memory is not reallocated
861 lpDIBh
->bmiHeader
.biHeight
= (DWORD
)(-height
);
862 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
*height
;
865 for( int j
=0; j
<height
; j
++ )
867 for(i
=0; i
<width
; i
++ )
869 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
870 unsigned char cr
= (*(ptdata
++)) ;
871 unsigned char cg
= (*(ptdata
++)) ;
872 unsigned char cb
= (*(ptdata
++)) ;
874 if( ( cr
!=r
) || (cg
!=g
) || (cb
!=b
) )
887 for( i
=0; i
< padding
; i
++ ) *(ptbits
++) = zero
;
889 ::StretchDIBits( memdc
, 0, origin
, width
, height
,\
890 0, 0, width
, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
, SRCCOPY
);
893 // create a wxMask object
894 wxMask
*mask
= new wxMask();
895 mask
->SetMaskBitmap( (WXHBITMAP
) hbitmap
);
897 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
898 /* The following can also be used but is slow to run
899 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
900 wxMask *mask = new wxMask( *this, colour );
904 ::SelectObject( memdc
, hbmpOld
);
907 // free allocated resources
909 ::ReleaseDC(NULL
, hdc
);
912 #endif // wxUSE_DIB_FOR_BITMAP
914 #if WXWIN_COMPATIBILITY_2
915 // check the wxBitmap object
916 GetBitmapData()->SetOk();
917 #endif // WXWIN_COMPATIBILITY_2
920 #endif // __WXMICROWIN__/!__WXMICROWIN__
923 wxImage
wxBitmap::ConvertToImage() const
925 #ifdef __WXMICROWIN__
926 // Initial attempt at a simple-minded implementation.
927 // The bitmap will always be created at the screen depth,
928 // so the 'depth' argument is ignored.
929 // TODO: transparency (create a mask image)
933 wxFAIL_MSG( wxT("bitmap is invalid") );
939 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
941 // create an wxImage object
942 int width
= GetWidth();
943 int height
= GetHeight();
944 image
.Create( width
, height
);
945 unsigned char *data
= image
.GetData();
948 wxFAIL_MSG( wxT("could not allocate data for image") );
952 HDC hScreenDC
= ::GetDC(NULL
);
954 HDC hMemDC
= ::CreateCompatibleDC(hScreenDC
);
955 ::ReleaseDC(NULL
, hScreenDC
);
957 HBITMAP hBitmap
= (HBITMAP
) GetHBITMAP();
959 HBITMAP hOldBitmap
= ::SelectObject(hMemDC
, hBitmap
);
962 for (i
= 0; i
< GetWidth(); i
++)
964 for (j
= 0; j
< GetHeight(); j
++)
966 COLORREF color
= ::GetPixel(hMemDC
, i
, j
);
967 unsigned char red
= GetRValue(color
);
968 unsigned char green
= GetGValue(color
);
969 unsigned char blue
= GetBValue(color
);
971 image
.SetRGB(i
, j
, red
, green
, blue
);
975 ::SelectObject(hMemDC
, hOldBitmap
);
979 // Copy the palette from the source image
981 image
.SetPalette(* GetPalette());
982 #endif // wxUSE_PALETTE
986 #else // !__WXMICROWIN__
989 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
991 // create an wxImage object
992 int width
= GetWidth();
993 int height
= GetHeight();
994 image
.Create( width
, height
);
995 unsigned char *data
= image
.GetData();
998 wxFAIL_MSG( wxT("could not allocate data for image") );
1002 // calc the number of bytes per scanline and padding in the DIB
1003 int bytePerLine
= width
*3;
1004 int sizeDWORD
= sizeof( DWORD
);
1005 int lineBoundary
= bytePerLine
% sizeDWORD
;
1007 if( lineBoundary
> 0 )
1009 padding
= sizeDWORD
- lineBoundary
;
1010 bytePerLine
+= padding
;
1013 // create a DIB header
1014 int headersize
= sizeof(BITMAPINFOHEADER
);
1015 BITMAPINFO
*lpDIBh
= (BITMAPINFO
*) malloc( headersize
);
1018 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
1022 // Fill in the DIB header
1023 lpDIBh
->bmiHeader
.biSize
= headersize
;
1024 lpDIBh
->bmiHeader
.biWidth
= width
;
1025 lpDIBh
->bmiHeader
.biHeight
= -height
;
1026 lpDIBh
->bmiHeader
.biSizeImage
= bytePerLine
* height
;
1027 lpDIBh
->bmiHeader
.biPlanes
= 1;
1028 lpDIBh
->bmiHeader
.biBitCount
= 24;
1029 lpDIBh
->bmiHeader
.biCompression
= BI_RGB
;
1030 lpDIBh
->bmiHeader
.biClrUsed
= 0;
1031 // These seem not really needed for our purpose here.
1032 lpDIBh
->bmiHeader
.biClrImportant
= 0;
1033 lpDIBh
->bmiHeader
.biXPelsPerMeter
= 0;
1034 lpDIBh
->bmiHeader
.biYPelsPerMeter
= 0;
1035 // memory for DIB data
1036 unsigned char *lpBits
;
1037 lpBits
= (unsigned char *) malloc( lpDIBh
->bmiHeader
.biSizeImage
);
1040 wxFAIL_MSG( wxT("could not allocate data for DIB") );
1046 // copy data from the device-dependent bitmap to the DIB
1047 HDC hdc
= ::GetDC(NULL
);
1049 hbitmap
= (HBITMAP
) GetHBITMAP();
1050 ::GetDIBits( hdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1052 // copy DIB data into the wxImage object
1054 unsigned char *ptdata
= data
;
1055 unsigned char *ptbits
= lpBits
;
1056 for( i
=0; i
<height
; i
++ )
1058 for( j
=0; j
<width
; j
++ )
1060 *(ptdata
++) = *(ptbits
+2);
1061 *(ptdata
++) = *(ptbits
+1);
1062 *(ptdata
++) = *(ptbits
);
1068 // similarly, set data according to the possible mask bitmap
1069 if( GetMask() && GetMask()->GetMaskBitmap() )
1071 hbitmap
= (HBITMAP
) GetMask()->GetMaskBitmap();
1072 // memory DC created, color set, data copied, and memory DC deleted
1073 HDC memdc
= ::CreateCompatibleDC( hdc
);
1074 ::SetTextColor( memdc
, RGB( 0, 0, 0 ) );
1075 ::SetBkColor( memdc
, RGB( 255, 255, 255 ) );
1076 ::GetDIBits( memdc
, hbitmap
, 0, height
, lpBits
, lpDIBh
, DIB_RGB_COLORS
);
1077 ::DeleteDC( memdc
);
1078 // background color set to RGB(16,16,16) in consistent with wxGTK
1079 unsigned char r
=16, g
=16, b
=16;
1082 for( i
=0; i
<height
; i
++ )
1084 for( j
=0; j
<width
; j
++ )
1098 image
.SetMaskColour( r
, g
, b
);
1099 image
.SetMask( TRUE
);
1103 image
.SetMask( FALSE
);
1105 // free allocated resources
1106 ::ReleaseDC(NULL
, hdc
);
1111 #endif // __WXMICROWIN__/!__WXMICROWIN__
1114 #endif // wxUSE_IMAGE
1116 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
1120 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
1124 m_refData
= new wxBitmapRefData
;
1126 return handler
->LoadFile(this, filename
, type
, -1, -1);
1132 if ( image
.LoadFile( filename
, type
) && image
.Ok() )
1134 *this = wxBitmap(image
);
1139 #endif // wxUSE_IMAGE
1144 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
1148 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
1152 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type
);
1157 m_refData
= new wxBitmapRefData
;
1159 return handler
->Create(this, data
, type
, width
, height
, depth
);
1162 bool wxBitmap::SaveFile(const wxString
& filename
,
1164 const wxPalette
*palette
)
1166 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
1170 return handler
->SaveFile(this, filename
, type
, palette
);
1175 // FIXME what about palette? shouldn't we use it?
1176 wxImage image
= ConvertToImage();
1179 return image
.SaveFile(filename
, type
);
1182 #endif // wxUSE_IMAGE
1187 // ----------------------------------------------------------------------------
1188 // sub bitmap extraction
1189 // ----------------------------------------------------------------------------
1191 wxBitmap
wxBitmap::GetSubBitmap( const wxRect
& rect
) const
1193 wxCHECK_MSG( Ok() &&
1194 (rect
.x
>= 0) && (rect
.y
>= 0) &&
1195 (rect
.x
+rect
.width
<= GetWidth()) &&
1196 (rect
.y
+rect
.height
<= GetHeight()),
1197 wxNullBitmap
, wxT("Invalid bitmap or bitmap region") );
1199 wxBitmap
ret( rect
.width
, rect
.height
, GetDepth() );
1200 wxASSERT_MSG( ret
.Ok(), wxT("GetSubBitmap error") );
1202 #ifndef __WXMICROWIN__
1204 MemoryHDC dcSrc
, dcDst
;
1207 SelectInHDC
selectSrc(dcSrc
, GetHbitmap()),
1208 selectDst(dcDst
, GetHbitmapOf(ret
));
1210 if ( !::BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
,
1211 dcSrc
, rect
.x
, rect
.y
, SRCCOPY
) )
1213 wxLogLastError(_T("BitBlt"));
1217 // copy mask if there is one
1220 HBITMAP hbmpMask
= ::CreateBitmap(rect
.width
, rect
.height
, 1, 1, 0);
1222 SelectInHDC
selectSrc(dcSrc
, (HBITMAP
) GetMask()->GetMaskBitmap()),
1223 selectDst(dcDst
, hbmpMask
);
1225 if ( !::BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
,
1226 dcSrc
, rect
.x
, rect
.y
, SRCCOPY
) )
1228 wxLogLastError(_T("BitBlt"));
1231 wxMask
*mask
= new wxMask((WXHBITMAP
) hbmpMask
);
1234 #endif // !__WXMICROWIN__
1239 // ----------------------------------------------------------------------------
1240 // wxBitmap accessors
1241 // ----------------------------------------------------------------------------
1243 wxPalette
* wxBitmap::GetPalette() const
1245 return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette
1246 : (wxPalette
*) NULL
;
1249 wxMask
*wxBitmap::GetMask() const
1251 return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask
*) NULL
;
1254 wxDC
*wxBitmap::GetSelectedInto() const
1256 return GetBitmapData() ? GetBitmapData()->m_selectedInto
: (wxDC
*) NULL
;
1259 #if wxUSE_DIB_FOR_BITMAP
1261 bool wxBitmap::IsDIB() const
1263 return GetBitmapData() && GetBitmapData()->m_hFileMap
!= NULL
;
1266 #endif // wxUSE_DIB_FOR_BITMAP
1268 #if WXWIN_COMPATIBILITY_2_4
1270 int wxBitmap::GetQuality() const
1275 #endif // WXWIN_COMPATIBILITY_2_4
1277 // ----------------------------------------------------------------------------
1279 // ----------------------------------------------------------------------------
1281 void wxBitmap::SetSelectedInto(wxDC
*dc
)
1283 if ( GetBitmapData() )
1284 GetBitmapData()->m_selectedInto
= dc
;
1289 void wxBitmap::SetPalette(const wxPalette
& palette
)
1293 GetBitmapData()->m_bitmapPalette
= palette
;
1296 #endif // wxUSE_PALETTE
1298 void wxBitmap::SetMask(wxMask
*mask
)
1302 GetBitmapData()->SetMask(mask
);
1305 #if WXWIN_COMPATIBILITY_2
1307 void wxBitmap::SetOk(bool isOk
)
1311 GetBitmapData()->m_ok
= isOk
;
1314 #endif // WXWIN_COMPATIBILITY_2
1316 #if WXWIN_COMPATIBILITY_2_4
1318 void wxBitmap::SetQuality(int WXUNUSED(quality
))
1322 #endif // WXWIN_COMPATIBILITY_2_4
1324 // ----------------------------------------------------------------------------
1325 // TODO: to be replaced by something better
1326 // ----------------------------------------------------------------------------
1328 // Creates a bitmap that matches the device context, from
1329 // an arbitray bitmap. At present, the original bitmap must have an
1330 // associated palette. TODO: use a default palette if no palette exists.
1331 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
1332 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
1334 #ifdef __WXMICROWIN__
1338 wxBitmap
tmpBitmap(GetWidth(), GetHeight(), dc
.GetDepth());
1339 HPALETTE hPal
= (HPALETTE
) NULL
;
1341 void *lpBits
= (void*) NULL
;
1344 if( GetPalette() && GetPalette()->Ok() )
1346 tmpBitmap
.SetPalette(*GetPalette());
1347 memDC
.SelectObject(tmpBitmap
);
1348 memDC
.SetPalette(*GetPalette());
1349 hPal
= (HPALETTE
)GetPalette()->GetHPALETTE();
1353 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
1355 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
1356 tmpBitmap
.SetPalette( palette
);
1357 memDC
.SelectObject(tmpBitmap
);
1358 memDC
.SetPalette( palette
);
1360 #else // !wxUSE_PALETTE
1361 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
1362 #endif // wxUSE_PALETTE/!wxUSE_PALETTE
1364 // set the height negative because in a DIB the order of the lines is
1366 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal
, &lpDib
) )
1368 return wxNullBitmap
;
1371 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
1373 ::GetBitmapBits(GetHbitmap(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
1375 ::SetDIBitsToDevice(GetHdcOf(memDC
), 0, 0,
1376 GetWidth(), GetHeight(),
1377 0, 0, 0, GetHeight(),
1378 lpBits
, lpDib
, DIB_RGB_COLORS
);
1388 // ----------------------------------------------------------------------------
1390 // ----------------------------------------------------------------------------
1397 // Construct a mask from a bitmap and a colour indicating
1398 // the transparent area
1399 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
1402 Create(bitmap
, colour
);
1405 // Construct a mask from a bitmap and a palette index indicating
1406 // the transparent area
1407 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
1410 Create(bitmap
, paletteIndex
);
1413 // Construct a mask from a mono bitmap (copies the bitmap).
1414 wxMask::wxMask(const wxBitmap
& bitmap
)
1423 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1426 // Create a mask from a mono bitmap (copies the bitmap).
1427 bool wxMask::Create(const wxBitmap
& bitmap
)
1429 #ifndef __WXMICROWIN__
1430 wxCHECK_MSG( bitmap
.Ok() && bitmap
.GetDepth() == 1, FALSE
,
1431 _T("can't create mask from invalid or not monochrome bitmap") );
1435 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1439 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
1444 HDC srcDC
= CreateCompatibleDC(0);
1445 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
1446 HDC destDC
= CreateCompatibleDC(0);
1447 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
1448 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
1449 SelectObject(srcDC
, 0);
1451 SelectObject(destDC
, 0);
1459 // Create a mask from a bitmap and a palette index indicating
1460 // the transparent area
1461 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
1465 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1470 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
1472 unsigned char red
, green
, blue
;
1473 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
1475 wxColour
transparentColour(red
, green
, blue
);
1476 return Create(bitmap
, transparentColour
);
1479 #endif // wxUSE_PALETTE
1484 // Create a mask from a bitmap and a colour indicating
1485 // the transparent area
1486 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
1488 #ifndef __WXMICROWIN__
1489 wxCHECK_MSG( bitmap
.Ok(), FALSE
, _T("invalid bitmap in wxMask::Create") );
1493 ::DeleteObject((HBITMAP
) m_maskBitmap
);
1497 int width
= bitmap
.GetWidth(),
1498 height
= bitmap
.GetHeight();
1500 // scan the bitmap for the transparent colour and set the corresponding
1501 // pixels in the mask to BLACK and the rest to WHITE
1502 COLORREF maskColour
= wxColourToPalRGB(colour
);
1503 m_maskBitmap
= (WXHBITMAP
)::CreateBitmap(width
, height
, 1, 1, 0);
1505 HDC srcDC
= ::CreateCompatibleDC(NULL
);
1506 HDC destDC
= ::CreateCompatibleDC(NULL
);
1507 if ( !srcDC
|| !destDC
)
1509 wxLogLastError(wxT("CreateCompatibleDC"));
1514 // SelectObject() will fail
1515 wxASSERT_MSG( !bitmap
.GetSelectedInto(),
1516 _T("bitmap can't be selected in another DC") );
1518 HGDIOBJ hbmpSrcOld
= ::SelectObject(srcDC
, GetHbitmapOf(bitmap
));
1521 wxLogLastError(wxT("SelectObject"));
1526 HGDIOBJ hbmpDstOld
= ::SelectObject(destDC
, (HBITMAP
)m_maskBitmap
);
1529 wxLogLastError(wxT("SelectObject"));
1536 // this will create a monochrome bitmap with 0 points for the pixels
1537 // which have the same value as the background colour and 1 for the
1539 ::SetBkColor(srcDC
, maskColour
);
1540 ::BitBlt(destDC
, 0, 0, width
, height
, srcDC
, 0, 0, NOTSRCCOPY
);
1543 ::SelectObject(srcDC
, hbmpSrcOld
);
1545 ::SelectObject(destDC
, hbmpDstOld
);
1549 #else // __WXMICROWIN__
1551 #endif // __WXMICROWIN__/!__WXMICROWIN__
1554 // ----------------------------------------------------------------------------
1556 // ----------------------------------------------------------------------------
1558 bool wxBitmapHandler::Create(wxGDIImage
*image
,
1561 int width
, int height
, int depth
)
1563 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
1565 return bitmap
? Create(bitmap
, data
, flags
, width
, height
, depth
) : FALSE
;
1568 bool wxBitmapHandler::Load(wxGDIImage
*image
,
1569 const wxString
& name
,
1571 int width
, int height
)
1573 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
1575 return bitmap
? LoadFile(bitmap
, name
, flags
, width
, height
) : FALSE
;
1578 bool wxBitmapHandler::Save(wxGDIImage
*image
,
1579 const wxString
& name
,
1582 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
1584 return bitmap
? SaveFile(bitmap
, name
, type
) : FALSE
;
1587 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
),
1588 void *WXUNUSED(data
),
1589 long WXUNUSED(type
),
1590 int WXUNUSED(width
),
1591 int WXUNUSED(height
),
1592 int WXUNUSED(depth
))
1597 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
),
1598 const wxString
& WXUNUSED(name
),
1599 long WXUNUSED(type
),
1600 int WXUNUSED(desiredWidth
),
1601 int WXUNUSED(desiredHeight
))
1606 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
),
1607 const wxString
& WXUNUSED(name
),
1609 const wxPalette
*WXUNUSED(palette
))
1614 // ----------------------------------------------------------------------------
1616 // ----------------------------------------------------------------------------
1618 #ifndef __WXMICROWIN__
1619 bool wxCreateDIB(long xSize
, long ySize
, long bitsPerPixel
,
1620 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
1622 unsigned long i
, headerSize
;
1623 LPBITMAPINFO lpDIBheader
= NULL
;
1624 LPPALETTEENTRY lpPe
= NULL
;
1627 // Allocate space for a DIB header
1628 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
1629 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
1630 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
1632 GetPaletteEntries(hPal
, 0, 256, lpPe
);
1634 memset(lpDIBheader
, 0x00, sizeof(BITMAPINFOHEADER
));
1636 // Fill in the static parts of the DIB header
1637 lpDIBheader
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1638 lpDIBheader
->bmiHeader
.biWidth
= xSize
;
1639 lpDIBheader
->bmiHeader
.biHeight
= ySize
;
1640 lpDIBheader
->bmiHeader
.biPlanes
= 1;
1642 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
1643 lpDIBheader
->bmiHeader
.biBitCount
= (WORD
)(bitsPerPixel
);
1644 lpDIBheader
->bmiHeader
.biCompression
= BI_RGB
;
1645 lpDIBheader
->bmiHeader
.biSizeImage
= xSize
* abs(ySize
) * bitsPerPixel
>> 3;
1646 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
1649 // Initialize the DIB palette
1650 for (i
= 0; i
< 256; i
++) {
1651 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
1652 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
1653 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
1654 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
1657 *lpDIBHeader
= lpDIBheader
;
1662 void wxFreeDIB(LPBITMAPINFO lpDIBHeader
)
1668 // ----------------------------------------------------------------------------
1669 // other helper functions
1670 // ----------------------------------------------------------------------------
1672 extern HBITMAP
wxInvertMask(HBITMAP hbmpMask
, int w
, int h
)
1674 #ifndef __WXMICROWIN__
1675 wxCHECK_MSG( hbmpMask
, 0, _T("invalid bitmap in wxInvertMask") );
1677 // get width/height from the bitmap if not given
1681 ::GetObject(hbmpMask
, sizeof(BITMAP
), (LPVOID
)&bm
);
1686 HDC hdcSrc
= ::CreateCompatibleDC(NULL
);
1687 HDC hdcDst
= ::CreateCompatibleDC(NULL
);
1688 if ( !hdcSrc
|| !hdcDst
)
1690 wxLogLastError(wxT("CreateCompatibleDC"));
1693 HBITMAP hbmpInvMask
= ::CreateBitmap(w
, h
, 1, 1, 0);
1696 wxLogLastError(wxT("CreateBitmap"));
1699 ::SelectObject(hdcSrc
, hbmpMask
);
1700 ::SelectObject(hdcDst
, hbmpInvMask
);
1701 if ( !::BitBlt(hdcDst
, 0, 0, w
, h
,
1705 wxLogLastError(wxT("BitBlt"));