[SHELL32] Fix Control_RunDLLW (#5400)
[reactos.git] / sdk / lib / atl / atlimage.h
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