]>
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" 
  36     #include "wx/string.h" 
  39     #include "wx/bitmap.h" 
  47 #if !defined(__MWERKS__) && !defined(__SALFORDC__) 
  52 #include "wx/msw/dib.h" 
  55     #include <shellapi.h>       // for SHLoadDIBitmap() 
  58 // ---------------------------------------------------------------------------- 
  60 // ---------------------------------------------------------------------------- 
  62 // calculate the number of palette entries needed for the bitmap with this 
  63 // number of bits per pixel 
  64 static inline WORD 
GetNumberOfColours(WORD bitsPerPixel
) 
  66     // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with 
  67     // 24bpp ones too but we don't support this as I think it's quite uncommon) 
  68     return (WORD
)(bitsPerPixel 
<= 8 ? 1 << bitsPerPixel 
: 0); 
  71 // wrapper around ::GetObject() for DIB sections 
  72 static inline bool GetDIBSection(HBITMAP hbmp
, DIBSECTION 
*ds
) 
  74     // note that at least under Win9x (this doesn't seem to happen under Win2K 
  75     // but this doesn't mean anything, of course), GetObject() may return 
  76     // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way 
  77     // to check for it is by looking at the bits pointer 
  78     return ::GetObject(hbmp
, sizeof(DIBSECTION
), ds
) == sizeof(DIBSECTION
) && 
  82 // ============================================================================ 
  84 // ============================================================================ 
  86 // ---------------------------------------------------------------------------- 
  88 // ---------------------------------------------------------------------------- 
  90 bool wxDIB::Create(int width
, int height
, int depth
) 
  92     // we don't support formats using palettes right now so we only create 
  93     // either 24bpp (RGB) or 32bpp (RGBA) bitmaps 
  94     wxASSERT_MSG( depth
, _T("invalid image depth in wxDIB::Create()") ); 
  98     // allocate memory for bitmap structures 
  99     static const int sizeHeader 
= sizeof(BITMAPINFOHEADER
); 
 101     BITMAPINFO 
*info 
= (BITMAPINFO 
*)malloc(sizeHeader
); 
 102     wxCHECK_MSG( info
, false, _T("malloc(BITMAPINFO) failed") ); 
 104     memset(info
, 0, sizeHeader
); 
 106     info
->bmiHeader
.biSize 
= sizeHeader
; 
 107     info
->bmiHeader
.biWidth 
= width
; 
 109     // we use positive height here which corresponds to a DIB with normal, i.e. 
 110     // bottom to top, order -- normally using negative height (which means 
 111     // reversed for MS and hence natural for all the normal people top to 
 112     // bottom line scan order) could be used to avoid the need for the image 
 113     // reversal in Create(image) but this doesn't work under NT, only Win9x! 
 114     info
->bmiHeader
.biHeight 
= height
; 
 116     info
->bmiHeader
.biPlanes 
= 1; 
 117     info
->bmiHeader
.biBitCount 
= (WORD
)depth
; 
 118     info
->bmiHeader
.biSizeImage 
= GetLineSize(width
, depth
)*height
; 
 120     m_handle 
= ::CreateDIBSection
 
 122                     0,              // hdc (unused with DIB_RGB_COLORS) 
 123                     info
,           // bitmap description 
 124                     DIB_RGB_COLORS
, // use RGB, not palette 
 125                     &m_data
,        // [out] DIB bits 
 126                     NULL
,           // don't use file mapping 
 127                     0               // file mapping offset (not used here) 
 134         wxLogLastError(wxT("CreateDIBSection")); 
 146 bool wxDIB::Create(const wxBitmap
& bmp
) 
 148     wxCHECK_MSG( bmp
.Ok(), false, _T("wxDIB::Create(): invalid bitmap") ); 
 150     if ( !Create(GetHbitmapOf(bmp
)) ) 
 153     m_hasAlpha 
