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 // TODO: use a string class
382 LPCWSTR pszNameW
= pszFileName
;
384 WCHAR szPath
[MAX_PATH
];
385 ::MultiByteToWideChar(CP_ACP
, 0, pszFileName
, -1, szPath
, MAX_PATH
);
386 LPCWSTR pszNameW
= szPath
;
389 // create a GpBitmap object from file
390 using namespace Gdiplus
;
391 GpBitmap
*pBitmap
= NULL
;
392 GetCommon().CreateBitmapFromFile(pszNameW
, &pBitmap
);
395 // TODO & FIXME: get parameters (m_rgbTransColor etc.)
399 Color
color(0xFF, 0xFF, 0xFF);
400 Gdiplus::Status status
;
401 status
= GetCommon().CreateHBITMAPFromBitmap(
402 pBitmap
, &hbm
, color
.GetValue());
405 GetCommon().DisposeImage(pBitmap
);
410 return (status
== Ok
? S_OK
: E_FAIL
);
412 HRESULT
Load(IStream
* pStream
) throw()
414 // create GpBitmap from stream
415 using namespace Gdiplus
;
416 GpBitmap
*pBitmap
= NULL
;
417 GetCommon().CreateBitmapFromStream(pStream
, &pBitmap
);
420 // TODO & FIXME: get parameters (m_rgbTransColor etc.)
424 Color
color(0xFF, 0xFF, 0xFF);
425 Gdiplus::Status status
;
426 status
= GetCommon().CreateHBITMAPFromBitmap(
427 pBitmap
, &hbm
, color
.GetValue());
430 GetCommon().DisposeImage(pBitmap
);
435 return (status
== Ok
? S_OK
: E_FAIL
);
438 // NOTE: LoadFromResource loads BITMAP resource only
439 void LoadFromResource(HINSTANCE hInstance
, LPCTSTR pszResourceName
) throw()
441 HANDLE hHandle
= ::LoadImage(hInstance
, pszResourceName
,
442 IMAGE_BITMAP
, 0, 0, LR_CREATEDIBSECTION
);
443 Attach(reinterpret_cast<HBITMAP
>(hHandle
));
445 void LoadFromResource(HINSTANCE hInstance
, UINT nIDResource
) throw()
447 LoadFromResource(hInstance
, MAKEINTRESOURCE(nIDResource
));
450 BOOL
MaskBlt(HDC hDestDC
, int xDest
, int yDest
,
451 int nDestWidth
, int nDestHeight
, int xSrc
, int ySrc
,
452 HBITMAP hbmMask
, int xMask
, int yMask
,
453 DWORD dwROP
= SRCCOPY
) const throw()
455 ATLASSERT(IsTransparencySupported());
457 BOOL ret
= ::MaskBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
459 hbmMask
, xMask
, yMask
, dwROP
);
463 BOOL
MaskBlt(HDC hDestDC
, const RECT
& rectDest
, const POINT
& pointSrc
,
464 HBITMAP hbmMask
, const POINT
& pointMask
,
465 DWORD dwROP
= SRCCOPY
) const throw()
467 return MaskBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
468 rectDest
.right
- rectDest
.left
, rectDest
.bottom
- rectDest
.top
,
469 pointSrc
.x
, pointSrc
.y
, hbmMask
, pointMask
.x
, pointMask
.y
, dwROP
);
471 BOOL
MaskBlt(HDC hDestDC
, int xDest
, int yDest
,
472 HBITMAP hbmMask
, DWORD dwROP
= SRCCOPY
) const throw()
474 return MaskBlt(hDestDC
, xDest
, yDest
, GetWidth(), GetHeight(),
475 0, 0, hbmMask
, 0, 0, dwROP
);
477 BOOL
MaskBlt(HDC hDestDC
, const POINT
& pointDest
,
478 HBITMAP hbmMask
, DWORD dwROP
= SRCCOPY
) const throw()
480 return MaskBlt(hDestDC
, pointDest
.x
, pointDest
.y
, hbmMask
, dwROP
);
483 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
,
484 int xSrc
, int ySrc
, int nSrcWidth
, int nSrcHeight
,
485 HBITMAP hbmMask
= NULL
,
486 int xMask
= 0, int yMask
= 0) const throw()
488 ATLASSERT(IsTransparencySupported());
490 BOOL ret
= ::PlgBlt(hDestDC
, pPoints
, m_hDC
,
491 xSrc
, ySrc
, nSrcWidth
, nSrcHeight
,
492 hbmMask
, xMask
, yMask
);
496 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
,
497 HBITMAP hbmMask
= NULL
) const throw()
499 return PlgBlt(hDestDC
, pPoints
, 0, 0, GetWidth(), GetHeight(),
502 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
, const RECT
& rectSrc
,
503 HBITMAP hbmMask
, const POINT
& pointMask
) const throw()
505 return PlgBlt(hDestDC
, pPoints
, rectSrc
.left
, rectSrc
.top
,
506 rectSrc
.right
- rectSrc
.left
, rectSrc
.bottom
- rectSrc
.top
,
507 hbmMask
, pointMask
.x
, pointMask
.y
);
509 BOOL
PlgBlt(HDC hDestDC
, const POINT
* pPoints
, const RECT
& rectSrc
,
510 HBITMAP hbmMask
= NULL
) const throw()
512 POINT pointMask
= {0, 0};
513 return PlgBlt(hDestDC
, pPoints
, rectSrc
, hbmMask
, pointMask
);
516 void ReleaseGDIPlus() throw()
518 COMMON
*& pCommon
= GetCommonPtr();
519 if (pCommon
&& pCommon
->Release() == 0)
526 HRESULT
Save(IStream
* pStream
, GUID
*guidFileType
) const throw()
528 using namespace Gdiplus
;
531 // TODO & FIXME: set parameters (m_rgbTransColor etc.)
533 if (!GetClsidFromFileType(&clsid
, guidFileType
))
536 // create a GpBitmap from HBITMAP
537 GpBitmap
*pBitmap
= NULL
;
538 GetCommon().CreateBitmapFromHBITMAP(m_hbm
, NULL
, &pBitmap
);
542 status
= GetCommon().SaveImageToStream(pBitmap
, pStream
, &clsid
, NULL
);
545 GetCommon().DisposeImage(pBitmap
);
547 return (status
== Ok
? S_OK
: E_FAIL
);
549 HRESULT
Save(LPCTSTR pszFileName
,
550 REFGUID guidFileType
= GUID_NULL
) const throw()
552 using namespace Gdiplus
;
555 // TODO & FIXME: set parameters (m_rgbTransColor etc.)
557 // convert the file name string into Unicode
558 // TODO: use a string class
560 LPCWSTR pszNameW
= pszFileName
;
562 WCHAR szPath
[MAX_PATH
];
563 ::MultiByteToWideChar(CP_ACP
, 0, pszFileName
, -1, szPath
, MAX_PATH
);
564 LPCWSTR pszNameW
= szPath
;
567 // if the file type is null, get the file type from extension
568 const GUID
*FileType
= &guidFileType
;
569 if (IsGuidEqual(guidFileType
, GUID_NULL
))
571 LPCWSTR pszExt
= GetFileExtension(pszNameW
);
572 FileType
= FileTypeFromExtension(pszExt
);
575 // get CLSID from file type
577 if (!GetClsidFromFileType(&clsid
, FileType
))
580 // create a GpBitmap from HBITMAP
581 GpBitmap
*pBitmap
= NULL
;
582 GetCommon().CreateBitmapFromHBITMAP(m_hbm
, NULL
, &pBitmap
);
586 status
= GetCommon().SaveImageToFile(pBitmap
, pszNameW
, &clsid
, NULL
);
589 GetCommon().DisposeImage(pBitmap
);
591 return (status
== Ok
? S_OK
: E_FAIL
);
594 void SetColorTable(UINT iFirstColor
, UINT nColors
,
595 const RGBQUAD
* prgbColors
) throw()
597 ATLASSERT(IsDIBSection());
599 ::SetDIBColorTable(m_hDC
, iFirstColor
, nColors
, prgbColors
);
603 void SetPixel(int x
, int y
, COLORREF color
) throw()
606 ::SetPixelV(m_hDC
, x
, y
, color
);
610 void SetPixelIndexed(int x
, int y
, int iIndex
) throw()
612 ATLASSERT(IsIndexed());
614 ::SetPixelV(m_hDC
, x
, y
, PALETTEINDEX(iIndex
));
618 void SetPixelRGB(int x
, int y
, BYTE r
, BYTE g
, BYTE b
) throw()
620 SetPixel(x
, y
, RGB(r
, g
, b
));
623 COLORREF
SetTransparentColor(COLORREF rgbTransparent
) throw()
626 COLORREF rgbOldColor
= m_rgbTransColor
;
627 m_rgbTransColor
= rgbTransparent
;
631 BOOL
StretchBlt(HDC hDestDC
, int xDest
, int yDest
,
632 int nDestWidth
, int nDestHeight
,
633 int xSrc
, int ySrc
, int nSrcWidth
, int nSrcHeight
,
634 DWORD dwROP
= SRCCOPY
) const throw()
637 BOOL ret
= ::StretchBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
638 m_hDC
, xSrc
, ySrc
, nSrcWidth
, nSrcHeight
, dwROP
);
642 BOOL
StretchBlt(HDC hDestDC
, int xDest
, int yDest
,
643 int nDestWidth
, int nDestHeight
,
644 DWORD dwROP
= SRCCOPY
) const throw()
646 return StretchBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
647 0, 0, GetWidth(), GetHeight(), dwROP
);
649 BOOL
StretchBlt(HDC hDestDC
, const RECT
& rectDest
,
650 DWORD dwROP
= SRCCOPY
) const throw()
652 return StretchBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
653 rectDest
.right
- rectDest
.left
,
654 rectDest
.bottom
- rectDest
.top
, dwROP
);
656 BOOL
StretchBlt(HDC hDestDC
, const RECT
& rectDest
,
657 const RECT
& rectSrc
, DWORD dwROP
= SRCCOPY
) const throw()
659 return StretchBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
660 rectDest
.right
- rectDest
.left
,
661 rectDest
.bottom
- rectDest
.top
,
662 rectSrc
.left
, rectSrc
.top
,
663 rectSrc
.right
- rectSrc
.left
,
664 rectSrc
.bottom
- rectSrc
.top
, dwROP
);
667 BOOL
TransparentBlt(HDC hDestDC
, int xDest
, int yDest
,
668 int nDestWidth
, int nDestHeight
,
669 int xSrc
, int ySrc
, int nSrcWidth
, int nSrcHeight
,
670 UINT crTransparent
= CLR_INVALID
) const throw()
672 ATLASSERT(IsTransparencySupported());
674 BOOL ret
= ::TransparentBlt(hDestDC
, xDest
, yDest
,
675 nDestWidth
, nDestHeight
,
677 nSrcWidth
, nSrcHeight
, crTransparent
);
681 BOOL
TransparentBlt(HDC hDestDC
, int xDest
, int yDest
,
682 int nDestWidth
, int nDestHeight
,
683 UINT crTransparent
= CLR_INVALID
) const throw()
685 return TransparentBlt(hDestDC
, xDest
, yDest
, nDestWidth
, nDestHeight
,
686 0, 0, GetWidth(), GetHeight(), crTransparent
);
688 BOOL
TransparentBlt(HDC hDestDC
, const RECT
& rectDest
,
689 UINT crTransparent
= CLR_INVALID
) const throw()
691 return TransparentBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
692 rectDest
.right
- rectDest
.left
,
693 rectDest
.bottom
- rectDest
.top
, crTransparent
);
696 HDC hDestDC
, const RECT
& rectDest
,
697 const RECT
& rectSrc
, UINT crTransparent
= CLR_INVALID
) const throw()
699 return TransparentBlt(hDestDC
, rectDest
.left
, rectDest
.top
,
700 rectDest
.right
- rectDest
.left
, rectDest
.bottom
- rectDest
.left
,
701 rectSrc
.left
, rectSrc
.top
, rectSrc
.right
- rectSrc
.left
,
702 rectSrc
.bottom
- rectSrc
.top
, crTransparent
);
706 static BOOL
IsTransparencySupported() throw()
721 excludeOther
= 0x80000000,
722 excludeDefaultLoad
= 0,
723 excludeDefaultSave
= excludeIcon
| excludeEMF
| excludeWMF
729 const TCHAR
*extensions
;
734 static HRESULT
GetCommonFilterString(
735 CSimpleString
& strFilter
,
736 CSimpleArray
<GUID
>& aguidFileTypes
,
737 LPCTSTR pszAllFilesDescription
,
741 static const FILTER_DATA table
[] =
743 {excludeBMP
, TEXT("BMP"), TEXT("*.BMP;*.DIB;*.RLE"), &Gdiplus::ImageFormatBMP
},
744 {excludeJPEG
, TEXT("JPEG"), TEXT("*.JPG;*.JPEG;*.JPE;*.JFIF"), &Gdiplus::ImageFormatJPEG
},
745 {excludeGIF
, TEXT("GIF"), TEXT("*.GIF"), &Gdiplus::ImageFormatGIF
},
746 {excludeEMF
, TEXT("EMF"), TEXT("*.EMF"), &Gdiplus::ImageFormatEMF
},
747 {excludeWMF
, TEXT("WMF"), TEXT("*.WMF"), &Gdiplus::ImageFormatWMF
},
748 {excludeTIFF
, TEXT("TIFF"), TEXT("*.TIF;*.TIFF"), &Gdiplus::ImageFormatTIFF
},
749 {excludePNG
, TEXT("PNG"), TEXT("*.PNG"), &Gdiplus::ImageFormatPNG
},
750 {excludeIcon
, TEXT("ICO"), TEXT("*.ICO"), &Gdiplus::ImageFormatIcon
}
753 if (pszAllFilesDescription
)
755 strFilter
+= pszAllFilesDescription
;
756 strFilter
+= chSeparator
;
759 for (size_t i
= 0; i
< _countof(table
); ++i
)
761 if ((dwExclude
& table
[i
].dwExclude
) != 0)
767 strFilter
+= TEXT(';');
769 strFilter
+= table
[i
].extensions
;
771 strFilter
+= chSeparator
;
773 aguidFileTypes
.Add(GUID_NULL
);
776 for (size_t i
= 0; i
< _countof(table
); ++i
)
778 if ((dwExclude
& table
[i
].dwExclude
) != 0)
780 strFilter
+= table
[i
].title
;
781 strFilter
+= TEXT(" (");
782 strFilter
+= table
[i
].extensions
;
783 strFilter
+= TEXT(")");
784 strFilter
+= chSeparator
;
785 strFilter
+= table
[i
].extensions
;
786 strFilter
+= chSeparator
;
788 aguidFileTypes
.Add(*table
[i
].guid
);
791 strFilter
+= chSeparator
;
797 static HRESULT
GetImporterFilterString(
798 CSimpleString
& strImporters
,
799 CSimpleArray
<GUID
>& aguidFileTypes
,
800 LPCTSTR pszAllFilesDescription
= NULL
,
801 DWORD dwExclude
= excludeDefaultLoad
,
802 TCHAR chSeparator
= TEXT('|'))
804 return GetCommonFilterString(strImporters
,
806 pszAllFilesDescription
,
811 static HRESULT
GetExporterFilterString(
812 CSimpleString
& strExporters
,
813 CSimpleArray
<GUID
>& aguidFileTypes
,
814 LPCTSTR pszAllFilesDescription
= NULL
,
815 DWORD dwExclude
= excludeDefaultSave
,
816 TCHAR chSeparator
= TEXT('|'))
818 return GetCommonFilterString(strExporters
,
820 pszAllFilesDescription
,
826 // an extension of BITMAPINFO
827 struct MYBITMAPINFOEX
829 BITMAPINFOHEADER bmiHeader
;
830 RGBQUAD bmiColors
[256];
833 return reinterpret_cast<BITMAPINFO
*>(this);
835 const BITMAPINFO
*get() const
837 return reinterpret_cast<const BITMAPINFO
*>(this);
841 // The common data of atlimage
844 // abbreviations of GDI+ basic types
845 typedef Gdiplus::GpStatus St
;
846 typedef Gdiplus::ImageCodecInfo ICI
;
847 typedef Gdiplus::GpBitmap Bm
;
848 typedef Gdiplus::EncoderParameters EncParams
;
849 typedef Gdiplus::GpImage Im
;
850 typedef Gdiplus::ARGB ARGB
;
852 typedef Gdiplus::GdiplusStartupInput GSI
;
853 typedef Gdiplus::GdiplusStartupOutput GSO
;
855 // GDI+ function types
858 #define API WINGDIPAPI
859 #define CST GDIPCONST
860 typedef St (WINAPI
*STARTUP
)(ULONG_PTR
*, const GSI
*, GSO
*);
861 typedef void (WINAPI
*SHUTDOWN
)(ULONG_PTR
);
862 typedef St (API
*GETIMAGEENCODERSSIZE
)(UINT
*, UINT
*);
863 typedef St (API
*GETIMAGEENCODERS
)(UINT
, UINT
, ICI
*);
864 typedef St (API
*CREATEBITMAPFROMFILE
)(CST WCHAR
*, Bm
**);
865 typedef St (API
*CREATEHBITMAPFROMBITMAP
)(Bm
*, HBM
*, ARGB
);
866 typedef St (API
*CREATEBITMAPFROMSTREAM
)(IStream
*, Bm
**);
867 typedef St (API
*CREATEBITMAPFROMHBITMAP
)(HBM
, HPALETTE
, Bm
**);
868 typedef St (API
*SAVEIMAGETOSTREAM
)(Im
*, IStream
*, CST CLSID
*,
870 typedef St (API
*SAVEIMAGETOFILE
)(Im
*, CST WCHAR
*, CST CLSID
*,
872 typedef St (API
*DISPOSEIMAGE
)(Im
*);
878 HINSTANCE hinstGdiPlus
;
879 ULONG_PTR gdiplusToken
;
884 GETIMAGEENCODERSSIZE GetImageEncodersSize
;
885 GETIMAGEENCODERS GetImageEncoders
;
886 CREATEBITMAPFROMFILE CreateBitmapFromFile
;
887 CREATEHBITMAPFROMBITMAP CreateHBITMAPFromBitmap
;
888 CREATEBITMAPFROMSTREAM CreateBitmapFromStream
;
889 CREATEBITMAPFROMHBITMAP CreateBitmapFromHBITMAP
;
890 SAVEIMAGETOSTREAM SaveImageToStream
;
891 SAVEIMAGETOFILE SaveImageToFile
;
892 DISPOSEIMAGE DisposeImage
;
900 GetImageEncodersSize
= NULL
;
901 GetImageEncoders
= NULL
;
902 CreateBitmapFromFile
= NULL
;
903 CreateHBITMAPFromBitmap
= NULL
;
904 CreateBitmapFromStream
= NULL
;
905 CreateBitmapFromHBITMAP
= NULL
;
906 SaveImageToStream
= NULL
;
907 SaveImageToFile
= NULL
;
924 // get procedure address of the DLL
925 template <typename TYPE
>
926 TYPE
AddrOf(const char *name
)
928 FARPROC proc
= ::GetProcAddress(hinstGdiPlus
, name
);
929 return reinterpret_cast<TYPE
>(proc
);
937 hinstGdiPlus
= ::LoadLibraryA("gdiplus.dll");
939 // get procedure addresses from the DLL
940 Startup
= AddrOf
<STARTUP
>("GdiplusStartup");
941 Shutdown
= AddrOf
<SHUTDOWN
>("GdiplusShutdown");
942 GetImageEncodersSize
=
943 AddrOf
<GETIMAGEENCODERSSIZE
>("GdipGetImageEncodersSize");
944 GetImageEncoders
= AddrOf
<GETIMAGEENCODERS
>("GdipGetImageEncoders");
945 CreateBitmapFromFile
=
946 AddrOf
<CREATEBITMAPFROMFILE
>("GdipCreateBitmapFromFile");
947 CreateHBITMAPFromBitmap
=
948 AddrOf
<CREATEHBITMAPFROMBITMAP
>("GdipCreateHBITMAPFromBitmap");
949 CreateBitmapFromStream
=
950 AddrOf
<CREATEBITMAPFROMSTREAM
>("GdipCreateBitmapFromStream");
951 CreateBitmapFromHBITMAP
=
952 AddrOf
<CREATEBITMAPFROMHBITMAP
>("GdipCreateBitmapFromHBITMAP");
954 AddrOf
<SAVEIMAGETOSTREAM
>("GdipSaveImageToStream");
955 SaveImageToFile
= AddrOf
<SAVEIMAGETOFILE
>("GdipSaveImageToFile");
956 DisposeImage
= AddrOf
<DISPOSEIMAGE
>("GdipDisposeImage");
958 if (hinstGdiPlus
&& Startup
)
960 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
961 Startup(&gdiplusToken
, &gdiplusStartupInput
, NULL
);
970 Shutdown(gdiplusToken
);
974 GetImageEncodersSize
= NULL
;
975 GetImageEncoders
= NULL
;
976 CreateBitmapFromFile
= NULL
;
977 CreateHBITMAPFromBitmap
= NULL
;
978 CreateBitmapFromStream
= NULL
;
979 CreateBitmapFromHBITMAP
= NULL
;
980 SaveImageToStream
= NULL
;
981 SaveImageToFile
= NULL
;
983 ::FreeLibrary(hinstGdiPlus
);
989 static COMMON
*& GetCommonPtr()
991 static COMMON
*s_pCommon
= NULL
;
995 static COMMON
& GetCommon()
997 COMMON
*& pCommon
= GetCommonPtr();
999 pCommon
= new COMMON
;
1005 mutable HGDIOBJ m_hbmOld
;
1007 DIBOrientation m_eOrientation
;
1010 COLORREF m_rgbTransColor
;
1017 LPCWSTR
GetFileExtension(LPCWSTR pszFileName
) const
1019 LPCWSTR pch
= wcsrchr(pszFileName
, L
'\\');
1021 pch
= wcsrchr(pszFileName
, L
'/');
1022 pch
= (pch
? wcsrchr(pch
, L
'.') : wcsrchr(pszFileName
, L
'.'));
1023 return (pch
? pch
: (pszFileName
+ ::lstrlenW(pszFileName
)));
1026 COLORREF
RGBFromPaletteIndex(int iIndex
) const
1029 GetColorTable(0, 256, table
);
1030 RGBQUAD
& quad
= table
[iIndex
];
1031 return RGB(quad
.rgbRed
, quad
.rgbGreen
, quad
.rgbBlue
);
1034 struct EXTENSION_ENTRY
1040 const GUID
*FileTypeFromExtension(LPCWSTR pszExt
) const
1042 static const EXTENSION_ENTRY table
[] =
1044 {L
".jpg", Gdiplus::ImageFormatJPEG
},
1045 {L
".png", Gdiplus::ImageFormatPNG
},
1046 {L
".bmp", Gdiplus::ImageFormatBMP
},
1047 {L
".gif", Gdiplus::ImageFormatGIF
},
1048 {L
".tif", Gdiplus::ImageFormatTIFF
},
1049 {L
".jpeg", Gdiplus::ImageFormatJPEG
},
1050 {L
".jpe", Gdiplus::ImageFormatJPEG
},
1051 {L
".jfif", Gdiplus::ImageFormatJPEG
},
1052 {L
".dib", Gdiplus::ImageFormatBMP
},
1053 {L
".rle", Gdiplus::ImageFormatBMP
},
1054 {L
".tiff", Gdiplus::ImageFormatTIFF
}
1056 const size_t count
= _countof(table
);
1057 for (size_t i
= 0; i
< count
; ++i
)
1059 if (::lstrcmpiW(table
[i
].pszExt
, pszExt
) == 0)
1060 return &table
[i
].guid
;
1071 bool GetClsidFromFileType(CLSID
*clsid
, const GUID
*guid
) const
1073 static const FORMAT_ENTRY table
[] =
1075 {Gdiplus::ImageFormatJPEG
, L
"image/jpeg"},
1076 {Gdiplus::ImageFormatPNG
, L
"image/png"},
1077 {Gdiplus::ImageFormatBMP
, L
"image/bmp"},
1078 {Gdiplus::ImageFormatGIF
, L
"image/gif"},
1079 {Gdiplus::ImageFormatTIFF
, L
"image/tiff"}
1081 const size_t count
= _countof(table
);
1082 for (size_t i
= 0; i
< count
; ++i
)
1084 if (IsGuidEqual(table
[i
].guid
, *guid
))
1086 int num
= GetEncoderClsid(table
[i
].mime
, clsid
);
1096 int GetEncoderClsid(LPCWSTR mime
, CLSID
*clsid
) const
1098 UINT count
= 0, total_size
= 0;
1099 GetCommon().GetImageEncodersSize(&count
, &total_size
);
1100 if (total_size
== 0)
1101 return -1; // failure
1103 Gdiplus::ImageCodecInfo
*pInfo
;
1104 BYTE
*pb
= new BYTE
[total_size
];
1106 pInfo
= reinterpret_cast<Gdiplus::ImageCodecInfo
*>(pb
);
1108 return -1; // failure
1110 GetCommon().GetImageEncoders(count
, total_size
, pInfo
);
1112 for (UINT iInfo
= 0; iInfo
< count
; ++iInfo
)
1114 if (::lstrcmpiW(pInfo
[iInfo
].MimeType
, mime
) == 0)
1116 *clsid
= pInfo
[iInfo
].Clsid
;
1118 return iInfo
; // success
1123 return -1; // failure
1126 bool IsGuidEqual(const GUID
& guid1
, const GUID
& guid2
) const
1129 if (::UuidEqual(const_cast<GUID
*>(&guid1
),
1130 const_cast<GUID
*>(&guid2
), &status
))
1132 if (status
== RPC_S_OK
)
1138 void AttachInternal(HBITMAP hBitmap
, DIBOrientation eOrientation
,
1143 const int size
= sizeof(DIBSECTION
);
1144 m_bIsDIBSec
= (::GetObject(hBitmap
, size
, &m_ds
) == size
);
1146 bool bOK
= (::GetObject(hBitmap
, sizeof(BITMAP
), &m_bm
) != 0);
1151 m_eOrientation
= eOrientation
;
1152 m_bHasAlphaCh
= (m_bm
.bmBitsPixel
== 32);
1153 m_rgbTransColor
= CLR_INVALID
;
1157 BOOL
CreateInternal(int nWidth
, int nHeight
, int nBPP
,
1158 DWORD eCompression
, const DWORD
* pdwBitmasks
= NULL
,
1159 DWORD dwFlags
= 0) throw()
1161 ATLASSERT(nWidth
!= 0);
1162 ATLASSERT(nHeight
!= 0);
1164 // initialize BITMAPINFO extension
1166 ZeroMemory(&bi
, sizeof(bi
));
1167 bi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1168 bi
.bmiHeader
.biWidth
= nWidth
;
1169 bi
.bmiHeader
.biHeight
= nHeight
;
1170 bi
.bmiHeader
.biPlanes
= 1;
1171 bi
.bmiHeader
.biBitCount
= nBPP
;
1172 bi
.bmiHeader
.biCompression
= eCompression
;
1174 // is there alpha channel?
1176 bHasAlphaCh
= (nBPP
== 32 && (dwFlags
& createAlphaChannel
));
1179 DIBOrientation eOrientation
;
1180 eOrientation
= ((nHeight
> 0) ? DIBOR_BOTTOMUP
: DIBOR_TOPDOWN
);
1182 // does it have bit fields?
1183 if (eCompression
== BI_BITFIELDS
)
1185 if (nBPP
== 16 || nBPP
== 32)
1187 // store the mask data
1188 LPDWORD pdwMask
= reinterpret_cast<LPDWORD
>(bi
.bmiColors
);
1189 pdwMask
[0] = pdwBitmasks
[0];
1190 pdwMask
[1] = pdwBitmasks
[1];
1191 pdwMask
[2] = pdwBitmasks
[2];
1200 ATLASSERT(pdwBitmasks
== NULL
);
1205 // create a DIB section
1206 HDC hDC
= ::CreateCompatibleDC(NULL
);
1209 HBITMAP hbm
= ::CreateDIBSection(hDC
, bi
.get(), DIB_RGB_COLORS
,
1215 AttachInternal(hbm
, eOrientation
, -1);
1216 m_bHasAlphaCh
= bHasAlphaCh
;
1222 // NOTE: CImage is not copyable
1223 CImage(const CImage
&);
1224 CImage
& operator=(const CImage
&);
1231 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE
1232 using namespace ATL
;
1233 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE