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)
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.
15 // TODO: CImage::Load, CImage::Save
16 // TODO: make CImage thread-safe
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
26 #include <cguid.h> // for GUID_NULL
27 #include <gdiplus.h> // GDI+
35 // flags for CImage::Create/CreateEx
38 createAlphaChannel
= 1 // enable alpha
44 DIBOR_DEFAULT
, // default
45 DIBOR_BOTTOMUP
, // bottom-up DIB
46 DIBOR_TOPDOWN
// top-down DIB
55 m_eOrientation
= DIBOR_DEFAULT
;
56 m_bHasAlphaCh
= false;
58 m_rgbTransColor
= CLR_INVALID
;
59 ZeroMemory(&m_ds
, sizeof(m_ds
));
61 if (GetCommon().AddRef() == 1)
63 GetCommon().LoadLib();
79 void Attach(HBITMAP hBitmap
, DIBOrientation eOrientation
= DIBOR_DEFAULT
)
81 AttachInternal(hBitmap
, eOrientation
, -1);
84 HBITMAP
Detach() throw()
86 m_eOrientation
= DIBOR_DEFAULT
;
87 m_bHasAlphaCh
= false;
88 m_rgbTransColor
= CLR_INVALID
;
89 ZeroMemory(&m_ds
, sizeof(m_ds
));
91 HBITMAP hBitmap
= m_hbm
;
96 HDC
GetDC() const throw()
101 m_hDC
= ::CreateCompatibleDC(NULL
);
102 m_hbmOld
= ::SelectObject(m_hDC
, m_hbm
);
106 void ReleaseDC() const throw()
115 ::SelectObject(m_hDC
, m_hbmOld
);
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
128 ATLASSERT(IsTransparencySupported());
131 bf
.BlendOp
= bBlendOp
;
133 bf
.SourceConstantAlpha
= bSrcAlpha
;
134 bf
.AlphaFormat
= AC_SRC_ALPHA
;
137 BOOL ret
= ::AlphaBlend(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
138 m_hDC
, xSrc
, ySrc
, nSrcWidth
, nSrcHeight
, bf
);
142 BOOL
AlphaBlend(HDC hDestDC
, int xDest
, int yDest
,
143 BYTE bSrcAlpha
= 0xFF, BYTE bBlendOp
= AC_SRC_OVER
) const
145 int width
= GetWidth();
146 int height
= GetHeight();
147 return AlphaBlend(hDestDC
, xDest
, yDest
, width
, height
, 0, 0,
148 width
, height
, bSrcAlpha
, bBlendOp
);
150 BOOL
AlphaBlend(HDC hDestDC
, const POINT
& pointDest
,
151 BYTE bSrcAlpha
= 0xFF, BYTE bBlendOp
= AC_SRC_OVER
) const
153 return AlphaBlend(hDestDC
, pointDest
.x
, pointDest
.y
, bSrcAlpha
, bBlendOp
);
155 BOOL
AlphaBlend(HDC hDestDC
, const RECT
& rectDest
, const RECT
& rectSrc
,
156 BYTE bSrcAlpha
= 0xFF, BYTE bBlendOp
= AC_SRC_OVER
) const
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
);
167 BOOL
BitBlt(HDC hDestDC
, int xDest
, int yDest
,
168 int nDestWidth
, int nDestHeight
,
169 int xSrc
, int ySrc
, DWORD dwROP
= SRCCOPY
) const throw()
172 BOOL ret
= ::BitBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
173 m_hDC
, xSrc
, ySrc
, dwROP
);
177 BOOL
BitBlt(HDC hDestDC
, int xDest
, int yDest
,
178 DWORD dwROP
= SRCCOPY
) const throw()
180 return BitBlt(hDestDC
, xDest
, yDest
,
181 GetWidth(), GetHeight(), 0, 0, dwROP
);
183 BOOL
BitBlt(HDC hDestDC
, const POINT
& pointDest
,
184 DWORD dwROP
= SRCCOPY
) const throw()
186 return BitBlt(hDestDC
, pointDest
.x
, pointDest
.y
, dwROP
);
188 BOOL
BitBlt(HDC hDestDC
, const RECT
& rectDest
, const POINT
& pointSrc
,
189 DWORD dwROP
= SRCCOPY
) const throw()
191 return BitBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
192 rectDest
.right
- rectDest
.left
,
193 rectDest
.bottom
- rectDest
.top
,
194 pointSrc
.x
, pointSrc
.y
, dwROP
);
197 BOOL
Create(int nWidth
, int nHeight
, int nBPP
, DWORD dwFlags
= 0) throw()
199 return CreateEx(nWidth
, nHeight
, nBPP
, BI_RGB
, NULL
, dwFlags
);
202 BOOL
CreateEx(int nWidth
, int nHeight
, int nBPP
, DWORD eCompression
,
203 const DWORD
* pdwBitmasks
= NULL
, DWORD dwFlags
= 0) throw()
205 return CreateInternal(nWidth
, nHeight
, nBPP
, eCompression
, pdwBitmasks
, dwFlags
);
208 void Destroy() throw()
212 ::DeleteObject(Detach());
216 BOOL
Draw(HDC hDestDC
, int xDest
, int yDest
, int nDestWidth
, int nDestHeight
,
217 int xSrc
, int ySrc
, int nSrcWidth
, int nSrcHeight
) const throw()
219 ATLASSERT(IsTransparencySupported());
222 return AlphaBlend(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
223 xSrc
, ySrc
, nSrcWidth
, nSrcHeight
);
225 else if (m_rgbTransColor
!= CLR_INVALID
)
228 if ((m_rgbTransColor
& 0xFF000000) == 0x01000000)
229 rgb
= RGBFromPaletteIndex(m_rgbTransColor
& 0xFF);
231 rgb
= m_rgbTransColor
;
232 return TransparentBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
233 xSrc
, ySrc
, nSrcWidth
, nSrcHeight
, rgb
);
237 return StretchBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
238 xSrc
, ySrc
, nSrcWidth
, nSrcHeight
);
241 BOOL
Draw(HDC hDestDC
, const RECT
& rectDest
, const RECT
& rectSrc
) const throw()
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
);
250 BOOL
Draw(HDC hDestDC
, int xDest
, int yDest
) const throw()
252 return Draw(hDestDC
, xDest
, yDest
, GetWidth(), GetHeight());
254 BOOL
Draw(HDC hDestDC
, const POINT
& pointDest
) const throw()
256 return Draw(hDestDC
, pointDest
.x
, pointDest
.y
);
258 BOOL
Draw(HDC hDestDC
, int xDest
, int yDest
,
259 int nDestWidth
, int nDestHeight
) const throw()
261 return Draw(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
262 0, 0, GetWidth(), GetHeight());
264 BOOL
Draw(HDC hDestDC
, const RECT
& rectDest
) const throw()
266 return Draw(hDestDC
, rectDest
.left
, rectDest
.top
,
267 rectDest
.right
- rectDest
.left
,
268 rectDest
.bottom
- rectDest
.top
);
271 void *GetBits() throw()
273 ATLASSERT(IsDIBSection());
274 BYTE
*pb
= (BYTE
*)m_bm
.bmBits
;
275 if (m_eOrientation
== DIBOR_BOTTOMUP
)
277 pb
+= m_bm
.bmWidthBytes
* (m_bm
.bmHeight
- 1);
282 int GetBPP() const throw()
285 return m_bm
.bmBitsPixel
;
288 void GetColorTable(UINT iFirstColor
, UINT nColors
,
289 RGBQUAD
* prgbColors
) const throw()
291 ATLASSERT(IsDIBSection());
293 ::GetDIBColorTable(m_hDC
, iFirstColor
, nColors
, prgbColors
);
297 int GetHeight() const throw()
300 return m_bm
.bmHeight
;
303 int GetMaxColorTableEntries() const throw()
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
)
314 if (m_ds
.dsBmih
.biCompression
== BI_BITFIELDS
)
323 int GetPitch() const throw()
325 ATLASSERT(IsDIBSection());
326 if (m_eOrientation
== DIBOR_BOTTOMUP
)
327 return -m_bm
.bmWidthBytes
;
329 return m_bm
.bmWidthBytes
;
332 COLORREF
GetPixel(int x
, int y
) const throw()
335 COLORREF ret
= ::GetPixel(m_hDC
, x
, y
);
340 void* GetPixelAddress(int x
, int y
) throw()
342 ATLASSERT(IsDIBSection());
343 BYTE
*pb
= (BYTE
*)GetBits();
344 pb
+= GetPitch() * y
;
345 pb
+= (GetBPP() * x
) / 8;
349 COLORREF
GetTransparentColor() const throw()
351 return m_rgbTransColor
;
354 int GetWidth() const throw()
360 bool IsDIBSection() const throw()
366 bool IsIndexed() const throw()
368 ATLASSERT(IsDIBSection());
369 return GetBPP() <= 8;
372 bool IsNull() const throw()
374 return m_hbm
== NULL
;
377 HRESULT
Load(LPCTSTR pszFileName
) throw()
379 // convert the file name string into Unicode
380 CStringW
pszNameW(pszFileName
);
382 // create a GpBitmap object from file
383 using namespace Gdiplus
;
384 GpBitmap
*pBitmap
= NULL
;
385 GetCommon().CreateBitmapFromFile(pszNameW
, &pBitmap
);
388 // TODO & FIXME: get parameters (m_rgbTransColor etc.)
392 Color
color(0xFF, 0xFF, 0xFF);
393 Gdiplus::Status status
;
394 status
= GetCommon().CreateHBITMAPFromBitmap(
395 pBitmap
, &hbm
, color
.GetValue());
398 GetCommon().DisposeImage(pBitmap
);
403 return (status
== Ok
? S_OK
: E_FAIL
);
405 HRESULT
Load(IStream
* pStream
) throw()
407 // create GpBitmap from stream
408 using namespace Gdiplus
;
409 GpBitmap
*pBitmap
= NULL
;
410 GetCommon().CreateBitmapFromStream(pStream
, &pBitmap
);
413 // TODO & FIXME: get parameters (m_rgbTransColor etc.)
417 Color
color(0xFF, 0xFF, 0xFF);
418 Gdiplus::Status status
;
419 status
= GetCommon().CreateHBITMAPFromBitmap(
420 pBitmap
, &hbm
, color
.GetValue());
423 GetCommon().DisposeImage(pBitmap
);
428 return (status
== Ok
? S_OK
: E_FAIL
);
431 // NOTE: LoadFromResource loads BITMAP resource only
432 void LoadFromResource(HINSTANCE hInstance
, LPCTSTR pszResourceName
) throw()
434 HANDLE hHandle
= ::LoadImage(hInstance
, pszResourceName
,
435 IMAGE_BITMAP
, 0, 0, LR_CREATEDIBSECTION
);
436 Attach(reinterpret_cast<HBITMAP
>(hHandle
));
438 void LoadFromResource(HINSTANCE hInstance
, UINT nIDResource
) throw()
440 LoadFromResource(hInstance
, MAKEINTRESOURCE(nIDResource
));
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()
448 ATLASSERT(IsTransparencySupported());
450 BOOL ret
= ::MaskBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
452 hbmMask
, xMask
, yMask
, dwROP
);
456 BOOL
MaskBlt(HDC hDestDC
, const RECT
& rectDest
, const POINT
& pointSrc
,
457 HBITMAP hbmMask
, const POINT
& pointMask
,
458 DWORD dwROP
= SRCCOPY
) const throw()
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
);
464 BOOL
MaskBlt(HDC hDestDC
, int xDest
, int yDest
,
465 HBITMAP hbmMask
, DWORD dwROP
= SRCCOPY
) const throw()
467 return MaskBlt(hDestDC
, xDest
, yDest
, GetWidth(), GetHeight(),
468 0, 0, hbmMask
, 0, 0, dwROP
);
470 BOOL
MaskBlt(HDC hDestDC
, const POINT
& pointDest
,
471 HBITMAP hbmMask
, DWORD dwROP
= SRCCOPY
) const throw()
473 return MaskBlt(hDestDC
, pointDest
.x
, pointDest
.y
, hbmMask
, dwROP
);
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()
481 ATLASSERT(IsTransparencySupported());
483 BOOL ret
= ::PlgBlt(hDestDC
, pPoints
, m_hDC
,
484 xSrc
, ySrc
, nSrcWidth
, nSrcHeight
,
485 hbmMask
, xMask
, yMask
);
489 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
,
490 HBITMAP hbmMask
= NULL
) const throw()
492 return PlgBlt(hDestDC
, pPoints
, 0, 0, GetWidth(), GetHeight(),
495 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
, const RECT
& rectSrc
,
496 HBITMAP hbmMask
, const POINT
& pointMask
) const throw()
498 return PlgBlt(hDestDC
, pPoints
, rectSrc
.left
, rectSrc
.top
,
499 rectSrc
.right
- rectSrc
.left
, rectSrc
.bottom
- rectSrc
.top
,
500 hbmMask
, pointMask
.x
, pointMask
.y
);
502 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
, const RECT
& rectSrc
,
503 HBITMAP hbmMask
= NULL
) const throw()
505 POINT pointMask
= {0, 0};
506 return PlgBlt(hDestDC
, pPoints
, rectSrc
, hbmMask
, pointMask
);
509 void ReleaseGDIPlus() throw()
511 COMMON
*& pCommon
= GetCommonPtr();
512 if (pCommon
&& pCommon
->Release() == 0)
519 HRESULT
Save(IStream
* pStream
, GUID
*guidFileType
) const throw()
521 using namespace Gdiplus
;
524 // TODO & FIXME: set parameters (m_rgbTransColor etc.)
526 if (!GetClsidFromFileType(&clsid
, guidFileType
))
529 // create a GpBitmap from HBITMAP
530 GpBitmap
*pBitmap
= NULL
;
531 GetCommon().CreateBitmapFromHBITMAP(m_hbm
, NULL
, &pBitmap
);
535 status
= GetCommon().SaveImageToStream(pBitmap
, pStream
, &clsid
, NULL
);
538 GetCommon().DisposeImage(pBitmap
);
540 return (status
== Ok
? S_OK
: E_FAIL
);
542 HRESULT
Save(LPCTSTR pszFileName
,
543 REFGUID guidFileType
= GUID_NULL
) const throw()
545 using namespace Gdiplus
;
548 // TODO & FIXME: set parameters (m_rgbTransColor etc.)
550 // convert the file name string into Unicode
551 CStringW
pszNameW(pszFileName
);
553 // if the file type is null, get the file type from extension
554 const GUID
*FileType
= &guidFileType
;
555 if (IsGuidEqual(guidFileType
, GUID_NULL
))
557 LPCWSTR pszExt
= GetFileExtension(pszNameW
);
558 FileType
= FileTypeFromExtension(pszExt
);
561 // get CLSID from file type
563 if (!GetClsidFromFileType(&clsid
, FileType
))
566 // create a GpBitmap from HBITMAP
567 GpBitmap
*pBitmap
= NULL
;
568 GetCommon().CreateBitmapFromHBITMAP(m_hbm
, NULL
, &pBitmap
);
572 status
= GetCommon().SaveImageToFile(pBitmap
, pszNameW
, &clsid
, NULL
);
575 GetCommon().DisposeImage(pBitmap
);
577 return (status
== Ok
? S_OK
: E_FAIL
);
580 void SetColorTable(UINT iFirstColor
, UINT nColors
,
581 const RGBQUAD
* prgbColors
) throw()
583 ATLASSERT(IsDIBSection());
585 ::SetDIBColorTable(m_hDC
, iFirstColor
, nColors
, prgbColors
);
589 void SetPixel(int x
, int y
, COLORREF color
) throw()
592 ::SetPixelV(m_hDC
, x
, y
, color
);
596 void SetPixelIndexed(int x
, int y
, int iIndex
) throw()
598 ATLASSERT(IsIndexed());
600 ::SetPixelV(m_hDC
, x
, y
, PALETTEINDEX(iIndex
));
604 void SetPixelRGB(int x
, int y
, BYTE r
, BYTE g
, BYTE b
) throw()
606 SetPixel(x
, y
, RGB(r
, g
, b
));
609 COLORREF
SetTransparentColor(COLORREF rgbTransparent
) throw()
612 COLORREF rgbOldColor
= m_rgbTransColor
;
613 m_rgbTransColor
= rgbTransparent
;
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()
623 BOOL ret
= ::StretchBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
624 m_hDC
, xSrc
, ySrc
, nSrcWidth
, nSrcHeight
, dwROP
);
628 BOOL
StretchBlt(HDC hDestDC
, int xDest
, int yDest
,
629 int nDestWidth
, int nDestHeight
,
630 DWORD dwROP
= SRCCOPY
) const throw()
632 return StretchBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
633 0, 0, GetWidth(), GetHeight(), dwROP
);
635 BOOL
StretchBlt(HDC hDestDC
, const RECT
& rectDest
,
636 DWORD dwROP
= SRCCOPY
) const throw()
638 return StretchBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
639 rectDest
.right
- rectDest
.left
,
640 rectDest
.bottom
- rectDest
.top
, dwROP
);
642 BOOL
StretchBlt(HDC hDestDC
, const RECT
& rectDest
,
643 const RECT
& rectSrc
, DWORD dwROP
= SRCCOPY
) const throw()
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
);
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()
658 ATLASSERT(IsTransparencySupported());
660 BOOL ret
= ::TransparentBlt(hDestDC
, xDest
, yDest
,
661 nDestWidth
, nDestHeight
,
663 nSrcWidth
, nSrcHeight
, crTransparent
);
667 BOOL
TransparentBlt(HDC hDestDC
, int xDest
, int yDest
,
668 int nDestWidth
, int nDestHeight
,
669 UINT crTransparent
= CLR_INVALID
) const throw()
671 return TransparentBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
672 0, 0, GetWidth(), GetHeight(), crTransparent
);
674 BOOL
TransparentBlt(HDC hDestDC
, const RECT
& rectDest
,
675 UINT crTransparent
= CLR_INVALID
) const throw()
677 return TransparentBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
678 rectDest
.right
- rectDest
.left
,
679 rectDest
.bottom
- rectDest
.top
, crTransparent
);
682 HDC hDestDC
, const RECT
& rectDest
,
683 const RECT
& rectSrc
, UINT crTransparent
= CLR_INVALID
) const throw()
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
);
692 static BOOL
IsTransparencySupported() throw()
707 excludeOther
= 0x80000000,
708 excludeDefaultLoad
= 0,
709 excludeDefaultSave
= excludeIcon
| excludeEMF
| excludeWMF
715 const TCHAR
*extensions
;
720 static HRESULT
GetCommonFilterString(
721 CSimpleString
& strFilter
,
722 CSimpleArray
<GUID
>& aguidFileTypes
,
723 LPCTSTR pszAllFilesDescription
,
727 static const FILTER_DATA table
[] =
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
}
739 if (pszAllFilesDescription
)
741 strFilter
+= pszAllFilesDescription
;
742 strFilter
+= chSeparator
;
745 for (size_t i
= 0; i
< _countof(table
); ++i
)
747 if ((dwExclude
& table
[i
].dwExclude
) != 0)
753 strFilter
+= TEXT(';');
755 strFilter
+= table
[i
].extensions
;
757 strFilter
+= chSeparator
;
759 aguidFileTypes
.Add(GUID_NULL
);
762 for (size_t i
= 0; i
< _countof(table
); ++i
)
764 if ((dwExclude
& table
[i
].dwExclude
) != 0)
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
;
774 aguidFileTypes
.Add(*table
[i
].guid
);
777 strFilter
+= chSeparator
;
783 static HRESULT
GetImporterFilterString(
784 CSimpleString
& strImporters
,
785 CSimpleArray
<GUID
>& aguidFileTypes
,
786 LPCTSTR pszAllFilesDescription
= NULL
,
787 DWORD dwExclude
= excludeDefaultLoad
,
788 TCHAR chSeparator
= TEXT('|'))
790 return GetCommonFilterString(strImporters
,
792 pszAllFilesDescription
,
797 static HRESULT
GetExporterFilterString(
798 CSimpleString
& strExporters
,
799 CSimpleArray
<GUID
>& aguidFileTypes
,
800 LPCTSTR pszAllFilesDescription
= NULL
,
801 DWORD dwExclude
= excludeDefaultSave
,
802 TCHAR chSeparator
= TEXT('|'))
804 return GetCommonFilterString(strExporters
,
806 pszAllFilesDescription
,
812 // an extension of BITMAPINFO
813 struct MYBITMAPINFOEX
815 BITMAPINFOHEADER bmiHeader
;
816 RGBQUAD bmiColors
[256];
819 return reinterpret_cast<BITMAPINFO
*>(this);
821 const BITMAPINFO
*get() const
823 return reinterpret_cast<const BITMAPINFO
*>(this);
827 // The common data of atlimage
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
;
838 typedef Gdiplus::GdiplusStartupInput GSI
;
839 typedef Gdiplus::GdiplusStartupOutput GSO
;
841 // GDI+ function types
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
*,
856 typedef St (API
*SAVEIMAGETOFILE
)(Im
*, CST WCHAR
*, CST CLSID
*,
858 typedef St (API
*DISPOSEIMAGE
)(Im
*);
864 HINSTANCE hinstGdiPlus
;
865 ULONG_PTR gdiplusToken
;
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
;
886 GetImageEncodersSize
= NULL
;
887 GetImageEncoders
= NULL
;
888 CreateBitmapFromFile
= NULL
;
889 CreateHBITMAPFromBitmap
= NULL
;
890 CreateBitmapFromStream
= NULL
;
891 CreateBitmapFromHBITMAP
= NULL
;
892 SaveImageToStream
= NULL
;
893 SaveImageToFile
= NULL
;
910 // get procedure address of the DLL
911 template <typename TYPE
>
912 TYPE
AddrOf(const char *name
)
914 FARPROC proc
= ::GetProcAddress(hinstGdiPlus
, name
);
915 return reinterpret_cast<TYPE
>(proc
);
923 hinstGdiPlus
= ::LoadLibraryA("gdiplus.dll");
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");
940 AddrOf
<SAVEIMAGETOSTREAM
>("GdipSaveImageToStream");
941 SaveImageToFile
= AddrOf
<SAVEIMAGETOFILE
>("GdipSaveImageToFile");
942 DisposeImage
= AddrOf
<DISPOSEIMAGE
>("GdipDisposeImage");
944 if (hinstGdiPlus
&& Startup
)
946 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
947 Startup(&gdiplusToken
, &gdiplusStartupInput
, NULL
);
956 Shutdown(gdiplusToken
);
960 GetImageEncodersSize
= NULL
;
961 GetImageEncoders
= NULL
;
962 CreateBitmapFromFile
= NULL
;
963 CreateHBITMAPFromBitmap
= NULL
;
964 CreateBitmapFromStream
= NULL
;
965 CreateBitmapFromHBITMAP
= NULL
;
966 SaveImageToStream
= NULL
;
967 SaveImageToFile
= NULL
;
969 ::FreeLibrary(hinstGdiPlus
);
975 static COMMON
*& GetCommonPtr()
977 static COMMON
*s_pCommon
= NULL
;
981 static COMMON
& GetCommon()
983 COMMON
*& pCommon
= GetCommonPtr();
985 pCommon
= new COMMON
;
991 mutable HGDIOBJ m_hbmOld
;
993 DIBOrientation m_eOrientation
;
996 COLORREF m_rgbTransColor
;
1003 LPCWSTR
GetFileExtension(LPCWSTR pszFileName
) const
1005 LPCWSTR pch
= wcsrchr(pszFileName
, L
'\\');
1007 pch
= wcsrchr(pszFileName
, L
'/');
1008 pch
= (pch
? wcsrchr(pch
, L
'.') : wcsrchr(pszFileName
, L
'.'));
1009 return (pch
? pch
: (pszFileName
+ ::lstrlenW(pszFileName
)));
1012 COLORREF
RGBFromPaletteIndex(int iIndex
) const
1015 GetColorTable(0, 256, table
);
1016 RGBQUAD
& quad
= table
[iIndex
];
1017 return RGB(quad
.rgbRed
, quad
.rgbGreen
, quad
.rgbBlue
);
1020 struct EXTENSION_ENTRY
1026 const GUID
*FileTypeFromExtension(LPCWSTR pszExt
) const
1028 static const EXTENSION_ENTRY table
[] =
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
}
1042 const size_t count
= _countof(table
);
1043 for (size_t i
= 0; i
< count
; ++i
)
1045 if (::lstrcmpiW(table
[i
].pszExt
, pszExt
) == 0)
1046 return &table
[i
].guid
;
1057 bool GetClsidFromFileType(CLSID
*clsid
, const GUID
*guid
) const
1059 static const FORMAT_ENTRY table
[] =
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"}
1067 const size_t count
= _countof(table
);
1068 for (size_t i
= 0; i
< count
; ++i
)
1070 if (IsGuidEqual(table
[i
].guid
, *guid
))
1072 int num
= GetEncoderClsid(table
[i
].mime
, clsid
);
1082 int GetEncoderClsid(LPCWSTR mime
, CLSID
*clsid
) const
1084 UINT count
= 0, total_size
= 0;
1085 GetCommon().GetImageEncodersSize(&count
, &total_size
);
1086 if (total_size
== 0)
1087 return -1; // failure
1089 Gdiplus::ImageCodecInfo
*pInfo
;
1090 BYTE
*pb
= new BYTE
[total_size
];
1092 pInfo
= reinterpret_cast<Gdiplus::ImageCodecInfo
*>(pb
);
1094 return -1; // failure
1096 GetCommon().GetImageEncoders(count
, total_size
, pInfo
);
1098 for (UINT iInfo
= 0; iInfo
< count
; ++iInfo
)
1100 if (::lstrcmpiW(pInfo
[iInfo
].MimeType
, mime
) == 0)
1102 *clsid
= pInfo
[iInfo
].Clsid
;
1104 return iInfo
; // success
1109 return -1; // failure
1112 bool IsGuidEqual(const GUID
& guid1
, const GUID
& guid2
) const
1115 if (::UuidEqual(const_cast<GUID
*>(&guid1
),
1116 const_cast<GUID
*>(&guid2
), &status
))
1118 if (status
== RPC_S_OK
)
1124 void AttachInternal(HBITMAP hBitmap
, DIBOrientation eOrientation
,
1129 const int size
= sizeof(DIBSECTION
);
1130 m_bIsDIBSec
= (::GetObject(hBitmap
, size
, &m_ds
) == size
);
1132 bool bOK
= (::GetObject(hBitmap
, sizeof(BITMAP
), &m_bm
) != 0);
1137 m_eOrientation
= eOrientation
;
1138 m_bHasAlphaCh
= (m_bm
.bmBitsPixel
== 32);
1139 m_rgbTransColor
= CLR_INVALID
;
1143 BOOL
CreateInternal(int nWidth
, int nHeight
, int nBPP
,
1144 DWORD eCompression
, const DWORD
* pdwBitmasks
= NULL
,
1145 DWORD dwFlags
= 0) throw()
1147 ATLASSERT(nWidth
!= 0);
1148 ATLASSERT(nHeight
!= 0);
1150 // initialize BITMAPINFO extension
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
;
1160 // is there alpha channel?
1162 bHasAlphaCh
= (nBPP
== 32 && (dwFlags
& createAlphaChannel
));
1165 DIBOrientation eOrientation
;
1166 eOrientation
= ((nHeight
> 0) ? DIBOR_BOTTOMUP
: DIBOR_TOPDOWN
);
1168 // does it have bit fields?
1169 if (eCompression
== BI_BITFIELDS
)
1171 if (nBPP
== 16 || nBPP
== 32)
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];
1186 ATLASSERT(pdwBitmasks
== NULL
);
1191 // create a DIB section
1192 HDC hDC
= ::CreateCompatibleDC(NULL
);
1195 HBITMAP hbm
= ::CreateDIBSection(hDC
, bi
.get(), DIB_RGB_COLORS
,
1201 AttachInternal(hbm
, eOrientation
, -1);
1202 m_bHasAlphaCh
= bHasAlphaCh
;
1208 // NOTE: CImage is not copyable
1209 CImage(const CImage
&);
1210 CImage
& operator=(const CImage
&);
1217 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE
1218 using namespace ATL
;
1219 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE