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

Windows Kernel

Development Platform:

Visual C++

  1. #include "thlibpch.h"
  2. CThumbnailMaker::CThumbnailMaker()
  3. {
  4.     pImH = NULL;
  5. }
  6. CThumbnailMaker::~CThumbnailMaker()
  7. {
  8.     if (pImH)
  9.         delete[] pImH;
  10. }
  11. STDMETHODIMP
  12. CThumbnailMaker::Init( UINT uiDstWidth_,
  13.                        UINT uiDstHeight_,
  14.                        UINT uiSrcWidth_,
  15.                        UINT uiSrcHeight_ )
  16. {
  17.     uiDstWidth = uiDstWidth_;
  18.     uiDstHeight = uiDstHeight_;
  19.     uiSrcWidth = uiSrcWidth_;
  20.     uiSrcHeight = uiSrcHeight_;
  21.     if (uiDstWidth < 1 || uiDstHeight < 1 ||
  22.         uiSrcWidth < 1 || uiSrcHeight < 1)
  23.         return E_INVALIDARG;
  24.     if (pImH)
  25.         delete[] pImH;
  26.     pImH = new BGR3[uiDstWidth * uiSrcHeight];
  27.     if (pImH == NULL)
  28.         return E_OUTOFMEMORY;
  29.     return S_OK;
  30. }
  31. void
  32. CThumbnailMaker::Scale( BGR3 *pucDst,
  33.                         UINT uiDstWidth,
  34.                         int iDstBytStep,
  35.                         BGR3 *pucSrc,
  36.                         UINT uiSrcWidth,
  37.                         int iSrcBytStep )
  38. {
  39.     UINT uiDstX;
  40.     int frac, mnum, mden;
  41.     mnum = uiSrcWidth;
  42.     mden = uiDstWidth;
  43.     //
  44.     // Scaling up, use a triangle filter.
  45.     //
  46.     if (mden >= mnum)
  47.     {
  48.         BGR3 *pucSrc1;
  49.         frac = 0;
  50.         //
  51.         // Adjust the slope so that we calculate the fraction of the
  52.         // "next" pixel to use (i.e. should be 0 for the first and
  53.         // last dst pixel).
  54.         //
  55.         --mnum;
  56.         if (--mden == 0)
  57.             mden = 0; // avoid div by 0
  58.         pucSrc1 = (BGR3 *)(((UCHAR *)pucSrc) + iSrcBytStep);
  59.         for (uiDstX = 0; uiDstX < uiDstWidth; ++uiDstX)
  60.         {
  61.             if (frac == 0)
  62.             {
  63.                 (*pucDst)[0] = (*pucSrc)[0];
  64.                 (*pucDst)[1] = (*pucSrc)[1];
  65.                 (*pucDst)[2] = (*pucSrc)[2];
  66.             }
  67.             else
  68.             {
  69.                 (*pucDst)[0] =
  70.                     ((mden - frac) * (*pucSrc)[0] +
  71.                      frac * (*pucSrc1)[0]) / mden;
  72.                 (*pucDst)[1] =
  73.                     ((mden - frac) * (*pucSrc)[1] +
  74.                      frac * (*pucSrc1)[1]) / mden;
  75.                 (*pucDst)[2] =
  76.                     ((mden - frac) * (*pucSrc)[2] +
  77.                      frac * (*pucSrc1)[2]) / mden;
  78.             }
  79.             pucDst = (BGR3 *)((UCHAR *)pucDst + iDstBytStep);
  80.             frac += mnum;
  81.             if (frac >= mden)
  82.             {
  83.                 frac -= mden;
  84.                 pucSrc = (BGR3 *)((UCHAR *)pucSrc +
  85.                           iSrcBytStep);
  86.                 pucSrc1 = (BGR3 *)((UCHAR *)pucSrc1 +
  87.                            iSrcBytStep);
  88.             }
  89.         }
  90.     }
  91.     //
  92.     // Scaling down, use a box filter.
  93.     //
  94.     else
  95.     {
  96.         frac = 0;
  97.         for (uiDstX = 0; uiDstX < uiDstWidth; ++uiDstX)
  98.         {
  99.             UINT uiSum[3];
  100.             UINT uiCnt;
  101.             uiSum[0] = uiSum[1] = uiSum[2] = 0;
  102.             uiCnt = 0;
  103.             frac += mnum;
  104.             while (frac >= mden)
  105.             {
  106.                 uiSum[0] += (*pucSrc)[0];
  107.                 uiSum[1] += (*pucSrc)[1];
  108.                 uiSum[2] += (*pucSrc)[2];
  109.                 ++uiCnt;
  110.                 frac -= mden;
  111.                 pucSrc = (BGR3 *)((UCHAR *)pucSrc +
  112.                           iSrcBytStep);
  113.             }
  114.             (*pucDst)[0] = uiSum[0] / uiCnt;
  115.             (*pucDst)[1] = uiSum[1] / uiCnt;
  116.             (*pucDst)[2] = uiSum[2] / uiCnt;
  117.             pucDst = (BGR3 *)((UCHAR *)pucDst + iDstBytStep);
  118.         }
  119.     }
  120. }
  121. //
  122. // For AddScanline, we scale the input horizontally into our temporary
  123. // image buffer.
  124. //
  125. STDMETHODIMP
  126. CThumbnailMaker::AddScanline( UCHAR *pucSrc,
  127.                               UINT uiY )
  128. {
  129.     if (pucSrc == NULL || uiY >= uiSrcHeight)
  130.         return E_INVALIDARG;
  131.     Scale(pImH + uiY * uiDstWidth, uiDstWidth, sizeof(BGR3),
  132.           (BGR3 *)pucSrc, uiSrcWidth, sizeof(BGR3));
  133.     return S_OK;
  134. }
  135. //
  136. // For GetBITMAPINFO, we complete the scaling vertically and return the
  137. // result as a DIB.
  138. //
  139. STDMETHODIMP
  140. CThumbnailMaker::GetBITMAPINFO( BITMAPINFO **ppBMInfo,
  141.                                 DWORD *pdwSize )
  142. {
  143.     BITMAPINFO *pBMI;
  144.     BITMAPINFOHEADER *pBMIH;
  145.     DWORD dwBPL, dwTotSize;
  146.     UCHAR *pDst;
  147.     UINT uiDstX;
  148.     if (ppBMInfo == NULL)
  149.         return E_INVALIDARG;
  150.     *ppBMInfo = NULL;
  151.     dwBPL = (((uiDstWidth * 24) + 31) >> 3) & ~3;
  152.     dwTotSize = sizeof(BITMAPINFOHEADER) + dwBPL * uiDstHeight;
  153.     pBMI = (BITMAPINFO *)CoTaskMemAlloc(dwTotSize);
  154.     if (pBMI == NULL)
  155.         return E_OUTOFMEMORY;
  156.     pBMIH = &pBMI->bmiHeader;
  157.     pBMIH->biSize = sizeof(BITMAPINFOHEADER);
  158.     pBMIH->biWidth = uiDstWidth;
  159.     pBMIH->biHeight = uiDstHeight;
  160.     pBMIH->biPlanes = 1;
  161.     pBMIH->biBitCount = 24;
  162.     pBMIH->biCompression = BI_RGB;
  163.     pBMIH->biXPelsPerMeter = 0;
  164.     pBMIH->biYPelsPerMeter = 0;
  165.     pBMIH->biSizeImage = dwBPL * uiDstHeight;
  166.     pBMIH->biClrUsed = 0;
  167.     pBMIH->biClrImportant = 0;
  168.     pDst = (UCHAR *)pBMIH + pBMIH->biSize + (uiDstHeight - 1) * dwBPL;
  169.     for (uiDstX = 0; uiDstX < uiDstWidth; ++uiDstX)
  170.     {
  171.         Scale((BGR3 *)pDst + uiDstX, uiDstHeight, -(int)dwBPL,
  172.               pImH + uiDstX, uiSrcHeight, uiDstWidth * sizeof(BGR3));
  173.     }
  174.     *ppBMInfo = pBMI;
  175.     if (pdwSize)
  176.         *pdwSize = dwTotSize;
  177.     return S_OK;
  178. }
  179. STDMETHODIMP
  180. CThumbnailMaker::GetSharpenedBITMAPINFO( UINT uiSharpPct,
  181.                                          BITMAPINFO **ppBMInfo,
  182.                                          DWORD *pdwSize )
  183. {
  184.     BITMAPINFO *pBMISrc;
  185.     HRESULT hr;
  186.     DWORD dwSize;
  187.     int bpl;
  188.     int x, y, wdiag, wadj, wcent;
  189. #define SCALE 10000
  190.     UCHAR *pucDst, *pucSrc[3];
  191.     if (uiSharpPct > 100)
  192.         return E_INVALIDARG;
  193.     //
  194.     // Get the unsharpened bitmap.
  195.     //
  196.     hr = GetBITMAPINFO(ppBMInfo, &dwSize);
  197.     if (FAILED(hr))
  198.         return hr;
  199.     if (pdwSize)
  200.         *pdwSize = dwSize;
  201.     //
  202.     // Create a duplicate to serve as the original.
  203.     //
  204.     pBMISrc = (BITMAPINFO *)new UCHAR[dwSize];
  205.     if (pBMISrc == NULL)
  206.     {
  207.         delete *ppBMInfo;
  208.         return E_OUTOFMEMORY;
  209.     }
  210.     memcpy(pBMISrc, *ppBMInfo, dwSize);
  211.     bpl = (pBMISrc->bmiHeader.biWidth * 3 + 3) & ~3;
  212.     //
  213.     // Sharpen inside a 1 pixel border
  214.     //
  215.     pucDst = (UCHAR *)*ppBMInfo + sizeof(BITMAPINFOHEADER);
  216.     pucSrc[0] = (UCHAR *)pBMISrc + sizeof(BITMAPINFOHEADER);
  217.     pucSrc[1] = pucSrc[0] + bpl;
  218.     pucSrc[2] = pucSrc[1] + bpl;
  219.     wdiag = (10355 * uiSharpPct) / 100;
  220.     wadj = (14645 * uiSharpPct) / 100;
  221.     wcent = 4 * (wdiag + wadj);
  222.     for (y = 1; y < pBMISrc->bmiHeader.biHeight-1; ++y)
  223.     {
  224.         for (x = 3*(pBMISrc->bmiHeader.biWidth-2); x >= 3; --x)
  225.         {
  226.             int v;
  227.             v = pucDst[x] +
  228.                 (pucSrc[1][x] * wcent -
  229.                  ((pucSrc[0][x - 3] +
  230.                    pucSrc[0][x + 3] +
  231.                    pucSrc[2][x - 3] +
  232.                    pucSrc[2][x + 3]) * wdiag +
  233.                   (pucSrc[0][x] +
  234.                    pucSrc[1][x - 3] +
  235.                    pucSrc[1][x + 3] +
  236.                    pucSrc[2][x]) * wadj)) / SCALE;
  237.             pucDst[x] = v < 0 ? 0 : v > 255 ? 255 : v;
  238.         }
  239.         pucDst += bpl;
  240.         pucSrc[0] = pucSrc[1];
  241.         pucSrc[1] = pucSrc[2];
  242.         pucSrc[2] += bpl;
  243.     }
  244.     delete[] pBMISrc;
  245.     return S_OK;
  246. #undef SCALE
  247. }
  248. HRESULT ThumbnailMaker_Create( IThumbnailMaker **ppThumbMaker )
  249. {
  250.     HRESULT hr;
  251.     CThumbnailMaker *pCThumbMaker;
  252.     if (ppThumbMaker == NULL)
  253.         return E_UNEXPECTED;
  254.     hr = S_OK;
  255.     pCThumbMaker = new CComObject<CThumbnailMaker>;
  256.     if (pCThumbMaker == NULL || FAILED(hr))
  257.     {
  258.         if (pCThumbMaker)
  259.             delete pCThumbMaker;
  260.         else
  261.             hr = E_OUTOFMEMORY;
  262.             
  263.         *ppThumbMaker = NULL;
  264.         return hr;
  265.     }
  266.     *ppThumbMaker = (IThumbnailMaker *) pCThumbMaker;
  267.     pCThumbMaker->AddRef();
  268.     return S_OK;
  269. }
  270. STDMETHODIMP CThumbnailMaker::AddDIB(BITMAPINFO *pBMI)
  271. {
  272.     UCHAR * pBits;
  273.     int ncolors;
  274.     
  275.     ncolors = pBMI->bmiHeader.biClrUsed;
  276.     if (ncolors == 0 && pBMI->bmiHeader.biBitCount <= 8)
  277.         ncolors = 1 << pBMI->bmiHeader.biBitCount;
  278.         
  279.     if (pBMI->bmiHeader.biBitCount == 16 ||
  280.         pBMI->bmiHeader.biBitCount == 32)
  281.     {
  282.         if (pBMI->bmiHeader.biCompression == BI_BITFIELDS)
  283.         {
  284.             ncolors = 3;
  285.         }
  286.     }
  287.     pBits = (UCHAR *)&pBMI->bmiColors[0] + ncolors * sizeof(RGBQUAD);
  288.     return AddDIBSECTION( pBMI, (LPVOID) pBits );
  289. }
  290. STDMETHODIMP CThumbnailMaker::AddDIBSECTION ( BITMAPINFO * pBMI, LPVOID pBits )
  291. {
  292.     RGBQUAD *pRGBQ, *pQ;
  293.     UCHAR *pucBits0, *pucBits, *pB, *pucBits240, *pucBits24, *pB24;
  294.     int bpl;
  295.     int x, y, ncolors;
  296.     ULONG rmask, gmask, bmask;
  297.     int rshift, gshift, bshift;
  298.     HRESULT hr;
  299.     //
  300.     // Make sure that thumbnail maker has been properly initialized.
  301.     //
  302.     if (pBMI == NULL)
  303.         return E_INVALIDARG;
  304.     if (pBMI->bmiHeader.biWidth != (LONG)uiSrcWidth ||
  305.         pBMI->bmiHeader.biHeight != (LONG)uiSrcHeight)
  306.         return E_INVALIDARG;
  307.     //
  308.     // Don't handle RLE.
  309.     //
  310.     if (pBMI->bmiHeader.biCompression != BI_RGB &&
  311.         pBMI->bmiHeader.biCompression != BI_BITFIELDS)
  312.         return E_INVALIDARG;
  313.     pRGBQ = (RGBQUAD *)&pBMI->bmiColors[0];
  314.     ncolors = pBMI->bmiHeader.biClrUsed;
  315.     if (ncolors == 0 && pBMI->bmiHeader.biBitCount <= 8)
  316.         ncolors = 1 << pBMI->bmiHeader.biBitCount;
  317.     //
  318.     // Decode 16/32bpp with masks.
  319.     //
  320.     if (pBMI->bmiHeader.biBitCount == 16 ||
  321.         pBMI->bmiHeader.biBitCount == 32)
  322.     {
  323.         if (pBMI->bmiHeader.biCompression == BI_BITFIELDS)
  324.         {
  325.             rmask = ((ULONG *)pRGBQ)[0];
  326.             gmask = ((ULONG *)pRGBQ)[1];
  327.             bmask = ((ULONG *)pRGBQ)[2];
  328.             ncolors = 3;
  329.         }
  330.         else if (pBMI->bmiHeader.biBitCount == 16)
  331.         {
  332.             rmask = 0x7c00;
  333.             gmask = 0x03e0;
  334.             bmask = 0x001f;
  335.         }
  336.         else /* 32 */
  337.         {
  338.             rmask = 0xff0000;
  339.             gmask = 0x00ff00;
  340.             bmask = 0x0000ff;
  341.         }
  342.         for (rshift = 0; (rmask & 1) == 0; rmask >>= 1, ++rshift);
  343.         if (rmask == 0)
  344.             rmask = 1;
  345.         for (gshift = 0; (gmask & 1) == 0; gmask >>= 1, ++gshift);
  346.         if (gmask == 0)
  347.             gmask = 1;
  348.         for (bshift = 0; (bmask & 1) == 0; bmask >>= 1, ++bshift);
  349.         if (bmask == 0)
  350.             bmask = 1;
  351.     }
  352.     bpl = ((pBMI->bmiHeader.biBitCount * uiSrcWidth + 31) >> 3) & ~3;
  353.     pucBits0 = (UCHAR *) pBits;
  354.     pucBits = pucBits0;
  355.     if (pBMI->bmiHeader.biBitCount == 24)
  356.         pucBits240 = pucBits;
  357.     else
  358.     {
  359.         int bpl24 = (uiSrcWidth * 3 + 3) & ~3;
  360.         pucBits240 = new UCHAR[bpl24];
  361.         if (pucBits240 == NULL)
  362.             return E_OUTOFMEMORY;
  363.     }
  364.     pucBits24 = pucBits240;
  365.     hr = S_OK;
  366.     for (y = 0; y < (int)uiSrcHeight; ++y)
  367.     {
  368.         pB = pucBits;
  369.         pB24 = pucBits24;
  370.         switch (pBMI->bmiHeader.biBitCount)
  371.         {
  372.         case 1:
  373.             for (x = uiSrcWidth; x >= 8; x -= 8)
  374.             {
  375.                 pQ = &pRGBQ[(*pB >> 7) & 1];
  376.                 *pB24++ = pQ->rgbBlue;
  377.                 *pB24++ = pQ->rgbGreen;
  378.                 *pB24++ = pQ->rgbRed;
  379.                 pQ = &pRGBQ[(*pB >> 6) & 1];
  380.                 *pB24++ = pQ->rgbBlue;
  381.                 *pB24++ = pQ->rgbGreen;
  382.                 *pB24++ = pQ->rgbRed;
  383.                 pQ = &pRGBQ[(*pB >> 5) & 1];
  384.                 *pB24++ = pQ->rgbBlue;
  385.                 *pB24++ = pQ->rgbGreen;
  386.                 *pB24++ = pQ->rgbRed;
  387.                 pQ = &pRGBQ[(*pB >> 4) & 1];
  388.                 *pB24++ = pQ->rgbBlue;
  389.                 *pB24++ = pQ->rgbGreen;
  390.                 *pB24++ = pQ->rgbRed;
  391.                 pQ = &pRGBQ[(*pB >> 3) & 1];
  392.                 *pB24++ = pQ->rgbBlue;
  393.                 *pB24++ = pQ->rgbGreen;
  394.                 *pB24++ = pQ->rgbRed;
  395.                 pQ = &pRGBQ[(*pB >> 2) & 1];
  396.                 *pB24++ = pQ->rgbBlue;
  397.                 *pB24++ = pQ->rgbGreen;
  398.                 *pB24++ = pQ->rgbRed;
  399.                 pQ = &pRGBQ[(*pB >> 1) & 1];
  400.                 *pB24++ = pQ->rgbBlue;
  401.                 *pB24++ = pQ->rgbGreen;
  402.                 *pB24++ = pQ->rgbRed;
  403.                 pQ = &pRGBQ[(*pB++) & 1];
  404.                 *pB24++ = pQ->rgbBlue;
  405.                 *pB24++ = pQ->rgbGreen;
  406.                 *pB24++ = pQ->rgbRed;
  407.             }
  408.             if (x > 0)
  409.             {
  410.                 int shf = 8;
  411.                 do
  412.                 {
  413.                     pQ = &pRGBQ[(*pB >> --shf) & 1];
  414.                     *pB24++ = pQ->rgbBlue;
  415.                     *pB24++ = pQ->rgbGreen;
  416.                     *pB24++ = pQ->rgbRed;
  417.                 }
  418.                 while (--x);
  419.             }
  420.             break;
  421.         case 4:
  422.             for (x = uiSrcWidth; x >= 2; x -= 2)
  423.             {
  424.                 pQ = &pRGBQ[(*pB >> 4) & 0xf];
  425.                 *pB24++ = pQ->rgbBlue;
  426.                 *pB24++ = pQ->rgbGreen;
  427.                 *pB24++ = pQ->rgbRed;
  428.                 pQ = &pRGBQ[*pB++ & 0xf];
  429.                 *pB24++ = pQ->rgbBlue;
  430.                 *pB24++ = pQ->rgbGreen;
  431.                 *pB24++ = pQ->rgbRed;
  432.             }
  433.             if (x > 0)
  434.             {
  435.                 pQ = &pRGBQ[(*pB >> 4) & 0xf];
  436.                 *pB24++ = pQ->rgbBlue;
  437.                 *pB24++ = pQ->rgbGreen;
  438.                 *pB24++ = pQ->rgbRed;
  439.                 if (x > 1)
  440.                 {
  441.                     pQ = &pRGBQ[*pB & 0xf];
  442.                     *pB24++ = pQ->rgbBlue;
  443.                     *pB24++ = pQ->rgbGreen;
  444.                     *pB24++ = pQ->rgbRed;
  445.                 }
  446.             }
  447.             break;
  448.         case 8:
  449.             for (x = uiSrcWidth; x--; )
  450.             {
  451.                 pQ = &pRGBQ[*pB++];
  452.                 *pB24++ = pQ->rgbBlue;
  453.                 *pB24++ = pQ->rgbGreen;
  454.                 *pB24++ = pQ->rgbRed;
  455.             }
  456.             break;
  457.         case 16:
  458.         {
  459.             USHORT *pW;
  460.             pW = (USHORT *)pucBits;
  461.             for (x = uiSrcWidth; x--; )
  462.             {
  463.                 ULONG w = *pW++;
  464.                 *pB24++ = (UCHAR)
  465.                      ((((w >> bshift) & bmask) * 255) / bmask);
  466.                 *pB24++ = (UCHAR)
  467.                      ((((w >> gshift) & gmask) * 255) / gmask);
  468.                 *pB24++ = (UCHAR)
  469.                      ((((w >> rshift) & rmask) * 255) / rmask);
  470.             }
  471.             break;
  472.         }
  473.         case 24:
  474.             pucBits24 = pucBits;
  475.             break;
  476.         case 32:
  477.         {
  478.             ULONG *pD;
  479.             pD = (ULONG *)pucBits;
  480.             for (x = uiSrcWidth; x--; )
  481.             {
  482.                 ULONG d = *pD++;
  483.                 *pB24++ = (UCHAR)
  484.                      ((((d >> bshift) & bmask) * 255) / bmask);
  485.                 *pB24++ = (UCHAR)
  486.                      ((((d >> gshift) & gmask) * 255) / gmask);
  487.                 *pB24++ = (UCHAR)
  488.                      ((((d >> rshift) & rmask) * 255) / rmask);
  489.             }
  490.             break;
  491.         }
  492.         default:
  493.             delete[] pucBits24;
  494.             return E_INVALIDARG;
  495.         }
  496.         hr = AddScanline(pucBits24, (uiSrcHeight-1) - y);
  497.         if (FAILED(hr))
  498.             break;
  499.         pucBits += bpl;
  500.     }
  501.     if (pucBits240 != pucBits0)
  502.         delete[] pucBits240;
  503.     return hr;
  504. }