]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dib.cpp
   1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/dib.cpp 
   3 // Purpose:     implements wxDIB class 
   4 // Author:      Vadim Zeitlin 
   6 // Created:     03.03.03 (replaces the old file with the same name) 
   8 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  13     TODO: support for palettes is very incomplete, several functions simply 
  14           ignore them (we should select and realize the palette, if any, before 
  15           caling GetDIBits() in the DC we use with it. 
  18 // ============================================================================ 
  20 // ============================================================================ 
  22 // ---------------------------------------------------------------------------- 
  24 // ---------------------------------------------------------------------------- 
  26 // For compilers that support precompilation, includes "wx.h". 
  27 #include "wx/wxprec.h" 
  34     #include "wx/string.h" 
  40 #include "wx/bitmap.h" 
  47 #if !defined(__MWERKS__) && !defined(__SALFORDC__) 
  51 #ifdef __GNUWIN32_OLD__ 
  52     #include "wx/msw/gnuwin32/extra.h" 
  56 #include "wx/msw/dib.h" 
  59     #include <shellapi.h>       // for SHLoadDIBitmap() 
  62 // ---------------------------------------------------------------------------- 
  64 // ---------------------------------------------------------------------------- 
  66 // calculate the number of palette entries needed for the bitmap with this 
  67 // number of bits per pixel 
  68 static inline WORD 
GetNumberOfColours(WORD bitsPerPixel
) 
  70     // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with 
  71     // 24bpp ones too but we don't support this as I think it's quite uncommon) 
  72     return bitsPerPixel 
<= 8 ? 1 << bitsPerPixel 
: 0; 
  75 // wrapper around ::GetObject() for DIB sections 
  76 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION 
*ds
) 
  78     // note that at least under Win9x (this doesn't seem to happen under Win2K 
  79     // but this doesn't mean anything, of course), GetObject() may return 
  80     // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way 
  81     // to check for it is by looking at the bits pointer 
  82     return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) && 
  86 // ============================================================================ 
  88 // ============================================================================ 
  90 // ---------------------------------------------------------------------------- 
  92 // ---------------------------------------------------------------------------- 
  94 bool wxDIB::Create(int width
, int height
, int depth
) 
  96     // we don't support formats using palettes right now so we only create 
  97     // either 24bpp (RGB) or 32bpp (RGBA) bitmaps 
  98     wxASSERT_MSG( depth
, _T("invalid image depth in wxDIB::Create()") ); 
 102     // allocate memory for bitmap structures 
 103     static const int sizeHeader 
= sizeof(BITMAPINFOHEADER
); 
 105     BITMAPINFO 
*info 
= (BITMAPINFO 
*)malloc(sizeHeader
); 
 106     wxCHECK_MSG( info
, false, _T("malloc(BITMAPINFO) failed") ); 
 108     memset(info
, 0, sizeHeader
); 
 110     info
->bmiHeader
.biSize 
= sizeHeader
; 
 111     info
->bmiHeader
.biWidth 
= width
; 
 113     // we use positive height here which corresponds to a DIB with normal, i.e. 
 114     // bottom to top, order -- normally using negative height (which means 
 115     // reversed for MS and hence natural for all the normal people top to 
 116     // bottom line scan order) could be used to avoid the need for the image 
 117     // reversal in Create(image) but this doesn't work under NT, only Win9x! 
 118     info
->bmiHeader
.biHeight 
= height
; 
 120     info
->bmiHeader
.biPlanes 
= 1; 
 121     info
->bmiHeader
.biBitCount 
= depth
; 
 122     info
->bmiHeader
.biSizeImage 
= GetLineSize(width
, depth
)*height
; 
 124     m_handle 
= ::CreateDIBSection
 
 126                     0,              // hdc (unused with DIB_RGB_COLORS) 
 127                     info
,           // bitmap description 
 128                     DIB_RGB_COLORS
, // use RGB, not palette 
 129                     &m_data
,        // [out] DIB bits 
 130                     NULL
