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