[ATL] CImage: Respect CODEC info (#5408)

Add _getAllEncoders and _getAllDecoders helper functions and use them
in GetImporterFilterString, GetExporterFilterString, FileTypeFromExtension
and GetClsidFromFileType functions.
CORE-18867, CORE-19008
This commit is contained in:
Katayama Hirofumi MZ 2023-07-31 07:22:38 +09:00 committed by GitHub
parent f8a6542b15
commit 50774f865c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -387,14 +387,10 @@ public:
return E_FAIL; return E_FAIL;
} }
// TODO & FIXME: get parameters (m_rgbTransColor etc.)
// get bitmap handle // get bitmap handle
HBITMAP hbm = NULL; HBITMAP hbm = NULL;
Color color(0xFF, 0xFF, 0xFF); Color color(0xFF, 0xFF, 0xFF);
Gdiplus::Status status; Status status = GetCommon().CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
status = GetCommon().CreateHBITMAPFromBitmap(
pBitmap, &hbm, color.GetValue());
// delete GpBitmap // delete GpBitmap
GetCommon().DisposeImage(pBitmap); GetCommon().DisposeImage(pBitmap);
@ -414,14 +410,10 @@ public:
return E_FAIL; return E_FAIL;
} }
// TODO & FIXME: get parameters (m_rgbTransColor etc.)
// get bitmap handle // get bitmap handle
HBITMAP hbm = NULL; HBITMAP hbm = NULL;
Color color(0xFF, 0xFF, 0xFF); Color color(0xFF, 0xFF, 0xFF);
Gdiplus::Status status; Status status = GetCommon().CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
status = GetCommon().CreateHBITMAPFromBitmap(
pBitmap, &hbm, color.GetValue());
// delete Bitmap // delete Bitmap
GetCommon().DisposeImage(pBitmap); GetCommon().DisposeImage(pBitmap);
@ -525,10 +517,13 @@ public:
using namespace Gdiplus; using namespace Gdiplus;
ATLASSERT(m_hbm); ATLASSERT(m_hbm);
// TODO & FIXME: set parameters (m_rgbTransColor etc.) // Get encoders
CLSID clsid; UINT cEncoders = 0;
if (!GetClsidFromFileType(&clsid, guidFileType)) ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
return E_FAIL;
// Get Codec
CLSID clsid = FindCodecForFileType(*guidFileType, pEncoders, cEncoders);
delete[] pEncoders;
// create a GpBitmap from HBITMAP // create a GpBitmap from HBITMAP
GpBitmap *pBitmap = NULL; GpBitmap *pBitmap = NULL;
@ -550,31 +545,32 @@ public:
using namespace Gdiplus; using namespace Gdiplus;
ATLASSERT(m_hbm); ATLASSERT(m_hbm);
// TODO & FIXME: set parameters (m_rgbTransColor etc.)
// convert the file name string into Unicode // convert the file name string into Unicode
CStringW pszNameW(pszFileName); CStringW pszNameW(pszFileName);
// Get encoders
UINT cEncoders = 0;
ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
// if the file type is null, get the file type from extension // if the file type is null, get the file type from extension
const GUID *FileType = &guidFileType; CLSID clsid;
if (::IsEqualGUID(guidFileType, GUID_NULL)) if (::IsEqualGUID(guidFileType, GUID_NULL))
{ {
LPCWSTR pszExt = GetFileExtension(pszNameW); CString strExt(GetFileExtension(pszNameW));
FileType = FileTypeFromExtension(pszExt); clsid = FindCodecForExtension(strExt, pEncoders, cEncoders);
} }
else
// get CLSID from file type {
CLSID clsid; clsid = FindCodecForFileType(guidFileType, pEncoders, cEncoders);
if (!GetClsidFromFileType(&clsid, FileType)) }
return E_FAIL; delete[] pEncoders;
// create a GpBitmap from HBITMAP // create a GpBitmap from HBITMAP
GpBitmap *pBitmap = NULL; GpBitmap *pBitmap = NULL;
GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap); GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
// save to file // save to file
Status status; Status status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
// destroy GpBitmap // destroy GpBitmap
GetCommon().DisposeImage(pBitmap); GetCommon().DisposeImage(pBitmap);
@ -714,73 +710,96 @@ public:
excludeDefaultSave = excludeIcon | excludeEMF | excludeWMF excludeDefaultSave = excludeIcon | excludeEMF | excludeWMF
}; };
struct FILTER_DATA {
DWORD dwExclude;
const TCHAR *title;
const TCHAR *extensions;
const GUID *guid;
};
protected: protected:
static HRESULT GetCommonFilterString( static bool ShouldExcludeFormat(REFGUID guidFileType, DWORD dwExclude)
{
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatGIF))
return !!(dwExclude & excludeGIF);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatBMP))
return !!(dwExclude & excludeBMP);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatEMF))
return !!(dwExclude & excludeEMF);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatWMF))
return !!(dwExclude & excludeWMF);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatJPEG))
return !!(dwExclude & excludeJPEG);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatPNG))
return !!(dwExclude & excludePNG);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatTIFF))
return !!(dwExclude & excludeTIFF);
if (::IsEqualGUID(guidFileType, Gdiplus::ImageFormatIcon))
return !!(dwExclude & excludeIcon);
return ((dwExclude & excludeOther) == excludeOther);
}
static HRESULT BuildCodecFilterString(
const Gdiplus::ImageCodecInfo* pCodecs,
UINT cCodecs,
CSimpleString& strFilter, CSimpleString& strFilter,
CSimpleArray<GUID>& aguidFileTypes, CSimpleArray<GUID>& aguidFileTypes,
LPCTSTR pszAllFilesDescription, LPCTSTR pszAllFilesDescription,
DWORD dwExclude, DWORD dwExclude,
TCHAR chSeparator) TCHAR chSeparator)
{ {
static const FILTER_DATA table[] = if (!pCodecs || !cCodecs)
{ {
{excludeBMP, TEXT("BMP"), TEXT("*.BMP;*.DIB;*.RLE"), &Gdiplus::ImageFormatBMP}, strFilter += chSeparator;
{excludeJPEG, TEXT("JPEG"), TEXT("*.JPG;*.JPEG;*.JPE;*.JFIF"), &Gdiplus::ImageFormatJPEG}, return E_FAIL;
{excludeGIF, TEXT("GIF"), TEXT("*.GIF"), &Gdiplus::ImageFormatGIF}, }
{excludeEMF, TEXT("EMF"), TEXT("*.EMF"), &Gdiplus::ImageFormatEMF},
{excludeWMF, TEXT("WMF"), TEXT("*.WMF"), &Gdiplus::ImageFormatWMF},
{excludeTIFF, TEXT("TIFF"), TEXT("*.TIF;*.TIFF"), &Gdiplus::ImageFormatTIFF},
{excludePNG, TEXT("PNG"), TEXT("*.PNG"), &Gdiplus::ImageFormatPNG},
{excludeIcon, TEXT("ICO"), TEXT("*.ICO"), &Gdiplus::ImageFormatIcon}
};
if (pszAllFilesDescription) if (pszAllFilesDescription)
{ {
strFilter += pszAllFilesDescription; strFilter += pszAllFilesDescription;
strFilter += chSeparator;
BOOL bFirst = TRUE; BOOL bFirst = TRUE;
for (size_t i = 0; i < _countof(table); ++i) CString extensions;
for (UINT i = 0; i < cCodecs; ++i)
{ {
if ((dwExclude & table[i].dwExclude) != 0) if (ShouldExcludeFormat(pCodecs[i].FormatID, dwExclude))
continue; continue;
if (bFirst) if (bFirst)
bFirst = FALSE; bFirst = FALSE;
else else
strFilter += TEXT(';'); extensions += TEXT(';');
strFilter += table[i].extensions; CString ext(pCodecs[i].FilenameExtension);
extensions += ext;
} }
extensions.MakeLower();
strFilter += TEXT(" (");
strFilter += extensions;
strFilter += TEXT(")");
strFilter += chSeparator;
strFilter += extensions;
strFilter += chSeparator; strFilter += chSeparator;
aguidFileTypes.Add(GUID_NULL); aguidFileTypes.Add(GUID_NULL);
} }
for (size_t i = 0; i < _countof(table); ++i) for (UINT i = 0; i < cCodecs; ++i)
{ {
if ((dwExclude & table[i].dwExclude) != 0) if (ShouldExcludeFormat(pCodecs[i].FormatID, dwExclude))
continue; continue;
strFilter += table[i].title;
CString extensions(pCodecs[i].FilenameExtension);
extensions.MakeLower();
CString desc(pCodecs[i].FormatDescription);
strFilter += desc;
strFilter += TEXT(" ("); strFilter += TEXT(" (");
strFilter += table[i].extensions; strFilter += extensions;
strFilter += TEXT(")"); strFilter += TEXT(")");
strFilter += chSeparator; strFilter += chSeparator;
strFilter += table[i].extensions; strFilter += extensions;
strFilter += chSeparator; strFilter += chSeparator;
aguidFileTypes.Add(*table[i].guid); aguidFileTypes.Add(pCodecs[i].FormatID);
} }
strFilter += chSeparator; strFilter += chSeparator;
return S_OK; return S_OK;
} }
@ -792,11 +811,17 @@ public:
DWORD dwExclude = excludeDefaultLoad, DWORD dwExclude = excludeDefaultLoad,
TCHAR chSeparator = TEXT('|')) TCHAR chSeparator = TEXT('|'))
{ {
return GetCommonFilterString(strImporters, UINT cDecoders = 0;
Gdiplus::ImageCodecInfo* pDecoders = _getAllDecoders(cDecoders);
HRESULT hr = BuildCodecFilterString(pDecoders,
cDecoders,
strImporters,
aguidFileTypes, aguidFileTypes,
pszAllFilesDescription, pszAllFilesDescription,
dwExclude, dwExclude,
chSeparator); chSeparator);
delete[] pDecoders;
return hr;
} }
static HRESULT GetExporterFilterString( static HRESULT GetExporterFilterString(
@ -806,30 +831,27 @@ public:
DWORD dwExclude = excludeDefaultSave, DWORD dwExclude = excludeDefaultSave,
TCHAR chSeparator = TEXT('|')) TCHAR chSeparator = TEXT('|'))
{ {
return GetCommonFilterString(strExporters, UINT cEncoders = 0;
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
HRESULT hr = BuildCodecFilterString(pEncoders,
cEncoders,
strExporters,
aguidFileTypes, aguidFileTypes,
pszAllFilesDescription, pszAllFilesDescription,
dwExclude, dwExclude,
chSeparator); chSeparator);
delete[] pEncoders;
return hr;
} }
protected: protected:
// an extension of BITMAPINFO // an extension of BITMAPINFO
struct MYBITMAPINFOEX struct MYBITMAPINFOEX : BITMAPINFO
{ {
BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColorsExtra[256 - 1];
RGBQUAD bmiColors[256];
BITMAPINFO *get()
{
return reinterpret_cast<BITMAPINFO *>(this);
}
const BITMAPINFO *get() const
{
return reinterpret_cast<const BITMAPINFO *>(this);
}
}; };
// abbreviations of GDI+ basic types // abbreviations of GDI+ basic types. FIXME: Delete us
typedef Gdiplus::GpStatus St; typedef Gdiplus::GpStatus St;
typedef Gdiplus::GpBitmap Bm; typedef Gdiplus::GpBitmap Bm;
typedef Gdiplus::GpImage Im; typedef Gdiplus::GpImage Im;
@ -837,69 +859,45 @@ protected:
// The common data of atlimage // The common data of atlimage
struct COMMON struct COMMON
{ {
// abbreviations of GDI+ basic types
typedef Gdiplus::ImageCodecInfo ICI;
typedef Gdiplus::EncoderParameters EncParams;
typedef Gdiplus::ARGB ARGB;
typedef HBITMAP HBM;
typedef Gdiplus::GdiplusStartupInput GSI;
typedef Gdiplus::GdiplusStartupOutput GSO;
// GDI+ function types // GDI+ function types
#undef API using FUN_Startup = decltype(&Gdiplus::GdiplusStartup);
#undef CST using FUN_Shutdown = decltype(&Gdiplus::GdiplusShutdown);
#define API WINGDIPAPI using FUN_GetImageEncoderSize = decltype(&Gdiplus::DllExports::GdipGetImageEncodersSize);
#define CST GDIPCONST using FUN_GetImageEncoder = decltype(&Gdiplus::DllExports::GdipGetImageEncoders);
typedef St (WINAPI *STARTUP)(ULONG_PTR *, const GSI *, GSO *); using FUN_GetImageDecoderSize = decltype(&Gdiplus::DllExports::GdipGetImageDecodersSize);
typedef void (WINAPI *SHUTDOWN)(ULONG_PTR); using FUN_GetImageDecoder = decltype(&Gdiplus::DllExports::GdipGetImageDecoders);
typedef St (API *GETIMAGEENCODERSSIZE)(UINT *, UINT *); using FUN_CreateBitmapFromFile = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromFile);
typedef St (API *GETIMAGEENCODERS)(UINT, UINT, ICI *); using FUN_CreateHBITMAPFromBitmap = decltype(&Gdiplus::DllExports::GdipCreateHBITMAPFromBitmap);
typedef St (API *CREATEBITMAPFROMFILE)(CST WCHAR*, Bm **); using FUN_CreateBitmapFromStream = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromStream);
typedef St (API *CREATEHBITMAPFROMBITMAP)(Bm *, HBM *, ARGB); using FUN_CreateBitmapFromHBITMAP = decltype(&Gdiplus::DllExports::GdipCreateBitmapFromHBITMAP);
typedef St (API *CREATEBITMAPFROMSTREAM)(IStream *, Bm **); using FUN_SaveImageToStream = decltype(&Gdiplus::DllExports::GdipSaveImageToStream);
typedef St (API *CREATEBITMAPFROMHBITMAP)(HBM, HPALETTE, Bm **); using FUN_SaveImageToFile = decltype(&Gdiplus::DllExports::GdipSaveImageToFile);
typedef St (API *SAVEIMAGETOSTREAM)(Im *, IStream *, CST CLSID *, using FUN_DisposeImage = decltype(&Gdiplus::DllExports::GdipDisposeImage);
CST EncParams *);
typedef St (API *SAVEIMAGETOFILE)(Im *, CST WCHAR *, CST CLSID *,
CST EncParams *);
typedef St (API *DISPOSEIMAGE)(Im*);
#undef API
#undef CST
// members // members
int count; int count = 0;
HINSTANCE hinstGdiPlus; HINSTANCE hinstGdiPlus = NULL;
ULONG_PTR gdiplusToken; ULONG_PTR gdiplusToken = 0;
// GDI+ functions // GDI+ functions
STARTUP Startup; FUN_Startup Startup = NULL;
SHUTDOWN Shutdown; FUN_Shutdown Shutdown = NULL;
GETIMAGEENCODERSSIZE GetImageEncodersSize; FUN_GetImageEncoderSize GetImageEncodersSize = NULL;
GETIMAGEENCODERS GetImageEncoders; FUN_GetImageEncoder GetImageEncoders = NULL;
CREATEBITMAPFROMFILE CreateBitmapFromFile; FUN_GetImageDecoderSize GetImageDecodersSize = NULL;
CREATEHBITMAPFROMBITMAP CreateHBITMAPFromBitmap; FUN_GetImageDecoder GetImageDecoders = NULL;
CREATEBITMAPFROMSTREAM CreateBitmapFromStream; FUN_CreateBitmapFromFile CreateBitmapFromFile = NULL;
CREATEBITMAPFROMHBITMAP CreateBitmapFromHBITMAP; FUN_CreateHBITMAPFromBitmap CreateHBITMAPFromBitmap = NULL;
SAVEIMAGETOSTREAM SaveImageToStream; FUN_CreateBitmapFromStream CreateBitmapFromStream = NULL;
SAVEIMAGETOFILE SaveImageToFile; FUN_CreateBitmapFromHBITMAP CreateBitmapFromHBITMAP = NULL;
DISPOSEIMAGE DisposeImage; FUN_SaveImageToStream SaveImageToStream = NULL;
FUN_SaveImageToFile SaveImageToFile = NULL;
FUN_DisposeImage DisposeImage = NULL;
COMMON() 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() ~COMMON()
{ {
FreeLib(); FreeLib();
@ -915,11 +913,13 @@ protected:
} }
// get procedure address of the DLL // get procedure address of the DLL
template <typename TYPE> template <typename FUN_T>
TYPE AddrOf(const char *name) FUN_T _getFUN(FUN_T& fun, const char *name)
{ {
FARPROC proc = ::GetProcAddress(hinstGdiPlus, name); if (fun)
return reinterpret_cast<TYPE>(proc); return fun;
fun = reinterpret_cast<FUN_T>(::GetProcAddress(hinstGdiPlus, name));
return fun;
} }
HINSTANCE LoadLib() HINSTANCE LoadLib()
@ -929,24 +929,19 @@ protected:
hinstGdiPlus = ::LoadLibraryA("gdiplus.dll"); hinstGdiPlus = ::LoadLibraryA("gdiplus.dll");
// get procedure addresses from the DLL _getFUN(Startup, "GdiplusStartup");
Startup = AddrOf<STARTUP>("GdiplusStartup"); _getFUN(Shutdown, "GdiplusShutdown");
Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown"); _getFUN(GetImageEncodersSize, "GdipGetImageEncodersSize");
GetImageEncodersSize = _getFUN(GetImageEncoders, "GdipGetImageEncoders");
AddrOf<GETIMAGEENCODERSSIZE>("GdipGetImageEncodersSize"); _getFUN(GetImageDecodersSize, "GdipGetImageDecodersSize");
GetImageEncoders = AddrOf<GETIMAGEENCODERS>("GdipGetImageEncoders"); _getFUN(GetImageDecoders, "GdipGetImageDecoders");
CreateBitmapFromFile = _getFUN(CreateBitmapFromFile, "GdipCreateBitmapFromFile");
AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile"); _getFUN(CreateHBITMAPFromBitmap, "GdipCreateHBITMAPFromBitmap");
CreateHBITMAPFromBitmap = _getFUN(CreateBitmapFromStream, "GdipCreateBitmapFromStream");
AddrOf<CREATEHBITMAPFROMBITMAP>("GdipCreateHBITMAPFromBitmap"); _getFUN(CreateBitmapFromHBITMAP, "GdipCreateBitmapFromHBITMAP");
CreateBitmapFromStream = _getFUN(SaveImageToStream, "GdipSaveImageToStream");
AddrOf<CREATEBITMAPFROMSTREAM>("GdipCreateBitmapFromStream"); _getFUN(SaveImageToFile, "GdipSaveImageToFile");
CreateBitmapFromHBITMAP = _getFUN(DisposeImage, "GdipDisposeImage");
AddrOf<CREATEBITMAPFROMHBITMAP>("GdipCreateBitmapFromHBITMAP");
SaveImageToStream =
AddrOf<SAVEIMAGETOSTREAM>("GdipSaveImageToStream");
SaveImageToFile = AddrOf<SAVEIMAGETOFILE>("GdipSaveImageToFile");
DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage");
if (hinstGdiPlus && Startup) if (hinstGdiPlus && Startup)
{ {
@ -966,6 +961,8 @@ protected:
Shutdown = NULL; Shutdown = NULL;
GetImageEncodersSize = NULL; GetImageEncodersSize = NULL;
GetImageEncoders = NULL; GetImageEncoders = NULL;
GetImageDecodersSize = NULL;
GetImageDecoders = NULL;
CreateBitmapFromFile = NULL; CreateBitmapFromFile = NULL;
CreateHBITMAPFromBitmap = NULL; CreateHBITMAPFromBitmap = NULL;
CreateBitmapFromStream = NULL; CreateBitmapFromStream = NULL;
@ -1024,96 +1021,143 @@ protected:
return RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue); return RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
} }
struct EXTENSION_ENTRY static CLSID
FindCodecForExtension(LPCTSTR dotext, const Gdiplus::ImageCodecInfo *pCodecs, UINT nCodecs)
{ {
LPCWSTR pszExt; for (UINT i = 0; i < nCodecs; ++i)
GUID guid; {
}; CString strSpecs(pCodecs[i].FilenameExtension);
int ichOld = 0, ichSep;
for (;;)
{
ichSep = strSpecs.Find(TEXT(';'), ichOld);
const GUID *FileTypeFromExtension(LPCWSTR pszExt) const CString strSpec;
{ if (ichSep < 0)
static const EXTENSION_ENTRY table[] = strSpec = strSpecs.Mid(ichOld);
{ else
{L".jpg", Gdiplus::ImageFormatJPEG}, strSpec = strSpecs.Mid(ichOld, ichSep - ichOld);
{L".png", Gdiplus::ImageFormatPNG},
{L".bmp", Gdiplus::ImageFormatBMP}, int ichDot = strSpec.ReverseFind(TEXT('.'));
{L".gif", Gdiplus::ImageFormatGIF}, if (ichDot >= 0)
{L".tif", Gdiplus::ImageFormatTIFF}, strSpec = strSpec.Mid(ichDot);
{L".jpeg", Gdiplus::ImageFormatJPEG},
{L".jpe", Gdiplus::ImageFormatJPEG}, if (!dotext || strSpec.CompareNoCase(dotext) == 0)
{L".jfif", Gdiplus::ImageFormatJPEG}, return pCodecs[i].Clsid;
{L".dib", Gdiplus::ImageFormatBMP},
{L".rle", Gdiplus::ImageFormatBMP}, if (ichSep < 0)
{L".tiff", Gdiplus::ImageFormatTIFF} break;
};
const size_t count = _countof(table); ichOld = ichSep + 1;
for (size_t i = 0; i < count; ++i)
{
if (::lstrcmpiW(table[i].pszExt, pszExt) == 0)
return &table[i].guid;
} }
}
return CLSID_NULL;
}
// Deprecated. Don't use this
static const GUID *FileTypeFromExtension(LPCTSTR dotext)
{
UINT cEncoders = 0;
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
for (UINT i = 0; i < cEncoders; ++i)
{
CString strSpecs(pEncoders[i].FilenameExtension);
int ichOld = 0, ichSep;
for (;;)
{
ichSep = strSpecs.Find(TEXT(';'), ichOld);
CString strSpec;
if (ichSep < 0)
strSpec = strSpecs.Mid(ichOld);
else
strSpec = strSpecs.Mid(ichOld, ichSep - ichOld);
int ichDot = strSpec.ReverseFind(TEXT('.'));
if (ichDot >= 0)
strSpec = strSpec.Mid(ichDot);
if (!dotext || strSpec.CompareNoCase(dotext) == 0)
{
static GUID s_guid;
s_guid = pEncoders[i].FormatID;
delete[] pEncoders;
return &s_guid;
}
if (ichSep < 0)
break;
ichOld = ichSep + 1;
}
}
delete[] pEncoders;
return NULL; return NULL;
} }
struct FORMAT_ENTRY static CLSID
FindCodecForFileType(REFGUID guidFileType, const Gdiplus::ImageCodecInfo *pCodecs, UINT nCodecs)
{ {
GUID guid; for (UINT iInfo = 0; iInfo < nCodecs; ++iInfo)
LPCWSTR mime; {
}; if (::IsEqualGUID(pCodecs[iInfo].FormatID, guidFileType))
return pCodecs[iInfo].Clsid;
}
return CLSID_NULL;
}
bool GetClsidFromFileType(CLSID *clsid, const GUID *guid) const // Deprecated. Don't use this
{ static bool GetClsidFromFileType(CLSID *clsid, const GUID *guid)
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 (::IsEqualGUID(table[i].guid, *guid))
{
int num = GetEncoderClsid(table[i].mime, clsid);
if (num >= 0)
{ {
UINT cEncoders = 0;
Gdiplus::ImageCodecInfo* pEncoders = _getAllEncoders(cEncoders);
*clsid = FindCodecForFileType(*guid, pEncoders, cEncoders);
delete[] pEncoders;
return true; return true;
} }
}
}
return false;
}
int GetEncoderClsid(LPCWSTR mime, CLSID *clsid) const static Gdiplus::ImageCodecInfo* _getAllEncoders(UINT& cEncoders)
{ {
UINT count = 0, total_size = 0; CImage image; // Initialize common
GetCommon().GetImageEncodersSize(&count, &total_size);
UINT total_size = 0;
GetCommon().GetImageEncodersSize(&cEncoders, &total_size);
if (total_size == 0) if (total_size == 0)
return -1; // failure return NULL; // failure
Gdiplus::ImageCodecInfo *pInfo; Gdiplus::ImageCodecInfo *ret;
BYTE *pb = new BYTE[total_size]; ret = new Gdiplus::ImageCodecInfo[total_size / sizeof(ret[0])];
ATLASSERT(pb); if (ret == NULL)
pInfo = reinterpret_cast<Gdiplus::ImageCodecInfo *>(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) cEncoders = 0;
{ return NULL; // failure
*clsid = pInfo[iInfo].Clsid;
delete[] pb;
return iInfo; // success
}
} }
delete[] pb; GetCommon().GetImageEncoders(cEncoders, total_size, ret);
return -1; // failure return ret; // needs delete[]
}
static Gdiplus::ImageCodecInfo* _getAllDecoders(UINT& cDecoders)
{
CImage image; // Initialize common
UINT total_size = 0;
GetCommon().GetImageDecodersSize(&cDecoders, &total_size);
if (total_size == 0)
return NULL; // failure
Gdiplus::ImageCodecInfo *ret;
ret = new Gdiplus::ImageCodecInfo[total_size / sizeof(ret[0])];
if (ret == NULL)
{
cDecoders = 0;
return NULL; // failure
}
GetCommon().GetImageDecoders(cDecoders, total_size, ret);
return ret; // needs delete[]
} }
void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation, void AttachInternal(HBITMAP hBitmap, DIBOrientation eOrientation,
@ -1186,9 +1230,7 @@ protected:
// create a DIB section // create a DIB section
HDC hDC = ::CreateCompatibleDC(NULL); HDC hDC = ::CreateCompatibleDC(NULL);
ATLASSERT(hDC); ATLASSERT(hDC);
LPVOID pvBits; HBITMAP hbm = ::CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, NULL, NULL, 0);
HBITMAP hbm = ::CreateDIBSection(hDC, bi.get(), DIB_RGB_COLORS,
&pvBits, NULL, 0);
ATLASSERT(hbm); ATLASSERT(hbm);
::DeleteDC(hDC); ::DeleteDC(hDC);