/******************************************************************************* * * (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(reinterpret_cast(pl) - reinterpret_cast(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; }