,           // don't use file mapping 
 131                     0               // file mapping offset (not used here) 
 138         wxLogLastError(wxT("CreateDIBSection")); 
 150 bool wxDIB::Create(const wxBitmap
& bmp
) 
 152     wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") ); 
 154     // this bitmap could already be a DIB section in which case we don't need 
 155     // to convert it to DIB 
 156     HBITMAP hbmp 
= GetHbitmapOf(bmp
); 
 159     if ( GetDIBSection(hbmp
, &ds
) ) 
 163         // wxBitmap will free it, not we 
 164         m_ownsHandle 
= false; 
 166         // copy all the bitmap parameters too as we have them now anyhow 
 167         m_width 
= ds
.dsBm
.bmWidth
; 
 168         m_height 
= ds
.dsBm
.bmHeight
; 
 169         m_depth 
= ds
.dsBm
.bmBitsPixel
; 
 171         m_data 
= ds
.dsBm
.bmBits
; 
 173     else // no, it's a DDB -- convert it to DIB 
 175         const int w 
= bmp
.GetWidth(); 
 176         const int h 
= bmp
.GetHeight(); 
 177         int d 
= bmp
.GetDepth(); 
 179             d 
= wxDisplayDepth(); 
 181         if ( !Create(w
, h
, d
) || !CopyFromDDB(hbmp
) ) 
 188 // Windows CE doesn't have GetDIBits() so use an alternative implementation 
 191 // in fact I'm not sure if GetDIBits() is really much better than using 
 192 // BitBlt() like this -- it should be faster but I didn't do any tests, if 
 193 // anybody has time to do them and by chance finds that GetDIBits() is not 
 194 // much faster than BitBlt(), we could always use the Win CE version here 
 197 bool wxDIB::CopyFromDDB(HBITMAP hbmp
) 
 203     SelectInHDC 
selectSrc(hdcSrc
, hbmp
); 
 211     SelectInHDC 
selectDst(hdcDst
, m_handle
); 
 218                     0, 0, m_width
, m_height
, 
 224         wxLogLastError(_T("BitBlt(DDB -> DIB)")); 
 232 #else // !__WXWINCE__ 
 234 bool wxDIB::CopyFromDDB(HBITMAP hbmp
) 
 237     if ( !GetDIBSection(m_handle
, &ds
) ) 
 239         // we're sure that our handle is a DIB section, so this should work 
 240         wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") ); 
 247                 ScreenHDC(),                // the DC to use 
 248                 hbmp
,                       // the source DDB 
 249                 0,                          // first scan line 
 250                 m_height
,                   // number of lines to copy 
 251                 ds
.dsBm
.bmBits
,             // pointer to the buffer 
 252                 (BITMAPINFO 
*)&ds
.dsBmih
,   // bitmap header 
 253                 DIB_RGB_COLORS              
// and not DIB_PAL_COLORS 
 256         wxLogLastError(wxT("GetDIBits()")); 
 264 #endif // __WXWINCE__/!__WXWINCE__ 
 266 // ---------------------------------------------------------------------------- 
 267 // Loading/saving the DIBs 
 268 // ---------------------------------------------------------------------------- 
 270 bool wxDIB::Load(const wxString
& filename
) 
 273     m_handle 
= SHLoadDIBitmap(filename
); 
 274 #else // !__WXWINCE__ 
 275     m_handle 
= (HBITMAP
)::LoadImage
 
 280                             0, 0, // don't specify the size 
 281                             LR_CREATEDIBSECTION 
| LR_LOADFROMFILE
 
 283 #endif // __WXWINCE__ 
 287         wxLogLastError(_T("Loading DIB from file")); 
 295 bool wxDIB::Save(const wxString
& filename
) 
 297     wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") ); 
 299     wxFile 
file(filename
, wxFile::write
); 
 300     bool ok 
= file
.IsOpened(); 
 304         if ( !GetDIBSection(m_handle
, &ds
) ) 
 306             wxLogLastError(_T("GetObject(hDIB)")); 
 310             BITMAPFILEHEADER bmpHdr
; 
 311             wxZeroMemory(bmpHdr
); 
 313             const size_t sizeHdr 
= ds
.dsBmih
.biSize
; 
 314             const size_t sizeImage 
