📄 fakecam.cpp
字号:
//
// This function reads a JPEG file looking for the frame header, which contains
// the width and height of the image.
//
HRESULT ReadDimFromJpeg(PTSTR ptszFullName, WORD *pWidth, WORD *pHeight)
{
DBG_FN("ReadDimFromJpeg");
HRESULT hr = S_OK;
BOOL ret;
//
// Locals
//
HANDLE hFile = NULL;
BYTE *pBuffer = NULL;
DWORD BytesRead = 0;
BYTE *pCur = NULL;
int SegmentLength = 0;
const int Overlap = 8; // if pCur gets within Overlap bytes of the end, read another chunk
const DWORD BytesToRead = 32 * 1024;
REQUIRE_ARGS(!ptszFullName || !pWidth || !pHeight, hr, "ReadDimFromJpeg");
*pWidth = 0;
*pHeight = 0;
hFile = CreateFile(ptszFullName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
REQUIRE_FILEHANDLE(hFile, hr, "ReadDimFromJpeg", "CreateFile failed");
pBuffer = new BYTE[BytesToRead];
REQUIRE_ALLOC(pBuffer, hr, "ReadDimFromJpeg");
ret = ReadFile(hFile, pBuffer, BytesToRead, &BytesRead, NULL);
REQUIRE_FILEIO(ret, hr, "ReadDimFromJpeg", "ReadFile failed");
wiauDbgTrace("ReadDimFromJpeg", "Read %d bytes", BytesRead);
pCur = pBuffer;
//
// Pretend that we read Overlap fewer bytes than were actually read
//
BytesRead -= Overlap;
while (SUCCEEDED(hr) &&
BytesRead != 0 &&
pCur[1] != 0xc0)
{
if (pCur[0] != 0xff)
{
wiauDbgError("ReadDimFromJpeg", "Not a JFIF format image");
hr = E_FAIL;
goto Cleanup;
}
//
// if the marker is >= 0xd0 and <= 0xd9 or is equal to 0x01
// there is no length field
//
if (((pCur[1] & 0xf0) == 0xd0 &&
(pCur[1] & 0x0f) < 0xa) ||
pCur[1] == 0x01)
{
SegmentLength = 0;
}
else
{
SegmentLength = ByteSwapWord(*((UNALIGNED WORD *) (pCur + 2)));
}
pCur += SegmentLength + 2;
if (pCur >= pBuffer + BytesRead)
{
memcpy(pBuffer, pBuffer + BytesRead, Overlap);
pCur -= BytesRead;
ret = ReadFile(hFile, pBuffer + Overlap, BytesToRead - Overlap, &BytesRead, NULL);
REQUIRE_FILEIO(ret, hr, "ReadDimFromJpeg", "ReadFile failed");
wiauDbgTrace("ReadDimFromJpeg", "Read %d more bytes", BytesRead);
}
}
if (pCur[0] != 0xff)
{
wiauDbgError("ReadDimFromJpeg", "Not a JFIF format image");
return E_FAIL;
}
*pHeight = ByteSwapWord(*((UNALIGNED WORD *) (pCur + 5)));
*pWidth = ByteSwapWord(*((UNALIGNED WORD *) (pCur + 7)));
Cleanup:
if (pBuffer) {
delete []pBuffer;
}
if (hFile && hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
return hr;
}
//
// The next section contains functions useful for reading information from
// Exif files.
//
HRESULT ReadJpegHdr(PTSTR ptszFullName, BYTE **ppBuf)
{
DBG_FN("ReadJpegHdr");
HRESULT hr = S_OK;
BOOL ret;
//
// Locals
//
HANDLE hFile = NULL;
//
// Note:
//
// The actual first 4 BYTEs from a JPEG IF file could be either:
//
// 0xFF 0xD8 0xFF 0xE0 for a JFIF 1.x file;
// 0xFF 0xD8 0xFF 0xE1 for a EEXIF 2.0 file.
//
// The code here is supporting only the EEXIF version:
//
BYTE JpegHdr[] = {0xff, 0xd8, 0xff, 0xe1};
const int JpegHdrSize = sizeof(JpegHdr) + 2;
BYTE tempBuf[JpegHdrSize];
DWORD BytesRead = 0;
WORD TagSize = 0;
hFile = CreateFile(ptszFullName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
REQUIRE_FILEHANDLE(hFile, hr, "ReadJpegHdr", "CreateFile failed");
ret = ReadFile(hFile, tempBuf, JpegHdrSize, &BytesRead, NULL);
REQUIRE_FILEIO(ret, hr, "ReadJpegHdr", "ReadFile failed");
if (BytesRead != JpegHdrSize) {
wiauDbgError("ReadJpegHdr", "Wrong amount read %d", BytesRead);
hr = E_FAIL;
goto Cleanup;
}
if(memcmp(tempBuf, JpegHdr, sizeof(JpegHdr)) != 0)
{
wiauDbgError("ReadJpegHdr", "JPEG header not found");
hr = E_FAIL;
goto Cleanup;
}
TagSize = GetWord(tempBuf + sizeof(JpegHdr), TRUE);
*ppBuf = new BYTE[TagSize];
REQUIRE_ALLOC(ppBuf, hr, "ReadJpegHdr");
ret = ReadFile(hFile, *ppBuf, TagSize, &BytesRead, NULL);
REQUIRE_FILEIO(ret, hr, "ReadJpegHdr", "ReadFile failed");
if (BytesRead != TagSize)
{
wiauDbgError("ReadJpegHdr", "Wrong amount read %d", BytesRead);
hr = E_FAIL;
goto Cleanup;
}
Cleanup:
if (hFile && hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
return hr;
}
HRESULT ReadExifJpeg(BYTE *pBuf, IFD *pImageIfd, IFD *pThumbIfd, BOOL *pbSwap)
{
DBG_FN("ReadExifJpeg");
HRESULT hr = S_OK;
//
// Note: this tag works only for EEXIF JPEG files
// (older JFIF files need 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01):
//
BYTE ExifTag[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
if (memcmp(pBuf, ExifTag, sizeof(ExifTag)) != 0)
{
wiauDbgError("ReadExifJpeg", "EXIF/JFIF tag not found");
hr = E_FAIL;
goto Cleanup;
}
hr = ReadTiff(pBuf + APP1_OFFSET, pImageIfd, pThumbIfd, pbSwap);
REQUIRE_SUCCESS(hr, "ReadExifJpeg", "ReadTiff failed");
Cleanup:
return hr;
}
HRESULT ReadTiff(BYTE *pBuf, IFD *pImageIfd, IFD *pThumbIfd, BOOL *pbSwap)
{
DBG_FN("ReadTiff");
HRESULT hr = S_OK;
//
// Locals
//
WORD MagicNumber = 0;
*pbSwap = FALSE;
if (pBuf[0] == 0x4d) {
*pbSwap = TRUE;
if (pBuf[1] != 0x4d)
{
wiauDbgError("ReadTiff", "Second TIFF byte swap indicator not present");
hr = E_FAIL;
goto Cleanup;
}
}
else if (pBuf[0] != 0x49 ||
pBuf[1] != 0x49)
{
wiauDbgError("ReadTiff", "TIFF byte swap indicator not present");
hr = E_FAIL;
goto Cleanup;
}
MagicNumber = GetWord(pBuf+2, *pbSwap);
if (MagicNumber != 42)
{
wiauDbgError("ReadTiff", "TIFF magic number not present");
hr = E_FAIL;
goto Cleanup;
}
wiauDbgTrace("ReadTiff", "Reading image IFD");
pImageIfd->Offset = GetDword(pBuf + 4, *pbSwap);
hr = ReadIfd(pBuf, pImageIfd, *pbSwap);
REQUIRE_SUCCESS(hr, "ReadTiff", "ReadIfd failed");
wiauDbgTrace("ReadTiff", "Reading thumb IFD");
pThumbIfd->Offset = pImageIfd->NextIfdOffset;
hr = ReadIfd(pBuf, pThumbIfd, *pbSwap);
REQUIRE_SUCCESS(hr, "ReadTiff", "ReadIfd failed");
Cleanup:
return hr;
}
HRESULT ReadIfd(BYTE *pBuf, IFD *pIfd, BOOL bSwap)
{
DBG_FN("ReadIfd");
HRESULT hr = S_OK;
const int DIR_ENTRY_SIZE = 12;
pBuf += pIfd->Offset;
pIfd->Count = GetWord(pBuf, bSwap);
pIfd->pEntries = new DIR_ENTRY[pIfd->Count];
if (!pIfd->pEntries)
return E_OUTOFMEMORY;
pBuf += 2;
for (int count = 0; count < pIfd->Count; count++)
{
pIfd->pEntries[count].Tag = GetWord(pBuf, bSwap);
pIfd->pEntries[count].Type = GetWord(pBuf + 2, bSwap);
pIfd->pEntries[count].Count = GetDword(pBuf + 4, bSwap);
pIfd->pEntries[count].Offset = GetDword(pBuf + 8, bSwap);
pBuf += DIR_ENTRY_SIZE;
wiauDbgDump("ReadIfd", "Tag 0x%04x, type %2d offset/value 0x%08x",
pIfd->pEntries[count].Tag, pIfd->pEntries[count].Type, pIfd->pEntries[count].Offset);
}
pIfd->NextIfdOffset = GetDword(pBuf, bSwap);
return hr;
}
VOID FreeIfd(IFD *pIfd)
{
if (pIfd->pEntries)
delete []pIfd->pEntries;
pIfd->pEntries = NULL;
}
WORD ByteSwapWord(WORD w)
{
return (w >> 8) | (w << 8);
}
DWORD ByteSwapDword(DWORD dw)
{
return ByteSwapWord((WORD) (dw >> 16)) | (ByteSwapWord((WORD) (dw & 0xffff)) << 16);
}
WORD GetWord(BYTE *pBuf, BOOL bSwap)
{
WORD w = *((UNALIGNED WORD *) pBuf);
if (bSwap)
w = ByteSwapWord(w);
return w;
}
DWORD GetDword(BYTE *pBuf, BOOL bSwap)
{
DWORD dw = *((UNALIGNED DWORD *) pBuf);
if (bSwap)
dw = ByteSwapDword(dw);
return dw;
}
/*
//
// Set the default and valid values for a property
//
VOID
FakeCamera::SetValidValues(
INT index,
CWiaPropertyList *pPropertyList
)
{
HRESULT hr = S_OK;
ULONG ExposureModeList[] = {
EXPOSUREMODE_MANUAL,
EXPOSUREMODE_AUTO,
EXPOSUREMODE_APERTURE_PRIORITY,
EXPOSUREMODE_SHUTTER_PRIORITY,
EXPOSUREMODE_PROGRAM_CREATIVE,
EXPOSUREMODE_PROGRAM_ACTION,
EXPOSUREMODE_PORTRAIT
};
PROPID PropId = pPropertyList->GetPropId(index);
WIA_PROPERTY_INFO *pPropInfo = pPropertyList->GetWiaPropInfo(index);
//
// Based on the property ID, populate the valid values range or list information
//
switch (PropId)
{
case WIA_DPC_EXPOSURE_MODE:
pPropInfo->ValidVal.List.Nom = EXPOSUREMODE_MANUAL;
pPropInfo->ValidVal.List.cNumList = sizeof(ExposureModeList) / sizeof(ExposureModeList[0]);
pPropInfo->ValidVal.List.pList = (BYTE*) ExposureModeList;
break;
case WIA_DPC_EXPOSURE_COMP:
pPropInfo->ValidVal.Range.Nom = 0;
pPropInfo->ValidVal.Range.Min = -200;
pPropInfo->ValidVal.Range.Max = 200;
pPropInfo->ValidVal.Range.Inc = 50;
break;
default:
WIAS_LERROR(g_pIWiaLog,WIALOG_NO_RESOURCE_ID,("FakeCamera::SetValidValues, property 0x%08x not defined", PropId));
return;
}
return;
}
*/
/**************************************************************************\
* DllMain
*
* Main library entry point. Receives DLL event notification from OS.
*
* We are not interested in thread attaches and detaches,
* so we disable thread notifications for performance reasons.
*
* Arguments:
*
* hinst -
* dwReason -
* lpReserved -
*
* Return Value:
*
* Returns TRUE to allow the DLL to load.
*
\**************************************************************************/
extern "C"
BOOL
APIENTRY
DllMain(
HINSTANCE hinst,
DWORD dwReason,
LPVOID lpReserved
)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH:
g_hInst = hinst;
DisableThreadLibraryCalls(hinst);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
/**************************************************************************\
* DllCanUnloadNow
*
* Determines whether the DLL has any outstanding interfaces.
*
* Arguments:
*
* None
*
* Return Value:
*
* Returns S_OK if the DLL can unload, S_FALSE if it is not safe to unload.
*
\**************************************************************************/
extern "C" STDMETHODIMP DllCanUnloadNow(void)
{
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -