1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/gdiimage.cpp 
   3 // Purpose:     wxGDIImage implementation 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "gdiimage.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  32     #include "wx/string.h" 
  36 #include "wx/msw/private.h" 
  40 #include "wx/bitmap.h" 
  41 #include "wx/msw/gdiimage.h" 
  44 #include "wx/msw/dib.h" 
  54 #include "wx/listimpl.cpp" 
  55 WX_DEFINE_LIST(wxGDIImageHandlerList
); 
  57 // ---------------------------------------------------------------------------- 
  58 // auxiliary functions 
  59 // ---------------------------------------------------------------------------- 
  62 // Used in wxBMPFileHandler::LoadFile 
  63 HBITMAP 
wxLoadBMP(const wxString
& filename
) ; 
  66 // ---------------------------------------------------------------------------- 
  68 // ---------------------------------------------------------------------------- 
  70 #ifndef __WXMICROWIN__ 
  72 // all image handlers are declared/defined in this file because the outside 
  73 // world doesn't have to know about them (but only about wxBITMAP_TYPE_XXX ids) 
  75 class WXDLLEXPORT wxBMPFileHandler 
: public wxBitmapHandler
 
  78     wxBMPFileHandler() : wxBitmapHandler(_T("Windows bitmap file"), _T("bmp"), 
  83     virtual bool LoadFile(wxBitmap 
*bitmap
, 
  84                           const wxString
& name
, long flags
, 
  85                           int desiredWidth
, int desiredHeight
); 
  86     virtual bool SaveFile(wxBitmap 
*bitmap
, 
  87                           const wxString
& name
, int type
, 
  88                           const wxPalette 
*palette 
= NULL
); 
  91     DECLARE_DYNAMIC_CLASS(wxBMPFileHandler
) 
  94 class WXDLLEXPORT wxBMPResourceHandler
: public wxBitmapHandler
 
  97     wxBMPResourceHandler() : wxBitmapHandler(_T("Windows bitmap resource"), 
  99                                              wxBITMAP_TYPE_BMP_RESOURCE
) 
 103     virtual bool LoadFile(wxBitmap 
*bitmap
, 
 104                           const wxString
& name
, long flags
, 
 105                           int desiredWidth
, int desiredHeight
); 
 108     DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler
) 
 111 class WXDLLEXPORT wxIconHandler 
: public wxGDIImageHandler
 
 114     wxIconHandler(const wxString
& name
, const wxString
& ext
, long type
) 
 115         : wxGDIImageHandler(name
, ext
, type
) 
 119     // creating and saving icons is not supported 
 120     virtual bool Create(wxGDIImage 
*WXUNUSED(image
), 
 121                         void *WXUNUSED(data
), 
 122                         long WXUNUSED(flags
), 
 124                         int WXUNUSED(height
), 
 125                         int WXUNUSED(depth
) = 1) 
 130     virtual bool Save(wxGDIImage 
*WXUNUSED(image
), 
 131                       const wxString
& WXUNUSED(name
), 
 137     virtual bool Load(wxGDIImage 
*image
, 
 138                       const wxString
& name
, 
 140                       int desiredWidth
, int desiredHeight
) 
 142         wxIcon 
*icon 
= wxDynamicCast(image
, wxIcon
); 
 143         wxCHECK_MSG( icon
, false, _T("wxIconHandler only works with icons") ); 
 145         return LoadIcon(icon
, name
, flags
, desiredWidth
, desiredHeight
); 
 149     virtual bool LoadIcon(wxIcon 
*icon
, 
 150                           const wxString
& name
, long flags
, 
 151                           int desiredWidth 
= -1, int desiredHeight 
= -1) = 0; 
 154 class WXDLLEXPORT wxICOFileHandler 
: public wxIconHandler
 
 157     wxICOFileHandler() : wxIconHandler(_T("ICO icon file"), 
 163     virtual bool LoadIcon(wxIcon 
*icon
, 
 164                           const wxString
& name
, long flags
, 
 165                           int desiredWidth 
= -1, int desiredHeight 
= -1); 
 168     DECLARE_DYNAMIC_CLASS(wxICOFileHandler
) 
 171 class WXDLLEXPORT wxICOResourceHandler
: public wxIconHandler
 
 174     wxICOResourceHandler() : wxIconHandler(_T("ICO resource"), 
 176                                            wxBITMAP_TYPE_ICO_RESOURCE
) 
 180     virtual bool LoadIcon(wxIcon 
*icon
, 
 181                           const wxString
& name
, long flags
, 
 182                           int desiredWidth 
= -1, int desiredHeight 
= -1); 
 185     DECLARE_DYNAMIC_CLASS(wxICOResourceHandler
) 
 188 // ---------------------------------------------------------------------------- 
 190 // ---------------------------------------------------------------------------- 
 192 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler
, wxBitmapHandler
) 
 193 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler
, wxBitmapHandler
) 
 194 IMPLEMENT_DYNAMIC_CLASS(wxICOFileHandler
, wxObject
) 
 195 IMPLEMENT_DYNAMIC_CLASS(wxICOResourceHandler
, wxObject
) 
 197 // ---------------------------------------------------------------------------- 
 199 // ---------------------------------------------------------------------------- 
 204 // ============================================================================ 
 206 // ============================================================================ 
 208 wxGDIImageHandlerList 
wxGDIImage::ms_handlers
; 
 210 // ---------------------------------------------------------------------------- 
 211 // wxGDIImage functions forwarded to wxGDIImageRefData 
 212 // ---------------------------------------------------------------------------- 
 214 bool wxGDIImage::FreeResource(bool WXUNUSED(force
)) 
 218         GetGDIImageData()->Free(); 
 219         GetGDIImageData()->m_handle 
= 0; 
 225 WXHANDLE 
wxGDIImage::GetResourceHandle() const 
 230 // ---------------------------------------------------------------------------- 
 231 // wxGDIImage handler stuff 
 232 // ---------------------------------------------------------------------------- 
 234 void wxGDIImage::AddHandler(wxGDIImageHandler 
*handler
) 
 236     ms_handlers
.Append(handler
); 
 239 void wxGDIImage::InsertHandler(wxGDIImageHandler 
*handler
) 
 241     ms_handlers
.Insert(handler
); 
 244 bool wxGDIImage::RemoveHandler(const wxString
& name
) 
 246     wxGDIImageHandler 
*handler 
= FindHandler(name
); 
 249         ms_handlers
.DeleteObject(handler
); 
 256 wxGDIImageHandler 
*wxGDIImage::FindHandler(const wxString
& name
) 
 258     wxGDIImageHandlerList::compatibility_iterator node 
= ms_handlers
.GetFirst(); 
 261         wxGDIImageHandler 
*handler 
= node
->GetData(); 
 262         if ( handler
->GetName() == name 
) 
 264         node 
= node
->GetNext(); 
 270 wxGDIImageHandler 