= ds
.dsBmih
.biSizeImage
; 
 316             bmpHdr
.bfType 
= 0x4d42;    // 'BM' in little endian 
 317             bmpHdr
.bfOffBits 
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
; 
 318             bmpHdr
.bfSize 
= bmpHdr
.bfOffBits 
+ sizeImage
; 
 320             // first write the file header, then the bitmap header and finally the 
 321             // bitmap data itself 
 322             ok 
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) && 
 323                     file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr 
&& 
 324                         file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
; 
 330         wxLogError(_("Failed to save the bitmap image to file \"%s\"."), 
 337 // ---------------------------------------------------------------------------- 
 339 // ---------------------------------------------------------------------------- 
 341 void wxDIB::DoGetObject() const 
 343     // only do something if we have a valid DIB but we don't [yet] have valid 
 345     if ( m_handle 
&& !m_data 
) 
 347         // although all the info we need is in BITMAP and so we don't really 
 348         // need DIBSECTION we still ask for it as modifying the bit values only 
 349         // works for the real DIBs and not for the bitmaps and it's better to 
 350         // check for this now rather than trying to find out why it doesn't 
 353         if ( !GetDIBSection(m_handle
, &ds
) ) 
 355             wxLogLastError(_T("GetObject(hDIB)")); 
 359         wxDIB 
*self 
= wxConstCast(this, wxDIB
); 
 361         self
->m_width 
= ds
.dsBm
.bmWidth
; 
 362         self
->m_height 
= ds
.dsBm
.bmHeight
; 
 363         self
->m_depth 
= ds
.dsBm
.bmBitsPixel
; 
 364         self
->m_data 
= ds
.dsBm
.bmBits
; 
 368 // ---------------------------------------------------------------------------- 
 369 // DDB <-> DIB conversions 
 370 // ---------------------------------------------------------------------------- 
 374 HBITMAP 
wxDIB::CreateDDB(HDC hdc
) const 
 376     wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") ); 
 379     if ( !GetDIBSection(m_handle
, &ds
) ) 
 381         wxLogLastError(_T("GetObject(hDIB)")); 
 386     return ConvertToBitmap((BITMAPINFO 
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
); 
 390 HBITMAP 
wxDIB::ConvertToBitmap(const BITMAPINFO 
*pbmi
, HDC hdc
, void *bits
) 
 392     wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") ); 
 394     // here we get BITMAPINFO struct followed by the actual bitmap bits and 
 395     // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info 
 396     const BITMAPINFOHEADER 
*pbmih 
= &pbmi
->bmiHeader
; 
 398     // get the pointer to the start of the real image data if we have a plain 
 399     // DIB and not a DIB section (in the latter case the pointer must be passed 
 400     // to us by the caller) 
 403         // we must skip over the colour table to get to the image data 
 405         // colour table either has the real colour data in which case its 
 406         // number of entries is given by biClrUsed or is used for masks to be 
 407         // used for extracting colour information from true colour bitmaps in 
 408         // which case it always have exactly 3 DWORDs 
 410         switch ( pbmih
->biCompression 
) 
 417                 // biClrUsed has the number of colors but it may be not initialized at 
 419                 numColors 
= pbmih
->biClrUsed
; 
 422                     numColors 
= GetNumberOfColours(pbmih
->biBitCount
); 
 427                 // no idea how it should be calculated for the other cases 
 431         bits 
= (char *)pbmih 
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
); 
 434     HBITMAP hbmp 
= ::CreateDIBitmap
 
 436                         hdc 
? hdc           
// create bitmap compatible 
 437                             : (HDC
) ScreenHDC(),  //  with this DC 
 438                         pbmih
,              // used to get size &c 
 439                         CBM_INIT
,           // initialize bitmap bits too 
 440                         bits
,               // ... using this data 
 441                         pbmi
,               // this is used for palette only 
 442                         DIB_RGB_COLORS      
// direct or indexed palette? 
 447         wxLogLastError(wxT("CreateDIBitmap")); 
 454 size_t wxDIB::ConvertFromBitmap(BITMAPINFO 
*pbi
, HBITMAP hbmp
) 
 456     wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") ); 
 458     // prepare all the info we need 
 460     if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) ) 
 462         wxLogLastError(wxT("GetObject(bitmap)")); 
 467     // we need a BITMAPINFO anyhow and if we're not given a pointer to it we 
 471     const bool wantSizeOnly 
