1 // PROJECT: ReactOS ATL CImage 2 // LICENSE: Public Domain 3 // PURPOSE: Provides compatibility to Microsoft ATL 4 // PROGRAMMERS: Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 5 6 #ifndef __ATLIMAGE_H__ 7 #define __ATLIMAGE_H__ 8 9 // !!!! 10 // TODO: The backend (gdi+) that this class relies on is not yet complete! 11 // Before that is finished, this class will not be a perfect replacement. 12 // See rostest/apitests/atl/CImage_WIP.txt for test results. 13 // !!!! 14 15 // TODO: CImage::Load, CImage::Save 16 // TODO: make CImage thread-safe 17 18 #pragma once 19 20 #include <atlcore.h> // for ATL Core 21 #include <atlstr.h> // for CAtlStringMgr 22 #include <atlsimpstr.h> // for CSimpleString 23 #include <atlsimpcoll.h> // for CSimpleArray 24 25 #include <wingdi.h> 26 #include <cguid.h> // for GUID_NULL 27 #include <gdiplus.h> // GDI+ 28 29 namespace ATL 30 { 31 32 class CImage 33 { 34 public: 35 // flags for CImage::Create/CreateEx 36 enum 37 { 38 createAlphaChannel = 1 // enable alpha 39 }; 40 41 // orientation of DIB 42 enum DIBOrientation 43 { 44 DIBOR_DEFAULT, // default 45 DIBOR_BOTTOMUP, // bottom-up DIB 46 DIBOR_TOPDOWN // top-down DIB 47 }; 48 49 CImage() throw() 50 { 51 m_hbm = NULL; 52 m_hbmOld = NULL; 53 m_hDC = NULL; 54 55 m_eOrientation = DIBOR_DEFAULT; 56 m_bHasAlphaCh = false; 57 m_bIsDIBSec = false; 58 m_rgbTransColor = CLR_INVALID; 59 ZeroMemory(&m_ds, sizeof(m_ds)); 60 61 if (GetCommon().AddRef() == 1) 62 { 63 GetCommon().LoadLib(); 64 } 65 } 66 67 ~CImage() 68 { 69 Destroy(); 70 ReleaseGDIPlus(); 71 } 72 73 operator HBITMAP() 74 { 75 return m_hbm; 76 } 77 78 public: 79 void Attach(HBITMAP hBitmap, DIBOrientation eOrientation = DIBOR_DEFAULT) 80 { 81 AttachInternal(hBitmap, eOrientation, -1); 82 } 83 84 HBITMAP Detach() throw() 85 { 86 m_eOrientation = DIBOR_DEFAULT; 87 m_bHasAlphaCh = false; 88 m_rgbTransColor = CLR_INVALID; 89 ZeroMemory(&m_ds, sizeof(m_ds)); 90 91 HBITMAP hBitmap = m_hbm; 92 m_hbm = NULL; 93 return hBitmap; 94 } 95 96 HDC GetDC() const throw() 97 { 98 if (m_hDC) 99 return m_hDC; 100 101 m_hDC = ::CreateCompatibleDC(NULL); 102 m_hbmOld = ::SelectObject(m_hDC, m_hbm); 103 return m_hDC; 104 } 105 106 void ReleaseDC() const throw() 107 { 108 ATLASSERT(m_hDC); 109 110 if (m_hDC == NULL) 111 return; 112 113 if (m_hbmOld) 114 { 115 ::SelectObject(m_hDC, m_hbmOld); 116 m_hbmOld = NULL; 117 } 118 ::DeleteDC(m_hDC); 119 m_hDC = NULL; 120 } 121 122 public: 123 BOOL AlphaBlend(HDC hDestDC, 124 int xDest, int yDest, int nDestWidth, int nDestHeight, 125 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 126 BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const 127 { 128 ATLASSERT(IsTransparencySupported()); 129 130 BLENDFUNCTION bf; 131 bf.BlendOp = bBlendOp; 132 bf.BlendFlags = 0; 133 bf.SourceConstantAlpha = bSrcAlpha; 134 bf.AlphaFormat = AC_SRC_ALPHA; 135 136 GetDC(); 137 BOOL ret = ::AlphaBlend(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 138 m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf); 139 ReleaseDC(); 140 return ret; 141 } 142 BOOL AlphaBlend(HDC hDestDC, int xDest, int yDest, 143 BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const 144 { 145 int width = GetWidth(); 146 int height = GetHeight(); 147 return AlphaBlend(hDestDC, xDest, yDest, width, height, 0, 0, 148 width, height, bSrcAlpha, bBlendOp); 149 } 150 BOOL AlphaBlend(HDC hDestDC, const POINT& pointDest, 151 BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const 152 { 153 return AlphaBlend(hDestDC, pointDest.x, pointDest.y, bSrcAlpha, bBlendOp); 154 } 155 BOOL AlphaBlend(HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, 156 BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const 157 { 158 return AlphaBlend(hDestDC, rectDest.left, rectDest.top, 159 rectDest.right - rectDest.left, 160 rectDest.bottom - rectDest.top, 161 rectSrc.left, rectSrc.top, 162 rectSrc.right - rectSrc.left, 163 rectSrc.bottom - rectSrc.top, 164 bSrcAlpha, bBlendOp); 165 } 166 167 BOOL BitBlt(HDC hDestDC, int xDest, int yDest, 168 int nDestWidth, int nDestHeight, 169 int xSrc, int ySrc, DWORD dwROP = SRCCOPY) const throw() 170 { 171 GetDC(); 172 BOOL ret = ::BitBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 173 m_hDC, xSrc, ySrc, dwROP); 174 ReleaseDC(); 175 return ret; 176 } 177 BOOL BitBlt(HDC hDestDC, int xDest, int yDest, 178 DWORD dwROP = SRCCOPY) const throw() 179 { 180 return BitBlt(hDestDC, xDest, yDest, 181 GetWidth(), GetHeight(), 0, 0, dwROP); 182 } 183 BOOL BitBlt(HDC hDestDC, const POINT& pointDest, 184 DWORD dwROP = SRCCOPY) const throw() 185 { 186 return BitBlt(hDestDC, pointDest.x, pointDest.y, dwROP); 187 } 188 BOOL BitBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, 189 DWORD dwROP = SRCCOPY) const throw() 190 { 191 return BitBlt(hDestDC, rectDest.left, rectDest.top, 192 rectDest.right - rectDest.left, 193 rectDest.bottom - rectDest.top, 194 pointSrc.x, pointSrc.y, dwROP); 195 } 196 197 BOOL Create(int nWidth, int nHeight, int nBPP, DWORD dwFlags = 0) throw() 198 { 199 return CreateEx(nWidth, nHeight, nBPP, BI_RGB, NULL, dwFlags); 200 } 201 202 BOOL CreateEx(int nWidth, int nHeight, int nBPP, DWORD eCompression, 203 const DWORD* pdwBitmasks = NULL, DWORD dwFlags = 0) throw() 204 { 205 return CreateInternal(nWidth, nHeight, nBPP, eCompression, pdwBitmasks, dwFlags); 206 } 207 208 void Destroy() throw() 209 { 210 if (m_hbm) 211 { 212 ::DeleteObject(Detach()); 213 } 214 } 215 216 BOOL Draw(HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, 217 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight) const throw() 218 { 219 ATLASSERT(IsTransparencySupported()); 220 if (m_bHasAlphaCh) 221 { 222 return AlphaBlend(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 223 xSrc, ySrc, nSrcWidth, nSrcHeight); 224 } 225 else if (m_rgbTransColor != CLR_INVALID) 226 { 227 COLORREF rgb; 228 if ((m_rgbTransColor & 0xFF000000) == 0x01000000) 229 rgb = RGBFromPaletteIndex(m_rgbTransColor & 0xFF); 230 else 231 rgb = m_rgbTransColor; 232 return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 233 xSrc, ySrc, nSrcWidth, nSrcHeight, rgb); 234 } 235 else 236 { 237 return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 238 xSrc, ySrc, nSrcWidth, nSrcHeight); 239 } 240 } 241 BOOL Draw(HDC hDestDC, const RECT& rectDest, const RECT& rectSrc) const throw() 242 { 243 return Draw(hDestDC, rectDest.left, rectDest.top, 244 rectDest.right - rectDest.left, 245 rectDest.bottom - rectDest.top, 246 rectSrc.left, rectSrc.top, 247 rectSrc.right - rectSrc.left, 248 rectSrc.bottom - rectSrc.top); 249 } 250 BOOL Draw(HDC hDestDC, int xDest, int yDest) const throw() 251 { 252 return Draw(hDestDC, xDest, yDest, GetWidth(), GetHeight()); 253 } 254 BOOL Draw(HDC hDestDC, const POINT& pointDest) const throw() 255 { 256 return Draw(hDestDC, pointDest.x, pointDest.y); 257 } 258 BOOL Draw(HDC hDestDC, int xDest, int yDest, 259 int nDestWidth, int nDestHeight) const throw() 260 { 261 return Draw(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 262 0, 0, GetWidth(), GetHeight()); 263 } 264 BOOL Draw(HDC hDestDC, const RECT& rectDest) const throw() 265 { 266 return Draw(hDestDC, rectDest.left, rectDest.top, 267 rectDest.right - rectDest.left, 268 rectDest.bottom - rectDest.top); 269 } 270 271 void *GetBits() throw() 272 { 273 ATLASSERT(IsDIBSection()); 274 BYTE *pb = (BYTE *)m_bm.bmBits; 275 if (m_eOrientation == DIBOR_BOTTOMUP) 276 { 277 pb += m_bm.bmWidthBytes * (m_bm.bmHeight - 1); 278 } 279 return pb; 280 } 281 282 int GetBPP() const throw() 283 { 284 ATLASSERT(m_hbm); 285 return m_bm.bmBitsPixel; 286 } 287 288 void GetColorTable(UINT iFirstColor, UINT nColors, 289 RGBQUAD* prgbColors) const throw() 290 { 291 ATLASSERT(IsDIBSection()); 292 GetDC(); 293 ::GetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors); 294 ReleaseDC(); 295 } 296 297 int GetHeight() const throw() 298 { 299 ATLASSERT(m_hbm); 300 return m_bm.bmHeight; 301 } 302 303 int GetMaxColorTableEntries() const throw() 304 { 305 ATLASSERT(IsDIBSection()); 306 if (m_ds.dsBmih.biClrUsed && m_ds.dsBmih.biBitCount < 16) 307 return m_ds.dsBmih.biClrUsed; 308 switch (m_bm.bmBitsPixel) 309 { 310 case 1: return 2; 311 case 4: return 16; 312 case 8: return 256; 313 case 16: case 32: 314 if (m_ds.dsBmih.biCompression == BI_BITFIELDS) 315 return 3; 316 return 0; 317 case 24: 318 default: 319 return 0; 320 } 321 } 322 323 int GetPitch() const throw() 324 { 325 ATLASSERT(IsDIBSection()); 326 if (m_eOrientation == DIBOR_BOTTOMUP) 327 return -m_bm.bmWidthBytes; 328 else 329 return m_bm.bmWidthBytes; 330 } 331 332 COLORREF GetPixel(int x, int y) const throw() 333 { 334 GetDC(); 335 COLORREF ret = ::GetPixel(m_hDC, x, y); 336 ReleaseDC(); 337 return ret; 338 } 339 340 void* GetPixelAddress(int x, int y) throw() 341 { 342 ATLASSERT(IsDIBSection()); 343 BYTE *pb = (BYTE *)GetBits(); 344 pb += GetPitch() * y; 345 pb += (GetBPP() * x) / 8; 346 return pb; 347 } 348 349 COLORREF GetTransparentColor() const throw() 350 { 351 return m_rgbTransColor; 352 } 353 354 int GetWidth() const throw() 355 { 356 ATLASSERT(m_hbm); 357 return m_bm.bmWidth; 358 } 359 360 bool IsDIBSection() const throw() 361 { 362 ATLASSERT(m_hbm); 363 return m_bIsDIBSec; 364 } 365 366 bool IsIndexed() const throw() 367 { 368 ATLASSERT(IsDIBSection()); 369 return GetBPP() <= 8; 370 } 371 372 bool IsNull() const throw() 373 { 374 return m_hbm == NULL; 375 } 376 377 HRESULT Load(LPCTSTR pszFileName) throw() 378 { 379 // convert the file name string into Unicode 380 CStringW pszNameW(pszFileName); 381 382 // create a GpBitmap object from file 383 using namespace Gdiplus; 384 GpBitmap *pBitmap = NULL; 385 GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap); 386 ATLASSERT(pBitmap); 387 388 // TODO & FIXME: get parameters (m_rgbTransColor etc.) 389 390 // get bitmap handle 391 HBITMAP hbm = NULL; 392 Color color(0xFF, 0xFF, 0xFF); 393 Gdiplus::Status status; 394 status = GetCommon().CreateHBITMAPFromBitmap( 395 pBitmap, &hbm, color.GetValue()); 396 397 // delete GpBitmap 398 GetCommon().DisposeImage(pBitmap); 399 400 // attach it 401 if (status == Ok) 402 Attach(hbm); 403 return (status == Ok ? S_OK : E_FAIL); 404 } 405 HRESULT Load(IStream* pStream) throw() 406 { 407 // create GpBitmap from stream 408 using namespace Gdiplus; 409 GpBitmap *pBitmap = NULL; 410 GetCommon().CreateBitmapFromStream(pStream, &pBitmap); 411 ATLASSERT(pBitmap); 412 413 // TODO & FIXME: get parameters (m_rgbTransColor etc.) 414 415 // get bitmap handle 416 HBITMAP hbm = NULL; 417 Color color(0xFF, 0xFF, 0xFF); 418 Gdiplus::Status status; 419 status = GetCommon().CreateHBITMAPFromBitmap( 420 pBitmap, &hbm, color.GetValue()); 421 422 // delete Bitmap 423 GetCommon().DisposeImage(pBitmap); 424 425 // attach it 426 if (status == Ok) 427 Attach(hbm); 428 return (status == Ok ? S_OK : E_FAIL); 429 } 430 431 // NOTE: LoadFromResource loads BITMAP resource only 432 void LoadFromResource(HINSTANCE hInstance, LPCTSTR pszResourceName) throw() 433 { 434 HANDLE hHandle = ::LoadImage(hInstance, pszResourceName, 435 IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); 436 Attach(reinterpret_cast<HBITMAP>(hHandle)); 437 } 438 void LoadFromResource(HINSTANCE hInstance, UINT nIDResource) throw() 439 { 440 LoadFromResource(hInstance, MAKEINTRESOURCE(nIDResource)); 441 } 442 443 BOOL MaskBlt(HDC hDestDC, int xDest, int yDest, 444 int nDestWidth, int nDestHeight, int xSrc, int ySrc, 445 HBITMAP hbmMask, int xMask, int yMask, 446 DWORD dwROP = SRCCOPY) const throw() 447 { 448 ATLASSERT(IsTransparencySupported()); 449 GetDC(); 450 BOOL ret = ::MaskBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 451 m_hDC, xSrc, ySrc, 452 hbmMask, xMask, yMask, dwROP); 453 ReleaseDC(); 454 return ret; 455 } 456 BOOL MaskBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, 457 HBITMAP hbmMask, const POINT& pointMask, 458 DWORD dwROP = SRCCOPY) const throw() 459 { 460 return MaskBlt(hDestDC, rectDest.left, rectDest.top, 461 rectDest.right - rectDest.left, rectDest.bottom - rectDest.top, 462 pointSrc.x, pointSrc.y, hbmMask, pointMask.x, pointMask.y, dwROP); 463 } 464 BOOL MaskBlt(HDC hDestDC, int xDest, int yDest, 465 HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw() 466 { 467 return MaskBlt(hDestDC, xDest, yDest, GetWidth(), GetHeight(), 468 0, 0, hbmMask, 0, 0, dwROP); 469 } 470 BOOL MaskBlt(HDC hDestDC, const POINT& pointDest, 471 HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw() 472 { 473 return MaskBlt(hDestDC, pointDest.x, pointDest.y, hbmMask, dwROP); 474 } 475 476 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, 477 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 478 HBITMAP hbmMask = NULL, 479 int xMask = 0, int yMask = 0) const throw() 480 { 481 ATLASSERT(IsTransparencySupported()); 482 GetDC(); 483 BOOL ret = ::PlgBlt(hDestDC, pPoints, m_hDC, 484 xSrc, ySrc, nSrcWidth, nSrcHeight, 485 hbmMask, xMask, yMask); 486 ReleaseDC(); 487 return ret; 488 } 489 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, 490 HBITMAP hbmMask = NULL) const throw() 491 { 492 return PlgBlt(hDestDC, pPoints, 0, 0, GetWidth(), GetHeight(), 493 hbmMask); 494 } 495 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, 496 HBITMAP hbmMask, const POINT& pointMask) const throw() 497 { 498 return PlgBlt(hDestDC, pPoints, rectSrc.left, rectSrc.top, 499 rectSrc.right - rectSrc.left, rectSrc.bottom - rectSrc.top, 500 hbmMask, pointMask.x, pointMask.y); 501 } 502 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, 503 HBITMAP hbmMask = NULL) const throw() 504 { 505 POINT pointMask = {0, 0}; 506 return PlgBlt(hDestDC, pPoints, rectSrc, hbmMask, pointMask); 507 } 508 509 void ReleaseGDIPlus() throw() 510 { 511 COMMON*& pCommon = GetCommonPtr(); 512 if (pCommon && pCommon->Release() == 0) 513 { 514 delete pCommon; 515 pCommon = NULL; 516 } 517 } 518 519 HRESULT Save(IStream* pStream, GUID *guidFileType) const throw() 520 { 521 using namespace Gdiplus; 522 ATLASSERT(m_hbm); 523 524 // TODO & FIXME: set parameters (m_rgbTransColor etc.) 525 CLSID clsid; 526 if (!GetClsidFromFileType(&clsid, guidFileType)) 527 return E_FAIL; 528 529 // create a GpBitmap from HBITMAP 530 GpBitmap *pBitmap = NULL; 531 GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); 532 533 // save to stream 534 Status status; 535 status = GetCommon().SaveImageToStream(pBitmap, pStream, &clsid, NULL); 536 537 // destroy GpBitmap 538 GetCommon().DisposeImage(pBitmap); 539 540 return (status == Ok ? S_OK : E_FAIL); 541 } 542 HRESULT Save(LPCTSTR pszFileName, 543 REFGUID guidFileType = GUID_NULL) const throw() 544 { 545 using namespace Gdiplus; 546 ATLASSERT(m_hbm); 547 548 // TODO & FIXME: set parameters (m_rgbTransColor etc.) 549 550 // convert the file name string into Unicode 551 CStringW pszNameW(pszFileName); 552 553 // if the file type is null, get the file type from extension 554 const GUID *FileType = &guidFileType; 555 if (IsGuidEqual(guidFileType, GUID_NULL)) 556 { 557 LPCWSTR pszExt = GetFileExtension(pszNameW); 558 FileType = FileTypeFromExtension(pszExt); 559 } 560 561 // get CLSID from file type 562 CLSID clsid; 563 if (!GetClsidFromFileType(&clsid, FileType)) 564 return E_FAIL; 565 566 // create a GpBitmap from HBITMAP 567 GpBitmap *pBitmap = NULL; 568 GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); 569 570 // save to file 571 Status status; 572 status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL); 573 574 // destroy GpBitmap 575 GetCommon().DisposeImage(pBitmap); 576 577 return (status == Ok ? S_OK : E_FAIL); 578 } 579 580 void SetColorTable(UINT iFirstColor, UINT nColors, 581 const RGBQUAD* prgbColors) throw() 582 { 583 ATLASSERT(IsDIBSection()); 584 GetDC(); 585 ::SetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors); 586 ReleaseDC(); 587 } 588 589 void SetPixel(int x, int y, COLORREF color) throw() 590 { 591 GetDC(); 592 ::SetPixelV(m_hDC, x, y, color); 593 ReleaseDC(); 594 } 595 596 void SetPixelIndexed(int x, int y, int iIndex) throw() 597 { 598 ATLASSERT(IsIndexed()); 599 GetDC(); 600 ::SetPixelV(m_hDC, x, y, PALETTEINDEX(iIndex)); 601 ReleaseDC(); 602 } 603 604 void SetPixelRGB(int x, int y, BYTE r, BYTE g, BYTE b) throw() 605 { 606 SetPixel(x, y, RGB(r, g, b)); 607 } 608 609 COLORREF SetTransparentColor(COLORREF rgbTransparent) throw() 610 { 611 ATLASSERT(m_hbm); 612 COLORREF rgbOldColor = m_rgbTransColor; 613 m_rgbTransColor = rgbTransparent; 614 return rgbOldColor; 615 } 616 617 BOOL StretchBlt(HDC hDestDC, int xDest, int yDest, 618 int nDestWidth, int nDestHeight, 619 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 620 DWORD dwROP = SRCCOPY) const throw() 621 { 622 GetDC(); 623 BOOL ret = ::StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 624 m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwROP); 625 ReleaseDC(); 626 return ret; 627 } 628 BOOL StretchBlt(HDC hDestDC, int xDest, int yDest, 629 int nDestWidth, int nDestHeight, 630 DWORD dwROP = SRCCOPY) const throw() 631 { 632 return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 633 0, 0, GetWidth(), GetHeight(), dwROP); 634 } 635 BOOL StretchBlt(HDC hDestDC, const RECT& rectDest, 636 DWORD dwROP = SRCCOPY) const throw() 637 { 638 return StretchBlt(hDestDC, rectDest.left, rectDest.top, 639 rectDest.right - rectDest.left, 640 rectDest.bottom - rectDest.top, dwROP); 641 } 642 BOOL StretchBlt(HDC hDestDC, const RECT& rectDest, 643 const RECT& rectSrc, DWORD dwROP = SRCCOPY) const throw() 644 { 645 return StretchBlt(hDestDC, rectDest.left, rectDest.top, 646 rectDest.right - rectDest.left, 647 rectDest.bottom - rectDest.top, 648 rectSrc.left, rectSrc.top, 649 rectSrc.right - rectSrc.left, 650 rectSrc.bottom - rectSrc.top, dwROP); 651 } 652 653 BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest, 654 int nDestWidth, int nDestHeight, 655 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 656 UINT crTransparent = CLR_INVALID) const throw() 657 { 658 ATLASSERT(IsTransparencySupported()); 659 GetDC(); 660 BOOL ret = ::TransparentBlt(hDestDC, xDest, yDest, 661 nDestWidth, nDestHeight, 662 m_hDC, xSrc, ySrc, 663 nSrcWidth, nSrcHeight, crTransparent); 664 ReleaseDC(); 665 return ret; 666 } 667 BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest, 668 int nDestWidth, int nDestHeight, 669 UINT crTransparent = CLR_INVALID) const throw() 670 { 671 return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 672 0, 0, GetWidth(), GetHeight(), crTransparent); 673 } 674 BOOL TransparentBlt(HDC hDestDC, const RECT& rectDest, 675 UINT crTransparent = CLR_INVALID) const throw() 676 { 677 return TransparentBlt(hDestDC, rectDest.left, rectDest.top, 678 rectDest.right - rectDest.left, 679 rectDest.bottom - rectDest.top, crTransparent); 680 } 681 BOOL TransparentBlt( 682 HDC hDestDC, const RECT& rectDest, 683 const RECT& rectSrc, UINT crTransparent = CLR_INVALID) const throw() 684 { 685 return TransparentBlt(hDestDC, rectDest.left, rectDest.top, 686 rectDest.right - rectDest.left, rectDest.bottom - rectDest.left, 687 rectSrc.left, rectSrc.top, rectSrc.right - rectSrc.left, 688 rectSrc.bottom - rectSrc.top, crTransparent); 689 } 690 691 public: 692 static BOOL IsTransparencySupported() throw() 693 { 694 return TRUE; 695 } 696 697 enum ExcludeFlags 698 { 699 excludeGIF = 0x01, 700 excludeBMP = 0x02, 701 excludeEMF = 0x04, 702 excludeWMF = 0x08, 703 excludeJPEG = 0x10, 704 excludePNG = 0x20, 705 excludeTIFF = 0x40, 706 excludeIcon = 0x80, 707 excludeOther = 0x80000000, 708 excludeDefaultLoad = 0, 709 excludeDefaultSave = excludeIcon | excludeEMF | excludeWMF 710 }; 711 712 struct FILTER_DATA { 713 DWORD dwExclude; 714 const TCHAR *title; 715 const TCHAR *extensions; 716 const GUID *guid; 717 }; 718 719 protected: 720 static HRESULT GetCommonFilterString( 721 CSimpleString& strFilter, 722 CSimpleArray<GUID>& aguidFileTypes, 723 LPCTSTR pszAllFilesDescription, 724 DWORD dwExclude, 725 TCHAR chSeparator) 726 { 727 static const FILTER_DATA table[] = 728 { 729 {excludeBMP, TEXT("BMP"), TEXT("*.BMP;*.DIB;*.RLE"), &Gdiplus::ImageFormatBMP}, 730 {excludeJPEG, TEXT("JPEG"), TEXT("*.JPG;*.JPEG;*.JPE;*.JFIF"), &Gdiplus::ImageFormatJPEG}, 731 {excludeGIF, TEXT("GIF"), TEXT("*.GIF"), &Gdiplus::ImageFormatGIF}, 732 {excludeEMF, TEXT("EMF"), TEXT("*.EMF"), &Gdiplus::ImageFormatEMF}, 733 {excludeWMF, TEXT("WMF"), TEXT("*.WMF"), &Gdiplus::ImageFormatWMF}, 734 {excludeTIFF, TEXT("TIFF"), TEXT("*.TIF;*.TIFF"), &Gdiplus::ImageFormatTIFF}, 735 {excludePNG, TEXT("PNG"), TEXT("*.PNG"), &Gdiplus::ImageFormatPNG}, 736 {excludeIcon, TEXT("ICO"), TEXT("*.ICO"), &Gdiplus::ImageFormatIcon} 737 }; 738 739 if (pszAllFilesDescription) 740 { 741 strFilter += pszAllFilesDescription; 742 strFilter += chSeparator; 743 744 BOOL bFirst = TRUE; 745 for (size_t i = 0; i < _countof(table); ++i) 746 { 747 if ((dwExclude & table[i].dwExclude) != 0) 748 continue; 749 750 if (bFirst) 751 bFirst = FALSE; 752 else 753 strFilter += TEXT(';'); 754 755 strFilter += table[i].extensions; 756 } 757 strFilter += chSeparator; 758 759 aguidFileTypes.Add(GUID_NULL); 760 } 761 762 for (size_t i = 0; i < _countof(table); ++i) 763 { 764 if ((dwExclude & table[i].dwExclude) != 0) 765 continue; 766 strFilter += table[i].title; 767 strFilter += TEXT(" ("); 768 strFilter += table[i].extensions; 769 strFilter += TEXT(")"); 770 strFilter += chSeparator; 771 strFilter += table[i].extensions; 772 strFilter += chSeparator; 773 774 aguidFileTypes.Add(*table[i].guid); 775 } 776 777 strFilter += chSeparator; 778 779 return S_OK; 780 } 781 782 public: 783 static HRESULT GetImporterFilterString( 784 CSimpleString& strImporters, 785 CSimpleArray<GUID>& aguidFileTypes, 786 LPCTSTR pszAllFilesDescription = NULL, 787 DWORD dwExclude = excludeDefaultLoad, 788 TCHAR chSeparator = TEXT('|')) 789 { 790 return GetCommonFilterString(strImporters, 791 aguidFileTypes, 792 pszAllFilesDescription, 793 dwExclude, 794 chSeparator); 795 } 796 797 static HRESULT GetExporterFilterString( 798 CSimpleString& strExporters, 799 CSimpleArray<GUID>& aguidFileTypes, 800 LPCTSTR pszAllFilesDescription = NULL, 801 DWORD dwExclude = excludeDefaultSave, 802 TCHAR chSeparator = TEXT('|')) 803 { 804 return GetCommonFilterString(strExporters, 805 aguidFileTypes, 806 pszAllFilesDescription, 807 dwExclude, 808 chSeparator); 809 } 810 811 protected: 812 // an extension of BITMAPINFO 813 struct MYBITMAPINFOEX 814 { 815 BITMAPINFOHEADER bmiHeader; 816 RGBQUAD bmiColors[256]; 817 BITMAPINFO *get() 818 { 819 return reinterpret_cast<BITMAPINFO *>(this); 820 } 821 const BITMAPINFO *get() const 822 { 823 return reinterpret_cast<const BITMAPINFO *>(this); 824 } 825 }; 826 827 // The common data of atlimage 828 struct COMMON 829 { 830 // abbreviations of GDI+ basic types 831 typedef Gdiplus::GpStatus St; 832 typedef Gdiplus::ImageCodecInfo ICI; 833 typedef Gdiplus::GpBitmap Bm; 834 typedef Gdiplus::EncoderParameters EncParams; 835 typedef Gdiplus::GpImage Im; 836 typedef Gdiplus::ARGB ARGB; 837 typedef HBITMAP HBM; 838 typedef Gdiplus::GdiplusStartupInput GSI; 839 typedef Gdiplus::GdiplusStartupOutput GSO; 840 841 // GDI+ function types 842 #undef API 843 #undef CST 844 #define API WINGDIPAPI 845 #define CST GDIPCONST 846 typedef St (WINAPI *STARTUP)(ULONG_PTR *, const GSI *, GSO *); 847 typedef void (WINAPI *SHUTDOWN)(ULONG_PTR); 848 typedef St (API *GETIMAGEENCODERSSIZE)(UINT *, UINT *); 849 typedef St (API *GETIMAGEENCODERS)(UINT, UINT, ICI *); 850 typedef St (API *CREATEBITMAPFROMFILE)(CST WCHAR*, Bm **); 851 typedef St (API *CREATEHBITMAPFROMBITMAP)(Bm *, HBM *, ARGB); 852 typedef St (API *CREATEBITMAPFROMSTREAM)(IStream *, Bm **); 853 typedef St (API *CREATEBITMAPFROMHBITMAP)(HBM, HPALETTE, Bm **); 854 typedef St (API *SAVEIMAGETOSTREAM)(Im *, IStream *, CST CLSID *, 855 CST EncParams *); 856 typedef St (API *SAVEIMAGETOFILE)(Im *, CST WCHAR *, CST CLSID *, 857 CST EncParams *); 858 typedef St (API *DISPOSEIMAGE)(Im*); 859 #undef API 860 #undef CST 861 862 // members 863 int count; 864 HINSTANCE hinstGdiPlus; 865 ULONG_PTR gdiplusToken; 866 867 // GDI+ functions 868 STARTUP Startup; 869 SHUTDOWN Shutdown; 870 GETIMAGEENCODERSSIZE GetImageEncodersSize; 871 GETIMAGEENCODERS GetImageEncoders; 872 CREATEBITMAPFROMFILE CreateBitmapFromFile; 873 CREATEHBITMAPFROMBITMAP CreateHBITMAPFromBitmap; 874 CREATEBITMAPFROMSTREAM CreateBitmapFromStream; 875 CREATEBITMAPFROMHBITMAP CreateBitmapFromHBITMAP; 876 SAVEIMAGETOSTREAM SaveImageToStream; 877 SAVEIMAGETOFILE SaveImageToFile; 878 DISPOSEIMAGE DisposeImage; 879 880 COMMON() 881 { 882 count = 0; 883 hinstGdiPlus = NULL; 884 Startup = NULL; 885 Shutdown = NULL; 886 GetImageEncodersSize = NULL; 887 GetImageEncoders = NULL; 888 CreateBitmapFromFile = NULL; 889 CreateHBITMAPFromBitmap = NULL; 890 CreateBitmapFromStream = NULL; 891 CreateBitmapFromHBITMAP = NULL; 892 SaveImageToStream = NULL; 893 SaveImageToFile = NULL; 894 DisposeImage = NULL; 895 } 896 ~COMMON() 897 { 898 FreeLib(); 899 } 900 901 ULONG AddRef() 902 { 903 return ++count; 904 } 905 ULONG Release() 906 { 907 return --count; 908 } 909 910 // get procedure address of the DLL 911 template <typename TYPE> 912 TYPE AddrOf(const char *name) 913 { 914 FARPROC proc = ::GetProcAddress(hinstGdiPlus, name); 915 return reinterpret_cast<TYPE>(proc); 916 } 917 918 HINSTANCE LoadLib() 919 { 920 if (hinstGdiPlus) 921 return hinstGdiPlus; 922 923 hinstGdiPlus = ::LoadLibraryA("gdiplus.dll"); 924 925 // get procedure addresses from the DLL 926 Startup = AddrOf<STARTUP>("GdiplusStartup"); 927 Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown"); 928 GetImageEncodersSize = 929 AddrOf<GETIMAGEENCODERSSIZE>("GdipGetImageEncodersSize"); 930 GetImageEncoders = AddrOf<GETIMAGEENCODERS>("GdipGetImageEncoders"); 931 CreateBitmapFromFile = 932 AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile"); 933 CreateHBITMAPFromBitmap = 934 AddrOf<CREATEHBITMAPFROMBITMAP>("GdipCreateHBITMAPFromBitmap"); 935 CreateBitmapFromStream = 936 AddrOf<CREATEBITMAPFROMSTREAM>("GdipCreateBitmapFromStream"); 937 CreateBitmapFromHBITMAP = 938 AddrOf<CREATEBITMAPFROMHBITMAP>("GdipCreateBitmapFromHBITMAP"); 939 SaveImageToStream = 940 AddrOf<SAVEIMAGETOSTREAM>("GdipSaveImageToStream"); 941 SaveImageToFile = AddrOf<SAVEIMAGETOFILE>("GdipSaveImageToFile"); 942 DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage"); 943 944 if (hinstGdiPlus && Startup) 945 { 946 Gdiplus::GdiplusStartupInput gdiplusStartupInput; 947 Startup(&gdiplusToken, &gdiplusStartupInput, NULL); 948 } 949 950 return hinstGdiPlus; 951 } 952 void FreeLib() 953 { 954 if (hinstGdiPlus) 955 { 956 Shutdown(gdiplusToken); 957 958 Startup = NULL; 959 Shutdown = NULL; 960 GetImageEncodersSize = NULL; 961 GetImageEncoders = NULL; 962 CreateBitmapFromFile = NULL; 963 CreateHBITMAPFromBitmap = NULL; 964 CreateBitmapFromStream = NULL; 965 CreateBitmapFromHBITMAP = NULL; 966 SaveImageToStream = NULL; 967 SaveImageToFile = NULL; 968 DisposeImage = NULL; 969 ::FreeLibrary(hinstGdiPlus); 970 hinstGdiPlus = NULL; 971 } 972 } 973 }; // struct COMMON 974 975 static COMMON*& GetCommonPtr() 976 { 977 static COMMON *s_pCommon = NULL; 978 return s_pCommon; 979 } 980 981 static COMMON& GetCommon() 982 { 983 COMMON*& pCommon = GetCommonPtr(); 984 if (pCommon == NULL) 985 pCommon = new COMMON; 986 return *pCommon; 987 } 988 989 protected: 990 HBITMAP m_hbm; 991 mutable HGDIOBJ m_hbmOld; 992 mutable HDC m_hDC; 993 DIBOrientation m_eOrientation; 994 bool m_bHasAlphaCh; 995 bool m_bIsDIBSec; 996 COLORREF m_rgbTransColor; 997 union 998 { 999 BITMAP m_bm; 1000 DIBSECTION m_ds; 1001 }; 1002 1003 LPCWSTR GetFileExtension(LPCWSTR pszFileName) const 1004 { 1005 LPCWSTR pch = wcsrchr(pszFileName, L'\\'); 1006 if (pch == NULL) 1007 pch = wcsrchr(pszFileName, L'/'); 1008 pch = (pch ? wcsrchr(pch, L'.') : wcsrchr(pszFileName, L'.')); 1009 return (pch ? pch : (pszFileName + ::lstrlenW(pszFileName))); 1010 } 1011 1012 COLORREF RGBFromPaletteIndex(int iIndex) const 1013 { 1014 RGBQUAD table[256]; 1015 GetColorTable(0, 256, table); 1016 RGBQUAD& quad = table[iIndex]; 1017 return RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue); 1018 } 1019 1020 struct EXTENSION_ENTRY 1021 { 1022 LPCWSTR pszExt; 1023 GUID guid; 1024 }; 1025 1026 const GUID *FileTypeFromExtension(LPCWSTR pszExt) const 1027 { 1028 static const EXTENSION_ENTRY table[] = 1029 { 1030 {L".jpg", Gdiplus::ImageFormatJPEG}, 1031 {L".png", Gdiplus::ImageFormatPNG}, 1032 {L".bmp", Gdiplus::ImageFormatBMP}, 1033 {L".gif", Gdiplus::ImageFormatGIF}, 1034 {L".tif", Gdiplus::ImageFormatTIFF}, 1035 {L".jpeg", Gdiplus::ImageFormatJPEG}, 1036 {L".jpe", Gdiplus::ImageFormatJPEG}, 1037 {L".jfif", Gdiplus::ImageFormatJPEG}, 1038 {L".dib", Gdiplus::ImageFormatBMP}, 1039 {L".rle", Gdiplus::ImageFormatBMP}, 1040 {L".tiff", Gdiplus::ImageFormatTIFF} 1041 }; 1042 const size_t count = _countof(table); 1043 for (size_t i = 0; i < count; ++i) 1044 { 1045 if (::lstrcmpiW(table[i].pszExt, pszExt) == 0) 1046 return &table[i].guid; 1047 } 1048 return NULL; 1049 } 1050 1051 struct FORMAT_ENTRY 1052 { 1053 GUID guid; 1054 LPCWSTR mime; 1055 }; 1056 1057 bool GetClsidFromFileType(CLSID *clsid, const GUID *guid) const 1058 { 1059 static const FORMAT_ENTRY table[] = 1060 { 1061 {Gdiplus::ImageFormatJPEG, L"image/jpeg"}, 1062 {Gdiplus::ImageFormatPNG, L"image/png"}, 1063 {Gdiplus::ImageFormatBMP, L"image/bmp"}, 1064 {Gdiplus::ImageFormatGIF, L"image/gif"}, 1065 {Gdiplus::ImageFormatTIFF, L"image/tiff"} 1066 }; 1067 const size_t count = _countof(table); 1068 for (size_t i = 0; i < count; ++i) 1069 { 1070 if (IsGuidEqual(table[i].guid, *guid)) 1071 { 1072 int num = GetEncoderClsid(table[i].mime, clsid); 1073 if (num >= 0) 1074 { 1075 return true; 1076 } 1077 } 1078 } 1079 return false; 1080 } 1081 1082 int GetEncoderClsid(LPCWSTR mime, CLSID *clsid) const 1083 { 1084 UINT count = 0, total_size = 0; 1085 GetCommon().GetImageEncodersSize(&count, &total_size); 1086 if (total_size == 0) 1087 return -1; // failure 1088 1089 Gdiplus::ImageCodecInfo *pInfo; 1090 BYTE *pb = new BYTE[total_size]; 1091 ATLASSERT(pb); 1092 pInfo = reinterpret_cast<Gdiplus::ImageCodecInfo *>(pb); 1093 if (pInfo == NULL) 1094 return -1; // failure 1095 1096 GetCommon().GetImageEncoders(count, total_size, pInfo); 1097 1098 for (UINT iInfo = 0; iInfo < count; ++iInfo) 1099 { 1100 if (::lstrcmpiW(pInfo[iInfo].MimeType, mime) == 0) 1101 { 1102 *clsid = pInfo[iInfo].Clsid; 1103 delete[] pb; 1104 return iInfo; // success 1105 } 1106 } 1107 1108 delete[] pb; 1109 return -1; // failure 1110 } 1111 1112 bool IsGuidEqual(const GUID& guid1, const GUID& guid2) const 1113 { 1114 RPC_STATUS status; 1115 if (::UuidEqual(const_cast<GUID *>(&guid1), 1116 const_cast<GUID *>(&guid2), &status)) 1117 { 1118 if (status == RPC_S_OK) 1119 return true; 1120 } 1121 return false; 1122 } 1123 1124 void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation, 1125 LONG iTransColor) 1126 { 1127 Destroy(); 1128 1129 const int size = sizeof(DIBSECTION); 1130 m_bIsDIBSec = (::GetObject(hBitmap, size, &m_ds) == size); 1131 1132 bool bOK = (::GetObject(hBitmap, sizeof(BITMAP), &m_bm) != 0); 1133 1134 if (bOK) 1135 { 1136 m_hbm = hBitmap; 1137 m_eOrientation = eOrientation; 1138 m_bHasAlphaCh = (m_bm.bmBitsPixel == 32); 1139 m_rgbTransColor = CLR_INVALID; 1140 } 1141 } 1142 1143 BOOL CreateInternal(int nWidth, int nHeight, int nBPP, 1144 DWORD eCompression, const DWORD* pdwBitmasks = NULL, 1145 DWORD dwFlags = 0) throw() 1146 { 1147 ATLASSERT(nWidth != 0); 1148 ATLASSERT(nHeight != 0); 1149 1150 // initialize BITMAPINFO extension 1151 MYBITMAPINFOEX bi; 1152 ZeroMemory(&bi, sizeof(bi)); 1153 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 1154 bi.bmiHeader.biWidth = nWidth; 1155 bi.bmiHeader.biHeight = nHeight; 1156 bi.bmiHeader.biPlanes = 1; 1157 bi.bmiHeader.biBitCount = nBPP; 1158 bi.bmiHeader.biCompression = eCompression; 1159 1160 // is there alpha channel? 1161 bool bHasAlphaCh; 1162 bHasAlphaCh = (nBPP == 32 && (dwFlags & createAlphaChannel)); 1163 1164 // get orientation 1165 DIBOrientation eOrientation; 1166 eOrientation = ((nHeight > 0) ? DIBOR_BOTTOMUP : DIBOR_TOPDOWN); 1167 1168 // does it have bit fields? 1169 if (eCompression == BI_BITFIELDS) 1170 { 1171 if (nBPP == 16 || nBPP == 32) 1172 { 1173 // store the mask data 1174 LPDWORD pdwMask = reinterpret_cast<LPDWORD>(bi.bmiColors); 1175 pdwMask[0] = pdwBitmasks[0]; 1176 pdwMask[1] = pdwBitmasks[1]; 1177 pdwMask[2] = pdwBitmasks[2]; 1178 } 1179 else 1180 { 1181 return FALSE; 1182 } 1183 } 1184 else 1185 { 1186 ATLASSERT(pdwBitmasks == NULL); 1187 if (pdwBitmasks) 1188 return FALSE; 1189 } 1190 1191 // create a DIB section 1192 HDC hDC = ::CreateCompatibleDC(NULL); 1193 ATLASSERT(hDC); 1194 LPVOID pvBits; 1195 HBITMAP hbm = ::CreateDIBSection(hDC, bi.get(), DIB_RGB_COLORS, 1196 &pvBits, NULL, 0); 1197 ATLASSERT(hbm); 1198 ::DeleteDC(hDC); 1199 1200 // attach it 1201 AttachInternal(hbm, eOrientation, -1); 1202 m_bHasAlphaCh = bHasAlphaCh; 1203 1204 return hbm != NULL; 1205 } 1206 1207 private: 1208 // NOTE: CImage is not copyable 1209 CImage(const CImage&); 1210 CImage& operator=(const CImage&); 1211 }; 1212 1213 } 1214 1215 #endif 1216 1217 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE 1218 using namespace ATL; 1219 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE 1220