tnapi.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 17k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /******************************Module*Header*******************************
  2. * Module Name: tnapi.cpp
  3. *
  4. * Methods for CThumbnailFCNContainer called directly from the shell
  5. *
  6. * Created: 27-Jan-1998
  7. * Author: Ori Gershony [orig]
  8. *
  9. * Copyright (c) 1996 Microsoft Corporation
  10. **************************************************************************/
  11. /**************************************************************************
  12. *
  13. * This module is responsible for encoding and decoding JPEG thumbnails, and
  14. * for storing and retrieving them from the summary information property
  15. * set of image files.  Here is the layout of the thumbnail data on disk:
  16. *
  17. *
  18. * -------------------------------------------------------------------------
  19. * | signature             | fileMiniHeader | jpegMiniHeader | jpeg stream |
  20. * | (THUMBNAIL_CLIPDATA)  |                |                |             |
  21. * -------------------------------------------------------------------------
  22. *
  23. * The 4 APIs in this module are called directly by the shell, and are also
  24. * called by IExtractThumbnail APIs.
  25. *
  26. * Created: 27-Jan-1998
  27. * Author: Ori Gershony [orig]
  28. *
  29. **************************************************************************/
  30. #include "stdafx.h"
  31. #include "jinclude.h"
  32. #include "jpeglib.h"
  33. #include "jversion.h"
  34. #include "jerror.h"
  35. #include "ddraw.h"
  36. #include "jpegapi.h"
  37. #include <atlbase.h>
  38. //You may derive a class from CComModule and use it if you want to override
  39. //something, but do not change the name of _Module
  40. extern CComModule _Module;
  41. #include <atlcom.h>
  42. #include "ImgUtil.h"
  43. #include "ocmm.h"
  44. #include "ctngen.h"
  45. #include "tnail.h"
  46. #include "shlwapi.h"
  47. #include "objbase.h"
  48. EXTERN_C const IID IID_IFlatStorage;  // Defined in ctngen.cpp
  49. //
  50. // JPEG mini-header
  51. //
  52. typedef struct _jpegMiniHeader
  53. {
  54.     ULONG ulVersion;
  55.     ULONG ulStreamSize;
  56.     ULONG ul_x;
  57.     ULONG ul_y;
  58. } jpegMiniHeader;
  59. typedef struct _fileMiniHeader
  60. {
  61.     ULONG ulSize;
  62.     FILETIME filetime;
  63. } fileMiniHeader;
  64. #define TNAIL_CURRENT_VER         1
  65. /******************************Public*Routine******************************
  66. * CThumbnailFCNContainer::EncodeThumbnail
  67. *
  68. *   Encodes a 32BPP thumbnail
  69. *
  70. * Arguments:
  71. *
  72. *   pInputBitmapBits -- A pointer to the bits of the bitmap.  Must be in 32BPP
  73. *       format!
  74. *   ulWidth -- The width of the bitmap
  75. *   ulHeight -- The height of the bitmap
  76. *   ppJPEGBuffer -- if *ppJPEGBuffer is NULL, we will set this to point to the
  77. *       buffer containing the
  78. *       compressed JPEG bytes.  This must be freed by the caller by calling
  79. *       CoTaskMemFree!  If not NULL, the existing pointer will be used.
  80. *   pulBufferSize -- upon exit this will indicate the size of ppJPEGBuffer
  81. *
  82. * Return Value:
  83. *
  84. *     none
  85. *
  86. * History:
  87. *
  88. *     27-Jan-1998 -by- Ori Gershony [orig]
  89. *
  90. **************************************************************************/
  91. STDMETHODIMP
  92. CThumbnailFCNContainer::EncodeThumbnail(
  93.     VOID *pInputBitmapBits,
  94.     ULONG ulWidth,
  95.     ULONG ulHeight,
  96.     VOID **ppJPEGBuffer,
  97.     ULONG *pulBufferSize
  98.     )
  99. {
  100.     //
  101.     // Allocate JPEG buffer if not allocated yet.  Compressed stream should never
  102.     // be larger than uncompressed thumbnail
  103.     //
  104.     if (*ppJPEGBuffer == NULL)
  105.     {
  106.         *ppJPEGBuffer = (VOID *) CoTaskMemAlloc (sizeof(jpegMiniHeader) + ulWidth * ulHeight * 4 + 4096);
  107.         if (*ppJPEGBuffer == NULL)
  108.         {
  109.             return E_OUTOFMEMORY;
  110.         }
  111.     }
  112.     EnterCriticalSection ( &g_csTNGEN );
  113.     //
  114.     // Compress thumbnail into JPEG stream
  115.     //
  116.     ULONG ulJpegSize;
  117.     JPEGFromRGBA((unsigned char *) pInputBitmapBits,
  118.         (BYTE *) *ppJPEGBuffer + sizeof(jpegMiniHeader),
  119.         Thumbnail_Quality,
  120.         &ulJpegSize,
  121.         m_hJpegC,
  122.         JCS_RGBA,
  123.         ulWidth,
  124.         ulHeight
  125.         );
  126.     //
  127.     // Now fill in the header
  128.     //
  129.     jpegMiniHeader *pjMiniH = (jpegMiniHeader *) *ppJPEGBuffer;
  130.     pjMiniH->ulVersion = TNAIL_CURRENT_VER;
  131.     pjMiniH->ulStreamSize = ulJpegSize;
  132.     pjMiniH->ul_x = ulWidth;
  133.     pjMiniH->ul_y = ulHeight;
  134.     *pulBufferSize = ulJpegSize + sizeof(jpegMiniHeader);
  135.     LeaveCriticalSection ( &g_csTNGEN );
  136.     return S_OK;
  137. }
  138. /******************************Public*Routine******************************
  139. * CThumbnailFCNContainer::DecodeThumbnail
  140. *
  141. *   Decode a JPEG stream
  142. *
  143. * Arguments:
  144. *
  145. *     phBitmap -- thumbnail bitmap
  146. *     pulWidth -- width of thumbnail
  147. *     pulHeight -- height of thumbnail
  148. *     pJPEGBuffer -- the compressed JPEG stream
  149. *     ulBufferSize -- the length of pBuffer
  150. *
  151. * Return Value:
  152. *
  153. *     none
  154. *
  155. * History:
  156. *
  157. *     27-Jan-1998 -by- Ori Gershony [orig]
  158. *
  159. **************************************************************************/
  160. STDMETHODIMP
  161. CThumbnailFCNContainer::DecodeThumbnail(
  162.     HBITMAP *phBitmap,
  163.     ULONG *pulWidth,
  164.     ULONG *pulHeight,
  165.     VOID *pJPEGBuffer,
  166.     ULONG ulBufferSize
  167.     )
  168. {
  169.     //
  170.     // Make sure the header is current
  171.     //
  172.     jpegMiniHeader *pjMiniH = (jpegMiniHeader *)pJPEGBuffer;
  173.     if (pjMiniH->ulVersion != TNAIL_CURRENT_VER)
  174.     {
  175.         return E_INVALIDARG;
  176.     }
  177.     EnterCriticalSection ( &g_csTNGEN );
  178.     //
  179.     // Allocate dibsection for thumbnail
  180.     //
  181.     BITMAPINFO bmi;
  182.     bmi.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
  183.     bmi.bmiHeader.biWidth           = pjMiniH->ul_x;
  184.     bmi.bmiHeader.biHeight          = pjMiniH->ul_y;
  185.     bmi.bmiHeader.biPlanes          = 1;
  186.     bmi.bmiHeader.biBitCount        = 32;
  187.     bmi.bmiHeader.biCompression     = BI_RGB;
  188.     bmi.bmiHeader.biSizeImage       = 0;
  189.     bmi.bmiHeader.biXPelsPerMeter   = 0;
  190.     bmi.bmiHeader.biYPelsPerMeter   = 0;
  191.     bmi.bmiHeader.biClrUsed         = 0;
  192.     bmi.bmiHeader.biClrImportant    = 0;
  193.     INT *ppvbits=NULL;
  194.     *phBitmap = CreateDIBSection (NULL, &bmi, DIB_RGB_COLORS, (VOID **)&ppvbits, NULL, 0);
  195.     //
  196.     // Decode the JPEG data
  197.     //
  198.     ULONG ulReturnedNumChannels;
  199.     RGBAFromJPEG((BYTE *)pJPEGBuffer + sizeof(jpegMiniHeader),
  200.         (BYTE *) ppvbits,
  201.         m_hJpegD,
  202.         pjMiniH->ulStreamSize,
  203.         1,
  204.         &ulReturnedNumChannels,
  205.         pjMiniH->ul_x,
  206.         pjMiniH->ul_y
  207.         );
  208.     *pulWidth  = pjMiniH->ul_x;
  209.     *pulHeight = pjMiniH->ul_y;
  210.     LeaveCriticalSection ( &g_csTNGEN );
  211.     return S_OK;
  212. }
  213. /******************************Public*Routine******************************
  214. * CThumbnailFCNContainer::WriteThumbnail
  215. *
  216. *     Write a thumbnail into the summary set property set of an image set
  217. *
  218. * Arguments:
  219. *
  220. *     pBuffer -- points to the buffer containing the compressed thumbnail
  221. *     ulBufferSize -- The size of the buffer pointed to by pBuffer
  222. *     pIStorage -- The storage to use
  223. *     bAlwaysWrite -- If true, write the thumbnail to the file even if the
  224. *         size of the image is less than MIN_JPEG_SIZE.
  225. *
  226. * Return Value:
  227. *
  228. *     none
  229. *
  230. * History:
  231. *
  232. *     27-Jan-1998 -by- Ori Gershony [orig]
  233. *
  234. **************************************************************************/
  235. STDMETHODIMP
  236. CThumbnailFCNContainer::WriteThumbnail(
  237.     VOID *pBuffer,
  238.     ULONG ulBufferSize,
  239.     IPropertySetStorage *pPropSetStg,
  240.     BOOLEAN bAlwaysWrite
  241.     )
  242. {
  243.     HRESULT retVal;
  244.     BOOLEAN bSaveThumbnail;
  245.     //
  246.     // A little bit of validation won't hurt, and can protect us against
  247.     // bad callers
  248.     //
  249.     if (pPropSetStg == NULL)
  250.     {
  251.         return E_INVALIDARG;
  252.     }
  253.     //
  254.     // Suppress timestamp changes
  255.     //
  256.     retVal = SuppressTimestampChanges(pPropSetStg);
  257.     if (FAILED(retVal))
  258.     {
  259.         return retVal;
  260.     }
  261.     EnterCriticalSection ( &g_csTNGEN );
  262.     //
  263.     // Make sure pPropSetStg stays for the duration of this call
  264.     //
  265.     pPropSetStg->AddRef();
  266.     //
  267.     // If the force flag is not set, then don't save thumbnails when the
  268.     // JPEG data is small.
  269.     //
  270.     bSaveThumbnail=TRUE;
  271.     retVal=S_OK;
  272.     if (! bAlwaysWrite)
  273.     {
  274.         IStorage *pStg;
  275.         IStream *pInputStream;
  276.         retVal = pPropSetStg->QueryInterface( IID_IFlatStorage, (PVOID*) & pStg );
  277.         if (SUCCEEDED(retVal))
  278.         {
  279.             //
  280.             // Open the stream containing image data and measure it's size.
  281.             //
  282.             DWORD grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE | STGM_DIRECT;
  283.             retVal = pStg->OpenStream( L"CONTENTS", NULL, grfMode,
  284.                                         0, &pInputStream);
  285.             if (SUCCEEDED(retVal))
  286.             {
  287.                 //
  288.                 // Only save thumbnails for images bigger than MIN_JPEG_SIZE
  289.                 //
  290.                 STATSTG statstg;
  291.                 retVal = pInputStream->Stat(&statstg, STATFLAG_NONAME);
  292.                 if (SUCCEEDED(retVal))
  293.                 {
  294.                     if ((statstg.cbSize.HighPart == 0)
  295.                         && (statstg.cbSize.LowPart <= MIN_JPEG_SIZE))
  296.                     {
  297.                         bSaveThumbnail = FALSE;
  298.                     }
  299.                 }
  300.                 pInputStream->Release();
  301.             }
  302.             pStg->Release();
  303.         }
  304.     }
  305.     //
  306.     // If nothing else has failed so far and we want to save the thumbnail.
  307.     //
  308.     if ((SUCCEEDED(retVal)) && bSaveThumbnail)
  309.     {
  310.         //
  311.         // Now access the property set
  312.         //
  313.         IPropertyStorage *pPropStg = NULL;
  314.         retVal = pPropSetStg->Open(FMTID_DiscardableInformation,
  315.             STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  316.             &pPropStg);
  317.         if (STG_E_FILENOTFOUND == retVal)
  318.         {
  319.             retVal = pPropSetStg->Create(FMTID_DiscardableInformation,
  320.                 &CLSID_NULL,
  321.                 PROPSETFLAG_DEFAULT,
  322.                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  323.                 &pPropStg);
  324.         }
  325.         if (SUCCEEDED(retVal))
  326.         {
  327.             PROPSPEC propSpec[1];
  328.             PROPVARIANT propVar[1];
  329.             CHAR *pTNBuffer;
  330.             if (pTNBuffer = (CHAR *) LocalAlloc(0, JPEG_BUFFER_SIZE))
  331.             {
  332.                 propSpec[0].ulKind = PRSPEC_PROPID;
  333.                 propSpec[0].propid = PIDDI_THUMBNAIL;
  334.                 propVar[0].vt = VT_BLOB;
  335.                 propVar[0].wReserved1 = 0;
  336.                 propVar[0].wReserved2 = 0;
  337.                 propVar[0].wReserved3 = 0;
  338.                 propVar[0].blob.cbSize = ulBufferSize + sizeof(fileMiniHeader);
  339.                 propVar[0].blob.pBlobData = (unsigned char *) pTNBuffer;
  340.                 //
  341.                 // Now get the timestamp
  342.                 //
  343.                 FILETIME filetime;
  344.                 retVal = GetTimeStamp(pPropSetStg, &filetime);
  345.                 if (SUCCEEDED(retVal))
  346.                 {
  347.                     ((fileMiniHeader *) pTNBuffer)->filetime = filetime;
  348.                     ((fileMiniHeader *) pTNBuffer)->ulSize = ulBufferSize + sizeof(fileMiniHeader);
  349.                     CopyMemory (pTNBuffer + sizeof(fileMiniHeader), pBuffer, ulBufferSize);
  350.                     retVal = pPropStg->WriteMultiple(1,
  351.                         propSpec,
  352.                         propVar,
  353.                         PID_FIRST_USABLE);
  354.                     pPropStg->Commit(STGC_DEFAULT);
  355.                 }
  356.                 LocalFree(pTNBuffer);
  357.             }
  358.             else
  359.             {
  360.                 retVal = E_OUTOFMEMORY;
  361.             }
  362.             pPropStg->Release();
  363.         }
  364.     }
  365.     else
  366.     {
  367.         if (SUCCEEDED(retVal))
  368.         {
  369.             //
  370.             // We decided not to save the thumbnail because the file is too small
  371.             //
  372.             retVal = E_FAIL; // A bit cryptic but I can't find anything better...
  373.         }
  374.     }
  375.     pPropSetStg->Release();     // release the stablizing reference.
  376.     LeaveCriticalSection ( &g_csTNGEN );
  377.     return retVal;
  378. }
  379. /******************************Public*Routine******************************
  380. * CThumbnailFCNContainer::ReadThumbnail
  381. *
  382. *   Reads a compressed thumbnail from the summary information property set
  383. *   of an image file.
  384. *
  385. * Arguments:
  386. *
  387. *       ppBuffer -- The buffer where the compressed JPEG stream will be stored.  If
  388. *           *ppBuffer is NULL we will allocate correct amount of memory which must
  389. *           then be freed by the caller by calling CoTaskMemFree.
  390. *       pulBufferSize -- Upon exit this will contain the number of bytes deposited in
  391. *           **ppBuffer.
  392. *       pPropSetStg -- A pointer for an IPropertySetStorage on the image file
  393. *
  394. *
  395. * Return Value:
  396. *
  397. *     none
  398. *
  399. * History:
  400. *
  401. *     27-Jan-1998 -by- Ori Gershony [orig]
  402. *
  403. **************************************************************************/
  404. STDMETHODIMP
  405. CThumbnailFCNContainer::ReadThumbnail(
  406.     VOID **ppBuffer,
  407.     ULONG *pulBufferSize,
  408.     IPropertySetStorage *pPropSetStg
  409.     )
  410. {
  411.     HRESULT retVal;
  412.     //
  413.     // A little bit of validation won't hurt, and can protect us against
  414.     // bad callers
  415.     //
  416.     if (pPropSetStg == NULL)
  417.     {
  418.         return E_INVALIDARG;
  419.     }
  420.     //
  421.     // Suppress timestamp changes
  422.     //  (this should not be necessary on a read.  We should test this.)
  423.     //
  424.     //SuppressTimestampChanges(pPropSetStg);
  425.     EnterCriticalSection ( &g_csTNGEN );
  426.     //
  427.     // Make sure pPropSetStg stays for the duration of this call
  428.     //
  429.     pPropSetStg->AddRef();
  430.     //
  431.     // Access the property set
  432.     //
  433.     IPropertyStorage *pPropStg = NULL;
  434.     //
  435.     // If we can't access the summary information stream, there's nothing
  436.     // more to do (don't create it because we're readers, not writers)
  437.     //
  438.     retVal = pPropSetStg->Open(FMTID_DiscardableInformation,
  439.         STGM_READ | STGM_SHARE_EXCLUSIVE,
  440.         &pPropStg);
  441.     if (SUCCEEDED(retVal))
  442.     {
  443.         //
  444.         // Now try to read the compressed thumbnail
  445.         //
  446.         PROPSPEC propSpec[1];
  447.         PROPVARIANT propVar[1];
  448.         propSpec[0].ulKind = PRSPEC_PROPID;
  449.         propSpec[0].propid = PIDDI_THUMBNAIL;
  450.         retVal = pPropStg->ReadMultiple(1,
  451.             propSpec,
  452.             propVar);
  453.         if (SUCCEEDED(retVal))
  454.         {
  455.             //
  456.             // Make sure we recognize the format of this thumbnail
  457.             //
  458.             if (propVar[0].vt == VT_BLOB)
  459.             {
  460.                 FILETIME filetime;
  461.                 retVal = GetTimeStamp(pPropSetStg, &filetime);
  462.                 if (SUCCEEDED(retVal))
  463.                 {
  464.                     // Should be at least large enough to hold file mini header
  465.                     if (propVar[0].blob.cbSize >= sizeof(fileMiniHeader))
  466.                     {
  467.                         VOID *pThumbnailData = (VOID *) propVar[0].blob.pBlobData;
  468.                         fileMiniHeader *pFileMH = (fileMiniHeader *) pThumbnailData;
  469.                         if ((filetime.dwLowDateTime  == pFileMH->filetime.dwLowDateTime) &&
  470.                             (filetime.dwHighDateTime == pFileMH->filetime.dwHighDateTime))
  471.                         {
  472.                             *pulBufferSize = pFileMH->ulSize - sizeof(fileMiniHeader);
  473.                             if (*pulBufferSize > 0)
  474.                             {
  475.                                 if (*ppBuffer == NULL)
  476.                                 {
  477.                                     *ppBuffer = (VOID *) CoTaskMemAlloc (*pulBufferSize);
  478.                                 }
  479.                                 if (*ppBuffer)
  480.                                 {
  481.                                     CopyMemory (*ppBuffer, (VOID *) (((CHAR *)pThumbnailData) + sizeof(fileMiniHeader)), *pulBufferSize);
  482.                                 }
  483.                                 else
  484.                                 {
  485.                                     retVal = E_OUTOFMEMORY;
  486.                                 }
  487.                             }
  488.                             else
  489.                             {
  490.                                 retVal = E_FAIL;
  491.                             }
  492.                         }
  493.                         else
  494.                         {
  495.                             retVal = TRUST_E_TIME_STAMP;
  496.                         }
  497.                     }
  498.                     else
  499.                     {
  500.                         // Not enough bytes to read file mini header--thumbnail is seriously broken
  501.                         retVal = E_FAIL;
  502.                     }
  503.                 }
  504.             }
  505.             else
  506.             {
  507.                 retVal = E_FAIL;
  508.             }
  509.             FreePropVariantArray(1, propVar);
  510.         }
  511.         else
  512.         {
  513.             retVal = E_FAIL;
  514.         }
  515.         pPropStg->Release();
  516.     }
  517.     else
  518.     {
  519.         retVal = E_FAIL;
  520.     }
  521.     pPropSetStg->Release(); // Release the Stablizing reference.
  522.     LeaveCriticalSection ( &g_csTNGEN );
  523.     return retVal;
  524. }