= pbi 
== NULL
; 
 475     // just for convenience 
 476     const int h 
= bm
.bmHeight
; 
 479     BITMAPINFOHEADER
& bi 
= pbi
->bmiHeader
; 
 481     bi
.biSize 
= sizeof(BITMAPINFOHEADER
); 
 482     bi
.biWidth 
= bm
.bmWidth
; 
 485     bi
.biBitCount 
= bm
.bmBitsPixel
; 
 487     // memory we need for BITMAPINFO only 
 488     DWORD dwLen 
= bi
.biSize 
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
); 
 490     // get either just the image size or the image bits 
 493                 ScreenHDC(),                        // the DC to use 
 494                 hbmp
,                               // the source DDB 
 495                 0,                                  // first scan line 
 496                 h
,                                  // number of lines to copy 
 497                 wantSizeOnly 
? NULL                 
// pointer to the buffer or 
 498                              : (char *)pbi 
+ dwLen
, // NULL if we don't have it 
 499                 pbi
,                                // bitmap header 
 500                 DIB_RGB_COLORS                      
// or DIB_PAL_COLORS 
 503         wxLogLastError(wxT("GetDIBits()")); 
 508     // return the total size 
 509     return dwLen 
+ bi
.biSizeImage
; 
 513 HGLOBAL 
wxDIB::ConvertFromBitmap(HBITMAP hbmp
) 
 515     // first calculate the size needed 
 516     const size_t size 
= ConvertFromBitmap(NULL
, hbmp
); 
 519         // conversion to DDB failed? 
 523     HGLOBAL hDIB 
= ::GlobalAlloc(GMEM_MOVEABLE
, size
); 
 526         // this is an error which does risk to happen especially under Win9x 
 527         // and which the user may understand so let him know about it 
 528         wxLogError(_("Failed to allocated %luKb of memory for bitmap data."), 
 529                    (unsigned long)(size 
/ 1024)); 
 534     if ( !ConvertFromBitmap((BITMAPINFO 
*)(void *)GlobalPtr(hDIB
), hbmp
) ) 
 536         // this really shouldn't happen... it worked the first time, why not 
 538         wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") ); 
 546 #endif // __WXWINCE__ 
 548 // ---------------------------------------------------------------------------- 
 550 // ---------------------------------------------------------------------------- 
 554 wxPalette 
*wxDIB::CreatePalette() const 
 556     wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") ); 
 559     if ( !GetDIBSection(m_handle
, &ds
) ) 
 561         wxLogLastError(_T("GetObject(hDIB)")); 
 566     // how many colours are we going to have in the palette? 
 567     DWORD biClrUsed 
= ds
.dsBmih
.biClrUsed
; 
 570         // biClrUsed field might not be set 
 571         biClrUsed 
= GetNumberOfColours(ds
.dsBmih
.biBitCount
); 
 576         // bitmaps of this depth don't have palettes at all 
 578         // NB: another possibility would be to return 
 579         //     GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()? 
 583     // LOGPALETTE struct has only 1 element in palPalEntry array, we're 
 584     // going to have biClrUsed of them so add necessary space 
 585     LOGPALETTE 
*pPalette 
= (LOGPALETTE 
*) 
 586         malloc(sizeof(LOGPALETTE
) + (biClrUsed 
- 1)*sizeof(PALETTEENTRY
)); 
 587     wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") ); 
 589     // initialize the palette header 
 590     pPalette
->palVersion 
= 0x300;  // magic number, not in docs but works 
 591     pPalette
->palNumEntries 
= biClrUsed
; 
 593     // and the colour table (it starts right after the end of the header) 
 594     const RGBQUAD 
*pRGB 
= (RGBQUAD 
*)((char *)&ds
.dsBmih 
+ ds
.dsBmih
.biSize
); 
 595     for ( DWORD i 
= 0; i 
< biClrUsed
; i
++, pRGB
++ ) 
 597         pPalette
