Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

546 lines
15 KiB

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1998
*
* TITLE: WiaTiff.Cpp
*
* VERSION: 2.0
*
* AUTHOR: ReedB
*
* DATE: 3 June, 1999
*
* DESCRIPTION:
* Implementation of TIFF helpers for WIA class driver.
*
*******************************************************************************/
#include "precomp.h"
#include "stiexe.h"
#include "wiamindr.h"
#include "helpers.h"
#include "wiatiff.h"
/**************************************************************************\
* GetTiffOffset
*
* Convert at TIFF header pointer to a TIFF file offset.
*
* Arguments:
*
* pl - Pointer to convert to an offset.
* pmdtc - Pointer to mini driver context.
*
* Return Value:
*
* Status
*
* History:
*
* 4/5/1999 Original Version
*
\**************************************************************************/
LONG GetTiffOffset(
PLONG pl,
PMINIDRV_TRANSFER_CONTEXT pmdtc)
{
return static_cast<LONG>(reinterpret_cast<LONG_PTR>(pl) - reinterpret_cast<LONG_PTR>(pmdtc->pTransferBuffer)) + pmdtc->lCurIfdOffset;
}
/**************************************************************************\
* WriteTiffHeader
*
* Write a TIFF header to a passed in buffer.
* Arguments:
*
* sNumTags - Number of TIFF tags.
* pmdtc - Pointer to mini driver context.
*
* Return Value:
*
* Status
*
* History:
*
* 4/5/1999 Original Version
*
\**************************************************************************/
HRESULT WriteTiffHeader(
SHORT sNumTags,
PMINIDRV_TRANSFER_CONTEXT pmdtc)
{
//
// Pre initialized TIFF header structures.
//
static TIFF_FILE_HEADER TiffFileHeader =
{
0x4949,
42,
sizeof(TIFF_FILE_HEADER)
};
static TIFF_HEADER TiffHeader =
{
12, // NumTags;
{TIFF_TAG_NewSubfileType, TIFF_TYPE_LONG, 1, 0},
{TIFF_TAG_ImageWidth, TIFF_TYPE_LONG, 1, 0},
{TIFF_TAG_ImageLength, TIFF_TYPE_LONG, 1, 0},
{TIFF_TAG_BitsPerSample, TIFF_TYPE_SHORT, 1, 0},
{TIFF_TAG_Compression, TIFF_TYPE_SHORT, 1, 0},
{TIFF_TAG_PhotometricInterpretation, TIFF_TYPE_SHORT, 1, 0},
{TIFF_TAG_StripOffsets, TIFF_TYPE_LONG, 1, 0},
{TIFF_TAG_RowsPerStrip, TIFF_TYPE_LONG, 1, 0},
{TIFF_TAG_StripByteCounts, TIFF_TYPE_LONG, 1, 0},
{TIFF_TAG_XResolution, TIFF_TYPE_RATIONAL, 1, 0},
{TIFF_TAG_YResolution, TIFF_TYPE_RATIONAL, 1, 0},
{TIFF_TAG_ResolutionUnit, TIFF_TYPE_SHORT, 1, 2},
0, // NextIFD;
0, // XResolution numerator
1, // XResolution denominator
0, // YResolution numerator
1, // YResolution denominator
};
//
// Write the TIFF file header only for the first page.
//
PTIFF_HEADER pth = (PTIFF_HEADER) pmdtc->pTransferBuffer;
if (!pmdtc->lPage) {
memcpy(pmdtc->pTransferBuffer, &TiffFileHeader, sizeof(TiffFileHeader));
pth = (PTIFF_HEADER) ((PBYTE) pth + sizeof(TiffFileHeader));
}
//
// Always write the TIFF header.
//
memcpy(pth, &TiffHeader, sizeof(TiffHeader));
// #define DEBUG_TIFF_HEADER
#ifdef DEBUG_TIFF_HEADER
DBG_TRC(("WriteTiffHeader"));
DBG_TRC((" lPage: 0x%08X, %d", pmdtc->lPage, pmdtc->lPage));
DBG_TRC((" lCurIfdOffset: 0x%08X, %d", pmdtc->lCurIfdOffset, pmdtc->lCurIfdOffset));
DBG_TRC((" lPrevIfdOffset: 0x%08X, %d", pmdtc->lPrevIfdOffset, pmdtc->lPrevIfdOffset));
#endif
//
// Write resolution values and their offsets.
//
pth->XResValue = pmdtc->lXRes;
pth->YResValue = pmdtc->lYRes;
pth->XResolution.Value = GetTiffOffset(&pth->XResValue, pmdtc);
pth->YResolution.Value = GetTiffOffset(&pth->YResValue, pmdtc);
//
// Write width, length values.
//
pth->ImageWidth.Value = pmdtc->lWidthInPixels;
pth->ImageLength.Value = pmdtc->lLines;
pth->RowsPerStrip.Value = pmdtc->lLines;
//
// Write depth value. NOTE: We do this in a really cheesy way, in the
// interests of minimal code change. This should be updated post Whistler.
// Note that BitsPerSample corresponds to the WIA property
// WIA_IPA_BITS_PER_CHANNEL, which we don't have in the
// MINIDRV_TRANSFER_CONTEXT that was handed in to us.
// For the time being, we assume 1 and 8 bit color depths correspond to
// BitsPerSample = pmdtc->lDepth. Anything else (which is generally 24
// for those that use the WIA service helper), is assumed to to be a
// 3 channel RGB, therefore BitsPerSample = pmdtc->lDepth / 3.
//
HRESULT hr = S_OK;
switch (pmdtc->lDepth) {
case 1:
pth->BitsPerSample.Value = 1;
break;
case 8:
pth->BitsPerSample.Value = 8;
break;
default:
if ((pmdtc->lDepth) && ((pmdtc->lDepth % 3) == 0)) {
pth->BitsPerSample.Value = pmdtc->lDepth / 3;
} else {
hr = E_INVALIDARG;
DBG_ERR(("::WriteTiffHeader, Bits Per Pixel is not a valid number (we accept 1, 8, and multiples of 3 for three channel-RGB, current value is %d), returning hr = 0x%08X", pmdtc->lDepth, hr));
return hr;
}
}
//
// Write strip offsets and count - since one strip only, use direct.
//
PBYTE pData = pmdtc->pTransferBuffer + pmdtc->lHeaderSize;
pth->StripOffsets.Value = GetTiffOffset((PLONG)pData, pmdtc);
pth->StripByteCounts.Value = pmdtc->lImageSize;
//
// Write compression value.
//
pth->Compression.Value = TIFF_CMP_Uncompressed;
switch (pmdtc->lCompression) {
case WIA_COMPRESSION_NONE:
pth->Compression.Value = TIFF_CMP_Uncompressed;
break;
case WIA_COMPRESSION_G3:
pth->Compression.Value = TIFF_CMP_CCITT_1D;
break;
default:
DBG_ERR(("WriteTiffHeader, unsupported compression type: 0x%08X", pmdtc->lCompression));
return E_INVALIDARG;
}
//
// Write photometric interpretation value.
//
switch (pmdtc->lDepth) {
case 1:
case 8:
if (pmdtc->lCompression == WIA_COMPRESSION_NONE) {
pth->PhotometricInterpretation.Value = TIFF_PMI_BlackIsZero;
}
else {
pth->PhotometricInterpretation.Value = TIFF_PMI_WhiteIsZero;
}
break;
case 24:
pth->PhotometricInterpretation.Value = TIFF_PMI_RGB;
break;
default:
DBG_ERR(("GetTIFFImageInfo, unsupported bit depth: %d", pmdtc->lDepth));
return DATA_E_FORMATETC;
}
return S_OK;
}
/**************************************************************************\
* GetTIFFImageInfo
*
* Calc size of TIFF header and file, if adequate header is provided then
* fill it out
*
* Arguments:
*
* pmdtc - Pointer to mini driver transfer context.
*
* Return Value:
*
* Status
*
* History:
*
* 4/5/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall GetTIFFImageInfo(PMINIDRV_TRANSFER_CONTEXT pmdtc)
{
//
// Calculate the TIFF header size
//
SHORT numTags = 12;
LONG lHeaderSize;
lHeaderSize = numTags * sizeof(TIFF_DIRECTORY_ENTRY) + // TIFF tags.
sizeof(LONG) + sizeof(SHORT) + // IFD offset and next offset
sizeof(LONG) * 4; // xres and yres
//
// First page has TIFF file header.
//
if (!pmdtc->lPage) {
lHeaderSize += sizeof(TIFF_FILE_HEADER);
}
pmdtc->lHeaderSize = lHeaderSize;
//
// Calculate number of bytes per line, only support 1, 8, 24 bpp now.
//
switch (pmdtc->lDepth) {
case 1:
pmdtc->cbWidthInBytes = (pmdtc->lWidthInPixels + 7) / 8;
break;
case 8:
pmdtc->cbWidthInBytes = pmdtc->lWidthInPixels;
break;
case 24:
pmdtc->cbWidthInBytes = pmdtc->lWidthInPixels * 3;
break;
default:
DBG_ERR(("GetTIFFImageInfo, unsupported bit depth: %d", pmdtc->lDepth));
return DATA_E_FORMATETC;
}
//
// Always fill in mini driver context with image size information.
//
pmdtc->lImageSize = pmdtc->cbWidthInBytes * pmdtc->lLines;
//
// With compression, image size is unknown.
//
if (pmdtc->lCompression != WIA_COMPRESSION_NONE) {
pmdtc->lItemSize = 0;
}
else {
pmdtc->lItemSize = pmdtc->lImageSize + lHeaderSize;
}
//
// If the buffer is null, then just return sizes.
//
if (pmdtc->pTransferBuffer == NULL) {
return S_OK;
}
else {
//
// make sure passed in header buffer is large enough
//
if (pmdtc->lBufferSize < lHeaderSize) {
DBG_ERR(("GetTIFFImageInfo, buffer won't hold header, need: %d", lHeaderSize));
return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
}
//
// Fill in the header
//
return WriteTiffHeader(numTags, pmdtc);
}
}
/**************************************************************************\
* GetMultiPageTIFFImageInfo
*
* Calc size of multi page TIFF header and file, if adequate header buffer
* is provided then fill it out.
*
* Arguments:
*
* pmdtc - Pointer to mini driver transfer context.
*
* Return Value:
*
* Status
*
* History:
*
* 4/5/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall GetMultiPageTIFFImageInfo(PMINIDRV_TRANSFER_CONTEXT pmdtc)
{
HRESULT hr = GetTIFFImageInfo(pmdtc);
//
// The actual page count is not known, so we don't know the total
// image size. The mini driver will need to maintain a buffer.
//
pmdtc->lItemSize = 0;
return hr;
}
/**************************************************************************\
* UpdateFileLong
*
* Update the long value at the passed offset with the passed value.
* The file position is not preserved.
*
* Arguments:
*
* lOffset - Offset from start of file.
* lValue - Value to write.
* pmdtc - Pointer to mini driver transfer context.
*
* Return Value:
*
* Status
*
* History:
*
* 4/5/1999 Original Version
*
\**************************************************************************/
HRESULT _stdcall UpdateFileLong(
LONG lOffset,
LONG lValue,
PMINIDRV_TRANSFER_CONTEXT pmdtc)
{
HRESULT hr = S_OK;
DWORD dwWritten;
// #define DEBUG_FILE_UPDATE
#ifdef DEBUG_FILE_UPDATE
DBG_TRC(("UpdateFileLong"));
DBG_TRC((" lOffset: 0x%08X, %d", lOffset, lOffset));
DBG_TRC((" lValue: 0x%08X, %d", lValue, lValue));
#endif
DWORD dwRes = SetFilePointer((HANDLE)pmdtc->hFile,
lOffset,
NULL,
FILE_BEGIN);
if (dwRes != INVALID_SET_FILE_POINTER) {
if (!WriteFile((HANDLE)pmdtc->hFile,
&lValue,
sizeof(LONG),
&dwWritten,
NULL) ||
(sizeof(LONG) != (LONG) dwWritten)) {
hr = HRESULT_FROM_WIN32(::GetLastError());
DBG_ERR(("UpdateFileLong, error writing long value 0x%X", hr));
return hr;
}
}
else {
hr = HRESULT_FROM_WIN32(::GetLastError());
DBG_ERR(("UpdateFileLong, error 0x%X seeking to offset: %d", hr, lOffset));
return hr;
}
return hr;
}
/**************************************************************************\
* WritePageToMultiPageTiff
*
* Write a page to a multi-page TIFF file.
*
* Arguments:
*
* pmdtc - Pointer to mini-driver transfer context.
*
* Return Value:
*
* Status
*
* History:
*
* 10/2/1998 Original Version
*
\**************************************************************************/
HRESULT _stdcall WritePageToMultiPageTiff(PMINIDRV_TRANSFER_CONTEXT pmdtc)
{
HRESULT hr = S_OK;
DWORD dwWritten;
//
// Save the current file position.
//
DWORD dwCurFilePos = SetFilePointer((HANDLE)pmdtc->hFile,
0,
NULL,
FILE_CURRENT);
//
// If this is not the first page we need to update the next IFD entry.
//
if (pmdtc->lPage) {
hr = UpdateFileLong(((pmdtc->lPage == 1) ? sizeof(TIFF_FILE_HEADER) : 0) +
pmdtc->lPrevIfdOffset + FIELD_OFFSET(_TIFF_HEADER, NextIFD),
pmdtc->lCurIfdOffset,
pmdtc);
if (FAILED(hr)) {
return hr;
}
}
//
// Update the StripByteCounts entry.
//
hr = UpdateFileLong(pmdtc->lCurIfdOffset +
((pmdtc->lPage) ? 0 : sizeof(TIFF_FILE_HEADER)) +
FIELD_OFFSET(_TIFF_HEADER, StripByteCounts) +
FIELD_OFFSET(_TIFF_DIRECTORY_ENTRY, Value),
pmdtc->lItemSize - pmdtc->lHeaderSize,
pmdtc);
if (FAILED(hr)) {
return hr;
}
//
// Save the current file position.
//
SetFilePointer((HANDLE)pmdtc->hFile, dwCurFilePos, NULL, FILE_BEGIN);
//
// Update the current Image File Directory offset.
//
pmdtc->lPrevIfdOffset = pmdtc->lCurIfdOffset;
pmdtc->lCurIfdOffset += pmdtc->lItemSize;
//
// Write the page data and update the page count.
//
if (SUCCEEDED(hr)) {
if (!WriteFile((HANDLE)pmdtc->hFile,
pmdtc->pTransferBuffer,
pmdtc->lItemSize,
&dwWritten,
NULL) ||
(pmdtc->lItemSize != (LONG) dwWritten)) {
hr = HRESULT_FROM_WIN32(::GetLastError());
DBG_ERR(("wiasWriteMultiPageTiffHeader, error 0x%X writing image data", hr));
}
}
pmdtc->lPage++;
return hr;
}