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

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1998
  4. *
  5. * TITLE: WiaTiff.Cpp
  6. *
  7. * VERSION: 2.0
  8. *
  9. * AUTHOR: ReedB
  10. *
  11. * DATE: 3 June, 1999
  12. *
  13. * DESCRIPTION:
  14. * Implementation of TIFF helpers for WIA class driver.
  15. *
  16. *******************************************************************************/
  17. #include "precomp.h"
  18. #include "stiexe.h"
  19. #include "wiamindr.h"
  20. #include "helpers.h"
  21. #include "wiatiff.h"
  22. /**************************************************************************\
  23. * GetTiffOffset
  24. *
  25. * Convert at TIFF header pointer to a TIFF file offset.
  26. *
  27. * Arguments:
  28. *
  29. * pl - Pointer to convert to an offset.
  30. * pmdtc - Pointer to mini driver context.
  31. *
  32. * Return Value:
  33. *
  34. * Status
  35. *
  36. * History:
  37. *
  38. * 4/5/1999 Original Version
  39. *
  40. \**************************************************************************/
  41. LONG GetTiffOffset(
  42. PLONG pl,
  43. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  44. {
  45. return static_cast<LONG>(reinterpret_cast<LONG_PTR>(pl) - reinterpret_cast<LONG_PTR>(pmdtc->pTransferBuffer)) + pmdtc->lCurIfdOffset;
  46. }
  47. /**************************************************************************\
  48. * WriteTiffHeader
  49. *
  50. * Write a TIFF header to a passed in buffer.
  51. * Arguments:
  52. *
  53. * sNumTags - Number of TIFF tags.
  54. * pmdtc - Pointer to mini driver context.
  55. *
  56. * Return Value:
  57. *
  58. * Status
  59. *
  60. * History:
  61. *
  62. * 4/5/1999 Original Version
  63. *
  64. \**************************************************************************/
  65. HRESULT WriteTiffHeader(
  66. SHORT sNumTags,
  67. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  68. {
  69. //
  70. // Pre initialized TIFF header structures.
  71. //
  72. static TIFF_FILE_HEADER TiffFileHeader =
  73. {
  74. 0x4949,
  75. 42,
  76. sizeof(TIFF_FILE_HEADER)
  77. };
  78. static TIFF_HEADER TiffHeader =
  79. {
  80. 12, // NumTags;
  81. {TIFF_TAG_NewSubfileType, TIFF_TYPE_LONG, 1, 0},
  82. {TIFF_TAG_ImageWidth, TIFF_TYPE_LONG, 1, 0},
  83. {TIFF_TAG_ImageLength, TIFF_TYPE_LONG, 1, 0},
  84. {TIFF_TAG_BitsPerSample, TIFF_TYPE_SHORT, 1, 0},
  85. {TIFF_TAG_Compression, TIFF_TYPE_SHORT, 1, 0},
  86. {TIFF_TAG_PhotometricInterpretation, TIFF_TYPE_SHORT, 1, 0},
  87. {TIFF_TAG_StripOffsets, TIFF_TYPE_LONG, 1, 0},
  88. {TIFF_TAG_RowsPerStrip, TIFF_TYPE_LONG, 1, 0},
  89. {TIFF_TAG_StripByteCounts, TIFF_TYPE_LONG, 1, 0},
  90. {TIFF_TAG_XResolution, TIFF_TYPE_RATIONAL, 1, 0},
  91. {TIFF_TAG_YResolution, TIFF_TYPE_RATIONAL, 1, 0},
  92. {TIFF_TAG_ResolutionUnit, TIFF_TYPE_SHORT, 1, 2},
  93. 0, // NextIFD;
  94. 0, // XResolution numerator
  95. 1, // XResolution denominator
  96. 0, // YResolution numerator
  97. 1, // YResolution denominator
  98. };
  99. //
  100. // Write the TIFF file header only for the first page.
  101. //
  102. PTIFF_HEADER pth = (PTIFF_HEADER) pmdtc->pTransferBuffer;
  103. if (!pmdtc->lPage) {
  104. memcpy(pmdtc->pTransferBuffer, &TiffFileHeader, sizeof(TiffFileHeader));
  105. pth = (PTIFF_HEADER) ((PBYTE) pth + sizeof(TiffFileHeader));
  106. }
  107. //
  108. // Always write the TIFF header.
  109. //
  110. memcpy(pth, &TiffHeader, sizeof(TiffHeader));
  111. // #define DEBUG_TIFF_HEADER
  112. #ifdef DEBUG_TIFF_HEADER
  113. DBG_TRC(("WriteTiffHeader"));
  114. DBG_TRC((" lPage: 0x%08X, %d", pmdtc->lPage, pmdtc->lPage));
  115. DBG_TRC((" lCurIfdOffset: 0x%08X, %d", pmdtc->lCurIfdOffset, pmdtc->lCurIfdOffset));
  116. DBG_TRC((" lPrevIfdOffset: 0x%08X, %d", pmdtc->lPrevIfdOffset, pmdtc->lPrevIfdOffset));
  117. #endif
  118. //
  119. // Write resolution values and their offsets.
  120. //
  121. pth->XResValue = pmdtc->lXRes;
  122. pth->YResValue = pmdtc->lYRes;
  123. pth->XResolution.Value = GetTiffOffset(&pth->XResValue, pmdtc);
  124. pth->YResolution.Value = GetTiffOffset(&pth->YResValue, pmdtc);
  125. //
  126. // Write width, length values.
  127. //
  128. pth->ImageWidth.Value = pmdtc->lWidthInPixels;
  129. pth->ImageLength.Value = pmdtc->lLines;
  130. pth->RowsPerStrip.Value = pmdtc->lLines;
  131. //
  132. // Write depth value. NOTE: We do this in a really cheesy way, in the
  133. // interests of minimal code change. This should be updated post Whistler.
  134. // Note that BitsPerSample corresponds to the WIA property
  135. // WIA_IPA_BITS_PER_CHANNEL, which we don't have in the
  136. // MINIDRV_TRANSFER_CONTEXT that was handed in to us.
  137. // For the time being, we assume 1 and 8 bit color depths correspond to
  138. // BitsPerSample = pmdtc->lDepth. Anything else (which is generally 24
  139. // for those that use the WIA service helper), is assumed to to be a
  140. // 3 channel RGB, therefore BitsPerSample = pmdtc->lDepth / 3.
  141. //
  142. HRESULT hr = S_OK;
  143. switch (pmdtc->lDepth) {
  144. case 1:
  145. pth->BitsPerSample.Value = 1;
  146. break;
  147. case 8:
  148. pth->BitsPerSample.Value = 8;
  149. break;
  150. default:
  151. if ((pmdtc->lDepth) && ((pmdtc->lDepth % 3) == 0)) {
  152. pth->BitsPerSample.Value = pmdtc->lDepth / 3;
  153. } else {
  154. hr = E_INVALIDARG;
  155. 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));
  156. return hr;
  157. }
  158. }
  159. //
  160. // Write strip offsets and count - since one strip only, use direct.
  161. //
  162. PBYTE pData = pmdtc->pTransferBuffer + pmdtc->lHeaderSize;
  163. pth->StripOffsets.Value = GetTiffOffset((PLONG)pData, pmdtc);
  164. pth->StripByteCounts.Value = pmdtc->lImageSize;
  165. //
  166. // Write compression value.
  167. //
  168. pth->Compression.Value = TIFF_CMP_Uncompressed;
  169. switch (pmdtc->lCompression) {
  170. case WIA_COMPRESSION_NONE:
  171. pth->Compression.Value = TIFF_CMP_Uncompressed;
  172. break;
  173. case WIA_COMPRESSION_G3:
  174. pth->Compression.Value = TIFF_CMP_CCITT_1D;
  175. break;
  176. default:
  177. DBG_ERR(("WriteTiffHeader, unsupported compression type: 0x%08X", pmdtc->lCompression));
  178. return E_INVALIDARG;
  179. }
  180. //
  181. // Write photometric interpretation value.
  182. //
  183. switch (pmdtc->lDepth) {
  184. case 1:
  185. case 8:
  186. if (pmdtc->lCompression == WIA_COMPRESSION_NONE) {
  187. pth->PhotometricInterpretation.Value = TIFF_PMI_BlackIsZero;
  188. }
  189. else {
  190. pth->PhotometricInterpretation.Value = TIFF_PMI_WhiteIsZero;
  191. }
  192. break;
  193. case 24:
  194. pth->PhotometricInterpretation.Value = TIFF_PMI_RGB;
  195. break;
  196. default:
  197. DBG_ERR(("GetTIFFImageInfo, unsupported bit depth: %d", pmdtc->lDepth));
  198. return DATA_E_FORMATETC;
  199. }
  200. return S_OK;
  201. }
  202. /**************************************************************************\
  203. * GetTIFFImageInfo
  204. *
  205. * Calc size of TIFF header and file, if adequate header is provided then
  206. * fill it out
  207. *
  208. * Arguments:
  209. *
  210. * pmdtc - Pointer to mini driver transfer context.
  211. *
  212. * Return Value:
  213. *
  214. * Status
  215. *
  216. * History:
  217. *
  218. * 4/5/1999 Original Version
  219. *
  220. \**************************************************************************/
  221. HRESULT _stdcall GetTIFFImageInfo(PMINIDRV_TRANSFER_CONTEXT pmdtc)
  222. {
  223. //
  224. // Calculate the TIFF header size
  225. //
  226. SHORT numTags = 12;
  227. LONG lHeaderSize;
  228. lHeaderSize = numTags * sizeof(TIFF_DIRECTORY_ENTRY) + // TIFF tags.
  229. sizeof(LONG) + sizeof(SHORT) + // IFD offset and next offset
  230. sizeof(LONG) * 4; // xres and yres
  231. //
  232. // First page has TIFF file header.
  233. //
  234. if (!pmdtc->lPage) {
  235. lHeaderSize += sizeof(TIFF_FILE_HEADER);
  236. }
  237. pmdtc->lHeaderSize = lHeaderSize;
  238. //
  239. // Calculate number of bytes per line, only support 1, 8, 24 bpp now.
  240. //
  241. switch (pmdtc->lDepth) {
  242. case 1:
  243. pmdtc->cbWidthInBytes = (pmdtc->lWidthInPixels + 7) / 8;
  244. break;
  245. case 8:
  246. pmdtc->cbWidthInBytes = pmdtc->lWidthInPixels;
  247. break;
  248. case 24:
  249. pmdtc->cbWidthInBytes = pmdtc->lWidthInPixels * 3;
  250. break;
  251. default:
  252. DBG_ERR(("GetTIFFImageInfo, unsupported bit depth: %d", pmdtc->lDepth));
  253. return DATA_E_FORMATETC;
  254. }
  255. //
  256. // Always fill in mini driver context with image size information.
  257. //
  258. pmdtc->lImageSize = pmdtc->cbWidthInBytes * pmdtc->lLines;
  259. //
  260. // With compression, image size is unknown.
  261. //
  262. if (pmdtc->lCompression != WIA_COMPRESSION_NONE) {
  263. pmdtc->lItemSize = 0;
  264. }
  265. else {
  266. pmdtc->lItemSize = pmdtc->lImageSize + lHeaderSize;
  267. }
  268. //
  269. // If the buffer is null, then just return sizes.
  270. //
  271. if (pmdtc->pTransferBuffer == NULL) {
  272. return S_OK;
  273. }
  274. else {
  275. //
  276. // make sure passed in header buffer is large enough
  277. //
  278. if (pmdtc->lBufferSize < lHeaderSize) {
  279. DBG_ERR(("GetTIFFImageInfo, buffer won't hold header, need: %d", lHeaderSize));
  280. return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  281. }
  282. //
  283. // Fill in the header
  284. //
  285. return WriteTiffHeader(numTags, pmdtc);
  286. }
  287. }
  288. /**************************************************************************\
  289. * GetMultiPageTIFFImageInfo
  290. *
  291. * Calc size of multi page TIFF header and file, if adequate header buffer
  292. * is provided then fill it out.
  293. *
  294. * Arguments:
  295. *
  296. * pmdtc - Pointer to mini driver transfer context.
  297. *
  298. * Return Value:
  299. *
  300. * Status
  301. *
  302. * History:
  303. *
  304. * 4/5/1999 Original Version
  305. *
  306. \**************************************************************************/
  307. HRESULT _stdcall GetMultiPageTIFFImageInfo(PMINIDRV_TRANSFER_CONTEXT pmdtc)
  308. {
  309. HRESULT hr = GetTIFFImageInfo(pmdtc);
  310. //
  311. // The actual page count is not known, so we don't know the total
  312. // image size. The mini driver will need to maintain a buffer.
  313. //
  314. pmdtc->lItemSize = 0;
  315. return hr;
  316. }
  317. /**************************************************************************\
  318. * UpdateFileLong
  319. *
  320. * Update the long value at the passed offset with the passed value.
  321. * The file position is not preserved.
  322. *
  323. * Arguments:
  324. *
  325. * lOffset - Offset from start of file.
  326. * lValue - Value to write.
  327. * pmdtc - Pointer to mini driver transfer context.
  328. *
  329. * Return Value:
  330. *
  331. * Status
  332. *
  333. * History:
  334. *
  335. * 4/5/1999 Original Version
  336. *
  337. \**************************************************************************/
  338. HRESULT _stdcall UpdateFileLong(
  339. LONG lOffset,
  340. LONG lValue,
  341. PMINIDRV_TRANSFER_CONTEXT pmdtc)
  342. {
  343. HRESULT hr = S_OK;
  344. DWORD dwWritten;
  345. // #define DEBUG_FILE_UPDATE
  346. #ifdef DEBUG_FILE_UPDATE
  347. DBG_TRC(("UpdateFileLong"));
  348. DBG_TRC((" lOffset: 0x%08X, %d", lOffset, lOffset));
  349. DBG_TRC((" lValue: 0x%08X, %d", lValue, lValue));
  350. #endif
  351. DWORD dwRes = SetFilePointer((HANDLE)pmdtc->hFile,
  352. lOffset,
  353. NULL,
  354. FILE_BEGIN);
  355. if (dwRes != INVALID_SET_FILE_POINTER) {
  356. if (!WriteFile((HANDLE)pmdtc->hFile,
  357. &lValue,
  358. sizeof(LONG),
  359. &dwWritten,
  360. NULL) ||
  361. (sizeof(LONG) != (LONG) dwWritten)) {
  362. hr = HRESULT_FROM_WIN32(::GetLastError());
  363. DBG_ERR(("UpdateFileLong, error writing long value 0x%X", hr));
  364. return hr;
  365. }
  366. }
  367. else {
  368. hr = HRESULT_FROM_WIN32(::GetLastError());
  369. DBG_ERR(("UpdateFileLong, error 0x%X seeking to offset: %d", hr, lOffset));
  370. return hr;
  371. }
  372. return hr;
  373. }
  374. /**************************************************************************\
  375. * WritePageToMultiPageTiff
  376. *
  377. * Write a page to a multi-page TIFF file.
  378. *
  379. * Arguments:
  380. *
  381. * pmdtc - Pointer to mini-driver transfer context.
  382. *
  383. * Return Value:
  384. *
  385. * Status
  386. *
  387. * History:
  388. *
  389. * 10/2/1998 Original Version
  390. *
  391. \**************************************************************************/
  392. HRESULT _stdcall WritePageToMultiPageTiff(PMINIDRV_TRANSFER_CONTEXT pmdtc)
  393. {
  394. HRESULT hr = S_OK;
  395. DWORD dwWritten;
  396. //
  397. // Save the current file position.
  398. //
  399. DWORD dwCurFilePos = SetFilePointer((HANDLE)pmdtc->hFile,
  400. 0,
  401. NULL,
  402. FILE_CURRENT);
  403. //
  404. // If this is not the first page we need to update the next IFD entry.
  405. //
  406. if (pmdtc->lPage) {
  407. hr = UpdateFileLong(((pmdtc->lPage == 1) ? sizeof(TIFF_FILE_HEADER) : 0) +
  408. pmdtc->lPrevIfdOffset + FIELD_OFFSET(_TIFF_HEADER, NextIFD),
  409. pmdtc->lCurIfdOffset,
  410. pmdtc);
  411. if (FAILED(hr)) {
  412. return hr;
  413. }
  414. }
  415. //
  416. // Update the StripByteCounts entry.
  417. //
  418. hr = UpdateFileLong(pmdtc->lCurIfdOffset +
  419. ((pmdtc->lPage) ? 0 : sizeof(TIFF_FILE_HEADER)) +
  420. FIELD_OFFSET(_TIFF_HEADER, StripByteCounts) +
  421. FIELD_OFFSET(_TIFF_DIRECTORY_ENTRY, Value),
  422. pmdtc->lItemSize - pmdtc->lHeaderSize,
  423. pmdtc);
  424. if (FAILED(hr)) {
  425. return hr;
  426. }
  427. //
  428. // Save the current file position.
  429. //
  430. SetFilePointer((HANDLE)pmdtc->hFile, dwCurFilePos, NULL, FILE_BEGIN);
  431. //
  432. // Update the current Image File Directory offset.
  433. //
  434. pmdtc->lPrevIfdOffset = pmdtc->lCurIfdOffset;
  435. pmdtc->lCurIfdOffset += pmdtc->lItemSize;
  436. //
  437. // Write the page data and update the page count.
  438. //
  439. if (SUCCEEDED(hr)) {
  440. if (!WriteFile((HANDLE)pmdtc->hFile,
  441. pmdtc->pTransferBuffer,
  442. pmdtc->lItemSize,
  443. &dwWritten,
  444. NULL) ||
  445. (pmdtc->lItemSize != (LONG) dwWritten)) {
  446. hr = HRESULT_FROM_WIN32(::GetLastError());
  447. DBG_ERR(("wiasWriteMultiPageTiffHeader, error 0x%X writing image data", hr));
  448. }
  449. }
  450. pmdtc->lPage++;
  451. return hr;
  452. }