*wxGDIImage::FindHandler(const wxString
& extension
, 
 273     wxGDIImageHandlerList::compatibility_iterator node 
= ms_handlers
.GetFirst(); 
 276         wxGDIImageHandler 
*handler 
= node
->GetData(); 
 277         if ( (handler
->GetExtension() = extension
) && 
 278              (type 
== -1 || handler
->GetType() == type
) ) 
 283         node 
= node
->GetNext(); 
 288 wxGDIImageHandler 
*wxGDIImage::FindHandler(long type
) 
 290     wxGDIImageHandlerList::compatibility_iterator node 
= ms_handlers
.GetFirst(); 
 293         wxGDIImageHandler 
*handler 
= node
->GetData(); 
 294         if ( handler
->GetType() == type 
) 
 297         node 
= node
->GetNext(); 
 303 void wxGDIImage::CleanUpHandlers() 
 305     wxGDIImageHandlerList::compatibility_iterator node 
= ms_handlers
.GetFirst(); 
 308         wxGDIImageHandler 
*handler 
= node
->GetData(); 
 309         wxGDIImageHandlerList::compatibility_iterator next 
= node
->GetNext(); 
 311         ms_handlers
.Erase( node 
); 
 316 void wxGDIImage::InitStandardHandlers() 
 318 #ifndef __WXMICROWIN__ 
 319     AddHandler(new wxBMPResourceHandler
); 
 320     AddHandler(new wxBMPFileHandler
); 
 321     AddHandler(new wxICOResourceHandler
); 
 322     AddHandler(new wxICOFileHandler
); 
 326 #ifndef __WXMICROWIN__ 
 328 // ---------------------------------------------------------------------------- 
 330 // ---------------------------------------------------------------------------- 
 332 bool wxBMPResourceHandler::LoadFile(wxBitmap 
*bitmap
, 
 333                                     const wxString
& name
, long WXUNUSED(flags
), 
 334                                     int WXUNUSED(desiredWidth
), 
 335                                     int WXUNUSED(desiredHeight
)) 
 337     // TODO: load colourmap. 
 338     bitmap
->SetHBITMAP((WXHBITMAP
)::LoadBitmap(wxGetInstance(), name
)); 
 342         // it's probably not found 
 343         wxLogError(wxT("Can't load bitmap '%s' from resources! Check .rc file."), 
 350     if ( !::GetObject(GetHbitmapOf(*bitmap
), sizeof(BITMAP
), (LPSTR
) &bm
) ) 
 352         wxLogLastError(wxT("GetObject(HBITMAP)")); 
 355     bitmap
->SetWidth(bm
.bmWidth
); 
 356     bitmap
->SetHeight(bm
.bmHeight
); 
 357     bitmap
->SetDepth(bm
.bmBitsPixel
); 
 359     // use 0xc0c0c0 as transparent colour by default 
 360     bitmap
->SetMask(new wxMask(*bitmap
, *wxLIGHT_GREY
)); 
 365 bool wxBMPFileHandler::LoadFile(wxBitmap 
*bitmap
, 
 366                                 const wxString
& name
, long WXUNUSED(flags
), 
 367                                 int WXUNUSED(desiredWidth
), 
 368                                 int WXUNUSED(desiredHeight
)) 
 371     wxCHECK_MSG( bitmap
, false, _T("NULL bitmap in LoadFile") ); 
 375     bool ok 
= dib
.IsOk() && bitmap
->CopyFromDIB(dib
); 
 378   WXHBITMAP hBitmap 
= (WXHBITMAP
)wxLoadBMP(name
); 
 380       bitmap
->SetHBITMAP(hBitmap
); 
 387 bool wxBMPFileHandler::SaveFile(wxBitmap 
*bitmap
, 
 388                                 const wxString
& name
, 
 390                                 const wxPalette 
* WXUNUSED(pal
)) 
 393     wxCHECK_MSG( bitmap
, false, _T("NULL bitmap in SaveFile") ); 
 397     return dib
.Save(name
); 
 403 // ---------------------------------------------------------------------------- 
 405 // ---------------------------------------------------------------------------- 
 407 bool wxICOFileHandler::LoadIcon(wxIcon 
*icon
, 
 408                                 const wxString
& name
, 
 409                                 long WXUNUSED(flags
), 
 410                                 int desiredWidth
, int desiredHeight
) 
 419     // Parse the filename: it may be of the form "filename;n" in order to 
 420     // specify the nth icon in the file. 
 422     // For the moment, ignore the issue of possible semicolons in the 
 425     wxString 
nameReal(name
); 
 426     wxString strIconIndex 
= name
.AfterLast(wxT(';')); 
 427     if (strIconIndex 
!= name
) 
 429         iconIndex 
= wxAtoi(strIconIndex
); 
 430         nameReal 
= name
.BeforeLast(wxT(';')); 
 434     // If we don't know what size icon we're looking for, 
 435     // try to find out what's there. 
 436     // Unfortunately this doesn't work, because ExtractIconEx 
 437     // will scale the icon to the 'desired' size, even if that 
 438     // size of icon isn't explicitly stored. So we would have 
 439     // to parse the icon file outselves. 
 440     if ( desiredWidth 
== -1 && 
 443         // Try loading a large icon first 
 444         if ( ::ExtractIconEx(nameReal
, iconIndex
, &hicon
, NULL
, 1) == 1) 
 447         // Then try loading a small icon 
 448         else if ( ::ExtractIconEx(nameReal
, iconIndex
, NULL
, &hicon
, 1) == 1) 
 454         // were we asked for a large icon? 
 455     if ( desiredWidth 
== ::GetSystemMetrics(SM_CXICON
) && 
 456          desiredHeight 
== ::GetSystemMetrics(SM_CYICON
) ) 
 458         // get the specified large icon from file 
 459         if ( !::ExtractIconEx(nameReal
, iconIndex
, &hicon
, NULL
, 1) ) 
 461             // it is not an error, but it might still be useful to be informed 
 462             // about it optionally 
 463             wxLogTrace(_T("iconload"), 
 464                        _T("No large icons found in the file '%s'."), 
 468     else if ( desiredWidth 
== ::GetSystemMetrics(SM_CXSMICON
) && 
 469               desiredHeight 
== ::GetSystemMetrics(SM_CYSMICON
) ) 
 471         // get the specified small icon from file 
 472         if ( !::ExtractIconEx(nameReal
, iconIndex
, NULL
, &hicon
, 1) ) 
 474             wxLogTrace(_T("iconload"), 
 475                        _T("No small icons found in the file '%s'."), 
 479     //else: not standard size, load below 
 484         // take any size icon from the file by index 
 485         hicon 
= ::ExtractIcon(wxGetInstance(), nameReal
, iconIndex
); 
 491         wxLogSysError(_T("Failed to load icon from the file '%s'"), 
 497     size 
= wxGetHiconSize(hicon
); 
 499     if ( (desiredWidth 
!= -1 && desiredWidth 
!= size
.x
) || 
 500          (desiredHeight 
!= -1 && desiredHeight 
!= size
.y
) ) 
 502         wxLogTrace(_T("iconload"), 
 503                    _T("Returning false from wxICOFileHandler::Load because of the size mismatch: actual (%d, %d), requested (%d, %d)"), 
 505                    desiredWidth
, desiredHeight
); 
 507         ::DestroyIcon(hicon
); 
 512     icon
->SetHICON((WXHICON
)hicon
); 
 513     icon
->SetSize(size
.x
, size
.y
); 
 518 bool wxICOResourceHandler::LoadIcon(wxIcon 
*icon
, 
 519                                     const wxString
& name
, 
 520                                     long WXUNUSED(flags
), 
 521                                     int desiredWidth
, int desiredHeight
) 
 525     // do we need the icon of the specific size or would any icon do? 
 526     bool hasSize 
= desiredWidth 
!= -1 || desiredHeight 
!= -1; 
 528     wxASSERT_MSG( !hasSize 
|| (desiredWidth 
!= -1 && desiredHeight 
!= -1), 
 529                   _T("width and height should be either both -1 or not") ); 
 531     // try to load the icon from this program first to allow overriding the 
 532     // standard icons (although why one would want to do it considering that 
 533     // we already have wxApp::GetStdIcon() is unclear) 
 535     // note that we can't just always call LoadImage() because it seems to do 
 536     // some icon rescaling internally which results in very ugly 16x16 icons 
 539         hicon 
= (HICON
)::LoadImage(wxGetInstance(), name
, IMAGE_ICON
, 
 540                                     desiredWidth
, desiredHeight
, 
 545         hicon 
= ::LoadIcon(wxGetInstance(), name
); 
 548     // next check if it's not a standard icon 
 550     if ( !hicon 
&& !hasSize 
) 
 558             { wxT("wxICON_QUESTION"),   IDI_QUESTION    
}, 
 559             { wxT("wxICON_WARNING"),    IDI_EXCLAMATION 
}, 
 560             { wxT("wxICON_ERROR"),      IDI_HAND        
}, 
 561             { wxT("wxICON_INFORMATION"),       IDI_ASTERISK    
}, 
 564         for ( size_t nIcon 
= 0; !hicon 
&& nIcon 
< WXSIZEOF(stdIcons
); nIcon
++ ) 
 566             if ( name 
== stdIcons
[nIcon
].name 
) 
 568                 hicon 
= ::LoadIcon((HINSTANCE
)NULL
, stdIcons
[nIcon
].id
); 
 574     wxSize size 
= wxGetHiconSize(hicon
); 
 575     icon
->SetSize(size
.x
, size
.y
); 
 577     icon
->SetHICON((WXHICON
)hicon
); 
 582 // ---------------------------------------------------------------------------- 
 584 // ---------------------------------------------------------------------------- 
 586 wxSize 
wxGetHiconSize(HICON hicon
) 
 588     wxSize 
size(32, 32);    // default 
 590     if ( hicon 
&& wxGetOsVersion() != wxWIN32S 
) 
 593         if ( !::GetIconInfo(hicon
, &info
) ) 
 595             wxLogLastError(wxT("GetIconInfo")); 
 599             HBITMAP hbmp 
= info
.hbmMask
; 
 603                 if ( ::GetObject(hbmp
, sizeof(BITMAP
), (LPSTR
) &bm
) ) 
 605                     size 
= wxSize(bm
.bmWidth
, bm
.bmHeight
); 
 608                 ::DeleteObject(info
.hbmMask
); 
 611                 ::DeleteObject(info
.hbmColor
); 
 618 #endif // __WXMICROWIN__ 
 621 // Used in wxBMPFileHandler::LoadFile 
 622 HBITMAP 
wxLoadBMP(const wxString
& filename
) 
 625   if(!file
.Open(filename
)) 
 628     // The first part of the file contains the file header. 
 629   // This will tell us if it is a bitmap, how big the header is, and how big 
 630     // the file is. The header size in the file header includes the color table. 
 631   BITMAPFILEHEADER BmpFileHdr
; 
 632   BITMAPINFO 
*pBmpInfo 
= (BITMAPINFO
*)malloc(sizeof(BITMAPINFO
)+255*sizeof(RGBQUAD
)); 
 636   if(file
.Read(&BmpFileHdr
, sizeof(BmpFileHdr
))==sizeof(BmpFileHdr
) 
 637     && !strncmp((char*)&BmpFileHdr
.bfType
,"BM",2) 
 638     && file
.Read(pBmpInfo
, sizeof(BITMAPINFOHEADER
))==sizeof(BITMAPINFOHEADER
) 
 639     && pBmpInfo
->bmiHeader
.biSize 
== sizeof(BITMAPINFOHEADER
)) { 
 642       unsigned int nColors 
= pBmpInfo
->bmiHeader
.biClrUsed 
? 
 643       pBmpInfo
->bmiHeader
.biClrUsed 
: 1 << pBmpInfo
->bmiHeader
.biBitCount
; 
 645       || file
.Read(pBmpInfo
->bmiColors
, nColors 
* sizeof(RGBQUAD
)) 
 646         == (off_t
)(nColors 
* sizeof(RGBQUAD
))) { 
 648       // So how big the bitmap surface is. 
 649       int nBitsSize 
= BmpFileHdr
.bfSize 
- BmpFileHdr
.bfOffBits
; 
 651         // Allocate the memory for the bits and read the bits from the file. 
 652       pBits 
= (BYTE
*) malloc(nBitsSize
*2); 
 654         // Seek to the bits in the file. 
 655         file
.Seek(BmpFileHdr
.bfOffBits
); 
 658         if(file
.Read(pBits
, nBitsSize
)==nBitsSize
) { 
 659           // Everything went OK. 
 660           pBmpInfo
->bmiHeader
.biSizeImage 
= nBitsSize
; 
 662           //HBITMAP hBitmap=SetBitmap((LPBITMAPINFO)pBmpInfo, pBits); 
 663             DWORD dwBitmapInfoSize 
= sizeof(BITMAPINFO
) + nColors
*sizeof(RGBQUAD
); 
 665             // Create a DC which will be used to get DIB, then create DIBsection 
 666             HDC hDC 
= ::GetDC(NULL
); 
 669             hBitmap 
= CreateDIBSection(hDC
, (const BITMAPINFO
*) pBmpInfo
, 
 670               DIB_RGB_COLORS
, &bits
, NULL
, 0); 
 674               DWORD dwImageSize 
= pBmpInfo
->bmiHeader
.biSizeImage
; 
 675               if (dwImageSize 
== 0) { 
 676                 int nBytesPerLine 
= pBmpInfo
->bmiHeader
.biWidth 
* pBmpInfo
->bmiHeader
.biBitCount
; 
 677                 nBytesPerLine 
= ( (nBytesPerLine 
+ 31) & (~31) ) / 8; 
 678                 dwImageSize 
= nBytesPerLine 
* pBmpInfo
->bmiHeader
.biHeight
; 
 680               memcpy(bits
, pBits
, dwImageSize
);