= bmp
.HasAlpha(); 
 158 bool wxDIB::Create(HBITMAP hbmp
) 
 160     // this bitmap could already be a DIB section in which case we don't need 
 161     // to convert it to DIB 
 163     if ( GetDIBSection(hbmp
, &ds
) ) 
 167         // wxBitmap will free it, not we 
 168         m_ownsHandle 
= false; 
 170         // copy all the bitmap parameters too as we have them now anyhow 
 171         m_width 
= ds
.dsBm
.bmWidth
; 
 172         m_height 
= ds
.dsBm
.bmHeight
; 
 173         m_depth 
= ds
.dsBm
.bmBitsPixel
; 
 175         m_data 
= ds
.dsBm
.bmBits
; 
 177     else // no, it's a DDB -- convert it to DIB 
 179         // prepare all the info we need 
 181         if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) ) 
 183             wxLogLastError(wxT("GetObject(bitmap)")); 
 188         int d 
= bm
.bmBitsPixel
; 
 190             d 
= wxDisplayDepth(); 
 192         if ( !Create(bm
.bmWidth
, bm
.bmHeight
, d
) || !CopyFromDDB(hbmp
) ) 
 199 // Windows CE doesn't have GetDIBits() so use an alternative implementation 
 202 // in fact I'm not sure if GetDIBits() is really much better than using 
 203 // BitBlt() like this -- it should be faster but I didn't do any tests, if 
 204 // anybody has time to do them and by chance finds that GetDIBits() is not 
 205 // much faster than BitBlt(), we could always use the Win CE version here 
 208 bool wxDIB::CopyFromDDB(HBITMAP hbmp
) 
 214     SelectInHDC 
selectSrc(hdcSrc
, hbmp
); 
 222     SelectInHDC 
selectDst(hdcDst
, m_handle
); 
 229                     0, 0, m_width
, m_height
, 
 235         wxLogLastError(_T("BitBlt(DDB -> DIB)")); 
 243 #else // !__WXWINCE__ 
 245 bool wxDIB::CopyFromDDB(HBITMAP hbmp
) 
 248     if ( !GetDIBSection(m_handle
, &ds
) ) 
 250         // we're sure that our handle is a DIB section, so this should work 
 251         wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") ); 
 258                 ScreenHDC(),                // the DC to use 
 259                 hbmp
,                       // the source DDB 
 260                 0,                          // first scan line 
 261                 m_height
,                   // number of lines to copy 
 262                 ds
.dsBm
.bmBits
,             // pointer to the buffer 
 263                 (BITMAPINFO 
*)&ds
.dsBmih
,   // bitmap header 
 264                 DIB_RGB_COLORS              
// and not DIB_PAL_COLORS 
 267         wxLogLastError(wxT("GetDIBits()")); 
 275 #endif // __WXWINCE__/!__WXWINCE__ 
 277 // ---------------------------------------------------------------------------- 
 278 // Loading/saving the DIBs 
 279 // ---------------------------------------------------------------------------- 
 281 bool wxDIB::Load(const wxString
& filename
) 
 284     m_handle 
= SHLoadDIBitmap(filename
); 
 285 #else // !__WXWINCE__ 
 286     m_handle 
= (HBITMAP
)::LoadImage
 
 291                             0, 0, // don't specify the size 
 292                             LR_CREATEDIBSECTION 
| LR_LOADFROMFILE
 
 294 #endif // __WXWINCE__ 
 298         wxLogLastError(_T("Loading DIB from file")); 
 306 bool wxDIB::Save(const wxString
& filename
) 
 308     wxCHECK_MSG( m_handle
, false, _T("wxDIB::Save(): invalid object") ); 
 310     wxFile 
file(filename
, wxFile::write
); 
 311     bool ok 
= file
.IsOpened(); 
 315         if ( !GetDIBSection(m_handle
, &ds
) ) 
 317             wxLogLastError(_T("GetObject(hDIB)")); 
 321             BITMAPFILEHEADER bmpHdr
