1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/dib.cpp 3// Purpose: implements wxDIB class 4// Author: Vadim Zeitlin 5// Modified by: 6// Created: 03.03.03 (replaces the old file with the same name) 7// RCS-ID: $Id: dib.cpp 48581 2007-09-05 23:01:02Z VZ $ 8// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org> 9// License: wxWindows licence 10/////////////////////////////////////////////////////////////////////////////// 11 12/* 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. 16 */ 17 18// ============================================================================ 19// declarations 20// ============================================================================ 21 22// ---------------------------------------------------------------------------- 23// headers 24// ---------------------------------------------------------------------------- 25 26// For compilers that support precompilation, includes "wx.h". 27#include "wx/wxprec.h" 28 29#ifdef __BORLANDC__ 30 #pragma hdrstop 31#endif 32 33#if wxUSE_WXDIB 34 35#ifndef WX_PRECOMP 36 #include "wx/string.h" 37 #include "wx/log.h" 38 #include "wx/intl.h" 39 #include "wx/bitmap.h" 40 #include "wx/image.h" 41#endif //WX_PRECOMP 42 43#include "wx/file.h" 44 45#include <stdio.h> 46#include <stdlib.h> 47 48#if !defined(__MWERKS__) && !defined(__SALFORDC__) 49 #include <memory.h> 50#endif 51 52#include "wx/msw/dib.h" 53 54#ifdef __WXWINCE__ 55 #include <shellapi.h> // for SHLoadDIBitmap() 56#endif 57 58// ---------------------------------------------------------------------------- 59// private functions 60// ---------------------------------------------------------------------------- 61 62// calculate the number of palette entries needed for the bitmap with this 63// number of bits per pixel 64static inline WORD GetNumberOfColours(WORD bitsPerPixel) 65{ 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); 69} 70 71// wrapper around ::GetObject() for DIB sections 72static inline bool GetDIBSection(HBITMAP hbmp, DIBSECTION *ds) 73{ 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) && 79 ds->dsBm.bmBits; 80} 81 82// ============================================================================ 83// implementation 84// ============================================================================ 85 86// ---------------------------------------------------------------------------- 87// wxDIB creation 88// ---------------------------------------------------------------------------- 89 90bool wxDIB::Create(int width, int height, int depth) 91{ 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()") ); 95 if ( depth < 24 ) 96 depth = 24; 97 98 // allocate memory for bitmap structures 99 static const int sizeHeader = sizeof(BITMAPINFOHEADER); 100 101 BITMAPINFO *info = (BITMAPINFO *)malloc(sizeHeader); 102 wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") ); 103 104 memset(info, 0, sizeHeader); 105 106 info->bmiHeader.biSize = sizeHeader; 107 info->bmiHeader.biWidth = width; 108 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; 115 116 info->bmiHeader.biPlanes = 1; 117 info->bmiHeader.biBitCount = (WORD)depth; 118 info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height; 119 120 m_handle = ::CreateDIBSection 121 ( 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) 128 ); 129 130 free(info); 131 132 if ( !m_handle ) 133 { 134 wxLogLastError(wxT("CreateDIBSection")); 135 136 return false; 137 } 138 139 m_width = width; 140 m_height = height; 141 m_depth = depth; 142 143 return true; 144} 145 146bool wxDIB::Create(const wxBitmap& bmp) 147{ 148 wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") ); 149 150 if ( !Create(GetHbitmapOf(bmp)) ) 151 return false; 152 153 m_hasAlpha = bmp.HasAlpha(); 154 155 return true; 156} 157 158bool wxDIB::Create(HBITMAP hbmp) 159{ 160 // this bitmap could already be a DIB section in which case we don't need 161 // to convert it to DIB 162 DIBSECTION ds; 163 if ( GetDIBSection(hbmp, &ds) ) 164 { 165 m_handle = hbmp; 166 167 // wxBitmap will free it, not we 168 m_ownsHandle = false; 169 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; 174 175 m_data = ds.dsBm.bmBits; 176 } 177 else // no, it's a DDB -- convert it to DIB 178 { 179 // prepare all the info we need 180 BITMAP bm; 181 if ( !::GetObject(hbmp, sizeof(bm), &bm) ) 182 { 183 wxLogLastError(wxT("GetObject(bitmap)")); 184 185 return false; 186 } 187 188 int d = bm.bmBitsPixel; 189 if ( d <= 0 ) 190 d = wxDisplayDepth(); 191 192 if ( !Create(bm.bmWidth, bm.bmHeight, d) || !CopyFromDDB(hbmp) ) 193 return false; 194 } 195 196 return true; 197} 198 199// Windows CE doesn't have GetDIBits() so use an alternative implementation 200// for it 201// 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 206#ifdef __WXWINCE__ 207 208bool wxDIB::CopyFromDDB(HBITMAP hbmp) 209{ 210 MemoryHDC hdcSrc; 211 if ( !hdcSrc ) 212 return false; 213 214 SelectInHDC selectSrc(hdcSrc, hbmp); 215 if ( !selectSrc ) 216 return false; 217 218 MemoryHDC hdcDst; 219 if ( !hdcDst ) 220 return false; 221 222 SelectInHDC selectDst(hdcDst, m_handle); 223 if ( !selectDst ) 224 return false; 225 226 227 if ( !::BitBlt( 228 hdcDst, 229 0, 0, m_width, m_height, 230 hdcSrc, 231 0, 0, 232 SRCCOPY 233 ) ) 234 { 235 wxLogLastError(_T("BitBlt(DDB -> DIB)")); 236 237 return false; 238 } 239 240 return true; 241} 242 243#else // !__WXWINCE__ 244 245bool wxDIB::CopyFromDDB(HBITMAP hbmp) 246{ 247 DIBSECTION ds; 248 if ( !GetDIBSection(m_handle, &ds) ) 249 { 250 // we're sure that our handle is a DIB section, so this should work 251 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") ); 252 253 return false; 254 } 255 256 if ( !::GetDIBits 257 ( 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 265 ) ) 266 { 267 wxLogLastError(wxT("GetDIBits()")); 268 269 return false; 270 } 271 272 return true; 273} 274 275#endif // __WXWINCE__/!__WXWINCE__ 276 277// ---------------------------------------------------------------------------- 278// Loading/saving the DIBs 279// ---------------------------------------------------------------------------- 280 281bool wxDIB::Load(const wxString& filename) 282{ 283#ifdef __WXWINCE__ 284 m_handle = SHLoadDIBitmap(filename); 285#else // !__WXWINCE__ 286 m_handle = (HBITMAP)::LoadImage 287 ( 288 wxGetInstance(), 289 filename, 290 IMAGE_BITMAP, 291 0, 0, // don't specify the size 292 LR_CREATEDIBSECTION | LR_LOADFROMFILE 293 ); 294#endif // __WXWINCE__ 295 296 if ( !m_handle ) 297 { 298 wxLogLastError(_T("Loading DIB from file")); 299 300 return false; 301 } 302 303 return true; 304} 305 306bool wxDIB::Save(const wxString& filename) 307{ 308 wxCHECK_MSG( m_handle, false, _T("wxDIB::Save(): invalid object") ); 309 310 wxFile file(filename, wxFile::write); 311 bool ok = file.IsOpened(); 312 if ( ok ) 313 { 314 DIBSECTION ds; 315 if ( !GetDIBSection(m_handle, &ds) ) 316 { 317 wxLogLastError(_T("GetObject(hDIB)")); 318 } 319 else 320 { 321 BITMAPFILEHEADER bmpHdr; 322 wxZeroMemory(bmpHdr); 323 324 const size_t sizeHdr = ds.dsBmih.biSize; 325 const size_t sizeImage = ds.dsBmih.biSizeImage; 326 327 bmpHdr.bfType = 0x4d42; // 'BM' in little endian 328 bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize; 329 bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage; 330 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; 336 } 337 } 338 339 if ( !ok ) 340 { 341 wxLogError(_("Failed to save the bitmap image to file \"%s\"."), 342 filename.c_str()); 343 } 344 345 return ok; 346} 347 348// ---------------------------------------------------------------------------- 349// wxDIB accessors 350// ---------------------------------------------------------------------------- 351 352void wxDIB::DoGetObject() const 353{ 354 // only do something if we have a valid DIB but we don't [yet] have valid 355 // data 356 if ( m_handle && !m_data ) 357 { 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 362 // work later 363 DIBSECTION ds; 364 if ( !GetDIBSection(m_handle, &ds) ) 365 { 366 wxLogLastError(_T("GetObject(hDIB)")); 367 return; 368 } 369 370 wxDIB *self = wxConstCast(this, wxDIB); 371 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; 376 } 377} 378 379// ---------------------------------------------------------------------------- 380// DDB <-> DIB conversions 381// ---------------------------------------------------------------------------- 382 383#ifndef __WXWINCE__ 384 385HBITMAP wxDIB::CreateDDB(HDC hdc) const 386{ 387 wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") ); 388 389 DIBSECTION ds; 390 if ( !GetDIBSection(m_handle, &ds) ) 391 { 392 wxLogLastError(_T("GetObject(hDIB)")); 393 394 return 0; 395 } 396 397 // how many colours are we going to have in the palette? 398 DWORD biClrUsed = ds.dsBmih.biClrUsed; 399 if ( !biClrUsed ) 400 { 401 // biClrUsed field might not be set 402 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount); 403 } 404 405 if ( !biClrUsed ) 406 { 407 return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits); 408 } 409 else 410 { 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(); 414 MemoryHDC hDC; 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); 419 420 return ConvertToBitmap(pBmi, hdc, ds.dsBm.bmBits); 421 } 422} 423 424/* static */ 425HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits) 426{ 427 wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") ); 428 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; 432 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) 436 if ( !bits ) 437 { 438 // we must skip over the colour table to get to the image data 439 // 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 444 int numColors; 445 switch ( pbmih->biCompression ) 446 { 447 case BI_BITFIELDS: 448 numColors = 3; 449 break; 450 451 case BI_RGB: 452 // biClrUsed has the number of colors but it may be not initialized at 453 // all 454 numColors = pbmih->biClrUsed; 455 if ( !numColors ) 456 { 457 numColors = GetNumberOfColours(pbmih->biBitCount); 458 } 459 break; 460 461 default: 462 // no idea how it should be calculated for the other cases 463 numColors = 0; 464 } 465 466 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD); 467 } 468 469 HBITMAP hbmp = ::CreateDIBitmap 470 ( 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? 478 ); 479 480 if ( !hbmp ) 481 { 482 wxLogLastError(wxT("CreateDIBitmap")); 483 } 484 485 return hbmp; 486} 487 488/* static */ 489size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp) 490{ 491 wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") ); 492 493 // prepare all the info we need 494 BITMAP bm; 495 if ( !::GetObject(hbmp, sizeof(bm), &bm) ) 496 { 497 wxLogLastError(wxT("GetObject(bitmap)")); 498 499 return 0; 500 } 501 502 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we 503 // use this one 504 BITMAPINFO bi2; 505 506 const bool wantSizeOnly = pbi == NULL; 507 if ( wantSizeOnly ) 508 pbi = &bi2; 509 510 // just for convenience 511 const int h = bm.bmHeight; 512 513 // init the header 514 BITMAPINFOHEADER& bi = pbi->bmiHeader; 515 wxZeroMemory(bi); 516 bi.biSize = sizeof(BITMAPINFOHEADER); 517 bi.biWidth = bm.bmWidth; 518 bi.biHeight = h; 519 bi.biPlanes = 1; 520 bi.biBitCount = bm.bmBitsPixel; 521 522 // memory we need for BITMAPINFO only 523 DWORD dwLen = bi.biSize + GetNumberOfColours(bm.bmBitsPixel) * sizeof(RGBQUAD); 524 525 // get either just the image size or the image bits 526 if ( !::GetDIBits 527 ( 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 536 ) ) 537 { 538 wxLogLastError(wxT("GetDIBits()")); 539 540 return 0; 541 } 542 543 // return the total size 544 return dwLen + bi.biSizeImage; 545} 546 547/* static */ 548HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp) 549{ 550 // first calculate the size needed 551 const size_t size = ConvertFromBitmap(NULL, hbmp); 552 if ( !size ) 553 { 554 // conversion to DDB failed? 555 return NULL; 556 } 557 558 HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size); 559 if ( !hDIB ) 560 { 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)); 565 566 return NULL; 567 } 568 569 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtrLock(hDIB), hbmp) ) 570 { 571 // this really shouldn't happen... it worked the first time, why not 572 // now? 573 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") ); 574 575 return NULL; 576 } 577 578 return hDIB; 579} 580 581#endif // __WXWINCE__ 582 583// ---------------------------------------------------------------------------- 584// palette support 585// ---------------------------------------------------------------------------- 586 587#if wxUSE_PALETTE 588 589wxPalette *wxDIB::CreatePalette() const 590{ 591 // GetDIBColorTable not available in eVC3 592#if defined(_WIN32_WCE) && _WIN32_WCE < 400 593 return NULL; 594#else 595 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") ); 596 597 DIBSECTION ds; 598 if ( !GetDIBSection(m_handle, &ds) ) 599 { 600 wxLogLastError(_T("GetObject(hDIB)")); 601 602 return 0; 603 } 604 605 // how many colours are we going to have in the palette? 606 DWORD biClrUsed = ds.dsBmih.biClrUsed; 607 if ( !biClrUsed ) 608 { 609 // biClrUsed field might not be set 610 biClrUsed = GetNumberOfColours(ds.dsBmih.biBitCount); 611 } 612 613 if ( !biClrUsed ) 614 { 615 // bitmaps of this depth don't have palettes at all 616 // 617 // NB: another possibility would be to return 618 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()? 619 return NULL; 620 } 621 622 MemoryHDC hDC; 623 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") ); 629 630 // initialize the palette header 631 pPalette->palVersion = 0x300; // magic number, not in docs but works 632 pPalette->palNumEntries = (WORD)biClrUsed; 633 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++ ) 640 { 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; 645 } 646 647 HPALETTE hPalette = ::CreatePalette(pPalette); 648 649 free(pPalette); 650 651 if ( !hPalette ) 652 { 653 wxLogLastError(_T("CreatePalette")); 654 655 return NULL; 656 } 657 658 wxPalette *palette = new wxPalette; 659 palette->SetHPALETTE((WXHPALETTE)hPalette); 660 661 return palette; 662#endif 663} 664 665#endif // wxUSE_PALETTE 666 667// ---------------------------------------------------------------------------- 668// wxImage support 669// ---------------------------------------------------------------------------- 670 671#if wxUSE_IMAGE 672 673bool wxDIB::Create(const wxImage& image) 674{ 675 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") ); 676 677 const int h = image.GetHeight(); 678 const int w = image.GetWidth(); 679 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; 684 685 if ( !Create(w, h, bpp) ) 686 return false; 687 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 694 : NULL; 695 unsigned char *dstLineStart = (unsigned char *)m_data; 696 for ( int y = 0; y < h; y++ ) 697 { 698 // copy one DIB line 699 unsigned char *dst = dstLineStart; 700 if ( alpha ) 701 { 702 for ( int x = 0; x < w; x++ ) 703 { 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); 710 *dst++ = a; 711 src += 3; 712 } 713 } 714 else // no alpha channel 715 { 716 for ( int x = 0; x < w; x++ ) 717 { 718 // RGB order is reversed. 719 *dst++ = src[2]; 720 *dst++ = src[1]; 721 *dst++ = src[0]; 722 src += 3; 723 } 724 } 725 726 // pass to the previous line in the image 727 src -= 2*srcBytesPerLine; 728 if ( alpha ) 729 alpha -= 2*w; 730 731 // and to the next one in the DIB 732 dstLineStart += dstBytesPerLine; 733 } 734 735 return true; 736} 737 738wxImage wxDIB::ConvertToImage() const 739{ 740 wxCHECK_MSG( IsOk(), wxNullImage, 741 wxT("can't convert invalid DIB to wxImage") ); 742 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 */); 747 if ( !image.Ok() ) 748 { 749 wxFAIL_MSG( wxT("could not allocate data for image") ); 750 return wxNullImage; 751 } 752 753 if ( m_hasAlpha ) 754 { 755 image.SetAlpha(); 756 } 757 758 // this is the same loop as in Create() just above but with copy direction 759 // reversed 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 765 : NULL; 766 const bool is32bit = bpp == 32; 767 const unsigned char *srcLineStart = (unsigned char *)GetData(); 768 for ( int y = 0; y < h; y++ ) 769 { 770 // copy one DIB line 771 const unsigned char *src = srcLineStart; 772 for ( int x = 0; x < w; x++ ) 773 { 774 dst[2] = *src++; 775 dst[1] = *src++; 776 dst[0] = *src++; 777 778 if ( is32bit ) 779 { 780 if ( alpha ) 781 { 782 // wxImage uses non premultiplied alpha so undo 783 // premultiplication done in Create() above 784 const unsigned char a = *src; 785 *alpha++ = a; 786 if ( a > 0 ) 787 { 788 dst[0] = (dst[0] * 255) / a; 789 dst[1] = (dst[1] * 255) / a; 790 dst[2] = (dst[2] * 255) / a; 791 } 792 } 793 794 src++; 795 } 796 797 dst += 3; 798 } 799 800 // pass to the previous line in the image 801 dst -= 2*dstBytesPerLine; 802 if ( alpha ) 803 alpha -= 2*w; 804 805 // and to the next one in the DIB 806 srcLineStart += srcBytesPerLine; 807 } 808 809 return image; 810} 811 812#endif // wxUSE_IMAGE 813 814#endif // wxUSE_WXDIB 815