1777 lines
58 KiB
C++
1777 lines
58 KiB
C++
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
|
|
*
|
|
* TITLE: GPHELPER.CPP
|
|
*
|
|
* VERSION: 1.0
|
|
*
|
|
* AUTHOR: ShaunIv
|
|
*
|
|
* DATE: 10/11/1999
|
|
*
|
|
* DESCRIPTION: Encapsulation of common GDI plus operationss
|
|
*
|
|
*******************************************************************************/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "gphelper.h"
|
|
#include <wiadebug.h>
|
|
#include <psutil.h>
|
|
|
|
using namespace Gdiplus;
|
|
|
|
CGdiPlusHelper::CGdiPlusHelper(void)
|
|
: m_pImageEncoderInfo(NULL),
|
|
m_nImageEncoderCount(0),
|
|
m_pImageDecoderInfo(NULL),
|
|
m_nImageDecoderCount(0)
|
|
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
|
|
CGdiPlusHelper::~CGdiPlusHelper(void)
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::Initialize(void)
|
|
{
|
|
WIA_PUSHFUNCTION(TEXT("CGdiPlusHelper::Initialize"));
|
|
|
|
|
|
//
|
|
// Get the installed encoders
|
|
//
|
|
UINT cbCodecs = 0;
|
|
HRESULT hr = GDISTATUS_TO_HRESULT(GetImageEncodersSize( &m_nImageEncoderCount, &cbCodecs ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (cbCodecs)
|
|
{
|
|
m_pImageEncoderInfo = static_cast<ImageCodecInfo*>(LocalAlloc(LPTR,cbCodecs));
|
|
if (m_pImageEncoderInfo)
|
|
{
|
|
hr = GDISTATUS_TO_HRESULT(GetImageEncoders( m_nImageEncoderCount, cbCodecs, m_pImageEncoderInfo ));
|
|
if (FAILED(hr))
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetImageEncoders failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
WIA_PRINTHRESULT((hr,TEXT("LocalAlloc failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
WIA_PRINTHRESULT((hr,TEXT("GetImageEncodersSize succeeded, but cbCodecs was 0")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetImageEncodersSize failed")));
|
|
}
|
|
|
|
//
|
|
// Get the installed decoders
|
|
//
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
cbCodecs = 0;
|
|
hr = GDISTATUS_TO_HRESULT(GetImageDecodersSize( &m_nImageDecoderCount, &cbCodecs ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (cbCodecs)
|
|
{
|
|
m_pImageDecoderInfo = static_cast<ImageCodecInfo*>(LocalAlloc(LPTR,cbCodecs));
|
|
if (m_pImageDecoderInfo)
|
|
{
|
|
hr = GDISTATUS_TO_HRESULT(GetImageDecoders( m_nImageDecoderCount, cbCodecs, m_pImageDecoderInfo ));
|
|
if (FAILED(hr))
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetImageDecoders failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
WIA_PRINTHRESULT((hr,TEXT("LocalAlloc failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
WIA_PRINTHRESULT((hr,TEXT("GetImageDecodersSize succeeded, but cbCodecs was 0")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetImageDecodersSize failed")));
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there was a problem, make sure there are no half-initialized things laying around
|
|
//
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
Destroy();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
void CGdiPlusHelper::Destroy(void)
|
|
{
|
|
|
|
#if defined(GDIPLUSHELPER_EXPLICIT_INITIALIZATION)
|
|
//
|
|
// Shut down GDI+
|
|
//
|
|
if (m_bGdiplusInitialized)
|
|
{
|
|
|
|
}
|
|
#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::GetClsidOfEncoder( const GUID &guidFormatId, CLSID &clsidFormat ) const
|
|
{
|
|
//
|
|
// Given an image format, find the clsid for the output type
|
|
//
|
|
if (IsValid())
|
|
{
|
|
for (UINT i=0;i<m_nImageEncoderCount;i++)
|
|
{
|
|
if (m_pImageEncoderInfo[i].FormatID == guidFormatId)
|
|
{
|
|
clsidFormat = m_pImageEncoderInfo[i].Clsid;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::GetClsidOfDecoder( const GUID &guidFormatId, CLSID &clsidFormat ) const
|
|
{
|
|
//
|
|
// Given an image format, find the clsid for the output type
|
|
//
|
|
if (IsValid())
|
|
{
|
|
for (UINT i=0;i<m_nImageDecoderCount;i++)
|
|
{
|
|
if (m_pImageDecoderInfo[i].FormatID == guidFormatId)
|
|
{
|
|
clsidFormat = m_pImageDecoderInfo[i].Clsid;
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::Convert( LPCWSTR pszInputFilename, LPCWSTR pszOutputFilename, const CLSID &guidOutputFormat ) const
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CGdiPlusHelper::Convert( %ws, %ws )"), pszInputFilename, pszOutputFilename ));
|
|
WIA_PRINTGUID((guidOutputFormat,TEXT("guidOutputFormat")));
|
|
|
|
HRESULT hr;
|
|
|
|
if (IsValid())
|
|
{
|
|
//
|
|
// Open the source image
|
|
//
|
|
Image SourceImage(pszInputFilename);
|
|
|
|
//
|
|
// Make sure it was valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the correct encoder
|
|
//
|
|
CLSID clsidEncoder;
|
|
hr = GetClsidOfEncoder( guidOutputFormat, clsidEncoder );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Save the image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.Save( pszOutputFilename, &clsidEncoder, NULL ));
|
|
if (FAILED(hr))
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetLastError() after Save()")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetClsidOfEncoder() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceImage.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("IsValid() returned false")));
|
|
hr = E_FAIL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT CGdiPlusHelper::Rotate( LPCWSTR pszInputFilename, LPCWSTR pszOutputFilename, int nRotationAngle, const CLSID &guidOutputFormat ) const
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CGdiPlusHelper::Rotate( %ws, %ws, %d )"), pszInputFilename, pszOutputFilename, nRotationAngle ));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (IsValid())
|
|
{
|
|
//
|
|
// Open the source image
|
|
//
|
|
Image SourceImage(pszInputFilename);
|
|
|
|
//
|
|
// Make sure it was valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Figure out what the output format should be. If it is IID_NULL, change it to the same format as the input format
|
|
//
|
|
GUID OutputFormat = guidOutputFormat;
|
|
if (OutputFormat == IID_NULL)
|
|
{
|
|
//
|
|
// Find the input format
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.GetRawFormat(&OutputFormat));
|
|
if (FAILED(hr))
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceImage.GetRawFormat() failed")));
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the encoder for this format
|
|
//
|
|
CLSID clsidEncoder;
|
|
hr = GetClsidOfEncoder( OutputFormat, clsidEncoder );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Lossless rotation for JPEGs...
|
|
//
|
|
if (ImageFormatJPEG == OutputFormat && (SourceImage.GetWidth() % 8 == 0) && (SourceImage.GetHeight() % 8 == 0))
|
|
{
|
|
WIA_TRACE((TEXT("Performing lossless rotation")));
|
|
LONG nTransform = 0;
|
|
|
|
//
|
|
// Which transform should we use?
|
|
//
|
|
switch (nRotationAngle % 360)
|
|
{
|
|
case 90:
|
|
case -270:
|
|
nTransform = EncoderValueTransformRotate90;
|
|
break;
|
|
|
|
case 180:
|
|
case -180:
|
|
nTransform = EncoderValueTransformRotate180;
|
|
break;
|
|
|
|
case 270:
|
|
case -90:
|
|
nTransform = EncoderValueTransformRotate270;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the transform is zero, an invalid rotation angle was specified
|
|
//
|
|
if (nTransform)
|
|
{
|
|
//
|
|
// Fill out the EncoderParameters for lossless JPEG rotation
|
|
//
|
|
EncoderParameters EncoderParams = {0};
|
|
EncoderParams.Parameter[0].Guid = Gdiplus::EncoderTransformation;
|
|
EncoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
|
|
EncoderParams.Parameter[0].NumberOfValues = 1;
|
|
EncoderParams.Parameter[0].Value = &nTransform;
|
|
EncoderParams.Count = 1;
|
|
|
|
//
|
|
// Save the image to the target file
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.Save( pszOutputFilename, &clsidEncoder, &EncoderParams ));
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Non-JPEG rotation, or rotation of JPEG files with non-standard sizes
|
|
//
|
|
else
|
|
{
|
|
WIA_TRACE((TEXT("Performing normal rotation")));
|
|
|
|
//
|
|
// Figure out which rotation flag to use
|
|
//
|
|
RotateFlipType rotateFlipType = RotateNoneFlipNone;
|
|
switch (nRotationAngle % 360)
|
|
{
|
|
case 90:
|
|
case -270:
|
|
rotateFlipType = Rotate90FlipNone;
|
|
break;
|
|
|
|
case 180:
|
|
case -180:
|
|
rotateFlipType = Rotate180FlipNone;
|
|
break;
|
|
|
|
case 270:
|
|
case -90:
|
|
rotateFlipType = Rotate270FlipNone;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure we have a valid rotation angle
|
|
//
|
|
if (rotateFlipType)
|
|
{
|
|
//
|
|
// Rotate the image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.RotateFlip(rotateFlipType));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Save the image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.Save( pszOutputFilename, &clsidEncoder, NULL ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid rotation specified (%d)"), nRotationAngle));
|
|
hr = E_FAIL;
|
|
}
|
|
} // End else if non JPEG
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetClsidOfEncoder failed")));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceImage.GetLastStatus()")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("IsValid() returned false")));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
WIA_PRINTHRESULT((hr,TEXT("Returning")));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT CGdiPlusHelper::Rotate( HBITMAP hSourceBitmap, HBITMAP &hTargetBitmap, int nRotationAngle ) const
|
|
{
|
|
//
|
|
// Initialize the result to NULL
|
|
//
|
|
hTargetBitmap = NULL;
|
|
|
|
//
|
|
// Assume failure
|
|
//
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Make sure we are in a valid state
|
|
//
|
|
if (IsValid())
|
|
{
|
|
//
|
|
// Make sure we have a valid source bitmap
|
|
//
|
|
if (hSourceBitmap)
|
|
{
|
|
//
|
|
// If we are rotating by 0 degrees, just copy the image
|
|
//
|
|
if (!nRotationAngle)
|
|
{
|
|
hTargetBitmap = reinterpret_cast<HBITMAP>(CopyImage( hSourceBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ));
|
|
if (hTargetBitmap)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
WIA_PRINTHRESULT((hr,TEXT("CopyImage failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create the source bitmap. No palette required, we assume it will always be a 24bit DIB.
|
|
//
|
|
Bitmap SourceBitmap( hSourceBitmap, NULL );
|
|
hr = GDISTATUS_TO_HRESULT(SourceBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// 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 target width and height are zero, so we can detect invalid rotation angles
|
|
//
|
|
UINT nTargetWidth = 0;
|
|
UINT nTargetHeight = 0;
|
|
RotateFlipType rotateFlipType = RotateNoneFlipNone;
|
|
|
|
//
|
|
// Find the transformation matrix for this rotation
|
|
//
|
|
switch (nRotationAngle % 360)
|
|
{
|
|
case -270:
|
|
case 90:
|
|
rotateFlipType = Rotate90FlipNone;
|
|
nTargetWidth = nSourceHeight;
|
|
nTargetHeight = nSourceWidth;
|
|
break;
|
|
|
|
case -180:
|
|
case 180:
|
|
rotateFlipType = Rotate180FlipNone;
|
|
nTargetWidth = nSourceWidth;
|
|
nTargetHeight = nSourceHeight;
|
|
break;
|
|
|
|
case -90:
|
|
case 270:
|
|
rotateFlipType = Rotate270FlipNone;
|
|
nTargetWidth = nSourceHeight;
|
|
nTargetHeight = nSourceWidth;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If either of these are zero, that means an invalid rotation was supplied
|
|
//
|
|
if (nTargetWidth && nTargetHeight)
|
|
{
|
|
//
|
|
// Rotate the image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceBitmap.RotateFlip(rotateFlipType));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Create the target bitmap and make sure it succeeded
|
|
//
|
|
Bitmap TargetBitmap( nTargetWidth, nTargetHeight );
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get a graphics to render to
|
|
//
|
|
Graphics *pGraphics = Graphics::FromImage(&TargetBitmap);
|
|
if (pGraphics)
|
|
{
|
|
//
|
|
// Make sure it is valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Draw image rotated to the graphics
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->DrawImage(&SourceBitmap,0,0));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the HBITMAP
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetHBITMAP( Color::Black, &hTargetBitmap ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (!hTargetBitmap)
|
|
{
|
|
WIA_ERROR((TEXT("hTargetBitmap was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Clean up our dynamically allocated graphics
|
|
//
|
|
delete pGraphics;
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pGraphics was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("TargetBitmap.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceBitmap.RotateFlip() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid Target Bitmap Dimensions")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid Source Bitmap Dimensions")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceBitmap.GetLastStatus() failed")));
|
|
}
|
|
} // end else if nRotationAngle != 0
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("hSourceBitmap was NULL")));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("IsValid() failed")));
|
|
}
|
|
|
|
WIA_PRINTHRESULT((hr,TEXT("Returning")));
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::LoadAndScale( HBITMAP &hTargetBitmap, IStream *pStream, UINT nMaxWidth, UINT nMaxHeight, bool bStretchSmallImages )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
hTargetBitmap = NULL;
|
|
//
|
|
// Make sure we have a valid filename
|
|
//
|
|
if (pStream)
|
|
{
|
|
Bitmap SourceBitmap( pStream );
|
|
hr = GDISTATUS_TO_HRESULT(SourceBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// 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 (nMaxWidth > 0 && nMaxHeight > 0)
|
|
{
|
|
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 );
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get a graphics to render to
|
|
//
|
|
Graphics *pGraphics = Graphics::FromImage(&TargetBitmap);
|
|
if (pGraphics)
|
|
{
|
|
//
|
|
// Make sure it is valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Draw scaled image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->DrawImage(&SourceBitmap, 0, 0, nTargetWidth, nTargetHeight));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get an HBITMAP for this image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetHBITMAP( Color::Black, &hTargetBitmap ));
|
|
if (!hTargetBitmap)
|
|
{
|
|
WIA_ERROR((TEXT("hTargetBitmap was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("pGraphics->DrawImage failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("pGraphics->GetLastStatus() failed")));
|
|
}
|
|
//
|
|
// Clean up our dynamically allocated graphics
|
|
//
|
|
delete pGraphics;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
WIA_ERROR((TEXT("pGraphics was NULL")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("TargetBitmap.GetLastStatus() is not OK")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid Target Bitmap Dimensions (%d,%d)"), nTargetWidth, nTargetHeight));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid Source Bitmap Dimensions")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceBitmap.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pStream was NULL")));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::LoadAndScale( HBITMAP &hTargetBitmap, LPCTSTR pszFilename, UINT nMaxWidth, UINT nMaxHeight, bool bStretchSmallImages )
|
|
{
|
|
hTargetBitmap = NULL;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
//
|
|
// Make sure we have a valid filename
|
|
//
|
|
if (pszFilename && lstrlen(pszFilename))
|
|
{
|
|
Bitmap SourceBitmap( CSimpleStringConvert::WideString(CSimpleString(pszFilename) ) );
|
|
hr = GDISTATUS_TO_HRESULT(SourceBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// 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 (nMaxWidth > 0 && nMaxHeight > 0)
|
|
{
|
|
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 );
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get a graphics to render to
|
|
//
|
|
Graphics *pGraphics = Graphics::FromImage(&TargetBitmap);
|
|
if (pGraphics)
|
|
{
|
|
//
|
|
// Make sure it is valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Draw scaled image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->DrawImage(&SourceBitmap, 0, 0, nTargetWidth, nTargetHeight));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get an HBITMAP for this image
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetHBITMAP( Color::Black, &hTargetBitmap ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (!hTargetBitmap)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("TargetBitmap.GetHBITMAP failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pGraphics->DrawImage failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pGraphics->GetLastStatus() failed")));
|
|
}
|
|
//
|
|
// Clean up our dynamically allocated graphics
|
|
//
|
|
delete pGraphics;
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pGraphics was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("TargetBitmap.GetLastStatus() is not OK")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid Target Bitmap Dimensions (%d,%d)"), nTargetWidth, nTargetHeight));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Invalid Source Bitmap Dimensions")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceBitmap.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("hSourceBitmap was NULL")));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// 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 );
|
|
}
|
|
|
|
|
|
EncoderParameters *CGdiPlusHelper::AppendEncoderParameter( EncoderParameters *pEncoderParameters, const GUID &guidProp, ULONG nType, PVOID pVoid )
|
|
{
|
|
if (pEncoderParameters)
|
|
{
|
|
pEncoderParameters->Parameter[pEncoderParameters->Count].Guid = guidProp;
|
|
pEncoderParameters->Parameter[pEncoderParameters->Count].Type = nType;
|
|
pEncoderParameters->Parameter[pEncoderParameters->Count].NumberOfValues = 1;
|
|
pEncoderParameters->Parameter[pEncoderParameters->Count].Value = pVoid;
|
|
pEncoderParameters->Count++;
|
|
}
|
|
return pEncoderParameters;
|
|
}
|
|
|
|
HRESULT CGdiPlusHelper::SaveMultipleImagesAsMultiPage( const CSimpleDynamicArray<CSimpleStringWide> &Filenames, const CSimpleStringWide &strFilename, const GUID &guidOutputFormat )
|
|
{
|
|
//
|
|
// Assume failure
|
|
//
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Parameters used in the encoder
|
|
//
|
|
ULONG nEncoderValueMultiFrame = EncoderValueMultiFrame;
|
|
ULONG nEncoderValueFrameDimensionPage = EncoderValueFrameDimensionPage;
|
|
ULONG nEncoderValueLastFrame = EncoderValueLastFrame;
|
|
|
|
//
|
|
// Make sure we have some files
|
|
//
|
|
if (Filenames.Size())
|
|
{
|
|
//
|
|
// Get the encoder
|
|
//
|
|
CLSID clsidEncoder = IID_NULL;
|
|
hr = GetClsidOfEncoder( guidOutputFormat, clsidEncoder );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Open the first image
|
|
//
|
|
Image SourceImage( Filenames[0] );
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
EncoderParameters encoderParameters = {0};
|
|
if (Filenames.Size() > 1)
|
|
{
|
|
AppendEncoderParameter( &encoderParameters, EncoderSaveFlag, EncoderParameterValueTypeLong, &nEncoderValueMultiFrame );
|
|
}
|
|
|
|
//
|
|
// Save the first page
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.Save( strFilename, &clsidEncoder, &encoderParameters ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Save each additional page
|
|
//
|
|
for (int i=1;i<Filenames.Size() && SUCCEEDED(hr);i++)
|
|
{
|
|
//
|
|
// Create the additional page
|
|
//
|
|
Image AdditionalPage(Filenames[i]);
|
|
|
|
//
|
|
// Make sure it succeeded
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(AdditionalPage.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Prepare the encoder parameters
|
|
//
|
|
EncoderParameters encoderParameters[2] = {0};
|
|
AppendEncoderParameter( encoderParameters, EncoderSaveFlag, EncoderParameterValueTypeLong, &nEncoderValueFrameDimensionPage );
|
|
|
|
//
|
|
// If this is the last page, append the "last frame" parameter
|
|
//
|
|
if (i == Filenames.Size()-1)
|
|
{
|
|
AppendEncoderParameter( encoderParameters, EncoderSaveFlag, EncoderParameterValueTypeLong, &nEncoderValueLastFrame );
|
|
}
|
|
|
|
//
|
|
// Try to add a page
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(SourceImage.SaveAdd( &AdditionalPage, encoderParameters ));
|
|
if (FAILED(hr))
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceImage.SaveAdd failed!")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("AdditionalPage.GetLastStatus failed!")));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceImage.Save failed!")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceImage.GetLastStatus failed!")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("GetClsidOfEncoder failed!")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("Filenames.Size was 0!")));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
static void CalculateBrightnessAndContrastParams( BYTE iBrightness, BYTE iContrast, float *scale, float *translate )
|
|
{
|
|
//
|
|
// force values to be at least 1, to avoid undesired effects
|
|
//
|
|
if (iBrightness < 1)
|
|
{
|
|
iBrightness = 1;
|
|
}
|
|
if (iContrast < 1)
|
|
{
|
|
iContrast = 1;
|
|
}
|
|
|
|
//
|
|
// get current brightness as a percentage of full scale
|
|
//
|
|
float fBrightness = (float)( 100 - iBrightness ) / 100.0f;
|
|
if (fBrightness > 0.95f)
|
|
{
|
|
fBrightness = 0.95f; /* clamp */
|
|
}
|
|
|
|
//
|
|
// get current contrast as a percentage of full scale
|
|
//
|
|
float fContrast = (float) iContrast / 100.0f;
|
|
if (fContrast > 1.0f)
|
|
{
|
|
fContrast = 1.0; /* limit to 1.0 */
|
|
}
|
|
|
|
//
|
|
// convert contrast to a scale value
|
|
//
|
|
if (fContrast <= 0.5f)
|
|
{
|
|
*scale = fContrast / 0.5f; /* 0 -> 0, .5 -> 1.0 */
|
|
}
|
|
else
|
|
{
|
|
if (fContrast == 1.0f)
|
|
{
|
|
fContrast = 0.9999f;
|
|
}
|
|
*scale = 0.5f / (1.0f - fContrast); /* .5 -> 1.0, 1.0 -> inf */
|
|
}
|
|
|
|
*translate = 0.5f - *scale * fBrightness;
|
|
}
|
|
|
|
|
|
HRESULT CGdiPlusHelper::SetBrightnessAndContrast( HBITMAP hSourceBitmap, HBITMAP &hTargetBitmap, BYTE nBrightness, BYTE nContrast )
|
|
{
|
|
WIA_TRACE((TEXT("nBrightness: %d, nContrast: %d"), nBrightness, nContrast ));
|
|
//
|
|
// Initialize the result to NULL
|
|
//
|
|
hTargetBitmap = NULL;
|
|
|
|
//
|
|
// Assume failure
|
|
//
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Make sure we are in a valid state
|
|
//
|
|
if (IsValid())
|
|
{
|
|
//
|
|
// Make sure we have a valid source bitmap
|
|
//
|
|
if (hSourceBitmap)
|
|
{
|
|
//
|
|
// Create the source bitmap. No palette required, we assume it will always be a 24bit DIB.
|
|
//
|
|
Bitmap SourceBitmap( hSourceBitmap, NULL );
|
|
|
|
hr = GDISTATUS_TO_HRESULT(SourceBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Create the target bitmap and make sure it succeeded
|
|
//
|
|
Bitmap TargetBitmap( SourceBitmap.GetWidth(), SourceBitmap.GetHeight() );
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get a graphics to render to
|
|
//
|
|
Graphics *pGraphics = Graphics::FromImage(&TargetBitmap);
|
|
if (pGraphics)
|
|
{
|
|
//
|
|
// Make sure it is valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ImageAttributes imageAttributes;
|
|
|
|
//
|
|
// Calculate the values needed for the matrix
|
|
//
|
|
REAL scale = 0.0;
|
|
REAL trans = 0.0;
|
|
CalculateBrightnessAndContrastParams( nBrightness, nContrast, &scale, &trans );
|
|
|
|
//
|
|
// Prepare the matrix for brightness and contrast transforms
|
|
//
|
|
ColorMatrix brightnessAndContrast = {scale, 0, 0, 0, 0,
|
|
0, scale, 0, 0, 0,
|
|
0, 0, scale, 0, 0,
|
|
0, 0, 0, 1, 0,
|
|
trans, trans, trans, 0, 1};
|
|
|
|
imageAttributes.SetColorMatrix(&brightnessAndContrast);
|
|
|
|
Rect rect( 0, 0, SourceBitmap.GetWidth(), SourceBitmap.GetHeight() );
|
|
|
|
|
|
//
|
|
// Draw the transformed image on the graphics
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->DrawImage(&SourceBitmap,rect,0,0,SourceBitmap.GetWidth(), SourceBitmap.GetHeight(),UnitPixel,&imageAttributes));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the HBITMAP
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetHBITMAP( Color::Black, &hTargetBitmap ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (!hTargetBitmap)
|
|
{
|
|
WIA_ERROR((TEXT("hTargetBitmap was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("Bitmap::GetHBITMAP failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("pGraphics->DrawImage failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("pGraphics->GetLastStatus() failed")));
|
|
}
|
|
//
|
|
// Clean up our dynamically allocated graphics
|
|
//
|
|
delete pGraphics;
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pGraphics was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("TargetBitmap.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceBitmap.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("hSourceBitmap was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("IsValid() returned false")));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
WIA_PRINTHRESULT((hr,TEXT("Returning")));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT CGdiPlusHelper::SetThreshold( HBITMAP hSourceBitmap, HBITMAP &hTargetBitmap, BYTE nThreshold )
|
|
{
|
|
//
|
|
// Initialize the result to NULL
|
|
//
|
|
hTargetBitmap = NULL;
|
|
|
|
//
|
|
// Assume failure
|
|
//
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Make sure we are in a valid state
|
|
//
|
|
if (IsValid())
|
|
{
|
|
//
|
|
// Make sure we have a valid source bitmap
|
|
//
|
|
if (hSourceBitmap)
|
|
{
|
|
//
|
|
// Create the source bitmap. No palette required, we assume it will always be a 24bit DIB.
|
|
//
|
|
Bitmap SourceBitmap( hSourceBitmap, NULL );
|
|
hr = GDISTATUS_TO_HRESULT(SourceBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Create the target bitmap and make sure it succeeded
|
|
//
|
|
Bitmap TargetBitmap( SourceBitmap.GetWidth(), SourceBitmap.GetHeight() );
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get a graphics to render to
|
|
//
|
|
Graphics *pGraphics = Graphics::FromImage(&TargetBitmap);
|
|
if (pGraphics)
|
|
{
|
|
//
|
|
// Make sure it is valid
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->GetLastStatus());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ImageAttributes imageAttributes;
|
|
imageAttributes.SetThreshold(static_cast<double>(100-nThreshold)/100);
|
|
|
|
Rect rect( 0, 0, SourceBitmap.GetWidth(), SourceBitmap.GetHeight() );
|
|
|
|
|
|
//
|
|
// Draw image rotated to the graphics
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(pGraphics->DrawImage(&SourceBitmap,rect,0,0,SourceBitmap.GetWidth(), SourceBitmap.GetHeight(),UnitPixel,&imageAttributes));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the HBITMAP
|
|
//
|
|
hr = GDISTATUS_TO_HRESULT(TargetBitmap.GetHBITMAP( Color::Black, &hTargetBitmap ));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (!hTargetBitmap)
|
|
{
|
|
WIA_ERROR((TEXT("hTargetBitmap was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("Bitmap::GetHBITMAP failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("pGraphics->DrawImage failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("pGraphics->GetLastStatus() failed")));
|
|
}
|
|
//
|
|
// Clean up our dynamically allocated graphics
|
|
//
|
|
delete pGraphics;
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pGraphics was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_PRINTHRESULT((hr,TEXT("SourceBitmap.GetLastStatus() failed")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("hSourceBitmap was NULL")));
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
WIA_PRINTHRESULT((hr,TEXT("Returning")));
|
|
return hr;
|
|
}
|
|
|
|
|
|
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 = NULL;
|
|
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
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CImageFileFormatVerifierItem::Match")));
|
|
WIA_PRINTGUID((m_clsidDecoder,TEXT("Decoder")));
|
|
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( IStream * pStream )
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CImageFileFormatVerifier::GetImageType( via IStream )")));
|
|
//
|
|
// Assume we will not find a match
|
|
//
|
|
GUID guidResult = IID_NULL;
|
|
|
|
//
|
|
// Make sure we have a valid IStream object...
|
|
//
|
|
if (pStream)
|
|
{
|
|
//
|
|
// Read the maximum signature length number of bytes
|
|
//
|
|
ULONG uBytesRead = 0;
|
|
HRESULT hr = pStream->Read( m_pSignatureBuffer, m_nMaxSignatureLength, &uBytesRead );
|
|
|
|
//
|
|
// Make sure we got some bytes
|
|
//
|
|
if (SUCCEEDED(hr) && uBytesRead)
|
|
{
|
|
//
|
|
// 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,uBytesRead))
|
|
{
|
|
guidResult = m_FileFormatVerifierList[i].Format();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pStream->Read() failed w/hr = 0x%x"),hr));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIA_ERROR((TEXT("pStream was NULL")));
|
|
}
|
|
|
|
//
|
|
// 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));
|
|
|
|
GUID guidImageType = IID_NULL;
|
|
|
|
//
|
|
// Get a stream object over the file...
|
|
//
|
|
|
|
IStream * pStream = NULL;
|
|
HRESULT hr = SHCreateStreamOnFile(pszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pStream );
|
|
|
|
if (SUCCEEDED(hr) && pStream)
|
|
{
|
|
guidImageType = GetImageType(pStream);
|
|
}
|
|
|
|
if (pStream)
|
|
{
|
|
pStream->Release();
|
|
}
|
|
|
|
WIA_PRINTGUID((guidImageType,TEXT("guidImageType")));
|
|
|
|
//
|
|
// If the image type is IID_NULL, it isn't an image
|
|
//
|
|
return ((IID_NULL != guidImageType) != FALSE);
|
|
}
|
|
|
|
|
|
bool CImageFileFormatVerifier::IsSupportedImageFromStream( IStream * pStream, GUID * pGuidOfFormat )
|
|
{
|
|
WIA_PUSH_FUNCTION((TEXT("CImageFileFormatVerifier::IsSupportedImageFromStream()")));
|
|
|
|
GUID guidImageType = IID_NULL;
|
|
|
|
//
|
|
// Get an IStream pointer for this file...
|
|
//
|
|
|
|
if (pStream)
|
|
{
|
|
guidImageType = GetImageType(pStream);
|
|
}
|
|
|
|
WIA_PRINTGUID((guidImageType,TEXT("guidImageType")));
|
|
|
|
if (pGuidOfFormat)
|
|
{
|
|
*pGuidOfFormat = guidImageType;
|
|
}
|
|
|
|
//
|
|
// If the image type is IID_NULL, it isn't an image
|
|
//
|
|
return ((IID_NULL != guidImageType) != FALSE);
|
|
}
|
|
|
|
CGdiPlusInit::CGdiPlusInit()
|
|
: m_pGdiplusToken(NULL)
|
|
{
|
|
//
|
|
// Make sure GDI+ is initialized
|
|
//
|
|
GdiplusStartupInput StartupInput;
|
|
GdiplusStartup(&m_pGdiplusToken,&StartupInput,NULL);
|
|
}
|
|
|
|
CGdiPlusInit::~CGdiPlusInit()
|
|
{
|
|
GdiplusShutdown(m_pGdiplusToken);
|
|
}
|