1154 lines
30 KiB
C++
1154 lines
30 KiB
C++
|
//------------------------------------------------------------------------------
|
||
|
// Copyright (c) 1999 Microsoft Corporation
|
||
|
//
|
||
|
// camxfer.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// Core ircamera (IrUseDevice object) imaging methods.
|
||
|
//
|
||
|
// Author:
|
||
|
// Edward Reus 03-Aug-99
|
||
|
// modeled after code by Mark Enstrom
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <objbase.h>
|
||
|
#include <tchar.h>
|
||
|
#include <sti.h>
|
||
|
#include <malloc.h>
|
||
|
#include "jpegutil.h"
|
||
|
|
||
|
extern HINSTANCE g_hInst; // Global hInstance
|
||
|
|
||
|
#include "ircamera.h"
|
||
|
|
||
|
|
||
|
#if FALSE
|
||
|
//------------------------------------------------------------------------------
|
||
|
// IrUsdDevice::OpenAndMapJPEG()
|
||
|
//
|
||
|
// Open and memory map the JPEG file. The JPEG file is opened read only and
|
||
|
// a pointer to the memory map is returned.
|
||
|
//------------------------------------------------------------------------------
|
||
|
HRESULT IrUsdDevice::OpenAndMapJPEG( IN IRCAM_IMAGE_CONTEXT *pIrCamContext,
|
||
|
OUT BYTE **ppJpeg )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
*ppJpeg = 0;
|
||
|
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// IrUsdDevice::CamLoadPicture()
|
||
|
//
|
||
|
// Read a .JPG image from the disk and copy it to the application.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pIrCamContext --
|
||
|
// pDataTransCtx --
|
||
|
// plCamErrVal --
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// status
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
HRESULT IrUsdDevice::CamLoadPicture( IRCAM_IMAGE_CONTEXT *pIrCamContext,
|
||
|
PMINIDRV_TRANSFER_CONTEXT pDataTransCtx,
|
||
|
PLONG plCamErrVal )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
LONG cbNeeded;
|
||
|
IWiaMiniDrvCallBack *pIProgressCB;
|
||
|
|
||
|
WIAS_TRACE((g_hInst,"IrUsdDevice::CamLoadPicture()"));
|
||
|
|
||
|
//
|
||
|
// Verify call arguments:
|
||
|
//
|
||
|
if ( (!pIrCamContext) || (!plCamErrVal))
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (pDataTransCtx->guidFormatID != WiaImgFmt_JPEG)
|
||
|
{
|
||
|
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 wants to cancel the transfer or error.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HANDLE hFile = CreateFile(
|
||
|
pIrCamContext->pszCameraImagePath,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
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)
|
||
|
{
|
||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(hFile);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the size of the JPEG:
|
||
|
//
|
||
|
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||
|
|
||
|
if (!GetFileInformationByHandle(hFile,&FileInfo))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
CloseHandle(hFile);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Map the JPEG into memory:
|
||
|
//
|
||
|
HANDLE hMap = CreateFileMapping( hFile,
|
||
|
NULL,
|
||
|
PAGE_READONLY,
|
||
|
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)MapViewOfFile(
|
||
|
hMap,
|
||
|
FILE_MAP_READ,
|
||
|
0,
|
||
|
0,
|
||
|
0 );
|
||
|
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 FALSE
|
||
|
//
|
||
|
// 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;
|
||
|
#endif
|
||
|
|
||
|
cbNeeded = FileInfo.nFileSizeLow;
|
||
|
|
||
|
if (cbNeeded > ((LONG)pDataTransCtx->lItemSize - (LONG)pDataTransCtx->cbOffset))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Copy the JPEG image...
|
||
|
//
|
||
|
memcpy(
|
||
|
pDataTransCtx->pTransferBuffer + pDataTransCtx->cbOffset,
|
||
|
pFile,
|
||
|
cbNeeded);
|
||
|
}
|
||
|
|
||
|
UnmapViewOfFile(pFile);
|
||
|
CloseHandle(hMap);
|
||
|
CloseHandle(hFile);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// IrUsdDevice::CamLoadPictureCB()
|
||
|
//
|
||
|
// Return data by filling the data buffer and calling back to the client.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pIrCamContext --
|
||
|
// pTransCtx -- mini driver transfer contect
|
||
|
// plCamErrVal --
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// HRESULT -- E_INVALIDARG
|
||
|
// E_NOTIMPL
|
||
|
// E_FAIL
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
HRESULT IrUsdDevice::CamLoadPictureCB( IRCAM_IMAGE_CONTEXT *pIrCamContext,
|
||
|
MINIDRV_TRANSFER_CONTEXT *pTransCtx,
|
||
|
PLONG plCamErrVal )
|
||
|
{
|
||
|
LONG lScanLineWidth;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
WIAS_TRACE((g_hInst,"IrUsdDevice::CamLoadPictureCB()"));
|
||
|
|
||
|
//
|
||
|
// Verify parameters:
|
||
|
//
|
||
|
if ((!pIrCamContext) || (!plCamErrVal))
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (pTransCtx == NULL)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (pTransCtx->guidFormatID != WiaImgFmt_JPEG)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// try to open disk file
|
||
|
//
|
||
|
|
||
|
HANDLE hFile = CreateFile(
|
||
|
pIrCamContext->pszCameraImagePath,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the size of the JPEG file:
|
||
|
//
|
||
|
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||
|
|
||
|
if (!GetFileInformationByHandle(hFile,&FileInfo))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
CloseHandle(hFile);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HANDLE hMap = CreateFileMapping( hFile,
|
||
|
NULL,
|
||
|
PAGE_READONLY,
|
||
|
0,
|
||
|
0,
|
||
|
NULL );
|
||
|
if (hMap == NULL)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
CloseHandle(hFile);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
PBYTE pFile = (PBYTE)MapViewOfFile(
|
||
|
hMap,
|
||
|
FILE_MAP_READ,
|
||
|
0,
|
||
|
0,
|
||
|
0 );
|
||
|
if (pFile == NULL)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
CloseHandle(hFile);
|
||
|
CloseHandle(hMap);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Callback loop
|
||
|
//
|
||
|
PBYTE pSrc = pFile;
|
||
|
|
||
|
LONG lBytesRemaining = FileInfo.nFileSizeLow;
|
||
|
LONG lTransferSize;
|
||
|
LONG lPercentComplete;
|
||
|
|
||
|
do {
|
||
|
|
||
|
PBYTE pDst = pTransCtx->pTransferBuffer;
|
||
|
|
||
|
//
|
||
|
// Transfer as much data as the transfer buffer will hold:
|
||
|
//
|
||
|
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);
|
||
|
//
|
||
|
// increment pointers (redundant pointers here):
|
||
|
//
|
||
|
pSrc += lTransferSize;
|
||
|
pTransCtx->cbOffset += lTransferSize;
|
||
|
lBytesRemaining -= lTransferSize;
|
||
|
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
} while (lBytesRemaining > 0);
|
||
|
|
||
|
//
|
||
|
// Cleanup:
|
||
|
//
|
||
|
UnmapViewOfFile(pFile);
|
||
|
CloseHandle(hMap);
|
||
|
CloseHandle(hFile);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// IrUsdDevice::CamGetPictureInfo()
|
||
|
//
|
||
|
// Load file and get information from image
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pIrCamContext --
|
||
|
// pPictInfo -- Infomation about the image
|
||
|
// ppBITMAPINFO -- Alloc and fill out BITMAPINFO
|
||
|
// pBITMAPINFOSize -- Size
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// HRESULT -- S_OK - No problem.
|
||
|
// E_FAIL - If we can't parse the JPEG.
|
||
|
// HRESULT mapped Win32 Errors from CreateFile()
|
||
|
//
|
||
|
//------------------------------------------------------------------------------
|
||
|
HRESULT IrUsdDevice::CamGetPictureInfo(
|
||
|
IRCAM_IMAGE_CONTEXT *pIrCamContext ,
|
||
|
CAMERA_PICTURE_INFO *pPictInfo )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
FILETIME ftCreate;
|
||
|
SYSTEMTIME stCreate;
|
||
|
|
||
|
WIAS_TRACE((g_hInst,"IrUsdDevice::CamGetPictureInfo()"));
|
||
|
|
||
|
memset(pPictInfo,0,sizeof(CAMERA_PICTURE_INFO));
|
||
|
|
||
|
//
|
||
|
// Try to open disk file
|
||
|
//
|
||
|
HANDLE hFile = CreateFile(
|
||
|
pIrCamContext->pszCameraImagePath,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the size of the JPEG:
|
||
|
//
|
||
|
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||
|
|
||
|
if (!GetFileInformationByHandle(hFile,&FileInfo))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
CloseHandle(hFile);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the creation time for this image:
|
||
|
//
|
||
|
if ( !GetFileTime( hFile, &ftCreate, NULL, NULL)
|
||
|
|| !FileTimeToSystemTime( &ftCreate, &stCreate) )
|
||
|
{
|
||
|
//
|
||
|
// If either of those fail, then return the system time:
|
||
|
//
|
||
|
GetLocalTime( &stCreate );
|
||
|
}
|
||
|
|
||
|
HANDLE hMap = CreateFileMapping(
|
||
|
hFile,
|
||
|
NULL,
|
||
|
PAGE_READONLY,
|
||
|
0,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
if (hMap == NULL)
|
||
|
{
|
||
|
CloseHandle(hFile);
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
PBYTE pJpeg = (PBYTE)MapViewOfFile(
|
||
|
hMap,
|
||
|
FILE_MAP_READ,
|
||
|
0,
|
||
|
0,
|
||
|
0 );
|
||
|
if (pJpeg == NULL)
|
||
|
{
|
||
|
CloseHandle(hFile);
|
||
|
CloseHandle(hMap);
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get JPEG image dimensions:
|
||
|
//
|
||
|
int iStatus;
|
||
|
long lWidth = 0;
|
||
|
long lHeight = 0;
|
||
|
WORD wNumChannels = 0;
|
||
|
DWORD dwJpegSize = FileInfo.nFileSizeLow;
|
||
|
|
||
|
iStatus = GetJPEGDimensions( pJpeg,
|
||
|
dwJpegSize,
|
||
|
&lWidth,
|
||
|
&lHeight,
|
||
|
&wNumChannels );
|
||
|
if (iStatus != JPEGERR_NO_ERROR)
|
||
|
{
|
||
|
UnmapViewOfFile(pJpeg);
|
||
|
CloseHandle(hFile);
|
||
|
CloseHandle(hMap);
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill out image information:
|
||
|
//
|
||
|
pPictInfo->PictNumber = 0; // Unknown
|
||
|
pPictInfo->ThumbWidth = 80;
|
||
|
pPictInfo->ThumbHeight = 60;
|
||
|
pPictInfo->PictWidth = lWidth;
|
||
|
pPictInfo->PictHeight = lHeight;
|
||
|
pPictInfo->PictCompSize = FileInfo.nFileSizeLow;
|
||
|
pPictInfo->PictFormat = CF_JPEG;
|
||
|
pPictInfo->PictBitsPerPixel = wNumChannels * 8;
|
||
|
pPictInfo->PictBytesPerRow = lWidth*wNumChannels;
|
||
|
|
||
|
memcpy( &pPictInfo->TimeStamp, &stCreate, sizeof(pPictInfo->TimeStamp) );
|
||
|
|
||
|
//
|
||
|
// Cleanup:
|
||
|
//
|
||
|
UnmapViewOfFile(pJpeg);
|
||
|
CloseHandle(hMap);
|
||
|
CloseHandle(hFile);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// IrUsdDevice::CamLoadThumbnail()
|
||
|
//
|
||
|
// Load the thumbnail of the specified picture. The picture is saved as
|
||
|
// a .JPG file, so it needs to be uncompressed into a DIB, then the DIB
|
||
|
// needs to be resized down to thumbnail size. The thumbnail DIBs are saved
|
||
|
// into *.tmb files the first time that they are read so that we only need
|
||
|
// to process them into DIBs once.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pCameraImage - image item
|
||
|
// pThumbnail - buffer for thumbnail
|
||
|
// pThumbSize - size of thumbnail
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// HRESULT: S_OK
|
||
|
// E_OUTOFMEMORY
|
||
|
// E_FAIL
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
HRESULT IrUsdDevice::CamLoadThumbnail(
|
||
|
IN IRCAM_IMAGE_CONTEXT *pIrCamContext,
|
||
|
OUT BYTE **ppThumbnail,
|
||
|
OUT LONG *pThumbSize )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
DWORD dwStatus = 0;
|
||
|
TCHAR pszThumbName[MAX_PATH];
|
||
|
BOOL bThumbExists = TRUE; // True if there is a thumbnail file already.
|
||
|
BOOL bCacheThumb = TRUE; // Should we try to cache the thumbnail if it
|
||
|
// isn't already cached? (TRUE == Yes).
|
||
|
BYTE *pTmbPixels = NULL;
|
||
|
HBITMAP hbmThumb = NULL;
|
||
|
BYTE *pThumb = NULL;
|
||
|
|
||
|
HANDLE hTmbFile = INVALID_HANDLE_VALUE;
|
||
|
HANDLE hTmbMap = NULL;
|
||
|
BYTE *pTmbFile = NULL;
|
||
|
|
||
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
|
HANDLE hMap = NULL;
|
||
|
BYTE *pFile = NULL;
|
||
|
|
||
|
BYTE *pDIB = NULL;
|
||
|
|
||
|
BITMAPINFO bmiDIB;
|
||
|
BITMAPINFO bmiJPEG;
|
||
|
HDC hdc = NULL;
|
||
|
HDC hdcm1 = NULL;
|
||
|
|
||
|
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||
|
|
||
|
long lThumbWidth;
|
||
|
long lThumbHeight;
|
||
|
double fImageWidth;
|
||
|
double fImageHeight;
|
||
|
double fAspect;
|
||
|
double fDefAspect = 80.0 / 60.0;
|
||
|
|
||
|
HBITMAP hbmDef;
|
||
|
|
||
|
int iStatus;
|
||
|
long lWidth;
|
||
|
long lHeight;
|
||
|
WORD wNumChannels;
|
||
|
DWORD dwBytesPerScanLine;
|
||
|
DWORD dwDIBSize;
|
||
|
|
||
|
WIAS_TRACE((g_hInst,"IrUsdDevice::CamLoadThumbnail()"));
|
||
|
|
||
|
//
|
||
|
// Initialize the return values
|
||
|
//
|
||
|
*ppThumbnail = NULL;
|
||
|
*pThumbSize = 0;
|
||
|
|
||
|
//
|
||
|
// Fill in the size of the tumbnail pixel buffer
|
||
|
//
|
||
|
|
||
|
bmiDIB.bmiHeader.biSizeImage = 80*60*3;
|
||
|
|
||
|
//
|
||
|
// Build thumbnail filename: <file>.bmp.tmb
|
||
|
//
|
||
|
_tcscpy(pszThumbName, pIrCamContext->pszCameraImagePath);
|
||
|
_tcscat(pszThumbName, SZ_TMB );
|
||
|
|
||
|
//
|
||
|
// See if a saved copy of the thumbnail already exists:
|
||
|
//
|
||
|
hTmbFile = CreateFile( pszThumbName,
|
||
|
GENERIC_READ | GENERIC_WRITE,
|
||
|
FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
|
||
|
if (hTmbFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
//
|
||
|
// It didn't, try to create a new one:
|
||
|
//
|
||
|
hTmbFile = CreateFile( pszThumbName,
|
||
|
GENERIC_READ | GENERIC_WRITE,
|
||
|
FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
CREATE_NEW,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
|
||
|
//
|
||
|
// So, we need to write into the thumbnail file:
|
||
|
//
|
||
|
bThumbExists = FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we could open (or create a new) .tmb file to hold the
|
||
|
// cached thumbnail then we are Ok to go on...
|
||
|
//
|
||
|
if (hTmbFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
hTmbMap = CreateFileMapping( hTmbFile,
|
||
|
NULL, // No special security
|
||
|
PAGE_READWRITE,
|
||
|
0, // Size high 32bits.
|
||
|
80*60*3,// Size low 32bits. (80*60*3).
|
||
|
NULL); // No handle name.
|
||
|
|
||
|
if (hTmbMap != NULL)
|
||
|
{
|
||
|
pTmbFile = (PBYTE)MapViewOfFile(
|
||
|
hTmbMap,
|
||
|
FILE_MAP_READ | FILE_MAP_WRITE,
|
||
|
0, 0, // Offset (64bit).
|
||
|
0 ); // Map entire file.
|
||
|
|
||
|
if (pTmbFile)
|
||
|
{
|
||
|
if (bThumbExists)
|
||
|
{
|
||
|
//
|
||
|
// Allocate memory for thumbnail pixels:
|
||
|
//
|
||
|
pTmbPixels = (PBYTE)ALLOC(80*60*3);
|
||
|
|
||
|
if (!pTmbPixels)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Pull the thumbnail from the cached file:
|
||
|
//
|
||
|
memcpy( pTmbPixels,
|
||
|
pTmbFile,
|
||
|
80*60*3);
|
||
|
|
||
|
//
|
||
|
// All done for the cached thumbnail case, set
|
||
|
// return values and goto cleanup...
|
||
|
//
|
||
|
*ppThumbnail = pTmbPixels;
|
||
|
*pThumbSize = 80*60*3;
|
||
|
|
||
|
goto cleanup;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// No existing thumbnail file, but opened a new
|
||
|
// file, so we will need to write out to cache:
|
||
|
//
|
||
|
bCacheThumb = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Couldn't memory map the thumbnail file, so don't
|
||
|
// try to cache it:
|
||
|
//
|
||
|
bCacheThumb = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Can't open/create thumbnail file, so we can't cache
|
||
|
// thumbnail:
|
||
|
//
|
||
|
bCacheThumb = FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try to create a thumbnail from the full-size image
|
||
|
// and cache it if the thumbnail cache file was created.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Open the .JPEG image file:
|
||
|
//
|
||
|
hFile = CreateFile(
|
||
|
pIrCamContext->pszCameraImagePath,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
if (!GetFileInformationByHandle(hFile,&FileInfo))
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Map the file into memory:
|
||
|
//
|
||
|
hMap = CreateFileMapping( hFile,
|
||
|
NULL, // No special security.
|
||
|
PAGE_READONLY, // Only read needed.
|
||
|
FileInfo.nFileSizeHigh, // File Size.
|
||
|
FileInfo.nFileSizeLow,
|
||
|
NULL ); // No handle name.
|
||
|
|
||
|
if (hMap == NULL)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
pFile = (PBYTE)MapViewOfFile(
|
||
|
hMap,
|
||
|
FILE_MAP_READ,
|
||
|
0, 0, // 64-bit file offset = 0.
|
||
|
0 ); // Bytes to map. 0 == Entire file.
|
||
|
|
||
|
if (pFile == NULL)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Here is where we will parse out the full JPEG into a DIB. We
|
||
|
// need to read the full JPEG, then squeeze it down to thumbnail
|
||
|
// size.
|
||
|
//
|
||
|
// First, we need to dimensions of the JPEG image:
|
||
|
//
|
||
|
iStatus = GetJPEGDimensions( pFile,
|
||
|
FileInfo.nFileSizeLow,
|
||
|
&lWidth,
|
||
|
&lHeight,
|
||
|
&wNumChannels );
|
||
|
|
||
|
if (iStatus != JPEGERR_NO_ERROR)
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate memory to hold a DIB of the entire JPEG:
|
||
|
//
|
||
|
dwBytesPerScanLine = lWidth * wNumChannels;
|
||
|
dwBytesPerScanLine = (dwBytesPerScanLine + wNumChannels) & 0xFFFFFFFC;
|
||
|
dwDIBSize = dwBytesPerScanLine * lHeight;
|
||
|
|
||
|
pDIB = (BYTE*)ALLOC(dwDIBSize);
|
||
|
|
||
|
if (!pDIB)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert the full JPEG image into a DIB:
|
||
|
//
|
||
|
iStatus = DecompJPEG( pFile,
|
||
|
FileInfo.nFileSizeLow,
|
||
|
pDIB,
|
||
|
dwBytesPerScanLine );
|
||
|
|
||
|
if (iStatus != JPEGERR_NO_ERROR)
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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());
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
hbmDef = (HBITMAP)SelectObject(hdcm1, hbmThumb);
|
||
|
|
||
|
//
|
||
|
// Initialize the DIB:
|
||
|
//
|
||
|
memset( pThumb, 0, bmiDIB.bmiHeader.biSizeImage );
|
||
|
|
||
|
//
|
||
|
// We want to create 80x60 thumbnail while preserving the original
|
||
|
// image aspect ratio.
|
||
|
//
|
||
|
fImageWidth = (double)lWidth;
|
||
|
fImageHeight = (double)lHeight;
|
||
|
fAspect = fImageWidth / fImageHeight;
|
||
|
|
||
|
if (fAspect > fDefAspect)
|
||
|
{
|
||
|
lThumbWidth = 80;
|
||
|
lThumbHeight = (LONG)(80.0 / fAspect);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lThumbHeight = 60;
|
||
|
lThumbWidth = (LONG)(60.0 * fAspect);
|
||
|
}
|
||
|
|
||
|
memset(&bmiJPEG,0,sizeof(bmiJPEG));
|
||
|
|
||
|
bmiJPEG.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bmiJPEG.bmiHeader.biBitCount = 24; // Use 0 for JPEG content.
|
||
|
bmiJPEG.bmiHeader.biWidth = lWidth;
|
||
|
bmiJPEG.bmiHeader.biHeight = lHeight;
|
||
|
bmiJPEG.bmiHeader.biPlanes = 1;
|
||
|
bmiJPEG.bmiHeader.biCompression = BI_RGB; // BI_JPEG;
|
||
|
bmiJPEG.bmiHeader.biXPelsPerMeter = 1000;
|
||
|
bmiJPEG.bmiHeader.biYPelsPerMeter = 1000;
|
||
|
bmiJPEG.bmiHeader.biClrUsed = 0;
|
||
|
bmiJPEG.bmiHeader.biClrImportant = 0;
|
||
|
bmiJPEG.bmiHeader.biSizeImage = FileInfo.nFileSizeLow;
|
||
|
|
||
|
iStatus = StretchDIBits( hdcm1,
|
||
|
0,
|
||
|
0,
|
||
|
lThumbWidth,
|
||
|
lThumbHeight,
|
||
|
0,
|
||
|
0,
|
||
|
lWidth,
|
||
|
lHeight,
|
||
|
pDIB, // pFile is our JPEG.
|
||
|
&bmiJPEG,
|
||
|
DIB_RGB_COLORS,
|
||
|
SRCCOPY );
|
||
|
if (iStatus == GDI_ERROR)
|
||
|
{
|
||
|
dwStatus = ::GetLastError();
|
||
|
hr = HRESULT_FROM_WIN32(dwStatus);
|
||
|
}
|
||
|
|
||
|
SelectObject(hdcm1, hbmDef);
|
||
|
|
||
|
//
|
||
|
// If necessary, cache the thumbnail:
|
||
|
//
|
||
|
if (bCacheThumb)
|
||
|
{
|
||
|
memcpy( pTmbFile, pThumb, bmiDIB.bmiHeader.biSizeImage );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate memory for thumbnail pixels:
|
||
|
//
|
||
|
pTmbPixels = (PBYTE)ALLOC(bmiDIB.bmiHeader.biSizeImage);
|
||
|
if (! pTmbPixels)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Write out the thumbnail data to the cache file:
|
||
|
//
|
||
|
memcpy( pTmbPixels, pThumb, bmiDIB.bmiHeader.biSizeImage);
|
||
|
*ppThumbnail = pTmbPixels;
|
||
|
*pThumbSize = bmiDIB.bmiHeader.biSizeImage;
|
||
|
|
||
|
|
||
|
cleanup:
|
||
|
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 hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// CamDeletePicture()
|
||
|
//
|
||
|
// Delete the specified picture from the temp directory. In this case, all
|
||
|
// that we have to do is delete image (.jpg) and the temporary thumbnail
|
||
|
// file that we created (.tmb).
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pIrCamContext --
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// HRESULT S_OK
|
||
|
// S_FAIL
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
HRESULT IrUsdDevice::CamDeletePicture( IRCAM_IMAGE_CONTEXT *pIrCamContext )
|
||
|
{
|
||
|
DWORD dwStatus;
|
||
|
|
||
|
WIAS_TRACE((g_hInst,"CamDeletePicture(): %s",pIrCamContext->pszCameraImagePath));
|
||
|
|
||
|
//
|
||
|
// First, delete the thumbnail (.tmb) file:
|
||
|
//
|
||
|
DWORD dwLen = _tcslen(pIrCamContext->pszCameraImagePath);
|
||
|
TCHAR *pszThumb = (TCHAR*)_alloca(sizeof(TCHAR)*(dwLen+1) + sizeof(SZ_TMB));
|
||
|
|
||
|
_tcscpy(pszThumb,pIrCamContext->pszCameraImagePath);
|
||
|
_tcscat(pszThumb,SZ_TMB);
|
||
|
|
||
|
if (!DeleteFile(pszThumb))
|
||
|
{
|
||
|
dwStatus = ::GetLastError();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, delete the image (.jpg):
|
||
|
//
|
||
|
if (!DeleteFile(pIrCamContext->pszCameraImagePath))
|
||
|
{
|
||
|
dwStatus = ::GetLastError();
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// CamTakePicture()
|
||
|
//
|
||
|
// Tell the camera to snap a picture. IrTran-P doesn't support this.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// pIrCamContext --
|
||
|
//
|
||
|
// pHandle --
|
||
|
//
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// HRESULT E_NOTIMPL
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
HRESULT CamTakePicture( IRCAM_IMAGE_CONTEXT *pIrCamContext ,
|
||
|
ULONG *pHandle)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|