windows-nt/Source/XPSP1/NT/shell/ext/sshow/gphelper.cpp
2020-09-26 16:20:57 +08:00

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);
}