]> git.saurik.com Git - wxWidgets.git/blob - src/os2/bitmap.cpp
fix for wxFrame's last focus bug (finally?)
[wxWidgets.git] / src / os2 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: David Webster
5 // Modified by:
6 // Created: 08/08/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "bitmap.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifndef WX_PRECOMP
20 #include <stdio.h>
21
22 #include "wx/list.h"
23 #include "wx/utils.h"
24 #include "wx/app.h"
25 #include "wx/palette.h"
26 #include "wx/dcmemory.h"
27 #include "wx/bitmap.h"
28 #include "wx/icon.h"
29 #endif
30
31 #include "wx/os2/private.h"
32 #include "wx/log.h"
33
34 //#include "wx/msw/dib.h"
35 #include "wx/image.h"
36
37 // ----------------------------------------------------------------------------
38 // macros
39 // ----------------------------------------------------------------------------
40
41 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
42 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
43
44 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
45
46 // ============================================================================
47 // implementation
48 // ============================================================================
49
50 // ----------------------------------------------------------------------------
51 // wxBitmapRefData
52 // ----------------------------------------------------------------------------
53
54 wxBitmapRefData::wxBitmapRefData()
55 {
56 m_nQuality = 0;
57 m_pSelectedInto = NULL;
58 m_nNumColors = 0;
59 m_pBitmapMask = NULL;
60 m_hBitmap = (WXHBITMAP) NULL;
61 } // end of wxBitmapRefData::wxBitmapRefData
62
63 void wxBitmapRefData::Free()
64 {
65 wxASSERT_MSG( !m_pSelectedInto,
66 wxT("deleting bitmap still selected into wxMemoryDC") );
67
68 if (m_hBitmap)
69 {
70 if ( !::GpiDeleteBitmap((HBITMAP)m_hBitmap) )
71 {
72 wxLogLastError("GpiDeleteBitmap(hbitmap)");
73 }
74 }
75
76 delete m_pBitmapMask;
77 m_pBitmapMask = NULL;
78 } // end of wxBitmapRefData::Free
79
80 // ----------------------------------------------------------------------------
81 // wxBitmap creation
82 // ----------------------------------------------------------------------------
83
84 // this function should be called from all wxBitmap ctors
85 void wxBitmap::Init()
86 {
87 // m_refData = NULL; done in the base class ctor
88
89 if (wxTheBitmapList)
90 wxTheBitmapList->AddBitmap(this);
91 } // end of wxBitmap::Init
92
93 bool wxBitmap::CopyFromIconOrCursor(
94 const wxGDIImage& rIcon
95 )
96 {
97 HPOINTER hIcon = (HPOINTER)rIcon.GetHandle();
98 POINTERINFO SIconInfo;
99
100 if (!::WinQueryPointerInfo(hIcon, &SIconInfo))
101 {
102 wxLogLastError(wxT("WinQueryPointerInfo"));
103 return FALSE;
104 }
105 wxBitmapRefData* pRefData = new wxBitmapRefData;
106
107 m_refData = pRefData;
108
109 int nWidth = rIcon.GetWidth();
110 int nHeight = rIcon.GetHeight();
111
112 pRefData->m_nWidth = nWidth;
113 pRefData->m_nHeight = nHeight;
114 pRefData->m_nDepth = wxDisplayDepth();
115
116 pRefData->m_hBitmap = (WXHBITMAP)SIconInfo.hbmColor;
117
118 //
119 // No mask in the Info struct in OS/2
120 //
121 return(TRUE);
122 } // end of wxBitmap::CopyFromIconOrCursor
123
124 bool wxBitmap::CopyFromCursor(
125 const wxCursor& rCursor
126 )
127 {
128 UnRef();
129
130 if (!rCursor.Ok())
131 return(FALSE);
132 return(CopyFromIconOrCursor(rCursor));
133 } // end of wxBitmap::CopyFromCursor
134
135 bool wxBitmap::CopyFromIcon(
136 const wxIcon& rIcon
137 )
138 {
139 UnRef();
140
141 if (!rIcon.Ok())
142 return(FALSE);
143
144 return CopyFromIconOrCursor(rIcon);
145 } // end of wxBitmap::CopyFromIcon
146
147 wxBitmap::~wxBitmap()
148 {
149 if (wxTheBitmapList)
150 wxTheBitmapList->DeleteObject(this);
151 } // end of wxBitmap::~wxBitmap
152
153 wxBitmap::wxBitmap(
154 const char zBits[]
155 , int nTheWidth
156 , int nTheHeight
157 , int nNoBits
158 )
159 {
160 Init();
161
162 wxBitmapRefData* pRefData = new wxBitmapRefData;
163 BITMAPINFOHEADER2 vHeader;
164 BITMAPINFO2 vInfo;
165 HDC hDc;
166 HPS hPs;
167 DEVOPENSTRUC vDop = { NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
168 SIZEL vSize = {0, 0};
169
170 wxASSERT(vHabmain != NULL);
171
172 hDc = ::DevOpenDC(vHabmain, OD_MEMORY, (PSZ)"*", 1L, (PDEVOPENDATA)&vDop, 0L);
173
174 vHeader.cbFix = sizeof(vHeader);
175 vHeader.cx = (USHORT)nTheWidth;
176 vHeader.cy = (USHORT)nTheHeight;
177 vHeader.cPlanes = 1L;
178 vHeader.cBitCount = nNoBits;
179 vHeader.ulCompression = BCA_UNCOMP;
180 vHeader.cxResolution = 0;
181 vHeader.cyResolution = 0;
182 vHeader.cclrUsed = 0;
183 vHeader.cclrImportant = 0;
184 vHeader.usUnits = BRU_METRIC;
185 vHeader.usRecording = BRA_BOTTOMUP;
186 vHeader.usRendering = BRH_NOTHALFTONED;
187 vHeader.cSize1 = 0;
188 vHeader.cSize2 = 0;
189 vHeader.ulColorEncoding = 0;
190 vHeader.ulIdentifier = 0;
191
192 hPs = ::GpiCreatePS(vHabmain, hDc, &vSize, GPIA_ASSOC | PU_PELS);
193 if (hPs == 0)
194 {
195 wxLogLastError("GpiCreatePS Failure");
196 }
197
198 m_refData = pRefData;
199
200 pRefData->m_nWidth = nTheWidth;
201 pRefData->m_nHeight = nTheHeight;
202 pRefData->m_nDepth = nNoBits;
203 pRefData->m_nNumColors = 0;
204 pRefData->m_pSelectedInto = NULL;
205
206 HBITMAP hBmp = ::GpiCreateBitmap(hPs, &vHeader, 0L, NULL, &vInfo);
207 if (!hBmp)
208 {
209 wxLogLastError("CreateBitmap");
210 }
211 SetHBITMAP((WXHBITMAP)hBmp);
212 } // end of wxBitmap::wxBitmap
213
214 //
215 // Create from XPM data
216 //
217 wxBitmap::wxBitmap(
218 char** ppData
219 )
220 {
221 Init();
222
223 (void)Create( (void *)ppData
224 ,wxBITMAP_TYPE_XPM_DATA
225 ,0
226 ,0
227 ,0
228 );
229 } // end of wxBitmap::wxBitmap
230
231 wxBitmap::wxBitmap(
232 const char** ppData
233 )
234 {
235 Init();
236
237 (void)Create( (void *)ppData
238 ,wxBITMAP_TYPE_XPM_DATA
239 ,0
240 ,0
241 ,0
242 );
243 } // end of wxBitmap::wxBitmap
244
245 wxBitmap::wxBitmap(
246 int nW
247 , int nH
248 , int nD
249 )
250 {
251 Init();
252
253 (void)Create( nW
254 ,nH
255 ,nD
256 );
257 } // end of wxBitmap::wxBitmap
258
259 wxBitmap::wxBitmap(
260 void* pData
261 , long lType
262 , int nWidth
263 , int nHeight
264 , int nDepth
265 )
266 {
267 Init();
268
269 (void)Create( pData
270 ,lType
271 ,nWidth
272 ,nHeight
273 ,nDepth
274 );
275 } // end of wxBitmap::wxBitmap
276
277 wxBitmap::wxBitmap(
278 const wxString& rFilename
279 , long lType
280 )
281 {
282 Init();
283
284 LoadFile( rFilename
285 ,(int)lType
286 );
287 } // end of wxBitmap::wxBitmap
288
289 bool wxBitmap::Create(
290 int nW
291 , int nH
292 , int nD
293 )
294 {
295 HBITMAP hBmp;
296 BITMAPINFOHEADER2 vHeader;
297
298 wxASSERT(vHabmain != NULL);
299 UnRef();
300 m_refData = new wxBitmapRefData;
301 GetBitmapData()->m_nWidth = nW;
302 GetBitmapData()->m_nHeight = nH;
303 GetBitmapData()->m_nDepth = nD;
304
305 if (nD > 0)
306 {
307 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
308 SIZEL vSize = {0, 0};
309 HDC hDC = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
310 HPS hPS = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
311
312 memset(&vHeader, '\0', sizeof(BITMAPINFOHEADER2));
313 vHeader.cbFix = sizeof(BITMAPINFOHEADER2);
314 vHeader.cx = nW;
315 vHeader.cy = nH;
316 vHeader.cPlanes = 1;
317 vHeader.cBitCount = nD;
318
319 hBmp = ::GpiCreateBitmap( hPS
320 ,&vHeader
321 ,0L
322 ,NULL
323 ,NULL
324 );
325 ::GpiDestroyPS(hPS);
326 ::DevCloseDC(hDC);
327 }
328 else
329 {
330 HPS hPSScreen;
331 HDC hDCScreen;
332 LONG lBitCount;
333
334 hPSScreen = ::WinGetScreenPS(HWND_DESKTOP);
335 hDCScreen = ::GpiQueryDevice(hPSScreen);
336 ::DevQueryCaps(hDCScreen, CAPS_COLOR_BITCOUNT, 1L, &lBitCount);
337
338 memset(&vHeader, '\0', sizeof(BITMAPINFOHEADER2));
339 vHeader.cbFix = sizeof(BITMAPINFOHEADER2);
340 vHeader.cx = nW;
341 vHeader.cy = nH;
342 vHeader.cPlanes = 1;
343 vHeader.cBitCount = lBitCount;
344
345 hBmp = ::GpiCreateBitmap( hPSScreen
346 ,&vHeader
347 ,0L
348 ,NULL
349 ,NULL
350 );
351
352 GetBitmapData()->m_nDepth = wxDisplayDepth();
353 ::WinReleasePS(hPSScreen);
354 }
355 SetHBITMAP((WXHBITMAP)hBmp);
356
357 #if WXWIN_COMPATIBILITY_2
358 GetBitmapData()->m_bOk = hBmp != 0;
359 #endif // WXWIN_COMPATIBILITY_2
360
361 return Ok();
362 } // end of wxBitmap::Create
363
364 bool wxBitmap::LoadFile(
365 const wxString& rFilename
366 , long lType
367 )
368 {
369 HPS hPs = NULLHANDLE;
370
371 UnRef();
372
373 wxBitmapHandler* pHandler = wxDynamicCast( FindHandler(lType)
374 ,wxBitmapHandler
375 );
376
377 if (pHandler)
378 {
379 m_refData = new wxBitmapRefData;
380
381 return(pHandler->LoadFile( this
382 ,rFilename
383 ,hPs
384 ,lType
385 , -1
386 , -1
387 ));
388 }
389 else
390 {
391 wxImage vImage;
392
393 if (!vImage.LoadFile(rFilename, lType) || !vImage.Ok() )
394 return(FALSE);
395
396 *this = vImage.ConvertToBitmap();
397
398 return(TRUE);
399 }
400 } // end of wxBitmap::LoadFile
401
402 bool wxBitmap::Create(
403 void* pData
404 , long lType
405 , int nWidth
406 , int nHeight
407 , int nDepth
408 )
409 {
410 UnRef();
411
412 wxBitmapHandler* pHandler = wxDynamicCast( FindHandler(lType)
413 ,wxBitmapHandler
414 );
415
416 if (!pHandler)
417 {
418 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for "
419 "type %d defined."), lType);
420
421 return(FALSE);
422 }
423
424 m_refData = new wxBitmapRefData;
425
426 return(pHandler->Create( this
427 ,pData
428 ,lType
429 ,nWidth
430 ,nHeight
431 ,nDepth
432 ));
433 } // end of wxBitmap::Create
434
435 bool wxBitmap::SaveFile(
436 const wxString& rFilename
437 , int lType
438 , const wxPalette* pPalette
439 )
440 {
441 wxBitmapHandler* pHandler = wxDynamicCast( FindHandler(lType)
442 ,wxBitmapHandler
443 );
444
445 if (pHandler)
446 {
447 return pHandler->SaveFile( this
448 ,rFilename
449 ,lType
450 ,pPalette
451 );
452 }
453 else
454 {
455 // FIXME what about palette? shouldn't we use it?
456 wxImage vImage(*this);
457
458 if (!vImage.Ok())
459 return(FALSE);
460
461 return(vImage.SaveFile( rFilename
462 ,lType
463 ));
464 }
465 } // end of wxBitmap::SaveFile
466
467
468 // ----------------------------------------------------------------------------
469 // wxImage-wxBitmap convertion
470 // ----------------------------------------------------------------------------
471
472 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
473 {
474 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
475
476 // TODO:
477 /*
478 int sizeLimit = 1024*768*3;
479
480 // width and height of the device-dependent bitmap
481 int width = GetWidth();
482 int bmpHeight = GetHeight();
483
484 // calc the number of bytes per scanline and padding
485 int bytePerLine = width*3;
486 int sizeDWORD = sizeof( DWORD );
487 int lineBoundary = bytePerLine % sizeDWORD;
488 int padding = 0;
489 if( lineBoundary > 0 )
490 {
491 padding = sizeDWORD - lineBoundary;
492 bytePerLine += padding;
493 }
494 // calc the number of DIBs and heights of DIBs
495 int numDIB = 1;
496 int hRemain = 0;
497 int height = sizeLimit/bytePerLine;
498 if( height >= bmpHeight )
499 height = bmpHeight;
500 else
501 {
502 numDIB = bmpHeight / height;
503 hRemain = bmpHeight % height;
504 if( hRemain >0 ) numDIB++;
505 }
506
507 // set bitmap parameters
508 wxBitmap bitmap;
509 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
510 bitmap.SetWidth( width );
511 bitmap.SetHeight( bmpHeight );
512 bitmap.SetDepth( wxDisplayDepth() );
513
514 // create a DIB header
515 int headersize = sizeof(BITMAPINFOHEADER);
516 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
517 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
518 // Fill in the DIB header
519 lpDIBh->bmiHeader.biSize = headersize;
520 lpDIBh->bmiHeader.biWidth = (DWORD)width;
521 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
522 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
523 // the general formula for biSizeImage:
524 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
525 lpDIBh->bmiHeader.biPlanes = 1;
526 lpDIBh->bmiHeader.biBitCount = 24;
527 lpDIBh->bmiHeader.biCompression = BI_RGB;
528 lpDIBh->bmiHeader.biClrUsed = 0;
529 // These seem not really needed for our purpose here.
530 lpDIBh->bmiHeader.biClrImportant = 0;
531 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
532 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
533 // memory for DIB data
534 unsigned char *lpBits;
535 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
536 if( !lpBits )
537 {
538 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
539 free( lpDIBh );
540 return bitmap;
541 }
542
543 // create and set the device-dependent bitmap
544 HDC hdc = ::GetDC(NULL);
545 HDC memdc = ::CreateCompatibleDC( hdc );
546 HBITMAP hbitmap;
547 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
548 ::SelectObject( memdc, hbitmap);
549
550 // copy image data into DIB data and then into DDB (in a loop)
551 unsigned char *data = GetData();
552 int i, j, n;
553 int origin = 0;
554 unsigned char *ptdata = data;
555 unsigned char *ptbits;
556
557 for( n=0; n<numDIB; n++ )
558 {
559 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
560 {
561 // redefine height and size of the (possibly) last smaller DIB
562 // memory is not reallocated
563 height = hRemain;
564 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
565 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
566 }
567 ptbits = lpBits;
568
569 for( j=0; j<height; j++ )
570 {
571 for( i=0; i<width; i++ )
572 {
573 *(ptbits++) = *(ptdata+2);
574 *(ptbits++) = *(ptdata+1);
575 *(ptbits++) = *(ptdata );
576 ptdata += 3;
577 }
578 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
579 }
580 ::StretchDIBits( memdc, 0, origin, width, height,\
581 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
582 origin += height;
583 // if numDIB = 1, lines below can also be used
584 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
585 // The above line is equivalent to the following two lines.
586 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
587 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
588 // or the following lines
589 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
590 // HDC memdc = ::CreateCompatibleDC( hdc );
591 // ::SelectObject( memdc, hbitmap);
592 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
593 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
594 // ::SelectObject( memdc, 0 );
595 // ::DeleteDC( memdc );
596 }
597 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
598
599 // similarly, created an mono-bitmap for the possible mask
600 if( HasMask() )
601 {
602 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
603 ::SelectObject( memdc, hbitmap);
604 if( numDIB == 1 ) height = bmpHeight;
605 else height = sizeLimit/bytePerLine;
606 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
607 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
608 origin = 0;
609 unsigned char r = GetMaskRed();
610 unsigned char g = GetMaskGreen();
611 unsigned char b = GetMaskBlue();
612 unsigned char zero = 0, one = 255;
613 ptdata = data;
614 for( n=0; n<numDIB; n++ )
615 {
616 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
617 {
618 // redefine height and size of the (possibly) last smaller DIB
619 // memory is not reallocated
620 height = hRemain;
621 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
622 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
623 }
624 ptbits = lpBits;
625 for( int j=0; j<height; j++ )
626 {
627 for(i=0; i<width; i++ )
628 {
629 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
630 {
631 *(ptbits++) = one;
632 *(ptbits++) = one;
633 *(ptbits++) = one;
634 }
635 else
636 {
637 *(ptbits++) = zero;
638 *(ptbits++) = zero;
639 *(ptbits++) = zero;
640 }
641 }
642 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
643 }
644 ::StretchDIBits( memdc, 0, origin, width, height,\
645 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
646 origin += height;
647 }
648 // create a wxMask object
649 wxMask *mask = new wxMask();
650 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
651 bitmap.SetMask( mask );
652 }
653
654 // free allocated resources
655 ::SelectObject( memdc, 0 );
656 ::DeleteDC( memdc );
657 ::ReleaseDC(NULL, hdc);
658 free(lpDIBh);
659 free(lpBits);
660
661 // check the wxBitmap object
662 if( bitmap.GetHBITMAP() )
663 bitmap.SetOk( TRUE );
664 else
665 bitmap.SetOk( FALSE );
666 */
667
668 return TRUE;
669 }
670
671 wxImage wxBitmap::ConvertToImage() const
672 {
673 wxImage image;
674
675 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
676
677 // create an wxImage object
678 int width = GetWidth();
679 int height = GetHeight();
680 image.Create( width, height );
681 unsigned char *data = image.GetData();
682 if( !data )
683 {
684 wxFAIL_MSG( wxT("could not allocate data for image") );
685 return wxNullImage;
686 }
687
688 // calc the number of bytes per scanline and padding in the DIB
689 int bytePerLine = width*3;
690 int sizeDWORD = sizeof( DWORD );
691 int lineBoundary = bytePerLine % sizeDWORD;
692 int padding = 0;
693 if( lineBoundary > 0 )
694 {
695 padding = sizeDWORD - lineBoundary;
696 bytePerLine += padding;
697 }
698 // TODO:
699 /*
700 // create a DIB header
701 int headersize = sizeof(BITMAPINFOHEADER);
702 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
703 if( !lpDIBh )
704 {
705 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
706 free( data );
707 return;
708 }
709 // Fill in the DIB header
710 lpDIBh->bmiHeader.biSize = headersize;
711 lpDIBh->bmiHeader.biWidth = width;
712 lpDIBh->bmiHeader.biHeight = -height;
713 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
714 lpDIBh->bmiHeader.biPlanes = 1;
715 lpDIBh->bmiHeader.biBitCount = 24;
716 lpDIBh->bmiHeader.biCompression = BI_RGB;
717 lpDIBh->bmiHeader.biClrUsed = 0;
718 // These seem not really needed for our purpose here.
719 lpDIBh->bmiHeader.biClrImportant = 0;
720 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
721 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
722 // memory for DIB data
723 unsigned char *lpBits;
724 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
725 if( !lpBits )
726 {
727 wxFAIL_MSG( wxT("could not allocate data for DIB") );
728 free( data );
729 free( lpDIBh );
730 return;
731 }
732
733 // copy data from the device-dependent bitmap to the DIB
734 HDC hdc = ::GetDC(NULL);
735 HBITMAP hbitmap;
736 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
737 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
738
739 // copy DIB data into the wxImage object
740 int i, j;
741 unsigned char *ptdata = data;
742 unsigned char *ptbits = lpBits;
743 for( i=0; i<height; i++ )
744 {
745 for( j=0; j<width; j++ )
746 {
747 *(ptdata++) = *(ptbits+2);
748 *(ptdata++) = *(ptbits+1);
749 *(ptdata++) = *(ptbits );
750 ptbits += 3;
751 }
752 ptbits += padding;
753 }
754
755 // similarly, set data according to the possible mask bitmap
756 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
757 {
758 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
759 // memory DC created, color set, data copied, and memory DC deleted
760 HDC memdc = ::CreateCompatibleDC( hdc );
761 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
762 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
763 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
764 ::DeleteDC( memdc );
765 // background color set to RGB(16,16,16) in consistent with wxGTK
766 unsigned char r=16, g=16, b=16;
767 ptdata = data;
768 ptbits = lpBits;
769 for( i=0; i<height; i++ )
770 {
771 for( j=0; j<width; j++ )
772 {
773 if( *ptbits != 0 )
774 ptdata += 3;
775 else
776 {
777 *(ptdata++) = r;
778 *(ptdata++) = g;
779 *(ptdata++) = b;
780 }
781 ptbits += 3;
782 }
783 ptbits += padding;
784 }
785 SetMaskColour( r, g, b );
786 SetMask( TRUE );
787 }
788 else
789 {
790 SetMask( FALSE );
791 }
792 // free allocated resources
793 ::ReleaseDC(NULL, hdc);
794 free(lpDIBh);
795 free(lpBits);
796 */
797
798 return image;
799 }
800
801
802 // ----------------------------------------------------------------------------
803 // sub bitmap extraction
804 // ----------------------------------------------------------------------------
805
806 wxBitmap wxBitmap::GetSubBitmap(
807 const wxRect& rRect
808 ) const
809 {
810 wxCHECK_MSG( Ok() &&
811 (rRect.x >= 0) && (rRect.y >= 0) &&
812 (rRect.x + rRect.width <= GetWidth()) &&
813 (rRect.y + rRect.height <= GetHeight()),
814 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
815
816 wxBitmap vRet( rRect.width
817 ,rRect.height
818 ,GetDepth()
819 );
820 wxASSERT_MSG( vRet.Ok(), wxT("GetSubBitmap error") );
821
822
823 //
824 // Copy bitmap data
825 //
826 SIZEL vSize = {0, 0};
827 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
828 HDC hDCSrc = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
829 HDC hDCDst = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
830 HPS hPSSrc = ::GpiCreatePS(vHabmain, hDCSrc, &vSize, PU_PELS | GPIA_ASSOC);
831 HPS hPSDst = ::GpiCreatePS(vHabmain, hDCDst, &vSize, PU_PELS | GPIA_ASSOC);
832 POINTL vPoint[4] = { rRect.x, rRect.y,
833 rRect.x + rRect.width, rRect.y + rRect.height,
834 0, 0, GetWidth(), GetHeight()
835 };
836
837 ::GpiSetBitmap(hPSSrc, (HBITMAP) GetHBITMAP());
838 ::GpiSetBitmap(hPSDst, (HBITMAP) vRet.GetHBITMAP());
839 ::GpiBitBlt( hPSDst
840 ,hPSSrc
841 ,4L
842 ,vPoint
843 ,ROP_SRCCOPY
844 ,BBO_IGNORE
845 );
846
847 //
848 // Copy mask if there is one
849 //
850 if (GetMask())
851 {
852 BITMAPINFOHEADER2 vBmih;
853
854 memset(&vBmih, '\0', sizeof(BITMAPINFOHEADER2));
855 vBmih.cbFix = sizeof(BITMAPINFOHEADER2);
856 vBmih.cx = rRect.width;
857 vBmih.cy = rRect.height;
858 vBmih.cPlanes = 1;
859 vBmih.cBitCount = 1;
860
861 HBITMAP hBmpMask = ::GpiCreateBitmap( hPSDst
862 ,&vBmih
863 ,0L
864 ,NULL
865 ,NULL
866 );
867
868 ::GpiSetBitmap(hPSSrc, (HBITMAP) GetHBITMAP());
869 ::GpiSetBitmap(hPSDst, (HBITMAP) vRet.GetHBITMAP());
870
871 ::GpiSetBitmap(hPSSrc, (HBITMAP) GetMask()->GetMaskBitmap());
872 ::GpiSetBitmap(hPSDst, (HBITMAP) hBmpMask);
873 ::GpiBitBlt( hPSDst
874 ,hPSSrc
875 ,4L
876 ,vPoint
877 ,ROP_SRCCOPY
878 ,BBO_IGNORE
879 );
880
881 wxMask* pMask = new wxMask((WXHBITMAP)hBmpMask);
882 vRet.SetMask(pMask);
883 }
884
885 ::GpiSetBitmap(hPSSrc, NULL);
886 ::GpiSetBitmap(hPSDst, NULL);
887 ::GpiDestroyPS(hPSSrc);
888 ::GpiDestroyPS(hPSDst);
889 ::DevCloseDC(hDCSrc);
890 ::DevCloseDC(hDCDst);
891 return vRet;
892 } // end of wxBitmap::GetSubBitmap
893
894 // ----------------------------------------------------------------------------
895 // wxBitmap accessors
896 // ----------------------------------------------------------------------------
897
898 void wxBitmap::SetQuality(
899 int nQ
900 )
901 {
902 EnsureHasData();
903
904 GetBitmapData()->m_nQuality = nQ;
905 } // end of wxBitmap::SetQuality
906
907 #if WXWIN_COMPATIBILITY_2
908 void wxBitmap::SetOk(
909 bool bOk
910 )
911 {
912 EnsureHasData();
913
914 GetBitmapData()->m_bOk = bOk;
915 } // end of wxBitmap::SetOk
916 #endif // WXWIN_COMPATIBILITY_2
917
918 void wxBitmap::SetPalette(
919 const wxPalette& rPalette
920 )
921 {
922 EnsureHasData();
923
924 GetBitmapData()->m_vBitmapPalette = rPalette;
925 } // end of wxBitmap::SetPalette
926
927 void wxBitmap::SetMask(
928 wxMask* pMask
929 )
930 {
931 EnsureHasData();
932
933 GetBitmapData()->m_pBitmapMask = pMask;
934 } // end of wxBitmap::SetMask
935
936 //
937 // Will try something for OS/2 but not really sure how close
938 // to the msw intent this is.
939 //
940 wxBitmap wxBitmap::GetBitmapForDC(
941 wxDC& rDc
942 ) const
943 {
944 wxMemoryDC vMemDC;
945 wxBitmap vTmpBitmap( this->GetWidth()
946 ,this->GetHeight()
947 ,rDc.GetDepth()
948 );
949 WXHBITMAP vOldBitmap;
950 HPS hMemoryPS;
951 HPS hPs;
952 POINTL vPoint[4];
953 SIZEL vSize = {0,0};
954
955 hMemoryPS = ::GpiCreatePS(vHabmain, (HDC)vMemDC.GetHDC(), &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
956 hPs = ::GpiCreatePS(vHabmain, (HDC)rDc.GetHDC(), &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
957
958 // TODO: Set the points
959
960 vOldBitmap = (WXHBITMAP)::GpiSetBitmap(hPs, (HBITMAP)vTmpBitmap.GetHBITMAP());
961 ::GpiBitBlt(hPs, hMemoryPS, 4L, vPoint, ROP_SRCCOPY, BBO_IGNORE);
962
963 return(vTmpBitmap);
964 } // end of wxBitmap::GetBitmapForDC
965
966 // ----------------------------------------------------------------------------
967 // wxMask
968 // ----------------------------------------------------------------------------
969
970 wxMask::wxMask()
971 {
972 m_hMaskBitmap = 0;
973 } // end of wxMask::wxMask
974
975 // Construct a mask from a bitmap and a colour indicating
976 // the transparent area
977 wxMask::wxMask(
978 const wxBitmap& rBitmap
979 , const wxColour& rColour
980 )
981 {
982 m_hMaskBitmap = 0;
983 Create( rBitmap
984 ,rColour
985 );
986 } // end of wxMask::wxMask
987
988 // Construct a mask from a bitmap and a palette index indicating
989 // the transparent area
990 wxMask::wxMask(
991 const wxBitmap& rBitmap
992 , int nPaletteIndex
993 )
994 {
995 m_hMaskBitmap = 0;
996 Create( rBitmap
997 ,nPaletteIndex
998 );
999 } // end of wxMask::wxMask
1000
1001 // Construct a mask from a mono bitmap (copies the bitmap).
1002 wxMask::wxMask(
1003 const wxBitmap& rBitmap
1004 )
1005 {
1006 m_hMaskBitmap = 0;
1007 Create(rBitmap);
1008 } // end of wxMask::wxMask
1009
1010 wxMask::~wxMask()
1011 {
1012 if (m_hMaskBitmap)
1013 ::GpiDeleteBitmap((HBITMAP)m_hMaskBitmap);
1014 } // end of wxMask::~wxMask
1015
1016 // Create a mask from a mono bitmap (copies the bitmap).
1017 bool wxMask::Create(
1018 const wxBitmap& rBitmap
1019 )
1020 {
1021 BITMAPINFOHEADER2 vBmih;
1022 SIZEL vSize = {0, 0};
1023 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
1024 HDC hDCSrc = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1025 HDC hDCDst = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1026 HPS hPSSrc = ::GpiCreatePS(vHabmain, hDCSrc, &vSize, PU_PELS | GPIA_ASSOC);
1027 HPS hPSDst = ::GpiCreatePS(vHabmain, hDCDst, &vSize, PU_PELS | GPIA_ASSOC);
1028 POINTL vPoint[4] = { 0 ,0, rBitmap.GetWidth(), rBitmap.GetHeight(),
1029 0, 0, rBitmap.GetWidth(), rBitmap.GetHeight()
1030 };
1031
1032 if (m_hMaskBitmap)
1033 {
1034 ::GpiDeleteBitmap((HBITMAP) m_hMaskBitmap);
1035 m_hMaskBitmap = 0;
1036 }
1037 if (!rBitmap.Ok() || rBitmap.GetDepth() != 1)
1038 {
1039 return(FALSE);
1040 }
1041
1042 memset(&vBmih, '\0', sizeof(BITMAPINFOHEADER2));
1043 vBmih.cbFix = sizeof(BITMAPINFOHEADER2);
1044 vBmih.cx = rBitmap.GetWidth();
1045 vBmih.cy = rBitmap.GetHeight();
1046 vBmih.cPlanes = 1;
1047 vBmih.cBitCount = 1;
1048
1049 m_hMaskBitmap = ::GpiCreateBitmap( hPSDst
1050 ,&vBmih
1051 ,0L
1052 ,NULL
1053 ,NULL
1054 );
1055
1056 ::GpiSetBitmap(hPSSrc, (HBITMAP) rBitmap.GetHBITMAP());
1057 ::GpiSetBitmap(hPSDst, (HBITMAP) m_hMaskBitmap);
1058 ::GpiBitBlt( hPSDst
1059 ,hPSSrc
1060 ,4L
1061 ,vPoint
1062 ,ROP_SRCCOPY
1063 ,BBO_IGNORE
1064 );
1065
1066 ::GpiDestroyPS(hPSSrc);
1067 ::GpiDestroyPS(hPSDst);
1068 ::DevCloseDC(hDCSrc);
1069 ::DevCloseDC(hDCDst);
1070 return(TRUE);
1071 } // end of wxMask::Create
1072
1073 // Create a mask from a bitmap and a palette index indicating
1074 // the transparent area
1075 bool wxMask::Create(
1076 const wxBitmap& rBitmap
1077 , int nPaletteIndex
1078 )
1079 {
1080 if (m_hMaskBitmap)
1081 {
1082 ::GpiDeleteBitmap((HBITMAP) m_hMaskBitmap);
1083 m_hMaskBitmap = 0;
1084 }
1085 if (rBitmap.Ok() && rBitmap.GetPalette()->Ok())
1086 {
1087 unsigned char cRed;
1088 unsigned char cGreen;
1089 unsigned char cBlue;
1090
1091 if (rBitmap.GetPalette()->GetRGB( nPaletteIndex
1092 ,&cRed
1093 ,&cGreen
1094 ,&cBlue
1095 ))
1096 {
1097 wxColour vTransparentColour( cRed
1098 ,cGreen
1099 ,cBlue
1100 );
1101
1102 return (Create( rBitmap
1103 ,vTransparentColour
1104 ));
1105 }
1106 }
1107 return(FALSE);
1108 } // end of wxMask::Create
1109
1110 // Create a mask from a bitmap and a colour indicating
1111 // the transparent area
1112 bool wxMask::Create(
1113 const wxBitmap& rBitmap
1114 , const wxColour& rColour
1115 )
1116 {
1117 bool bOk = TRUE;
1118 COLORREF vMaskColour = OS2RGB( rColour.Red()
1119 ,rColour.Green()
1120 ,rColour.Blue()
1121 );
1122 BITMAPINFOHEADER2 vBmih;
1123 SIZEL vSize = {0, 0};
1124 DEVOPENSTRUC vDop = { NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1125 HDC hDCSrc = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1126 HDC hDCDst = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1127 HPS hPSSrc = ::GpiCreatePS(vHabmain, hDCSrc, &vSize, PU_PELS | GPIA_ASSOC);
1128 HPS hPSDst = ::GpiCreatePS(vHabmain, hDCDst, &vSize, PU_PELS | GPIA_ASSOC);
1129 POINTL vPoint[4] = { 0 ,0, rBitmap.GetWidth(), rBitmap.GetHeight(),
1130 0, 0, rBitmap.GetWidth(), rBitmap.GetHeight()
1131 };
1132
1133 if (m_hMaskBitmap)
1134 {
1135 ::GpiDeleteBitmap((HBITMAP) m_hMaskBitmap);
1136 m_hMaskBitmap = 0;
1137 }
1138 if (!rBitmap.Ok())
1139 {
1140 return(FALSE);
1141 }
1142
1143 //
1144 // Scan the bitmap for the transparent colour and set
1145 // the corresponding pixels in the mask to BLACK and
1146 // the rest to WHITE
1147 //
1148
1149 memset(&vBmih, '\0', sizeof(BITMAPINFOHEADER2));
1150 vBmih.cbFix = sizeof(BITMAPINFOHEADER2);
1151 vBmih.cx = rBitmap.GetWidth();
1152 vBmih.cy = rBitmap.GetHeight();
1153 vBmih.cPlanes = 1;
1154 vBmih.cBitCount = 1;
1155
1156 m_hMaskBitmap = ::GpiCreateBitmap( hPSDst
1157 ,&vBmih
1158 ,0L
1159 ,NULL
1160 ,NULL
1161 );
1162
1163 ::GpiSetBitmap(hPSSrc, (HBITMAP) rBitmap.GetHBITMAP());
1164 ::GpiSetBitmap(hPSDst, (HBITMAP) m_hMaskBitmap);
1165
1166 //
1167 // This is not very efficient, but I can't think
1168 // of a better way of doing it
1169 //
1170 for (int w = 0; w < rBitmap.GetWidth(); w++)
1171 {
1172 for (int h = 0; h < rBitmap.GetHeight(); h++)
1173 {
1174 POINTL vPt = {w, h};
1175 COLORREF vCol = (COLORREF)::GpiQueryPel(hPSSrc, &vPt);
1176 if (vCol == (COLORREF)CLR_NOINDEX)
1177 {
1178 //
1179 // Doesn't make sense to continue
1180 //
1181 bOk = FALSE;
1182 break;
1183 }
1184
1185 if (vCol == vMaskColour)
1186 {
1187 ::GpiSetColor(hPSDst, OS2RGB(0, 0, 0));
1188 ::GpiSetPel(hPSDst, &vPt);
1189 }
1190 else
1191 {
1192 ::GpiSetColor(hPSDst, OS2RGB(255, 255, 255));
1193 ::GpiSetPel(hPSDst, &vPt);
1194 }
1195 }
1196 }
1197 ::GpiSetBitmap(hPSSrc, NULL);
1198 ::GpiSetBitmap(hPSDst, NULL);
1199 ::GpiDestroyPS(hPSSrc);
1200 ::GpiDestroyPS(hPSDst);
1201 ::DevCloseDC(hDCSrc);
1202 ::DevCloseDC(hDCDst);
1203 return(TRUE);
1204 } // end of wxMask::Create
1205
1206 // ----------------------------------------------------------------------------
1207 // wxBitmapHandler
1208 // ----------------------------------------------------------------------------
1209
1210 bool wxBitmapHandler::Create(
1211 wxGDIImage* pImage
1212 , void* pData
1213 , long lFlags
1214 , int nWidth
1215 , int nHeight
1216 , int nDepth
1217 )
1218 {
1219 wxBitmap* pBitmap = wxDynamicCast( pImage
1220 ,wxBitmap
1221 );
1222
1223 return(pBitmap ? Create( pBitmap
1224 ,pData
1225 ,nWidth
1226 ,nHeight
1227 ,nDepth
1228 ) : FALSE);
1229 }
1230
1231 bool wxBitmapHandler::Load(
1232 wxGDIImage* pImage
1233 , const wxString& rName
1234 , HPS hPs
1235 , long lFlags
1236 , int nWidth
1237 , int nHeight
1238 )
1239 {
1240 wxBitmap* pBitmap = wxDynamicCast( pImage
1241 ,wxBitmap
1242 );
1243
1244 return(pBitmap ? LoadFile( pBitmap
1245 ,rName
1246 ,hPs
1247 ,lFlags
1248 ,nWidth
1249 ,nHeight
1250 ) : FALSE);
1251 }
1252
1253 bool wxBitmapHandler::Save(
1254 wxGDIImage* pImage
1255 , const wxString& rName
1256 , int lType
1257 )
1258 {
1259 wxBitmap* pBitmap = wxDynamicCast( pImage
1260 ,wxBitmap
1261 );
1262
1263 return(pBitmap ? SaveFile( pBitmap
1264 ,rName
1265 ,lType
1266 ) : FALSE);
1267 }
1268
1269 bool wxBitmapHandler::Create(
1270 wxBitmap* WXUNUSED(pBitmap)
1271 , void* WXUNUSED(pData)
1272 , long WXUNUSED(lType)
1273 , int WXUNUSED(nWidth)
1274 , int WXUNUSED(nHeight)
1275 , int WXUNUSED(nDepth)
1276 )
1277 {
1278 return(FALSE);
1279 }
1280
1281 bool wxBitmapHandler::LoadFile(
1282 wxBitmap* WXUNUSED(pBitmap)
1283 , const wxString& WXUNUSED(rName)
1284 , HPS WXUNUSED(hPs)
1285 , long WXUNUSED(lType)
1286 , int WXUNUSED(nDesiredWidth)
1287 , int WXUNUSED(nDesiredHeight)
1288 )
1289 {
1290 return(FALSE);
1291 }
1292
1293 bool wxBitmapHandler::SaveFile(
1294 wxBitmap* WXUNUSED(pBitmap)
1295 , const wxString& WXUNUSED(rName)
1296 , int WXUNUSED(nType)
1297 , const wxPalette* WXUNUSED(pPalette)
1298 )
1299 {
1300 return(FALSE);
1301 }
1302
1303 // ----------------------------------------------------------------------------
1304 // Utility functions
1305 // ----------------------------------------------------------------------------
1306 HBITMAP wxInvertMask(
1307 HBITMAP hBmpMask
1308 , int nWidth
1309 , int nHeight
1310 )
1311 {
1312 HBITMAP hBmpInvMask = 0;
1313
1314 wxCHECK_MSG( hBmpMask, 0, _T("invalid bitmap in wxInvertMask") );
1315
1316 //
1317 // Get width/height from the bitmap if not given
1318 //
1319 if (!nWidth || !nHeight)
1320 {
1321 BITMAPINFOHEADER2 vBmhdr;
1322
1323 ::GpiQueryBitmapInfoHeader( hBmpMask
1324 ,&vBmhdr
1325 );
1326 nWidth = (int)vBmhdr.cx;
1327 nHeight = (int)vBmhdr.cy;
1328 }
1329
1330 BITMAPINFOHEADER2 vBmih;
1331 SIZEL vSize = {0, 0};
1332 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
1333 HDC hDCSrc = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1334 HDC hDCDst = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
1335 HPS hPSSrc = ::GpiCreatePS(vHabmain, hDCSrc, &vSize, PU_PELS | GPIA_ASSOC);
1336 HPS hPSDst = ::GpiCreatePS(vHabmain, hDCDst, &vSize, PU_PELS | GPIA_ASSOC);
1337 POINTL vPoint[4] = { 0 ,0, nWidth, nHeight,
1338 0, 0, nWidth, nHeight
1339 };
1340
1341 memset(&vBmih, '\0', sizeof(BITMAPINFOHEADER2));
1342 vBmih.cbFix = sizeof(BITMAPINFOHEADER2);
1343 vBmih.cx = nWidth;
1344 vBmih.cy = nHeight;
1345 vBmih.cPlanes = 1;
1346 vBmih.cBitCount = 1;
1347
1348 hBmpInvMask = ::GpiCreateBitmap( hPSDst
1349 ,&vBmih
1350 ,0L
1351 ,NULL
1352 ,NULL
1353 );
1354
1355 ::GpiSetBitmap(hPSSrc, (HBITMAP) hBmpMask);
1356 ::GpiSetBitmap(hPSDst, (HBITMAP) hBmpInvMask);
1357
1358 ::GpiBitBlt( hPSDst
1359 ,hPSSrc
1360 ,4L
1361 ,vPoint
1362 ,ROP_SRCINVERT
1363 ,BBO_IGNORE
1364 );
1365
1366 ::GpiDestroyPS(hPSSrc);
1367 ::GpiDestroyPS(hPSDst);
1368 ::DevCloseDC(hDCSrc);
1369 ::DevCloseDC(hDCDst);
1370
1371 return hBmpInvMask;
1372 } // end of WxWinGdi_InvertMask