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"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 #if !USE_SHARED_LIBRARIES
53 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
54 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
57 // ============================================================================
59 // ============================================================================
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
65 wxBitmapRefData::wxBitmapRefData()
73 m_selectedInto
= NULL
;
78 wxBitmapRefData::~wxBitmapRefData()
80 wxASSERT_MSG( !m_selectedInto
,
81 wxT("deleting bitmap still selected into wxMemoryDC") );
84 DeleteObject((HBITMAP
) m_hBitmap
);
90 // ----------------------------------------------------------------------------
92 // ----------------------------------------------------------------------------
94 wxList
wxBitmap::sm_handlers
;
98 if ( wxTheBitmapList
)
99 wxTheBitmapList
->AddBitmap(this);
102 wxBitmap::wxBitmap(const wxBitmap
& bitmap
)
104 wxIcon
*icon
= wxDynamicCast(&bitmap
, wxIcon
);
107 HDC hdc
= ::CreateCompatibleDC(NULL
); // screen DC
108 HBITMAP hbitmap
= ::CreateCompatibleBitmap(hdc
,
111 ::SelectObject(hdc
, hbitmap
);
112 ::DrawIcon(hdc
, 0, 0, (HICON
)icon
->GetHICON());
116 SetHBITMAP((WXHBITMAP
)hbitmap
);
123 if ( wxTheBitmapList
)
124 wxTheBitmapList
->AddBitmap(this);
127 wxBitmap::~wxBitmap()
130 wxTheBitmapList
->DeleteObject(this);
133 bool wxBitmap::FreeResource(bool WXUNUSED(force
))
138 wxASSERT_MSG( !M_BITMAPDATA
->m_selectedInto
,
139 wxT("freeing bitmap still selected into wxMemoryDC") );
141 if (M_BITMAPDATA
->m_hBitmap
)
143 DeleteObject((HBITMAP
) M_BITMAPDATA
->m_hBitmap
);
145 M_BITMAPDATA
->m_hBitmap
= 0 ;
148 if (M_BITMAPDATA->m_bitmapPalette)
149 delete M_BITMAPDATA->m_bitmapPalette;
151 M_BITMAPDATA->m_bitmapPalette = NULL ;
158 wxBitmap::wxBitmap(const char bits
[], int the_width
, int the_height
, int no_bits
)
160 m_refData
= new wxBitmapRefData
;
162 M_BITMAPDATA
->m_width
= the_width
;
163 M_BITMAPDATA
->m_height
= the_height
;
164 M_BITMAPDATA
->m_depth
= no_bits
;
165 M_BITMAPDATA
->m_numColors
= 0;
167 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateBitmap(the_width
, the_height
, 1, no_bits
, bits
);
169 if (M_BITMAPDATA
->m_hBitmap
)
170 M_BITMAPDATA
->m_ok
= TRUE
;
172 M_BITMAPDATA
->m_ok
= FALSE
;
174 M_BITMAPDATA
->m_selectedInto
= NULL
;
176 if ( wxTheBitmapList
)
177 wxTheBitmapList
->AddBitmap(this);
180 // Create from XPM data
181 wxBitmap::wxBitmap(char **data
, wxControl
*WXUNUSED(anItem
))
183 (void) Create((void *)data
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
186 wxBitmap::wxBitmap(int w
, int h
, int d
)
188 (void)Create(w
, h
, d
);
190 if ( wxTheBitmapList
)
191 wxTheBitmapList
->AddBitmap(this);
194 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
196 (void) Create(data
, type
, width
, height
, depth
);
198 if ( wxTheBitmapList
)
199 wxTheBitmapList
->AddBitmap(this);
202 wxBitmap::wxBitmap(const wxString
& filename
, long type
)
204 LoadFile(filename
, (int)type
);
206 if ( wxTheBitmapList
)
207 wxTheBitmapList
->AddBitmap(this);
210 bool wxBitmap::Create(int w
, int h
, int d
)
214 m_refData
= new wxBitmapRefData
;
216 M_BITMAPDATA
->m_width
= w
;
217 M_BITMAPDATA
->m_height
= h
;
218 M_BITMAPDATA
->m_depth
= d
;
222 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateBitmap(w
, h
, 1, d
, NULL
);
226 HDC dc
= GetDC((HWND
) NULL
);
227 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateCompatibleBitmap(dc
, w
, h
);
228 ReleaseDC((HWND
) NULL
, dc
);
229 M_BITMAPDATA
->m_depth
= wxDisplayDepth();
231 if (M_BITMAPDATA
->m_hBitmap
)
232 M_BITMAPDATA
->m_ok
= TRUE
;
234 M_BITMAPDATA
->m_ok
= FALSE
;
235 return M_BITMAPDATA
->m_ok
;
238 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
242 m_refData
= new wxBitmapRefData
;
244 wxBitmapHandler
*handler
= FindHandler(type
);
246 if ( handler
== NULL
) {
247 wxLogWarning(wxT("no bitmap handler for type %d defined."), type
);
252 return handler
->LoadFile(this, filename
, type
, -1, -1);
255 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
259 m_refData
= new wxBitmapRefData
;
261 wxBitmapHandler
*handler
= FindHandler(type
);
263 if ( handler
== NULL
) {
264 wxLogWarning(wxT("no bitmap handler for type %d defined."), type
);
269 return handler
->Create(this, data
, type
, width
, height
, depth
);
272 bool wxBitmap::SaveFile(const wxString
& filename
, int type
, const wxPalette
*palette
)
274 wxBitmapHandler
*handler
= FindHandler(type
);
276 if ( handler
== NULL
) {
277 wxLogWarning(wxT("no bitmap handler for type %d defined."), type
);
282 return handler
->SaveFile(this, filename
, type
, palette
);
285 void wxBitmap::SetWidth(int w
)
288 m_refData
= new wxBitmapRefData
;
290 M_BITMAPDATA
->m_width
= w
;
293 void wxBitmap::SetHeight(int h
)
296 m_refData
= new wxBitmapRefData
;
298 M_BITMAPDATA
->m_height
= h
;
301 void wxBitmap::SetDepth(int d
)
304 m_refData
= new wxBitmapRefData
;
306 M_BITMAPDATA
->m_depth
= d
;
309 void wxBitmap::SetQuality(int q
)
312 m_refData
= new wxBitmapRefData
;
314 M_BITMAPDATA
->m_quality
= q
;
317 void wxBitmap::SetOk(bool isOk
)
320 m_refData
= new wxBitmapRefData
;
322 M_BITMAPDATA
->m_ok
= isOk
;
325 void wxBitmap::SetPalette(const wxPalette
& palette
)
328 m_refData
= new wxBitmapRefData
;
330 M_BITMAPDATA
->m_bitmapPalette
= palette
;
333 void wxBitmap::SetMask(wxMask
*mask
)
336 m_refData
= new wxBitmapRefData
;
338 M_BITMAPDATA
->m_bitmapMask
= mask
;
341 void wxBitmap::SetHBITMAP(WXHBITMAP bmp
)
344 m_refData
= new wxBitmapRefData
;
346 M_BITMAPDATA
->m_hBitmap
= bmp
;
347 M_BITMAPDATA
->m_ok
= bmp
!= 0;
350 void wxBitmap::AddHandler(wxBitmapHandler
*handler
)
352 sm_handlers
.Append(handler
);
355 void wxBitmap::InsertHandler(wxBitmapHandler
*handler
)
357 sm_handlers
.Insert(handler
);
360 bool wxBitmap::RemoveHandler(const wxString
& name
)
362 wxBitmapHandler
*handler
= FindHandler(name
);
365 sm_handlers
.DeleteObject(handler
);
372 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& name
)
374 wxNode
*node
= sm_handlers
.First();
377 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
378 if ( (handler
->GetName().Cmp(name
) == 0) )
385 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& extension
, long bitmapType
)
387 wxNode
*node
= sm_handlers
.First();
390 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
391 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
392 (bitmapType
== -1 || (handler
->GetType() == bitmapType
)) )
399 wxBitmapHandler
*wxBitmap::FindHandler(long bitmapType
)
401 wxNode
*node
= sm_handlers
.First();
404 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
405 if (handler
->GetType() == bitmapType
)
412 // New Create/FreeDIB functions since ones in dibutils.cpp are confusing
413 static long createDIB(long xSize
, long ySize
, long bitsPerPixel
,
414 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
);
415 static long freeDIB(LPBITMAPINFO lpDIBHeader
);
417 // Creates a bitmap that matches the device context, from
418 // an arbitray bitmap. At present, the original bitmap must have an
419 // associated palette. TODO: use a default palette if no palette exists.
420 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
421 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
424 wxBitmap
tmpBitmap(this->GetWidth(), this->GetHeight(), dc
.GetDepth());
425 HPALETTE hPal
= (HPALETTE
) NULL
;
427 void *lpBits
= (void*) NULL
;
430 wxASSERT( this->GetPalette() && this->GetPalette()->Ok() && (this->GetPalette()->GetHPALETTE() != 0) );
432 tmpBitmap.SetPalette(this->GetPalette());
433 memDC.SelectObject(tmpBitmap);
434 memDC.SetPalette(this->GetPalette());
436 hPal = (HPALETTE) this->GetPalette()->GetHPALETTE();
438 if( this->GetPalette() && this->GetPalette()->Ok() && (this->GetPalette()->GetHPALETTE() != 0) )
440 tmpBitmap
.SetPalette(* this->GetPalette());
441 memDC
.SelectObject(tmpBitmap
);
442 memDC
.SetPalette(* this->GetPalette());
443 hPal
= (HPALETTE
) this->GetPalette()->GetHPALETTE();
447 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
449 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
450 tmpBitmap
.SetPalette( palette
);
451 memDC
.SelectObject(tmpBitmap
);
452 memDC
.SetPalette( palette
);
455 // set the height negative because in a DIB the order of the lines is reversed
456 createDIB(this->GetWidth(), -this->GetHeight(), this->GetDepth(), hPal
, &lpDib
);
458 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
460 ::GetBitmapBits((HBITMAP
)GetHBITMAP(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
462 ::SetDIBitsToDevice((HDC
) memDC
.GetHDC(), 0, 0, this->GetWidth(), this->GetHeight(),
463 0, 0, 0, this->GetHeight(), lpBits
, lpDib
, DIB_RGB_COLORS
);
480 // Construct a mask from a bitmap and a colour indicating
481 // the transparent area
482 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
485 Create(bitmap
, colour
);
488 // Construct a mask from a bitmap and a palette index indicating
489 // the transparent area
490 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
493 Create(bitmap
, paletteIndex
);
496 // Construct a mask from a mono bitmap (copies the bitmap).
497 wxMask::wxMask(const wxBitmap
& bitmap
)
506 ::DeleteObject((HBITMAP
) m_maskBitmap
);
509 // Create a mask from a mono bitmap (copies the bitmap).
510 bool wxMask::Create(const wxBitmap
& bitmap
)
514 ::DeleteObject((HBITMAP
) m_maskBitmap
);
517 if (!bitmap
.Ok() || bitmap
.GetDepth() != 1)
521 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
526 HDC srcDC
= CreateCompatibleDC(0);
527 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
528 HDC destDC
= CreateCompatibleDC(0);
529 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
530 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
531 SelectObject(srcDC
, 0);
533 SelectObject(destDC
, 0);
538 // Create a mask from a bitmap and a palette index indicating
539 // the transparent area
540 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
544 ::DeleteObject((HBITMAP
) m_maskBitmap
);
547 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
549 unsigned char red
, green
, blue
;
550 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
552 wxColour
transparentColour(red
, green
, blue
);
553 return Create(bitmap
, transparentColour
);
559 // Create a mask from a bitmap and a colour indicating
560 // the transparent area
561 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
565 ::DeleteObject((HBITMAP
) m_maskBitmap
);
573 // scan the bitmap for the transparent colour and set
574 // the corresponding pixels in the mask to BLACK and
576 COLORREF maskColour
= RGB(colour
.Red(), colour
.Green(), colour
.Blue());
577 m_maskBitmap
= (WXHBITMAP
) ::CreateBitmap(
582 HDC srcDC
= ::CreateCompatibleDC(0);
583 ::SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
584 HDC destDC
= ::CreateCompatibleDC(0);
585 ::SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
587 // this is not very efficient, but I can't think
588 // of a better way of doing it
589 for (int w
= 0; w
< bitmap
.GetWidth(); w
++)
591 for (int h
= 0; h
< bitmap
.GetHeight(); h
++)
593 COLORREF col
= GetPixel(srcDC
, w
, h
);
594 if (col
== maskColour
)
596 ::SetPixel(destDC
, w
, h
, RGB(0, 0, 0));
600 ::SetPixel(destDC
, w
, h
, RGB(255, 255, 255));
604 ::SelectObject(srcDC
, 0);
606 ::SelectObject(destDC
, 0);
615 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
617 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
), void *WXUNUSED(data
), long WXUNUSED(type
), int WXUNUSED(width
), int WXUNUSED(height
), int WXUNUSED(depth
))
622 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), long WXUNUSED(type
),
623 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
628 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), int WXUNUSED(type
), const wxPalette
*WXUNUSED(palette
))
637 class WXDLLEXPORT wxBMPResourceHandler
: public wxBitmapHandler
639 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler
)
641 inline wxBMPResourceHandler()
643 m_name
= "Windows bitmap resource";
645 m_type
= wxBITMAP_TYPE_BMP_RESOURCE
;
648 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
649 int desiredWidth
, int desiredHeight
);
651 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler
, wxBitmapHandler
)
653 bool wxBMPResourceHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
654 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
656 // TODO: load colourmap.
657 M_BITMAPHANDLERDATA
->m_hBitmap
= (WXHBITMAP
) ::LoadBitmap(wxGetInstance(), name
);
658 if (M_BITMAPHANDLERDATA
->m_hBitmap
)
660 M_BITMAPHANDLERDATA
->m_ok
= TRUE
;
662 GetObject((HBITMAP
) M_BITMAPHANDLERDATA
->m_hBitmap
, sizeof(BITMAP
), (LPSTR
) &bm
);
663 M_BITMAPHANDLERDATA
->m_width
= bm
.bmWidth
;
664 M_BITMAPHANDLERDATA
->m_height
= bm
.bmHeight
;
665 M_BITMAPHANDLERDATA
->m_depth
= bm
.bmBitsPixel
;
667 if ( bitmap
->IsKindOf(CLASSINFO(wxIcon
)) )
674 // it's probably not found
675 wxLogError(wxT("Can't load bitmap '%s' from resources! Check .rc file."), name
.c_str());
680 class WXDLLEXPORT wxBMPFileHandler
: public wxBitmapHandler
682 DECLARE_DYNAMIC_CLASS(wxBMPFileHandler
)
684 inline wxBMPFileHandler()
686 m_name
= "Windows bitmap file";
688 m_type
= wxBITMAP_TYPE_BMP
;
691 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
692 int desiredWidth
, int desiredHeight
);
693 virtual bool SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int type
, const wxPalette
*palette
= NULL
);
695 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler
, wxBitmapHandler
)
697 bool wxBMPFileHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
698 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
700 #if wxUSE_IMAGE_LOADING_IN_MSW
701 wxPalette
*palette
= NULL
;
702 bool success
= FALSE
;
704 if (type & wxBITMAP_DISCARD_COLOURMAP)
705 success = wxLoadIntoBitmap(WXSTRINGCAST name, bitmap);
708 success
= (wxLoadIntoBitmap(WXSTRINGCAST name
, bitmap
, &palette
) != 0);
709 if (!success
&& palette
)
716 M_BITMAPHANDLERDATA
->m_bitmapPalette
= *palette
;
725 bool wxBMPFileHandler::SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int WXUNUSED(type
), const wxPalette
*pal
)
727 #if wxUSE_IMAGE_LOADING_IN_MSW
728 wxPalette
*actualPalette
= (wxPalette
*)pal
;
729 if (!actualPalette
&& (!M_BITMAPHANDLERDATA
->m_bitmapPalette
.IsNull()))
730 actualPalette
= & (M_BITMAPHANDLERDATA
->m_bitmapPalette
);
731 return (wxSaveBitmap(WXSTRINGCAST name
, bitmap
, actualPalette
) != 0);
737 void wxBitmap::CleanUpHandlers()
739 wxNode
*node
= sm_handlers
.First();
742 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
743 wxNode
*next
= node
->Next();
750 void wxBitmap::InitStandardHandlers()
752 AddHandler(new wxBMPResourceHandler
);
753 AddHandler(new wxBMPFileHandler
);
755 // Not added by default: include xpmhand.h in your app
756 // and call these in your wxApp::OnInit.
757 // AddHandler(new wxXPMFileHandler);
758 // AddHandler(new wxXPMDataHandler);
760 AddHandler(new wxICOResourceHandler
);
761 AddHandler(new wxICOFileHandler
);
764 static long createDIB(long xSize
, long ySize
, long bitsPerPixel
,
765 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
767 unsigned long i
, headerSize
;
768 LPBITMAPINFO lpDIBheader
= NULL
;
769 LPPALETTEENTRY lpPe
= NULL
;
772 // Allocate space for a DIB header
773 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
774 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
775 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
777 GetPaletteEntries(hPal
, 0, 256, lpPe
);
780 memset(lpDIBheader
, 0x00, sizeof(BITMAPINFOHEADER
));
783 // Fill in the static parts of the DIB header
784 lpDIBheader
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
785 lpDIBheader
->bmiHeader
.biWidth
= xSize
;
786 lpDIBheader
->bmiHeader
.biHeight
= ySize
;
787 lpDIBheader
->bmiHeader
.biPlanes
= 1;
789 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
790 lpDIBheader
->bmiHeader
.biBitCount
= (WORD
)(bitsPerPixel
);
791 lpDIBheader
->bmiHeader
.biCompression
= BI_RGB
;
792 lpDIBheader
->bmiHeader
.biSizeImage
= xSize
* abs(ySize
) * bitsPerPixel
>>
794 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
797 // Initialize the DIB palette
798 for (i
= 0; i
< 256; i
++) {
799 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
800 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
801 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
802 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
805 *lpDIBHeader
= lpDIBheader
;
814 static long freeDIB(LPBITMAPINFO lpDIBHeader
)
817 if (lpDIBHeader
!= NULL
) {