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