]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "bitmap.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
37 #include "wx/palette.h"
38 #include "wx/dcmemory.h"
39 #include "wx/bitmap.h"
43 #include "wx/msw/private.h"
46 #include "wx/msw/dib.h"
49 // missing from mingw32 header
51 #define CLR_INVALID ((COLORREF)-1)
52 #endif // no CLR_INVALID
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
59 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
61 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
63 // ============================================================================
65 // ============================================================================
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
71 wxBitmapRefData::wxBitmapRefData()
74 m_selectedInto
= NULL
;
77 m_hBitmap
= (WXHBITMAP
) NULL
;
80 void wxBitmapRefData::Free()
82 wxASSERT_MSG( !m_selectedInto
,
83 wxT("deleting bitmap still selected into wxMemoryDC") );
87 if ( !::DeleteObject((HBITMAP
)m_hBitmap
) )
89 wxLogLastError(wxT("DeleteObject(hbitmap)"));
97 // ----------------------------------------------------------------------------
99 // ----------------------------------------------------------------------------
101 // this function should be called from all wxBitmap ctors
102 void wxBitmap::Init()
104 // m_refData = NULL; done in the base class ctor
106 if ( wxTheBitmapList
)
107 wxTheBitmapList
->AddBitmap(this);
112 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage
& icon
)
114 // it may be either HICON or HCURSOR
115 HICON hicon
= (HICON
)icon
.GetHandle();
118 if ( !::GetIconInfo(hicon
, &iconInfo
) )
120 wxLogLastError(wxT("GetIconInfo"));
125 wxBitmapRefData
*refData
= new wxBitmapRefData
;
128 int w
= icon
.GetWidth(),
129 h
= icon
.GetHeight();
131 refData
->m_width
= w
;
132 refData
->m_height
= h
;
133 refData
->m_depth
= wxDisplayDepth();
135 refData
->m_hBitmap
= (WXHBITMAP
)iconInfo
.hbmColor
;
137 // the mask returned by GetIconInfo() is inversed compared to the usual
139 refData
->m_bitmapMask
= new wxMask((WXHBITMAP
)
140 wxInvertMask(iconInfo
.hbmMask
, w
, h
));
142 #if WXWIN_COMPATIBILITY_2
143 refData
->m_ok
= TRUE
;
144 #endif // WXWIN_COMPATIBILITY_2
151 bool wxBitmap::CopyFromCursor(const wxCursor
& cursor
)
159 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
163 return CopyFromIconOrCursor(cursor
);
167 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
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
178 int width
= icon
.GetWidth(),
179 height
= icon
.GetHeight();
181 // copy the icon to the bitmap
183 HDC hdc
= ::CreateCompatibleDC(hdcScreen
);
184 HBITMAP hbitmap
= ::CreateCompatibleBitmap(hdcScreen
, width
, height
);
185 HBITMAP hbmpOld
= (HBITMAP
)::SelectObject(hdc
, hbitmap
);
187 ::DrawIcon(hdc
, 0, 0, GetHiconOf(icon
));
189 ::SelectObject(hdc
, hbmpOld
);
192 wxBitmapRefData
*refData
= new wxBitmapRefData
;
195 refData
->m_width
= width
;
196 refData
->m_height
= height
;
197 refData
->m_depth
= wxDisplayDepth();
199 refData
->m_hBitmap
= (WXHBITMAP
)hbitmap
;
201 #if WXWIN_COMPATIBILITY_2
202 refData
->m_ok
= TRUE
;
203 #endif // WXWIN_COMPATIBILITY_2
207 return CopyFromIconOrCursor(icon
);
208 #endif // Win16/Win32
211 wxBitmap::~wxBitmap()
214 wxTheBitmapList
->DeleteObject(this);
217 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
221 wxBitmapRefData
*refData
= new wxBitmapRefData
;
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
;
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
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
;
243 for ( int rows
= 0; rows
< height
; rows
++ )
245 for ( size_t cols
= 0; cols
< bytesPerLine
; cols
++ )
247 unsigned char val
= *src
++;
248 unsigned char reversed
= 0;
250 for ( int bits
= 0; bits
< 8; bits
++)
253 reversed
|= (val
& 0x01);
265 // bits should already be in Windows standard format
266 data
= (char *)bits
; // const_cast is harmless
269 HBITMAP hbmp
= ::CreateBitmap(width
, height
, 1, depth
, data
);
272 wxLogLastError(wxT("CreateBitmap"));
280 SetHBITMAP((WXHBITMAP
)hbmp
);
283 // Create from XPM data
284 bool wxBitmap::CreateFromXpm(const char **data
)
288 return Create((void *)data
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
291 wxBitmap::wxBitmap(int w
, int h
, int d
)
295 (void)Create(w
, h
, d
);
298 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
302 (void)Create(data
, type
, width
, height
, depth
);
305 wxBitmap::wxBitmap(const wxString
& filename
, long type
)
309 LoadFile(filename
, (int)type
);
312 bool wxBitmap::Create(int w
, int h
, int d
)
316 m_refData
= new wxBitmapRefData
;
318 GetBitmapData()->m_width
= w
;
319 GetBitmapData()->m_height
= h
;
320 GetBitmapData()->m_depth
= d
;
326 hbmp
= ::CreateBitmap(w
, h
, 1, d
, NULL
);
329 wxLogLastError(wxT("CreateBitmap"));
335 hbmp
= ::CreateCompatibleBitmap(dc
, w
, h
);
338 wxLogLastError(wxT("CreateCompatibleBitmap"));
341 GetBitmapData()->m_depth
= wxDisplayDepth();
344 SetHBITMAP((WXHBITMAP
)hbmp
);
346 #if WXWIN_COMPATIBILITY_2
347 GetBitmapData()->m_ok
= hbmp
!= 0;
348 #endif // WXWIN_COMPATIBILITY_2
353 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
357 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
361 m_refData
= new wxBitmapRefData
;
363 return handler
->LoadFile(this, filename
, type
, -1, -1);
368 if ( !image
.LoadFile( filename
, type
) || !image
.Ok() )
371 *this = image
.ConvertToBitmap();
377 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
381 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
385 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %d defined."), type
);
390 m_refData
= new wxBitmapRefData
;
392 return handler
->Create(this, data
, type
, width
, height
, depth
);
395 bool wxBitmap::SaveFile(const wxString
& filename
, int type
, const wxPalette
*palette
)
397 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
401 return handler
->SaveFile(this, filename
, type
, palette
);
405 // FIXME what about palette? shouldn't we use it?
406 wxImage
image( *this );
410 return image
.SaveFile( filename
, type
);
414 // ----------------------------------------------------------------------------
415 // sub bitmap extraction
416 // ----------------------------------------------------------------------------
418 wxBitmap
wxBitmap::GetSubBitmap( const wxRect
& rect
) const
421 (rect
.x
>= 0) && (rect
.y
>= 0) &&
422 (rect
.x
+rect
.width
<= GetWidth()) &&
423 (rect
.y
+rect
.height
<= GetHeight()),
424 wxNullBitmap
, wxT("Invalid bitmap or bitmap region") );
426 wxBitmap
ret( rect
.width
, rect
.height
, GetDepth() );
427 wxASSERT_MSG( ret
.Ok(), wxT("GetSubBitmap error") );
430 HDC dcSrc
= ::CreateCompatibleDC(NULL
);
431 HDC dcDst
= ::CreateCompatibleDC(NULL
);
432 SelectObject(dcSrc
, (HBITMAP
) GetHBITMAP());
433 SelectObject(dcDst
, (HBITMAP
) ret
.GetHBITMAP());
434 BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
, dcSrc
, rect
.x
, rect
.y
, SRCCOPY
);
436 // copy mask if there is one
439 HBITMAP hbmpMask
= ::CreateBitmap(rect
.width
, rect
.height
, 1, 1, 0);
441 SelectObject(dcSrc
, (HBITMAP
) GetMask()->GetMaskBitmap());
442 SelectObject(dcDst
, (HBITMAP
) hbmpMask
);
443 BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
, dcSrc
, rect
.x
, rect
.y
, SRCCOPY
);
445 wxMask
*mask
= new wxMask((WXHBITMAP
) hbmpMask
);
449 SelectObject(dcDst
, NULL
);
450 SelectObject(dcSrc
, NULL
);
457 // ----------------------------------------------------------------------------
458 // wxBitmap accessors
459 // ----------------------------------------------------------------------------
461 void wxBitmap::SetQuality(int q
)
465 GetBitmapData()->m_quality
= q
;
468 #if WXWIN_COMPATIBILITY_2
469 void wxBitmap::SetOk(bool isOk
)
473 GetBitmapData()->m_ok
= isOk
;
475 #endif // WXWIN_COMPATIBILITY_2
477 void wxBitmap::SetPalette(const wxPalette
& palette
)
481 GetBitmapData()->m_bitmapPalette
= palette
;
484 void wxBitmap::SetMask(wxMask
*mask
)
488 GetBitmapData()->m_bitmapMask
= mask
;
491 // Creates a bitmap that matches the device context, from
492 // an arbitray bitmap. At present, the original bitmap must have an
493 // associated palette. TODO: use a default palette if no palette exists.
494 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
495 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
498 wxBitmap
tmpBitmap(GetWidth(), GetHeight(), dc
.GetDepth());
499 HPALETTE hPal
= (HPALETTE
) NULL
;
501 void *lpBits
= (void*) NULL
;
503 if( GetPalette() && GetPalette()->Ok() )
505 tmpBitmap
.SetPalette(*GetPalette());
506 memDC
.SelectObject(tmpBitmap
);
507 memDC
.SetPalette(*GetPalette());
508 hPal
= (HPALETTE
)GetPalette()->GetHPALETTE();
512 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
514 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
515 tmpBitmap
.SetPalette( palette
);
516 memDC
.SelectObject(tmpBitmap
);
517 memDC
.SetPalette( palette
);
520 // set the height negative because in a DIB the order of the lines is
522 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal
, &lpDib
) )
527 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
529 ::GetBitmapBits(GetHbitmap(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
531 ::SetDIBitsToDevice(GetHdcOf(memDC
), 0, 0,
532 GetWidth(), GetHeight(),
533 0, 0, 0, GetHeight(),
534 lpBits
, lpDib
, DIB_RGB_COLORS
);
543 // ----------------------------------------------------------------------------
545 // ----------------------------------------------------------------------------
552 // Construct a mask from a bitmap and a colour indicating
553 // the transparent area
554 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
557 Create(bitmap
, colour
);
560 // Construct a mask from a bitmap and a palette index indicating
561 // the transparent area
562 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
565 Create(bitmap
, paletteIndex
);
568 // Construct a mask from a mono bitmap (copies the bitmap).
569 wxMask::wxMask(const wxBitmap
& bitmap
)
578 ::DeleteObject((HBITMAP
) m_maskBitmap
);
581 // Create a mask from a mono bitmap (copies the bitmap).
582 bool wxMask::Create(const wxBitmap
& bitmap
)
584 wxCHECK_MSG( bitmap
.Ok() && bitmap
.GetDepth() == 1, FALSE
,
585 _T("can't create mask from invalid or not monochrome bitmap") );
589 ::DeleteObject((HBITMAP
) m_maskBitmap
);
593 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
598 HDC srcDC
= CreateCompatibleDC(0);
599 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
600 HDC destDC
= CreateCompatibleDC(0);
601 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
602 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
603 SelectObject(srcDC
, 0);
605 SelectObject(destDC
, 0);
610 // Create a mask from a bitmap and a palette index indicating
611 // the transparent area
612 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
616 ::DeleteObject((HBITMAP
) m_maskBitmap
);
619 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
621 unsigned char red
, green
, blue
;
622 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
624 wxColour
transparentColour(red
, green
, blue
);
625 return Create(bitmap
, transparentColour
);
631 // Create a mask from a bitmap and a colour indicating
632 // the transparent area
633 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
635 wxCHECK_MSG( bitmap
.Ok(), FALSE
, _T("invalid bitmap in wxMask::Create") );
639 ::DeleteObject((HBITMAP
) m_maskBitmap
);
643 int width
= bitmap
.GetWidth(),
644 height
= bitmap
.GetHeight();
646 // scan the bitmap for the transparent colour and set the corresponding
647 // pixels in the mask to BLACK and the rest to WHITE
648 COLORREF maskColour
= wxColourToRGB(colour
);
649 m_maskBitmap
= (WXHBITMAP
)::CreateBitmap(width
, height
, 1, 1, 0);
651 HDC srcDC
= ::CreateCompatibleDC(NULL
);
652 HDC destDC
= ::CreateCompatibleDC(NULL
);
653 if ( !srcDC
|| !destDC
)
655 wxLogLastError(wxT("CreateCompatibleDC"));
660 HGDIOBJ hbmpSrcOld
= ::SelectObject(srcDC
, GetHbitmapOf(bitmap
));
663 wxLogLastError(wxT("SelectObject"));
668 HGDIOBJ hbmpDstOld
= ::SelectObject(destDC
, (HBITMAP
)m_maskBitmap
);
671 wxLogLastError(wxT("SelectObject"));
676 // this is not very efficient, but I can't think of a better way of doing
678 for ( int w
= 0; ok
&& (w
< width
); w
++ )
680 for ( int h
= 0; ok
&& (h
< height
); h
++ )
682 COLORREF col
= GetPixel(srcDC
, w
, h
);
683 if ( col
== CLR_INVALID
)
685 wxLogLastError(wxT("GetPixel"));
687 // doesn't make sense to continue
693 if ( col
== maskColour
)
695 ::SetPixel(destDC
, w
, h
, RGB(0, 0, 0));
699 ::SetPixel(destDC
, w
, h
, RGB(255, 255, 255));
704 ::SelectObject(srcDC
, hbmpSrcOld
);
706 ::SelectObject(destDC
, hbmpDstOld
);
712 // ----------------------------------------------------------------------------
714 // ----------------------------------------------------------------------------
716 bool wxBitmapHandler::Create(wxGDIImage
*image
,
719 int width
, int height
, int depth
)
721 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
723 return bitmap
? Create(bitmap
, data
, flags
, width
, height
, depth
) : FALSE
;
726 bool wxBitmapHandler::Load(wxGDIImage
*image
,
727 const wxString
& name
,
729 int width
, int height
)
731 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
733 return bitmap
? LoadFile(bitmap
, name
, flags
, width
, height
) : FALSE
;
736 bool wxBitmapHandler::Save(wxGDIImage
*image
,
737 const wxString
& name
,
740 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
742 return bitmap
? SaveFile(bitmap
, name
, type
) : FALSE
;
745 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
),
746 void *WXUNUSED(data
),
749 int WXUNUSED(height
),
755 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
),
756 const wxString
& WXUNUSED(name
),
758 int WXUNUSED(desiredWidth
),
759 int WXUNUSED(desiredHeight
))
764 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
),
765 const wxString
& WXUNUSED(name
),
767 const wxPalette
*WXUNUSED(palette
))
772 // ----------------------------------------------------------------------------
774 // ----------------------------------------------------------------------------
776 bool wxCreateDIB(long xSize
, long ySize
, long bitsPerPixel
,
777 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
779 unsigned long i
, headerSize
;
780 LPBITMAPINFO lpDIBheader
= NULL
;
781 LPPALETTEENTRY lpPe
= NULL
;
784 // Allocate space for a DIB header
785 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
786 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
787 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
789 GetPaletteEntries(hPal
, 0, 256, lpPe
);
791 memset(lpDIBheader
, 0x00, sizeof(BITMAPINFOHEADER
));
793 // Fill in the static parts of the DIB header
794 lpDIBheader
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
795 lpDIBheader
->bmiHeader
.biWidth
= xSize
;
796 lpDIBheader
->bmiHeader
.biHeight
= ySize
;
797 lpDIBheader
->bmiHeader
.biPlanes
= 1;
799 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
800 lpDIBheader
->bmiHeader
.biBitCount
= (WORD
)(bitsPerPixel
);
801 lpDIBheader
->bmiHeader
.biCompression
= BI_RGB
;
802 lpDIBheader
->bmiHeader
.biSizeImage
= xSize
* abs(ySize
) * bitsPerPixel
>> 3;
803 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
806 // Initialize the DIB palette
807 for (i
= 0; i
< 256; i
++) {
808 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
809 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
810 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
811 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
814 *lpDIBHeader
= lpDIBheader
;
819 void wxFreeDIB(LPBITMAPINFO lpDIBHeader
)
824 // ----------------------------------------------------------------------------
825 // other helper functions
826 // ----------------------------------------------------------------------------
828 extern HBITMAP
wxInvertMask(HBITMAP hbmpMask
, int w
, int h
)
830 wxCHECK_MSG( hbmpMask
, 0, _T("invalid bitmap in wxInvertMask") );
832 // get width/height from the bitmap if not given
836 ::GetObject(hbmpMask
, sizeof(BITMAP
), (LPVOID
)&bm
);
841 HDC hdcSrc
= ::CreateCompatibleDC(NULL
);
842 HDC hdcDst
= ::CreateCompatibleDC(NULL
);
843 if ( !hdcSrc
|| !hdcDst
)
845 wxLogLastError(wxT("CreateCompatibleDC"));
848 HBITMAP hbmpInvMask
= ::CreateBitmap(w
, h
, 1, 1, 0);
851 wxLogLastError(wxT("CreateBitmap"));
854 ::SelectObject(hdcSrc
, hbmpMask
);
855 ::SelectObject(hdcDst
, hbmpInvMask
);
856 if ( !::BitBlt(hdcDst
, 0, 0, w
, h
,
860 wxLogLastError(wxT("BitBlt"));