Click here to Skip to main content
Click here to Skip to main content

Two Pass Scaling using Filters

By , 11 Dec 1999
 
  • Download source files - 4 Kb

    Sample Image - 2_pass_scaling.jpg

    Unlike traditional scaling of images, where every n'th pixel is sampled and copied to the result image, this template provides much more accurate image scaling features.

    It takes a buffer of RGB values (as COLORREFs) and creates another buffer with new dimensions. The input / output buffers are sequential pixels (not compressed) compatible with the format used in 24-bit DIBs.

    The template is instantiated with a specific filter. The filter determines the quality of the output image. Different basic filters are supplied with this template and additional filters can be easily added.

    Major features:

    • Provides professional quality image scaling.
    • Code is optimized for image quality, not speed.
    • Supports various image filters:
      • Box filter.
      • Bilinear filter.
      • Gaussian filter.
      • Hamming filter.
      • Blackman filter.
      • ...New filters can be easily added.
    • Supports both magnification and minification.
    • Does not force aspect ratio limitations. e.g. an image can be magnified horizontally and minified vertically.
    • Supports 24-bit images. With little change can support other image formats / depths.
    • Template based - no need for libraries, DLLs etc. No linkage problems.

    How to use the scaling template:

    Assuming you have a non-compressed true-color 24-bit DIB in memory (the bits array is pointed by m_pBits), where the original bitmap width is m_dwWidth and height is m_dwHeight.

    Your code should look something like this:

    #include <2PassScale.h>
    ...
    
    void CMyDIB::ScaleTo (DWORD dwNewWidth, DWORD dwNewHeight)
    {
    	C2PassScale <CBilinearFilter> ScaleEngine;
    	COLORREF *pOldBitmap = m_pBits;
    	m_pBits = ScaleEngine.AllocAndScale(m_pBits,
    	                                    m_dwWidth,
    	                                    m_dwHeight,
    	                                    dwNewWidth,
    	                                    dwNewHeight
    	                                    );
    	if (NULL == m_pBits)
    	{
    		//
    		// Handle errors here
    		//
    	}
    	m_dwWidth = dwNewWidth;
    	m_dwHeight = dwNewHeight;
    	delete pOldBitmap;
    }
    
    // Alternatively, if you already have a pre-allocated destination buffer
    // in the new size you can call ScaleEngine.Scale (...) and give it that buffer
    
    
  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    About the Author

    Eran Yariv
    United States United States
    Member
    No Biography provided

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    GeneralHere is HUGE speed improvementmemberJake Montgomery17 Jan '05 - 11:48 
    Below is the code for a modified version of C2PassScale that uses integer arithmetic to achieve a 3x-4x speed improvement.
    It also handles images with more than 3 colors (change PS_MAX_DEPTH if you plan on using more than 4 colors).
    It does _not_ currently handles images with other than 8 bits per channel.
    There were also some bug fixes that I have included.
     
    It also now takes the size of a full scan line in bytes.   By using this intelligently, it is possible to scale a sub-rectangle of an image into a full image, or into another sub rectangle.
     
    Unfortunately, I had already made some windows specific modifications for my own use, and I am too busy to take them out.   So if you are not running on a windows platform, you will need to take out the ASSERT lines, and change some of the data types.
     
    [3-30-05] Added comments to Scale() and AllocAndScale() to clarify the parameters.
     
    Hope this is useful,
          Jake Montgomery
     

    =============== CODE BELOW ==================
     
    #pragma once
     
    #include <math.h>
     
    #define BOUND(x,a,b) \
          (((x) <= (a)) ? (a) : (((x) > (b)) ? (b) : (x)))
     
    #define PS_MAX_DEPTH 4
                        
    // Based on Eran Yariv's TwoPassScale, modified for speed, bug fixes, and variable depths.
     
    // Does 2 pass scaling of bitmaps
    // Template based, can use various methods for interpolation.
    // Could certainly be improved.
     
    //      to use:
    //      C2PassScale <CBilinearFilter> ScaleEngine;
    //      ScaleEngine.Scale ((UCHAR *)dibSrc.GetBits(),             // A pointer to the source bitmap bits
    //                                    depth,                                 // The size of a single pixel in bytes (both source and scaled image)
    //                                    dibSrc.Width(),                       // The width of a line of the source image to scale in pixels
    //                                    dibSrc.WidthBytes(),                  // The width of a single line of the source image in bytes (to allow for padding, etc.)
    //                                    dibSrc.Height(),                       // The height of the source image to scale in pixels.
    //                                    (UCHAR *)GetBits(),                  // A pointer to a buffer to hold the ecaled image
    //                                    Width(),                                 // The desired width of a line of the scaled image in pixels
    //                                    WidthBytes(),                            // The width of a single line of the scaled image in bytes (to allow for padding, etc.)
    //                                    Height());                            // The desired height of the scaled image in pixels.
    //      or AllocAndScale()
     
    // Modified 1-17-05 to use more integer math -- much faater. [JRM]
     

    class CGenericFilter
    {
    public:
         
          CGenericFilter (double dWidth) : m_dWidth (dWidth) {}
          virtual ~CGenericFilter() {}
     
          double GetWidth()                           { return m_dWidth; }
          void   SetWidth (double dWidth)      { m_dWidth = dWidth; }
     
          virtual double Filter (double dVal) = 0;
     
    protected:
     
          #define FILTER_PI   double (3.1415926535897932384626433832795)
          #define FILTER_2PI double (2.0 * 3.1415926535897932384626433832795)
          #define FILTER_4PI double (4.0 * 3.1415926535897932384626433832795)
     
          double   m_dWidth;
    };
     
    class CBoxFilter : public CGenericFilter
    {
    public:
     
          CBoxFilter (double dWidth = double(0.5)) : CGenericFilter(dWidth) {}
          virtual ~CBoxFilter() {}
     
          double Filter (double dVal) { return (fabs(dVal) <= m_dWidth ? 1.0 : 0.0); }
    };
     
    class CBilinearFilter : public CGenericFilter
    {
    public:
     
          CBilinearFilter (double dWidth = double(1.0)) : CGenericFilter(dWidth) {}
          virtual ~CBilinearFilter() {}
     
          double Filter (double dVal)
                {
                      dVal = fabs(dVal);
                      return (dVal < m_dWidth ? m_dWidth - dVal : 0.0);
                }
    };
     
    class CGaussianFilter : public CGenericFilter
    {
    public:
     
          CGaussianFilter (double dWidth = double(3.0)) : CGenericFilter(dWidth) {}
          virtual ~CGaussianFilter() {}
     
          double Filter (double dVal)
                {
                      if (fabs (dVal) > m_dWidth)
                      {
                            return 0.0;
                      }
                      return exp (-dVal * dVal / 2.0) / sqrt (FILTER_2PI);
                }
    };
     
    class CHammingFilter : public CGenericFilter
    {
    public:
     
          CHammingFilter (double dWidth = double(0.5)) : CGenericFilter(dWidth) {}
          virtual ~CHammingFilter() {}
     
          double Filter (double dVal)
                {
                      if (fabs (dVal) > m_dWidth)
                      {
                            return 0.0;
                      }
                      double dWindow = 0.54 + 0.46 * cos (FILTER_2PI * dVal);
                      double dSinc = (dVal == 0) ? 1.0 : sin (FILTER_PI * dVal) / (FILTER_PI * dVal);
                      return dWindow * dSinc;
                }
    };
     
    class CBlackmanFilter : public CGenericFilter
    {
    public:
     
          CBlackmanFilter (double dWidth = double(0.5)) : CGenericFilter(dWidth) {}
          virtual ~CBlackmanFilter() {}
     
          double Filter (double dVal)
                {
                      if (fabs (dVal) > m_dWidth)
                      {
                            return 0.0;
                      }
                      double dN = 2.0 * m_dWidth + 1.0;
                      return 0.42 + 0.5 * cos (FILTER_2PI * dVal / ( dN - 1.0 )) +
                               0.08 * cos (FILTER_4PI * dVal / ( dN - 1.0 ));
                }
    };
     

    typedef struct
    {
       unsigned int*Weights;   // Normalized weights of neighboring pixels
       int Left,Right;   // Bounds of source pixels window
    } ContributionType;   // Contirbution information for a single pixel
     
    typedef struct
    {
       ContributionType *ContribRow; // Row (or column) of contribution weights
       UINT WindowSize,                     // Filter window size (of affecting source pixels)
                LineLength;                     // Length of line (no. or rows / cols)
    } LineContribType;                     // Contribution information for an entire line (row or column)
     

     
    typedef BOOL (*ProgressAnbAbortCallBack)(BYTE bPercentComplete);
     
    template <class FilterClass>
    class C2PassScale
    {
    public:
     
          C2PassScale (ProgressAnbAbortCallBack callback = NULL) :
                m_Callback (callback) {m_byteDepth = 3;}
     
          virtual ~C2PassScale() {}
     
          UCHAR * AllocAndScale (  
                UCHAR   *pOrigImage,
                UINT            pixelBytes,
                UINT            uOrigWidth,
                UINT            uOrigWidthBytes,
                UINT            uOrigHeight,
                UINT            uNewWidth,
                UINT            uNewWidthBytes,
                UINT            uNewHeight);
     
          UCHAR * Scale (  
                UCHAR   *pOrigImage,
                UINT            pixelBytes,
                UINT            uOrigWidth,
                UINT            uOrigWidthBytes,
                UINT            uOrigHeight,
                UCHAR   *pDstImage,
                UINT            uNewWidth,
                UINT            uNewWidthBytes,
                UINT            uNewHeight);
     
                int                                          m_byteDepth;
     
    private:
     
          ProgressAnbAbortCallBack      m_Callback;
          BOOL                                    m_bCanceled;
     
          LineContribType *AllocContributions (   UINT uLineLength,
                                                                      UINT uWindowSize);
     
          void FreeContributions (LineContribType * p);
     
          LineContribType *CalcContributions (      UINT      uLineSize,
                                                                      UINT      uSrcSize,
                                                                      double   dScale);
     
          void ScaleRow ( UCHAR               *pSrc,
                                  UINT                        uSrcWidth,
                                  UINT                        uSrcWidthBytes,
                                  UCHAR               *pRes,
                                  UINT                        uResWidth,
                                  UINT                        uDstWidthBytes,
                                  UINT                        uRow,
                                  LineContribType      *Contrib);
     
          void HorizScale (   UCHAR               *pSrc,
                                        UINT                        uSrcWidth,
                                        UINT                        uSrcWidthBytes,
                                        UINT                        uSrcHeight,
                                        UCHAR               *pDst,
                                        UINT                        uResWidth,
                                        UINT                        uResWidthBytes);
     
          void ScaleCol ( UCHAR               *pSrc,
                                  UINT                        uSrcWidth,
                                  UINT                        uSrcWidthBytes,
                                  UCHAR               *pRes,
                                  UINT                        uResWidth,
                                  UINT                        uResWidthBytes,
                                  UINT                        uResHeight,
                                  UINT                        uCol,
                                  LineContribType      *Contrib);
     
          void VertScale (      UCHAR               *pSrc,
                                        UINT                        uSrcWidth,
                                        UINT                        uSrcWidthBytes,
                                        UINT                        uSrcHeight,
                                        UCHAR               *pDst,
                                        UINT                        uResHeight);
    };
     
    template <class FilterClass>
    LineContribType *
    C2PassScale<FilterClass>::
    AllocContributions (UINT uLineLength, UINT uWindowSize)
    {
          LineContribType *res = new LineContribType;
                // Init structure header
          res->WindowSize = uWindowSize;
          res->LineLength = uLineLength;
                // Allocate list of contributions
          res->ContribRow = new ContributionType[uLineLength];
          for (UINT u = 0 ; u < uLineLength ; u++)
          {
                // Allocate contributions for every pixel
                res->ContribRow[u].Weights = new unsigned int[uWindowSize];
          }
          return res;
    }
     
    template <class FilterClass>
    void
    C2PassScale<FilterClass>::
    FreeContributions (LineContribType * p)
    {
          for (UINT u = 0; u < p->LineLength; u++)
          {
                // Free contribs for every pixel
                delete [] p->ContribRow[u].Weights;
          }
          delete [] p->ContribRow;      // Free list of pixels contribs
          delete p;                           // Free contribs header
    }
     
    template <class FilterClass>
    LineContribType *
    C2PassScale<FilterClass>::
    CalcContributions (UINT uLineSize, UINT uSrcSize, double dScale)
    {
          FilterClass CurFilter;
     
          double dWidth;
          double dFScale = 1.0;
          double dFilterWidth = CurFilter.GetWidth();
     
          if (dScale < 1.0)
          {      // Minification
                dWidth = dFilterWidth / dScale;
                dFScale = dScale;
          }
          else
          {      // Magnification
                dWidth= dFilterWidth;
          }
     
          // Window size is the number of sampled pixels
    //      int iWindowSize = 2 * (int)ceil(dWidth) + 1;
          int iWindowSize = 2 * ((int)ceil(dWidth) + 1);      // changed ... causing crash with bi-linear filiter?? [JRM]
     
          // Allocate a new line contributions strucutre
          LineContribType *res = AllocContributions (uLineSize, iWindowSize);
     
          double *dWeights = new double[iWindowSize];
     
          for (UINT u = 0; u < uLineSize; u++)
          {   // Scan through line of contributions
                double dCenter = (double)u / dScale;   // Reverse mapping
                // Find the significant edge points that affect the pixel
                int iLeft = max (0, (int)floor (dCenter - dWidth));
                int iRight = min ((int)ceil (dCenter + dWidth), int(uSrcSize) - 1);
     
                // Cut edge points to fit in filter window in case of spill-off
                if (iRight - iLeft + 1 > iWindowSize)
                {
                      if (iLeft < (int(uSrcSize) - 1 / 2))
                      {
                            iLeft++;
                      }
                      else
                      {
                            iRight--;
                      }
                }
                int nFallback = iLeft;     
     
                BOOL bNonZeroFound = false;
                double dTotalWeight = 0.0;   // Zero sum of weights
                double dVal;
                for (int iSrc = iLeft; iSrc <= iRight; iSrc++)
                {   // Calculate weights
                      dVal = CurFilter.Filter (dFScale * (dCenter - (double)iSrc));
                      if (dVal > 0.0)
                            dVal *= dFScale;
                      else
                      {
                            dVal = 0.0;
                            // zero conribution, trim
                            if (!bNonZeroFound)
                            {
                                  // we are on the left side, trim left
                                  iLeft = iSrc+1;
                                  continue;
                            }
                            else
                            {
                                  // we are on the right side, trim right
                                  iRight = iSrc-1;
                                  break;
                            }
                      }
                      bNonZeroFound = true;
                      dTotalWeight += dVal;
                      dWeights[iSrc-iLeft] = dVal;
                }
     
                if (iLeft > iRight)
                {
                      ASSERT(FALSE);
                      iLeft = iRight = nFallback;
                      dWeights[0] = 0.0;
                }
                res->ContribRow[u].Left = iLeft;
                res->ContribRow[u].Right = iRight;
     
                ASSERT (dTotalWeight >= 0.0);   // An error in the filter function can cause this
                if (dTotalWeight > 0.0)
                {   // Normalize weight of neighbouring points
                      for (iSrc = iLeft; iSrc <= iRight; iSrc++)
                      {   // Normalize point
                            dWeights[iSrc-iLeft] /= dTotalWeight;
                      }
                }
                // scale weights to integers weights for effeciency
                for (iSrc = iLeft; iSrc <= iRight; iSrc++)
                      res->ContribRow[u].Weights[iSrc-iLeft] = (unsigned int)(dWeights[iSrc-iLeft] * 0xffff);
       }
       delete [] dWeights;
       return res;
    }
     

    template <class FilterClass>
    void
    C2PassScale<FilterClass>::
    ScaleRow (   UCHAR               *pSrc,
                      UINT                        uSrcWidth,
                      UINT                        uSrcWidthBytes,
                      UCHAR               *pRes,
                      UINT                        uResWidth,
                      UINT                        uResWidthBytes,
                      UINT                        uRow,
                      LineContribType      *Contrib)
    {
          UCHAR * const pSrcRow = &(pSrc[uRow * uSrcWidthBytes]);
          UCHAR * const pDstRow = &(pRes[uRow * uResWidthBytes]);
          UCHAR *pSrcLoc;
          UCHAR *pDstLoc;
          unsigned int vals[PS_MAX_DEPTH];
     
          for (UINT x = 0; x < uResWidth; x++)
          {   // Loop through row
                int v, i;
                for (v= 0; v < m_byteDepth; v++)
                      vals[v] = 0;
                int iLeft = Contrib->ContribRow[x].Left;      // Retrieve left boundries
                int iRight = Contrib->ContribRow[x].Right;   // Retrieve right boundries
                pSrcLoc = &pSrcRow[iLeft*m_byteDepth];
                for (i = iLeft; i <= iRight; i++)
                {   // Scan between boundries
                      #ifdef _DEBUG
                            ASSERT(i-iLeft < (int)Contrib->WindowSize);
                      #endif
                      // Accumulate weighted effect of each neighboring pixel
                      for (v= 0; v < m_byteDepth; v++)
                            vals[v] += Contrib->ContribRow[x].Weights[i-iLeft] * *pSrcLoc++;
                }
                pDstLoc = &pDstRow[x*m_byteDepth];
                for (v= 0; v < m_byteDepth; v++)
                {
                      // copy to destination, and scale back down by BYTE
                      *pDstLoc++ = BOUND(vals[v] >> 16, 0, 0xff); // Place result in destination pixel
                }
          }
    }
     
    template <class FilterClass>
    void
    C2PassScale<FilterClass>::
    HorizScale (      UCHAR               *pSrc,
                            UINT                        uSrcWidth,
                            UINT                        uSrcWidthBytes,
                            UINT                        uSrcHeight,
                            UCHAR               *pDst,
                            UINT                        uResWidth,
                            UINT                        uResWidthBytes)
    {
          // Assumes heights are the same
    //      TRACE ("Performing horizontal scaling...\n");
          if (uResWidth == uSrcWidth)
          {   // No scaling required, just copy
                if(uSrcHeight <= 0) return;
                if (uResWidthBytes == uSrcWidthBytes)
                {
                      int copy = ((uSrcHeight -1) * uSrcWidthBytes) + uSrcWidth*m_byteDepth; // avoids overrun if starting in middle of image.
                         memcpy (pDst, pSrc, copy);
                      return;
                }
                else
                {
                      for (UINT y = 0; y < uSrcHeight; y++)
                            memcpy(pDst+uResWidthBytes*y, pSrc+uSrcWidthBytes*y, uSrcWidth*m_byteDepth);
                      return;
                }
          }
          // Allocate and calculate the contributions
          LineContribType * Contrib = CalcContributions (uResWidth, uSrcWidth, double(uResWidth) / double(uSrcWidth));
          for (UINT u = 0; u < uSrcHeight; u++)
          {   // Step through rows
                if (NULL != m_Callback)
                {
                      //
                      // Progress and report callback supplied
                      //
                      if (!m_Callback (BYTE(double(u) / double (uSrcHeight) * 50.0)))
                      {
                            //
                            // User wished to abort now
                            //
                            m_bCanceled = TRUE;
                            FreeContributions (Contrib);   // Free contributions structure
                            return;
                      }
                }
                           
                ScaleRow (   pSrc,
                                  uSrcWidth,
                                  uSrcWidthBytes,
                                  pDst,
                                  uResWidth,
                                  uResWidthBytes,
                                  u,
                                  Contrib);      // Scale each row
          }
          FreeContributions (Contrib);   // Free contributions structure
    }
     
    template <class FilterClass>
    void
    C2PassScale<FilterClass>::
    ScaleCol (   UCHAR               *pSrc,
                      UINT                        uSrcWidth,
                      UINT                        uSrcWidthBytes,
                      UCHAR               *pRes,
                      UINT                        uResWidth,
                      UINT                        uResWidthBytes,
                      UINT                        uResHeight,
                      UINT                        uCol,
                      LineContribType      *Contrib)
    {
          UCHAR *pSrcLoc;
          UCHAR *pDstLoc;
          unsigned int vals[PS_MAX_DEPTH];
     
          // assumes same height
          for (UINT y = 0; y < uResHeight; y++)
          {      // Loop through column
                int v, i;
                for (v= 0; v < m_byteDepth; v++)
                      vals[v] = 0;
     
                int iLeft = Contrib->ContribRow[y].Left;      // Retrieve left boundries
                int iRight = Contrib->ContribRow[y].Right;   // Retrieve right boundries
                pSrcLoc = pSrc + uSrcWidthBytes*iLeft + uCol* m_byteDepth;
                for (i = iLeft; i <= iRight; i++)
                {   // Scan between boundries
                      // Accumulate weighted effect of each neighboring pixel
                      UCHAR *pCurSrc = pSrc + uSrcWidthBytes*i + uCol* m_byteDepth;
                      #ifdef _DEBUG
                            ASSERT(i-iLeft < (int)Contrib->WindowSize);
                      #endif
                      for (v= 0; v < m_byteDepth; v++)
                            vals[v] += Contrib->ContribRow[y].Weights[i-iLeft] * pSrcLoc[v];
                      pSrcLoc += uSrcWidthBytes;
                }
                pDstLoc = pRes + (y * uResWidthBytes) + uCol*m_byteDepth;
                for (v= 0; v < m_byteDepth; v++)
                {
                      // scale back
                      *pDstLoc++ = BOUND( vals[v] >> 16, 0, 0xff);   // Place result in destination pixel
                }
          }
    }
     

    template <class FilterClass>
    void
    C2PassScale<FilterClass>::
    VertScale ( UCHAR               *pSrc,
                      UINT                        uSrcWidth,
                      UINT                        uSrcWidthBytes,
                      UINT                        uSrcHeight,
                      UCHAR               *pDst,
                      UINT                        uResHeight)
    {
    //      TRACE ("Performing vertical scaling...");
     
          // assumes widths are the same!
          if (uSrcHeight == uResHeight)
          {   // No scaling required, just copy
                if (uSrcHeight <= 0) return;
                int copy = ((uSrcHeight -1) * uSrcWidthBytes) + uSrcWidth*m_byteDepth; // avoids overrun if starting in middle of image.
                memcpy (pDst, pSrc, copy);
                return;
          }
          // Allocate and calculate the contributions
          LineContribType * Contrib = CalcContributions (uResHeight, uSrcHeight, double(uResHeight) / double(uSrcHeight));
          for (UINT u = 0; u < uSrcWidth; u++)
          {   // Step through columns
                if (NULL != m_Callback)
                {
                      //
                      // Progress and report callback supplied
                      //
                      if (!m_Callback (BYTE(double(u) / double (uSrcWidth) * 50.0) + 50))
                      {
                            //
                            // User wished to abort now
                            //
                            m_bCanceled = TRUE;
                            FreeContributions (Contrib);   // Free contributions structure
                            return;
                      }
                }
                ScaleCol (   pSrc,
                                  uSrcWidth,
                                  uSrcWidthBytes,
                                  pDst,
                                  uSrcWidth,
                                  uSrcWidthBytes,
                                  uResHeight,
                                  u,
                                  Contrib);   // Scale each column
          }
          FreeContributions (Contrib);      // Free contributions structure
    }
     
    template <class FilterClass>
    UCHAR *
    C2PassScale<FilterClass>::
    AllocAndScale (
          UCHAR   *pOrigImage,               // A pointer to the source bitmap bits
          UINT            pixelBytes,          // The size of a single pixel in bytes (both source and scaled image)
          UINT            uOrigWidth,               // The width of a line of the source image to scale in pixels
          UINT            uOrigWidthBytes,     // The width of a single line of the source image in bytes (to allow for padding, etc.)
          UINT            uOrigHeight,          // The height of the source image to scale in pixels.
          UINT            uNewWidth,               // The desired width of a line of the scaled image in pixels
          UINT            uNewWidthBytes,          // The width of a single line of the scaled image in bytes (to allow for padding, etc.)
          UINT            uNewHeight)               // The desired height of the scaled image in pixels.
    {
          // Scale source image horizontally into temporary image
          m_byteDepth = pixelBytes;
          m_bCanceled = FALSE;
          UCHAR *pTemp = new UCHAR [uNewWidthBytes * uOrigHeight];
          HorizScale (pOrigImage,
                            uOrigWidth,
                            uOrigWidthBytes,
                            uOrigHeight,
                            pTemp,
                            uNewWidth,
                            uNewWidthBytes);
          if (m_bCanceled)
          {
                delete [] pTemp;
                return NULL;
          }
          // Scale temporary image vertically into result image     
          UCHAR *pRes = new UCHAR [uNewWidth * uNewHeight *m_byteDepth];
          VertScale ( pTemp,
                            uNewWidth,
                            uNewWidthBytes,
                            uOrigHeight,
                            pRes,
                            uNewHeight);
          if (m_bCanceled)
          {
                delete [] pTemp;
                delete [] pRes;
                return NULL;
          }
          delete [] pTemp;
          return pRes;
    }
     
    template <class FilterClass>
    UCHAR *
    C2PassScale<FilterClass>::
    Scale (
          UCHAR   *pOrigImage,               // A pointer to the source bitmap bits
          UINT            pixelBytes,          // The size of a single pixel in bytes (both source and scaled image)
          UINT            uOrigWidth,               // The width of a line of the source image to scale in pixels
          UINT            uOrigWidthBytes,     // The width of a single line of the source image in bytes (to allow for padding, etc.)
          UINT            uOrigHeight,          // The height of the source image to scale in pixels.
          UCHAR   *pDstImage,                    // A pointer to a buffer to hold the ecaled image
          UINT            uNewWidth,               // The desired width of a line of the scaled image in pixels
          UINT            uNewWidthBytes,          // The width of a single line of the scaled image in bytes (to allow for padding, etc.)
          UINT            uNewHeight)               // The desired height of the scaled image in pixels.
    {
          // Scale source image horizontally into temporary image
          ASSERT(PS_MAX_DEPTH >= pixelBytes);
          m_byteDepth = pixelBytes;
          m_bCanceled = FALSE;
          UCHAR *pTemp = new UCHAR [ uOrigHeight *uNewWidthBytes];
          HorizScale (pOrigImage,
                            uOrigWidth,
                            uOrigWidthBytes,
                            uOrigHeight,
                            pTemp,
                            uNewWidth,
                            uNewWidthBytes);
          if (m_bCanceled)
          {
                delete [] pTemp;
                return NULL;
          }
     
          // Scale temporary image vertically into result image     
          VertScale ( pTemp,
                            uNewWidth,
                            uNewWidthBytes,
                            uOrigHeight,
                            pDstImage,
                            uNewHeight);
          delete [] pTemp;
          if (m_bCanceled)
          {
                return NULL;
          }
          return pDstImage;
    }

    GeneralRe: Here is HUGE speed improvementmemberArlen Albert16 Mar '05 - 16:24 
    Where is the "macros.h" header file?
    It is impossible to compile your file under MSVC.NET 2003 because BOUND isn't defined and so on.

    GeneralRe: Here is HUGE speed improvementmemberJake Montgomery17 Mar '05 - 8:04 
    I have fixed the original post.
    The only item you need from macros.h is
     
    #define BOUND(x,a,b) \
    (((x) <= (a)) ? (a) : (((x) > (b)) ? (b) : (x)))
    GeneralRe: Here is HUGE speed improvementmemberArlen Albert18 Mar '05 - 4:14 
    Thanks Smile | :)
    GeneralRe: Here is HUGE speed improvementmemberGautam Jain13 May '06 - 7:34 
    In the below code you are using dibSrc object. Which class is this? I don't see it in this project. Can you give the URL from where I can download the dibSrc class?
     
    Because I don't know to calculate WidthBytes that is passed to AllocAndScale function
     
    Thanks.
     


    // C2PassScale ScaleEngine;
    // ScaleEngine.Scale ((UCHAR *)dibSrc.GetBits(),
    // depth,
    // dibSrc.Width(),
    // dibSrc.WidthBytes(),
    // dibSrc.Height(),
    // (UCHAR *)GetBits(),
    // Width(),
    // WidthBytes(),
    // Height());

     
    -- modified at 13:35 Saturday 13th May, 2006
    GeneralRe: Here is HUGE speed improvementmemberJake Montgomery10 Jul '06 - 9:20 
    I believe that dibSrc is only used in the example code in the comments, therefore it should be understood to be incomplete. dibSrc in this case is not a class, but an instance of an image class that is not defined in this project. There is a comment on the WidthBytes that you removed: "The width of a single line of the source image in bytes (to allow for padding, etc.)". If this is not enough explanation, then I will try again. "WidthBytes" (uOrigWidthBytes and uNewWidthBytes in the code) is the number of bytes between lines of the image, so if line 0 starts at address 0x1000, and line 1 starts at 0x1321, then "WidthBytes" would be 0x0321. If your image is tightly packed, with no memory gap between lines, the WidthBytes is simply the "width in pixels" * "size of a single pixel in bytes". Hope this helps.

    GeneralRe: Here is HUGE speed improvementmembera.mulay5 Oct '06 - 2:38 
    I am having a problem while scaling an image 800 x 600 to a size of 75 x 75.
    It works fine for 76 x 76. It throws access violation error in following method.
     
    template
    void
    C2PassScale::
    ScaleCol

     
    Can you elaborate why this is happening?
    GeneralRe: Here is HUGE speed improvementmemberDKScherpy6 Nov '06 - 7:19 
    In my experience working with images and whatnot, image dimensions that are a multiple of 4 seem to be much more agreeable. Try making sure that your dimensions are multiples of 4.
    GeneralRe: Here is HUGE speed improvementmembera.mulay7 Nov '06 - 0:44 
    Yes, I tried out what u suggested. The width of the image must be multiple of 4 in order for the algorithm to work. Rose | [Rose]
    GeneralBugs for 24 bit.memberguju4 May '11 - 3:43 
    I do strongly advise not to use this code for 24bit bitmaps – there are bugs all over.
    The destination bitmap is VERY much smoothed, it’s is shifted 1 pixel upwards and 1 pixel to the right, it produces wrong colours (for example a grey bitmap (128) is turned to 126; very bright values are turned to about 2 values too low).
    I didn’t test on other than 24bit bitmaps, but wouldn’t be surprised if it’s the same there. As the code contains some strange lines (for example int ... – 1 / 2, or „caused crash ...“).
     
    To me this is typical example how openly disposed code should not be: Only very bad tested, not maintained, ...
    So, if you want my opinion: Don’t use this junk.
    If you need 24bit resampling, StretchDIBits (in Mode HALFTONE) does a good job. For example: www.christian-etter.de/?p=283

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web02 | 2.6.130523.1 | Last Updated 12 Dec 1999
    Article Copyright 1999 by Eran Yariv
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid