/***************************************************************************** * * (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 #pragma hdrstop CLSID g_clsidBMPEncoder = GUID_NULL; using namespace Gdiplus; /***************************************************************************** CImage constructor/desctructor *****************************************************************************/ 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; }