; 
 322             wxZeroMemory(bmpHdr
); 
 324             const size_t sizeHdr 
= ds
.dsBmih
.biSize
; 
 325             const size_t sizeImage 
= ds
.dsBmih
.biSizeImage
; 
 327             bmpHdr
.bfType 
= 0x4d42;    // 'BM' in little endian 
 328             bmpHdr
.bfOffBits 
= sizeof(BITMAPFILEHEADER
) + ds
.dsBmih
.biSize
; 
 329             bmpHdr
.bfSize 
= bmpHdr
.bfOffBits 
+ sizeImage
; 
 331             // first write the file header, then the bitmap header and finally the 
 332             // bitmap data itself 
 333             ok 
= file
.Write(&bmpHdr
, sizeof(bmpHdr
)) == sizeof(bmpHdr
) && 
 334                     file
.Write(&ds
.dsBmih
, sizeHdr
) == sizeHdr 
&& 
 335                         file
.Write(ds
.dsBm
.bmBits
, sizeImage
) == sizeImage
; 
 341         wxLogError(_("Failed to save the bitmap image to file \"%s\"."), 
 348 // ---------------------------------------------------------------------------- 
 350 // ---------------------------------------------------------------------------- 
 352 void wxDIB::DoGetObject() const 
 354     // only do something if we have a valid DIB but we don't [yet] have valid 
 356     if ( m_handle 
&& !m_data 
) 
 358         // although all the info we need is in BITMAP and so we don't really 
 359         // need DIBSECTION we still ask for it as modifying the bit values only 
 360         // works for the real DIBs and not for the bitmaps and it's better to 
 361         // check for this now rather than trying to find out why it doesn't 
 364         if ( !GetDIBSection(m_handle
, &ds
) ) 
 366             wxLogLastError(_T("GetObject(hDIB)")); 
 370         wxDIB 
*self 
= wxConstCast(this, wxDIB
); 
 372         self
->m_width 
= ds
.dsBm
.bmWidth
; 
 373         self
->m_height 
= ds
.dsBm
.bmHeight
; 
 374         self
->m_depth 
= ds
.dsBm
.bmBitsPixel
; 
 375         self
->m_data 
= ds
.dsBm
.bmBits
; 
 379 // ---------------------------------------------------------------------------- 
 380 // DDB <-> DIB conversions 
 381 // ---------------------------------------------------------------------------- 
 385 HBITMAP 
wxDIB::CreateDDB(HDC hdc
) const 
 387     wxCHECK_MSG( m_handle
, 0, _T("wxDIB::CreateDDB(): invalid object") ); 
 390     if ( !GetDIBSection(m_handle
, &ds
) ) 
 392         wxLogLastError(_T("GetObject(hDIB)")); 
 397     // how many colours are we going to have in the palette? 
 398     DWORD biClrUsed 
= ds
.dsBmih
.biClrUsed
; 
 401         // biClrUsed field might not be set 
 402         biClrUsed 
= GetNumberOfColours(ds
.dsBmih
.biBitCount
); 
 407         return ConvertToBitmap((BITMAPINFO 
*)&ds
.dsBmih
, hdc
, ds
.dsBm
.bmBits
); 
 411         // fake a BITMAPINFO w/o bits, just the palette info 
 412         wxCharBuffer 
bmi(sizeof(BITMAPINFO
) + (biClrUsed 
- 1)*sizeof(RGBQUAD
)); 
 413         BITMAPINFO 
*pBmi 
= (BITMAPINFO 
*)bmi
.data(); 
 415         // get the colour table 
 416         SelectInHDC 
sDC(hDC
, m_handle
); 
 417         ::GetDIBColorTable(hDC
, 0, biClrUsed
, pBmi
->bmiColors
); 
 418         memcpy(&pBmi
->bmiHeader
, &ds
.dsBmih
, ds
.dsBmih
.biSize
); 
 420         return ConvertToBitmap(pBmi
, hdc
, ds
.dsBm
.bmBits
); 
 425 HBITMAP 
wxDIB::ConvertToBitmap(const BITMAPINFO 
*pbmi
, HDC hdc
, void *bits
) 
 427     wxCHECK_MSG( pbmi
, 0, _T("invalid DIB in ConvertToBitmap") ); 
 429     // here we get BITMAPINFO struct followed by the actual bitmap bits and 
 430     // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info 
 431     const BITMAPINFOHEADER 
*pbmih 
= &pbmi
->bmiHeader
; 
 433     // get the pointer to the start of the real image data if we have a plain 
 434     // DIB and not a DIB section (in the latter case the pointer must be passed 
 435     // to us by the caller) 
 438         // we must skip over the colour table to get to the image data 
 440         // colour table either has the real colour data in which case its 
 441         // number of entries is given by biClrUsed or is used for masks to be 
 442         // used for extracting colour information from true colour bitmaps in 
 443         // which case it always have exactly 3 DWORDs 
 445         switch ( pbmih
->biCompression 
) 
 452                 // biClrUsed has the number of colors but it may be not initialized at 
 454                 numColors 
= pbmih
->biClrUsed
; 
 457                     numColors 
= GetNumberOfColours(pbmih
->biBitCount
); 
 462                 // no idea how it should be calculated for the other cases 
 466         bits 
= (char *)pbmih 
+ sizeof(*pbmih
) + numColors
*sizeof(RGBQUAD
); 
 469     HBITMAP hbmp 
= ::CreateDIBitmap
 
 471                         hdc 
? hdc           
// create bitmap compatible 
 472                             : (HDC
) ScreenHDC(),  //  with this DC 
 473                         pbmih
,              // used to get size &c 
 474                         CBM_INIT
,           // initialize bitmap bits too 
 475                         bits
,               // ... using this data 
 476                         pbmi
,               // this is used for palette only 
 477                         DIB_RGB_COLORS      
// direct or indexed palette? 
 482         wxLogLastError(wxT("CreateDIBitmap")); 
 489 size_t wxDIB::ConvertFromBitmap(BITMAPINFO 
*pbi
, HBITMAP hbmp
) 
 491     wxASSERT_MSG( hbmp
, wxT("invalid bmp can't be converted to DIB") ); 
 493     // prepare all the info we need 
 495     if ( !::GetObject(hbmp
, sizeof(bm
), &bm
) ) 
 497         wxLogLastError(wxT("GetObject(bitmap)")); 
 502     // we need a BITMAPINFO anyhow and if we're not given a pointer to it we 
 506     const bool wantSizeOnly 
= pbi 
== NULL
; 
 510     // just for convenience 
 511     const int h 
= bm
.bmHeight
; 
 514     BITMAPINFOHEADER
& bi 
= pbi
->bmiHeader
; 
 516     bi
.biSize 
= sizeof(BITMAPINFOHEADER
); 
 517     bi
.biWidth 
= bm
.bmWidth
; 
 520     bi
.biBitCount 
= bm
.bmBitsPixel
; 
 522     // memory we need for BITMAPINFO only 
 523     DWORD dwLen 
= bi
.biSize 
+ GetNumberOfColours(bm
.bmBitsPixel
) * sizeof(RGBQUAD
); 
 525     // get either just the image size or the image bits 
 528                 ScreenHDC(),                        // the DC to use 
 529                 hbmp
,                               // the source DDB 
 530                 0,                                  // first scan line 
 531                 h
,                                  // number of lines to copy 
 532                 wantSizeOnly 
? NULL                 
// pointer to the buffer or 
 533                              : (char *)pbi 
+ dwLen
, // NULL if we don't have it 
 534                 pbi
,                                // bitmap header 
 535                 DIB_RGB_COLORS                      
// or DIB_PAL_COLORS 
 538         wxLogLastError(wxT("GetDIBits()")); 
 543     // return the total size 
 544     return dwLen 
+ bi
.biSizeImage
; 
 548 HGLOBAL 
wxDIB::ConvertFromBitmap(HBITMAP hbmp
) 
 550     // first calculate the size needed 
 551     const size_t size 
= ConvertFromBitmap(NULL
, hbmp
); 
 554         // conversion to DDB failed? 
 558     HGLOBAL hDIB 
= ::GlobalAlloc(GMEM_MOVEABLE
, size
); 
 561         // this is an error which does risk to happen especially under Win9x 
 562         // and which the user may understand so let him know about it 
 563         wxLogError(_("Failed to allocated %luKb of memory for bitmap data."), 
 564                    (unsigned long)(size 
/ 1024)); 
 569     if ( !ConvertFromBitmap((BITMAPINFO 
*)(void *)GlobalPtrLock(hDIB
), hbmp
) ) 
 571         // this really shouldn't happen... it worked the first time, why not 
 573         wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") ); 
 581 #endif // __WXWINCE__ 
 583 // ---------------------------------------------------------------------------- 
 585 // ---------------------------------------------------------------------------- 
 589 wxPalette 
*wxDIB::CreatePalette() const 
 591     // GetDIBColorTable not available in eVC3 
 592 #if defined(_WIN32_WCE) && _WIN32_WCE < 400 
 595     wxCHECK_MSG( m_handle
, NULL
, _T("wxDIB::CreatePalette(): invalid object") ); 
 598     if ( !GetDIBSection(m_handle
, &ds
) ) 
 600         wxLogLastError(_T("GetObject(hDIB)")); 
 605     // how many colours are we going to have in the palette? 
 606     DWORD biClrUsed 
= ds
.dsBmih
.biClrUsed
; 
 609         // biClrUsed field might not be set 
 610         biClrUsed 
= GetNumberOfColours(ds
.dsBmih
.biBitCount
); 
 615         // bitmaps of this depth don't have palettes at all 
 617         // NB: another possibility would be to return 
 618         //     GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()? 
 624     // LOGPALETTE struct has only 1 element in palPalEntry array, we're 
 625     // going to have biClrUsed of them so add necessary space 
 626     LOGPALETTE 
*pPalette 
= (LOGPALETTE 
*) 
 627         malloc(sizeof(LOGPALETTE
) + (biClrUsed 
- 1)*sizeof(PALETTEENTRY
)); 
 628     wxCHECK_MSG( pPalette
, NULL
, _T("out of memory") ); 
 630     // initialize the palette header 
 631     pPalette
->palVersion 
= 0x300;  // magic number, not in docs but works 
 632     pPalette
->palNumEntries 
= (WORD
)biClrUsed
; 
 634     // and the colour table 
 635     wxCharBuffer 
rgb(sizeof(RGBQUAD
) * biClrUsed
); 
 636     RGBQUAD 
*pRGB 
= (RGBQUAD
*)rgb
.data(); 
 637     SelectInHDC 
selectHandle(hDC
, m_handle
); 
 638     ::GetDIBColorTable(hDC
, 0, biClrUsed
, pRGB
); 
 639     for ( DWORD i 
= 0; i 
< biClrUsed
; i
++, pRGB
++ ) 
 641         pPalette
->palPalEntry
[i
].peRed 
= pRGB
->rgbRed
; 
 642         pPalette
->palPalEntry
[i
].peGreen 
= pRGB
->rgbGreen
; 
 643         pPalette
->palPalEntry
[i
].peBlue 
= pRGB
->rgbBlue
; 
 644         pPalette
->palPalEntry
[i
].peFlags 
= 0; 
 647     HPALETTE hPalette 
= ::CreatePalette(pPalette
); 
 653         wxLogLastError(_T("CreatePalette")); 
 658     wxPalette 
*palette 
= new wxPalette
; 
 659     palette
->SetHPALETTE((WXHPALETTE
)hPalette
); 
 665 #endif // wxUSE_PALETTE 
 667 // ---------------------------------------------------------------------------- 
 669 // ---------------------------------------------------------------------------- 
 673 bool wxDIB::Create(const wxImage
& image
) 
 675     wxCHECK_MSG( image
.Ok(), false, _T("invalid wxImage in wxDIB ctor") ); 
 677     const int h 
= image
.GetHeight(); 
 678     const int w 
= image
.GetWidth(); 
 680     // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise 
 681     // a 24bpp RGB is sufficient 
 682     m_hasAlpha 
= image
.HasAlpha(); 
 683     const int bpp 
= m_hasAlpha 
? 32 : 24; 
 685     if ( !Create(w
, h
, bpp
) ) 
 688     // DIBs are stored in bottom to top order (see also the comment above in 
 689     // Create()) so we need to copy bits line by line and starting from the end 
 690     const int srcBytesPerLine 
= w 
* 3; 
 691     const int dstBytesPerLine 
= GetLineSize(w
, bpp
); 
 692     const unsigned char *src 
= image
.GetData() + ((h 
- 1) * srcBytesPerLine
); 
 693     const unsigned char *alpha 
= m_hasAlpha 
? image
.GetAlpha() + (h 
- 1)*w
 
 695     unsigned char *dstLineStart 
= (unsigned char *)m_data
; 
 696     for ( int y 
= 0; y 
< h
; y
++ ) 
 699         unsigned char *dst 
= dstLineStart
; 
 702             for ( int x 
= 0; x 
< w
; x
++ ) 
 704                 // RGB order is reversed, and we need to premultiply 
 705                 // all channels by alpha value for use with ::AlphaBlend. 
 706                 const unsigned char a 
= *alpha
++; 
 707                 *dst
++ = (unsigned char)((src
[2] * a 
+ 127) / 255); 
 708                 *dst
++ = (unsigned char)((src
[1] * a 
+ 127) / 255); 
 709                 *dst
++ = (unsigned char)((src
[0] * a 
+ 127) / 255); 
 714         else // no alpha channel 
 716             for ( int x 
= 0; x 
< w
; x
++ ) 
 718                 // RGB order is reversed. 
 726         // pass to the previous line in the image 
 727         src 
-= 2*srcBytesPerLine
; 
 731         // and to the next one in the DIB 
 732         dstLineStart 
+= dstBytesPerLine
; 
 738 wxImage 
wxDIB::ConvertToImage() const 
 740     wxCHECK_MSG( IsOk(), wxNullImage
, 
 741                     wxT("can't convert invalid DIB to wxImage") ); 
 743     // create the wxImage object 
 744     const int w 
= GetWidth(); 
 745     const int h 
= GetHeight(); 
 746     wxImage 
image(w
, h
, false /* don't bother clearing memory */); 
 749         wxFAIL_MSG( wxT("could not allocate data for image") ); 
 758     // this is the same loop as in Create() just above but with copy direction 
 760     const int bpp 
= GetDepth(); 
 761     const int dstBytesPerLine 
= w 
* 3; 
 762     const int srcBytesPerLine 
= GetLineSize(w
, bpp
); 
 763     unsigned char *dst 
= image
.GetData() + ((h 
- 1) * dstBytesPerLine
); 
 764     unsigned char *alpha 
= image
.HasAlpha() ? image
.GetAlpha() + (h 
- 1)*w
 
 766     const bool is32bit 
= bpp 
== 32; 
 767     const unsigned char *srcLineStart 
= (unsigned char *)GetData(); 
 768     for ( int y 
= 0; y 
< h
; y
++ ) 
 771         const unsigned char *src 
= srcLineStart
; 
 772         for ( int x 
= 0; x 
< w
; x
++ ) 
 788         // pass to the previous line in the image 
 789         dst 
-= 2*dstBytesPerLine
; 
 793         // and to the next one in the DIB 
 794         srcLineStart 
+= srcBytesPerLine
; 
 800 #endif // wxUSE_IMAGE 
 802 #endif // wxUSE_WXDIB