->palPalEntry
[i
].peRed 
= pRGB
->rgbRed
; 
 598         pPalette
->palPalEntry
[i
].peGreen 
= pRGB
->rgbGreen
; 
 599         pPalette
->palPalEntry
[i
].peBlue 
= pRGB
->rgbBlue
; 
 600         pPalette
->palPalEntry
[i
].peFlags 
= 0; 
 603     HPALETTE hPalette 
= ::CreatePalette(pPalette
); 
 609         wxLogLastError(_T("CreatePalette")); 
 614     wxPalette 
*palette 
= new wxPalette
; 
 615     palette
->SetHPALETTE((WXHPALETTE
)hPalette
); 
 620 #endif // wxUSE_PALETTE 
 622 // ---------------------------------------------------------------------------- 
 624 // ---------------------------------------------------------------------------- 
 628 bool wxDIB::Create(const wxImage
& image
) 
 630     wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") ); 
 632     const int h 
= image
.GetHeight(); 
 633     const int w 
= image
.GetWidth(); 
 635     // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise 
 636     // a 24bpp RGB is sufficient 
 637     const bool hasAlpha 
= image
.HasAlpha(); 
 638     const int bpp 
= hasAlpha 
? 32 : 24; 
 640     if ( !Create(w
, h
, bpp
) ) 
 643     // DIBs are stored in bottom to top order (see also the comment above in 
 644     // Create()) so we need to copy bits line by line and starting from the end 
 645     const int srcBytesPerLine 
= w 
* 3; 
 646     const int dstBytesPerLine 
= GetLineSize(w
, bpp
); 
 647     const unsigned char *src 
= image
.GetData() + ((h 
- 1) * srcBytesPerLine
); 
 648     const unsigned char *alpha 
= hasAlpha 
? image
.GetAlpha() + (h 
- 1)*w 
: NULL
; 
 649     unsigned char *dstLineStart 
= (unsigned char *)m_data
; 
 650     for ( int y 
= 0; y 
< h
; y
++ ) 
 653         unsigned char *dst 
= dstLineStart
; 
 654         for ( int x 
= 0; x 
< w
; x
++ ) 
 656             // also, the order of RGB is inversed for DIBs 
 667         // pass to the previous line in the image 
 668         src 
-= 2*srcBytesPerLine
; 
 672         // and to the next one in the DIB 
 673         dstLineStart 
+= dstBytesPerLine
; 
 679 wxImage 
wxDIB::ConvertToImage() const 
 681     wxCHECK_MSG( IsOk(), wxNullImage
, 
 682                     wxT("can't convert invalid DIB to wxImage") ); 
 684     // create the wxImage object 
 685     const int w 
= GetWidth(); 
 686     const int h 
= GetHeight(); 
 687     wxImage 
image(w
, h
, false /* don't bother clearing memory */); 
 690         wxFAIL_MSG( wxT("could not allocate data for image") ); 
 694     const int bpp 
= GetDepth(); 
 700     // this is the same loop as in Create() just above but with copy direction 
 702     const int dstBytesPerLine 
= w 
* 3; 
 703     const int srcBytesPerLine 
= GetLineSize(w
, bpp
); 
 704     unsigned char *dst 
= image
.GetData() + ((h 
- 1) * dstBytesPerLine
); 
 705     unsigned char *alpha 
= image
.HasAlpha() ? image
.GetAlpha() + (h 
- 1)*w
 
 707     const unsigned char *srcLineStart 
= (unsigned char *)GetData(); 
 708     for ( int y 
= 0; y 
< h
; y
++ ) 
 711         const unsigned char *src 
= srcLineStart
; 
 712         for ( int x 
= 0; x 
< w
; x
++ ) 
 724         // pass to the previous line in the image 
 725         dst 
-= 2*dstBytesPerLine
; 
 729         // and to the next one in the DIB 
 730         srcLineStart 
+= srcBytesPerLine
; 
 736 #endif // wxUSE_IMAGE 
 738 #endif // wxUSE_WXDIB