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()
83 wxSprintf(buf
, _T("Bitmap was deleted without selecting out of wxMemoryDC %X."), (unsigned int) m_selectedInto
);
88 DeleteObject((HBITMAP
) m_hBitmap
);
98 // ----------------------------------------------------------------------------
100 // ----------------------------------------------------------------------------
102 wxList
wxBitmap::sm_handlers
;
106 if ( wxTheBitmapList
)
107 wxTheBitmapList
->AddBitmap(this);
110 wxBitmap::wxBitmap(const wxBitmap
& bitmap
)
112 wxIcon
*icon
= wxDynamicCast(&bitmap
, wxIcon
);
115 HDC hdc
= ::CreateCompatibleDC(NULL
); // screen DC
116 HBITMAP hbitmap
= ::CreateCompatibleBitmap(hdc
,
119 ::SelectObject(hdc
, hbitmap
);
120 ::DrawIcon(hdc
, 0, 0, (HICON
)icon
->GetHICON());
124 SetHBITMAP((WXHBITMAP
)hbitmap
);
131 if ( wxTheBitmapList
)
132 wxTheBitmapList
->AddBitmap(this);
135 wxBitmap::~wxBitmap()
138 wxTheBitmapList
->DeleteObject(this);
141 bool wxBitmap::FreeResource(bool WXUNUSED(force
))
146 if (M_BITMAPDATA
->m_selectedInto
)
149 wxSprintf(buf
, _T("Bitmap %X was deleted without selecting out of wxMemoryDC %X."), (unsigned int) this, (unsigned int) M_BITMAPDATA
->m_selectedInto
);
152 if (M_BITMAPDATA
->m_hBitmap
)
154 DeleteObject((HBITMAP
) M_BITMAPDATA
->m_hBitmap
);
156 M_BITMAPDATA
->m_hBitmap
= 0 ;
159 if (M_BITMAPDATA->m_bitmapPalette)
160 delete M_BITMAPDATA->m_bitmapPalette;
162 M_BITMAPDATA->m_bitmapPalette = NULL ;
169 wxBitmap::wxBitmap(const char bits
[], int the_width
, int the_height
, int no_bits
)
171 m_refData
= new wxBitmapRefData
;
173 M_BITMAPDATA
->m_width
= the_width
;
174 M_BITMAPDATA
->m_height
= the_height
;
175 M_BITMAPDATA
->m_depth
= no_bits
;
176 M_BITMAPDATA
->m_numColors
= 0;
178 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateBitmap(the_width
, the_height
, 1, no_bits
, bits
);
180 if (M_BITMAPDATA
->m_hBitmap
)
181 M_BITMAPDATA
->m_ok
= TRUE
;
183 M_BITMAPDATA
->m_ok
= FALSE
;
185 M_BITMAPDATA
->m_selectedInto
= NULL
;
187 if ( wxTheBitmapList
)
188 wxTheBitmapList
->AddBitmap(this);
191 // Create from XPM data
192 wxBitmap::wxBitmap(char **data
, wxControl
*WXUNUSED(anItem
))
194 (void) Create((void *)data
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
197 wxBitmap::wxBitmap(int w
, int h
, int d
)
199 (void)Create(w
, h
, d
);
201 if ( wxTheBitmapList
)
202 wxTheBitmapList
->AddBitmap(this);
205 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
207 (void) Create(data
, type
, width
, height
, depth
);
209 if ( wxTheBitmapList
)
210 wxTheBitmapList
->AddBitmap(this);
213 wxBitmap::wxBitmap(const wxString
& filename
, long type
)
215 LoadFile(filename
, (int)type
);
217 if ( wxTheBitmapList
)
218 wxTheBitmapList
->AddBitmap(this);
221 bool wxBitmap::Create(int w
, int h
, int d
)
225 m_refData
= new wxBitmapRefData
;
227 M_BITMAPDATA
->m_width
= w
;
228 M_BITMAPDATA
->m_height
= h
;
229 M_BITMAPDATA
->m_depth
= d
;
233 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateBitmap(w
, h
, 1, d
, NULL
);
237 HDC dc
= GetDC((HWND
) NULL
);
238 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateCompatibleBitmap(dc
, w
, h
);
239 ReleaseDC((HWND
) NULL
, dc
);
240 M_BITMAPDATA
->m_depth
= wxDisplayDepth();
242 if (M_BITMAPDATA
->m_hBitmap
)
243 M_BITMAPDATA
->m_ok
= TRUE
;
245 M_BITMAPDATA
->m_ok
= FALSE
;
246 return M_BITMAPDATA
->m_ok
;
249 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
253 m_refData
= new wxBitmapRefData
;
255 wxBitmapHandler
*handler
= FindHandler(type
);
257 if ( handler
== NULL
) {
258 wxLogWarning(_T("no bitmap handler for type %d defined."), type
);
263 return handler
->LoadFile(this, filename
, type
, -1, -1);
266 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
270 m_refData
= new wxBitmapRefData
;
272 wxBitmapHandler
*handler
= FindHandler(type
);
274 if ( handler
== NULL
) {
275 wxLogWarning(_T("no bitmap handler for type %d defined."), type
);
280 return handler
->Create(this, data
, type
, width
, height
, depth
);
283 bool wxBitmap::SaveFile(const wxString
& filename
, int type
, const wxPalette
*palette
)
285 wxBitmapHandler
*handler
= FindHandler(type
);
287 if ( handler
== NULL
) {
288 wxLogWarning(_T("no bitmap handler for type %d defined."), type
);
293 return handler
->SaveFile(this, filename
, type
, palette
);
296 void wxBitmap::SetWidth(int w
)
299 m_refData
= new wxBitmapRefData
;
301 M_BITMAPDATA
->m_width
= w
;
304 void wxBitmap::SetHeight(int h
)
307 m_refData
= new wxBitmapRefData
;
309 M_BITMAPDATA
->m_height
= h
;
312 void wxBitmap::SetDepth(int d
)
315 m_refData
= new wxBitmapRefData
;
317 M_BITMAPDATA
->m_depth
= d
;
320 void wxBitmap::SetQuality(int q
)
323 m_refData
= new wxBitmapRefData
;
325 M_BITMAPDATA
->m_quality
= q
;
328 void wxBitmap::SetOk(bool isOk
)
331 m_refData
= new wxBitmapRefData
;
333 M_BITMAPDATA
->m_ok
= isOk
;
336 void wxBitmap::SetPalette(const wxPalette
& palette
)
339 m_refData
= new wxBitmapRefData
;
341 M_BITMAPDATA
->m_bitmapPalette
= palette
;
344 void wxBitmap::SetMask(wxMask
*mask
)
347 m_refData
= new wxBitmapRefData
;
349 M_BITMAPDATA
->m_bitmapMask
= mask
;
352 void wxBitmap::SetHBITMAP(WXHBITMAP bmp
)
355 m_refData
= new wxBitmapRefData
;
357 M_BITMAPDATA
->m_hBitmap
= bmp
;
360 void wxBitmap::AddHandler(wxBitmapHandler
*handler
)
362 sm_handlers
.Append(handler
);
365 void wxBitmap::InsertHandler(wxBitmapHandler
*handler
)
367 sm_handlers
.Insert(handler
);
370 bool wxBitmap::RemoveHandler(const wxString
& name
)
372 wxBitmapHandler
*handler
= FindHandler(name
);
375 sm_handlers
.DeleteObject(handler
);
382 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& name
)
384 wxNode
*node
= sm_handlers
.First();
387 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
388 if ( (handler
->GetName().Cmp(name
) == 0) )
395 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& extension
, long bitmapType
)
397 wxNode
*node
= sm_handlers
.First();
400 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
401 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
402 (bitmapType
== -1 || (handler
->GetType() == bitmapType
)) )
409 wxBitmapHandler
*wxBitmap::FindHandler(long bitmapType
)
411 wxNode
*node
= sm_handlers
.First();
414 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
415 if (handler
->GetType() == bitmapType
)
422 // New Create/FreeDIB functions since ones in dibutils.cpp are confusing
423 static long createDIB(long xSize
, long ySize
, long bitsPerPixel
,
424 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
);
425 static long freeDIB(LPBITMAPINFO lpDIBHeader
);
427 // Creates a bitmap that matches the device context, from
428 // an arbitray bitmap. At present, the original bitmap must have an
429 // associated palette. TODO: use a default palette if no palette exists.
430 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
431 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
434 wxBitmap
tmpBitmap(this->GetWidth(), this->GetHeight(), dc
.GetDepth());
435 HPALETTE hPal
= (HPALETTE
) NULL
;
437 void *lpBits
= (void*) NULL
;
440 wxASSERT( this->GetPalette() && this->GetPalette()->Ok() && (this->GetPalette()->GetHPALETTE() != 0) );
442 tmpBitmap.SetPalette(this->GetPalette());
443 memDC.SelectObject(tmpBitmap);
444 memDC.SetPalette(this->GetPalette());
446 hPal = (HPALETTE) this->GetPalette()->GetHPALETTE();
448 if( this->GetPalette() && this->GetPalette()->Ok() && (this->GetPalette()->GetHPALETTE() != 0) )
450 tmpBitmap
.SetPalette(* this->GetPalette());
451 memDC
.SelectObject(tmpBitmap
);
452 memDC
.SetPalette(* this->GetPalette());
453 hPal
= (HPALETTE
) this->GetPalette()->GetHPALETTE();
457 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
459 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
460 tmpBitmap
.SetPalette( palette
);
461 memDC
.SelectObject(tmpBitmap
);
462 memDC
.SetPalette( palette
);
465 // set the height negative because in a DIB the order of the lines is reversed
466 createDIB(this->GetWidth(), -this->GetHeight(), this->GetDepth(), hPal
, &lpDib
);
468 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
470 ::GetBitmapBits((HBITMAP
)GetHBITMAP(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
472 ::SetDIBitsToDevice((HDC
) memDC
.GetHDC(), 0, 0, this->GetWidth(), this->GetHeight(),
473 0, 0, 0, this->GetHeight(), lpBits
, lpDib
, DIB_RGB_COLORS
);
490 // Construct a mask from a bitmap and a colour indicating
491 // the transparent area
492 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
495 Create(bitmap
, colour
);
498 // Construct a mask from a bitmap and a palette index indicating
499 // the transparent area
500 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
503 Create(bitmap
, paletteIndex
);
506 // Construct a mask from a mono bitmap (copies the bitmap).
507 wxMask::wxMask(const wxBitmap
& bitmap
)
516 ::DeleteObject((HBITMAP
) m_maskBitmap
);
519 // Create a mask from a mono bitmap (copies the bitmap).
520 bool wxMask::Create(const wxBitmap
& bitmap
)
524 ::DeleteObject((HBITMAP
) m_maskBitmap
);
527 if (!bitmap
.Ok() || bitmap
.GetDepth() != 1)
531 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
536 HDC srcDC
= CreateCompatibleDC(0);
537 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
538 HDC destDC
= CreateCompatibleDC(0);
539 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
540 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
541 SelectObject(srcDC
, 0);
543 SelectObject(destDC
, 0);
548 // Create a mask from a bitmap and a palette index indicating
549 // the transparent area
550 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
554 ::DeleteObject((HBITMAP
) m_maskBitmap
);
557 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
559 unsigned char red
, green
, blue
;
560 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
562 wxColour
transparentColour(red
, green
, blue
);
563 return Create(bitmap
, transparentColour
);
569 // Create a mask from a bitmap and a colour indicating
570 // the transparent area
571 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
575 ::DeleteObject((HBITMAP
) m_maskBitmap
);
583 // scan the bitmap for the transparent colour and set
584 // the corresponding pixels in the mask to BLACK and
586 COLORREF maskColour
= RGB(colour
.Red(), colour
.Green(), colour
.Blue());
587 m_maskBitmap
= (WXHBITMAP
) ::CreateBitmap(
592 HDC srcDC
= ::CreateCompatibleDC(0);
593 ::SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
594 HDC destDC
= ::CreateCompatibleDC(0);
595 ::SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
597 // this is not very efficient, but I can't think
598 // of a better way of doing it
599 for (int w
= 0; w
< bitmap
.GetWidth(); w
++)
601 for (int h
= 0; h
< bitmap
.GetHeight(); h
++)
603 COLORREF col
= GetPixel(srcDC
, w
, h
);
604 if (col
== maskColour
)
606 ::SetPixel(destDC
, w
, h
, RGB(0, 0, 0));
610 ::SetPixel(destDC
, w
, h
, RGB(255, 255, 255));
614 ::SelectObject(srcDC
, 0);
616 ::SelectObject(destDC
, 0);
625 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
627 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
), void *WXUNUSED(data
), long WXUNUSED(type
), int WXUNUSED(width
), int WXUNUSED(height
), int WXUNUSED(depth
))
632 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), long WXUNUSED(type
),
633 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
638 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), int WXUNUSED(type
), const wxPalette
*WXUNUSED(palette
))
647 class WXDLLEXPORT wxBMPResourceHandler
: public wxBitmapHandler
649 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler
)
651 inline wxBMPResourceHandler()
653 m_name
= "Windows bitmap resource";
655 m_type
= wxBITMAP_TYPE_BMP_RESOURCE
;
658 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
659 int desiredWidth
, int desiredHeight
);
661 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler
, wxBitmapHandler
)
663 bool wxBMPResourceHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
664 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
666 // TODO: load colourmap.
667 M_BITMAPHANDLERDATA
->m_hBitmap
= (WXHBITMAP
) ::LoadBitmap(wxGetInstance(), name
);
668 if (M_BITMAPHANDLERDATA
->m_hBitmap
)
670 M_BITMAPHANDLERDATA
->m_ok
= TRUE
;
672 GetObject((HBITMAP
) M_BITMAPHANDLERDATA
->m_hBitmap
, sizeof(BITMAP
), (LPSTR
) &bm
);
673 M_BITMAPHANDLERDATA
->m_width
= bm
.bmWidth
;
674 M_BITMAPHANDLERDATA
->m_height
= bm
.bmHeight
;
675 M_BITMAPHANDLERDATA
->m_depth
= bm
.bmBitsPixel
;
677 if ( bitmap
->IsKindOf(CLASSINFO(wxIcon
)) )
684 // it's probably not found
685 wxLogError(_T("Can't load bitmap '%s' from resources! Check .rc file."), name
.c_str());
690 class WXDLLEXPORT wxBMPFileHandler
: public wxBitmapHandler
692 DECLARE_DYNAMIC_CLASS(wxBMPFileHandler
)
694 inline wxBMPFileHandler()
696 m_name
= "Windows bitmap file";
698 m_type
= wxBITMAP_TYPE_BMP
;
701 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
702 int desiredWidth
, int desiredHeight
);
703 virtual bool SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int type
, const wxPalette
*palette
= NULL
);
705 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler
, wxBitmapHandler
)
707 bool wxBMPFileHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
708 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
710 #if wxUSE_IMAGE_LOADING_IN_MSW
711 wxPalette
*palette
= NULL
;
712 bool success
= FALSE
;
714 if (type & wxBITMAP_DISCARD_COLOURMAP)
715 success = wxLoadIntoBitmap(WXSTRINGCAST name, bitmap);
718 success
= (wxLoadIntoBitmap(WXSTRINGCAST name
, bitmap
, &palette
) != 0);
719 if (!success
&& palette
)
726 M_BITMAPHANDLERDATA
->m_bitmapPalette
= *palette
;
735 bool wxBMPFileHandler::SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int WXUNUSED(type
), const wxPalette
*pal
)
737 #if wxUSE_IMAGE_LOADING_IN_MSW
738 wxPalette
*actualPalette
= (wxPalette
*)pal
;
739 if (!actualPalette
&& (!M_BITMAPHANDLERDATA
->m_bitmapPalette
.IsNull()))
740 actualPalette
= & (M_BITMAPHANDLERDATA
->m_bitmapPalette
);
741 return (wxSaveBitmap(WXSTRINGCAST name
, bitmap
, actualPalette
) != 0);
747 void wxBitmap::CleanUpHandlers()
749 wxNode
*node
= sm_handlers
.First();
752 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
753 wxNode
*next
= node
->Next();
760 void wxBitmap::InitStandardHandlers()
762 AddHandler(new wxBMPResourceHandler
);
763 AddHandler(new wxBMPFileHandler
);
765 // Not added by default: include xpmhand.h in your app
766 // and call these in your wxApp::OnInit.
767 // AddHandler(new wxXPMFileHandler);
768 // AddHandler(new wxXPMDataHandler);
770 AddHandler(new wxICOResourceHandler
);
771 AddHandler(new wxICOFileHandler
);
774 static long createDIB(long xSize
, long ySize
, long bitsPerPixel
,
775 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
777 unsigned long i
, headerSize
;
778 LPBITMAPINFO lpDIBheader
= NULL
;
779 LPPALETTEENTRY lpPe
= NULL
;
782 // Allocate space for a DIB header
783 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
784 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
785 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
787 GetPaletteEntries(hPal
, 0, 256, lpPe
);
790 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
>>
804 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
807 // Initialize the DIB palette
808 for (i
= 0; i
< 256; i
++) {
809 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
810 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
811 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
812 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
815 *lpDIBHeader
= lpDIBheader
;
824 static long freeDIB(LPBITMAPINFO lpDIBHeader
)
827 if (lpDIBHeader
!= NULL
) {