1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "bitmap.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
29 #include "wx/palette.h"
30 #include "wx/dcmemory.h"
31 #include "wx/bitmap.h"
35 #include "wx/msw/private.h"
40 #include "wx/msw/dib.h"
42 #if !USE_SHARED_LIBRARIES
43 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
44 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
47 wxBitmapRefData::wxBitmapRefData(void)
55 m_selectedInto
= NULL
;
60 wxBitmapRefData::~wxBitmapRefData(void)
65 wxSprintf(buf
, _T("Bitmap was deleted without selecting out of wxMemoryDC %X."), (unsigned int) m_selectedInto
);
70 DeleteObject((HBITMAP
) m_hBitmap
);
80 wxList
wxBitmap::sm_handlers
;
82 wxBitmap::wxBitmap(void)
84 if ( wxTheBitmapList
)
85 wxTheBitmapList
->AddBitmap(this);
88 wxBitmap::~wxBitmap(void)
91 wxTheBitmapList
->DeleteObject(this);
94 bool wxBitmap::FreeResource(bool WXUNUSED(force
))
99 if (M_BITMAPDATA
->m_selectedInto
)
102 wxSprintf(buf
, _T("Bitmap %X was deleted without selecting out of wxMemoryDC %X."), (unsigned int) this, (unsigned int) M_BITMAPDATA
->m_selectedInto
);
105 if (M_BITMAPDATA
->m_hBitmap
)
107 DeleteObject((HBITMAP
) M_BITMAPDATA
->m_hBitmap
);
109 M_BITMAPDATA
->m_hBitmap
= 0 ;
112 if (M_BITMAPDATA->m_bitmapPalette)
113 delete M_BITMAPDATA->m_bitmapPalette;
115 M_BITMAPDATA->m_bitmapPalette = NULL ;
122 wxBitmap::wxBitmap(const char bits
[], int the_width
, int the_height
, int no_bits
)
124 m_refData
= new wxBitmapRefData
;
126 M_BITMAPDATA
->m_width
= the_width
;
127 M_BITMAPDATA
->m_height
= the_height
;
128 M_BITMAPDATA
->m_depth
= no_bits
;
129 M_BITMAPDATA
->m_numColors
= 0;
131 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateBitmap(the_width
, the_height
, 1, no_bits
, bits
);
133 if (M_BITMAPDATA
->m_hBitmap
)
134 M_BITMAPDATA
->m_ok
= TRUE
;
136 M_BITMAPDATA
->m_ok
= FALSE
;
138 M_BITMAPDATA
->m_selectedInto
= NULL
;
140 if ( wxTheBitmapList
)
141 wxTheBitmapList
->AddBitmap(this);
144 // Create from XPM data
145 wxBitmap::wxBitmap(char **data
, wxControl
*WXUNUSED(anItem
))
147 (void) Create((void *)data
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
150 wxBitmap::wxBitmap(int w
, int h
, int d
)
152 (void)Create(w
, h
, d
);
154 if ( wxTheBitmapList
)
155 wxTheBitmapList
->AddBitmap(this);
158 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
160 (void) Create(data
, type
, width
, height
, depth
);
162 if ( wxTheBitmapList
)
163 wxTheBitmapList
->AddBitmap(this);
166 wxBitmap::wxBitmap(const wxString
& filename
, long type
)
168 LoadFile(filename
, (int)type
);
170 if ( wxTheBitmapList
)
171 wxTheBitmapList
->AddBitmap(this);
174 bool wxBitmap::Create(int w
, int h
, int d
)
178 m_refData
= new wxBitmapRefData
;
180 M_BITMAPDATA
->m_width
= w
;
181 M_BITMAPDATA
->m_height
= h
;
182 M_BITMAPDATA
->m_depth
= d
;
186 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateBitmap(w
, h
, 1, d
, NULL
);
190 HDC dc
= GetDC((HWND
) NULL
);
191 M_BITMAPDATA
->m_hBitmap
= (WXHBITMAP
) CreateCompatibleBitmap(dc
, w
, h
);
192 ReleaseDC((HWND
) NULL
, dc
);
193 M_BITMAPDATA
->m_depth
= wxDisplayDepth();
195 if (M_BITMAPDATA
->m_hBitmap
)
196 M_BITMAPDATA
->m_ok
= TRUE
;
198 M_BITMAPDATA
->m_ok
= FALSE
;
199 return M_BITMAPDATA
->m_ok
;
202 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
206 m_refData
= new wxBitmapRefData
;
208 wxBitmapHandler
*handler
= FindHandler(type
);
210 if ( handler
== NULL
) {
211 wxLogWarning(_T("no bitmap handler for type %d defined."), type
);
216 return handler
->LoadFile(this, filename
, type
, -1, -1);
219 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
223 m_refData
= new wxBitmapRefData
;
225 wxBitmapHandler
*handler
= FindHandler(type
);
227 if ( handler
== NULL
) {
228 wxLogWarning(_T("no bitmap handler for type %d defined."), type
);
233 return handler
->Create(this, data
, type
, width
, height
, depth
);
236 bool wxBitmap::SaveFile(const wxString
& filename
, int type
, const wxPalette
*palette
)
238 wxBitmapHandler
*handler
= FindHandler(type
);
240 if ( handler
== NULL
) {
241 wxLogWarning(_T("no bitmap handler for type %d defined."), type
);
246 return handler
->SaveFile(this, filename
, type
, palette
);
249 void wxBitmap::SetWidth(int w
)
252 m_refData
= new wxBitmapRefData
;
254 M_BITMAPDATA
->m_width
= w
;
257 void wxBitmap::SetHeight(int h
)
260 m_refData
= new wxBitmapRefData
;
262 M_BITMAPDATA
->m_height
= h
;
265 void wxBitmap::SetDepth(int d
)
268 m_refData
= new wxBitmapRefData
;
270 M_BITMAPDATA
->m_depth
= d
;
273 void wxBitmap::SetQuality(int q
)
276 m_refData
= new wxBitmapRefData
;
278 M_BITMAPDATA
->m_quality
= q
;
281 void wxBitmap::SetOk(bool isOk
)
284 m_refData
= new wxBitmapRefData
;
286 M_BITMAPDATA
->m_ok
= isOk
;
289 void wxBitmap::SetPalette(const wxPalette
& palette
)
292 m_refData
= new wxBitmapRefData
;
294 M_BITMAPDATA
->m_bitmapPalette
= palette
;
297 void wxBitmap::SetMask(wxMask
*mask
)
300 m_refData
= new wxBitmapRefData
;
302 M_BITMAPDATA
->m_bitmapMask
= mask
;
305 void wxBitmap::SetHBITMAP(WXHBITMAP bmp
)
308 m_refData
= new wxBitmapRefData
;
310 M_BITMAPDATA
->m_hBitmap
= bmp
;
313 void wxBitmap::AddHandler(wxBitmapHandler
*handler
)
315 sm_handlers
.Append(handler
);
318 void wxBitmap::InsertHandler(wxBitmapHandler
*handler
)
320 sm_handlers
.Insert(handler
);
323 bool wxBitmap::RemoveHandler(const wxString
& name
)
325 wxBitmapHandler
*handler
= FindHandler(name
);
328 sm_handlers
.DeleteObject(handler
);
335 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& name
)
337 wxNode
*node
= sm_handlers
.First();
340 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
341 if ( (handler
->GetName().Cmp(name
) == 0) )
348 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& extension
, long bitmapType
)
350 wxNode
*node
= sm_handlers
.First();
353 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
354 if ( (handler
->GetExtension().Cmp(extension
) == 0) &&
355 (bitmapType
== -1 || (handler
->GetType() == bitmapType
)) )
362 wxBitmapHandler
*wxBitmap::FindHandler(long bitmapType
)
364 wxNode
*node
= sm_handlers
.First();
367 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
368 if (handler
->GetType() == bitmapType
)
375 // New Create/FreeDIB functions since ones in dibutils.cpp are confusing
376 static long createDIB(long xSize
, long ySize
, long bitsPerPixel
,
377 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
);
378 static long freeDIB(LPBITMAPINFO lpDIBHeader
);
380 // Creates a bitmap that matches the device context, from
381 // an arbitray bitmap. At present, the original bitmap must have an
382 // associated palette. TODO: use a default palette if no palette exists.
383 // Contributed by Frederic Villeneuve <frederic.villeneuve@natinst.com>
384 wxBitmap
wxBitmap::GetBitmapForDC(wxDC
& dc
) const
387 wxBitmap
tmpBitmap(this->GetWidth(), this->GetHeight(), dc
.GetDepth());
388 HPALETTE hPal
= (HPALETTE
) NULL
;
390 void *lpBits
= (void*) NULL
;
393 wxASSERT( this->GetPalette() && this->GetPalette()->Ok() && (this->GetPalette()->GetHPALETTE() != 0) );
395 tmpBitmap.SetPalette(this->GetPalette());
396 memDC.SelectObject(tmpBitmap);
397 memDC.SetPalette(this->GetPalette());
399 hPal = (HPALETTE) this->GetPalette()->GetHPALETTE();
401 if( this->GetPalette() && this->GetPalette()->Ok() && (this->GetPalette()->GetHPALETTE() != 0) )
403 tmpBitmap
.SetPalette(* this->GetPalette());
404 memDC
.SelectObject(tmpBitmap
);
405 memDC
.SetPalette(* this->GetPalette());
406 hPal
= (HPALETTE
) this->GetPalette()->GetHPALETTE();
410 hPal
= (HPALETTE
) ::GetStockObject(DEFAULT_PALETTE
);
412 palette
.SetHPALETTE( (WXHPALETTE
)hPal
);
413 tmpBitmap
.SetPalette( palette
);
414 memDC
.SelectObject(tmpBitmap
);
415 memDC
.SetPalette( palette
);
418 // set the height negative because in a DIB the order of the lines is reversed
419 createDIB(this->GetWidth(), -this->GetHeight(), this->GetDepth(), hPal
, &lpDib
);
421 lpBits
= malloc(lpDib
->bmiHeader
.biSizeImage
);
423 ::GetBitmapBits((HBITMAP
)GetHBITMAP(), lpDib
->bmiHeader
.biSizeImage
, lpBits
);
425 ::SetDIBitsToDevice((HDC
) memDC
.GetHDC(), 0, 0, this->GetWidth(), this->GetHeight(),
426 0, 0, 0, this->GetHeight(), lpBits
, lpDib
, DIB_RGB_COLORS
);
443 // Construct a mask from a bitmap and a colour indicating
444 // the transparent area
445 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
448 Create(bitmap
, colour
);
451 // Construct a mask from a bitmap and a palette index indicating
452 // the transparent area
453 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
456 Create(bitmap
, paletteIndex
);
459 // Construct a mask from a mono bitmap (copies the bitmap).
460 wxMask::wxMask(const wxBitmap
& bitmap
)
466 wxMask::~wxMask(void)
469 ::DeleteObject((HBITMAP
) m_maskBitmap
);
472 // Create a mask from a mono bitmap (copies the bitmap).
473 bool wxMask::Create(const wxBitmap
& bitmap
)
477 ::DeleteObject((HBITMAP
) m_maskBitmap
);
480 if (!bitmap
.Ok() || bitmap
.GetDepth() != 1)
484 m_maskBitmap
= (WXHBITMAP
) CreateBitmap(
489 HDC srcDC
= CreateCompatibleDC(0);
490 SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
491 HDC destDC
= CreateCompatibleDC(0);
492 SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
493 BitBlt(destDC
, 0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), srcDC
, 0, 0, SRCCOPY
);
494 SelectObject(srcDC
, 0);
496 SelectObject(destDC
, 0);
501 // Create a mask from a bitmap and a palette index indicating
502 // the transparent area
503 bool wxMask::Create(const wxBitmap
& bitmap
, int paletteIndex
)
507 ::DeleteObject((HBITMAP
) m_maskBitmap
);
510 if (bitmap
.Ok() && bitmap
.GetPalette()->Ok())
512 unsigned char red
, green
, blue
;
513 if (bitmap
.GetPalette()->GetRGB(paletteIndex
, &red
, &green
, &blue
))
515 wxColour
transparentColour(red
, green
, blue
);
516 return Create(bitmap
, transparentColour
);
522 // Create a mask from a bitmap and a colour indicating
523 // the transparent area
524 bool wxMask::Create(const wxBitmap
& bitmap
, const wxColour
& colour
)
528 ::DeleteObject((HBITMAP
) m_maskBitmap
);
536 // scan the bitmap for the transparent colour and set
537 // the corresponding pixels in the mask to BLACK and
539 COLORREF maskColour
= RGB(colour
.Red(), colour
.Green(), colour
.Blue());
540 m_maskBitmap
= (WXHBITMAP
) ::CreateBitmap(
545 HDC srcDC
= ::CreateCompatibleDC(0);
546 ::SelectObject(srcDC
, (HBITMAP
) bitmap
.GetHBITMAP());
547 HDC destDC
= ::CreateCompatibleDC(0);
548 ::SelectObject(destDC
, (HBITMAP
) m_maskBitmap
);
550 // this is not very efficient, but I can't think
551 // of a better way of doing it
552 for (int w
= 0; w
< bitmap
.GetWidth(); w
++)
554 for (int h
= 0; h
< bitmap
.GetHeight(); h
++)
556 COLORREF col
= GetPixel(srcDC
, w
, h
);
557 if (col
== maskColour
)
559 ::SetPixel(destDC
, w
, h
, RGB(0, 0, 0));
563 ::SetPixel(destDC
, w
, h
, RGB(255, 255, 255));
567 ::SelectObject(srcDC
, 0);
569 ::SelectObject(destDC
, 0);
578 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
580 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
), void *WXUNUSED(data
), long WXUNUSED(type
), int WXUNUSED(width
), int WXUNUSED(height
), int WXUNUSED(depth
))
585 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), long WXUNUSED(type
),
586 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
591 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), int WXUNUSED(type
), const wxPalette
*WXUNUSED(palette
))
600 class WXDLLEXPORT wxBMPResourceHandler
: public wxBitmapHandler
602 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler
)
604 inline wxBMPResourceHandler(void)
606 m_name
= "Windows bitmap resource";
608 m_type
= wxBITMAP_TYPE_BMP_RESOURCE
;
611 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
612 int desiredWidth
, int desiredHeight
);
614 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler
, wxBitmapHandler
)
616 bool wxBMPResourceHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
617 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
619 // TODO: load colourmap.
620 M_BITMAPHANDLERDATA
->m_hBitmap
= (WXHBITMAP
) ::LoadBitmap(wxGetInstance(), name
);
621 if (M_BITMAPHANDLERDATA
->m_hBitmap
)
623 M_BITMAPHANDLERDATA
->m_ok
= TRUE
;
625 GetObject((HBITMAP
) M_BITMAPHANDLERDATA
->m_hBitmap
, sizeof(BITMAP
), (LPSTR
) &bm
);
626 M_BITMAPHANDLERDATA
->m_width
= bm
.bmWidth
;
627 M_BITMAPHANDLERDATA
->m_height
= bm
.bmHeight
;
628 M_BITMAPHANDLERDATA
->m_depth
= bm
.bmBitsPixel
;
630 if ( bitmap
->IsKindOf(CLASSINFO(wxIcon
)) )
637 // it's probably not found
638 wxLogError(_T("Can't load bitmap '%s' from resources! Check .rc file."), name
.c_str());
643 class WXDLLEXPORT wxBMPFileHandler
: public wxBitmapHandler
645 DECLARE_DYNAMIC_CLASS(wxBMPFileHandler
)
647 inline wxBMPFileHandler(void)
649 m_name
= "Windows bitmap file";
651 m_type
= wxBITMAP_TYPE_BMP
;
654 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
655 int desiredWidth
, int desiredHeight
);
656 virtual bool SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int type
, const wxPalette
*palette
= NULL
);
658 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler
, wxBitmapHandler
)
660 bool wxBMPFileHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
661 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
663 #if wxUSE_IMAGE_LOADING_IN_MSW
664 wxPalette
*palette
= NULL
;
665 bool success
= FALSE
;
667 if (type & wxBITMAP_DISCARD_COLOURMAP)
668 success = wxLoadIntoBitmap(WXSTRINGCAST name, bitmap);
671 success
= (wxLoadIntoBitmap(WXSTRINGCAST name
, bitmap
, &palette
) != 0);
672 if (!success
&& palette
)
679 M_BITMAPHANDLERDATA
->m_bitmapPalette
= *palette
;
688 bool wxBMPFileHandler::SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int WXUNUSED(type
), const wxPalette
*pal
)
690 #if wxUSE_IMAGE_LOADING_IN_MSW
691 wxPalette
*actualPalette
= (wxPalette
*)pal
;
692 if (!actualPalette
&& (!M_BITMAPHANDLERDATA
->m_bitmapPalette
.IsNull()))
693 actualPalette
= & (M_BITMAPHANDLERDATA
->m_bitmapPalette
);
694 return (wxSaveBitmap(WXSTRINGCAST name
, bitmap
, actualPalette
) != 0);
700 void wxBitmap::CleanUpHandlers(void)
702 wxNode
*node
= sm_handlers
.First();
705 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
706 wxNode
*next
= node
->Next();
713 void wxBitmap::InitStandardHandlers(void)
715 AddHandler(new wxBMPResourceHandler
);
716 AddHandler(new wxBMPFileHandler
);
718 // Not added by default: include xpmhand.h in your app
719 // and call these in your wxApp::OnInit.
720 // AddHandler(new wxXPMFileHandler);
721 // AddHandler(new wxXPMDataHandler);
723 AddHandler(new wxICOResourceHandler
);
724 AddHandler(new wxICOFileHandler
);
727 static long createDIB(long xSize
, long ySize
, long bitsPerPixel
,
728 HPALETTE hPal
, LPBITMAPINFO
* lpDIBHeader
)
730 unsigned long i
, headerSize
;
731 LPBITMAPINFO lpDIBheader
= NULL
;
732 LPPALETTEENTRY lpPe
= NULL
;
735 // Allocate space for a DIB header
736 headerSize
= (sizeof(BITMAPINFOHEADER
) + (256 * sizeof(PALETTEENTRY
)));
737 lpDIBheader
= (BITMAPINFO
*) malloc(headerSize
);
738 lpPe
= (PALETTEENTRY
*)((BYTE
*)lpDIBheader
+ sizeof(BITMAPINFOHEADER
));
740 GetPaletteEntries(hPal
, 0, 256, lpPe
);
743 memset(lpDIBheader
, 0x00, sizeof(BITMAPINFOHEADER
));
746 // Fill in the static parts of the DIB header
747 lpDIBheader
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
748 lpDIBheader
->bmiHeader
.biWidth
= xSize
;
749 lpDIBheader
->bmiHeader
.biHeight
= ySize
;
750 lpDIBheader
->bmiHeader
.biPlanes
= 1;
752 // this value must be 1, 4, 8 or 24 so PixelDepth can only be
753 lpDIBheader
->bmiHeader
.biBitCount
= (WORD
)(bitsPerPixel
);
754 lpDIBheader
->bmiHeader
.biCompression
= BI_RGB
;
755 lpDIBheader
->bmiHeader
.biSizeImage
= xSize
* abs(ySize
) * bitsPerPixel
>>
757 lpDIBheader
->bmiHeader
.biClrUsed
= 256;
760 // Initialize the DIB palette
761 for (i
= 0; i
< 256; i
++) {
762 lpDIBheader
->bmiColors
[i
].rgbReserved
= lpPe
[i
].peFlags
;
763 lpDIBheader
->bmiColors
[i
].rgbRed
= lpPe
[i
].peRed
;
764 lpDIBheader
->bmiColors
[i
].rgbGreen
= lpPe
[i
].peGreen
;
765 lpDIBheader
->bmiColors
[i
].rgbBlue
= lpPe
[i
].peBlue
;
768 *lpDIBHeader
= lpDIBheader
;
777 static long freeDIB(LPBITMAPINFO lpDIBHeader
)
780 if (lpDIBHeader
!= NULL
) {