]> git.saurik.com Git - wxWidgets.git/blob - src/msw/bitmap.cpp
applied correction from Marc Newsam in calculations of linesize
[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 // ----------------------------------------------------------------------------
354 // wxImage to/from conversions
355 // ----------------------------------------------------------------------------
356
357 #if wxUSE_IMAGE
358
359 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
360 {
361 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
362
363 m_refData = new wxBitmapRefData();
364
365 // sizeLimit is the MS upper limit for the DIB size
366 #ifdef WIN32
367 int sizeLimit = 1024*768*3;
368 #else
369 int sizeLimit = 0x7fff ;
370 #endif
371
372 // width and height of the device-dependent bitmap
373 int width = image.GetWidth();
374 int bmpHeight = image.GetHeight();
375
376 // calc the number of bytes per scanline and padding
377 int bytePerLine = width*3;
378 int sizeDWORD = sizeof( DWORD );
379 int lineBoundary = bytePerLine % sizeDWORD;
380 int padding = 0;
381 if( lineBoundary > 0 )
382 {
383 padding = sizeDWORD - lineBoundary;
384 bytePerLine += padding;
385 }
386 // calc the number of DIBs and heights of DIBs
387 int numDIB = 1;
388 int hRemain = 0;
389 int height = sizeLimit/bytePerLine;
390 if( height >= bmpHeight )
391 height = bmpHeight;
392 else
393 {
394 numDIB = bmpHeight / height;
395 hRemain = bmpHeight % height;
396 if( hRemain >0 ) numDIB++;
397 }
398
399 // set bitmap parameters
400 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") );
401 SetWidth( width );
402 SetHeight( bmpHeight );
403 if (depth == -1) depth = wxDisplayDepth();
404 SetDepth( depth );
405
406 // create a DIB header
407 int headersize = sizeof(BITMAPINFOHEADER);
408 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
409 wxCHECK_MSG( lpDIBh, FALSE, wxT("could not allocate memory for DIB header") );
410 // Fill in the DIB header
411 lpDIBh->bmiHeader.biSize = headersize;
412 lpDIBh->bmiHeader.biWidth = (DWORD)width;
413 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
414 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
415 // the general formula for biSizeImage:
416 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
417 lpDIBh->bmiHeader.biPlanes = 1;
418 lpDIBh->bmiHeader.biBitCount = 24;
419 lpDIBh->bmiHeader.biCompression = BI_RGB;
420 lpDIBh->bmiHeader.biClrUsed = 0;
421 // These seem not really needed for our purpose here.
422 lpDIBh->bmiHeader.biClrImportant = 0;
423 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
424 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
425 // memory for DIB data
426 unsigned char *lpBits;
427 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
428 if( !lpBits )
429 {
430 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
431 free( lpDIBh );
432 return FALSE;
433 }
434
435 // create and set the device-dependent bitmap
436 HDC hdc = ::GetDC(NULL);
437 HDC memdc = ::CreateCompatibleDC( hdc );
438 HBITMAP hbitmap;
439 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
440 ::SelectObject( memdc, hbitmap);
441
442 HPALETTE hOldPalette = 0;
443 if (image.GetPalette().Ok())
444 {
445 hOldPalette = ::SelectPalette(memdc, (HPALETTE) image.GetPalette().GetHPALETTE(), FALSE);
446 ::RealizePalette(memdc);
447 }
448
449 // copy image data into DIB data and then into DDB (in a loop)
450 unsigned char *data = image.GetData();
451 int i, j, n;
452 int origin = 0;
453 unsigned char *ptdata = data;
454 unsigned char *ptbits;
455
456 for( n=0; n<numDIB; n++ )
457 {
458 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
459 {
460 // redefine height and size of the (possibly) last smaller DIB
461 // memory is not reallocated
462 height = hRemain;
463 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
464 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
465 }
466 ptbits = lpBits;
467
468 for( j=0; j<height; j++ )
469 {
470 for( i=0; i<width; i++ )
471 {
472 *(ptbits++) = *(ptdata+2);
473 *(ptbits++) = *(ptdata+1);
474 *(ptbits++) = *(ptdata );
475 ptdata += 3;
476 }
477 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
478 }
479 ::StretchDIBits( memdc, 0, origin, width, height,\
480 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
481 origin += height;
482 // if numDIB = 1, lines below can also be used
483 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
484 // The above line is equivalent to the following two lines.
485 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
486 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
487 // or the following lines
488 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
489 // HDC memdc = ::CreateCompatibleDC( hdc );
490 // ::SelectObject( memdc, hbitmap);
491 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
492 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
493 // ::SelectObject( memdc, 0 );
494 // ::DeleteDC( memdc );
495 }
496 SetHBITMAP( (WXHBITMAP) hbitmap );
497
498 if (hOldPalette)
499 SelectPalette(memdc, hOldPalette, FALSE);
500
501 // similarly, created an mono-bitmap for the possible mask
502 if( image.HasMask() )
503 {
504 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
505 HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
506 if( numDIB == 1 ) height = bmpHeight;
507 else height = sizeLimit/bytePerLine;
508 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
509 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
510 origin = 0;
511 unsigned char r = image.GetMaskRed();
512 unsigned char g = image.GetMaskGreen();
513 unsigned char b = image.GetMaskBlue();
514 unsigned char zero = 0, one = 255;
515 ptdata = data;
516 for( n=0; n<numDIB; n++ )
517 {
518 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
519 {
520 // redefine height and size of the (possibly) last smaller DIB
521 // memory is not reallocated
522 height = hRemain;
523 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
524 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
525 }
526 ptbits = lpBits;
527 for( int j=0; j<height; j++ )
528 {
529 for(i=0; i<width; i++ )
530 {
531 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
532 unsigned char cr = (*(ptdata++)) ;
533 unsigned char cg = (*(ptdata++)) ;
534 unsigned char cb = (*(ptdata++)) ;
535
536 if( ( cr !=r) || (cg!=g) || (cb!=b) )
537 {
538 *(ptbits++) = one;
539 *(ptbits++) = one;
540 *(ptbits++) = one;
541 }
542 else
543 {
544 *(ptbits++) = zero;
545 *(ptbits++) = zero;
546 *(ptbits++) = zero;
547 }
548 }
549 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
550 }
551 ::StretchDIBits( memdc, 0, origin, width, height,\
552 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
553 origin += height;
554 }
555 // create a wxMask object
556 wxMask *mask = new wxMask();
557 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
558 SetMask( mask );
559 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
560 /* The following can also be used but is slow to run
561 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
562 wxMask *mask = new wxMask( *this, colour );
563 SetMask( mask );
564 */
565
566 ::SelectObject( memdc, hbmpOld );
567 }
568
569 // free allocated resources
570 ::DeleteDC( memdc );
571 ::ReleaseDC(NULL, hdc);
572 free(lpDIBh);
573 free(lpBits);
574
575 #if WXWIN_COMPATIBILITY_2
576 // check the wxBitmap object
577 GetBitmapData()->SetOk();
578 #endif // WXWIN_COMPATIBILITY_2
579
580 if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
581
582 return TRUE;
583 }
584
585 wxImage wxBitmap::ConvertToImage() const
586 {
587 wxImage image;
588
589 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
590
591 // create an wxImage object
592 int width = GetWidth();
593 int height = GetHeight();
594 image.Create( width, height );
595 unsigned char *data = image.GetData();
596 if( !data )
597 {
598 wxFAIL_MSG( wxT("could not allocate data for image") );
599 return wxNullImage;
600 }
601
602 // calc the number of bytes per scanline and padding in the DIB
603 int bytePerLine = width*3;
604 int sizeDWORD = sizeof( DWORD );
605 int lineBoundary = bytePerLine % sizeDWORD;
606 int padding = 0;
607 if( lineBoundary > 0 )
608 {
609 padding = sizeDWORD - lineBoundary;
610 bytePerLine += padding;
611 }
612
613 // create a DIB header
614 int headersize = sizeof(BITMAPINFOHEADER);
615 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
616 if( !lpDIBh )
617 {
618 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
619 free( data );
620 return wxNullImage;
621 }
622 // Fill in the DIB header
623 lpDIBh->bmiHeader.biSize = headersize;
624 lpDIBh->bmiHeader.biWidth = width;
625 lpDIBh->bmiHeader.biHeight = -height;
626 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
627 lpDIBh->bmiHeader.biPlanes = 1;
628 lpDIBh->bmiHeader.biBitCount = 24;
629 lpDIBh->bmiHeader.biCompression = BI_RGB;
630 lpDIBh->bmiHeader.biClrUsed = 0;
631 // These seem not really needed for our purpose here.
632 lpDIBh->bmiHeader.biClrImportant = 0;
633 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
634 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
635 // memory for DIB data
636 unsigned char *lpBits;
637 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
638 if( !lpBits )
639 {
640 wxFAIL_MSG( wxT("could not allocate data for DIB") );
641 free( data );
642 free( lpDIBh );
643 return wxNullImage;
644 }
645
646 // copy data from the device-dependent bitmap to the DIB
647 HDC hdc = ::GetDC(NULL);
648 HBITMAP hbitmap;
649 hbitmap = (HBITMAP) GetHBITMAP();
650 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
651
652 // copy DIB data into the wxImage object
653 int i, j;
654 unsigned char *ptdata = data;
655 unsigned char *ptbits = lpBits;
656 for( i=0; i<height; i++ )
657 {
658 for( j=0; j<width; j++ )
659 {
660 *(ptdata++) = *(ptbits+2);
661 *(ptdata++) = *(ptbits+1);
662 *(ptdata++) = *(ptbits );
663 ptbits += 3;
664 }
665 ptbits += padding;
666 }
667
668 // similarly, set data according to the possible mask bitmap
669 if( GetMask() && GetMask()->GetMaskBitmap() )
670 {
671 hbitmap = (HBITMAP) GetMask()->GetMaskBitmap();
672 // memory DC created, color set, data copied, and memory DC deleted
673 HDC memdc = ::CreateCompatibleDC( hdc );
674 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
675 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
676 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
677 ::DeleteDC( memdc );
678 // background color set to RGB(16,16,16) in consistent with wxGTK
679 unsigned char r=16, g=16, b=16;
680 ptdata = data;
681 ptbits = lpBits;
682 for( i=0; i<height; i++ )
683 {
684 for( j=0; j<width; j++ )
685 {
686 if( *ptbits != 0 )
687 ptdata += 3;
688 else
689 {
690 *(ptdata++) = r;
691 *(ptdata++) = g;
692 *(ptdata++) = b;
693 }
694 ptbits += 3;
695 }
696 ptbits += padding;
697 }
698 image.SetMaskColour( r, g, b );
699 image.SetMask( TRUE );
700 }
701 else
702 {
703 image.SetMask( FALSE );
704 }
705 // free allocated resources
706 ::ReleaseDC(NULL, hdc);
707 free(lpDIBh);
708 free(lpBits);
709
710 return image;
711 }
712
713 #endif // wxUSE_IMAGE
714
715 bool wxBitmap::LoadFile(const wxString& filename, long type)
716 {
717 UnRef();
718
719 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
720
721 if ( handler )
722 {
723 m_refData = new wxBitmapRefData;
724
725 return handler->LoadFile(this, filename, type, -1, -1);
726 }
727 #if wxUSE_IMAGE
728 else
729 {
730 wxImage image;
731 if ( image.LoadFile( filename, type ) && image.Ok() )
732 {
733 *this = image.ConvertToBitmap();
734
735 return TRUE;
736 }
737 }
738 #endif // wxUSE_IMAGE
739
740 return FALSE;
741 }
742
743 bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
744 {
745 UnRef();
746
747 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
748
749 if ( !handler )
750 {
751 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %d defined."), type);
752
753 return FALSE;
754 }
755
756 m_refData = new wxBitmapRefData;
757
758 return handler->Create(this, data, type, width, height, depth);
759 }
760
761 bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette)
762 {
763 wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);
764
765 if ( handler )
766 {
767 return handler->SaveFile(this, filename, type, palette);
768 }
769 #if wxUSE_IMAGE
770 else
771 {
772 // FIXME what about palette? shouldn't we use it?
773 wxImage image( *this );
774 if ( image.Ok() )
775 {
776 return image.SaveFile(filename, type);
777 }
778 }
779 #endif // wxUSE_IMAGE
780
781 return FALSE;
782 }
783
784 // ----------------------------------------------------------------------------
785 // sub bitmap extraction
786 // ----------------------------------------------------------------------------
787
788 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
789 {
790 wxCHECK_MSG( Ok() &&
791 (rect.x >= 0) && (rect.y >= 0) &&
792 (rect.x+rect.width <= GetWidth()) &&
793 (rect.y+rect.height <= GetHeight()),
794 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
795
796 wxBitmap ret( rect.width, rect.height, GetDepth() );
797 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
798
799 // copy bitmap data
800 HDC dcSrc = ::CreateCompatibleDC(NULL);
801 HDC dcDst = ::CreateCompatibleDC(NULL);
802 SelectObject(dcSrc, (HBITMAP) GetHBITMAP());
803 SelectObject(dcDst, (HBITMAP) ret.GetHBITMAP());
804 BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY);
805
806 // copy mask if there is one
807 if (GetMask())
808 {
809 HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);
810
811 SelectObject(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap());
812 SelectObject(dcDst, (HBITMAP) hbmpMask);
813 BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY);
814
815 wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
816 ret.SetMask(mask);
817 }
818
819 SelectObject(dcDst, NULL);
820 SelectObject(dcSrc, NULL);
821 DeleteDC(dcDst);
822 DeleteDC(dcSrc);
823
824 return ret;
825 }
826
827 // ----------------------------------------------------------------------------
828 // wxBitmap accessors
829 // ----------------------------------------------------------------------------
830
831 void wxBitmap::SetQuality(int q)
832 {
833 EnsureHasData();
834
835 GetBitmapData()->m_quality = q;
836 }
837
838 #if WXWIN_COMPATIBILITY_2
839 void wxBitmap::SetOk(bool isOk)
840 {
841 EnsureHasData();
842
843 GetBitmapData()->m_ok = isOk;
844 }
845 #endif // WXWIN_COMPATIBILITY_2
846
847 void wxBitmap::SetPalette(const wxPalette& palette)
848 {
849 EnsureHasData();
850
851 GetBitmapData()->m_bitmapPalette = palette;
852 }
853
854 void wxBitmap::SetMask(wxMask *mask)
855 {
856 EnsureHasData();
857
858 GetBitmapData()->m_bitmapMask = mask;
859 }
860
861 // Creates a bitmap that matches the device context, from
862 // an arbitray bitmap. At present, the original bitmap must have an
863 // associated palette. TODO: use a default palette if no palette exists.
864 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
865 wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const
866 {
867 wxMemoryDC memDC;
868 wxBitmap tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth());
869 HPALETTE hPal = (HPALETTE) NULL;
870 LPBITMAPINFO lpDib;
871 void *lpBits = (void*) NULL;
872
873 if( GetPalette() && GetPalette()->Ok() )
874 {
875 tmpBitmap.SetPalette(*GetPalette());
876 memDC.SelectObject(tmpBitmap);
877 memDC.SetPalette(*GetPalette());
878 hPal = (HPALETTE)GetPalette()->GetHPALETTE();
879 }
880 else
881 {
882 hPal = (HPALETTE) ::GetStockObject(DEFAULT_PALETTE);
883 wxPalette palette;
884 palette.SetHPALETTE( (WXHPALETTE)hPal );
885 tmpBitmap.SetPalette( palette );
886 memDC.SelectObject(tmpBitmap);
887 memDC.SetPalette( palette );
888 }
889
890 // set the height negative because in a DIB the order of the lines is
891 // reversed
892 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal, &lpDib) )
893 {
894 return wxNullBitmap;
895 }
896
897 lpBits = malloc(lpDib->bmiHeader.biSizeImage);
898
899 ::GetBitmapBits(GetHbitmap(), lpDib->bmiHeader.biSizeImage, lpBits);
900
901 ::SetDIBitsToDevice(GetHdcOf(memDC), 0, 0,
902 GetWidth(), GetHeight(),
903 0, 0, 0, GetHeight(),
904 lpBits, lpDib, DIB_RGB_COLORS);
905
906 free(lpBits);
907
908 wxFreeDIB(lpDib);
909
910 return tmpBitmap;
911 }
912
913 // ----------------------------------------------------------------------------
914 // wxMask
915 // ----------------------------------------------------------------------------
916
917 wxMask::wxMask()
918 {
919 m_maskBitmap = 0;
920 }
921
922 // Construct a mask from a bitmap and a colour indicating
923 // the transparent area
924 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
925 {
926 m_maskBitmap = 0;
927 Create(bitmap, colour);
928 }
929
930 // Construct a mask from a bitmap and a palette index indicating
931 // the transparent area
932 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
933 {
934 m_maskBitmap = 0;
935 Create(bitmap, paletteIndex);
936 }
937
938 // Construct a mask from a mono bitmap (copies the bitmap).
939 wxMask::wxMask(const wxBitmap& bitmap)
940 {
941 m_maskBitmap = 0;
942 Create(bitmap);
943 }
944
945 wxMask::~wxMask()
946 {
947 if ( m_maskBitmap )
948 ::DeleteObject((HBITMAP) m_maskBitmap);
949 }
950
951 // Create a mask from a mono bitmap (copies the bitmap).
952 bool wxMask::Create(const wxBitmap& bitmap)
953 {
954 wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, FALSE,
955 _T("can't create mask from invalid or not monochrome bitmap") );
956
957 if ( m_maskBitmap )
958 {
959 ::DeleteObject((HBITMAP) m_maskBitmap);
960 m_maskBitmap = 0;
961 }
962
963 m_maskBitmap = (WXHBITMAP) CreateBitmap(
964 bitmap.GetWidth(),
965 bitmap.GetHeight(),
966 1, 1, 0
967 );
968 HDC srcDC = CreateCompatibleDC(0);
969 SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
970 HDC destDC = CreateCompatibleDC(0);
971 SelectObject(destDC, (HBITMAP) m_maskBitmap);
972 BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY);
973 SelectObject(srcDC, 0);
974 DeleteDC(srcDC);
975 SelectObject(destDC, 0);
976 DeleteDC(destDC);
977 return TRUE;
978 }
979
980 // Create a mask from a bitmap and a palette index indicating
981 // the transparent area
982 bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
983 {
984 if ( m_maskBitmap )
985 {
986 ::DeleteObject((HBITMAP) m_maskBitmap);
987 m_maskBitmap = 0;
988 }
989 if (bitmap.Ok() && bitmap.GetPalette()->Ok())
990 {
991 unsigned char red, green, blue;
992 if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue))
993 {
994 wxColour transparentColour(red, green, blue);
995 return Create(bitmap, transparentColour);
996 }
997 }
998 return FALSE;
999 }
1000
1001 // Create a mask from a bitmap and a colour indicating
1002 // the transparent area
1003 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
1004 {
1005 wxCHECK_MSG( bitmap.Ok(), FALSE, _T("invalid bitmap in wxMask::Create") );
1006
1007 if ( m_maskBitmap )
1008 {
1009 ::DeleteObject((HBITMAP) m_maskBitmap);
1010 m_maskBitmap = 0;
1011 }
1012
1013 int width = bitmap.GetWidth(),
1014 height = bitmap.GetHeight();
1015
1016 // scan the bitmap for the transparent colour and set the corresponding
1017 // pixels in the mask to BLACK and the rest to WHITE
1018 COLORREF maskColour = wxColourToRGB(colour);
1019 m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0);
1020
1021 HDC srcDC = ::CreateCompatibleDC(NULL);
1022 HDC destDC = ::CreateCompatibleDC(NULL);
1023 if ( !srcDC || !destDC )
1024 {
1025 wxLogLastError(wxT("CreateCompatibleDC"));
1026 }
1027
1028 bool ok = TRUE;
1029
1030 HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap));
1031 if ( !hbmpSrcOld )
1032 {
1033 wxLogLastError(wxT("SelectObject"));
1034
1035 ok = FALSE;
1036 }
1037
1038 HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap);
1039 if ( !hbmpDstOld )
1040 {
1041 wxLogLastError(wxT("SelectObject"));
1042
1043 ok = FALSE;
1044 }
1045
1046 // this is not very efficient, but I can't think of a better way of doing
1047 // it
1048 for ( int w = 0; ok && (w < width); w++ )
1049 {
1050 for ( int h = 0; ok && (h < height); h++ )
1051 {
1052 COLORREF col = GetPixel(srcDC, w, h);
1053 if ( col == CLR_INVALID )
1054 {
1055 wxLogLastError(wxT("GetPixel"));
1056
1057 // doesn't make sense to continue
1058 ok = FALSE;
1059
1060 break;
1061 }
1062
1063 if ( col == maskColour )
1064 {
1065 ::SetPixel(destDC, w, h, RGB(0, 0, 0));
1066 }
1067 else
1068 {
1069 ::SetPixel(destDC, w, h, RGB(255, 255, 255));
1070 }
1071 }
1072 }
1073
1074 ::SelectObject(srcDC, hbmpSrcOld);
1075 ::DeleteDC(srcDC);
1076 ::SelectObject(destDC, hbmpDstOld);
1077 ::DeleteDC(destDC);
1078
1079 return ok;
1080 }
1081
1082 // ----------------------------------------------------------------------------
1083 // wxBitmapHandler
1084 // ----------------------------------------------------------------------------
1085
1086 bool wxBitmapHandler::Create(wxGDIImage *image,
1087 void *data,
1088 long flags,
1089 int width, int height, int depth)
1090 {
1091 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1092
1093 return bitmap ? Create(bitmap, data, flags, width, height, depth) : FALSE;
1094 }
1095
1096 bool wxBitmapHandler::Load(wxGDIImage *image,
1097 const wxString& name,
1098 long flags,
1099 int width, int height)
1100 {
1101 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1102
1103 return bitmap ? LoadFile(bitmap, name, flags, width, height) : FALSE;
1104 }
1105
1106 bool wxBitmapHandler::Save(wxGDIImage *image,
1107 const wxString& name,
1108 int type)
1109 {
1110 wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
1111
1112 return bitmap ? SaveFile(bitmap, name, type) : FALSE;
1113 }
1114
1115 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap),
1116 void *WXUNUSED(data),
1117 long WXUNUSED(type),
1118 int WXUNUSED(width),
1119 int WXUNUSED(height),
1120 int WXUNUSED(depth))
1121 {
1122 return FALSE;
1123 }
1124
1125 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap),
1126 const wxString& WXUNUSED(name),
1127 long WXUNUSED(type),
1128 int WXUNUSED(desiredWidth),
1129 int WXUNUSED(desiredHeight))
1130 {
1131 return FALSE;
1132 }
1133
1134 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap),
1135 const wxString& WXUNUSED(name),
1136 int WXUNUSED(type),
1137 const wxPalette *WXUNUSED(palette))
1138 {
1139 return FALSE;
1140 }
1141
1142 // ----------------------------------------------------------------------------
1143 // DIB functions
1144 // ----------------------------------------------------------------------------
1145
1146 bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel,
1147 HPALETTE hPal, LPBITMAPINFO* lpDIBHeader)
1148 {
1149 unsigned long i, headerSize;
1150 LPBITMAPINFO lpDIBheader = NULL;
1151 LPPALETTEENTRY lpPe = NULL;
1152
1153
1154 // Allocate space for a DIB header
1155 headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY)));
1156 lpDIBheader = (BITMAPINFO *) malloc(headerSize);
1157 lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER));
1158
1159 GetPaletteEntries(hPal, 0, 256, lpPe);
1160
1161 memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER));
1162
1163 // Fill in the static parts of the DIB header
1164 lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1165 lpDIBheader->bmiHeader.biWidth = xSize;
1166 lpDIBheader->bmiHeader.biHeight = ySize;
1167 lpDIBheader->bmiHeader.biPlanes = 1;
1168
1169 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
1170 lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel);
1171 lpDIBheader->bmiHeader.biCompression = BI_RGB;
1172 lpDIBheader->bmiHeader.biSizeImage = xSize * abs(ySize) * bitsPerPixel >> 3;
1173 lpDIBheader->bmiHeader.biClrUsed = 256;
1174
1175
1176 // Initialize the DIB palette
1177 for (i = 0; i < 256; i++) {
1178 lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags;
1179 lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed;
1180 lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen;
1181 lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue;
1182 }
1183
1184 *lpDIBHeader = lpDIBheader;
1185
1186 return TRUE;
1187 }
1188
1189 void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
1190 {
1191 free(lpDIBHeader);
1192 }
1193
1194 // ----------------------------------------------------------------------------
1195 // other helper functions
1196 // ----------------------------------------------------------------------------
1197
1198 extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h)
1199 {
1200 wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") );
1201
1202 // get width/height from the bitmap if not given
1203 if ( !w || !h )
1204 {
1205 BITMAP bm;
1206 ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm);
1207 w = bm.bmWidth;
1208 h = bm.bmHeight;
1209 }
1210
1211 HDC hdcSrc = ::CreateCompatibleDC(NULL);
1212 HDC hdcDst = ::CreateCompatibleDC(NULL);
1213 if ( !hdcSrc || !hdcDst )
1214 {
1215 wxLogLastError(wxT("CreateCompatibleDC"));
1216 }
1217
1218 HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0);
1219 if ( !hbmpInvMask )
1220 {
1221 wxLogLastError(wxT("CreateBitmap"));
1222 }
1223
1224 ::SelectObject(hdcSrc, hbmpMask);
1225 ::SelectObject(hdcDst, hbmpInvMask);
1226 if ( !::BitBlt(hdcDst, 0, 0, w, h,
1227 hdcSrc, 0, 0,
1228 NOTSRCCOPY) )
1229 {
1230 wxLogLastError(wxT("BitBlt"));
1231 }
1232
1233 ::DeleteDC(hdcSrc);
1234 ::DeleteDC(hdcDst);
1235
1236 return hbmpInvMask;
1237 }