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