From: Mark Jansen Date: Thu, 18 Aug 2016 19:27:49 +0000 (+0000) Subject: [ATL][ATL_APITEST] Add CImage initial implementation + tests, by Katayama Hirofumi... X-Git-Tag: backups/sndblst@72664~287 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=6db0c12e8521e590c95c60d48f437d80ff1c62f2 [ATL][ATL_APITEST] Add CImage initial implementation + tests, by Katayama Hirofumi MZ. CORE-10029 #comment Thanks, first iteration committed! - Tests focus mainly on loading + saving images. - The implementation is not perfect yet, see CImage_WIP.txt for test results. - The GDI+ functions should be fixed before this test can pass fully, MS' ATL fails in ReactOS, but passes on Windows. svn path=/trunk/; revision=72332 --- diff --git a/reactos/sdk/lib/atl/atlcom.h b/reactos/sdk/lib/atl/atlcom.h index 98d0ca08a88..57121ff3973 100644 --- a/reactos/sdk/lib/atl/atlcom.h +++ b/reactos/sdk/lib/atl/atlcom.h @@ -21,6 +21,8 @@ #pragma once +#include // for GUID_NULL + namespace ATL { diff --git a/reactos/sdk/lib/atl/atlimage.h b/reactos/sdk/lib/atl/atlimage.h new file mode 100644 index 00000000000..d964805012d --- /dev/null +++ b/reactos/sdk/lib/atl/atlimage.h @@ -0,0 +1,1142 @@ +// PROJECT: ReactOS ATL CImage +// LICENSE: Public Domain +// PURPOSE: Provides compatibility to Microsoft ATL +// PROGRAMMERS: Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + +#ifndef __ATLIMAGE_H__ +#define __ATLIMAGE_H__ + +// !!!! +// TODO: The backend (gdi+) that this class relies on is not yet complete! +// Before that is finished, this class will not be a perfect replacement. +// See rostest/apitests/atl/CImage_WIP.txt for test results. +// !!!! + +// TODO: GetImporterFilterString, GetExporterFilterString, Load, Save +// TODO: make CImage thread-safe + +#pragma once + +#include + +#include +#include // for GUID_NULL +#include // GDI+ + +namespace ATL +{ + +class CImage +{ +public: + // flags for CImage::Create/CreateEx + enum + { + createAlphaChannel = 1 // enable alpha + }; + + // orientation of DIB + enum DIBOrientation + { + DIBOR_DEFAULT, // default + DIBOR_BOTTOMUP, // bottom-up DIB + DIBOR_TOPDOWN // top-down DIB + }; + + CImage() throw() + { + m_hbm = NULL; + m_hbmOld = NULL; + m_hDC = NULL; + + m_eOrientation = DIBOR_DEFAULT; + m_bHasAlphaCh = false; + m_bIsDIBSec = false; + m_rgbTransColor = CLR_INVALID; + ZeroMemory(&m_ds, sizeof(m_ds)); + + if (GetCommon().AddRef() == 1) + { + GetCommon().LoadLib(); + } + } + + ~CImage() + { + Destroy(); + ReleaseGDIPlus(); + } + + operator HBITMAP() + { + return m_hbm; + } + +public: + void Attach(HBITMAP hBitmap, DIBOrientation eOrientation = DIBOR_DEFAULT) + { + AttachInternal(hBitmap, eOrientation, -1); + } + + HBITMAP Detach() throw() + { + m_eOrientation = DIBOR_DEFAULT; + m_bHasAlphaCh = false; + m_rgbTransColor = CLR_INVALID; + ZeroMemory(&m_ds, sizeof(m_ds)); + + HBITMAP hBitmap = m_hbm; + m_hbm = NULL; + return hBitmap; + } + + HDC GetDC() const throw() + { + if (m_hDC) + return m_hDC; + + m_hDC = ::CreateCompatibleDC(NULL); + m_hbmOld = ::SelectObject(m_hDC, m_hbm); + return m_hDC; + } + + void ReleaseDC() const throw() + { + ATLASSERT(m_hDC); + + if (m_hDC == NULL) + return; + + if (m_hbmOld) + { + ::SelectObject(m_hDC, m_hbmOld); + m_hbmOld = NULL; + } + ::DeleteDC(m_hDC); + m_hDC = NULL; + } + +public: + BOOL AlphaBlend(HDC hDestDC, + int xDest, int yDest, int nDestWidth, int nDestHeight, + int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, + BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const + { + ATLASSERT(IsTransparencySupported()); + + BLENDFUNCTION bf; + bf.BlendOp = bBlendOp; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = bSrcAlpha; + bf.AlphaFormat = AC_SRC_ALPHA; + + GetDC(); + BOOL ret = ::AlphaBlend(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf); + ReleaseDC(); + return ret; + } + BOOL AlphaBlend(HDC hDestDC, int xDest, int yDest, + BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const + { + int width = GetWidth(); + int height = GetHeight(); + return AlphaBlend(hDestDC, xDest, yDest, width, height, 0, 0, + width, height, bSrcAlpha, bBlendOp); + } + BOOL AlphaBlend(HDC hDestDC, const POINT& pointDest, + BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const + { + return AlphaBlend(hDestDC, pointDest.x, pointDest.y, bSrcAlpha, bBlendOp); + } + BOOL AlphaBlend(HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, + BYTE bSrcAlpha = 0xFF, BYTE bBlendOp = AC_SRC_OVER) const + { + return AlphaBlend(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top, + rectSrc.left, rectSrc.top, + rectSrc.right - rectSrc.left, + rectSrc.bottom - rectSrc.top, + bSrcAlpha, bBlendOp); + } + + BOOL BitBlt(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight, + int xSrc, int ySrc, DWORD dwROP = SRCCOPY) const throw() + { + GetDC(); + BOOL ret = ::BitBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + m_hDC, xSrc, ySrc, dwROP); + ReleaseDC(); + return ret; + } + BOOL BitBlt(HDC hDestDC, int xDest, int yDest, + DWORD dwROP = SRCCOPY) const throw() + { + return BitBlt(hDestDC, xDest, yDest, + GetWidth(), GetHeight(), 0, 0, dwROP); + } + BOOL BitBlt(HDC hDestDC, const POINT& pointDest, + DWORD dwROP = SRCCOPY) const throw() + { + return BitBlt(hDestDC, pointDest.x, pointDest.y, dwROP); + } + BOOL BitBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, + DWORD dwROP = SRCCOPY) const throw() + { + return BitBlt(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top, + pointSrc.x, pointSrc.y, dwROP); + } + + BOOL Create(int nWidth, int nHeight, int nBPP, DWORD dwFlags = 0) throw() + { + return CreateEx(nWidth, nHeight, nBPP, BI_RGB, NULL, dwFlags); + } + + BOOL CreateEx(int nWidth, int nHeight, int nBPP, DWORD eCompression, + const DWORD* pdwBitmasks = NULL, DWORD dwFlags = 0) throw() + { + return CreateInternal(nWidth, nHeight, nBPP, eCompression, pdwBitmasks, dwFlags); + } + + void Destroy() throw() + { + if (m_hbm) + { + ::DeleteObject(Detach()); + } + } + + BOOL Draw(HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, + int xSrc, int ySrc, int nSrcWidth, int nSrcHeight) const throw() + { + ATLASSERT(IsTransparencySupported()); + if (m_bHasAlphaCh) + { + return AlphaBlend(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + xSrc, ySrc, nSrcWidth, nSrcHeight); + } + else if (m_rgbTransColor != CLR_INVALID) + { + COLORREF rgb; + if ((m_rgbTransColor & 0xFF000000) == 0x01000000) + rgb = RGBFromPaletteIndex(m_rgbTransColor & 0xFF); + else + rgb = m_rgbTransColor; + return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + xSrc, ySrc, nSrcWidth, nSrcHeight, rgb); + } + else + { + return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + xSrc, ySrc, nSrcWidth, nSrcHeight); + } + } + BOOL Draw(HDC hDestDC, const RECT& rectDest, const RECT& rectSrc) const throw() + { + return Draw(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top, + rectSrc.left, rectSrc.top, + rectSrc.right - rectSrc.left, + rectSrc.bottom - rectSrc.top); + } + BOOL Draw(HDC hDestDC, int xDest, int yDest) const throw() + { + return Draw(hDestDC, xDest, yDest, GetWidth(), GetHeight()); + } + BOOL Draw(HDC hDestDC, const POINT& pointDest) const throw() + { + return Draw(hDestDC, pointDest.x, pointDest.y); + } + BOOL Draw(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight) const throw() + { + return Draw(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + 0, 0, GetWidth(), GetHeight()); + } + BOOL Draw(HDC hDestDC, const RECT& rectDest) const throw() + { + return Draw(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top); + } + + void *GetBits() throw() + { + ATLASSERT(IsDIBSection()); + BYTE *pb = (BYTE *)m_bm.bmBits; + if (m_eOrientation == DIBOR_BOTTOMUP) + { + pb += m_bm.bmWidthBytes * (m_bm.bmHeight - 1); + } + return pb; + } + + int GetBPP() const throw() + { + ATLASSERT(m_hbm); + return m_bm.bmBitsPixel; + } + + void GetColorTable(UINT iFirstColor, UINT nColors, + RGBQUAD* prgbColors) const throw() + { + ATLASSERT(IsDIBSection()); + GetDC(); + ::GetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors); + ReleaseDC(); + } + + int GetHeight() const throw() + { + ATLASSERT(m_hbm); + return m_bm.bmHeight; + } + + int GetMaxColorTableEntries() const throw() + { + ATLASSERT(IsDIBSection()); + if (m_ds.dsBmih.biClrUsed && m_ds.dsBmih.biBitCount < 16) + return m_ds.dsBmih.biClrUsed; + switch (m_bm.bmBitsPixel) + { + case 1: return 2; + case 4: return 16; + case 8: return 256; + case 16: case 32: + if (m_ds.dsBmih.biCompression == BI_BITFIELDS) + return 3; + return 0; + case 24: + default: + return 0; + } + } + + int GetPitch() const throw() + { + ATLASSERT(IsDIBSection()); + if (m_eOrientation == DIBOR_BOTTOMUP) + return -m_bm.bmWidthBytes; + else + return m_bm.bmWidthBytes; + } + + COLORREF GetPixel(int x, int y) const throw() + { + GetDC(); + COLORREF ret = ::GetPixel(m_hDC, x, y); + ReleaseDC(); + return ret; + } + + void* GetPixelAddress(int x, int y) throw() + { + ATLASSERT(IsDIBSection()); + BYTE *pb = (BYTE *)GetBits(); + pb += GetPitch() * y; + pb += (GetBPP() * x) / 8; + return pb; + } + + COLORREF GetTransparentColor() const throw() + { + return m_rgbTransColor; + } + + int GetWidth() const throw() + { + ATLASSERT(m_hbm); + return m_bm.bmWidth; + } + + bool IsDIBSection() const throw() + { + ATLASSERT(m_hbm); + return m_bIsDIBSec; + } + + bool IsIndexed() const throw() + { + ATLASSERT(IsDIBSection()); + return GetBPP() <= 8; + } + + bool IsNull() const throw() + { + return m_hbm == NULL; + } + + HRESULT Load(LPCTSTR pszFileName) throw() + { + // convert the file name string into Unicode + // TODO: use a string class +#ifdef UNICODE + LPCWSTR pszNameW = pszFileName; +#else + WCHAR szPath[MAX_PATH]; + ::MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szPath, MAX_PATH); + LPCWSTR pszNameW = szPath; +#endif + + // create a GpBitmap object from file + using namespace Gdiplus; + GpBitmap *pBitmap = NULL; + GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap); + ATLASSERT(pBitmap); + + // TODO & FIXME: get parameters (m_rgbTransColor etc.) + + // get bitmap handle + HBITMAP hbm = NULL; + Color color(0xFF, 0xFF, 0xFF); + Gdiplus::Status status; + status = GetCommon().CreateHBITMAPFromBitmap( + pBitmap, &hbm, color.GetValue()); + + // delete GpBitmap + GetCommon().DisposeImage(pBitmap); + + // attach it + if (status == Ok) + Attach(hbm); + return (status == Ok ? S_OK : E_FAIL); + } + HRESULT Load(IStream* pStream) throw() + { + // create GpBitmap from stream + using namespace Gdiplus; + GpBitmap *pBitmap = NULL; + GetCommon().CreateBitmapFromStream(pStream, &pBitmap); + ATLASSERT(pBitmap); + + // TODO & FIXME: get parameters (m_rgbTransColor etc.) + + // get bitmap handle + HBITMAP hbm = NULL; + Color color(0xFF, 0xFF, 0xFF); + Gdiplus::Status status; + status = GetCommon().CreateHBITMAPFromBitmap( + pBitmap, &hbm, color.GetValue()); + + // delete Bitmap + GetCommon().DisposeImage(pBitmap); + + // attach it + if (status == Ok) + Attach(hbm); + return (status == Ok ? S_OK : E_FAIL); + } + + // NOTE: LoadFromResource loads BITMAP resource only + void LoadFromResource(HINSTANCE hInstance, LPCTSTR pszResourceName) throw() + { + HANDLE hHandle = ::LoadImage(hInstance, pszResourceName, + IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); + Attach(reinterpret_cast(hHandle)); + } + void LoadFromResource(HINSTANCE hInstance, UINT nIDResource) throw() + { + LoadFromResource(hInstance, MAKEINTRESOURCE(nIDResource)); + } + + BOOL MaskBlt(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight, int xSrc, int ySrc, + HBITMAP hbmMask, int xMask, int yMask, + DWORD dwROP = SRCCOPY) const throw() + { + ATLASSERT(IsTransparencySupported()); + GetDC(); + BOOL ret = ::MaskBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + m_hDC, xSrc, ySrc, + hbmMask, xMask, yMask, dwROP); + ReleaseDC(); + return ret; + } + BOOL MaskBlt(HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, + HBITMAP hbmMask, const POINT& pointMask, + DWORD dwROP = SRCCOPY) const throw() + { + return MaskBlt(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, rectDest.bottom - rectDest.top, + pointSrc.x, pointSrc.y, hbmMask, pointMask.x, pointMask.y, dwROP); + } + BOOL MaskBlt(HDC hDestDC, int xDest, int yDest, + HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw() + { + return MaskBlt(hDestDC, xDest, yDest, GetWidth(), GetHeight(), + 0, 0, hbmMask, 0, 0, dwROP); + } + BOOL MaskBlt(HDC hDestDC, const POINT& pointDest, + HBITMAP hbmMask, DWORD dwROP = SRCCOPY) const throw() + { + return MaskBlt(hDestDC, pointDest.x, pointDest.y, hbmMask, dwROP); + } + + BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, + int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, + HBITMAP hbmMask = NULL, + int xMask = 0, int yMask = 0) const throw() + { + ATLASSERT(IsTransparencySupported()); + GetDC(); + BOOL ret = ::PlgBlt(hDestDC, pPoints, m_hDC, + xSrc, ySrc, nSrcWidth, nSrcHeight, + hbmMask, xMask, yMask); + ReleaseDC(); + return ret; + } + BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, + HBITMAP hbmMask = NULL) const throw() + { + return PlgBlt(hDestDC, pPoints, 0, 0, GetWidth(), GetHeight(), + hbmMask); + } + BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, + HBITMAP hbmMask, const POINT& pointMask) const throw() + { + return PlgBlt(hDestDC, pPoints, rectSrc.left, rectSrc.top, + rectSrc.right - rectSrc.left, rectSrc.bottom - rectSrc.top, + hbmMask, pointMask.x, pointMask.y); + } + BOOL PlgBlt(HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, + HBITMAP hbmMask = NULL) const throw() + { + POINT pointMask = {0, 0}; + return PlgBlt(hDestDC, pPoints, rectSrc, hbmMask, pointMask); + } + + void ReleaseGDIPlus() throw() + { + COMMON*& pCommon = GetCommonPtr(); + if (pCommon && pCommon->Release() == 0) + { + delete pCommon; + pCommon = NULL; + } + } + + HRESULT Save(IStream* pStream, GUID *guidFileType) const throw() + { + using namespace Gdiplus; + ATLASSERT(m_hbm); + + // TODO & FIXME: set parameters (m_rgbTransColor etc.) + CLSID clsid; + if (!GetClsidFromFileType(&clsid, guidFileType)) + return E_FAIL; + + // create a GpBitmap from HBITMAP + GpBitmap *pBitmap = NULL; + GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); + + // save to stream + Status status; + status = GetCommon().SaveImageToStream(pBitmap, pStream, &clsid, NULL); + + // destroy GpBitmap + GetCommon().DisposeImage(pBitmap); + + return (status == Ok ? S_OK : E_FAIL); + } + HRESULT Save(LPCTSTR pszFileName, + REFGUID guidFileType = GUID_NULL) const throw() + { + using namespace Gdiplus; + ATLASSERT(m_hbm); + + // TODO & FIXME: set parameters (m_rgbTransColor etc.) + + // convert the file name string into Unicode + // TODO: use a string class +#ifdef UNICODE + LPCWSTR pszNameW = pszFileName; +#else + WCHAR szPath[MAX_PATH]; + ::MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, szPath, MAX_PATH); + LPCWSTR pszNameW = szPath; +#endif + + // if the file type is null, get the file type from extension + const GUID *FileType = &guidFileType; + if (IsGuidEqual(guidFileType, GUID_NULL)) + { + LPCWSTR pszExt = GetFileExtension(pszNameW); + FileType = FileTypeFromExtension(pszExt); + } + + // get CLSID from file type + CLSID clsid; + if (!GetClsidFromFileType(&clsid, FileType)) + return E_FAIL; + + // create a GpBitmap from HBITMAP + GpBitmap *pBitmap = NULL; + GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); + + // save to file + Status status; + status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL); + + // destroy GpBitmap + GetCommon().DisposeImage(pBitmap); + + return (status == Ok ? S_OK : E_FAIL); + } + + void SetColorTable(UINT iFirstColor, UINT nColors, + const RGBQUAD* prgbColors) throw() + { + ATLASSERT(IsDIBSection()); + GetDC(); + ::SetDIBColorTable(m_hDC, iFirstColor, nColors, prgbColors); + ReleaseDC(); + } + + void SetPixel(int x, int y, COLORREF color) throw() + { + GetDC(); + ::SetPixelV(m_hDC, x, y, color); + ReleaseDC(); + } + + void SetPixelIndexed(int x, int y, int iIndex) throw() + { + ATLASSERT(IsIndexed()); + GetDC(); + ::SetPixelV(m_hDC, x, y, PALETTEINDEX(iIndex)); + ReleaseDC(); + } + + void SetPixelRGB(int x, int y, BYTE r, BYTE g, BYTE b) throw() + { + SetPixel(x, y, RGB(r, g, b)); + } + + COLORREF SetTransparentColor(COLORREF rgbTransparent) throw() + { + ATLASSERT(m_hbm); + COLORREF rgbOldColor = m_rgbTransColor; + m_rgbTransColor = rgbTransparent; + return rgbOldColor; + } + + BOOL StretchBlt(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight, + int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, + DWORD dwROP = SRCCOPY) const throw() + { + GetDC(); + BOOL ret = ::StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwROP); + ReleaseDC(); + return ret; + } + BOOL StretchBlt(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight, + DWORD dwROP = SRCCOPY) const throw() + { + return StretchBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + 0, 0, GetWidth(), GetHeight(), dwROP); + } + BOOL StretchBlt(HDC hDestDC, const RECT& rectDest, + DWORD dwROP = SRCCOPY) const throw() + { + return StretchBlt(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top, dwROP); + } + BOOL StretchBlt(HDC hDestDC, const RECT& rectDest, + const RECT& rectSrc, DWORD dwROP = SRCCOPY) const throw() + { + return StretchBlt(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top, + rectSrc.left, rectSrc.top, + rectSrc.right - rectSrc.left, + rectSrc.bottom - rectSrc.top, dwROP); + } + + BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight, + int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, + UINT crTransparent = CLR_INVALID) const throw() + { + ATLASSERT(IsTransparencySupported()); + GetDC(); + BOOL ret = ::TransparentBlt(hDestDC, xDest, yDest, + nDestWidth, nDestHeight, + m_hDC, xSrc, ySrc, + nSrcWidth, nSrcHeight, crTransparent); + ReleaseDC(); + return ret; + } + BOOL TransparentBlt(HDC hDestDC, int xDest, int yDest, + int nDestWidth, int nDestHeight, + UINT crTransparent = CLR_INVALID) const throw() + { + return TransparentBlt(hDestDC, xDest, yDest, nDestWidth, nDestHeight, + 0, 0, GetWidth(), GetHeight(), crTransparent); + } + BOOL TransparentBlt(HDC hDestDC, const RECT& rectDest, + UINT crTransparent = CLR_INVALID) const throw() + { + return TransparentBlt(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, + rectDest.bottom - rectDest.top, crTransparent); + } + BOOL TransparentBlt( + HDC hDestDC, const RECT& rectDest, + const RECT& rectSrc, UINT crTransparent = CLR_INVALID) const throw() + { + return TransparentBlt(hDestDC, rectDest.left, rectDest.top, + rectDest.right - rectDest.left, rectDest.bottom - rectDest.left, + rectSrc.left, rectSrc.top, rectSrc.right - rectSrc.left, + rectSrc.bottom - rectSrc.top, crTransparent); + } + +public: + static BOOL IsTransparencySupported() throw() + { + return TRUE; + } + +#if 0 + // TODO: implement this + static HRESULT GetImporterFilterString( + CSimpleString& strImporters, + CSimpleArray& aguidFileTypes, + LPCTSTR pszAllFilesDescription = NULL, + DWORD dwExclude = excludeDefaultLoad, + TCHAR chSeparator = _T('|')) + { + ATLASSERT(0); + return -1; + } + + // TODO: implement this + static HRESULT GetExporterFilterString( + CSimpleString& strExporters, + CSimpleArray& aguidFileTypes, + LPCTSTR pszAllFilesDescription = NULL, + DWORD dwExclude = excludeDefaultSave, + TCHAR chSeparator = _T('|')) + { + ATLASSERT(0); + return -1; + } +#endif // 0 + +protected: + // an extension of BITMAPINFO + struct MYBITMAPINFOEX + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; + BITMAPINFO *get() + { + return reinterpret_cast(this); + } + const BITMAPINFO *get() const + { + return reinterpret_cast(this); + } + }; + + // The common data of atlimage + struct COMMON + { + // abbreviations of GDI+ basic types + typedef Gdiplus::GpStatus St; + typedef Gdiplus::ImageCodecInfo ICI; + typedef Gdiplus::GpBitmap Bm; + typedef Gdiplus::EncoderParameters EncParams; + typedef Gdiplus::GpImage Im; + typedef Gdiplus::ARGB ARGB; + typedef HBITMAP HBM; + typedef Gdiplus::GdiplusStartupInput GSI; + typedef Gdiplus::GdiplusStartupOutput GSO; + + // GDI+ function types +#undef API +#undef CST +#define API WINGDIPAPI +#define CST GDIPCONST + typedef St (WINAPI *STARTUP)(ULONG_PTR *, const GSI *, GSO *); + typedef void (WINAPI *SHUTDOWN)(ULONG_PTR); + typedef St (API *GETIMAGEENCODERSSIZE)(UINT *, UINT *); + typedef St (API *GETIMAGEENCODERS)(UINT, UINT, ICI *); + typedef St (API *CREATEBITMAPFROMFILE)(CST WCHAR*, Bm **); + typedef St (API *CREATEHBITMAPFROMBITMAP)(Bm *, HBM *, ARGB); + typedef St (API *CREATEBITMAPFROMSTREAM)(IStream *, Bm **); + typedef St (API *CREATEBITMAPFROMHBITMAP)(HBM, HPALETTE, Bm **); + typedef St (API *SAVEIMAGETOSTREAM)(Im *, IStream *, CST CLSID *, + CST EncParams *); + typedef St (API *SAVEIMAGETOFILE)(Im *, CST WCHAR *, CST CLSID *, + CST EncParams *); + typedef St (API *DISPOSEIMAGE)(Im*); +#undef API +#undef CST + + // members + int count; + HINSTANCE hinstGdiPlus; + ULONG_PTR gdiplusToken; + + // GDI+ functions + STARTUP Startup; + SHUTDOWN Shutdown; + GETIMAGEENCODERSSIZE GetImageEncodersSize; + GETIMAGEENCODERS GetImageEncoders; + CREATEBITMAPFROMFILE CreateBitmapFromFile; + CREATEHBITMAPFROMBITMAP CreateHBITMAPFromBitmap; + CREATEBITMAPFROMSTREAM CreateBitmapFromStream; + CREATEBITMAPFROMHBITMAP CreateBitmapFromHBITMAP; + SAVEIMAGETOSTREAM SaveImageToStream; + SAVEIMAGETOFILE SaveImageToFile; + DISPOSEIMAGE DisposeImage; + + COMMON() + { + count = 0; + hinstGdiPlus = NULL; + Startup = NULL; + Shutdown = NULL; + GetImageEncodersSize = NULL; + GetImageEncoders = NULL; + CreateBitmapFromFile = NULL; + CreateHBITMAPFromBitmap = NULL; + CreateBitmapFromStream = NULL; + CreateBitmapFromHBITMAP = NULL; + SaveImageToStream = NULL; + SaveImageToFile = NULL; + DisposeImage = NULL; + } + ~COMMON() + { + FreeLib(); + } + + ULONG AddRef() + { + return ++count; + } + ULONG Release() + { + return --count; + } + + // get procedure address of the DLL + template + TYPE AddrOf(const char *name) + { + FARPROC proc = ::GetProcAddress(hinstGdiPlus, name); + return reinterpret_cast(proc); + } + + HINSTANCE LoadLib() + { + if (hinstGdiPlus) + return hinstGdiPlus; + + hinstGdiPlus = ::LoadLibraryA("gdiplus.dll"); + + // get procedure addresses from the DLL + Startup = AddrOf("GdiplusStartup"); + Shutdown = AddrOf("GdiplusShutdown"); + GetImageEncodersSize = + AddrOf("GdipGetImageEncodersSize"); + GetImageEncoders = AddrOf("GdipGetImageEncoders"); + CreateBitmapFromFile = + AddrOf("GdipCreateBitmapFromFile"); + CreateHBITMAPFromBitmap = + AddrOf("GdipCreateHBITMAPFromBitmap"); + CreateBitmapFromStream = + AddrOf("GdipCreateBitmapFromStream"); + CreateBitmapFromHBITMAP = + AddrOf("GdipCreateBitmapFromHBITMAP"); + SaveImageToStream = + AddrOf("GdipSaveImageToStream"); + SaveImageToFile = AddrOf("GdipSaveImageToFile"); + DisposeImage = AddrOf("GdipDisposeImage"); + + if (hinstGdiPlus && Startup) + { + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + Startup(&gdiplusToken, &gdiplusStartupInput, NULL); + } + + return hinstGdiPlus; + } + void FreeLib() + { + if (hinstGdiPlus) + { + Shutdown(gdiplusToken); + + Startup = NULL; + Shutdown = NULL; + GetImageEncodersSize = NULL; + GetImageEncoders = NULL; + CreateBitmapFromFile = NULL; + CreateHBITMAPFromBitmap = NULL; + CreateBitmapFromStream = NULL; + CreateBitmapFromHBITMAP = NULL; + SaveImageToStream = NULL; + SaveImageToFile = NULL; + DisposeImage = NULL; + ::FreeLibrary(hinstGdiPlus); + hinstGdiPlus = NULL; + } + } + }; // struct COMMON + + static COMMON*& GetCommonPtr() + { + static COMMON *s_pCommon = NULL; + return s_pCommon; + } + + static COMMON& GetCommon() + { + COMMON*& pCommon = GetCommonPtr(); + if (pCommon == NULL) + pCommon = new COMMON; + return *pCommon; + } + +protected: + HBITMAP m_hbm; + mutable HGDIOBJ m_hbmOld; + mutable HDC m_hDC; + DIBOrientation m_eOrientation; + bool m_bHasAlphaCh; + bool m_bIsDIBSec; + COLORREF m_rgbTransColor; + union + { + BITMAP m_bm; + DIBSECTION m_ds; + }; + + LPCWSTR GetFileExtension(LPCWSTR pszFileName) const + { + LPCWSTR pch = wcsrchr(pszFileName, L'\\'); + if (pch == NULL) + pch = wcsrchr(pszFileName, L'/'); + pch = (pch ? wcsrchr(pch, L'.') : wcsrchr(pszFileName, L'.')); + return (pch ? pch : (pszFileName + ::lstrlenW(pszFileName))); + } + + COLORREF RGBFromPaletteIndex(int iIndex) const + { + RGBQUAD table[256]; + GetColorTable(0, 256, table); + RGBQUAD& quad = table[iIndex]; + return RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue); + } + + struct EXTENSION_ENTRY + { + LPCWSTR pszExt; + GUID guid; + }; + + const GUID *FileTypeFromExtension(LPCWSTR pszExt) const + { + static const EXTENSION_ENTRY table[] = + { + {L".jpg", Gdiplus::ImageFormatJPEG}, + {L".png", Gdiplus::ImageFormatPNG}, + {L".bmp", Gdiplus::ImageFormatBMP}, + {L".gif", Gdiplus::ImageFormatGIF}, + {L".tif", Gdiplus::ImageFormatTIFF}, + {L".jpeg", Gdiplus::ImageFormatJPEG}, + {L".jpe", Gdiplus::ImageFormatJPEG}, + {L".jfif", Gdiplus::ImageFormatJPEG}, + {L".dib", Gdiplus::ImageFormatBMP}, + {L".rle", Gdiplus::ImageFormatBMP}, + {L".tiff", Gdiplus::ImageFormatTIFF} + }; + const size_t count = _countof(table); + for (size_t i = 0; i < count; ++i) + { + if (::lstrcmpiW(table[i].pszExt, pszExt) == 0) + return &table[i].guid; + } + return NULL; + } + + struct FORMAT_ENTRY + { + GUID guid; + LPCWSTR mime; + }; + + bool GetClsidFromFileType(CLSID *clsid, const GUID *guid) const + { + static const FORMAT_ENTRY table[] = + { + {Gdiplus::ImageFormatJPEG, L"image/jpeg"}, + {Gdiplus::ImageFormatPNG, L"image/png"}, + {Gdiplus::ImageFormatBMP, L"image/bmp"}, + {Gdiplus::ImageFormatGIF, L"image/gif"}, + {Gdiplus::ImageFormatTIFF, L"image/tiff"} + }; + const size_t count = _countof(table); + for (size_t i = 0; i < count; ++i) + { + if (IsGuidEqual(table[i].guid, *guid)) + { + int num = GetEncoderClsid(table[i].mime, clsid); + if (num >= 0) + { + return true; + } + } + } + return false; + } + + int GetEncoderClsid(LPCWSTR mime, CLSID *clsid) const + { + UINT count = 0, total_size = 0; + GetCommon().GetImageEncodersSize(&count, &total_size); + if (total_size == 0) + return -1; // failure + + Gdiplus::ImageCodecInfo *pInfo; + BYTE *pb = new BYTE[total_size]; + ATLASSERT(pb); + pInfo = reinterpret_cast(pb); + if (pInfo == NULL) + return -1; // failure + + GetCommon().GetImageEncoders(count, total_size, pInfo); + + for (UINT iInfo = 0; iInfo < count; ++iInfo) + { + if (::lstrcmpiW(pInfo[iInfo].MimeType, mime) == 0) + { + *clsid = pInfo[iInfo].Clsid; + delete[] pb; + return iInfo; // success + } + } + + delete[] pb; + return -1; // failure + } + + bool IsGuidEqual(const GUID& guid1, const GUID& guid2) const + { + RPC_STATUS status; + if (::UuidEqual(const_cast(&guid1), + const_cast(&guid2), &status)) + { + if (status == RPC_S_OK) + return true; + } + return false; + } + + void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation, + LONG iTransColor) + { + Destroy(); + + const int size = sizeof(DIBSECTION); + m_bIsDIBSec = (::GetObject(hBitmap, size, &m_ds) == size); + + bool bOK = (::GetObject(hBitmap, sizeof(BITMAP), &m_bm) != 0); + + if (bOK) + { + m_hbm = hBitmap; + m_eOrientation = eOrientation; + m_bHasAlphaCh = (m_bm.bmBitsPixel == 32); + m_rgbTransColor = CLR_INVALID; + } + } + + BOOL CreateInternal(int nWidth, int nHeight, int nBPP, + DWORD eCompression, const DWORD* pdwBitmasks = NULL, + DWORD dwFlags = 0) throw() + { + ATLASSERT(nWidth != 0); + ATLASSERT(nHeight != 0); + + // initialize BITMAPINFO extension + MYBITMAPINFOEX bi; + ZeroMemory(&bi, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = nWidth; + bi.bmiHeader.biHeight = nHeight; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = nBPP; + bi.bmiHeader.biCompression = eCompression; + + // is there alpha channel? + bool bHasAlphaCh; + bHasAlphaCh = (nBPP == 32 && (dwFlags & createAlphaChannel)); + + // get orientation + DIBOrientation eOrientation; + eOrientation = ((nHeight > 0) ? DIBOR_BOTTOMUP : DIBOR_TOPDOWN); + + // does it have bit fields? + if (eCompression == BI_BITFIELDS) + { + if (nBPP == 16 || nBPP == 32) + { + // store the mask data + LPDWORD pdwMask = reinterpret_cast(bi.bmiColors); + pdwMask[0] = pdwBitmasks[0]; + pdwMask[1] = pdwBitmasks[1]; + pdwMask[2] = pdwBitmasks[2]; + } + else + { + return FALSE; + } + } + else + { + ATLASSERT(pdwBitmasks == NULL); + if (pdwBitmasks) + return FALSE; + } + + // create a DIB section + HDC hDC = ::CreateCompatibleDC(NULL); + ATLASSERT(hDC); + LPVOID pvBits; + HBITMAP hbm = ::CreateDIBSection(hDC, bi.get(), DIB_RGB_COLORS, + &pvBits, NULL, 0); + ATLASSERT(hbm); + ::DeleteDC(hDC); + + // attach it + AttachInternal(hbm, eOrientation, -1); + m_bHasAlphaCh = bHasAlphaCh; + + return hbm != NULL; + } + +private: + // NOTE: CImage is not copyable + CImage(const CImage&); + CImage& operator=(const CImage&); +}; + +} + +#endif + +#ifndef _ATL_NO_AUTOMATIC_NAMESPACE +using namespace ATL; +#endif //!_ATL_NO_AUTOMATIC_NAMESPACE diff --git a/rostests/apitests/atl/CImage.cpp b/rostests/apitests/atl/CImage.cpp new file mode 100644 index 00000000000..d294aa2ee45 --- /dev/null +++ b/rostests/apitests/atl/CImage.cpp @@ -0,0 +1,278 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory + * PURPOSE: Test for CImage + * PROGRAMMER: Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include +#include "resource.h" + +#ifdef __REACTOS__ + #include +#else + #include + #include + #include + const char *g_file = NULL; + int g_line = 0; + int g_tests_executed = 0; + int g_tests_failed = 0; + void ok_func(BOOL value, const char *fmt, ...) + { + va_list va; + va_start(va, fmt); + if (!value) + { + printf("%s (%d): ", g_file, g_line); + vprintf(fmt, va); + g_tests_failed++; + } + g_tests_executed++; + va_end(va); + } + #undef ok + #define ok g_file = __FILE__; g_line = __LINE__; ok_func + #define START_TEST(x) int main(void) +#endif + + +const TCHAR* szFiles[] = { + TEXT("ant.png"), + TEXT("ant.tif"), + TEXT("ant.gif"), + TEXT("ant.jpg"), + TEXT("ant.bmp"), +}; + +static TCHAR szTempPath[MAX_PATH]; +TCHAR* file_name(const TCHAR* file) +{ + static TCHAR buffer[MAX_PATH]; + lstrcpy(buffer, szTempPath); + lstrcat(buffer, TEXT("\\")); + lstrcat(buffer, file); + return buffer; +} + +static void write_bitmap(HINSTANCE hInst, int id, TCHAR* file) +{ + HRSRC rsrc; + + rsrc = FindResource(hInst, MAKEINTRESOURCE(id), MAKEINTRESOURCE(RT_BITMAP)); + ok(rsrc != NULL, "Expected to find an image resource\n"); + if (rsrc) + { + void *rsrc_data; + HANDLE hfile; + BOOL ret; + HGLOBAL glob = LoadResource(hInst, rsrc); + DWORD rsrc_size = SizeofResource(hInst, rsrc); + + rsrc_data = LockResource(glob); + + hfile = CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + ok(hfile != INVALID_HANDLE_VALUE, "Unable to open temp file: %lu\n", GetLastError()); + if (hfile != INVALID_HANDLE_VALUE) + { + BITMAPFILEHEADER bfh = { 0 }; + DWORD dwWritten; + + bfh.bfType = 'MB'; + bfh.bfSize = rsrc_size + sizeof(BITMAPFILEHEADER); + bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + bfh.bfReserved1 = bfh.bfReserved2 = 0; + ret = WriteFile(hfile, &bfh, sizeof(bfh), &dwWritten, NULL); + ok(ret, "Unable to write temp file: %lu\n", GetLastError()); + ret = WriteFile(hfile, rsrc_data, rsrc_size, &dwWritten, NULL); + ok(ret, "Unable to write temp file: %lu\n", GetLastError()); + CloseHandle(hfile); + } + UnlockResource(rsrc_data); + } +} + +typedef Gdiplus::GpStatus (WINAPI *STARTUP)(ULONG_PTR *, const Gdiplus::GdiplusStartupInput *, Gdiplus::GdiplusStartupOutput *); +typedef void (WINAPI *SHUTDOWN)(ULONG_PTR); +typedef Gdiplus::GpStatus (WINGDIPAPI *CREATEBITMAPFROMFILE)(GDIPCONST WCHAR*, Gdiplus::GpBitmap **); +typedef Gdiplus::GpStatus (WINGDIPAPI *GETPIXELFORMAT)(Gdiplus::GpImage *image, Gdiplus::PixelFormat *format); +typedef Gdiplus::GpStatus (WINGDIPAPI *DISPOSEIMAGE)(Gdiplus::GpImage *); + +static HINSTANCE hinstGdiPlus; +static ULONG_PTR gdiplusToken; + +static STARTUP Startup; +static SHUTDOWN Shutdown; +static CREATEBITMAPFROMFILE CreateBitmapFromFile; +static GETPIXELFORMAT GetImagePixelFormat; +static DISPOSEIMAGE DisposeImage; + +template +TYPE AddrOf(const char *name) +{ + FARPROC proc = ::GetProcAddress(hinstGdiPlus, name); + return reinterpret_cast(proc); +} + +static void init_gdip() +{ + hinstGdiPlus = ::LoadLibraryA("gdiplus.dll"); + Startup = AddrOf("GdiplusStartup"); + Shutdown = AddrOf("GdiplusShutdown"); + CreateBitmapFromFile = AddrOf("GdipCreateBitmapFromFile"); + GetImagePixelFormat = AddrOf("GdipGetImagePixelFormat"); + DisposeImage = AddrOf("GdipDisposeImage"); +} + + +static void determine_file_bpp(TCHAR* tfile, Gdiplus::PixelFormat expect_pf) +{ + using namespace Gdiplus; + GpBitmap *pBitmap = NULL; + +#ifdef UNICODE + WCHAR* file = tfile; +#else + WCHAR file[MAX_PATH]; + ::MultiByteToWideChar(CP_ACP, 0, tfile, -1, file, MAX_PATH); +#endif + + if (Startup == NULL) + init_gdip(); + + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + Startup(&gdiplusToken, &gdiplusStartupInput, NULL); + + + Gdiplus::GpStatus status = CreateBitmapFromFile(file, &pBitmap); + ok(status == Gdiplus::Ok, "Expected status to be %i, was: %i\n", (int)Gdiplus::Ok, (int)status); + ok(pBitmap != NULL, "Expected a valid bitmap\n"); + if (pBitmap) + { + PixelFormat pf; + GetImagePixelFormat(pBitmap, &pf); + ok(pf == expect_pf, "Expected PixelFormat to be 0x%x, was: 0x%x\n", (int)expect_pf, (int)pf); + + DisposeImage(pBitmap); + } + Shutdown(gdiplusToken); +} + + +START_TEST(CImage) +{ + HRESULT hr; + TCHAR* file; + BOOL bOK; + int width, height, bpp; + size_t n; + CImage image1, image2; + COLORREF color; + HDC hDC; + +#if 0 + width = image1.GetWidth(); + height = image1.GetHeight(); + bpp = image1.GetBPP(); +#endif + + HINSTANCE hInst = GetModuleHandle(NULL); + GetTempPath(MAX_PATH, szTempPath); + + image1.LoadFromResource(hInst, IDB_ANT); + ok(!image1.IsNull(), "Expected image1 is not null\n"); + + width = image1.GetWidth(); + ok(width == 48, "Expected width to be 48, was: %d\n", width); + height = image1.GetHeight(); + ok(height == 48, "Expected height to be 48, was: %d\n", height); + bpp = image1.GetBPP(); + ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp); + + + image2.LoadFromResource(hInst, IDB_CROSS); + ok(!image2.IsNull(), "Expected image2 is not null\n"); + image2.SetTransparentColor(RGB(255, 255, 255)); + + width = image2.GetWidth(); + ok(width == 32, "Expected width to be 32, was: %d\n", width); + height = image2.GetHeight(); + ok(height == 32, "Expected height to be 32, was: %d\n", height); + bpp = image2.GetBPP(); + ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp); + + color = image1.GetPixel(5, 5); + ok(color == RGB(166, 202, 240), "Expected color to be 166, 202, 240; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color)); + + hDC = image1.GetDC(); + bOK = image2.Draw(hDC, 0, 0); + image1.ReleaseDC(); + ok(bOK != FALSE, "Expected bDraw to be TRUE, was: %d\n", bOK); + image2.Destroy(); + + color = image1.GetPixel(5, 5); + ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color)); + + file = file_name(TEXT("ant.bmp")); + write_bitmap(hInst, IDB_ANT, file); + + init_gdip(); + + determine_file_bpp(file, PixelFormat8bppIndexed); + + hr = image2.Load(file); + ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx\n", hr); + ok(!image2.IsNull(), "Expected image1 is not null\n"); + bOK = DeleteFile(file); + ok(bOK, "Expected bOK to be TRUE, was: %d\n", bOK); + + width = image2.GetWidth(); + ok(width == 48, "Expected width to be 48, was: %d\n", width); + height = image2.GetHeight(); + ok(height == 48, "Expected height to be 48, was: %d\n", height); + bpp = image2.GetBPP(); + ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp); + + for (n = 0; n < _countof(szFiles); ++n) + { + file = file_name(szFiles[n]); + image2.Destroy(); + + if (n == 0) + hr = image1.Save(file, Gdiplus::ImageFormatPNG); + else + hr = image1.Save(file); + ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n); + + bOK = (GetFileAttributes(file) != 0xFFFFFFFF); + ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n); + + hr = image2.Load(file); + ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n); + + width = image2.GetWidth(); + ok(width == 48, "Expected width to be 48, was: %d (for %i)\n", width, n); + height = image2.GetHeight(); + ok(height == 48, "Expected height to be 48, was: %d (for %i)\n", height, n); + bpp = image2.GetBPP(); + if (n == 3) + { + ok(bpp == 24, "Expected bpp to be 24, was: %d (for %i)\n", bpp, n); + determine_file_bpp(file, PixelFormat24bppRGB); + } + else + { + ok(bpp == 8, "Expected bpp to be 8, was: %d (for %i)\n", bpp, n); + determine_file_bpp(file, PixelFormat8bppIndexed); + } + color = image1.GetPixel(5, 5); + ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i (for %i)\n", GetRValue(color), GetGValue(color), GetBValue(color), n); + + bOK = DeleteFile(file); + ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n); + } + +#ifndef __REACTOS__ + printf("CImage: %i tests executed (0 marked as todo, %i failures), 0 skipped.\n", g_tests_executed, g_tests_failed); +#endif +} diff --git a/rostests/apitests/atl/CImage_WIP.txt b/rostests/apitests/atl/CImage_WIP.txt new file mode 100644 index 00000000000..ea2671239b8 --- /dev/null +++ b/rostests/apitests/atl/CImage_WIP.txt @@ -0,0 +1,86 @@ +Test files: + +atl_apitest: CImage class from reactos +CImage.exe : CImage class from microsoft + +================================================================================================================ +Windows Server 2003 SP2: +================================================================================================================ +>atl_apitest.exe CImage +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(234): Test failed: Expected bpp to be 8, was: 32 +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 0) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 1) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 2) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(260): Test failed: Expected bpp to be 24, was: 32 (for 3) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 4) + +CImage: 79 tests executed (0 marked as todo, 6 failures), 0 skipped. +================================================================================================================ +>CImage.exe +CImage: 79 tests executed (0 marked as todo, 0 failures), 0 skipped. +================================================================================================================ +================================================================================================================ +Windows 10: +================================================================================================================ +>atl_apitest.exe CImage +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(234): Test failed: Expected bpp to be 8, was: 32 +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 0) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 1) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 2) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(260): Test failed: Expected bpp to be 24, was: 32 (for 3) +R:\src\trunk\reactos\modules\rostests\apitests\atl\CImage.cpp(265): Test failed: Expected bpp to be 8, was: 32 (for 4) + +CImage: 79 tests executed (0 marked as todo, 6 failures), 0 skipped. +================================================================================================================ +>CImage.exe +CImage: 79 tests executed (0 marked as todo, 0 failures), 0 skipped. +================================================================================================================ +================================================================================================================ +ReactOS: +================================================================================================================ +>atl_apitest.exe CImage +CImage.cpp:234: Test failed: Expected bpp to be 8, was: 32 +CImage.cpp:265: Test failed: Expected bpp to be 8, was: 32 (for 0) +CImage.cpp:245: Test failed: Expected hr to be S_OK, was: 80004005 (for 1) +CImage.cpp:251: Test failed: Expected hr to be S_OK, was: 80004005 (for 1) +CImage.cpp:254: Test failed: Expected width to be 48, was: 0 (for 1) +CImage.cpp:256: Test failed: Expected height to be 48, was: 0 (for 1) +CImage.cpp:265: Test failed: Expected bpp to be 8, was: 0 (for 1) +CImage.cpp:148: Test failed: Expected status to be 0, was: 1 +CImage.cpp:149: Test failed: Expected a valid bitmap +CImage.cpp:245: Test failed: Expected hr to be S_OK, was: 80004005 (for 2) +CImage.cpp:251: Test failed: Expected hr to be S_OK, was: 80004005 (for 2) +CImage.cpp:254: Test failed: Expected width to be 48, was: 0 (for 2) +CImage.cpp:256: Test failed: Expected height to be 48, was: 0 (for 2) +CImage.cpp:265: Test failed: Expected bpp to be 8, was: 0 (for 2) +CImage.cpp:148: Test failed: Expected status to be 0, was: 1 +CImage.cpp:149: Test failed: Expected a valid bitmap +CImage.cpp:260: Test failed: Expected bpp to be 24, was: 32 (for 3) +CImage.cpp:154: Test failed: Expected PixelFormat to be 0x21808, was: 0x30803 +CImage.cpp:265: Test failed: Expected bpp to be 8, was: 32 (for 4) +CImage.cpp:154: Test failed: Expected PixelFormat to be 0x30803, was: 0x21808 + +CImage: 77 tests executed (0 marked as todo, 20 failures), 0 skipped. +================================================================================================================ +>CImage.exe +../CImage.cpp (245): Expected hr to be S_OK, was: 80004005 (for 1) +../CImage.cpp (251): Expected hr to be S_OK, was: 80004005 (for 1) +../CImage.cpp (254): Expected width to be 48, was: 0 (for 1) +../CImage.cpp (256): Expected height to be 48, was: 0 (for 1) +../CImage.cpp (265): Expected bpp to be 8, was: 0 (for 1) +../CImage.cpp (148): Expected status to be 0, was: 1 +../CImage.cpp (149): Expected a valid bitmap +../CImage.cpp (245): Expected hr to be S_OK, was: 80004005 (for 2) +../CImage.cpp (251): Expected hr to be S_OK, was: 80004005 (for 2) +../CImage.cpp (254): Expected width to be 48, was: 0 (for 2) +../CImage.cpp (256): Expected height to be 48, was: 0 (for 2) +../CImage.cpp (265): Expected bpp to be 8, was: 0 (for 2) +../CImage.cpp (148): Expected status to be 0, was: 1 +../CImage.cpp (149): Expected a valid bitmap +../CImage.cpp (260): Expected bpp to be 24, was: 8 (for 3) +../CImage.cpp (154): Expected PixelFormat to be 0x21808, was: 0x30803 +../CImage.cpp (265): Expected bpp to be 8, was: 24 (for 4) +../CImage.cpp (154): Expected PixelFormat to be 0x30803, was: 0x21808 +CImage: 77 tests executed (0 marked as todo, 18 failures), 0 skipped. +================================================================================================================ + diff --git a/rostests/apitests/atl/CMakeLists.txt b/rostests/apitests/atl/CMakeLists.txt index ddb722993b8..ada8acd98c2 100644 --- a/rostests/apitests/atl/CMakeLists.txt +++ b/rostests/apitests/atl/CMakeLists.txt @@ -1,4 +1,5 @@ +add_definitions(-DINITGUID) set_cpp(WITH_RUNTIME WITH_EXCEPTIONS) include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl) @@ -7,6 +8,7 @@ add_executable(atl_apitest atltypes.cpp CComBSTR.cpp CComHeapPtr.cpp + CImage.cpp CRegKey.cpp CString.cpp testlist.c @@ -14,5 +16,5 @@ add_executable(atl_apitest target_link_libraries(atl_apitest wine uuid) set_module_type(atl_apitest win32cui) -add_importlibs(atl_apitest ole32 oleaut32 advapi32 user32 msvcrt kernel32) +add_importlibs(atl_apitest rpcrt4 ole32 oleaut32 msimg32 gdi32 advapi32 user32 msvcrt kernel32) add_cd_file(TARGET atl_apitest DESTINATION reactos/bin FOR all) diff --git a/rostests/apitests/atl/ant.bmp b/rostests/apitests/atl/ant.bmp new file mode 100644 index 00000000000..aea13bd2089 Binary files /dev/null and b/rostests/apitests/atl/ant.bmp differ diff --git a/rostests/apitests/atl/atl_apitest.rc b/rostests/apitests/atl/atl_apitest.rc index 760690b6d76..a103786287a 100644 --- a/rostests/apitests/atl/atl_apitest.rc +++ b/rostests/apitests/atl/atl_apitest.rc @@ -9,3 +9,5 @@ BEGIN IDS_TEST2 "I am a happy BSTR" END +IDB_ANT BITMAP "ant.bmp" +IDB_CROSS BITMAP "cross.bmp" diff --git a/rostests/apitests/atl/cross.bmp b/rostests/apitests/atl/cross.bmp new file mode 100644 index 00000000000..a8ea2fdc19e Binary files /dev/null and b/rostests/apitests/atl/cross.bmp differ diff --git a/rostests/apitests/atl/devenv/CImage.sln b/rostests/apitests/atl/devenv/CImage.sln new file mode 100644 index 00000000000..099c2c3851a --- /dev/null +++ b/rostests/apitests/atl/devenv/CImage.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CImage", "CImage.vcxproj", "{AE520E17-2DAE-40FF-B082-F32A7A935FB2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x64.ActiveCfg = Debug|x64 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x64.Build.0 = Debug|x64 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x86.ActiveCfg = Debug|Win32 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Debug|x86.Build.0 = Debug|Win32 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x64.ActiveCfg = Release|x64 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x64.Build.0 = Release|x64 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x86.ActiveCfg = Release|Win32 + {AE520E17-2DAE-40FF-B082-F32A7A935FB2}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/rostests/apitests/atl/devenv/CImage.vcxproj b/rostests/apitests/atl/devenv/CImage.vcxproj new file mode 100644 index 00000000000..571f2e3c94c --- /dev/null +++ b/rostests/apitests/atl/devenv/CImage.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {AE520E17-2DAE-40FF-B082-F32A7A935FB2} + 8.1 + AtlProj + + + + Application + true + v140 + Unicode + + + Application + false + v120_xp + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + Unicode + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + true + false + + + true + false + + + + NotUsing + Level3 + Disabled + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + true + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + Console + true + true + + + + + NotUsing + Level3 + Disabled + _WINDOWS;_DEBUG;%(PreprocessorDefinitions) + true + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + Console + true + true + + + + + NotUsing + Level3 + MaxSpeed + WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + true + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + Console + true + true + true + true + + + + + NotUsing + Level3 + MaxSpeed + _WINDOWS;NDEBUG;%(PreprocessorDefinitions) + true + + + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + Console + true + true + true + true + + + + + MultiThreaded + MultiThreaded + MultiThreadedDebug + MultiThreadedDebug + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + \ No newline at end of file diff --git a/rostests/apitests/atl/resource.h b/rostests/apitests/atl/resource.h index bc0ff64cc3b..ca804d82cbe 100644 --- a/rostests/apitests/atl/resource.h +++ b/rostests/apitests/atl/resource.h @@ -1,3 +1,6 @@ #define IDS_TEST1 2000 #define IDS_TEST2 2001 + +#define IDB_ANT 1 +#define IDB_CROSS 2 diff --git a/rostests/apitests/atl/testlist.c b/rostests/apitests/atl/testlist.c index 380bb669544..535f8bced89 100644 --- a/rostests/apitests/atl/testlist.c +++ b/rostests/apitests/atl/testlist.c @@ -4,6 +4,7 @@ extern void func_atltypes(void); extern void func_CComBSTR(void); extern void func_CComHeapPtr(void); +extern void func_CImage(void); extern void func_CRegKey(void); extern void func_CString(void); @@ -12,6 +13,7 @@ const struct test winetest_testlist[] = { "atltypes", func_atltypes }, { "CComBSTR", func_CComBSTR }, { "CComHeapPtr", func_CComHeapPtr }, + { "CImage", func_CImage }, { "CRegKey", func_CRegKey }, { "CString", func_CString }, { 0, 0 }