windows-nt/Source/XPSP1/NT/printscan/wia/drivers/video/usd/image.cpp
2020-09-26 16:20:57 +08:00

894 lines
27 KiB
C++

/*****************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 1999 - 2000
*
* TITLE: image.cpp
*
* VERSION: 1.0
*
* AUTHOR: RickTu
*
* DATE: 9/16/99
*
* DESCRIPTION: Image class that encapsulates stored images from the
* streaming video device.
*
*****************************************************************************/
#include <precomp.h>
#pragma hdrstop
CLSID g_clsidBMPEncoder = GUID_NULL;
using namespace Gdiplus;
/*****************************************************************************
CImage constructor/desctructor
<Notes>
*****************************************************************************/
CImage::CImage(LPCTSTR pszStillPath,
BSTR bstrRootFullItemName,
LPCTSTR pszPath,
LPCTSTR pszName,
LONG FolderType)
: m_strRootPath(pszStillPath),
m_strPathItem(pszPath),
m_strName(pszName),
m_bstrItemName(pszName),
m_bstrRootFullItemName(bstrRootFullItemName),
m_FolderType(FolderType),
m_bImageTimeValid(FALSE),
m_pThumb(NULL)
{
DBG_FN("CImage::CImage");
CSimpleStringWide str;
CSimpleStringWide strName(m_bstrItemName);
//
// First, we need to strip off the extensions
// from the appropriate places
//
strName = strName.Left(strName.ReverseFind( TEXT('.') ));
m_bstrItemName = CSimpleBStr(strName);
str = bstrRootFullItemName;
str.Concat(L"\\");
str += CSimpleStringWide(m_bstrItemName);
m_bstrFullItemName = str.String();
}
CImage::~CImage()
{
if (m_pThumb)
{
delete [] m_pThumb;
}
}
/*****************************************************************************
CImage::LoadImageInfo
Loads information about the image such as its width, height, type, etc.
*****************************************************************************/
STDMETHODIMP
CImage::LoadImageInfo( BYTE * pWiasContext )
{
ASSERT(pWiasContext != NULL);
HRESULT hr = S_OK;
LONG lBitsPerChannel = 0;
LONG lBitsPerPixel = 0;
LONG lWidth = 0;
LONG lHeight = 0;
LONG lChannelsPerPixel = 0;
LONG lBytesPerLine = 0;
Bitmap Image(CSimpleStringConvert::WideString(m_strPathItem));
if (pWiasContext == NULL)
{
hr = E_POINTER;
CHECK_S_OK2(hr, ("LoadImageInfo received a NULL pointer"));
return hr;
}
else if (Image.GetLastStatus() != Ok)
{
hr = E_FAIL;
CHECK_S_OK2(hr, ("CImage::LoadImageInfo failed to get the image information"
"for file '%ls'", CSimpleStringConvert::WideString(m_strPathItem)));
return hr;
}
if (hr == S_OK)
{
PixelFormat lFormat;
lFormat = Image.GetPixelFormat();
if ((lFormat == PixelFormat16bppGrayScale) ||
(lFormat == PixelFormat16bppRGB555) ||
(lFormat == PixelFormat16bppRGB565) ||
(lFormat == PixelFormat16bppARGB1555))
{
lBitsPerPixel = 16;
lBitsPerChannel = 5; // this is actually not completely correct for RGB565, but anyway...
}
else if (lFormat == PixelFormat24bppRGB)
{
lBitsPerPixel = 24;
lBitsPerChannel = 8;
}
else if ((lFormat == PixelFormat32bppRGB) ||
(lFormat == PixelFormat32bppARGB) ||
(lFormat == PixelFormat32bppPARGB))
{
lBitsPerPixel = 32;
lBitsPerChannel = 10; // well, video cap won't have alpha in it,
}
lWidth = (LONG) Image.GetWidth();
lHeight = (LONG) Image.GetHeight();
lChannelsPerPixel = 3;
lBytesPerLine = lWidth * (lBitsPerPixel / 8);
}
if (hr == S_OK)
{
PROPSPEC propSpecs[7];
PROPVARIANT propVars[7];
ZeroMemory(&propSpecs, sizeof(propSpecs));
// WIA_IPA_DATATYPE
propSpecs[0].ulKind = PRSPEC_PROPID;
propSpecs[0].propid = WIA_IPA_DATATYPE;
propVars[0].vt = VT_I4;
propVars[0].lVal = WIA_DATA_COLOR;
// WIA_IPA_DEPTH
propSpecs[1].ulKind = PRSPEC_PROPID;
propSpecs[1].propid = WIA_IPA_DEPTH;
propVars[1].vt = VT_I4;
propVars[1].lVal = lBitsPerPixel;
// WIA_IPA_PIXELS_PER_LINE
propSpecs[2].ulKind = PRSPEC_PROPID;
propSpecs[2].propid = WIA_IPA_PIXELS_PER_LINE;
propVars[2].vt = VT_I4;
propVars[2].lVal = lWidth;
// WIA_IPA_NUMBER_OF_LINES
propSpecs[3].ulKind = PRSPEC_PROPID;
propSpecs[3].propid = WIA_IPA_NUMBER_OF_LINES;
propVars[3].vt = VT_I4;
propVars[3].lVal = lHeight;
// WIA_IPA_CHANNELS_PER_PIXEL
propSpecs[4].ulKind = PRSPEC_PROPID;
propSpecs[4].propid = WIA_IPA_CHANNELS_PER_PIXEL;
propVars[4].vt = VT_I4;
propVars[4].lVal = lChannelsPerPixel;
// WIA_IPA_BITS_PER_CHANNEL
propSpecs[5].ulKind = PRSPEC_PROPID;
propSpecs[5].propid = WIA_IPA_BITS_PER_CHANNEL;
propVars[5].vt = VT_I4;
propVars[5].lVal = lBitsPerChannel;
// WIA_IPA_BYTES_PER_LINE
propSpecs[6].ulKind = PRSPEC_PROPID;
propSpecs[6].propid = WIA_IPA_BYTES_PER_LINE;
propVars[6].vt = VT_I4;
propVars[6].lVal = lBytesPerLine;
// write the values of the properties.
hr = wiasWriteMultiple(pWiasContext,
sizeof(propVars) / sizeof(propVars[0]),
propSpecs,
propVars);
CHECK_S_OK2(hr, ("CImage::LoadImageInfo, failed to write image properties"));
}
return hr;
}
/*****************************************************************************
CImage::SetItemSize
Call wia to calc new item size
*****************************************************************************/
STDMETHODIMP
CImage::SetItemSize(BYTE * pWiasContext,
MINIDRV_TRANSFER_CONTEXT * pDrvTranCtx)
{
HRESULT hr;
MINIDRV_TRANSFER_CONTEXT drvTranCtx;
GUID guidFormatID;
BOOL bWriteProps = (pDrvTranCtx == NULL);
DBG_FN("CImage::SetItemSize");
ZeroMemory(&drvTranCtx, sizeof(MINIDRV_TRANSFER_CONTEXT));
if (!pDrvTranCtx)
{
pDrvTranCtx = &drvTranCtx;
}
hr = wiasReadPropGuid(pWiasContext,
WIA_IPA_FORMAT,
(GUID*)&(pDrvTranCtx->guidFormatID),
NULL,
FALSE);
CHECK_S_OK2(hr,("wiasReadPropGuid( WIA_IPA_FORMAT )"));
if (FAILED(hr))
{
return hr;
}
hr = wiasReadPropLong( pWiasContext,
WIA_IPA_TYMED,
(LONG*)&(pDrvTranCtx->tymed),
NULL,
FALSE
);
CHECK_S_OK2(hr,("wiasReadPropLong( WIA_IPA_TYMED )"));
if (FAILED(hr))
{
return hr;
}
//
// Wias works for DIB, and minidriver support native formats
//
if ((pDrvTranCtx->guidFormatID != WiaImgFmt_JPEG) &&
(pDrvTranCtx->guidFormatID != WiaImgFmt_FLASHPIX) &&
(pDrvTranCtx->guidFormatID != WiaImgFmt_TIFF))
{
//
// Create the image from the file.
//
Bitmap BitmapImage(CSimpleStringConvert::WideString(m_strPathItem));
if (Ok == BitmapImage.GetLastStatus())
{
//
// Get the image's dimensions
//
UINT nSourceWidth = BitmapImage.GetWidth();
UINT nSourceHeight = BitmapImage.GetHeight();
if (nSourceWidth && nSourceHeight)
{
//
// Fill in info for drvTranCtx
//
pDrvTranCtx->lCompression = WIA_COMPRESSION_NONE;
pDrvTranCtx->lWidthInPixels = nSourceWidth;
pDrvTranCtx->lLines = nSourceHeight;
pDrvTranCtx->lDepth = 24;
hr = wiasGetImageInformation( pWiasContext, 0, pDrvTranCtx );
//
// We need to write out the item size based on
// the JPEG converted to a BMP. But we only need
// to do this if the incoming context was NULL.
//
if (bWriteProps)
{
hr = wiasWritePropLong( pWiasContext,
WIA_IPA_ITEM_SIZE,
pDrvTranCtx->lItemSize
);
CHECK_S_OK2(hr,("wiasWritePropLong( WIA_IPA_ITEM_SIZE )"));
hr = wiasWritePropLong( pWiasContext,
WIA_IPA_BYTES_PER_LINE,
pDrvTranCtx->cbWidthInBytes
);
CHECK_S_OK2(hr,("wiasWritePropLong( WIA_IPA_BYTES_PER_LINE )"));
}
}
else
{
DBG_ERR(("nSourceWidth OR nSourceHeight were zero"));
hr = E_FAIL;
}
}
else
{
DBG_ERR(("Ok == BitmapImage.GetLastStatus failed"));
hr = E_FAIL;
}
}
else
{
CMappedView cmv( ActualImagePath(), 0, OPEN_EXISTING );
LARGE_INTEGER liSize = cmv.FileSize();
ULONG ulSize;
if (liSize.HighPart)
{
ulSize = 0;
DBG_ERR(("The file was bigger than 4GB!!!"));
}
else
{
//
// We could truncate here, I know, but that would have to be one huge file...
// Anyway, the size wouldn't fit in te properties, which expects a LONG
//
ulSize = (ULONG)liSize.LowPart;
}
pDrvTranCtx->lItemSize = ulSize;
pDrvTranCtx->cbWidthInBytes = 0;
if (bWriteProps)
{
//
// We need to write out the item size based on the file size...
//
hr = wiasWritePropLong(pWiasContext,
WIA_IPA_ITEM_SIZE,
ulSize);
CHECK_S_OK2(hr,("wiasWritePropLong( WIA_IPA_ITEM_SIZE )"));
hr = wiasWritePropLong(pWiasContext,
WIA_IPA_BYTES_PER_LINE,
0);
}
CHECK_S_OK2(hr,("wiasWritePropLong( WIA_IPA_BYTES_PER_LINE )"));
}
CHECK_S_OK(hr);
return hr;
}
/*****************************************************************************
CImage::LoadThumbnail
Loads (or creates if not already present) the thumbnail for this item.
We also write the thumbnail as a property for this item.
*****************************************************************************/
STDMETHODIMP
CImage::LoadThumbnail( BYTE * pWiasContext )
{
HRESULT hr = E_FAIL;
DBG_FN("CImage::LoadThumbnail");
//
// Only create the thumbnail if we haven't done so already
//
if (!m_pThumb)
{
Status StatusResult = Ok;
//
// Open the source image and make sure it is OK
//
Bitmap SourceImage( CSimpleStringConvert::WideString(m_strPathItem) );
StatusResult = SourceImage.GetLastStatus();
if (Ok == StatusResult)
{
//
// Create the scaled bitmap and make sure it is OK
//
Bitmap ScaledImage(THUMB_WIDTH, THUMB_HEIGHT);
StatusResult = ScaledImage.GetLastStatus();
if (Ok == StatusResult)
{
//
// Get a graphics to render the scaled image to and make sure it isn't NULL
//
Graphics *pScaledGraphics = Graphics::FromImage(&ScaledImage);
if (pScaledGraphics)
{
//
// Make sure it is valid
//
StatusResult = pScaledGraphics->GetLastStatus();
if (StatusResult == Ok)
{
//
// Draw the image scaled to thumbnail size
//
StatusResult = pScaledGraphics->DrawImage(&SourceImage, 0, 0, THUMB_WIDTH, THUMB_HEIGHT );
if (Ok == StatusResult)
{
//
// Create a bitmap to hold the flipped thumbnail and make sure it is OK
//
Bitmap FlippedImage(THUMB_WIDTH, THUMB_HEIGHT);
StatusResult = FlippedImage.GetLastStatus();
if (Ok == StatusResult)
{
//
// Create a graphics object to render the flipped image to and make sure it isn't NULL
//
Graphics *pFlippedGraphics = Graphics::FromImage(&FlippedImage);
if (pFlippedGraphics)
{
//
// Make sure it is valid
//
StatusResult = pFlippedGraphics->GetLastStatus();
if (Ok == StatusResult)
{
//
// Set up the parallelogram to flip the image
//
Point SourcePoints[3];
SourcePoints[0].X = 0;
SourcePoints[0].Y = THUMB_HEIGHT;
SourcePoints[1].X = THUMB_WIDTH;
SourcePoints[1].Y = THUMB_HEIGHT;
SourcePoints[2].X = 0;
SourcePoints[2].Y = 0;
//
// Draw the image, flipped
//
StatusResult = pFlippedGraphics->DrawImage(&ScaledImage, SourcePoints, 3);
if (StatusResult == Ok)
{
//
// Get the scaled and flipped image bits
//
Rect rcThumb( 0, 0, THUMB_WIDTH, THUMB_HEIGHT );
BitmapData BitmapData;
// This ifdef is due to an API change in GDI+. Notice
// that the first param to LockBits in the new version
// takes a ptr to RECT. Old version takes a reference
// to a RECT.
#ifdef DCR_USE_NEW_293849
StatusResult = FlippedImage.LockBits( &rcThumb, ImageLockModeRead, PixelFormat24bppRGB, &BitmapData );
#else
StatusResult = FlippedImage.LockBits( rcThumb, ImageLockModeRead, PixelFormat24bppRGB, &BitmapData );
#endif
if (Ok == StatusResult)
{
//
// Allocate the thumbnail data
//
m_pThumb = new BYTE[THUMB_SIZE_BYTES];
if (m_pThumb)
{
//
// Copy the thumbnail data over
//
CopyMemory( m_pThumb, BitmapData.Scan0, THUMB_SIZE_BYTES );
}
else
{
hr = E_OUTOFMEMORY;
CHECK_S_OK2(hr, ("m_pThumb is NULL, couldn't allocate memory"));
}
//
// Unlock the bits
//
FlippedImage.UnlockBits( &BitmapData );
}
else
{
DBG_ERR(("FlippedImage.LockBits( &rcThumb, ImageLockModeRead, PixelFormat24bppRGB, &BitmapData ) failed"));
}
}
else
{
DBG_ERR(("pFlippedGraphics->DrawImage(&ScaledImage, SourcePoints, 3) failed"));
}
}
else
{
DBG_ERR(("Ok == pFlippedGraphics->GetLastStatus() failed = '%d' (0x%08x)",
StatusResult, StatusResult));
}
//
// Free the graphics object
//
delete pFlippedGraphics;
}
else
{
DBG_ERR(("Graphics *pFlippedGraphics = Graphics::FromImage(&FlippedImage); returned NULL"));
}
}
else
{
DBG_ERR(("Ok == FlippedImage.GetLastStatus() failed = '%d',(0x%08x)",
StatusResult, StatusResult));
}
}
else
{
DBG_ERR(("pScaledGraphics->DrawImage(&SourceImage, 0, 0, THUMB_WIDTH, THUMB_HEIGHT ) failed"));
}
}
else
{
DBG_ERR(("pScaledGraphics->GetLastStatus() failed = '%d' (0x%08x)",
StatusResult, StatusResult));
}
//
// Free the graphics object
//
delete pScaledGraphics;
}
else
{
DBG_ERR(("Graphics *pScaledGraphics = Graphics::FromImage(&ScaledImage); returned NULL"));
}
}
else
{
DBG_ERR(("ScaledImage.GetLastStatus() failed = '%d' (0x%08x)",
StatusResult, StatusResult));
}
}
else
{
DBG_ERR(("SourceImage.GetLastStatus() failed = '%d' (0x%08x)",
StatusResult, StatusResult));
}
}
if (m_pThumb)
{
//
// We have the bits, write them out as a property
//
PROPSPEC propSpec;
PROPVARIANT propVar;
PropVariantInit(&propVar);
propVar.vt = VT_VECTOR | VT_UI1;
propVar.caub.cElems = THUMB_SIZE_BYTES;
propVar.caub.pElems = m_pThumb;
propSpec.ulKind = PRSPEC_PROPID;
propSpec.propid = WIA_IPC_THUMBNAIL;
hr = wiasWriteMultiple(pWiasContext, 1, &propSpec, &propVar);
CHECK_S_OK2(hr,("wiasWriteMultiple( WIA_IPC_THUMBNAIL )"));
}
else
{
if (SUCCEEDED(hr))
{
hr = E_FAIL;
}
}
CHECK_S_OK(hr);
return hr;
}
/*****************************************************************************
CImage::InitImageInformation
Called to initialize the properties for this image. In the process,
we also load (or create if needed) the thumbnail for this item.
*****************************************************************************/
STDMETHODIMP
CImage::InitImageInformation(BYTE *pWiasContext,
LONG *plDevErrVal)
{
HRESULT hr = S_OK;
SYSTEMTIME st;
DBG_FN("CImage::InitImageInformation");
//
// Use WIA services to set the extended property access and
// valid value information from gWiaPropInfoDefaults.
//
hr = wiasSetItemPropAttribs( pWiasContext,
NUM_CAM_ITEM_PROPS,
gPropSpecDefaults,
gWiaPropInfoDefaults
);
//
// Use WIA services to write image properties.
//
hr = wiasWritePropLong(pWiasContext, WIA_IPC_THUMB_WIDTH, ThumbWidth());
CHECK_S_OK2(hr,("wiasWritePropLong( WIA_IPC_THUMB_WIDTH )"));
hr = wiasWritePropLong(pWiasContext, WIA_IPC_THUMB_HEIGHT, ThumbHeight());
CHECK_S_OK2(hr,("wiasWritePropLong( WIA_IPC_THUMB_HEIGHT )"));
hr = wiasWritePropGuid(pWiasContext, WIA_IPA_PREFERRED_FORMAT, WiaImgFmt_JPEG);
CHECK_S_OK2(hr,("wiasWritePropGuid( WIA_IPA_PREFERRED_FORMAT )"));
GetImageTimeStamp( &st );
hr = wiasWritePropBin( pWiasContext, WIA_IPA_ITEM_TIME, sizeof(SYSTEMTIME), (PBYTE)&st);
CHECK_S_OK2(hr,("wiasWritePropBin( WIA_IPA_ITEM_TIME )"));
//
// calc item size
//
hr = SetItemSize(pWiasContext,NULL);
CHECK_S_OK2(hr,("SetItemSize"));
//
// load thumbnail
//
hr = LoadThumbnail( pWiasContext );
CHECK_S_OK2(hr,("LoadThumbnail"));
//
// Load additional image information such as the pixels per line,
// number of lines, etc.
//
hr = LoadImageInfo(pWiasContext);
CHECK_S_OK2(hr,("wiaSetItemPropAttribs"));
return hr;
}
/*****************************************************************************
CImage::bstrItemName
Returns the item name in the form of a BSTR.
*****************************************************************************/
BSTR
CImage::bstrItemName()
{
DBG_FN("CImage::bstrItemName");
return m_bstrItemName;
}
/*****************************************************************************
CImage::bstrFullItemName
Returns the full item name in the form of a BSTR.
*****************************************************************************/
BSTR
CImage::bstrFullItemName()
{
DBG_FN("CImage::bstrFullItemName");
return m_bstrFullItemName;
}
/*****************************************************************************
CImage::ThumbWidth
returns the thumbnail width
*****************************************************************************/
LONG
CImage::ThumbWidth()
{
DBG_FN("CImage::ThumbWidth");
return THUMB_WIDTH;
}
/*****************************************************************************
CImage::ThumbHeight
returns the thumbnail height
*****************************************************************************/
LONG
CImage::ThumbHeight()
{
DBG_FN("CImage::ThumbHeight");
return THUMB_HEIGHT;
}
/*****************************************************************************
CImage::ImageTimeStamp
returns creation time of image
*****************************************************************************/
void
CImage::GetImageTimeStamp(SYSTEMTIME * pst)
{
DBG_FN("CImage::ImageTimeStamp");
if (!m_bImageTimeValid)
{
HANDLE hFile = CreateFile(m_strPathItem,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
FILETIME ft;
if (GetFileTime( hFile, &ft, NULL, NULL ))
{
FILETIME ftLocal;
if (FileTimeToLocalFileTime(&ft, &ftLocal))
{
if (FileTimeToSystemTime( &ftLocal, &m_ImageTime ))
{
m_bImageTimeValid = TRUE;
}
}
}
CloseHandle( hFile );
}
else
{
DBG_ERR(("CreateFile( %ls ) failed, GLE = %d",
m_strPathItem.String(), GetLastError()));
//
// default to filling in structure w/zeros
//
memset( pst, 0, sizeof(SYSTEMTIME) );
}
}
if (m_bImageTimeValid && pst)
{
*pst = m_ImageTime;
}
}
/*****************************************************************************
CImage::ActualImagePath
Returns filename path of actual image
*****************************************************************************/
LPCTSTR
CImage::ActualImagePath()
{
DBG_FN("CImage::ActualImagePath");
return m_strPathItem.String();
}
/*****************************************************************************
CImage::DoDelete
Deletes the file (and thumbail) from the disk.
*****************************************************************************/
HRESULT
CImage::DoDelete()
{
HRESULT hr = S_OK;
BOOL bResFile;
DBG_FN("CImage::DoDelete");
//
// Make sure we have a file to delete...
//
if (!m_strPathItem.Length())
{
DBG_ERR(("filename for item is zero length!"));
hr = E_INVALIDARG;
}
else
{
//
// We've got an item, so delete it and the thumbnail file
//
bResFile = DeleteFile(m_strPathItem.String());
if (!bResFile)
{
DBG_ERR(("DeleteFile( %ls ) failed, GLE = %d",
m_strPathItem.String(),GetLastError()));
}
if (bResFile)
{
m_strPathItem = NULL;
m_strRootPath = NULL;
m_strName = NULL;
m_bstrRootFullItemName = NULL;
m_bstrFullItemName = NULL;
m_bImageTimeValid = FALSE;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
CHECK_S_OK(hr);
return hr;
}