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