]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/bitmap.cpp
6737631938fc25fd9f0113dcf43f97971fcba6a3
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 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
54 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
56 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
58 // ============================================================================
60 // ============================================================================
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 wxBitmapRefData::wxBitmapRefData()
69 m_selectedInto
= NULL
;
72 m_hBitmap
= (WXHBITMAP
) NULL
;
75 void wxBitmapRefData::Free()
77 wxASSERT_MSG( !m_selectedInto
,
78 wxT("deleting bitmap still selected into wxMemoryDC") );
82 if ( !::DeleteObject((HBITMAP
)m_hBitmap
) )
84 wxLogLastError("DeleteObject(hbitmap)");
92 // ----------------------------------------------------------------------------
94 // ----------------------------------------------------------------------------
96 // this function should be called from all wxBitmap ctors
99 // m_refData = NULL; done in the base class ctor
101 if ( wxTheBitmapList
)
102 wxTheBitmapList
->AddBitmap(this);
107 bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage
& icon
)
109 // it may be either HICON or HCURSOR
110 HICON hicon
= (HICON
)icon
.GetHandle();
113 if ( !::GetIconInfo(hicon
, &iconInfo
) )
115 wxLogLastError("GetIconInfo");
120 wxBitmapRefData
*refData
= new wxBitmapRefData
;
123 int w
= icon
.GetWidth(),
124 h
= icon
.GetHeight();
126 refData
->m_width
= w
;
127 refData
->m_height
= h
;
128 refData
->m_depth
= wxDisplayDepth();
130 refData
->m_hBitmap
= (WXHBITMAP
)iconInfo
.hbmColor
;
132 // the mask returned by GetIconInfo() is inversed compared to the usual
134 HBITMAP hbmpMask
= ::CreateBitmap(w
, h
, 1, 1, 0);
136 // the icons mask is opposite to the usual wxWin convention
137 HDC dcSrc
= ::CreateCompatibleDC(NULL
);
138 HDC dcDst
= ::CreateCompatibleDC(NULL
);
139 (void)SelectObject(dcSrc
, iconInfo
.hbmMask
);
140 (void)SelectObject(dcDst
, hbmpMask
);
142 HBRUSH brush
= ::CreateSolidBrush(RGB(255, 255, 255));
143 RECT rect
= { 0, 0, w
, h
};
144 FillRect(dcDst
, &rect
, brush
);
146 BitBlt(dcDst
, 0, 0, w
, h
, dcSrc
, 0, 0, SRCINVERT
);
148 SelectObject(dcDst
, NULL
);
149 SelectObject(dcSrc
, NULL
);
153 refData
->m_bitmapMask
= new wxMask((WXHBITMAP
)hbmpMask
);
155 #if WXWIN_COMPATIBILITY_2
156 refData
->m_ok
= TRUE
;
157 #endif // WXWIN_COMPATIBILITY_2
164 bool wxBitmap::CopyFromCursor(const wxCursor
& cursor
)
172 wxFAIL_MSG( _T("don't know how to convert cursor to bitmap") );
176 return CopyFromIconOrCursor(cursor
);
180 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
187 // GetIconInfo() doesn't exist under Win16 and I don't know any other way
188 // to create a bitmap from icon there - but using this way we won't have
191 int width
= icon
.GetWidth(),
192 height
= icon
.GetHeight();
194 // copy the icon to the bitmap
196 HDC hdc
= ::CreateCompatibleDC(hdcScreen
);
197 HBITMAP hbitmap
= ::CreateCompatibleBitmap(hdcScreen
, width
, height
);
198 HBITMAP hbmpOld
= (HBITMAP
)::SelectObject(hdc
, hbitmap
);
200 ::DrawIcon(hdc
, 0, 0, GetHiconOf(icon
));
202 ::SelectObject(hdc
, hbmpOld
);
205 wxBitmapRefData
*refData
= new wxBitmapRefData
;
208 refData
->m_width
= width
;
209 refData
->m_height
= height
;
210 refData
->m_depth
= wxDisplayDepth();
212 refData
->m_hBitmap
= (WXHBITMAP
)hbitmap
;
214 #if WXWIN_COMPATIBILITY_2
215 refData
->m_ok
= TRUE
;
216 #endif // WXWIN_COMPATIBILITY_2
220 return CopyFromIconOrCursor(icon
);
221 #endif // Win16/Win32
224 wxBitmap::~wxBitmap()
227 wxTheBitmapList
->DeleteObject(this);
230 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
234 wxBitmapRefData
*refData
= new wxBitmapRefData
;
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
;
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
249 static const size_t bytesPerLine
= (width
+ 7) / 8;
250 static const size_t padding
= bytesPerLine
% 2;
251 static const size_t len
= height
* ( padding
+ bytesPerLine
);
252 data
= (char *)malloc(len
);
253 const char *src
= bits
;
256 for ( int rows
= 0; rows
< height
; rows
++ )
258 for ( size_t cols
= 0; cols
< bytesPerLine
; cols
++ )
260 unsigned char val
= *src
++;
261 unsigned char reversed
= 0;
263 for ( int bits
= 0; bits
< 8; bits
++)
266 reversed
|= (val
& 0x01);
278 // bits should already be in Windows standard format
279 data
= (char *)bits
; // const_cast is harmless
282 HBITMAP hbmp
= ::CreateBitmap(width
, height
, 1, depth
, data
);
285 wxLogLastError("CreateBitmap");
293 SetHBITMAP((WXHBITMAP
)hbmp
);
297 wxBitmap
wxBitmap::GetSubBitmap( const wxRect
& rect
) const
300 (rect
.x
>= 0) && (rect
.y
>= 0) &&
301 (rect
.x
+rect
.width
<= GetWidth()) &&
302 (rect
.y
+rect
.height
<= GetHeight()),
303 wxNullBitmap
, wxT("Invalid bitmap or bitmap region") );
305 wxBitmap
ret( rect
.width
, rect
.height
, GetDepth() );
306 wxASSERT_MSG( ret
.Ok(), wxT("GetSubBitmap error") );
309 HDC dcSrc
= ::CreateCompatibleDC(NULL
);
310 HDC dcDst
= ::CreateCompatibleDC(NULL
);
311 SelectObject(dcSrc
, (HBITMAP
) GetHBITMAP());
312 SelectObject(dcDst
, (HBITMAP
) ret
.GetHBITMAP());
313 BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
, dcSrc
, rect
.x
, rect
.y
, SRCCOPY
);
315 // copy mask if there is one
318 HBITMAP hbmpMask
= ::CreateBitmap(rect
.width
, rect
.height
, 1, 1, 0);
320 SelectObject(dcSrc
, (HBITMAP
) GetMask()->GetMaskBitmap());
321 SelectObject(dcDst
, (HBITMAP
) hbmpMask
);
322 BitBlt(dcDst
, 0, 0, rect
.width
, rect
.height
, dcSrc
, rect
.x
, rect
.y
, SRCCOPY
);
324 wxMask
*mask
= new wxMask((WXHBITMAP
) hbmpMask
);
328 SelectObject(dcDst
, NULL
);
329 SelectObject(dcSrc
, NULL
);
336 // Create from XPM data
337 wxBitmap::wxBitmap(char **data
, wxControl
*WXUNUSED(anItem
))
341 (void)Create((void *)data
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
344 wxBitmap::wxBitmap(int w
, int h
, int d
)
348 (void)Create(w
, h
, d
);
351 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
355 (void)Create(data
, type
, width
, height
, depth
);
358 wxBitmap::wxBitmap(const wxString
& filename
, long type
)
362 LoadFile(filename
, (int)type
);
365 bool wxBitmap::Create(int w
, int h
, int d
)
369 m_refData
= new wxBitmapRefData
;
371 GetBitmapData()->m_width
= w
;
372 GetBitmapData()->m_height
= h
;
373 GetBitmapData()->m_depth
= d
;
379 hbmp
= ::CreateBitmap(w
, h
, 1, d
, NULL
);
382 wxLogLastError("CreateBitmap");
388 hbmp
= ::CreateCompatibleBitmap(dc
, w
, h
);
391 wxLogLastError("CreateCompatibleBitmap");
394 GetBitmapData()->m_depth
= wxDisplayDepth();
397 SetHBITMAP((WXHBITMAP
)hbmp
);
399 #if WXWIN_COMPATIBILITY_2
400 GetBitmapData()->m_ok
= hbmp
!= 0;
401 #endif // WXWIN_COMPATIBILITY_2
406 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
410 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
414 m_refData
= new wxBitmapRefData
;
416 return handler
->LoadFile(this, filename
, type
, -1, -1);
421 if ( !image
.LoadFile( filename
, type
) || !image
.Ok() )
424 *this = image
.ConvertToBitmap();
430 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
434 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
438 wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for "
439 "type %d defined."), type
);
444 m_refData
= new wxBitmapRefData
;
446 return handler
->Create(this, data
, type
, width
, height
, depth
);
449 bool wxBitmap::SaveFile(const wxString
& filename
, int type
, const wxPalette
*palette
)
451 wxBitmapHandler
*handler
= wxDynamicCast(FindHandler(type
), wxBitmapHandler
);
455 return handler
->SaveFile(this, filename
, type
, palette
);
459 // FIXME what about palette? shouldn't we use it?
460 wxImage
image( *this );
464 return image
.SaveFile( filename
, type
);
468 // ----------------------------------------------------------------------------
469 // wxBitmap accessors
470 // ----------------------------------------------------------------------------
472 void wxBitmap::SetQuality(int q
)
476 GetBitmapData()->m_quality
= q
;
479 #if WXWIN_COMPATIBILITY_2
480 void wxBitmap::SetOk(bool isOk
)
484 GetBitmapData()->m_ok
= isOk
;
486 #endif // WXWIN_COMPATIBILITY_2
488 void wxBitmap::SetPalette(const wxPalette
& palette
)
492 GetBitmapData()->m_bitmapPalette
= palette
;
495 void wxBitmap::SetMask(wxMask
*mask
)
499 GetBitmapData()->m_bitmapMask
= mask
;
502 // Creates a bitmap that matches the device context, from
503 // an arbitray bitmap. At present, the original bitmap must have an
504 // associated palette. TODO: use a default palette if no palette exists.
505 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
506 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
509 wxBitmap
tmpBitmap(this->GetWidth(), this->GetHeight(), dc
.GetDepth());
510 HPALETTE hPal
= (HPALETTE
) NULL
;
512 void *lpBits
= (void*) NULL
;
514 if( GetPalette() && GetPalette()->Ok() )
516 tmpBitmap
.SetPalette(*GetPalette());
517 memDC
.SelectObject(tmpBitmap
);
518 memDC
.SetPalette(*GetPalette());
519 hPal
= (HPALETTE
)GetPalette()->GetHPALETTE();
523 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
525 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
526 tmpBitmap
.SetPalette( palette
);
527 memDC
.SelectObject(tmpBitmap
);
528 memDC
.SetPalette( palette
);
531 // set the height negative because in a DIB the order of the lines is
533 if ( !wxCreateDIB(GetWidth(), -GetHeight(), GetDepth(), hPal
, &lpDib
) )
538 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
540 ::GetBitmapBits(GetHbitmap(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
542 ::SetDIBitsToDevice(GetHdcOf(memDC
), 0, 0,
543 GetWidth(), GetHeight(),
544 0, 0, 0, GetHeight(),
545 lpBits
, lpDib
, DIB_RGB_COLORS
);
554 // ----------------------------------------------------------------------------
556 // ----------------------------------------------------------------------------
563 // Construct a mask from a bitmap and a colour indicating
564 // the transparent area
565 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
568 Create(bitmap
, colour
);
571 // Construct a mask from a bitmap and a palette index indicating
572 // the transparent area
573 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
576 Create(bitmap
, paletteIndex
);
579 // Construct a mask from a mono bitmap (copies the bitmap).
580 wxMask::wxMask(const wxBitmap
& bitmap
)
589 ::DeleteObject((HBITMAP
) m_maskBitmap
);
592 // Create a mask from a mono bitmap (copies the bitmap).
593 bool wxMask::Create(const wxBitmap
& bitmap
)
597 ::DeleteObject((HBITMAP
) m_maskBitmap
);
600 if (!bitmap
.Ok() || bitmap
.GetDepth() != 1)
604 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
609 HDC srcDC
= CreateCompatibleDC(0);
610 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
611 HDC destDC
= CreateCompatibleDC(0);
612 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
613 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
614 SelectObject(srcDC
, 0);
616 SelectObject(destDC
, 0);
621 // Create a mask from a bitmap and a palette index indicating
622 // the transparent area
623 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
627 ::DeleteObject((HBITMAP
) m_maskBitmap
);
630 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
632 unsigned char red
, green
, blue
;
633 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
635 wxColour
transparentColour(red
, green
, blue
);
636 return Create(bitmap
, transparentColour
);
642 // Create a mask from a bitmap and a colour indicating
643 // the transparent area
644 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
648 ::DeleteObject((HBITMAP
) m_maskBitmap
);
656 // scan the bitmap for the transparent colour and set
657 // the corresponding pixels in the mask to BLACK and
659 COLORREF maskColour
= RGB(colour
.Red(), colour
.Green(), colour
.Blue());
660 m_maskBitmap
= (WXHBITMAP
) ::CreateBitmap(
665 HDC srcDC
= ::CreateCompatibleDC(0);
666 ::SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
667 HDC destDC
= ::CreateCompatibleDC(0);
668 ::SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
670 // this is not very efficient, but I can't think
671 // of a better way of doing it
672 for (int w
= 0; w
< bitmap
.GetWidth(); w
++)
674 for (int h
= 0; h
< bitmap
.GetHeight(); h
++)
676 COLORREF col
= GetPixel(srcDC
, w
, h
);
677 if (col
== maskColour
)
679 ::SetPixel(destDC
, w
, h
, RGB(0, 0, 0));
683 ::SetPixel(destDC
, w
, h
, RGB(255, 255, 255));
687 ::SelectObject(srcDC
, 0);
689 ::SelectObject(destDC
, 0);
694 // ----------------------------------------------------------------------------
696 // ----------------------------------------------------------------------------
698 bool wxBitmapHandler::Create(wxGDIImage
*image
,
701 int width
, int height
, int depth
)
703 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
705 return bitmap
? Create(bitmap
, data
, width
, height
, depth
) : FALSE
;
708 bool wxBitmapHandler::Load(wxGDIImage
*image
,
709 const wxString
& name
,
711 int width
, int height
)
713 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
715 return bitmap
? LoadFile(bitmap
, name
, flags
, width
, height
) : FALSE
;
718 bool wxBitmapHandler::Save(wxGDIImage
*image
,
719 const wxString
& name
,
722 wxBitmap
*bitmap
= wxDynamicCast(image
, wxBitmap
);
724 return bitmap
? SaveFile(bitmap
, name
, type
) : FALSE
;
727 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
),
728 void *WXUNUSED(data
),
731 int WXUNUSED(height
),
737 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
),
738 const wxString
& WXUNUSED(name
),
740 int WXUNUSED(desiredWidth
),
741 int WXUNUSED(desiredHeight
))
746 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
),
747 const wxString
& WXUNUSED(name
),
749 const wxPalette
*WXUNUSED(palette
))
754 // ----------------------------------------------------------------------------
756 // ----------------------------------------------------------------------------
758 bool wxCreateDIB(long xSize
, long ySize
, long bitsPerPixel
,
759 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
761 unsigned long i
, headerSize
;
762 LPBITMAPINFO lpDIBheader
= NULL
;
763 LPPALETTEENTRY lpPe
= NULL
;
766 // Allocate space for a DIB header
767 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
768 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
769 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
771 GetPaletteEntries(hPal
, 0, 256, lpPe
);
773 memset(lpDIBheader
, 0x00, sizeof(BITMAPINFOHEADER
));
775 // Fill in the static parts of the DIB header
776 lpDIBheader
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
777 lpDIBheader
->bmiHeader
.biWidth
= xSize
;
778 lpDIBheader
->bmiHeader
.biHeight
= ySize
;
779 lpDIBheader
->bmiHeader
.biPlanes
= 1;
781 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
782 lpDIBheader
->bmiHeader
.biBitCount
= (WORD
)(bitsPerPixel
);
783 lpDIBheader
->bmiHeader
.biCompression
= BI_RGB
;
784 lpDIBheader
->bmiHeader
.biSizeImage
= xSize
* abs(ySize
) * bitsPerPixel
>> 3;
785 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
788 // Initialize the DIB palette
789 for (i
= 0; i
< 256; i
++) {
790 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
791 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
792 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
793 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
796 *lpDIBHeader
= lpDIBheader
;
801 void wxFreeDIB(LPBITMAPINFO lpDIBHeader
)