/******************************************************************************* * * (C) COPYRIGHT MICROSOFT CORP., 1998 * * TITLE: memcam.cpp * * VERSION: 2.0 * * AUTHOR: Mark Enstrom [marke] * Indy Zhu [indyz] * * DATE: 2/4/1998 * 5/18/1998 * * DESCRIPTION: * Implementation of an ImageIn test camera device object. * *******************************************************************************/ #include #include #include #include extern HINSTANCE g_hInst; // Global hInstance #include "testusd.h" VOID VerticalFlip( PBYTE pImageTop, LONG iHeight, LONG iWidthInBytes); /**************************************************************************\ * CamLoadPicture * * load a bmp from disk and copy it to application * * Arguments: * * pCameraImage - pointer to data structure with image info * pDataTransCtx - pointer to minidriver transfer context * * Return Value: * * status * * History: * * 2/10/1998 Mark Enstrom [marke] * \**************************************************************************/ HRESULT TestUsdDevice::CamLoadPicture( MEMCAM_IMAGE_CONTEXT *pMCamContext, PMINIDRV_TRANSFER_CONTEXT pDataTransCtx, PLONG plCamErrVal) { LONG lScanLineWidth; HRESULT hr = S_OK; LONG cbNeeded; IWiaMiniDrvCallBack *pIProgressCB; WIAS_TRACE((g_hInst,"CamLoadPicture")); // // verify some params // if (! pMCamContext) { return (E_INVALIDARG); } if (pDataTransCtx->guidFormatID != WiaImgFmt_BMP && pDataTransCtx->guidFormatID != WiaAudFmt_WAV) { return (E_NOTIMPL); } pIProgressCB = pDataTransCtx->pIWiaMiniDrvCallBack; // // Simulate the download of data from the camera // if (pIProgressCB) { hr = pIProgressCB->MiniDrvCallback( IT_MSG_STATUS, IT_STATUS_TRANSFER_FROM_DEVICE, (LONG)0, // Percentage Complete, 0, 0, pDataTransCtx, 0); if (hr != S_OK) { return (hr); // Client want to cancel the transfer or error } } HANDLE hFile = CreateFile( pMCamContext->pszCameraImagePath, GENERIC_WRITE | GENERIC_READ , FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(::GetLastError()); return (hr); } if (pIProgressCB) { hr = pIProgressCB->MiniDrvCallback( IT_MSG_STATUS, IT_STATUS_TRANSFER_FROM_DEVICE, (LONG)25, // Percentage Complete, 0, 0, pDataTransCtx, 0); } if (hr != S_OK) { CloseHandle(hFile); return (hr); } HANDLE hMap = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL); if (hMap == NULL) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { if (pIProgressCB) { hr = pIProgressCB->MiniDrvCallback( IT_MSG_STATUS, IT_STATUS_TRANSFER_FROM_DEVICE, (LONG)50, // Percentage Complete, 0, 0, pDataTransCtx, 0); } } if (hr != S_OK) { CloseHandle(hFile); return (hr); } PBYTE pFile = (PBYTE)MapViewOfFileEx( hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, NULL); if (pFile == NULL) { hr = HRESULT_FROM_WIN32(::GetLastError()); } else { if (pIProgressCB) { hr = pIProgressCB->MiniDrvCallback( IT_MSG_STATUS, IT_STATUS_TRANSFER_FROM_DEVICE, (LONG)100, // Percentage Complete, 0, 0, pDataTransCtx, 0); } } if (hr != S_OK) { CloseHandle(hFile); CloseHandle(hMap); return(hr); } if (pDataTransCtx->guidFormatID == WiaImgFmt_BMP) { // // File contains BITMAPFILEHEADER + BITMAPINFO structure. // // DIB Data is located bfOffBits after start of file // PBITMAPFILEHEADER pbmFile = (PBITMAPFILEHEADER)pFile; PBITMAPINFO pbmi = (PBITMAPINFO)(pFile + sizeof(BITMAPFILEHEADER)); // // validate bitmap // if (pbmFile->bfType != 'MB') { // // file is not a bitmap // UnmapViewOfFile(pFile); CloseHandle(hMap); CloseHandle(hFile); return(E_FAIL); } // // write image size // // make sure to align scanline to ULONG boundary // // calculate byte width // lScanLineWidth = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biBitCount; // // round up to nearenst DWORD // lScanLineWidth = (lScanLineWidth + 31) >> 3; lScanLineWidth &= 0xfffffffc; cbNeeded = lScanLineWidth * pbmi->bmiHeader.biHeight; if (cbNeeded > ((LONG)pDataTransCtx->lItemSize - (LONG)pDataTransCtx->cbOffset)) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); } else { // // copy only the bitmap bits (no headers) // memcpy( pDataTransCtx->pTransferBuffer + pDataTransCtx->cbOffset, pFile + pbmFile->bfOffBits, cbNeeded); } } else { memcpy (pDataTransCtx->pTransferBuffer, pFile, pDataTransCtx->lItemSize); } UnmapViewOfFile(pFile); CloseHandle(hMap); CloseHandle(hFile); return(S_OK); } /**************************************************************************\ * CamLoadPictureCB * * return data by filling the data buffer and calling back to the client * * Arguments: * * pCameraImage - image item * pTransCtx - mini driver transfer contect * * Return Value: * * status * * History: * * 1/10/1999 Mark Enstrom [marke] * \**************************************************************************/ HRESULT TestUsdDevice::CamLoadPictureCB( MEMCAM_IMAGE_CONTEXT *pMCamContext, MINIDRV_TRANSFER_CONTEXT *pTransCtx, PLONG plCamErrVal) { LONG lScanLineWidth; HRESULT hr = E_FAIL; WIAS_TRACE((g_hInst,"CamLoadPictureCB")); // // verify parameters // if (!pMCamContext) { return (E_INVALIDARG); } if (pTransCtx == NULL) { return (E_INVALIDARG); } if ((pTransCtx->guidFormatID != WiaImgFmt_BMP) && (pTransCtx->guidFormatID != WiaImgFmt_MEMORYBMP)) { return (E_NOTIMPL); } // // try to open disk file // HANDLE hFile = CreateFile( pMCamContext->pszCameraImagePath, GENERIC_WRITE | GENERIC_READ , FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } HANDLE hMap = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL); if (hMap == NULL) { CloseHandle(hFile); hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } PBYTE pFile = (PBYTE)MapViewOfFileEx( hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, NULL); if (pFile == NULL) { CloseHandle(hFile); CloseHandle(hMap); hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } // // File contains BITMAPFILEHEADER + BITMAPINFO structure. // // DIB Data is located bfOffBits after start of file // PBITMAPFILEHEADER pbmFile = (PBITMAPFILEHEADER)pFile; PBITMAPINFO pbmi = (PBITMAPINFO)(pFile + sizeof(BITMAPFILEHEADER)); // // validate bitmap // if (pbmFile->bfType != 'MB') { // // file is not a bitmap // UnmapViewOfFile(pFile); CloseHandle(hMap); CloseHandle(hFile); return(E_FAIL); } // // get image size // // make sure to align scanline to ULONG boundary // // calculate byte width // lScanLineWidth = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biBitCount; // // round up to nearenst DWORD // lScanLineWidth = (lScanLineWidth + 31) >> 3; lScanLineWidth &= 0xfffffffc; LONG lBytesRemaining = lScanLineWidth * pbmi->bmiHeader.biHeight; // // Flip the image vertically if WiaImgFmt_MEMORYBMP is requested // if (pTransCtx->guidFormatID == WiaImgFmt_MEMORYBMP) { VerticalFlip( (PBYTE)pFile + pbmFile->bfOffBits, pbmi->bmiHeader.biHeight, lScanLineWidth); } // // callback loop // PBYTE pSrc = (PBYTE)pFile + pbmFile->bfOffBits; LONG lTransferSize; LONG lPercentComplete; do { PBYTE pDst = pTransCtx->pTransferBuffer; // // transfer up to entire buffer size // lTransferSize = lBytesRemaining; if (lBytesRemaining > pTransCtx->lBufferSize) { lTransferSize = pTransCtx->lBufferSize; } // // copy data // memcpy(pDst, pSrc, lTransferSize); lPercentComplete = 100 * (pTransCtx->cbOffset + lTransferSize); lPercentComplete /= pTransCtx->lItemSize; // // make callback // hr = pTransCtx->pIWiaMiniDrvCallBack->MiniDrvCallback( IT_MSG_DATA, IT_STATUS_TRANSFER_TO_CLIENT, lPercentComplete, pTransCtx->cbOffset, lTransferSize, pTransCtx, 0); // // inc pointers (redundant pointers here) // pSrc += lTransferSize; pTransCtx->cbOffset += lTransferSize; lBytesRemaining -= lTransferSize; if (hr != S_OK) { break; } } while (lBytesRemaining > 0); // // Flip the image back if WiaImgFmt_MEMORYBMP is requested // if (pTransCtx->guidFormatID == WiaImgFmt_MEMORYBMP) { VerticalFlip( (PBYTE)pFile + pbmFile->bfOffBits, pbmi->bmiHeader.biHeight, lScanLineWidth); } // // Garbage collection // UnmapViewOfFile(pFile); CloseHandle(hMap); CloseHandle(hFile); return(hr); } /**************************************************************************\ * CamGetPictureInfo * * Load file, get information from image * * Arguments: * * pCameraImage - image item * pPictInfo - fill out ino about image * ppBITMAPINFO - alloc and fill out BITMAPINFO * pBITMAPINFOSize - size * * Return Value: * * status * * History: * * 1/17/1999 Mark Enstrom [marke] * \**************************************************************************/ HRESULT TestUsdDevice::CamGetPictureInfo( MEMCAM_IMAGE_CONTEXT *pMCamContext, PCAMERA_PICTURE_INFO pPictInfo, PBYTE *ppBITMAPINFO, LONG *pBITMAPINFOSize) { HRESULT hr = S_OK; FILETIME ftCreate; SYSTEMTIME stCreate; WIAS_TRACE((g_hInst,"CamGetPictureInfo")); // // Try to open disk file // HANDLE hFile = CreateFile( pMCamContext->pszCameraImagePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } // // Grab the creation time for this image // if (GetFileTime( hFile, &ftCreate, NULL, NULL)) { FileTimeToSystemTime( &ftCreate, &stCreate ); } else { // // To return something, use the system time // GetLocalTime( &stCreate ); } HANDLE hMap = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL ); if (hMap == NULL) { CloseHandle(hFile); hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } PBYTE pFile = (PBYTE)MapViewOfFileEx( hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, NULL); if (pFile == NULL) { CloseHandle(hFile); CloseHandle(hMap); hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } // // File contains BITMAPFILEHEADER + BITMAPINFO structure. // // DIB Data is located bfOffBits after start of file // PBITMAPFILEHEADER pbmFile = (PBITMAPFILEHEADER)pFile; PBITMAPINFOHEADER pbmiHeader = (PBITMAPINFOHEADER)(pFile + sizeof(BITMAPFILEHEADER)); PBYTE pDIBFile = pFile + pbmFile->bfOffBits; // // validate bitmap. // if (pbmFile->bfType != 'MB') { // // file is not a bitmap // UnmapViewOfFile(pFile); CloseHandle(hFile); CloseHandle(hMap); return(E_FAIL); } // // fill out image information // pPictInfo->PictNumber = 0; // ??? Should support picture handle ??? pPictInfo->ThumbWidth = 80; pPictInfo->ThumbHeight = 60; pPictInfo->PictWidth = pbmiHeader->biWidth; pPictInfo->PictHeight = pbmiHeader->biHeight; pPictInfo->PictCompSize = 0; pPictInfo->PictFormat = 0; pPictInfo->PictBitsPerPixel = pbmiHeader->biBitCount; { LONG lScanLineWidth = (pbmiHeader->biWidth * pbmiHeader->biBitCount); // // round up to nearenst DWORD // lScanLineWidth = (lScanLineWidth + 31) >> 3; // // remove extra bytes // lScanLineWidth &= 0xfffffffc; pPictInfo->PictBytesPerRow = lScanLineWidth; } // // is there a color table // LONG ColorMapSize = 0; LONG bmiSize; if (pbmiHeader->biBitCount == 1) { ColorMapSize = 2; } else if (pbmiHeader->biBitCount == 4) { ColorMapSize = 16; } else if (pbmiHeader->biBitCount == 8) { ColorMapSize = 256; } // // Changed by Indy on 5/18/98 to BITMAPINFOHEADER // bmiSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ColorMapSize; *ppBITMAPINFO = (PBYTE)ALLOC(bmiSize); if (*ppBITMAPINFO != NULL) { memcpy(*ppBITMAPINFO, pbmiHeader, bmiSize); *pBITMAPINFOSize = bmiSize; } else { UnmapViewOfFile(pFile); CloseHandle(hFile); CloseHandle(hMap); return(E_OUTOFMEMORY); } // // Set the time for the image // memcpy(&pPictInfo->TimeStamp, &stCreate, sizeof(pPictInfo->TimeStamp)); // // close up the file // UnmapViewOfFile(pFile); CloseHandle(hMap); CloseHandle(hFile); return(hr); } /**************************************************************************\ * CamLoadThumbnail * * Load the thumbnail of the specified picture * * Arguments: * * pCameraImage - image item * pThumbnail - buffer for thumbnail * pThumbSize - size of thumbnail * * Return Value: * * status * * History: * * 2/9/1998 Mark Enstrom [marke] * 6/9/1998 Indy Zhu [indyz] * \**************************************************************************/ HRESULT TestUsdDevice::CamLoadThumbnail( MEMCAM_IMAGE_CONTEXT *pMCamContext , PBYTE *pThumbnail, LONG *pThumbSize ) { TCHAR pszThumbName[MAX_PATH]; HRESULT hr; BOOL bCacheThumb = TRUE; BOOL bThumbExists = TRUE; PBYTE pTmbPixels; HBITMAP hbmThumb = NULL; PBYTE pThumb = NULL; HANDLE hTmbFile = INVALID_HANDLE_VALUE; HANDLE hTmbMap = NULL; PBYTE pTmbFile = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hMap = NULL; PBYTE pFile = NULL; BITMAPINFO bmiDIB; HDC hdc = NULL; HDC hdcm1 = NULL; WIAS_TRACE((g_hInst,"CamLoadThumbnail")); // // Initialize the return values // *pThumbnail = NULL; *pThumbSize = 0; // // Fill in the size of the tumbnail pixel buffer // bmiDIB.bmiHeader.biSizeImage = 80*60*3; // // Build thumbnail filename Image.bmp.tmb // _tcscpy(pszThumbName, pMCamContext->pszCameraImagePath); _tcscat(pszThumbName, TEXT(".tmb")); __try { hTmbFile = CreateFile( pszThumbName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); // // See if cached thumbnail already exists // if (hTmbFile == INVALID_HANDLE_VALUE) { // // Try to create a new one // hTmbFile = CreateFile( pszThumbName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); // // Thumbnail need to be created // bThumbExists = FALSE; } // // thumbnail file exists // if (hTmbFile != INVALID_HANDLE_VALUE) { hTmbMap = CreateFileMapping( hTmbFile, NULL, PAGE_READWRITE, 0, 80 * 60 * 3, NULL); if (hTmbMap != NULL) { pTmbFile = (PBYTE)MapViewOfFileEx( hTmbMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, NULL); if (pTmbFile) { if (bThumbExists) { // // Alloca memory for thumbnail pixels // pTmbPixels = (PBYTE)ALLOC(bmiDIB.bmiHeader.biSizeImage); if (! pTmbPixels) { return(E_OUTOFMEMORY); } // // Pull the thumbnail from the cached file // memcpy(pTmbPixels, pTmbFile, bmiDIB.bmiHeader.biSizeImage); // // All the handles will be closed in __finally block // *pThumbnail = pTmbPixels; *pThumbSize = bmiDIB.bmiHeader.biSizeImage; return(S_OK); } } else { bCacheThumb = FALSE; } } else { bCacheThumb = FALSE; } } else { // // Can't cache thumbnail // bCacheThumb = FALSE; } // // Try to create a thumbnail from the full-size image // and cache it if the thumbnail cache file is created // hFile = CreateFile( pMCamContext->pszCameraImagePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } hMap = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL ); if (hMap == NULL) { hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } pFile = (PBYTE)MapViewOfFileEx( hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, NULL ); if (pFile == NULL) { hr = HRESULT_FROM_WIN32(::GetLastError()); return(hr); } PBITMAPFILEHEADER pbmFile = (PBITMAPFILEHEADER)pFile; PBITMAPINFO pbmi = (PBITMAPINFO)(pFile + sizeof(BITMAPFILEHEADER)); PBYTE pPixels = pFile + pbmFile->bfOffBits; // // Generate the thumbnail from the full-size image // hdc = GetDC(NULL); hdcm1 = CreateCompatibleDC(hdc); SetStretchBltMode(hdcm1, COLORONCOLOR); // // Create a BITMAP for rendering the thumbnail // bmiDIB.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmiDIB.bmiHeader.biBitCount = 24; bmiDIB.bmiHeader.biWidth = 80; bmiDIB.bmiHeader.biHeight = 60; bmiDIB.bmiHeader.biPlanes = 1; bmiDIB.bmiHeader.biCompression = BI_RGB; bmiDIB.bmiHeader.biXPelsPerMeter = 100; bmiDIB.bmiHeader.biYPelsPerMeter = 100; bmiDIB.bmiHeader.biClrUsed = 0; bmiDIB.bmiHeader.biClrImportant = 0; hbmThumb = CreateDIBSection(hdc, &bmiDIB, DIB_RGB_COLORS, (VOID **)&pThumb, NULL, 0); if (! hbmThumb) { hr = HRESULT_FROM_WIN32(::GetLastError()); return hr; } HBITMAP hbmDef = (HBITMAP)SelectObject(hdcm1, hbmThumb); // // Init DIB // memset(pThumb, 0, bmiDIB.bmiHeader.biSizeImage); // // create 80x60 thumbnail while preserving image // aspect ratio // LONG lThumbWidth; LONG lThumbHeight; double fImageWidth = (double)pbmi->bmiHeader.biWidth; double fImageHeight = (double)pbmi->bmiHeader.biHeight; double fAspect = fImageWidth / fImageHeight; double fDefAspect = 80.0 / 60.0; if (fAspect > fDefAspect) { lThumbWidth = 80; lThumbHeight = (LONG)(80.0 / fAspect); } else { lThumbHeight = 60; lThumbWidth = (LONG)(60.0 * fAspect); } int i = StretchDIBits( hdcm1, 0, 0, lThumbWidth, lThumbHeight, 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, pPixels, pbmi, DIB_RGB_COLORS, SRCCOPY ); SelectObject(hdcm1, hbmDef); // // Cache ? // if (bCacheThumb) { memcpy(pTmbFile, pThumb, bmiDIB.bmiHeader.biSizeImage); } // // Alloca memory for thumbnail pixels // pTmbPixels = (PBYTE)ALLOC(bmiDIB.bmiHeader.biSizeImage); if (! pTmbPixels) { return(E_OUTOFMEMORY); } // // Write out data // memcpy(pTmbPixels, pThumb, bmiDIB.bmiHeader.biSizeImage); *pThumbnail = pTmbPixels; *pThumbSize = bmiDIB.bmiHeader.biSizeImage; return(S_OK); } // End of __try { ... } block __finally { if (pTmbFile) { UnmapViewOfFile(pTmbFile); } if (hTmbMap) { CloseHandle(hTmbMap); } if (hTmbFile != INVALID_HANDLE_VALUE) { CloseHandle(hTmbFile); } if (pFile) { UnmapViewOfFile(pFile); } if (hMap) { CloseHandle(hMap); } if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); } if (hbmThumb) { DeleteObject(hbmThumb); } if (hdcm1) { DeleteDC(hdcm1); } if (hdc) { ReleaseDC(NULL, hdc); } } return(E_FAIL); } /**************************************************************************\ * CamDeletePicture * * * Arguments: * * * * Return Value: * * * * History: * * 6/3/1998 Mark Enstrom [marke] * \**************************************************************************/ HRESULT CamDeletePicture( MEMCAM_IMAGE_CONTEXT *pMCamContext) { return(E_NOTIMPL); } /**************************************************************************\ * CamTakePicture * * * Arguments: * * * * Return Value: * * * * History: * * 6/3/1998 Mark Enstrom [marke] * \**************************************************************************/ HRESULT CamTakePicture( MEMCAM_IMAGE_CONTEXT *pMCamContext , ULONG *pHandle) { return (E_NOTIMPL); } /**************************************************************************\ * VertivalFlip * * * * Arguments: * * * * Return Value: * * Status * * History: * * 11/18/1998 Original Version * \**************************************************************************/ VOID VerticalFlip( PBYTE pImageTop, LONG iHeight, LONG iWidthInBytes) { // // try to allocat a temp scan line buffer // PBYTE pBuffer = (PBYTE)LocalAlloc(LPTR,iWidthInBytes); if (pBuffer != NULL) { LONG index; PBYTE pImageBottom; pImageBottom = pImageTop + (iHeight-1) * iWidthInBytes; for (index = 0;index < (iHeight/2);index++) { memcpy(pBuffer,pImageTop,iWidthInBytes); memcpy(pImageTop,pImageBottom,iWidthInBytes); memcpy(pImageBottom,pBuffer,iWidthInBytes); pImageTop += iWidthInBytes; pImageBottom -= iWidthInBytes; } LocalFree(pBuffer); } }