|
|
/*****************************************************************************
* * (C) COPYRIGHT MICROSOFT CORPORATION, 2000 * * TITLE: item.cpp * * VERSION: 1.0 * * AUTHOR: RickTu * * DATE: 10/18/00 * * DESCRIPTION: Implements an item class that encapsulates the photos * we are dealing with. * *****************************************************************************/
#include <precomp.h>
#pragma hdrstop
/*****************************************************************************
_ScaleImage
Scales src rect to fit into dest rect while preserving aspect ratio
*****************************************************************************/
HRESULT _ScaleImage( Gdiplus::Rect * pSrc, Gdiplus::Rect * pDest ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("_ScaleImage()")));
if (!pDest || !pSrc) { WIA_ERROR((TEXT("_ScaleImage: bad params, exiting early!"))); return E_INVALIDARG; }
WIA_TRACE((TEXT("_ScaleImage: src before scaling: (%d, %d) @ (%d, %d)"), pSrc->Width, pSrc->Height, pSrc->X, pSrc->Y));
//
// Scale without any crop
//
SIZE sizeNew; INT NewX = pDest->X, NewY = pDest->Y;
WIA_TRACE((TEXT("_ScaleImage: dest before scaling: (%d, %d) @ (%d, %d)"),pDest->Width, pDest->Height, pDest->X, pDest->Y));
sizeNew = PrintScanUtil::ScalePreserveAspectRatio( pDest->Width, pDest->Height, pSrc->Width, pSrc->Height );
NewX += ((pDest->Width - sizeNew.cx) / 2); NewY += ((pDest->Height - sizeNew.cy) / 2);
pDest->X = NewX; pDest->Y = NewY; pDest->Width = sizeNew.cx; pDest->Height = sizeNew.cy;
WIA_TRACE((TEXT("_ScaleImage: dest after scaling: (%d, %d) @ (%d, %d)"),pDest->Width, pDest->Height, pDest->X, pDest->Y));
return S_OK; }
/*****************************************************************************
_CropImage
Scales src rect to fit into dest rect while preserving aspect ratio
*****************************************************************************/
HRESULT _CropImage( Gdiplus::Rect * pSrc, Gdiplus::Rect * pDest ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("_CropImage()")));
if (!pDest || !pSrc) { WIA_ERROR((TEXT("_CropImage: bad params, exiting early!"))); return E_INVALIDARG; }
WIA_TRACE((TEXT("_CropImage: pDest before cropping: (%d, %d) @ (%d, %d)"), pDest->Width, pDest->Height, pDest->X, pDest->Y));
//
// Scale without any crop
//
SIZE sizeNew; INT NewX = pSrc->X, NewY = pSrc->Y;
WIA_TRACE((TEXT("_CropImage: pSrc before cropping: (%d, %d) @ (%d, %d)"),pSrc->Width, pSrc->Height, pSrc->X, pSrc->Y));
sizeNew = PrintScanUtil::ScalePreserveAspectRatio( pSrc->Width, pSrc->Height, pDest->Width, pDest->Height );
NewX += ((pSrc->Width - sizeNew.cx) / 2); NewY += ((pSrc->Height - sizeNew.cy) / 2);
pSrc->X = NewX; pSrc->Y = NewY; pSrc->Width = sizeNew.cx; pSrc->Height = sizeNew.cy;
WIA_TRACE((TEXT("_CropImage: pSrc after cropping: (%d, %d) @ (%d, %d)"),pSrc->Width, pSrc->Height, pSrc->X, pSrc->Y));
return S_OK; }
/*****************************************************************************
_GetImageDimensions
Given a GDI+ image object, return the dimensions in the given rectangle...
*****************************************************************************/
HRESULT _GetImageDimensions( Gdiplus::Image * pImage, Gdiplus::RectF &rect, Gdiplus::REAL &scalingFactorForY ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("_GetImageDimensions()")));
if (!pImage) { WIA_ERROR((TEXT("_GetImageDimensions: bad params, exiting early!"))); return E_INVALIDARG; }
Gdiplus::Unit Unit;
HRESULT hr = Gdiplus2HRESULT( pImage->GetBounds( &rect, &Unit ) );
if (FAILED(hr)) { //
// Try the old fashioned way...
//
rect.X = (Gdiplus::REAL)0.0; rect.Y = (Gdiplus::REAL)0.0;
rect.Width = (Gdiplus::REAL)pImage->GetWidth(); hr = Gdiplus2HRESULT( pImage->GetLastStatus() ); WIA_CHECK_HR(hr,"_GetImageDimensions: GetWidth failed!"); if (SUCCEEDED(hr)) { rect.Height = (Gdiplus::REAL)pImage->GetHeight(); hr = Gdiplus2HRESULT( pImage->GetLastStatus() ); WIA_CHECK_HR(hr,"_GetImageDimensions: GetHeight failed!"); } } else { if (Unit != Gdiplus::UnitPixel) { hr = S_FALSE; } }
Gdiplus::REAL xDPI = pImage->GetHorizontalResolution(); Gdiplus::REAL yDPI = pImage->GetVerticalResolution();
if (yDPI) { scalingFactorForY = xDPI / yDPI; } else { scalingFactorForY = (Gdiplus::REAL)1.0; }
WIA_RETURN_HR(hr); }
/*****************************************************************************
CPhotoItem -- constructors/desctructor
<Notes>
*****************************************************************************/
CPhotoItem::CPhotoItem( LPITEMIDLIST pidlFull ) : _pidlFull(NULL), _pImage(NULL), _lFrameCount(-1), _bTimeFrames(FALSE), _pAnnotations(NULL), _pAnnotBits(NULL), _bWeKnowAnnotationsDontExist(FALSE), _pThumbnails(NULL), _cRef(0), _llFileSize(0), _uImageType(DontKnowImageType), _DPIx((Gdiplus::REAL)0.0), _DPIy((Gdiplus::REAL)0.0) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM, TEXT("CPhotoItem::CPhotoItem( fully qualified pidl )")));
if (pidlFull) { _pidlFull = ILClone( pidlFull ); WIA_TRACE((TEXT("_pidlFull = 0x%x"),_pidlFull)); }
*_szFileName = 0;
//
// Get just file name from the pidl
//
SHFILEINFO fi = {0};
if (SHGetFileInfo( (LPCTSTR)pidlFull, 0, &fi, sizeof(fi), SHGFI_DISPLAYNAME| SHGFI_PIDL )) { lstrcpyn( _szFileName, fi.szDisplayName, ARRAYSIZE(_szFileName) ); }
}
CPhotoItem::~CPhotoItem() { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM, TEXT("CPhotoItem::~CPhotoItem()")));
CAutoCriticalSection lock( _csItem );
//
// Free pidl for item
//
if (_pidlFull) { WIA_TRACE((TEXT("_pidlFull = 0x%x"),_pidlFull)); ILFree( _pidlFull ); _pidlFull = NULL; }
//
// Free GDI+ icon
//
if (_pClassBitmap) { delete _pClassBitmap; _pClassBitmap = NULL; }
//
// Free bitmaps of thumbnails
//
if (_pThumbnails) { for (INT i=0; i < _lFrameCount; i++) { if (_pThumbnails[i]) { DeleteObject( _pThumbnails[i] ); } }
delete _pThumbnails; _pThumbnails = NULL; }
//
// Destroy GDI+ backing images. This also destroys any
// annotation data we have...
//
_DiscardGdiPlusImages();
}
/*****************************************************************************
CPhotoItem IUnknown methods
<Notes>
*****************************************************************************/
ULONG CPhotoItem::AddRef() { LONG l = InterlockedIncrement(&_cRef);
WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS,TEXT("CPhotoItem(0x%x)::AddRef( new count is %d )"),this,l));
if (l < 0) { return 0; }
return (ULONG)l; }
ULONG CPhotoItem::Release() { LONG l = InterlockedDecrement(&_cRef);
WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS,TEXT("CPhotoItem(0x%x)::Release( new count is %d )"),this,l));
if (l > 0) return (ULONG)l;
WIA_TRACE((TEXT("deleting object ( this == 0x%x ) because ref count is zero."),this)); delete this; return 0; }
ULONG CPhotoItem::ReleaseWithoutDeleting() { LONG l = InterlockedDecrement(&_cRef);
WIA_PUSH_FUNCTION_MASK((TRACE_REF_COUNTS,TEXT("CPhotoItem(0x%x)::Release( new count is %d )"),this,l));
return (ULONG)l; }
/*****************************************************************************
CPhotoItem::GetImageFrameCount
returns the number of frames (pages) in this image
*****************************************************************************/
HRESULT CPhotoItem::GetImageFrameCount(LONG * pFrameCount) {
WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::GetImageFrameCount(%s)"),_szFileName));
if (!pFrameCount) { return E_INVALIDARG; }
HRESULT hr = S_OK;
//
// Protect us as we go get info about the item...
//
CAutoCriticalSection lock(_csItem);
if (_lFrameCount == -1) { _lFrameCount = 1;
//
// Ensure the GDI+ image object has been created...this will also
// update the frame count...
//
hr = _CreateGdiPlusImage();
if (SUCCEEDED(hr) && _pImage) { LONG lPageFrames; LONG lTimeFrames;
lPageFrames = _pImage->GetFrameCount(&Gdiplus::FrameDimensionPage); lTimeFrames = _pImage->GetFrameCount(&Gdiplus::FrameDimensionTime);
if ((lPageFrames > 0) && (lTimeFrames <= 1)) { _lFrameCount = lPageFrames; } else if (lTimeFrames > 0) { //
// This is an animated GIF, report only 1 frame...
//
_lFrameCount = 1; _bTimeFrames = TRUE; } else { _lFrameCount = 1; }
}
}
*pFrameCount = ((_lFrameCount == -1) ? 0 : _lFrameCount);
WIA_TRACE((TEXT("%s: returning _FrameCount = %d"),_szFileName,*pFrameCount));
return hr; }
/*****************************************************************************
CPhotoItem::GetClassBitmap
Returns default icon for class (.jpg, .bmp, etc) for this item...
*****************************************************************************/
HBITMAP CPhotoItem::GetClassBitmap( const SIZE &sizeDesired ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::GetClassBitmap( %s, size = %d,%d "),_szFileName,sizeDesired.cx, sizeDesired.cy ));
HBITMAP hbmReturn = NULL;
CAutoCriticalSection lock(_csItem);
if (!_pClassBitmap) { //
// Get icon from shell
//
SHFILEINFO fi = {0};
if (SHGetFileInfo( (LPCTSTR)_pidlFull, 0, &fi, sizeof(fi), SHGFI_PIDL | SHGFI_SYSICONINDEX )) { //
// Get large (48 x 48) icon image list
//
IImageList * piml = NULL; if (SUCCEEDED(SHGetImageList( SHIL_EXTRALARGE, IID_IImageList, (void **)&piml )) && piml) {
HICON hIcon = NULL;
if (SUCCEEDED(piml->GetIcon( fi.iIcon, 0, &hIcon )) && hIcon) { //
// Got the ICON, create a bitmap for it...
//
hbmReturn = WiaUiUtil::CreateIconThumbnail( (HWND)NULL, 50, 60, hIcon, NULL );
if (hbmReturn) { _pClassBitmap = new Gdiplus::Bitmap( hbmReturn, NULL ); DeleteObject( hbmReturn ); hbmReturn = NULL; }
DestroyIcon( hIcon ); } piml->Release(); } } }
if (_pClassBitmap) { SIZE sizeDrawSize = {0};
//
// Scale image to fill thumbnail space while preserving
// aspect ratio...
//
sizeDrawSize = PrintScanUtil::ScalePreserveAspectRatio( sizeDesired.cx, sizeDesired.cy, _pClassBitmap->GetWidth(), _pClassBitmap->GetHeight() );
WIA_TRACE((TEXT("CPhotoItem::GetClassBitmap(%s) - _pClassBitmap( %d, %d )"),_szFileName,_pClassBitmap->GetWidth(), _pClassBitmap->GetHeight())); WIA_TRACE((TEXT("CPhotoItem::GetClassBitmap(%s) - sizeDesired( %d, %d )"),_szFileName,sizeDesired.cx, sizeDesired.cy)); WIA_TRACE((TEXT("CPhotoItem::GetClassBitmap(%s) - sizeDrawsize( %d, %d )"),_szFileName,sizeDrawSize.cx, sizeDrawSize.cy));
Gdiplus::Bitmap * pImage = new Gdiplus::Bitmap( sizeDesired.cx, sizeDesired.cy ); if (pImage) { HRESULT hr = Gdiplus2HRESULT(pImage->GetLastStatus()); if (SUCCEEDED(hr)) { //
// Get a graphics to render to
//
Graphics *pGraphics = Gdiplus::Graphics::FromImage((Gdiplus::Image *)pImage);
if (pGraphics) { hr = Gdiplus2HRESULT(pGraphics->GetLastStatus());
//
// Make sure it is valid
//
if (SUCCEEDED(hr)) { //
// erase the background of the image
//
pGraphics->Clear( g_wndColor );
//
// Set the interpolation mode to high quality
//
pGraphics->SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBicubic );
//
// Set the smoothing (anti-aliasing) mode to high quality as well
//
pGraphics->SetSmoothingMode( Gdiplus::SmoothingModeHighQuality );
//
// Draw scaled image
//
WIA_TRACE((TEXT("CPhotoItem::GetClassBitmap(%s) - calling pGraphics->DrawImage( _pClassBitmap, %d, %d, %d, %d )"),_szFileName,0 + ((sizeDesired.cx - sizeDrawSize.cx) / 2),0 + ((sizeDesired.cy - sizeDrawSize.cy) / 2),sizeDrawSize.cx,sizeDrawSize.cy));
hr = Gdiplus2HRESULT(pGraphics->DrawImage( _pClassBitmap, 0 + ((sizeDesired.cx - sizeDrawSize.cx) / 2), 0 + ((sizeDesired.cy - sizeDrawSize.cy) / 2), sizeDrawSize.cx, sizeDrawSize.cy ));
WIA_CHECK_HR(hr,"CPhotoItem::GetClassBitmap() - pGraphics->DrawImage( _pClassBitmap ) failed!");
if (SUCCEEDED(hr)) { pImage->GetHBITMAP( g_wndColor, &hbmReturn ); }
}
//
// Clean up our dynamically allocated graphics
//
delete pGraphics;
} else { WIA_ERROR((TEXT("CPhotoItem::GetClassBitmap(%s) - pGraphics was NULL!"),_szFileName)); hr = E_OUTOFMEMORY; } } else { WIA_ERROR((TEXT("CPhotoItem::GetClassBitmap(%s) - pImage failed to be created, hr = 0x%x"),hr)); }
delete pImage; }
}
return hbmReturn;
}
/*****************************************************************************
CPhotoItem::GetThumbnailBitmap
Given a DC and a desired size, return an HBITMAP of the thumbnail for a this item. The caller MUST free the HBITMAP returned from this function.
*****************************************************************************/
HBITMAP CPhotoItem::GetThumbnailBitmap( const SIZE &sizeDesired, LONG lFrame ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::GetThumbnailBitmap( %s, size = %d,%d "),_szFileName,sizeDesired.cx, sizeDesired.cy ));
HBITMAP hbmReturn = NULL; Gdiplus::Image * pImageToUse = NULL;
CAutoCriticalSection lock(_csItem);
//
// Make sure we have a thumbnail image for our photo...
//
_CreateGdiPlusThumbnail( sizeDesired, lFrame );
if (_pThumbnails && (lFrame < _lFrameCount) && _pThumbnails[lFrame]) { //
// Use bitmap to draw with instead of going to the file...
//
pImageToUse = (Gdiplus::Image *)(Gdiplus::Bitmap::FromHBITMAP( _pThumbnails[lFrame], NULL )); }
if (pImageToUse) { WIA_TRACE((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - pImageToUse is (%d x %d)"),_szFileName,pImageToUse->GetWidth(),pImageToUse->GetHeight()));
Gdiplus::Bitmap * pImage = new Gdiplus::Bitmap( sizeDesired.cx, sizeDesired.cy ); if (pImage) { HRESULT hr = Gdiplus2HRESULT(pImage->GetLastStatus()); if (SUCCEEDED(hr)) { //
// Get a graphics to render to
//
Graphics *pGraphics = Gdiplus::Graphics::FromImage((Gdiplus::Image *)pImage);
if (pGraphics) { hr = Gdiplus2HRESULT(pGraphics->GetLastStatus());
//
// Make sure it is valid
//
if (SUCCEEDED(hr)) { //
// compute how to scale the thumbnail image
//
SIZE sizeDrawSize = {0}; sizeDrawSize = PrintScanUtil::ScalePreserveAspectRatio( sizeDesired.cx, sizeDesired.cy, pImageToUse->GetWidth(), pImageToUse->GetHeight() );
//
// erase the background of the image
//
pGraphics->Clear( g_wndColor );
//
// Set the interpolation mode to high quality
//
pGraphics->SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear );
//
// Draw scaled image
//
WIA_TRACE((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - calling pGraphics->DrawImage( pImageToUse, %d, %d, %d, %d )"),_szFileName,0 + ((sizeDesired.cx - sizeDrawSize.cx) / 2),0 + ((sizeDesired.cy - sizeDrawSize.cy) / 2),sizeDrawSize.cx,sizeDrawSize.cy));
hr = Gdiplus2HRESULT(pGraphics->DrawImage( pImageToUse, 0 + ((sizeDesired.cx - sizeDrawSize.cx) / 2), 0 + ((sizeDesired.cy - sizeDrawSize.cy) / 2), sizeDrawSize.cx, sizeDrawSize.cy ));
WIA_CHECK_HR(hr,"CPhotoItem::GetThumbnailBitmap() - pGraphics->DrawImage( pImageToUse ) failed!");
if (SUCCEEDED(hr)) { pImage->GetHBITMAP( g_wndColor, &hbmReturn ); }
}
//
// Clean up our dynamically allocated graphics
//
delete pGraphics;
} else { WIA_ERROR((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - pGraphics was NULL!"),_szFileName)); hr = E_OUTOFMEMORY; } } else { WIA_ERROR((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - pImage failed to be created, hr = 0x%x"),hr)); }
delete pImage; }
//
// If we created an image to wrap the bitmap bits, then delete it...
//
if (pImageToUse) { delete pImageToUse; }
} else { WIA_ERROR((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - don't have stored thumbnail bitmap for this image!"),_szFileName)); }
return hbmReturn; }
/*****************************************************************************
CPhotoItem::_DoRotateAnnotations
This function requires that the annotation data be already set up and initialized. This is true for the _pImage object as well. This function will not initialize on the fly.
*****************************************************************************/
HRESULT CPhotoItem::_DoRotateAnnotations( BOOL bClockwise, UINT Flags ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_DoRotateAnnotations( %s, Flags = 0x%x )"),_szFileName,Flags));
if (!_pAnnotations) { WIA_RETURN_HR(E_INVALIDARG); }
if (!_pImage) { WIA_RETURN_HR(E_INVALIDARG); }
HRESULT hr; Gdiplus::REAL scaleY;
//
// Get width & height of backing image...
//
Gdiplus::RectF rectBounds; hr = _GetImageDimensions( _pImage, rectBounds, scaleY );
if (SUCCEEDED(hr)) { INT i = 0; CAnnotation * pA = NULL; INT iNewW = 0, iNewH = 0;
if ((Flags & RF_USE_THUMBNAIL_DATA) || (Flags & RF_USE_MEDIUM_QUALITY_DATA)) { //
// We flip here, because in the main _DoHandleRotation we only
// rotated the thumbnail data, so the backing image width & height
// haven't changed. It will be changed when we rotate to print, however,
// so feed the correct values to the annotation rotate code...
//
iNewW = (INT)rectBounds.Height; iNewH = (INT)rectBounds.Width; } else { iNewW = (INT)rectBounds.Width; iNewH = (INT)rectBounds.Height; }
WIA_TRACE((TEXT("CPhotoItem::_DoRotateAnnotations - bClockwise = %d, new width = %d, new height = %d"),bClockwise,iNewW,iNewH));
//
// rotate all the annotations
//
do { pA = _pAnnotations->GetAnnotation(i++);
if (pA) { pA->Rotate( iNewW, iNewH, bClockwise ); }
} while( pA );
}
WIA_RETURN_HR(hr); }
#define DO_CONVERT_GDIPLUS_STATUS(hr,status) if ( (status == Gdiplus::Ok) || \
(status == Gdiplus::OutOfMemory) || \ (status == Gdiplus::ObjectBusy) || \ (status == Gdiplus::FileNotFound) || \ (status == Gdiplus::AccessDenied) || \ (status == Gdiplus::Win32Error) \ ) \ { \ hr = Gdiplus2HRESULT( status ); \ }\ else \ {\ WIA_TRACE((TEXT("Mapping Gdiplus error %d to PPW_E_UNABLE_TO_ROTATE"),status));\ hr = PPW_E_UNABLE_TO_ROTATE;\ }
/*****************************************************************************
CPhotoItem::_DoHandleRotation
Handle rotating the image to render if/when needed or specified...
*****************************************************************************/
HRESULT CPhotoItem::_DoHandleRotation( Gdiplus::Image * pImage, Gdiplus::Rect &src, Gdiplus::Rect * pDest, UINT Flags, Gdiplus::REAL &ScaleFactorForY ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_DoHandleRotation( %s, Flags = 0x%x )"),_szFileName,Flags));
HRESULT hr = S_OK; Gdiplus::GpStatus status = Gdiplus::Ok;
if (Flags & RF_ROTATION_MASK) { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - A rotation flag was specified"),_szFileName)); if (Flags & RF_ROTATE_AS_NEEDED) { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - RF_ROTATE_AS_NEEDED was specified"),_szFileName));
//
// If the source and destination aspect ratios are on the opposite sides of 1.0,
// rotate the image 90 degrees
//
const DOUBLE srcAspect = (DOUBLE)src.Width / (DOUBLE)src.Height; const DOUBLE destAspect = (DOUBLE)pDest->Width / (DOUBLE)pDest->Height;
if((srcAspect >= (DOUBLE)1.0) ^ (destAspect >= (DOUBLE)1.0)) { //
// Rotate the image as needed...
//
if (Flags & RF_ROTATE_270) { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - Rotating Image 270 degrees"),_szFileName)); status = pImage->RotateFlip( Gdiplus::Rotate270FlipNone ); if (status == Gdiplus::Ok) { _DoRotateAnnotations( FALSE, Flags ); }
} else { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - Rotating Image 90 degrees"),_szFileName)); status = pImage->RotateFlip( Gdiplus::Rotate90FlipNone ); if (status == Gdiplus::Ok) { _DoRotateAnnotations( TRUE, Flags ); } }
//
// Map most of these error codes to UNABLE_TO_ROTATE...
//
DO_CONVERT_GDIPLUS_STATUS(hr,status) }
} else { //
// Rotate the image...
//
if (Flags & RF_ROTATE_90) { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - Rotating Image 90 degrees"),_szFileName)); status = pImage->RotateFlip( Gdiplus::Rotate90FlipNone ); if (status == Gdiplus::Ok) { _DoRotateAnnotations( TRUE, Flags ); } } else if (Flags & RF_ROTATE_180) { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - Rotating Image 180 degrees"),_szFileName)); status = pImage->RotateFlip( Gdiplus::Rotate180FlipNone );
if (status == Gdiplus::Ok) { //
// Rotate 90 degrees twice...
//
_DoRotateAnnotations( TRUE, Flags ); _DoRotateAnnotations( TRUE, Flags ); }
} else if (Flags & RF_ROTATE_270) { WIA_TRACE((TEXT("CPhotoItem::_DoHandleRotation(%s) - Rotating Image 270 degrees"),_szFileName)); status = pImage->RotateFlip( Gdiplus::Rotate270FlipNone ); if (status == Gdiplus::Ok) { _DoRotateAnnotations( FALSE, Flags ); } } else { status = Gdiplus::Ok; }
//
// Map most of these error codes to UNABLE_TO_ROTATE...
//
DO_CONVERT_GDIPLUS_STATUS(hr,status); }
//
// If we were able to rotate the image, then update the source rectangle
// to make sure it still reflects reality...
//
if (SUCCEEDED(hr)) { Gdiplus::RectF rectBounds; hr = _GetImageDimensions( pImage, rectBounds, ScaleFactorForY );
if (SUCCEEDED(hr)) { src.Width = (INT)rectBounds.Width; src.Height = (INT)(rectBounds.Height * ScaleFactorForY); src.X = (INT)rectBounds.X; src.Y = (INT)(rectBounds.Y * ScaleFactorForY); } else { src.Width = 0; src.Height = 0; src.X = 0; src.Y = 0; } } }
if (Flags & RF_NO_ERRORS_ON_FAILURE_TO_ROTATE) { WIA_RETURN_HR(S_OK); }
WIA_RETURN_HR(hr);
}
/*****************************************************************************
CPhotoItem::_RenderAnnotations
If annotations exist, then render them on top of this image...
*****************************************************************************/
HRESULT CPhotoItem::_RenderAnnotations( HDC hDC, RENDER_DIMENSIONS * pDim, Gdiplus::Rect * pDest, Gdiplus::Rect &src, Gdiplus::Rect &srcAfterClipping ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_RenderAnnotations(%s)"),_szFileName));
if (!_pAnnotations || !hDC) { WIA_RETURN_HR(E_INVALIDARG); }
//
// Save the settings for this DC...
//
INT iSavedDC = SaveDC( hDC );
//
// setup the destination DC:
//
SetMapMode(hDC, MM_TEXT); SetStretchBltMode(hDC, COLORONCOLOR);
WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - dest is (%d,%d) @ (%d,%d)"),_szFileName,pDest->Width,pDest->Height,pDest->X,pDest->Y)); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - rcDevice is (%d,%d) @ (%d,%d)"),_szFileName,pDim->rcDevice.right - pDim->rcDevice.left,pDim->rcDevice.bottom - pDim->rcDevice.top,pDim->rcDevice.left,pDim->rcDevice.top)); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - NominalPhysicalSize is (%d,%d)"),_szFileName,pDim->NominalPhysicalSize.cx,pDim->NominalPhysicalSize.cy)); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - NominalDevicePrintArea is (%d,%d)"),_szFileName,pDim->NominalDevicePrintArea.cx,pDim->NominalDevicePrintArea.cy));
//
// Get device rect
//
Gdiplus::RectF rectDevice;
rectDevice.X = (Gdiplus::REAL)pDim->rcDevice.left; rectDevice.Y = (Gdiplus::REAL)pDim->rcDevice.top; rectDevice.Width = (Gdiplus::REAL)(pDim->rcDevice.right - pDim->rcDevice.left); rectDevice.Height = (Gdiplus::REAL)(pDim->rcDevice.bottom - pDim->rcDevice.top);
//
// Compute LPtoDP scaling factors
//
Gdiplus::REAL xLPtoDP = 0.0; Gdiplus::REAL yLPtoDP = 0.0;
if (pDim->bDeviceIsScreen) { xLPtoDP = rectDevice.Width / (Gdiplus::REAL)pDim->NominalPhysicalSize.cx; yLPtoDP = rectDevice.Height / (Gdiplus::REAL)pDim->NominalPhysicalSize.cy; } else { xLPtoDP = rectDevice.Width / (Gdiplus::REAL)pDim->NominalDevicePrintArea.cx; yLPtoDP = rectDevice.Height / (Gdiplus::REAL)pDim->NominalDevicePrintArea.cy; }
//
// Get destination rect in device coords...
//
Gdiplus::RectF rectDest;
rectDest.X = pDest->X * xLPtoDP; rectDest.Y = pDest->Y * xLPtoDP; rectDest.Width = pDest->Width * xLPtoDP; rectDest.Height = pDest->Height * xLPtoDP;
WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - original source rect is (%d, %d) @ (%d, %d)"),_szFileName,src.Width,src.Height,src.X,src.Y)); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - clipped source rect is (%d, %d) @ (%d, %d)"),_szFileName,srcAfterClipping.Width,srcAfterClipping.Height,srcAfterClipping.X,srcAfterClipping.Y)); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - clipped destination rect in device coords is (%d, %d) @ (%d, %d)"),_szFileName,(INT)rectDest.Width, (INT)rectDest.Height, (INT)rectDest.X, (INT)rectDest.Y));
//
// dx & dy represent how much bigger a destination rectangle would be
// for the whole image, rather than the copped image...
//
Gdiplus::REAL dx = (Gdiplus::REAL)(src.Width - srcAfterClipping.Width) * (rectDest.Width / (Gdiplus::REAL)srcAfterClipping.Width); Gdiplus::REAL dy = (Gdiplus::REAL)(src.Height - srcAfterClipping.Height) * (rectDest.Height / (Gdiplus::REAL)srcAfterClipping.Height);
WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - dx = %d dy = %d"),_szFileName,(INT)dx,(INT)dy));
//
// Set the clipping rectangle on the device hDC in device coords...
//
RECT rcClip; rcClip.left = (INT)rectDest.X; rcClip.right = rcClip.left + (INT)rectDest.Width; rcClip.top = (INT)rectDest.Y; rcClip.bottom = rcClip.top + (INT)rectDest.Height;
#ifdef SHOW_ANNOT_RECTS
{ WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - rcClip is (%d,%d) @ (%d,%d)"),_szFileName,rcClip.right-rcClip.left,rcClip.bottom-rcClip.top,rcClip.left,rcClip.top)); HBRUSH hbr = CreateSolidBrush( RGB( 0xFF, 0x00, 0x00 ) ); FrameRect( hDC, &rcClip, hbr ); DeleteObject( (HGDIOBJ)hbr ); } #endif
HRGN hrgn = CreateRectRgnIndirect(&rcClip); if (hrgn != NULL) { WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - setting clip region to (%d, %d, %d, %d)"),_szFileName,rcClip.left, rcClip.top, rcClip.right, rcClip.bottom)); SelectClipRgn(hDC, hrgn); }
//
// Make dest rect for whole image, knowing we will clip later...
//
rectDest.X -= (dx / (Gdiplus::REAL)2.0); rectDest.Y -= (dy / (Gdiplus::REAL)2.0); rectDest.Width += dx; rectDest.Height += dy;
WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - full dest image rect in device coords is (%d, %d) @ (%d,%d)"),_szFileName,(INT)rectDevice.Width,(INT)rectDevice.Height,(INT)rectDevice.X,(INT)rectDevice.Y));
#ifdef SHOW_ANNOT_RECTS
{ RECT rc; rc.left = (INT)rectDest.X; rc.top = (INT)rectDest.Y; rc.right = rc.left + (INT)rectDest.Width; rc.bottom = rc.top + (INT)rectDest.Height; HBRUSH hbr = CreateSolidBrush( RGB( 0x00, 0xFF, 0x00 ) ); FrameRect( hDC, &rc, hbr ); DeleteObject( (HGDIOBJ)hbr ); } #endif
//
// set up mapping modes for annotations
//
SetMapMode(hDC, MM_ANISOTROPIC);
//
// Set window org/ext to entire image...
//
SetWindowOrgEx(hDC, src.X, src.Y, NULL); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - set window org to (%d,%d)"),_szFileName,src.X,src.Y));
SetWindowExtEx(hDC, src.Width, src.Height, NULL); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - set window ext to (%d,%d)"),_szFileName,src.Width,src.Height));
//
// Set the viewport to be at the corner of the image we are trying
// to draw annotations for...
//
SetViewportOrgEx( hDC, (INT)rectDest.X, (INT)rectDest.Y, NULL ); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - set viewport org to (%d,%d)"),_szFileName,(INT)rectDest.X,(INT)rectDest.Y));
//
// We need to set scaling mode of image to dest rect
//
SetViewportExtEx( hDC, (INT)rectDest.Width, (INT)rectDest.Height, NULL ); WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - set viewport ext to (%d,%d)"),_szFileName,(INT)rectDest.Width, (INT)rectDest.Height));
//
// Now that everything is set up, render the annotations...
//
WIA_TRACE((TEXT("CPhotoItem::_RenderAnnotations(%s) - calling RenderAllMarks(0x%x)"),_szFileName,hDC)); _pAnnotations->RenderAllMarks(hDC);
SelectClipRgn(hDC, NULL);
if (hrgn != NULL) DeleteObject(hrgn);
if (iSavedDC) { RestoreDC( hDC, iSavedDC ); }
WIA_RETURN_HR(S_OK); }
/*****************************************************************************
CPhotoItem::_MungeAnnotationDataForThumbnails
If we're rendering using thumbnails, then we need to munge some data so that we will render correctly...
*****************************************************************************/
HRESULT CPhotoItem::_MungeAnnotationDataForThumbnails( Gdiplus::Rect &src, Gdiplus::Rect &srcBeforeClipping, Gdiplus::Rect * pDest, UINT Flags ) { WIA_TRACE((TEXT("CPhotoItem::_MungeAnnotationDataForThumbnails(%s)"),_szFileName));
HRESULT hr = _CreateGdiPlusImage();
if (FAILED(hr)) { WIA_RETURN_HR(hr); }
if (!_pImage) { WIA_RETURN_HR(E_FAIL); }
//
// we need to construct the original image rectangle appropriate for
// annotation use...
//
Gdiplus::RectF rectImage; Gdiplus::REAL scaleY;
hr = _GetImageDimensions( _pImage, rectImage, scaleY );
if (FAILED(hr)) { //
// If we couldn't accurately get the image dimensions, then bail...
//
return hr; }
//
// Scale image if it's non-square pixels
//
if (scaleY != (Gdiplus::REAL)0.0) { rectImage.Height *= scaleY; rectImage.Y *= scaleY; }
WIA_TRACE((TEXT("CPhotoItem::_Munge(%s) - rectImage is (%d,%d) @ (%d,%d)"),_szFileName,(INT)rectImage.Width,(INT)rectImage.Height,(INT)rectImage.X,(INT)rectImage.Y));
//
// Now, do all the transforms on the real image rectangle...
//
const DOUBLE srcAspect = (DOUBLE)rectImage.Width / (DOUBLE)rectImage.Height; const DOUBLE destAspect = (DOUBLE)pDest->Width / (DOUBLE)pDest->Height;
if((srcAspect >= (DOUBLE)1.0) ^ (destAspect >= (DOUBLE)1.0)) { //
// Image needs to be rotated, swap width & height
//
rectImage.X = rectImage.Width; rectImage.Width = rectImage.Height; rectImage.Height = rectImage.X; rectImage.X = 0.0; }
src.X = (INT)rectImage.X; src.Y = (INT)rectImage.Y; src.Width = (INT)rectImage.Width; src.Height = (INT)rectImage.Height;
WIA_TRACE((TEXT("CPhotoItem::_Munge(%s) - srcRect after rotation is (%d,%d) @ (%d,%d)"),_szFileName,src.Width,src.Height,src.X,src.Y));
srcBeforeClipping = src;
if (Flags & RF_CROP_TO_FIT) { hr = _CropImage( &src, pDest ); } else if (Flags & RF_SCALE_TO_FIT) { hr = _ScaleImage( &src, pDest ); }
//
// Unscale the src rect
//
if (scaleY != (Gdiplus::REAL)0.0) { src.Height = (INT)(((Gdiplus::REAL)src.Height) / scaleY); src.Y = (INT)(((Gdiplus::REAL)src.Y) / scaleY);
srcBeforeClipping.Height = (INT)(((Gdiplus::REAL)srcBeforeClipping.Height) / scaleY); srcBeforeClipping.Y = (INT)(((Gdiplus::REAL)srcBeforeClipping.Y) / scaleY);
}
WIA_RETURN_HR(hr); }
/*****************************************************************************
CPhotoItem::_GetThumbnailQualityImage
Returns in ppImage a pointer to an image class. If pbNeedsToBeDeleted then the caller must call delete on the returned pImage.
*****************************************************************************/
HRESULT CPhotoItem::_GetThumbnailQualityImage( Gdiplus::Image ** ppImage, RENDER_OPTIONS * pRO, BOOL * pbNeedsToBeDeleted ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_GetThumbnailQualityImage( %s )"),_szFileName));
if (!ppImage || !pRO || !pbNeedsToBeDeleted) { WIA_ERROR((TEXT("CPhotoItem::_GetThumbnailQualityImage( %s ) - returning E_INVALIDARG!"),_szFileName)); return E_INVALIDARG; }
//
// Initialize incoming params
//
*ppImage = NULL; *pbNeedsToBeDeleted = FALSE;
//
// Make sure we have a GDI+ image class for our thumbnail...
//
SIZE sizeDesired = { DEFAULT_THUMB_WIDTH, DEFAULT_THUMB_HEIGHT }; HRESULT hr = _CreateGdiPlusThumbnail( sizeDesired, pRO->lFrame );
if (SUCCEEDED(hr) && (NULL!=_pThumbnails) && (pRO->lFrame < _lFrameCount) && (NULL!=_pThumbnails[pRO->lFrame])) { //
// If we already have thumbnail bits, then use those by creating
// a GDI+ bitmap class over those bits...
//
*ppImage = Gdiplus::Bitmap::FromHBITMAP( _pThumbnails[pRO->lFrame], NULL );
if (*ppImage) { hr = Gdiplus2HRESULT((*ppImage)->GetLastStatus()); WIA_TRACE((TEXT("CPhotoItem::_GetThumbnailQualityImage(%s) -- pImage created from thumbnail data is sized as (%d x %d)"),_szFileName,(*ppImage)->GetWidth(),(*ppImage)->GetHeight()));
if (SUCCEEDED(hr)) { *pbNeedsToBeDeleted = TRUE; } else { delete (*ppImage); *ppImage = NULL; } } else { hr = E_OUTOFMEMORY; }
} else { WIA_ERROR((TEXT("CPhotoItem::_GetThumbnailQualityImage(%s) -- no thumbnail exists (_pThumbnails=0x%x, lFrame = %d, _lFrameCount = %d)"),_szFileName,_pThumbnails,pRO->lFrame,_lFrameCount)); }
WIA_RETURN_HR(hr);
}
/*****************************************************************************
CPhotoItem::_GetMediumQualityImage
Returns in ppImage a pointer to an image class. If pbNeedsToBeDeleted then the caller must call delete on the returned pImage.
*****************************************************************************/
HRESULT CPhotoItem::_GetMediumQualityImage( Gdiplus::Image ** ppImage, RENDER_OPTIONS * pRO, BOOL * pbNeedsToBeDeleted ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_GetMediumQualityImage( %s )"),_szFileName));
if (!ppImage || !pRO || !pbNeedsToBeDeleted) { WIA_ERROR((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - returning E_INVALIDARG!"),_szFileName)); return E_INVALIDARG; }
//
// Initialize incoming params
//
*ppImage = NULL; *pbNeedsToBeDeleted = FALSE;
//
// We want to use the full high-res image.
// Make sure we have a GDI+ image class for our photo...
//
HRESULT hr = _CreateGdiPlusImage();
if (SUCCEEDED(hr) && _pImage) { //
// If this a metafile type of image, just use the original image
//
GUID guidFormat = {0};
hr = Gdiplus2HRESULT(_pImage->GetRawFormat(&guidFormat));
if ( (SUCCEEDED(hr) && (guidFormat == ImageFormatIcon)) || (Gdiplus::ImageTypeMetafile == _pImage->GetType()) ) { WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - this is a metafile or an icon, using the full image..."),_szFileName)); hr = Gdiplus2HRESULT(_pImage->SelectActiveFrame( _bTimeFrames ? &Gdiplus::FrameDimensionTime : &Gdiplus::FrameDimensionPage, pRO->lFrame )); *ppImage = _pImage; } else { //
// Select the specified page
//
hr = Gdiplus2HRESULT(_pImage->SelectActiveFrame( _bTimeFrames ? &Gdiplus::FrameDimensionTime : &Gdiplus::FrameDimensionPage, pRO->lFrame )); WIA_CHECK_HR(hr,"CPhotoItem::_GetMediumQualityImage() - couldn't select frame!");
if (SUCCEEDED(hr)) {
//
// Here's the algoritm to decide how big an image to create.
//
// (1) At least thumbnail size (120x120)
// (2) Attempt to scale to either 150dpi or 180dpi, depending on X DPI resolution of the printer
//
INT xDPI = 0, yDPI = 0;
if ((pRO->Dim.DPI.cx % 150) == 0) { //
// DPI is some even multiple of 150 (i.e., 150, 300, 600, 1200, 2400, etc)
//
xDPI = 150; yDPI = MulDiv( pRO->Dim.DPI.cy, xDPI, pRO->Dim.DPI.cx ); } else { //
// DPI is some even multiple of 180 (i.e., 180, 360, 720, 1440, 2880, etc)
//
xDPI = 180; yDPI = MulDiv( pRO->Dim.DPI.cy, xDPI, pRO->Dim.DPI.cx ); }
WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - scaling to xDPI=%d yDPI=%d"),_szFileName,xDPI,yDPI));
//
// Handle the error case of trying to scale yDPI
//
if (yDPI <= 0) { yDPI = xDPI; WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - fixing up yDPI to be %d"),_szFileName,yDPI)); }
//
// Figure out the desired size of the new image...
//
INT Width = MulDiv( pRO->pDest->Width, xDPI, 10000 ); INT Height = MulDiv( pRO->pDest->Height, yDPI, 10000 );
WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - desired size of image is (%d x %d)"),_szFileName,Width,Height));
if ((Width < DEFAULT_THUMB_WIDTH) && (Height < DEFAULT_THUMB_HEIGHT)) { Width = 120; Height = 120; WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - desired size of image is smaller than thumbnail, making it thumbnail size (%d x %d)"),_szFileName,Width,Height)); }
//
// Now we now what size we're trying to scale to, create an image scaled (without cropping) to that size...
//
Gdiplus::RectF rectImage; Gdiplus::REAL scaleY;
if (SUCCEEDED(_GetImageDimensions( _pImage, rectImage, scaleY ))) { //
// scale for non-square pixels...
//
if (scaleY != (Gdiplus::REAL)0.0) { rectImage.Height *= scaleY; rectImage.Y *= scaleY; }
SIZE sizeDrawSize = {0}; sizeDrawSize = PrintScanUtil::ScalePreserveAspectRatio( Width, Height, (INT)rectImage.Width, (INT)rectImage.Height );
WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - size of full image( %d x %d )"),_szFileName, (INT)rectImage.Width, (INT)rectImage.Height)); WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - sizeDesired( %d x %d )"),_szFileName, Width, Height)); WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - sizeDrawsize( %d x %d )"),_szFileName, sizeDrawSize.cx, sizeDrawSize.cy));
//
// Create the target bitmap and make sure it succeeded
//
*ppImage = (Gdiplus::Image *)new Gdiplus::Bitmap( sizeDrawSize.cx, sizeDrawSize.cy ); if (*ppImage) { hr = Gdiplus2HRESULT((*ppImage)->GetLastStatus()); if (SUCCEEDED(hr)) { //
// Set the resolution (DPI) for the bitmap
//
((Gdiplus::Bitmap *)(*ppImage))->SetResolution( (Gdiplus::REAL)xDPI, (Gdiplus::REAL)yDPI );
//
// Get a graphics to render to
//
Graphics *pGraphics = Gdiplus::Graphics::FromImage(*ppImage); if (pGraphics) { hr = Gdiplus2HRESULT(pGraphics->GetLastStatus());
//
// Make sure it is valid
//
if (SUCCEEDED(hr)) { //
// Set the interpolation mode to high quality
//
pGraphics->SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBicubic );
//
// Set the smoothing (anti-aliasing) mode to high quality as well
//
pGraphics->SetSmoothingMode( Gdiplus::SmoothingModeHighQuality );
//
// Draw scaled image
//
WIA_TRACE((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - calling pGraphics->DrawImage( _pImage, 0, 0, %d, %d )"),_szFileName,sizeDrawSize.cx,sizeDrawSize.cy));
Gdiplus::Rect rectDest; rectDest.X = 0; rectDest.Y = 0; rectDest.Width = sizeDrawSize.cx; rectDest.Height = sizeDrawSize.cy;
Gdiplus::ImageAttributes imageAttr; imageAttr.SetWrapMode( Gdiplus::WrapModeTileFlipXY, Gdiplus::Color(), FALSE );
//
// Undo scaling
//
if (scaleY != (Gdiplus::REAL)0.0) { rectImage.Height /= scaleY; rectImage.Y /= scaleY; }
//
// Finally render the image w/the right settings
//
pGraphics->DrawImage( _pImage, rectDest, 0, 0, (INT)rectImage.Width, (INT)rectImage.Height, Gdiplus::UnitPixel, &imageAttr );
WIA_CHECK_HR(hr,"CPhotoItem::_GetMediumQualityImage() - pGraphics->DrawImage( _pImage, 0, 0, sizeDrawSize.cx, sizeDrawSize.cy ) failed!");
if (SUCCEEDED(hr)) { *pbNeedsToBeDeleted = TRUE; } else { delete (*ppImage); *ppImage = NULL; }
}
//
// Clean up our dynamically allocated graphics
//
delete pGraphics;
} else { WIA_ERROR((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - pGraphics was NULL!"),_szFileName)); hr = E_OUTOFMEMORY; } } else { delete (*ppImage); *ppImage = NULL; } } else { WIA_ERROR((TEXT("CPhotoItem::_GetMediumQualityImage(%s) - failed to create new pImage for medium quality data!"),_szFileName)); hr = E_OUTOFMEMORY; }
} } } }
WIA_RETURN_HR(hr); }
/*****************************************************************************
CPhotoItem::_GetFullQualityImage
Returns in ppImage a pointer to an image class. If pbNeedsToBeDeleted then the caller must call delete on the returned pImage.
*****************************************************************************/
HRESULT CPhotoItem::_GetFullQualityImage( Gdiplus::Image ** ppImage, RENDER_OPTIONS * pRO, BOOL * pbNeedsToBeDeleted ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_GetFullQualityImage( %s )"),_szFileName));
if (!ppImage || !pbNeedsToBeDeleted) { WIA_ERROR((TEXT("CPhotoItem::_GetFullQualityImage(%s) - returning E_INVALIDARG!"),_szFileName)); return E_INVALIDARG; }
//
// Initialize incoming params
//
*ppImage = NULL; *pbNeedsToBeDeleted = FALSE;
//
// We want to use the full high-res image.
// Make sure we have a GDI+ image class for our photo...
//
HRESULT hr = _CreateGdiPlusImage();
if (SUCCEEDED(hr) && _pImage) { //
// Select the specified page
//
hr = Gdiplus2HRESULT(_pImage->SelectActiveFrame( _bTimeFrames ? &Gdiplus::FrameDimensionTime : &Gdiplus::FrameDimensionPage, pRO->lFrame ));
if (SUCCEEDED(hr)) { *ppImage = _pImage; WIA_TRACE((TEXT("CPhotoItem::_GetFullQualityImage(%s) -- *ppImage created from full image data is sized as (%d x %d)"),_szFileName,_pImage->GetWidth(),_pImage->GetHeight())); } else { WIA_ERROR((TEXT("CPhotoItem::_GetFullQualityImage(%s) - couldn't select frame %d, hr = 0x%x"),_szFileName,pRO->lFrame,hr)); }
}
WIA_RETURN_HR(hr); }
#define CHECK_AND_EXIT_ON_FAILURE(hr) if (FAILED(hr)) {if (pImage && (pImage!=_pImage)) {delete pImage;} WIA_RETURN_HR(hr);}
/*****************************************************************************
CPhotoItem::Render
Renders the given item into the Graphics that is supplied...
*****************************************************************************/
HRESULT CPhotoItem::Render( RENDER_OPTIONS * pRO ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::Render( %s, pRO = 0x%x)"),_szFileName,pRO));
if (!pRO) { WIA_ERROR((TEXT("CPhotoItem::Render(%s) - pRO is NULL, don't have any input!"),_szFileName)); return E_INVALIDARG; }
WIA_TRACE((TEXT("CPhotoItem::Render(%s) - Render Options were specificed as:"),_szFileName)); WIA_TRACE((TEXT("CPhotoItem::Render(%s) - g = 0x%x"),_szFileName,pRO->g)); WIA_TRACE((TEXT("CPhotoItem::Render(%s) - pDest = (%d x %d) at (%d,%d)"),_szFileName,pRO->pDest->Width,pRO->pDest->Height,pRO->pDest->X,pRO->pDest->Y)); WIA_TRACE((TEXT("CPhotoItem::Render(%s) - Flags = 0x%x"),_szFileName,pRO->Flags)); WIA_TRACE((TEXT("CPhotoItem::Render(%s) - lFrame = %d"),_szFileName,pRO->lFrame));
HRESULT hr = S_OK; Gdiplus::Image * pImage = NULL; BOOL bNeedsToBeDeleted = FALSE; Gdiplus::GpStatus status;
//
// Check for bad args...
//
if (!pRO->g) { WIA_ERROR((TEXT("CPhotoItem::Render(%s) - g is NULL, can't draw anything"),_szFileName)); return E_INVALIDARG; }
if ((pRO->Flags & RF_STRETCH_TO_FIT) && (pRO->Flags & (RF_CROP_TO_FIT | RF_SCALE_TO_FIT))) { WIA_ERROR((TEXT("CPhotoItem::Render(%s) - RF_STRETCH_TO_FIT can't be combined with CROP or SCALE"),_szFileName)); return E_INVALIDARG; }
CAutoCriticalSection lock(_csItem);
//
// Refresh annotation data if we have it
//
_LoadAnnotations();
if (pRO->Flags & RF_USE_THUMBNAIL_DATA) { WIA_TRACE((TEXT("CPhotoItem::Render(%s) -- render using thumbnail data..."),_szFileName)); hr = _GetThumbnailQualityImage( &pImage, pRO, &bNeedsToBeDeleted ); } else if (pRO->Flags & RF_USE_MEDIUM_QUALITY_DATA) { WIA_TRACE((TEXT("CPhotoItem::Render(%s) -- render using high quality thumbnail data..."),_szFileName)); hr = _GetMediumQualityImage( &pImage, pRO, &bNeedsToBeDeleted );
} else if (pRO->Flags & RF_USE_FULL_IMAGE_DATA) { WIA_TRACE((TEXT("CPhotoItem::Render(%s) -- render using full image data..."),_szFileName)); hr = _GetFullQualityImage( &pImage, pRO, &bNeedsToBeDeleted ); } else { WIA_ERROR((TEXT("CPhotoItem::Render(%s) -- bad render data flags"),_szFileName)); WIA_RETURN_HR(E_INVALIDARG); }
CHECK_AND_EXIT_ON_FAILURE(hr);
//
// We've constructed the appropriate image, now try to load the annotations...
//
if (_pAnnotBits && _pAnnotBits[pRO->lFrame] && _pAnnotations && _pImage) { _pAnnotations->BuildAllMarksFromData( _pAnnotBits[pRO->lFrame]->value, _pAnnotBits[pRO->lFrame]->length, (ULONG)_pImage->GetHorizontalResolution(), (ULONG)_pImage->GetVerticalResolution() );
WIA_TRACE((TEXT("CPhotoItem::Render(%s) -- %d annotation marks for frame %d found and initialized"),_szFileName,_pAnnotations->GetCount(),pRO->lFrame));
}
//
// Get the dimensions of the source image...
//
Gdiplus::Rect src;
//
// Do this so EMF/WMF print and draw correctly...
//
Gdiplus::RectF rectBounds; Gdiplus::REAL scaleY;
hr = _GetImageDimensions( pImage, rectBounds, scaleY ); if (SUCCEEDED(hr)) { src.Width = (INT)rectBounds.Width; src.Height = (INT)(rectBounds.Height * scaleY); src.X = (INT)rectBounds.X; src.Y = (INT)(rectBounds.Y * scaleY); }
CHECK_AND_EXIT_ON_FAILURE(hr);
WIA_TRACE((TEXT("CPhotoItem::Render(%s) - srcRect is (%d,%d) @ (%d,%d) before any changes"),_szFileName,src.Width, src.Height, src.X, src.Y));
//
// do any needed rotation
//
hr = _DoHandleRotation( pImage, src, pRO->pDest, pRO->Flags, scaleY ); CHECK_AND_EXIT_ON_FAILURE(hr);
WIA_TRACE((TEXT("CPhotoItem::Render(%s) - srcRect is (%d,%d) @ (%d,%d) after any needed rotation"),_szFileName,src.Width,src.Height,src.X,src.Y)); WIA_TRACE((TEXT("CPhotoItem::Render(%s) - destRect is (%d,%d) @ (%d,%d) after any needed rotation"),_szFileName,pRO->pDest->Width,pRO->pDest->Height,pRO->pDest->X,pRO->pDest->Y));
//
// If things are still good, do croping/scaling and then draw the image...
//
// First check if we should crop...
//
Gdiplus::Rect srcBeforeClipping = src;
if (pRO->Flags & (RF_CROP_TO_FIT | RF_SCALE_TO_FIT)) { #ifdef DEBUG
if (pRO->Flags & RF_CROP_TO_FIT) { WIA_TRACE((TEXT("CPhotoItem::Render(%s) - RF_CROP_TO_FIT was specified"),_szFileName)); } if (pRO->Flags & RF_SCALE_TO_FIT) { WIA_TRACE((TEXT("CPhotoItem::Render(%s) - RF_SCALE_TO_FIT was specified"),_szFileName)); } #endif
if (pRO->Flags & RF_CROP_TO_FIT) { hr = _CropImage( &src, pRO->pDest ); } else if (pRO->Flags & RF_SCALE_TO_FIT) { hr = _ScaleImage( &src, pRO->pDest ); } else { WIA_ERROR((TEXT("CPhotoItem::Render(%s) - CropScale: unknown configuration"),_szFileName)); hr = E_FAIL; } }
WIA_TRACE((TEXT("CPhotoItem::Render(%s) - srcRect is (%d,%d) @ (%d,%d) after scaling"),_szFileName,src.Width, src.Height, src.X, src.Y)); WIA_TRACE((TEXT("CPhotoItem::Render(%s) - destRect is (%d,%d) @ (%d,%d) after scaling"),_szFileName,pRO->pDest->Width, pRO->pDest->Height, pRO->pDest->X, pRO->pDest->Y));
CHECK_AND_EXIT_ON_FAILURE(hr);
//
// set the destination rectangle...
//
Gdiplus::Rect destTemp( pRO->pDest->X, pRO->pDest->Y, pRO->pDest->Width, pRO->pDest->Height );
//
// If this is a non-square pixel image, we need to reset the source rectangle to be back to actual
// pixels, instead of incorporating DPI as well...
//
if ((scaleY != (Gdiplus::REAL)0.0) && (scaleY != (Gdiplus::REAL)1.0)) { src.Height = (INT)((Gdiplus::REAL)src.Height / scaleY); src.Y = (INT)((Gdiplus::REAL)src.Y / scaleY); srcBeforeClipping.Height = (INT)((Gdiplus::REAL)srcBeforeClipping.Height / scaleY); srcBeforeClipping.Y = (INT)((Gdiplus::REAL)srcBeforeClipping.Y / scaleY); }
//
// Set the interpolation mode to high quality
//
pRO->g->SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBicubic );
//
// Set the smoothing (anti-aliasing) mode to high quality as well
//
pRO->g->SetSmoothingMode( Gdiplus::SmoothingModeHighQuality );
//
// Set the wrap mode
//
Gdiplus::ImageAttributes imageAttr; imageAttr.SetWrapMode( Gdiplus::WrapModeTileFlipXY, Gdiplus::Color(), FALSE );
//
// Time to draw the image.
//
WIA_TRACE((TEXT("CPhotoItem::Render(%s) - calling DrawImage( pImage, destTemp( %d x %d at %d,%d ), %d, %d, %d, %d )"),_szFileName,destTemp.Width,destTemp.Height,destTemp.X,destTemp.Y,src.X,src.Y,src.Width,src.Height)); status = pRO->g->DrawImage( pImage, destTemp, src.X, src.Y, src.Width, src.Height, Gdiplus::UnitPixel, &imageAttr );
//
// Check for errors, and then draw annotations...
//
hr = Gdiplus2HRESULT(status); WIA_CHECK_HR(hr,"CPhotoItem::Render() - g->DrawImage( pImage ) failed!");
//
// Render annotations if they exist...
//
if (_pAnnotations && _pAnnotBits && _pAnnotBits[pRO->lFrame]) { if ((pRO->Flags & RF_USE_THUMBNAIL_DATA) || (pRO->Flags & RF_USE_MEDIUM_QUALITY_DATA)) { _MungeAnnotationDataForThumbnails( src, srcBeforeClipping, pRO->pDest, pRO->Flags ); }
HDC hdcTemp = pRO->g->GetHDC(); if ((Gdiplus::Ok == pRO->g->GetLastStatus()) && hdcTemp) { _RenderAnnotations( hdcTemp, &pRO->Dim, pRO->pDest, srcBeforeClipping, src ); pRO->g->ReleaseHDC( hdcTemp ); } }
//
// If we created a new object for the image bits then delete it here...
//
if (bNeedsToBeDeleted) { delete pImage; }
//
// To save memory, once we have rendered the full image we discard it
// so the memory can be reclaimed...
//
if ((pRO->Flags & RF_USE_FULL_IMAGE_DATA) || (pRO->Flags & RF_USE_MEDIUM_QUALITY_DATA)) { _DiscardGdiPlusImages(); }
WIA_RETURN_HR(hr); }
/*****************************************************************************
CPhotoItem::_LoadAnnotations
If there are annotations in this image, load them...
*****************************************************************************/
HRESULT CPhotoItem::_LoadAnnotations() { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_LoadAnnotations(%s)"),_szFileName));
//
// Only do this if we don't already have the data and haven't already
// tried to load this before and found out there are no annotations...
//
if (!_pAnnotBits && !_pAnnotations && !_bWeKnowAnnotationsDontExist) { //
// Ensure we have the image...
//
_CreateGdiPlusImage();
//
// Make sure we have frame data
//
LONG lDummy = 0; GetImageFrameCount( &lDummy );
//
// If we have any annotations, then load them up accross all the frames...
//
UINT uSize = 0; BOOL bHasAnnotations = FALSE; Gdiplus::Status status;
_pAnnotations = (CAnnotationSet *)new CAnnotationSet();
if (_pAnnotations) { _pAnnotBits = (Gdiplus::PropertyItem **) new BYTE[ sizeof(LPVOID) * _lFrameCount ];
if (_pAnnotBits) { for (LONG lCurFrame=0; lCurFrame < _lFrameCount; lCurFrame++) { status = _pImage->SelectActiveFrame( _bTimeFrames ? &Gdiplus::FrameDimensionTime : &Gdiplus::FrameDimensionPage, lCurFrame );
if (Gdiplus::Ok == status) { //
// Load the annotation bits for this frame...
//
uSize = _pImage->GetPropertyItemSize( ANNOTATION_IMAGE_TAG );
if (uSize > 0) { _pAnnotBits[lCurFrame] = (Gdiplus::PropertyItem *) new BYTE[ uSize ]; if (_pAnnotBits[lCurFrame]) { //
// Read the annotations tag from the file...
//
status = _pImage->GetPropertyItem( ANNOTATION_IMAGE_TAG, uSize, _pAnnotBits[lCurFrame] ); if ((Gdiplus::Ok == status) && _pAnnotBits[lCurFrame]) { bHasAnnotations = TRUE; } else { WIA_ERROR((TEXT("CPhotoItem::_LoadAnnotations - GetPropertyItem failed w/hr=0x%x"),Gdiplus2HRESULT(status))); } } else { WIA_ERROR((TEXT("CPhotoItem::_LoadAnnotations - couldn't create _pAnnotBits[%d]"),lCurFrame)); } } else { WIA_TRACE((TEXT("CPhotoItem::_LoadAnnotations - GetPropertyItemSize returned %d size"),uSize)); }
} else { WIA_ERROR((TEXT("CPhotoItem::_LoadAnnotations - SelectActiveFrame(%d) failed w/hr=0x%x"),lCurFrame,Gdiplus2HRESULT(status))); } } } else { WIA_ERROR((TEXT("CPhotoItem::_LoadAnnotations - couldn't create _pAnnotBits")));
delete _pAnnotations; _pAnnotations = NULL; } } else { WIA_ERROR((TEXT("CPhotoItem::_LoadAnnotations - couldn't create _pAnnotations!"))); }
if (!bHasAnnotations) { WIA_TRACE((TEXT("CPhotoItem::_LoadAnnotations - no annotations were found!")));
//
// delete anything we created, as we didn't load any annotations...
//
if (_pAnnotBits) { for (LONG l=0; l < _lFrameCount; l++) { delete [] _pAnnotBits[l]; _pAnnotBits[l] = NULL; }
delete [] _pAnnotBits; _pAnnotBits = NULL; }
if (_pAnnotations) { delete _pAnnotations; _pAnnotations = NULL; }
//
// We gave it our best shot -- there aren't any annotations
// so don't bother trying again for this session of the wizard
// for this image...
_bWeKnowAnnotationsDontExist = TRUE;
}
} else { WIA_TRACE((TEXT("CPhotoItem::_LoadAnnotations - not loading because we already have pointers to the data."))); }
WIA_RETURN_HR(S_OK); }
/*****************************************************************************
CPhotoItem::_CreateGdiPlusImage
Instantiates Gdi+ plus over the given image...
*****************************************************************************/
HRESULT CPhotoItem::_CreateGdiPlusImage() { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_CreateGdiPlusImage(%s)"),_szFileName));
HRESULT hr = S_OK;
CAutoCriticalSection lock(_csItem);
//
// Try and get the size of the file...
//
if (_llFileSize == 0) { TCHAR szPath[ MAX_PATH + 64 ];
*szPath = 0; if (SHGetPathFromIDList( _pidlFull, szPath ) && *szPath) { HANDLE hFile = CreateFile( szPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (hFile != INVALID_HANDLE_VALUE) { LARGE_INTEGER li; if (GetFileSizeEx( hFile, &li )) { _llFileSize = li.QuadPart; }
CloseHandle( hFile ); }
} }
//
// Make sure we've got a stream pointer to the file
//
if (!_pImage) { //
// Get an IStream pointer for our item
//
CComPtr<IShellFolder> psfDesktop; hr = SHGetDesktopFolder( &psfDesktop ); if (SUCCEEDED(hr) && psfDesktop) { hr = psfDesktop->BindToObject( _pidlFull, NULL, IID_IStream, (LPVOID *)&_pStream ); WIA_CHECK_HR(hr,"_CreateGdiPlusImage: psfDesktop->BindToObject( IStream for _pidlFull )");
if (SUCCEEDED(hr) && _pStream) { //
// Create GDI+ image object from stream
//
_pImage = new Gdiplus::Image( _pStream, TRUE ); if (!_pImage) { _pStream = NULL; WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusImage(%s) - _pImage is NULL, creation of GDI+ image object failed!"),_szFileName)); hr = E_OUTOFMEMORY; } else { hr = Gdiplus2HRESULT(_pImage->GetLastStatus());
if (FAILED(hr)) { delete _pImage; _pImage = NULL; _pStream = NULL; WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusImage(%s) - creation of image failed w/GDI+ hr = 0x%x"),_szFileName,hr)); } }
} } else { WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusImage(%s) - Couldn't get psfDesktop!"),_szFileName)); } }
WIA_RETURN_HR(hr);
}
/*****************************************************************************
CPhotoItem::_CreateGdiPlusThumbnail
Ensure we have a GdiPlus::Image for the thumbnail
*****************************************************************************/
HRESULT CPhotoItem::_CreateGdiPlusThumbnail( const SIZE &sizeDesired, LONG lFrame ) { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_CreateGdiPlusThumbnail( %s, this = 0x%x )"),_szFileName,this));
HRESULT hr = S_OK; Gdiplus::GpStatus status = Gdiplus::Ok;
CAutoCriticalSection lock(_csItem);
//
// Ensure we have backing Image for file..
//
hr = _CreateGdiPlusImage();
if (SUCCEEDED(hr) && _pImage) { //
// Get the number of frames...
//
LONG lFrameCount = 0; hr = GetImageFrameCount( &lFrameCount );
if (SUCCEEDED(hr)) {
//
// Our primary goal is to get at the thumbnail bitmap bits for the
// specified frame. First, make sure we've got an array to place
// these in to.
//
if ((!_pThumbnails) && (lFrameCount >= 1)) { WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - _pThumbnails(0x%x) and _lFrameCount(%d)"),_szFileName,_pThumbnails,lFrameCount));
_pThumbnails = (HBITMAP *) new HBITMAP [lFrameCount];
if (_pThumbnails) { //
// Ensure we start out with NULL HBITMAPS...
//
for (INT i=0; i<lFrameCount; i++) { _pThumbnails[i] = NULL; } } else { hr = E_OUTOFMEMORY; }
WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - _pThumbnails is now (0x%x)"),_szFileName,_pThumbnails)); }
if (SUCCEEDED(hr) && _pThumbnails) { WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - we have _pThumbnails"),_szFileName));
//
// Do we already have thumbnail bits for this frame?
//
if ((lFrame < lFrameCount) && (!_pThumbnails[lFrame])) { //
// Have to create thumbnail for this frame.
// Select the specified frame.
//
status = _pImage->SelectActiveFrame( _bTimeFrames ? &Gdiplus::FrameDimensionTime : &Gdiplus::FrameDimensionPage, lFrame ); hr = Gdiplus2HRESULT(status);
if (SUCCEEDED(hr)) { GUID guidFormat = {0}; Gdiplus::Image * pThumb = NULL;
status = _pImage->GetRawFormat( &guidFormat );
if (status == Gdiplus::Ok && (guidFormat == ImageFormatIcon)) { pThumb = _pImage; } else { pThumb = _pImage->GetThumbnailImage( 0, 0, NULL, NULL ); }
if (pThumb) {
WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - SIZE - _pImage (%d x %d )"),_szFileName,_pImage->GetWidth(), _pImage->GetHeight())); WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - SIZE - pThumb (%d x %d)"),_szFileName,pThumb->GetWidth(),pThumb->GetHeight()));
//
// Scale image to fill thumbnail space while preserving
// aspect ratio...
//
SIZE sizeDrawSize = {0}; sizeDrawSize = PrintScanUtil::ScalePreserveAspectRatio( sizeDesired.cx, sizeDesired.cy, _pImage->GetWidth(), _pImage->GetHeight() );
WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - SIZE - sizeDesired( %d x %d )"),_szFileName,sizeDesired.cx, sizeDesired.cy)); WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s) - SIZE - sizeDrawsize( %d x %d )"),_szFileName,sizeDrawSize.cx, sizeDrawSize.cy));
//
// Create an HBITMAP of the thumbnail...
//
Gdiplus::Bitmap * pBitmap = new Gdiplus::Bitmap( sizeDrawSize.cx, sizeDrawSize.cy ); if (pBitmap) { hr = Gdiplus2HRESULT(pBitmap->GetLastStatus()); if (SUCCEEDED(hr)) { //
// Get a graphics to render to
//
Graphics *pGraphics = Gdiplus::Graphics::FromImage((Gdiplus::Image *)pBitmap);
if (pGraphics) { hr = Gdiplus2HRESULT(pGraphics->GetLastStatus());
//
// Make sure it is valid
//
if (SUCCEEDED(hr)) { //
// erase the background of the image
//
pGraphics->Clear( g_wndColor );
//
// Set the interpolation mode to high quality
//
pGraphics->SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear );
//
// Draw scaled image
//
WIA_TRACE((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - calling pGraphics->DrawImage( pThumb, %d, %d, %d, %d )"),_szFileName,0 + ((sizeDesired.cx - sizeDrawSize.cx) / 2),0 + ((sizeDesired.cy - sizeDrawSize.cy) / 2),sizeDrawSize.cx,sizeDrawSize.cy));
hr = Gdiplus2HRESULT(pGraphics->DrawImage( pThumb, 0, 0, sizeDrawSize.cx, sizeDrawSize.cy ));
WIA_CHECK_HR(hr,"CPhotoItem::GetThumbnailBitmap() - pGraphics->DrawImage( pThumb ) failed!");
if (SUCCEEDED(hr)) { DWORD dw = GetSysColor( COLOR_WINDOW ); Gdiplus::Color wndClr(255,GetRValue(dw),GetGValue(dw),GetBValue(dw));
pBitmap->GetHBITMAP( wndClr, &_pThumbnails[lFrame] ); }
}
//
// Clean up our dynamically allocated graphics
//
delete pGraphics;
} else { WIA_ERROR((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - pGraphics was NULL!"),_szFileName)); hr = E_OUTOFMEMORY; } } else { WIA_ERROR((TEXT("CPhotoItem::GetThumbnailBitmap(%s) - pImage failed to be created, hr = 0x%x"),hr)); }
delete pBitmap; }
if (pThumb != _pImage) { delete pThumb; } } else { hr = Gdiplus2HRESULT(_pImage->GetLastStatus()); WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s): unable to GetThumbnailImage"),_szFileName)); }
} else { WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s): unable to select frame %d"),_szFileName,lFrame)); }
} else { WIA_TRACE((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s): we already have _pThumbnails[%d], it is (0x%x)"),_szFileName,lFrame,_pThumbnails[lFrame])); }
}
} else { WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s): _pImage was NULL!"),_szFileName)); }
} else { WIA_ERROR((TEXT("CPhotoItem::_CreateGdiPlusThumbnail(%s): _pImage was NULL!"),_szFileName)); }
WIA_RETURN_HR(hr); }
/*****************************************************************************
CPhotoItem::_DiscardGdiPlusImages
Releases GDI+ objects for thumbnail and image
*****************************************************************************/
HRESULT CPhotoItem::_DiscardGdiPlusImages() { WIA_PUSH_FUNCTION_MASK((TRACE_PHOTO_ITEM,TEXT("CPhotoItem::_DiscardGdiPlusImages(%s)"),_szFileName));
CAutoCriticalSection lock(_csItem);
//
// Clear out GDI+ image objects...
//
if (_pImage) { delete _pImage; _pImage = NULL; }
if (_pStream) { //
// Since this is an CComPtr, setting this to NULL will free
// the reference on the stream object...
//
_pStream = NULL; }
if (_pClassBitmap) { delete _pClassBitmap; _pClassBitmap = NULL; }
if (_pAnnotations) { delete _pAnnotations; _pAnnotations = NULL; }
if (_pAnnotBits) { for (INT i=0; i < _lFrameCount; i++) { delete [] _pAnnotBits[i]; _pAnnotBits[i] = NULL; }
delete [] _pAnnotBits; _pAnnotBits = NULL; }
return S_OK;
}
|