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 // TODO: use a string class 381 #ifdef UNICODE 382 LPCWSTR pszNameW = pszFileName; 383 #else 384 WCHAR szPath[MAX_PATH]; 385 ::MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szPath, MAX_PATH); 386 LPCWSTR pszNameW = szPath; 387 #endif 388 389 // create a GpBitmap object from file 390 using namespace Gdiplus; 391 GpBitmap *pBitmap = NULL; 392 GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap); 393 ATLASSERT(pBitmap); 394 395 // TODO & FIXME: get parameters (m_rgbTransColor etc.) 396 397 // get bitmap handle 398 HBITMAP hbm = NULL; 399 Color color(0xFF, 0xFF, 0xFF); 400 Gdiplus::Status status; 401 status = GetCommon().CreateHBITMAPFromBitmap( 402 pBitmap, &hbm, color.GetValue()); 403 404 // delete GpBitmap 405 GetCommon().DisposeImage(pBitmap); 406 407 // attach it 408 if (status == Ok) 409 Attach(hbm); 410 return (status == Ok ? S_OK : E_FAIL); 411 } 412 HRESULT Load(IStream* pStream) throw() 413 { 414 // create GpBitmap from stream 415 using namespace Gdiplus; 416 GpBitmap *pBitmap = NULL; 417 GetCommon().CreateBitmapFromStream(pStream, &pBitmap); 418 ATLASSERT(pBitmap); 419 420 // TODO & FIXME: get parameters (m_rgbTransColor etc.) 421 422 // get bitmap handle 423 HBITMAP hbm = NULL; 424 Color color(0xFF, 0xFF, 0xFF); 425 Gdiplus::Status status; 426 status = GetCommon().CreateHBITMAPFromBitmap( 427 pBitmap, &hbm, color.GetValue()); 428 429 // delete Bitmap 430 GetCommon().DisposeImage(pBitmap); 431 432 // attach it 433 if (status == Ok) 434 Attach(hbm); 435 return (status == Ok ? S_OK : E_FAIL); 436 } 437 438 // NOTE: LoadFromResource loads BITMAP resource only 439 void LoadFromResource(HINSTANCE hInstance, LPCTSTR pszResourceName) throw() 440 { 441 HANDLE hHandle = ::LoadImage(hInstance, pszResourceName, 442 IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); 443 Attach(reinterpret_cast<HBITMAP>(hHandle)); 444 } 445 void LoadFromResource(HINSTANCE hInstance, UINT nIDResource) throw() 446 { 447 LoadFromResource(hInstance, MAKEINTRESOURCE(nIDResource)); 448 } 449 450 BOOL MaskBlt(HDC hDestDC, int xDest, int yDest, 451 int nDestWidth, int nDestHeight, int xSrc, int ySrc, 452 HBITMAP hbmMask, int xMask, int yMask, 453 DWORD dwROP = SRCCOPY) const throw() 454 { 455 ATLASSERT(IsTransparencySupported()); 456 GetDC(); 457 BOOL ret = ::MaskBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 458 m_hDC, xSrc, ySrc, 459 hbmMask, xMask, yMask, dwROP); 460 ReleaseDC(); 461 return ret; 462 } 463 BOOL MaskBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, 464 HBITMAP hbmMask, const POINT& pointMask, 465 DWORD dwROP = SRCCOPY) const throw() 466 { 467 return MaskBlt(hDestDC, rectDest.left, rectDest.top, 468 rectDest.right - rectDest.left, rectDest.bottom - rectDest.top, 469 pointSrc.x, pointSrc.y, hbmMask, pointMask.x, pointMask.y, dwROP); 470 } 471 BOOL MaskBlt(HDC hDestDC, int xDest, int yDest, 472 HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw() 473 { 474 return MaskBlt(hDestDC, xDest, yDest, GetWidth(), GetHeight(), 475 0, 0, hbmMask, 0, 0, dwROP); 476 } 477 BOOL MaskBlt(HDC hDestDC, const POINT& pointDest, 478 HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw() 479 { 480 return MaskBlt(hDestDC, pointDest.x, pointDest.y, hbmMask, dwROP); 481 } 482 483 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, 484 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 485 HBITMAP hbmMask = NULL, 486 int xMask = 0, int yMask = 0) const throw() 487 { 488 ATLASSERT(IsTransparencySupported()); 489 GetDC(); 490 BOOL ret = ::PlgBlt(hDestDC, pPoints, m_hDC, 491 xSrc, ySrc, nSrcWidth, nSrcHeight, 492 hbmMask, xMask, yMask); 493 ReleaseDC(); 494 return ret; 495 } 496 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, 497 HBITMAP hbmMask = NULL) const throw() 498 { 499 return PlgBlt(hDestDC, pPoints, 0, 0, GetWidth(), GetHeight(), 500 hbmMask); 501 } 502 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, 503 HBITMAP hbmMask, const POINT& pointMask) const throw() 504 { 505 return PlgBlt(hDestDC, pPoints, rectSrc.left, rectSrc.top, 506 rectSrc.right - rectSrc.left, rectSrc.bottom - rectSrc.top, 507 hbmMask, pointMask.x, pointMask.y); 508 } 509 BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, 510 HBITMAP hbmMask = NULL) const throw() 511 { 512 POINT pointMask = {0, 0}; 513 return PlgBlt(hDestDC, pPoints, rectSrc, hbmMask, pointMask); 514 } 515 516 void ReleaseGDIPlus() throw() 517 { 518 COMMON*& pCommon = GetCommonPtr(); 519 if (pCommon && pCommon->Release() == 0) 520 { 521 delete pCommon; 522 pCommon = NULL; 523 } 524 } 525 526 HRESULT Save(IStream* pStream, GUID *guidFileType) const throw() 527 { 528 using namespace Gdiplus; 529 ATLASSERT(m_hbm); 530 531 // TODO & FIXME: set parameters (m_rgbTransColor etc.) 532 CLSID clsid; 533 if (!GetClsidFromFileType(&clsid, guidFileType)) 534 return E_FAIL; 535 536 // create a GpBitmap from HBITMAP 537 GpBitmap *pBitmap = NULL; 538 GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); 539 540 // save to stream 541 Status status; 542 status = GetCommon().SaveImageToStream(pBitmap, pStream, &clsid, NULL); 543 544 // destroy GpBitmap 545 GetCommon().DisposeImage(pBitmap); 546 547 return (status == Ok ? S_OK : E_FAIL); 548 } 549 HRESULT Save(LPCTSTR pszFileName, 550 REFGUID guidFileType = GUID_NULL) const throw() 551 { 552 using namespace Gdiplus; 553 ATLASSERT(m_hbm); 554 555 // TODO & FIXME: set parameters (m_rgbTransColor etc.) 556 557 // convert the file name string into Unicode 558 // TODO: use a string class 559 #ifdef UNICODE 560 LPCWSTR pszNameW = pszFileName; 561 #else 562 WCHAR szPath[MAX_PATH]; 563 ::MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szPath, MAX_PATH); 564 LPCWSTR pszNameW = szPath; 565 #endif 566 567 // if the file type is null, get the file type from extension 568 const GUID *FileType = &guidFileType; 569 if (IsGuidEqual(guidFileType, GUID_NULL)) 570 { 571 LPCWSTR pszExt = GetFileExtension(pszNameW); 572 FileType = FileTypeFromExtension(pszExt); 573 } 574 575 // get CLSID from file type 576 CLSID clsid; 577 if (!GetClsidFromFileType(&clsid, FileType)) 578 return E_FAIL; 579 580 // create a GpBitmap from HBITMAP 581 GpBitmap *pBitmap = NULL; 582 GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); 583 584 // save to file 585 Status status; 586 status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL); 587 588 // destroy GpBitmap 589 GetCommon().DisposeImage(pBitmap); 590 591 return (status == Ok ? S_OK : E_FAIL); 592 } 593 594 void SetColorTable(UINT iFirstColor, UINT nColors, 595 const RGBQUAD* prgbColors) throw() 596 { 597 ATLASSERT(IsDIBSection()); 598 GetDC(); 599 ::SetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors); 600 ReleaseDC(); 601 } 602 603 void SetPixel(int x, int y, COLORREF color) throw() 604 { 605 GetDC(); 606 ::SetPixelV(m_hDC, x, y, color); 607 ReleaseDC(); 608 } 609 610 void SetPixelIndexed(int x, int y, int iIndex) throw() 611 { 612 ATLASSERT(IsIndexed()); 613 GetDC(); 614 ::SetPixelV(m_hDC, x, y, PALETTEINDEX(iIndex)); 615 ReleaseDC(); 616 } 617 618 void SetPixelRGB(int x, int y, BYTE r, BYTE g, BYTE b) throw() 619 { 620 SetPixel(x, y, RGB(r, g, b)); 621 } 622 623 COLORREF SetTransparentColor(COLORREF rgbTransparent) throw() 624 { 625 ATLASSERT(m_hbm); 626 COLORREF rgbOldColor = m_rgbTransColor; 627 m_rgbTransColor = rgbTransparent; 628 return rgbOldColor; 629 } 630 631 BOOL StretchBlt(HDC hDestDC, int xDest, int yDest, 632 int nDestWidth, int nDestHeight, 633 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 634 DWORD dwROP = SRCCOPY) const throw() 635 { 636 GetDC(); 637 BOOL ret = ::StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 638 m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwROP); 639 ReleaseDC(); 640 return ret; 641 } 642 BOOL StretchBlt(HDC hDestDC, int xDest, int yDest, 643 int nDestWidth, int nDestHeight, 644 DWORD dwROP = SRCCOPY) const throw() 645 { 646 return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 647 0, 0, GetWidth(), GetHeight(), dwROP); 648 } 649 BOOL StretchBlt(HDC hDestDC, const RECT& rectDest, 650 DWORD dwROP = SRCCOPY) const throw() 651 { 652 return StretchBlt(hDestDC, rectDest.left, rectDest.top, 653 rectDest.right - rectDest.left, 654 rectDest.bottom - rectDest.top, dwROP); 655 } 656 BOOL StretchBlt(HDC hDestDC, const RECT& rectDest, 657 const RECT& rectSrc, DWORD dwROP = SRCCOPY) const throw() 658 { 659 return StretchBlt(hDestDC, rectDest.left, rectDest.top, 660 rectDest.right - rectDest.left, 661 rectDest.bottom - rectDest.top, 662 rectSrc.left, rectSrc.top, 663 rectSrc.right - rectSrc.left, 664 rectSrc.bottom - rectSrc.top, dwROP); 665 } 666 667 BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest, 668 int nDestWidth, int nDestHeight, 669 int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, 670 UINT crTransparent = CLR_INVALID) const throw() 671 { 672 ATLASSERT(IsTransparencySupported()); 673 GetDC(); 674 BOOL ret = ::TransparentBlt(hDestDC, xDest, yDest, 675 nDestWidth, nDestHeight, 676 m_hDC, xSrc, ySrc, 677 nSrcWidth, nSrcHeight, crTransparent); 678 ReleaseDC(); 679 return ret; 680 } 681 BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest, 682 int nDestWidth, int nDestHeight, 683 UINT crTransparent = CLR_INVALID) const throw() 684 { 685 return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, 686 0, 0, GetWidth(), GetHeight(), crTransparent); 687 } 688 BOOL TransparentBlt(HDC hDestDC, const RECT& rectDest, 689 UINT crTransparent = CLR_INVALID) const throw() 690 { 691 return TransparentBlt(hDestDC, rectDest.left, rectDest.top, 692 rectDest.right - rectDest.left, 693 rectDest.bottom - rectDest.top, crTransparent); 694 } 695 BOOL TransparentBlt( 696 HDC hDestDC, const RECT& rectDest, 697 const RECT& rectSrc, UINT crTransparent = CLR_INVALID) const throw() 698 { 699 return TransparentBlt(hDestDC, rectDest.left, rectDest.top, 700 rectDest.right - rectDest.left, rectDest.bottom - rectDest.left, 701 rectSrc.left, rectSrc.top, rectSrc.right - rectSrc.left, 702 rectSrc.bottom - rectSrc.top, crTransparent); 703 } 704 705 public: 706 static BOOL IsTransparencySupported() throw() 707 { 708 return TRUE; 709 } 710 711 enum ExcludeFlags 712 { 713 excludeGIF = 0x01, 714 excludeBMP = 0x02, 715 excludeEMF = 0x04, 716 excludeWMF = 0x08, 717 excludeJPEG = 0x10, 718 excludePNG = 0x20, 719 excludeTIFF = 0x40, 720 excludeIcon = 0x80, 721 excludeOther = 0x80000000, 722 excludeDefaultLoad = 0, 723 excludeDefaultSave = excludeIcon | excludeEMF | excludeWMF 724 }; 725 726 struct FILTER_DATA { 727 DWORD dwExclude; 728 const TCHAR *title; 729 const TCHAR *extensions; 730 const GUID *guid; 731 }; 732 733 protected: 734 static HRESULT GetCommonFilterString( 735 CSimpleString& strFilter, 736 CSimpleArray<GUID>& aguidFileTypes, 737 LPCTSTR pszAllFilesDescription, 738 DWORD dwExclude, 739 TCHAR chSeparator) 740 { 741 static const FILTER_DATA table[] = 742 { 743 {excludeBMP, TEXT("BMP"), TEXT("*.BMP;*.DIB;*.RLE"), &Gdiplus::ImageFormatBMP}, 744 {excludeJPEG, TEXT("JPEG"), TEXT("*.JPG;*.JPEG;*.JPE;*.JFIF"), &Gdiplus::ImageFormatJPEG}, 745 {excludeGIF, TEXT("GIF"), TEXT("*.GIF"), &Gdiplus::ImageFormatGIF}, 746 {excludeEMF, TEXT("EMF"), TEXT("*.EMF"), &Gdiplus::ImageFormatEMF}, 747 {excludeWMF, TEXT("WMF"), TEXT("*.WMF"), &Gdiplus::ImageFormatWMF}, 748 {excludeTIFF, TEXT("TIFF"), TEXT("*.TIF;*.TIFF"), &Gdiplus::ImageFormatTIFF}, 749 {excludePNG, TEXT("PNG"), TEXT("*.PNG"), &Gdiplus::ImageFormatPNG}, 750 {excludeIcon, TEXT("ICO"), TEXT("*.ICO"), &Gdiplus::ImageFormatIcon} 751 }; 752 753 if (pszAllFilesDescription) 754 { 755 strFilter += pszAllFilesDescription; 756 strFilter += chSeparator; 757 758 BOOL bFirst = TRUE; 759 for (size_t i = 0; i < _countof(table); ++i) 760 { 761 if ((dwExclude & table[i].dwExclude) != 0) 762 continue; 763 764 if (bFirst) 765 bFirst = FALSE; 766 else 767 strFilter += TEXT(';'); 768 769 strFilter += table[i].extensions; 770 } 771 strFilter += chSeparator; 772 773 aguidFileTypes.Add(GUID_NULL); 774 } 775 776 for (size_t i = 0; i < _countof(table); ++i) 777 { 778 if ((dwExclude & table[i].dwExclude) != 0) 779 continue; 780 strFilter += table[i].title; 781 strFilter += TEXT(" ("); 782 strFilter += table[i].extensions; 783 strFilter += TEXT(")"); 784 strFilter += chSeparator; 785 strFilter += table[i].extensions; 786 strFilter += chSeparator; 787 788 aguidFileTypes.Add(*table[i].guid); 789 } 790 791 strFilter += chSeparator; 792 793 return S_OK; 794 } 795 796 public: 797 static HRESULT GetImporterFilterString( 798 CSimpleString& strImporters, 799 CSimpleArray<GUID>& aguidFileTypes, 800 LPCTSTR pszAllFilesDescription = NULL, 801 DWORD dwExclude = excludeDefaultLoad, 802 TCHAR chSeparator = TEXT('|')) 803 { 804 return GetCommonFilterString(strImporters, 805 aguidFileTypes, 806 pszAllFilesDescription, 807 dwExclude, 808 chSeparator); 809 } 810 811 static HRESULT GetExporterFilterString( 812 CSimpleString& strExporters, 813 CSimpleArray<GUID>& aguidFileTypes, 814 LPCTSTR pszAllFilesDescription = NULL, 815 DWORD dwExclude = excludeDefaultSave, 816 TCHAR chSeparator = TEXT('|')) 817 { 818 return GetCommonFilterString(strExporters, 819 aguidFileTypes, 820 pszAllFilesDescription, 821 dwExclude, 822 chSeparator); 823 } 824 825 protected: 826 // an extension of BITMAPINFO 827 struct MYBITMAPINFOEX 828 { 829 BITMAPINFOHEADER bmiHeader; 830 RGBQUAD bmiColors[256]; 831 BITMAPINFO *get() 832 { 833 return reinterpret_cast<BITMAPINFO *>(this); 834 } 835 const BITMAPINFO *get() const 836 { 837 return reinterpret_cast<const BITMAPINFO *>(this); 838 } 839 }; 840 841 // The common data of atlimage 842 struct COMMON 843 { 844 // abbreviations of GDI+ basic types 845 typedef Gdiplus::GpStatus St; 846 typedef Gdiplus::ImageCodecInfo ICI; 847 typedef Gdiplus::GpBitmap Bm; 848 typedef Gdiplus::EncoderParameters EncParams; 849 typedef Gdiplus::GpImage Im; 850 typedef Gdiplus::ARGB ARGB; 851 typedef HBITMAP HBM; 852 typedef Gdiplus::GdiplusStartupInput GSI; 853 typedef Gdiplus::GdiplusStartupOutput GSO; 854 855 // GDI+ function types 856 #undef API 857 #undef CST 858 #define API WINGDIPAPI 859 #define CST GDIPCONST 860 typedef St (WINAPI *STARTUP)(ULONG_PTR *, const GSI *, GSO *); 861 typedef void (WINAPI *SHUTDOWN)(ULONG_PTR); 862 typedef St (API *GETIMAGEENCODERSSIZE)(UINT *, UINT *); 863 typedef St (API *GETIMAGEENCODERS)(UINT, UINT, ICI *); 864 typedef St (API *CREATEBITMAPFROMFILE)(CST WCHAR*, Bm **); 865 typedef St (API *CREATEHBITMAPFROMBITMAP)(Bm *, HBM *, ARGB); 866 typedef St (API *CREATEBITMAPFROMSTREAM)(IStream *, Bm **); 867 typedef St (API *CREATEBITMAPFROMHBITMAP)(HBM, HPALETTE, Bm **); 868 typedef St (API *SAVEIMAGETOSTREAM)(Im *, IStream *, CST CLSID *, 869 CST EncParams *); 870 typedef St (API *SAVEIMAGETOFILE)(Im *, CST WCHAR *, CST CLSID *, 871 CST EncParams *); 872 typedef St (API *DISPOSEIMAGE)(Im*); 873 #undef API 874 #undef CST 875 876 // members 877 int count; 878 HINSTANCE hinstGdiPlus; 879 ULONG_PTR gdiplusToken; 880 881 // GDI+ functions 882 STARTUP Startup; 883 SHUTDOWN Shutdown; 884 GETIMAGEENCODERSSIZE GetImageEncodersSize; 885 GETIMAGEENCODERS GetImageEncoders; 886 CREATEBITMAPFROMFILE CreateBitmapFromFile; 887 CREATEHBITMAPFROMBITMAP CreateHBITMAPFromBitmap; 888 CREATEBITMAPFROMSTREAM CreateBitmapFromStream; 889 CREATEBITMAPFROMHBITMAP CreateBitmapFromHBITMAP; 890 SAVEIMAGETOSTREAM SaveImageToStream; 891 SAVEIMAGETOFILE SaveImageToFile; 892 DISPOSEIMAGE DisposeImage; 893 894 COMMON() 895 { 896 count = 0; 897 hinstGdiPlus = NULL; 898 Startup = NULL; 899 Shutdown = NULL; 900 GetImageEncodersSize = NULL; 901 GetImageEncoders = NULL; 902 CreateBitmapFromFile = NULL; 903 CreateHBITMAPFromBitmap = NULL; 904 CreateBitmapFromStream = NULL; 905 CreateBitmapFromHBITMAP = NULL; 906 SaveImageToStream = NULL; 907 SaveImageToFile = NULL; 908 DisposeImage = NULL; 909 } 910 ~COMMON() 911 { 912 FreeLib(); 913 } 914 915 ULONG AddRef() 916 { 917 return ++count; 918 } 919 ULONG Release() 920 { 921 return --count; 922 } 923 924 // get procedure address of the DLL 925 template <typename TYPE> 926 TYPE AddrOf(const char *name) 927 { 928 FARPROC proc = ::GetProcAddress(hinstGdiPlus, name); 929 return reinterpret_cast<TYPE>(proc); 930 } 931 932 HINSTANCE LoadLib() 933 { 934 if (hinstGdiPlus) 935 return hinstGdiPlus; 936 937 hinstGdiPlus = ::LoadLibraryA("gdiplus.dll"); 938 939 // get procedure addresses from the DLL 940 Startup = AddrOf<STARTUP>("GdiplusStartup"); 941 Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown"); 942 GetImageEncodersSize = 943 AddrOf<GETIMAGEENCODERSSIZE>("GdipGetImageEncodersSize"); 944 GetImageEncoders = AddrOf<GETIMAGEENCODERS>("GdipGetImageEncoders"); 945 CreateBitmapFromFile = 946 AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile"); 947 CreateHBITMAPFromBitmap = 948 AddrOf<CREATEHBITMAPFROMBITMAP>("GdipCreateHBITMAPFromBitmap"); 949 CreateBitmapFromStream = 950 AddrOf<CREATEBITMAPFROMSTREAM>("GdipCreateBitmapFromStream"); 951 CreateBitmapFromHBITMAP = 952 AddrOf<CREATEBITMAPFROMHBITMAP>("GdipCreateBitmapFromHBITMAP"); 953 SaveImageToStream = 954 AddrOf<SAVEIMAGETOSTREAM>("GdipSaveImageToStream"); 955 SaveImageToFile = AddrOf<SAVEIMAGETOFILE>("GdipSaveImageToFile"); 956 DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage"); 957 958 if (hinstGdiPlus && Startup) 959 { 960 Gdiplus::GdiplusStartupInput gdiplusStartupInput; 961 Startup(&gdiplusToken, &gdiplusStartupInput, NULL); 962 } 963 964 return hinstGdiPlus; 965 } 966 void FreeLib() 967 { 968 if (hinstGdiPlus) 969 { 970 Shutdown(gdiplusToken); 971 972 Startup = NULL; 973 Shutdown = NULL; 974 GetImageEncodersSize = NULL; 975 GetImageEncoders = NULL; 976 CreateBitmapFromFile = NULL; 977 CreateHBITMAPFromBitmap = NULL; 978 CreateBitmapFromStream = NULL; 979 CreateBitmapFromHBITMAP = NULL; 980 SaveImageToStream = NULL; 981 SaveImageToFile = NULL; 982 DisposeImage = NULL; 983 ::FreeLibrary(hinstGdiPlus); 984 hinstGdiPlus = NULL; 985 } 986 } 987 }; // struct COMMON 988 989 static COMMON*& GetCommonPtr() 990 { 991 static COMMON *s_pCommon = NULL; 992 return s_pCommon; 993 } 994 995 static COMMON& GetCommon() 996 { 997 COMMON*& pCommon = GetCommonPtr(); 998 if (pCommon == NULL) 999 pCommon = new COMMON; 1000 return *pCommon; 1001 } 1002 1003 protected: 1004 HBITMAP m_hbm; 1005 mutable HGDIOBJ m_hbmOld; 1006 mutable HDC m_hDC; 1007 DIBOrientation m_eOrientation; 1008 bool m_bHasAlphaCh; 1009 bool m_bIsDIBSec; 1010 COLORREF m_rgbTransColor; 1011 union 1012 { 1013 BITMAP m_bm; 1014 DIBSECTION m_ds; 1015 }; 1016 1017 LPCWSTR GetFileExtension(LPCWSTR pszFileName) const 1018 { 1019 LPCWSTR pch = wcsrchr(pszFileName, L'\\'); 1020 if (pch == NULL) 1021 pch = wcsrchr(pszFileName, L'/'); 1022 pch = (pch ? wcsrchr(pch, L'.') : wcsrchr(pszFileName, L'.')); 1023 return (pch ? pch : (pszFileName + ::lstrlenW(pszFileName))); 1024 } 1025 1026 COLORREF RGBFromPaletteIndex(int iIndex) const 1027 { 1028 RGBQUAD table[256]; 1029 GetColorTable(0, 256, table); 1030 RGBQUAD& quad = table[iIndex]; 1031 return RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue); 1032 } 1033 1034 struct EXTENSION_ENTRY 1035 { 1036 LPCWSTR pszExt; 1037 GUID guid; 1038 }; 1039 1040 const GUID *FileTypeFromExtension(LPCWSTR pszExt) const 1041 { 1042 static const EXTENSION_ENTRY table[] = 1043 { 1044 {L".jpg", Gdiplus::ImageFormatJPEG}, 1045 {L".png", Gdiplus::ImageFormatPNG}, 1046 {L".bmp", Gdiplus::ImageFormatBMP}, 1047 {L".gif", Gdiplus::ImageFormatGIF}, 1048 {L".tif", Gdiplus::ImageFormatTIFF}, 1049 {L".jpeg", Gdiplus::ImageFormatJPEG}, 1050 {L".jpe", Gdiplus::ImageFormatJPEG}, 1051 {L".jfif", Gdiplus::ImageFormatJPEG}, 1052 {L".dib", Gdiplus::ImageFormatBMP}, 1053 {L".rle", Gdiplus::ImageFormatBMP}, 1054 {L".tiff", Gdiplus::ImageFormatTIFF} 1055 }; 1056 const size_t count = _countof(table); 1057 for (size_t i = 0; i < count; ++i) 1058 { 1059 if (::lstrcmpiW(table[i].pszExt, pszExt) == 0) 1060 return &table[i].guid; 1061 } 1062 return NULL; 1063 } 1064 1065 struct FORMAT_ENTRY 1066 { 1067 GUID guid; 1068 LPCWSTR mime; 1069 }; 1070 1071 bool GetClsidFromFileType(CLSID *clsid, const GUID *guid) const 1072 { 1073 static const FORMAT_ENTRY table[] = 1074 { 1075 {Gdiplus::ImageFormatJPEG, L"image/jpeg"}, 1076 {Gdiplus::ImageFormatPNG, L"image/png"}, 1077 {Gdiplus::ImageFormatBMP, L"image/bmp"}, 1078 {Gdiplus::ImageFormatGIF, L"image/gif"}, 1079 {Gdiplus::ImageFormatTIFF, L"image/tiff"} 1080 }; 1081 const size_t count = _countof(table); 1082 for (size_t i = 0; i < count; ++i) 1083 { 1084 if (IsGuidEqual(table[i].guid, *guid)) 1085 { 1086 int num = GetEncoderClsid(table[i].mime, clsid); 1087 if (num >= 0) 1088 { 1089 return true; 1090 } 1091 } 1092 } 1093 return false; 1094 } 1095 1096 int GetEncoderClsid(LPCWSTR mime, CLSID *clsid) const 1097 { 1098 UINT count = 0, total_size = 0; 1099 GetCommon().GetImageEncodersSize(&count, &total_size); 1100 if (total_size == 0) 1101 return -1; // failure 1102 1103 Gdiplus::ImageCodecInfo *pInfo; 1104 BYTE *pb = new BYTE[total_size]; 1105 ATLASSERT(pb); 1106 pInfo = reinterpret_cast<Gdiplus::ImageCodecInfo *>(pb); 1107 if (pInfo == NULL) 1108 return -1; // failure 1109 1110 GetCommon().GetImageEncoders(count, total_size, pInfo); 1111 1112 for (UINT iInfo = 0; iInfo < count; ++iInfo) 1113 { 1114 if (::lstrcmpiW(pInfo[iInfo].MimeType, mime) == 0) 1115 { 1116 *clsid = pInfo[iInfo].Clsid; 1117 delete[] pb; 1118 return iInfo; // success 1119 } 1120 } 1121 1122 delete[] pb; 1123 return -1; // failure 1124 } 1125 1126 bool IsGuidEqual(const GUID& guid1, const GUID& guid2) const 1127 { 1128 RPC_STATUS status; 1129 if (::UuidEqual(const_cast<GUID *>(&guid1), 1130 const_cast<GUID *>(&guid2), &status)) 1131 { 1132 if (status == RPC_S_OK) 1133 return true; 1134 } 1135 return false; 1136 } 1137 1138 void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation, 1139 LONG iTransColor) 1140 { 1141 Destroy(); 1142 1143 const int size = sizeof(DIBSECTION); 1144 m_bIsDIBSec = (::GetObject(hBitmap, size, &m_ds) == size); 1145 1146 bool bOK = (::GetObject(hBitmap, sizeof(BITMAP), &m_bm) != 0); 1147 1148 if (bOK) 1149 { 1150 m_hbm = hBitmap; 1151 m_eOrientation = eOrientation; 1152 m_bHasAlphaCh = (m_bm.bmBitsPixel == 32); 1153 m_rgbTransColor = CLR_INVALID; 1154 } 1155 } 1156 1157 BOOL CreateInternal(int nWidth, int nHeight, int nBPP, 1158 DWORD eCompression, const DWORD* pdwBitmasks = NULL, 1159 DWORD dwFlags = 0) throw() 1160 { 1161 ATLASSERT(nWidth != 0); 1162 ATLASSERT(nHeight != 0); 1163 1164 // initialize BITMAPINFO extension 1165 MYBITMAPINFOEX bi; 1166 ZeroMemory(&bi, sizeof(bi)); 1167 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 1168 bi.bmiHeader.biWidth = nWidth; 1169 bi.bmiHeader.biHeight = nHeight; 1170 bi.bmiHeader.biPlanes = 1; 1171 bi.bmiHeader.biBitCount = nBPP; 1172 bi.bmiHeader.biCompression = eCompression; 1173 1174 // is there alpha channel? 1175 bool bHasAlphaCh; 1176 bHasAlphaCh = (nBPP == 32 && (dwFlags & createAlphaChannel)); 1177 1178 // get orientation 1179 DIBOrientation eOrientation; 1180 eOrientation = ((nHeight > 0) ? DIBOR_BOTTOMUP : DIBOR_TOPDOWN); 1181 1182 // does it have bit fields? 1183 if (eCompression == BI_BITFIELDS) 1184 { 1185 if (nBPP == 16 || nBPP == 32) 1186 { 1187 // store the mask data 1188 LPDWORD pdwMask = reinterpret_cast<LPDWORD>(bi.bmiColors); 1189 pdwMask[0] = pdwBitmasks[0]; 1190 pdwMask[1] = pdwBitmasks[1]; 1191 pdwMask[2] = pdwBitmasks[2]; 1192 } 1193 else 1194 { 1195 return FALSE; 1196 } 1197 } 1198 else 1199 { 1200 ATLASSERT(pdwBitmasks == NULL); 1201 if (pdwBitmasks) 1202 return FALSE; 1203 } 1204 1205 // create a DIB section 1206 HDC hDC = ::CreateCompatibleDC(NULL); 1207 ATLASSERT(hDC); 1208 LPVOID pvBits; 1209 HBITMAP hbm = ::CreateDIBSection(hDC, bi.get(), DIB_RGB_COLORS, 1210 &pvBits, NULL, 0); 1211 ATLASSERT(hbm); 1212 ::DeleteDC(hDC); 1213 1214 // attach it 1215 AttachInternal(hbm, eOrientation, -1); 1216 m_bHasAlphaCh = bHasAlphaCh; 1217 1218 return hbm != NULL; 1219 } 1220 1221 private: 1222 // NOTE: CImage is not copyable 1223 CImage(const CImage&); 1224 CImage& operator=(const CImage&); 1225 }; 1226 1227 } 1228 1229 #endif 1230 1231 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE 1232 using namespace ATL; 1233 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE 1234