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.

967 lines
29 KiB

  1. /*++
  2. Copyright (C) 1999- Microsoft Corporation
  3. Module Name:
  4. minidrv.cpp
  5. Abstract:
  6. This module implements main part of CWiaMiniDriver class
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "pch.h"
  12. const WORD TIFFTAG_IMAGELENGTH = 257;
  13. const WORD TIFFTAG_IMAGEWIDTH = 256;
  14. const WORD TIFFTAG_RESOLUTIONUNIT = 296;
  15. const WORD TIFFTAG_PHOTOMETRIC = 262;
  16. const WORD TIFFTAG_COMPRESSION = 259;
  17. const WORD TIFFTAG_XRESOLUTION = 282;
  18. const WORD TIFFTAG_YRESOLUTION = 283;
  19. const WORD TIFFTAG_ROWSPERSTRIP = 278;
  20. const WORD TIFFTAG_STRIPOFFSETS = 273;
  21. const WORD TIFFTAG_STRIPBYTECOUNTS = 279;
  22. const WORD TIFFTAG_COLORMAP = 320;
  23. const WORD TIFFTAG_BITSPERSAMPLE = 258;
  24. const WORD TIFFTAG_SAMPLESPERPIXEL = 277;
  25. const WORD TIFFTAG_ARTIST = 315;
  26. const WORD TIFFTAG_COPYRIGHT = 33432;
  27. const WORD TIFFTAG_DATETIME = 306;
  28. const WORD TIFFTAG_MAKE = 271;
  29. const WORD TIFFTAG_IMAGEDESCRIPTION = 270;
  30. const WORD TIFFTAG_MAXSAMPLEVALUE = 281;
  31. const WORD TIFFTAG_MINSAMPLEVALUE = 280;
  32. const WORD TIFFTAG_MODEL = 272;
  33. const WORD TIFFTAG_NEWSUBFILETYPE = 254;
  34. const WORD TIFFTAG_ORIENTATION = 274;
  35. const WORD TIFFTAG_PLANARCONFIGURATION = 284;
  36. const char LITTLE_ENDIAN_MARKER = 'I';
  37. const char BIG_ENDIAN_MARKER = 'M';
  38. const WORD TIFF_SIGNATURE_I = 0x002A;
  39. const WORD TIFF_SIGNATURE_M = 0x2A00;
  40. const WORD TIFF_PHOTOMETRIC_WHITE = 0;
  41. const WORD TIFF_PHOTOMETRIC_BLACK = 1;
  42. const WORD TIFF_PHOTOMETRIC_RGB = 2;
  43. const WORD TIFF_PHOTOMETRIC_PALETTE = 3;
  44. const WORD TIFF_COMPRESSION_NONE = 1;
  45. const WORD TIFF_TYPE_BYTE = 1;
  46. const WORD TIFF_TYPE_ASCII = 2;
  47. const WORD TIFF_TYPE_SHORT = 3;
  48. const WORD TIFF_TYPE_LONG = 4;
  49. const WORD TIFF_TYPE_RATIONAL = 5;
  50. const WORD TIFF_TYPE_SBYTE = 6;
  51. const WORD TIFF_TYPE_UNDEFINED = 7;
  52. const WORD TIFF_TYPE_SSHORT = 8;
  53. const WORD TIFF_TYPE_SLONG = 9;
  54. const WORD TIFF_TYPE_SRATIONAL = 10;
  55. const WORD TIFF_TYPE_FLOAT = 11;
  56. const WORD TIFF_TYPE_DOUBLE = 12;
  57. typedef struct tagTiffHeader
  58. {
  59. char ByteOrder_1;
  60. char ByteOrder_2;
  61. WORD Signature;
  62. DWORD IFDOffset;
  63. }TIFF_HEADER, *PTIFF_HEADER;
  64. typedef struct tagTiffTag
  65. {
  66. WORD TagId; // tag id
  67. WORD Type; // tag data type
  68. DWORD Count; // how many items
  69. DWORD ValOffset; // offset to the data items
  70. }TIFF_TAG, *PTIFF_TAG;
  71. typedef struct tagTiffImageInfo
  72. {
  73. DWORD ImageHeight;
  74. DWORD ImageWidth;
  75. DWORD BitsPerSample;
  76. DWORD SamplesPerPixel;
  77. DWORD PhotoMetric;
  78. DWORD Compression;
  79. DWORD RowsPerStrip;
  80. DWORD NumStrips;
  81. DWORD *pStripOffsets;
  82. DWORD *pStripByteCounts;
  83. }TIFF_IMAGEINFO, *PTIFF_IMAGEINFO;
  84. WORD
  85. ByteSwapWord(WORD w)
  86. {
  87. return((w &0xFF00) >> 8 | (w & 0xFF) << 8);
  88. }
  89. DWORD
  90. ByteSwapDword(DWORD dw)
  91. {
  92. return((DWORD)(ByteSwapWord((WORD)((dw &0xFFFF0000) >> 16))) |
  93. (DWORD)(ByteSwapWord((WORD)(dw & 0xFFFF))) << 16);
  94. }
  95. DWORD
  96. GetDIBLineSize(
  97. DWORD Width,
  98. DWORD BitsCount
  99. )
  100. {
  101. return(Width * (BitsCount / 8) + 3) & ~3;
  102. }
  103. DWORD
  104. GetDIBSize(
  105. BITMAPINFO *pbmi
  106. )
  107. {
  108. return GetDIBBitsOffset(pbmi) +
  109. GetDIBLineSize(pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biBitCount) *
  110. abs(pbmi->bmiHeader.biHeight);
  111. }
  112. DWORD
  113. GetDIBBitsOffset(
  114. BITMAPINFO *pbmi
  115. )
  116. {
  117. DWORD Offset = (DWORD)-1;
  118. if (pbmi && pbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
  119. {
  120. Offset = pbmi->bmiHeader.biSize;
  121. if (pbmi->bmiHeader.biBitCount <= 8)
  122. {
  123. if (pbmi->bmiHeader.biClrUsed)
  124. {
  125. Offset += pbmi->bmiHeader.biClrUsed * sizeof(RGBQUAD);
  126. }
  127. else
  128. {
  129. Offset += ((DWORD) 1 << pbmi->bmiHeader.biBitCount) * sizeof(RGBQUAD);
  130. }
  131. }
  132. if (BI_BITFIELDS == pbmi->bmiHeader.biCompression)
  133. {
  134. Offset += 3 * sizeof(DWORD);
  135. }
  136. }
  137. return Offset;
  138. }
  139. HRESULT
  140. WINAPI
  141. GetTiffDimensions(
  142. BYTE *pTiff,
  143. UINT TiffSize,
  144. UINT *pWidth,
  145. UINT *pHeight,
  146. UINT *pBitDepth
  147. )
  148. {
  149. if (!pTiff || !TiffSize || !pWidth || !pHeight || !pBitDepth)
  150. return E_INVALIDARG;
  151. DWORD CurOffset;
  152. WORD TagCounts;
  153. BOOL bByteSwap;
  154. TIFF_TAG *pTiffTags;
  155. HRESULT hr;
  156. DWORD BitsPerSample;
  157. DWORD SamplesPerPixel;
  158. if (BIG_ENDIAN_MARKER == *((CHAR *)pTiff) &&
  159. BIG_ENDIAN_MARKER == *((CHAR *)pTiff + 1))
  160. {
  161. if (TIFF_SIGNATURE_M != *((WORD *)pTiff + 1))
  162. return E_INVALIDARG;
  163. bByteSwap = TRUE;
  164. CurOffset = ByteSwapDword(*((DWORD *)(pTiff + 4)));
  165. TagCounts = ByteSwapWord(*((WORD *)(pTiff + CurOffset)));
  166. }
  167. else
  168. {
  169. if (TIFF_SIGNATURE_I != *((WORD *)pTiff + 1))
  170. return E_INVALIDARG;
  171. bByteSwap = FALSE;
  172. CurOffset = *((DWORD *)(pTiff + 4));
  173. TagCounts = *((WORD *)(pTiff + CurOffset));
  174. }
  175. pTiffTags = (TIFF_TAG *)(pTiff + CurOffset + sizeof(WORD));
  176. hr = S_OK;
  177. *pWidth = 0;
  178. *pHeight = 0;
  179. *pBitDepth = 0;
  180. //
  181. // Assuming it is 24bits color
  182. //
  183. BitsPerSample = 8;
  184. SamplesPerPixel = 3;
  185. while (TagCounts && S_OK == hr)
  186. {
  187. WORD TagId;
  188. WORD Type;
  189. DWORD Count;
  190. DWORD ValOffset;
  191. WORD i;
  192. DWORD *pdwOffset;
  193. WORD *pwOffset;
  194. if (bByteSwap)
  195. {
  196. TagId = ByteSwapWord(pTiffTags->TagId);
  197. Type = ByteSwapWord(pTiffTags->Type);
  198. Count = ByteSwapDword(pTiffTags->Count);
  199. ValOffset = ByteSwapDword(pTiffTags->ValOffset);
  200. }
  201. else
  202. {
  203. TagId = pTiffTags->TagId;
  204. Type = pTiffTags->Type;
  205. Count = pTiffTags->Count;
  206. ValOffset = pTiffTags->ValOffset;
  207. }
  208. switch (TagId)
  209. {
  210. case TIFFTAG_IMAGELENGTH:
  211. if (TIFF_TYPE_SHORT == Type)
  212. *pHeight = (WORD)ValOffset;
  213. else
  214. *pHeight = ValOffset;
  215. break;
  216. case TIFFTAG_IMAGEWIDTH:
  217. if (TIFF_TYPE_SHORT == Type)
  218. *pWidth = (WORD)ValOffset;
  219. else
  220. *pWidth = ValOffset;
  221. break;
  222. case TIFFTAG_PHOTOMETRIC:
  223. if (TIFF_PHOTOMETRIC_RGB != (WORD)ValOffset)
  224. {
  225. //
  226. // bi-level or grayscale or palette.
  227. //
  228. SamplesPerPixel = 1;
  229. }
  230. else
  231. {
  232. SamplesPerPixel = 3;
  233. }
  234. break;
  235. case TIFFTAG_BITSPERSAMPLE:
  236. BitsPerSample = (WORD)ValOffset;
  237. break;
  238. case TIFFTAG_SAMPLESPERPIXEL:
  239. SamplesPerPixel = (WORD)ValOffset;
  240. break;
  241. default:
  242. break;
  243. }
  244. pTiffTags++;
  245. TagCounts--;
  246. }
  247. *pBitDepth = SamplesPerPixel * BitsPerSample;
  248. return S_OK;
  249. }
  250. //
  251. // This function converts a TIFF file in memory to DIB bitmap
  252. // Input:
  253. // pTiff -- Tiff file in memory. TIFF, TIFF/EP, TIFF/IT are supported
  254. // TiffSize -- the TIFF file size
  255. // DIBBmpSize -- DIB bitmap buffer size
  256. // pDIBBmp -- DIB bitmap buffer
  257. // LineSize -- destination scanline size in bytes
  258. // MaxLines -- maximum scanline can be delivered per callback
  259. // 0 if we decide it.
  260. // pProgressCB -- optional callback
  261. // pCBContext -- context for the callback.
  262. // If no callback is provided, the given dib
  263. // bitmap buffer must be big enough to
  264. // receive the entire bitmap.
  265. // Output:
  266. // HRESULT -- S_FALSE if the client aborted the transfer
  267. //
  268. HRESULT
  269. WINAPI
  270. Tiff2DIBBitmap(
  271. BYTE *pTiff,
  272. UINT TiffSize,
  273. BYTE *pDIBBmp,
  274. UINT DIBBmpSize,
  275. UINT LineSize,
  276. UINT MaxLines
  277. )
  278. {
  279. if (!pTiff || !TiffSize || !pDIBBmp || !DIBBmpSize || !LineSize)
  280. return E_INVALIDARG;
  281. HRESULT hr;
  282. DWORD CurOffset;
  283. WORD TagCounts;
  284. BOOL bByteSwap;
  285. TIFF_TAG *pTiffTags;
  286. TIFF_IMAGEINFO TiffImageInfo;
  287. ZeroMemory(&TiffImageInfo, sizeof(TiffImageInfo));
  288. //
  289. // Set some default values
  290. //
  291. TiffImageInfo.PhotoMetric = TIFF_PHOTOMETRIC_RGB;
  292. TiffImageInfo.SamplesPerPixel = 3;
  293. TiffImageInfo.BitsPerSample = 8;
  294. TiffImageInfo.Compression = TIFF_COMPRESSION_NONE;
  295. if (BIG_ENDIAN_MARKER == *((CHAR *)pTiff) &&
  296. BIG_ENDIAN_MARKER == *((CHAR *)pTiff + 1))
  297. {
  298. if (TIFF_SIGNATURE_M != *((WORD *)pTiff + 1))
  299. return E_INVALIDARG;
  300. bByteSwap = TRUE;
  301. CurOffset = ByteSwapDword(*((DWORD *)(pTiff + 4)));
  302. TagCounts = ByteSwapWord(*((WORD *)(pTiff + CurOffset)));
  303. }
  304. else
  305. {
  306. if (TIFF_SIGNATURE_I != *((WORD *)pTiff + 1))
  307. return E_INVALIDARG;
  308. bByteSwap = FALSE;
  309. CurOffset = *((DWORD *)(pTiff + 4));
  310. TagCounts = *((WORD *)(pTiff + CurOffset));
  311. }
  312. pTiffTags = (TIFF_TAG *)(pTiff + CurOffset + sizeof(WORD));
  313. hr = S_OK;
  314. while (TagCounts && SUCCEEDED(hr))
  315. {
  316. WORD TagId;
  317. WORD Type;
  318. DWORD Count;
  319. DWORD ValOffset;
  320. WORD i;
  321. DWORD *pdwOffset;
  322. WORD *pwOffset;
  323. if (bByteSwap)
  324. {
  325. TagId = ByteSwapWord(pTiffTags->TagId);
  326. Type = ByteSwapWord(pTiffTags->Type);
  327. Count = ByteSwapDword(pTiffTags->Count);
  328. ValOffset = ByteSwapDword(pTiffTags->ValOffset);
  329. }
  330. else
  331. {
  332. TagId = pTiffTags->TagId;
  333. Type = pTiffTags->Type;
  334. Count = pTiffTags->Count;
  335. ValOffset = pTiffTags->ValOffset;
  336. }
  337. switch (TagId)
  338. {
  339. case TIFFTAG_IMAGELENGTH:
  340. if (TIFF_TYPE_SHORT == Type)
  341. TiffImageInfo.ImageHeight = (WORD)ValOffset;
  342. else
  343. TiffImageInfo.ImageHeight = ValOffset;
  344. break;
  345. case TIFFTAG_IMAGEWIDTH:
  346. if (TIFF_TYPE_SHORT == Type)
  347. TiffImageInfo.ImageWidth = (WORD)ValOffset;
  348. else
  349. TiffImageInfo.ImageWidth = ValOffset;
  350. break;
  351. case TIFFTAG_PHOTOMETRIC:
  352. TiffImageInfo.PhotoMetric = (WORD)ValOffset;
  353. if (TIFF_PHOTOMETRIC_RGB != (WORD)ValOffset)
  354. {
  355. //
  356. // bi-level or grayscale or palette.
  357. //
  358. TiffImageInfo.SamplesPerPixel = 1;
  359. }
  360. else
  361. {
  362. TiffImageInfo.SamplesPerPixel = 3;
  363. }
  364. break;
  365. case TIFFTAG_COMPRESSION:
  366. TiffImageInfo.Compression = ValOffset;
  367. break;
  368. case TIFFTAG_ROWSPERSTRIP:
  369. if (TIFF_TYPE_SHORT == Type)
  370. TiffImageInfo.RowsPerStrip = (WORD)ValOffset;
  371. else
  372. TiffImageInfo.RowsPerStrip = ValOffset;
  373. break;
  374. case TIFFTAG_STRIPOFFSETS:
  375. TiffImageInfo.pStripOffsets = new DWORD[Count];
  376. TiffImageInfo.NumStrips = Count;
  377. if (!TiffImageInfo.pStripOffsets)
  378. {
  379. hr = E_OUTOFMEMORY;
  380. break;
  381. }
  382. for (i = 0; i < Count ; i++)
  383. {
  384. if (TIFF_TYPE_SHORT == Type)
  385. {
  386. pwOffset = (WORD *)(pTiff + ValOffset);
  387. if (bByteSwap)
  388. {
  389. TiffImageInfo.pStripOffsets[i] = ByteSwapWord(*pwOffset);
  390. }
  391. else
  392. {
  393. TiffImageInfo.pStripOffsets[i] = *pwOffset;
  394. }
  395. }
  396. else if (TIFF_TYPE_LONG == Type)
  397. {
  398. pdwOffset = (DWORD *)(pTiff + ValOffset);
  399. if (bByteSwap)
  400. {
  401. TiffImageInfo.pStripOffsets[i] = ByteSwapDword(*pdwOffset);
  402. }
  403. else
  404. {
  405. TiffImageInfo.pStripOffsets[i] = *pdwOffset;
  406. }
  407. }
  408. }
  409. break;
  410. case TIFFTAG_STRIPBYTECOUNTS:
  411. TiffImageInfo.pStripByteCounts = new DWORD[Count];
  412. TiffImageInfo.NumStrips = Count;
  413. if (!TiffImageInfo.pStripByteCounts)
  414. {
  415. hr = E_OUTOFMEMORY;
  416. break;
  417. }
  418. for (i = 0; i < Count ; i++)
  419. {
  420. if (TIFF_TYPE_SHORT == Type)
  421. {
  422. pwOffset = (WORD *)(pTiff + ValOffset);
  423. if (bByteSwap)
  424. {
  425. TiffImageInfo.pStripByteCounts[i] = ByteSwapWord(*pwOffset);
  426. }
  427. else
  428. {
  429. TiffImageInfo.pStripByteCounts[i] = *pwOffset;
  430. }
  431. }
  432. else if (TIFF_TYPE_LONG == Type)
  433. {
  434. pdwOffset = (DWORD *)(pTiff + ValOffset);
  435. if (bByteSwap)
  436. {
  437. TiffImageInfo.pStripByteCounts[i] = ByteSwapDword(*pdwOffset);
  438. }
  439. else
  440. {
  441. TiffImageInfo.pStripByteCounts[i] = *pdwOffset;
  442. }
  443. }
  444. }
  445. break;
  446. case TIFFTAG_BITSPERSAMPLE:
  447. TiffImageInfo.BitsPerSample = (WORD)ValOffset;
  448. break;
  449. case TIFFTAG_SAMPLESPERPIXEL:
  450. TiffImageInfo.SamplesPerPixel = (WORD)ValOffset;
  451. break;
  452. case TIFFTAG_XRESOLUTION:
  453. case TIFFTAG_YRESOLUTION:
  454. case TIFFTAG_RESOLUTIONUNIT:
  455. // do this later
  456. break;
  457. default:
  458. break;
  459. }
  460. pTiffTags++;
  461. TagCounts--;
  462. }
  463. if (!SUCCEEDED(hr))
  464. {
  465. //
  466. // If something wrong happen along the way, free
  467. // any memory we have allocated.
  468. //
  469. if (TiffImageInfo.pStripOffsets)
  470. delete [] TiffImageInfo.pStripOffsets;
  471. if (TiffImageInfo.pStripByteCounts)
  472. delete [] TiffImageInfo.pStripByteCounts;
  473. return hr;
  474. }
  475. //
  476. // Support RGB full color for now.
  477. // Also, we do not support any compression.
  478. //
  479. if (TIFF_PHOTOMETRIC_RGB != TiffImageInfo.PhotoMetric ||
  480. TIFF_COMPRESSION_NONE != TiffImageInfo.Compression ||
  481. DIBBmpSize < LineSize * TiffImageInfo.ImageHeight)
  482. {
  483. delete [] TiffImageInfo.pStripOffsets;
  484. delete [] TiffImageInfo.pStripByteCounts;
  485. return E_INVALIDARG;
  486. }
  487. if (1 == TiffImageInfo.NumStrips)
  488. {
  489. //
  490. // With single strip, the writer may write a
  491. // 2**31 -1(infinity) which would confuses our
  492. // code below. Here, we set it to the right value
  493. //
  494. TiffImageInfo.RowsPerStrip = TiffImageInfo.ImageHeight;
  495. }
  496. //
  497. // DIB scanlines are DWORD aligned while TIFF scanlines
  498. // are BYTE aligned(when the compression value is 1 which
  499. // is the case we enforce). Because of this, we copy the bitmap
  500. // scanline by scanline
  501. //
  502. DWORD NumStrips;
  503. DWORD *pStripOffsets;
  504. DWORD *pStripByteCounts;
  505. DWORD TiffLineSize;
  506. //
  507. // Tiff scanlines with compression 1 are byte aligned.
  508. //
  509. TiffLineSize = TiffImageInfo.ImageWidth * TiffImageInfo. BitsPerSample *
  510. TiffImageInfo.SamplesPerPixel / 8;
  511. //
  512. // For convenience
  513. //
  514. pStripOffsets = TiffImageInfo.pStripOffsets;
  515. pStripByteCounts = TiffImageInfo.pStripByteCounts;
  516. NumStrips = TiffImageInfo.NumStrips;
  517. for (hr = S_OK, NumStrips = TiffImageInfo.NumStrips; NumStrips; NumStrips--)
  518. {
  519. DWORD Lines;
  520. BYTE *pTiffBits;
  521. //
  522. // how many lines to copy in this strip. Ignore any remaining bytes
  523. //
  524. Lines = *pStripByteCounts / TiffLineSize;
  525. //
  526. // The bits
  527. //
  528. pTiffBits = pTiff + *pStripOffsets;
  529. for (hr = S_OK; Lines, S_OK == hr; Lines--)
  530. {
  531. if (DIBBmpSize >= LineSize)
  532. {
  533. memcpy(pDIBBmp, pTiffBits, TiffLineSize);
  534. pDIBBmp -= LineSize;
  535. DIBBmpSize -= LineSize;
  536. }
  537. else
  538. {
  539. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  540. }
  541. pTiffBits += TiffLineSize;
  542. }
  543. pStripOffsets++;
  544. pStripByteCounts++;
  545. }
  546. delete [] TiffImageInfo.pStripOffsets;
  547. delete [] TiffImageInfo.pStripByteCounts;
  548. return hr;
  549. }
  550. ////////////////////////////// GDI+ dynamic linking, image geometry
  551. ////////////////////////////// retrieval & decompression
  552. #include <gdiplus.h>
  553. #include <gdiplusflat.h>
  554. #include <private.h>
  555. HINSTANCE g_hGdiPlus = NULL;
  556. ULONG_PTR g_GdiPlusToken = 0;
  557. GUID g_guidCodecBmp;
  558. Gdiplus::GdiplusStartupInput g_GdiPlusStartupInput;
  559. Gdiplus::GpStatus (WINAPI *pGdipLoadImageFromStream)(IStream *pStream, Gdiplus::GpImage **pImage) = NULL;
  560. Gdiplus::GpStatus (WINAPI *pGdipSaveImageToStream)(Gdiplus::GpImage *image, IStream* stream,
  561. CLSID* clsidEncoder, Gdiplus::EncoderParameters* encoderParams) = NULL;
  562. Gdiplus::GpStatus (WINAPI *pGdipSaveImageToFile)(Gdiplus::GpImage *image, WCHAR * stream,
  563. CLSID* clsidEncoder, Gdiplus::EncoderParameters* encoderParams) = NULL;
  564. Gdiplus::GpStatus (WINAPI *pGdipGetImageWidth)(Gdiplus::GpImage *pImage, UINT *pWidth) = NULL;
  565. Gdiplus::GpStatus (WINAPI *pGdipGetImageHeight)(Gdiplus::GpImage *pImage, UINT *pWidth) = NULL;
  566. Gdiplus::GpStatus (WINAPI *pGdipGetImagePixelFormat)(Gdiplus::GpImage *pImage, Gdiplus::PixelFormat *pFormat) = NULL;
  567. Gdiplus::GpStatus (WINAPI *pGdipDisposeImage)(Gdiplus::GpImage *pImage) = NULL;
  568. Gdiplus::GpStatus (WINAPI *pGdiplusStartup)(ULONG_PTR *token,
  569. const Gdiplus::GdiplusStartupInput *input,
  570. Gdiplus::GdiplusStartupOutput *output) = NULL;
  571. Gdiplus::GpStatus (WINAPI *pGdipGetImageEncodersSize)(UINT *numEncoders, UINT *size) = NULL;
  572. Gdiplus::GpStatus (WINAPI *pGdipGetImageEncoders)(UINT numEncoders, UINT size, Gdiplus::ImageCodecInfo *encoders) = NULL;
  573. VOID (WINAPI *pGdiplusShutdown)(ULONG_PTR token) = NULL;
  574. HRESULT InitializeGDIPlus(void)
  575. {
  576. HRESULT hr = E_FAIL;
  577. Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
  578. g_hGdiPlus = LoadLibraryA("gdiplus.dll");
  579. if(!g_hGdiPlus) {
  580. wiauDbgError("InitializeGDIPlus", "Failed to load gdiplus.dll");
  581. return HRESULT_FROM_WIN32(GetLastError());
  582. }
  583. *((FARPROC*)&pGdipLoadImageFromStream) = GetProcAddress(g_hGdiPlus, "GdipLoadImageFromStream");
  584. *((FARPROC*)&pGdipSaveImageToStream) = GetProcAddress(g_hGdiPlus, "GdipSaveImageToStream");
  585. *((FARPROC*)&pGdipSaveImageToFile) = GetProcAddress(g_hGdiPlus, "GdipSaveImageToFile");
  586. *((FARPROC*)&pGdipGetImageWidth) = GetProcAddress(g_hGdiPlus, "GdipGetImageWidth");
  587. *((FARPROC*)&pGdipGetImageHeight) = GetProcAddress(g_hGdiPlus, "GdipGetImageHeight");
  588. *((FARPROC*)&pGdipGetImagePixelFormat) = GetProcAddress(g_hGdiPlus, "GdipGetImagePixelFormat");
  589. *((FARPROC*)&pGdipDisposeImage) = GetProcAddress(g_hGdiPlus, "GdipDisposeImage");
  590. *((FARPROC*)&pGdiplusStartup) = GetProcAddress(g_hGdiPlus, "GdiplusStartup");
  591. *((FARPROC*)&pGdipGetImageEncodersSize) = GetProcAddress(g_hGdiPlus, "GdipGetImageEncodersSize");
  592. *((FARPROC*)&pGdipGetImageEncoders) = GetProcAddress(g_hGdiPlus, "GdipGetImageEncoders");
  593. *((FARPROC*)&pGdiplusShutdown) = GetProcAddress(g_hGdiPlus, "GdiplusShutdown");
  594. if(!pGdipLoadImageFromStream ||
  595. !pGdipSaveImageToStream ||
  596. !pGdipGetImageWidth ||
  597. !pGdipGetImageHeight ||
  598. !pGdipGetImagePixelFormat ||
  599. !pGdipDisposeImage ||
  600. !pGdiplusStartup ||
  601. !pGdipGetImageEncodersSize ||
  602. !pGdipGetImageEncoders ||
  603. !pGdiplusShutdown)
  604. {
  605. wiauDbgError("InitializeGDIPlus", "Failed to retrieve all the entry points from GDIPLUS.DLL");
  606. hr = E_FAIL;
  607. goto Cleanup;
  608. }
  609. if(Gdiplus::Ok != pGdiplusStartup(&g_GdiPlusToken, &g_GdiPlusStartupInput, NULL)) {
  610. wiauDbgError("InitializeGDIPlus", "GdiPlusStartup() failed");
  611. hr = E_FAIL;
  612. goto Cleanup;
  613. }
  614. UINT num = 0; // number of image encoders
  615. UINT size = 0; // size of the image encoder array in bytes
  616. pGdipGetImageEncodersSize(&num, &size);
  617. if(size == 0)
  618. {
  619. wiauDbgError("InitializeGDIPlus", "GetImageEncodersSize() failed");
  620. hr = E_FAIL;
  621. goto Cleanup;
  622. }
  623. pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
  624. if(pImageCodecInfo == NULL) {
  625. wiauDbgError("InitializeGDIPlus", "failed to allocate encoders data");
  626. hr = E_OUTOFMEMORY;
  627. goto Cleanup;
  628. }
  629. if(Gdiplus::Ok != pGdipGetImageEncoders(num, size, pImageCodecInfo))
  630. {
  631. wiauDbgError("InitializeGDIPlus", "failed to retrieve encoders data");
  632. hr = E_FAIL;
  633. goto Cleanup;
  634. }
  635. for(UINT j = 0; j < num; ++j)
  636. {
  637. if( pImageCodecInfo[j].FormatID == WiaImgFmt_BMP)
  638. {
  639. g_guidCodecBmp = pImageCodecInfo[j].Clsid;
  640. hr = S_OK;
  641. break;
  642. }
  643. } // for
  644. Cleanup:
  645. if(pImageCodecInfo) free(pImageCodecInfo);
  646. return hr;
  647. }
  648. void UnInitializeGDIPlus(void)
  649. {
  650. if(!pGdipLoadImageFromStream)
  651. return;
  652. if(pGdiplusShutdown)
  653. pGdiplusShutdown(g_GdiPlusToken);
  654. FreeLibrary(g_hGdiPlus);
  655. pGdipLoadImageFromStream = 0;
  656. }
  657. HRESULT LoadImageFromMemory(BYTE *pData, UINT CompressedDataSize, Gdiplus::GpImage **ppImage)
  658. {
  659. HRESULT hr = S_OK;
  660. if(pData == NULL || CompressedDataSize == 0 || ppImage == NULL) {
  661. return E_INVALIDARG;
  662. }
  663. if(!pGdipLoadImageFromStream) {
  664. hr = InitializeGDIPlus();
  665. if(FAILED(hr)) {
  666. wiauDbgError("LoadImageFromMemory", "Failed to initialize GDI+");
  667. return hr;
  668. }
  669. }
  670. CImageStream *pStream = new CImageStream();
  671. if(!pStream) {
  672. wiauDbgError("LoadImageFromMemory", "Failed to create Image Stream");
  673. return E_OUTOFMEMORY;
  674. }
  675. hr = pStream->SetBuffer(pData, CompressedDataSize);
  676. if(FAILED(hr)) {
  677. wiauDbgError("LoadImageFromMemory", "Failed to create Image Stream");
  678. goto Cleanup;
  679. }
  680. if(Gdiplus::Ok == pGdipLoadImageFromStream(pStream, ppImage)) {
  681. hr = S_OK;
  682. } else {
  683. wiauDbgError("LoadImageFromMemory", "GDI+ failed to load image");
  684. hr = E_FAIL;
  685. }
  686. Cleanup:
  687. if(pStream)
  688. pStream->Release();
  689. return hr;
  690. }
  691. HRESULT DisposeImage(Gdiplus::GpImage **ppImage)
  692. {
  693. if(ppImage == NULL || *ppImage == NULL) {
  694. return E_INVALIDARG;
  695. }
  696. if(pGdipDisposeImage) {
  697. pGdipDisposeImage(*ppImage);
  698. }
  699. *ppImage = NULL;
  700. return S_OK;
  701. }
  702. HRESULT SaveImageToBitmap(Gdiplus::GpImage *pImage, BYTE *pBuffer, UINT BufferSize)
  703. {
  704. HRESULT hr = S_OK;
  705. CImageStream *pOutStream = new CImageStream;
  706. if(!pOutStream) {
  707. wiauDbgError("SaveImageToBitmap", "failed to allocate CImageStream");
  708. hr = E_OUTOFMEMORY;
  709. goto Cleanup;
  710. }
  711. hr = pOutStream->SetBuffer(pBuffer, BufferSize, SKIP_OFF);
  712. if(FAILED(hr)) {
  713. wiauDbgError("SaveImageToBitmap", "failed to set output buffer");
  714. goto Cleanup;
  715. }
  716. if(Gdiplus::Ok != pGdipSaveImageToStream(pImage, pOutStream, &g_guidCodecBmp, NULL)) {
  717. wiauDbgError("SaveImageToBitmap", "GDI+ save failed");
  718. hr = E_FAIL;
  719. goto Cleanup;
  720. }
  721. Cleanup:
  722. if(pOutStream) {
  723. pOutStream->Release();
  724. }
  725. return hr;
  726. }
  727. HRESULT
  728. WINAPI
  729. GetImageDimensions(
  730. UINT ptpFormatCode,
  731. BYTE *pCompressedData,
  732. UINT CompressedDataSize,
  733. UINT *pWidth,
  734. UINT *pHeight,
  735. UINT *pBitDepth
  736. )
  737. {
  738. HRESULT hr = S_OK;
  739. if(pWidth) *pWidth = 0;
  740. if(pHeight) *pHeight = 0;
  741. if(pBitDepth) *pBitDepth = 0;
  742. // locate GUID for this particular format
  743. FORMAT_INFO *pFormatInfo = FormatCodeToFormatInfo((WORD) ptpFormatCode);
  744. if(pFormatInfo == NULL ||
  745. pFormatInfo->FormatGuid == NULL ||
  746. IsEqualGUID(WiaImgFmt_UNDEFINED, *pFormatInfo->FormatGuid))
  747. {
  748. wiauDbgError("GetImageDimensions", "unrecoginzed PTP format code");
  749. return E_INVALIDARG;
  750. }
  751. Gdiplus::GpImage *pImage = NULL;
  752. hr = LoadImageFromMemory(pCompressedData, CompressedDataSize, &pImage);
  753. if(FAILED(hr) || !pImage) {
  754. wiauDbgError("GetImageDimensions", "failed to create GDI+ image from supplied data.");
  755. return hr;
  756. }
  757. if(pWidth) pGdipGetImageWidth(pImage, pWidth);
  758. if(pHeight) pGdipGetImageHeight(pImage, pHeight);
  759. if(pBitDepth) {
  760. Gdiplus::PixelFormat pf = 0;
  761. pGdipGetImagePixelFormat(pImage, &pf);
  762. *pBitDepth = Gdiplus::GetPixelFormatSize(pf);
  763. }
  764. DisposeImage(&pImage);
  765. return hr;
  766. }
  767. HRESULT WINAPI
  768. ConvertAnyImageToBmp(BYTE *pCompressedImage,
  769. UINT CompressedSize,
  770. UINT *pWidth,
  771. UINT *pHeight,
  772. UINT *pBitDepth,
  773. BYTE **pDIBBmp,
  774. UINT *pImageSize,
  775. UINT *pHeaderSize
  776. )
  777. {
  778. HRESULT hr = S_OK;
  779. Gdiplus::GpImage *pImage = NULL;
  780. Gdiplus::PixelFormat pf = 0;
  781. UINT headersize;
  782. UNALIGNED BITMAPINFOHEADER *pbi;
  783. UNALIGNED BITMAPFILEHEADER *pbf;
  784. if(!pCompressedImage || !CompressedSize || !pWidth || !pHeight || !pBitDepth || !pDIBBmp || !pImageSize || !pHeaderSize)
  785. {
  786. hr = E_INVALIDARG;
  787. goto Cleanup;
  788. }
  789. hr = LoadImageFromMemory(pCompressedImage, CompressedSize, &pImage);
  790. if(FAILED(hr) || !pImage) {
  791. wiauDbgError("ConvertAnyImageToBmp", "failed to create GDI+ image from supplied data.");
  792. goto Cleanup;
  793. }
  794. pGdipGetImageWidth(pImage, pWidth);
  795. pGdipGetImageHeight(pImage, pHeight);
  796. pGdipGetImagePixelFormat(pImage, &pf);
  797. *pBitDepth = Gdiplus::GetPixelFormatSize(pf);
  798. *pImageSize = ((*pWidth) * (*pBitDepth) / 8L) * *pHeight;
  799. headersize = 8192; // big enough to hold any bitmap header
  800. *pDIBBmp = new BYTE[*pImageSize + headersize];
  801. if(!*pDIBBmp) {
  802. wiauDbgError("ConvertAnyImageToBmp", "failed to convert GDI+ image to bitmap.");
  803. hr = E_OUTOFMEMORY;
  804. goto Cleanup;
  805. }
  806. hr = SaveImageToBitmap(pImage, *pDIBBmp, *pImageSize + headersize);
  807. if(FAILED(hr)) {
  808. wiauDbgError("ConvertAnyImageToBmp", "failed to convert GDI+ image to bitmap.");
  809. goto Cleanup;
  810. }
  811. // find out real header size
  812. pbf = (BITMAPFILEHEADER *)*pDIBBmp;
  813. pbi = (BITMAPINFOHEADER *)(*pDIBBmp + sizeof(BITMAPFILEHEADER));
  814. if(*pBitDepth == 8 && pbi->biClrUsed == 2) {
  815. // expand color table for bilevel images
  816. // (TWAIN apps don't understand 2 entry colortable (0,0,0)(1,1,1)
  817. UNALIGNED RGBQUAD *pRgb = (RGBQUAD *)((BYTE *)pbi + pbi->biSize);
  818. BYTE *src = (BYTE *)(pRgb + 2);
  819. BYTE *dst = (BYTE *)(pRgb + 256);
  820. int i;
  821. // negate and move image
  822. for(i = *pImageSize - 1; i >= 0; i--) {
  823. dst[i] = src[i] ? 255 : 0;
  824. }
  825. pbi->biClrUsed = 256;
  826. pbi->biClrImportant = 256;
  827. pRgb[0].rgbBlue = pRgb[0].rgbRed = pRgb[0].rgbGreen = 0;
  828. pRgb[0].rgbReserved = 0;
  829. for(i = 1; i < 256; i++) {
  830. pRgb[i].rgbReserved = 0;
  831. pRgb[i].rgbBlue = pRgb[i].rgbRed = pRgb[i].rgbGreen = 255;
  832. }
  833. pbf->bfOffBits = sizeof(BITMAPFILEHEADER) + pbi->biSize + sizeof(RGBQUAD) * 256;
  834. pbf->bfSize = pbf->bfOffBits + *pImageSize;
  835. }
  836. *pHeaderSize = pbf->bfOffBits;
  837. Cleanup:
  838. if(FAILED(hr)) {
  839. delete [] *pDIBBmp;
  840. *pDIBBmp = NULL;
  841. }
  842. DisposeImage(&pImage);
  843. return hr;
  844. }