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