489 lines
16 KiB
C++
489 lines
16 KiB
C++
#include "precomp.h"
|
|
#include "gphelper.h"
|
|
#include "psutil.h"
|
|
|
|
using namespace Gdiplus;
|
|
|
|
CGdiPlusHelper::CGdiPlusHelper(void)
|
|
: m_pImageEncoderInfo(NULL),
|
|
m_nImageEncoderCount(0),
|
|
m_pImageDecoderInfo(NULL),
|
|
m_nImageDecoderCount(0)
|
|
#if defined(GDIPLUSHELPER_EXPLICIT_INITIALIZATION)
|
|
,m_bGdiplusInitialized(false)
|
|
,m_pGdiplusToken(NULL)
|
|
#endif
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
CGdiPlusHelper::~CGdiPlusHelper(void)
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
HRESULT CGdiPlusHelper::Initialize(void)
|
|
{
|
|
#if defined(GDIPLUSHELPER_EXPLICIT_INITIALIZATION)
|
|
// Make sure GDI+ is initialized
|
|
Gdiplus::GdiplusStartupInput StartupInput;
|
|
m_bGdiplusInitialized = (Gdiplus::GdiplusStartup(&m_pGdiplusToken,&StartupInput,NULL) == Gdiplus::Ok);
|
|
#endif
|
|
|
|
// Get the installed encoders
|
|
HRESULT hr = E_FAIL;
|
|
UINT cbCodecs = 0;
|
|
GetImageEncodersSize( &m_nImageEncoderCount, &cbCodecs );
|
|
if (cbCodecs)
|
|
{
|
|
m_pImageEncoderInfo = static_cast<ImageCodecInfo*>(LocalAlloc(LPTR,cbCodecs));
|
|
if (m_pImageEncoderInfo)
|
|
{
|
|
GpStatus Status = GetImageEncoders( m_nImageEncoderCount, cbCodecs, m_pImageEncoderInfo );
|
|
if (Ok == Status)
|
|
{
|
|
for (UINT i=0;i<m_nImageEncoderCount;i++)
|
|
{
|
|
////WIA_PRINTGUID((m_pImageEncoderInfo[i].Clsid,TEXT("m_pImageEncoderInfo[i].Clsid")));
|
|
////WIA_PRINTGUID((m_pImageEncoderInfo[i].FormatID,TEXT("m_pImageEncoderInfo[i].FormatID")));
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the installed decoders
|
|
cbCodecs = 0;
|
|
GetImageDecodersSize( &m_nImageDecoderCount, &cbCodecs );
|
|
if (cbCodecs)
|
|
{
|
|
m_pImageDecoderInfo = static_cast<ImageCodecInfo*>(LocalAlloc(LPTR,cbCodecs));
|
|
if (m_pImageDecoderInfo)
|
|
{
|
|
GpStatus Status = GetImageDecoders( m_nImageDecoderCount, cbCodecs, m_pImageDecoderInfo );
|
|
if (Ok == Status)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
// If there was a problem, make sure there are no half-initialized things laying around
|
|
if (FAILED(hr))
|
|
{
|
|
Destroy();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
void CGdiPlusHelper::Destroy(void)
|
|
{
|
|
|
|
#if defined(GDIPLUSHELPER_EXPLICIT_INITIALIZATION)
|
|
// Shut down GDI+
|
|
if (m_bGdiplusInitialized)
|
|
{
|
|
Gdiplus::GdiplusShutdown(m_pGdiplusToken);
|
|
m_bGdiplusInitialized = false;
|
|
m_pGdiplusToken = NULL;
|
|
}
|
|
#endif
|
|
|
|
// Free the lists of Encoders and Decoders
|
|
if (m_pImageEncoderInfo)
|
|
{
|
|
LocalFree(m_pImageEncoderInfo);
|
|
m_pImageEncoderInfo = NULL;
|
|
}
|
|
m_nImageEncoderCount = 0;
|
|
|
|
if (m_pImageDecoderInfo)
|
|
{
|
|
LocalFree(m_pImageDecoderInfo);
|
|
m_pImageDecoderInfo = NULL;
|
|
}
|
|
m_nImageDecoderCount = 0;
|
|
}
|
|
|
|
bool CGdiPlusHelper::IsValid(void) const
|
|
{
|
|
// Make sure we've been completely created
|
|
#if defined(GDIPLUSHELPER_EXPLICIT_INITIALIZATION)
|
|
return(m_bGdiplusInitialized && m_pImageEncoderInfo && m_nImageEncoderCount && m_pImageDecoderInfo && m_nImageDecoderCount);
|
|
#else
|
|
return(m_pImageEncoderInfo && m_nImageEncoderCount && m_pImageDecoderInfo && m_nImageDecoderCount);
|
|
#endif
|
|
}
|
|
|
|
HRESULT CGdiPlusHelper::LoadAndScale( HBITMAP &hTargetBitmap, LPCTSTR pszFilename, UINT nMaxWidth, UINT nMaxHeight, bool bStretchSmallImages )
|
|
{
|
|
hTargetBitmap = NULL;
|
|
// Make sure we have a valid filename
|
|
if (pszFilename && lstrlen(pszFilename))
|
|
{
|
|
Bitmap SourceBitmap( CSimpleStringConvert::WideString(CSimpleString(pszFilename) ) );
|
|
if (Ok == SourceBitmap.GetLastStatus())
|
|
{
|
|
// Get the image width and height
|
|
UINT nSourceWidth = SourceBitmap.GetWidth();
|
|
UINT nSourceHeight = SourceBitmap.GetHeight();
|
|
|
|
// Make sure the width and height are non-zero
|
|
if (nSourceWidth && nSourceHeight)
|
|
{
|
|
// Assume the source dimensions are fine
|
|
UINT nTargetWidth = nSourceWidth;
|
|
UINT nTargetHeight = nSourceHeight;
|
|
|
|
// If the height or the width exceed the allowed maximum, scale it down, or if we are allowing stretching
|
|
if ((nTargetWidth > nMaxWidth) || (nTargetHeight > nMaxHeight) || bStretchSmallImages)
|
|
{
|
|
SIZE sizeDesiredImageSize = PrintScanUtil::ScalePreserveAspectRatio( nMaxWidth, nMaxHeight, nTargetWidth, nTargetHeight );
|
|
nTargetWidth = sizeDesiredImageSize.cx;
|
|
nTargetHeight = sizeDesiredImageSize.cy;
|
|
}
|
|
|
|
// Make sure we have valid sizes
|
|
if (nTargetWidth && nTargetHeight)
|
|
{
|
|
// Create the target bitmap and make sure it succeeded
|
|
Bitmap TargetBitmap( nTargetWidth, nTargetHeight );
|
|
if (Ok == TargetBitmap.GetLastStatus())
|
|
{
|
|
// Get a graphics to render to
|
|
Graphics *pGraphics = Graphics::FromImage(&TargetBitmap);
|
|
if (pGraphics)
|
|
{
|
|
// Make sure it is valid
|
|
if (pGraphics->GetLastStatus() == Ok)
|
|
{
|
|
// Draw scaled image
|
|
if (pGraphics->DrawImage(&SourceBitmap, 0, 0, nTargetWidth, nTargetHeight) == Ok)
|
|
{
|
|
// Get an HBITMAP for this image
|
|
TargetBitmap.GetHBITMAP( Color::Black, &hTargetBitmap );
|
|
}
|
|
}
|
|
// Clean up our dynamically allocated graphics
|
|
delete pGraphics;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(hTargetBitmap ? S_OK : E_FAIL);
|
|
}
|
|
|
|
|
|
// Construct a string like this: JPG;BMP;PNG with all supported extensions
|
|
HRESULT CGdiPlusHelper::ConstructCodecExtensionSearchStrings( CSimpleString &strExtensions, Gdiplus::ImageCodecInfo *pImageCodecInfo, UINT nImageCodecCount )
|
|
{
|
|
for (UINT i=0;i<nImageCodecCount;i++)
|
|
{
|
|
if (strExtensions.Length())
|
|
{
|
|
strExtensions += TEXT(";");
|
|
}
|
|
strExtensions += CSimpleStringConvert::NaturalString(CSimpleStringWide(pImageCodecInfo[i].FilenameExtension));
|
|
}
|
|
return (strExtensions.Length() ? S_OK : E_FAIL);
|
|
}
|
|
|
|
HRESULT CGdiPlusHelper::ConstructDecoderExtensionSearchStrings( CSimpleString &strExtensions )
|
|
{
|
|
return CGdiPlusHelper::ConstructCodecExtensionSearchStrings( strExtensions, m_pImageDecoderInfo, m_nImageDecoderCount );
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::ConstructEncoderExtensionSearchStrings( CSimpleString &strExtensions )
|
|
{
|
|
return CGdiPlusHelper::ConstructCodecExtensionSearchStrings( strExtensions, m_pImageEncoderInfo, m_nImageEncoderCount );
|
|
}
|
|
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifierItem::CImageFileFormatVerifierItem(void)
|
|
: m_pSignature(NULL),
|
|
m_pMask(NULL),
|
|
m_nLength(0),
|
|
m_guidFormat(IID_NULL),
|
|
m_clsidDecoder(IID_NULL)
|
|
{
|
|
}
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifierItem::CImageFileFormatVerifierItem( const PBYTE pSignature, const PBYTE pMask, int nLength, const GUID &guidFormat, const CLSID &guidDecoder )
|
|
: m_pSignature(NULL),
|
|
m_pMask(NULL),
|
|
m_nLength(0),
|
|
m_guidFormat(IID_NULL),
|
|
m_clsidDecoder(IID_NULL)
|
|
{
|
|
Assign( pSignature, pMask, nLength, guidFormat, guidDecoder );
|
|
}
|
|
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifierItem::CImageFileFormatVerifierItem( const CImageFileFormatVerifierItem &other )
|
|
: m_pSignature(NULL),
|
|
m_pMask(NULL),
|
|
m_nLength(0),
|
|
m_guidFormat(IID_NULL),
|
|
m_clsidDecoder(IID_NULL)
|
|
{
|
|
Assign( other.Signature(), other.Mask(), other.Length(), other.Format(), other.Decoder() );
|
|
}
|
|
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifierItem &CImageFileFormatVerifier::CImageFileFormatVerifierItem::operator=( const CImageFileFormatVerifierItem &other )
|
|
{
|
|
if (this != &other)
|
|
{
|
|
return Assign( other.Signature(), other.Mask(), other.Length(), other.Format(), other.Decoder() );
|
|
}
|
|
else return *this;
|
|
}
|
|
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifierItem &CImageFileFormatVerifier::CImageFileFormatVerifierItem::Assign( const PBYTE pSignature, const PBYTE pMask, int nLength, const GUID &guidFormat, const CLSID &clsidDecoder )
|
|
{
|
|
Destroy();
|
|
bool bOK = false;
|
|
m_nLength = nLength;
|
|
m_guidFormat = guidFormat;
|
|
m_clsidDecoder = clsidDecoder;
|
|
if (nLength && pSignature && pMask)
|
|
{
|
|
m_pSignature = new BYTE[nLength];
|
|
m_pMask = new BYTE[nLength];
|
|
if (m_pSignature && m_pMask)
|
|
{
|
|
CopyMemory( m_pSignature, pSignature, nLength );
|
|
CopyMemory( m_pMask, pMask, nLength );
|
|
bOK = true;
|
|
}
|
|
}
|
|
if (!bOK)
|
|
{
|
|
Destroy();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
void CImageFileFormatVerifier::CImageFileFormatVerifierItem::Destroy(void)
|
|
{
|
|
if (m_pSignature)
|
|
{
|
|
delete[] m_pSignature;
|
|
m_pSignature = NULL;
|
|
}
|
|
if (m_pMask)
|
|
{
|
|
delete[] m_pMask;
|
|
m_pMask;
|
|
}
|
|
m_nLength = 0;
|
|
m_guidFormat = IID_NULL;
|
|
m_clsidDecoder = IID_NULL;
|
|
}
|
|
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifierItem::~CImageFileFormatVerifierItem(void)
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
|
|
PBYTE CImageFileFormatVerifier::CImageFileFormatVerifierItem::Signature(void) const
|
|
{
|
|
return m_pSignature;
|
|
}
|
|
|
|
|
|
PBYTE CImageFileFormatVerifier::CImageFileFormatVerifierItem::Mask(void) const
|
|
{
|
|
return m_pMask;
|
|
}
|
|
|
|
|
|
int CImageFileFormatVerifier::CImageFileFormatVerifierItem::Length(void) const
|
|
{
|
|
return m_nLength;
|
|
}
|
|
|
|
|
|
GUID CImageFileFormatVerifier::CImageFileFormatVerifierItem::Format(void) const
|
|
{
|
|
return m_guidFormat;
|
|
}
|
|
|
|
|
|
CLSID CImageFileFormatVerifier::CImageFileFormatVerifierItem::Decoder(void) const
|
|
{
|
|
return m_clsidDecoder;
|
|
}
|
|
|
|
|
|
bool CImageFileFormatVerifier::CImageFileFormatVerifierItem::Match( PBYTE pBytes, int nLen ) const
|
|
{
|
|
if (nLen < Length())
|
|
{
|
|
return false;
|
|
}
|
|
for (int i=0;i<Length();i++)
|
|
{
|
|
if (false == ((pBytes[i] & m_pMask[i]) == m_pSignature[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
CImageFileFormatVerifier::CImageFileFormatVerifier(void)
|
|
: m_nMaxSignatureLength(0),
|
|
m_pSignatureBuffer(NULL)
|
|
{
|
|
// Get the decoder count and size of the decoder info array
|
|
UINT nImageDecoderCount = 0, cbCodecs = 0;
|
|
if (Gdiplus::Ok == Gdiplus::GetImageDecodersSize( &nImageDecoderCount, &cbCodecs ))
|
|
{
|
|
// Make sure we got good sizes back
|
|
if (cbCodecs && nImageDecoderCount)
|
|
{
|
|
// Allocate the array
|
|
Gdiplus::ImageCodecInfo *pImageDecoderInfo = static_cast<Gdiplus::ImageCodecInfo*>(LocalAlloc(LPTR,cbCodecs));
|
|
if (pImageDecoderInfo)
|
|
{
|
|
// Get the actual decoder info
|
|
if (Gdiplus::Ok == Gdiplus::GetImageDecoders( nImageDecoderCount, cbCodecs, pImageDecoderInfo ))
|
|
{
|
|
// Add each decoder to the format list
|
|
for (UINT i=0;i<nImageDecoderCount;i++)
|
|
{
|
|
// Add each signature to the format list
|
|
for (UINT j=0;j<pImageDecoderInfo[i].SigCount;j++)
|
|
{
|
|
#if defined(DBG)
|
|
CSimpleString strPattern;
|
|
CSimpleString strMask;
|
|
for (ULONG x=0;x<pImageDecoderInfo[i].SigSize;x++)
|
|
{
|
|
strPattern += CSimpleString().Format( TEXT("%02X"), ((const PBYTE)(pImageDecoderInfo[i].SigPattern+(j*pImageDecoderInfo[i].SigSize)))[x] );
|
|
strMask += CSimpleString().Format( TEXT("%02X"), ((const PBYTE)(pImageDecoderInfo[i].SigMask+(j*pImageDecoderInfo[i].SigSize)))[x] );
|
|
}
|
|
//WIA_PRINTGUID((pImageDecoderInfo[i].FormatID,TEXT("FormatID")));
|
|
//WIA_PRINTGUID((pImageDecoderInfo[i].Clsid,TEXT(" Clsid")));
|
|
//WIA_TRACE((TEXT(" strPattern: %s, strMask: %s, SigSize: %d"), strPattern.String(), strMask.String(), pImageDecoderInfo[i].SigSize ));
|
|
#endif
|
|
m_FileFormatVerifierList.Append( CImageFileFormatVerifier::CImageFileFormatVerifierItem( (const PBYTE)(pImageDecoderInfo[i].SigPattern+(j*pImageDecoderInfo[i].SigSize)), (const PBYTE)(pImageDecoderInfo[i].SigMask+(j*pImageDecoderInfo[i].SigSize)), pImageDecoderInfo[i].SigSize, pImageDecoderInfo[i].FormatID, pImageDecoderInfo[i].Clsid ) );
|
|
}
|
|
}
|
|
}
|
|
// Free the array
|
|
LocalFree(pImageDecoderInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Assume the max length is Zero
|
|
m_nMaxSignatureLength = 0;
|
|
|
|
// For each signature, check if it is greater in length than the maximum.
|
|
for (int i=0;i<m_FileFormatVerifierList.Size();i++)
|
|
{
|
|
// If it is the longest, save the length
|
|
if (m_FileFormatVerifierList[i].Length() > m_nMaxSignatureLength)
|
|
{
|
|
m_nMaxSignatureLength = m_FileFormatVerifierList[i].Length();
|
|
}
|
|
}
|
|
|
|
// If we have a valid max length, allocate a buffer to hold the file's data
|
|
if (m_nMaxSignatureLength)
|
|
{
|
|
m_pSignatureBuffer = new BYTE[m_nMaxSignatureLength];
|
|
}
|
|
|
|
// If anything failed, free everything
|
|
if (!IsValid())
|
|
{
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
|
|
void CImageFileFormatVerifier::Destroy(void)
|
|
{
|
|
// Free the file signature buffer
|
|
if (m_pSignatureBuffer)
|
|
{
|
|
delete[] m_pSignatureBuffer;
|
|
m_pSignatureBuffer = NULL;
|
|
}
|
|
m_nMaxSignatureLength = 0;
|
|
m_FileFormatVerifierList.Destroy();
|
|
}
|
|
|
|
|
|
bool CImageFileFormatVerifier::IsValid(void) const
|
|
{
|
|
return (m_pSignatureBuffer && m_nMaxSignatureLength && m_FileFormatVerifierList.Size());
|
|
}
|
|
|
|
CImageFileFormatVerifier::~CImageFileFormatVerifier(void)
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
|
|
GUID CImageFileFormatVerifier::GetImageType( LPCTSTR pszFilename )
|
|
{
|
|
// Assume we will not find a match
|
|
GUID guidResult = IID_NULL;
|
|
|
|
// Open the file for reading
|
|
HANDLE hFile = CreateFile( pszFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
// Read the maximum signature length number of bytes
|
|
DWORD dwBytesRead = 0;
|
|
if (ReadFile( hFile, m_pSignatureBuffer, m_nMaxSignatureLength, &dwBytesRead, NULL ))
|
|
{
|
|
// Make sure we got some bytes
|
|
if (dwBytesRead)
|
|
{
|
|
// Go though the list and try to find a match
|
|
for (int i=0;i<m_FileFormatVerifierList.Size();i++)
|
|
{
|
|
// If we found a match, we are done
|
|
if (m_FileFormatVerifierList[i].Match(m_pSignatureBuffer,dwBytesRead))
|
|
{
|
|
guidResult = m_FileFormatVerifierList[i].Format();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Close the file
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
// This will contain IID_NULL if no matching image type was found
|
|
return guidResult;
|
|
}
|
|
|
|
|
|
bool CImageFileFormatVerifier::IsImageFile( LPCTSTR pszFilename )
|
|
{
|
|
//WIA_PUSH_FUNCTION((TEXT("CImageFileFormatVerifier::IsImageFile(%s)"),pszFilename));
|
|
// Try to find the image type
|
|
GUID guidImageType = GetImageType(pszFilename);
|
|
|
|
//WIA_PRINTGUID((guidImageType,TEXT("guidImageType")));
|
|
|
|
// If the image type is IID_NULL, it isn't an image
|
|
return ((IID_NULL != guidImageType) != FALSE);
|
|
}
|
|
|