217 lines
5.8 KiB
C++
217 lines
5.8 KiB
C++
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include <objbase.h>
|
||
|
#include "gdiplus.h"
|
||
|
#include <shlwapi.h>
|
||
|
#include <initguid.h>
|
||
|
//#include <shlwapip.h>
|
||
|
using namespace Gdiplus;
|
||
|
DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||
|
|
||
|
UINT FindInDecoderList(ImageCodecInfo *pici, UINT cDecoders, LPCTSTR pszFile)
|
||
|
{
|
||
|
LPCTSTR pszExt = PathFindExtension(pszFile); // speed up PathMatchSpec calls
|
||
|
|
||
|
// look at the list of decoders to see if this format is there
|
||
|
for (UINT i = 0; i < cDecoders; i++)
|
||
|
{
|
||
|
if (PathMatchSpec(pszExt, pici[i].FilenameExtension))
|
||
|
return i;
|
||
|
}
|
||
|
return (UINT)-1; // not found!
|
||
|
}
|
||
|
|
||
|
class CEncoderInfo
|
||
|
{
|
||
|
public:
|
||
|
Status GetDataFormatFromPath(LPCWSTR pszPath, GUID *pguidFmt);
|
||
|
Status GetEncoderList();
|
||
|
Status GetEncoderFromFormat(const GUID *pfmt, CLSID *pclsidEncoder);
|
||
|
CEncoderInfo();
|
||
|
~CEncoderInfo();
|
||
|
|
||
|
private:
|
||
|
UINT _cEncoders; // number of encoders discovered
|
||
|
ImageCodecInfo *_pici; // array of image encoder classes
|
||
|
};
|
||
|
|
||
|
|
||
|
CEncoderInfo::CEncoderInfo()
|
||
|
{
|
||
|
_cEncoders = 0;
|
||
|
_pici = NULL;
|
||
|
}
|
||
|
|
||
|
CEncoderInfo::~CEncoderInfo()
|
||
|
{
|
||
|
LocalFree (_pici);
|
||
|
}
|
||
|
Status CEncoderInfo::GetDataFormatFromPath(LPCWSTR pszPath, GUID *pguidFmt)
|
||
|
{
|
||
|
*pguidFmt = GUID_NULL;
|
||
|
|
||
|
Status s = GetEncoderList();
|
||
|
if (Ok == s)
|
||
|
{
|
||
|
UINT i = FindInDecoderList(_pici, _cEncoders, pszPath);
|
||
|
if (-1 != i)
|
||
|
{
|
||
|
*pguidFmt = _pici[i].FormatID;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s = GenericError;
|
||
|
}
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
Status CEncoderInfo::GetEncoderList()
|
||
|
{
|
||
|
Status s = Ok;
|
||
|
if (!_pici)
|
||
|
{
|
||
|
// lets pick up the list of encoders, first we get the encoder size which
|
||
|
// gives us the CB and the number of encoders that are installed on the
|
||
|
// machine.
|
||
|
|
||
|
UINT cb;
|
||
|
s = GetImageEncodersSize(&_cEncoders, &cb);
|
||
|
if (Ok == s)
|
||
|
{
|
||
|
// allocate the buffer for the encoders and then fill it
|
||
|
// with the encoder list.
|
||
|
|
||
|
_pici = (ImageCodecInfo*)LocalAlloc(LPTR, cb);
|
||
|
if (_pici)
|
||
|
{
|
||
|
s = GetImageEncoders(_cEncoders, cb, _pici);
|
||
|
if (Ok != s)
|
||
|
{
|
||
|
LocalFree(_pici);
|
||
|
_pici = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s = OutOfMemory;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
|
||
|
Status CEncoderInfo::GetEncoderFromFormat(const GUID *pfmt, CLSID *pclsidEncoder)
|
||
|
{
|
||
|
Status s = GetEncoderList();
|
||
|
if (Ok == s)
|
||
|
{
|
||
|
s = GenericError;
|
||
|
for (UINT i = 0; i != _cEncoders; i++)
|
||
|
{
|
||
|
if (_pici[i].FormatID == *pfmt)
|
||
|
{
|
||
|
if (pclsidEncoder)
|
||
|
{
|
||
|
*pclsidEncoder = _pici[i].Clsid; // return the CLSID of the encoder so we can create again
|
||
|
}
|
||
|
s = Ok;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
void AddEncParameter(EncoderParameters *pep, GUID guidProperty, ULONG type, void *pv)
|
||
|
{
|
||
|
pep->Parameter[pep->Count].Guid = guidProperty;
|
||
|
pep->Parameter[pep->Count].Type = type;
|
||
|
pep->Parameter[pep->Count].NumberOfValues = 1;
|
||
|
pep->Parameter[pep->Count].Value = pv;
|
||
|
pep->Count++;
|
||
|
}
|
||
|
|
||
|
class CGraphicsInit
|
||
|
{
|
||
|
ULONG_PTR _token;
|
||
|
public:
|
||
|
CGraphicsInit()
|
||
|
{
|
||
|
GdiplusStartupInput gsi;
|
||
|
GdiplusStartupOutput gso;
|
||
|
GdiplusStartup(&_token, &gsi, &gso);
|
||
|
};
|
||
|
~CGraphicsInit()
|
||
|
{
|
||
|
GdiplusShutdown(_token);
|
||
|
};
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
int __cdecl wmain(int argc, LPCWSTR argv[])
|
||
|
{
|
||
|
if (argc < 2)
|
||
|
{
|
||
|
printf("Usage: rotimg <filename> <targetfile>\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CGraphicsInit cgi;
|
||
|
LPCWSTR szSrc = argv[1];
|
||
|
LPCWSTR szSave = argc > 2 ? argv[2] : argv[1];
|
||
|
Status s;
|
||
|
printf("Source image: %ls, Target image: %ls\n", szSrc, szSave);
|
||
|
Image *pimg = new Image(szSrc, TRUE);
|
||
|
s = pimg->GetLastStatus();
|
||
|
if (Ok != s)
|
||
|
{
|
||
|
printf("Error %d constructing Image\n", s);
|
||
|
}
|
||
|
UINT nPages = pimg->GetFrameCount(&FrameDimensionPage);
|
||
|
Image *pimgWork = pimg->Clone();
|
||
|
|
||
|
|
||
|
s = pimgWork->RotateFlip(Rotate90FlipNone);
|
||
|
if (Ok != s)
|
||
|
{
|
||
|
printf("RotateFlip returned %d\n", s);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IStream *pstrm;
|
||
|
SHCreateStreamOnFileEx(szSave, STGM_WRITE | STGM_CREATE, 0, TRUE, NULL, &pstrm);
|
||
|
|
||
|
CEncoderInfo cei;
|
||
|
GUID guidFmt;
|
||
|
CLSID clsidEncoder;
|
||
|
cei.GetDataFormatFromPath(szSave, &guidFmt);
|
||
|
cei.GetEncoderFromFormat(&guidFmt, &clsidEncoder);
|
||
|
EncoderParameters ep[1] = {0};
|
||
|
ULONG flagValueMulti = nPages > 1 ? EncoderValueMultiFrame : EncoderValueLastFrame;
|
||
|
AddEncParameter(ep, EncoderSaveFlag, EncoderParameterValueTypeLong, &flagValueMulti);
|
||
|
pimgWork->SelectActiveFrame(&FrameDimensionPage, 0);
|
||
|
s = pimgWork->Save(pstrm,&clsidEncoder, ep);
|
||
|
printf("first Save returned %d\n", s);
|
||
|
if (Ok == s && nPages > 1)
|
||
|
{
|
||
|
EncoderParameters ep[2] = {0};
|
||
|
ULONG flagValueDim = EncoderValueFrameDimensionPage;
|
||
|
ULONG flagValueLastFrame = EncoderValueLastFrame;
|
||
|
pimg->SelectActiveFrame(&FrameDimensionPage, 1);
|
||
|
AddEncParameter(ep, EncoderSaveFlag, EncoderParameterValueTypeLong, &flagValueDim);
|
||
|
AddEncParameter(ep, EncoderSaveFlag, EncoderParameterValueTypeLong, &flagValueLastFrame);
|
||
|
s = pimgWork->SaveAdd(pimg, ep);
|
||
|
printf("SaveAdd returned %d\n", s);
|
||
|
}
|
||
|
pstrm->Release();
|
||
|
}
|
||
|
delete pimg;
|
||
|
delete pimgWork;
|
||
|
}
|
||
|
printf("Rotimg complete\n");
|
||
|
}
|