Click here to Skip to main content
15,886,873 members
Articles / Desktop Programming / MFC
Article

Two Pass Scaling using Filters

Rate me:
Please Sign up or sign in to vote.
4.94/5 (23 votes)
11 Dec 1999 572.7K   2.8K   64   28
A smart way of scaling bitmaps
  • 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


    Written By
    United States United States
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    Question16-bit version? Pin
    kennygoers8-Feb-07 5:13
    kennygoers8-Feb-07 5:13 
    GeneralSo close to what I needed Pin
    Waldermort11-Sep-06 8:54
    Waldermort11-Sep-06 8:54 
    GeneralRe: So close to what I needed Pin
    Teashirt213-Sep-07 5:52
    Teashirt213-Sep-07 5:52 
    GeneralRe: So close to what I needed Pin
    Waldermort13-Sep-07 6:01
    Waldermort13-Sep-07 6:01 
    Generalinteger division of 1 by 2 Pin
    KummerSurfer26-Feb-06 7:53
    KummerSurfer26-Feb-06 7:53 
    GeneralHere is HUGE speed improvement Pin
    Jake Montgomery17-Jan-05 11:48
    Jake 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 improvement Pin
    Arlen Albert16-Mar-05 16:24
    Arlen Albert16-Mar-05 16:24 
    GeneralRe: Here is HUGE speed improvement Pin
    Jake Montgomery17-Mar-05 8:04
    Jake Montgomery17-Mar-05 8:04 
    GeneralRe: Here is HUGE speed improvement Pin
    Arlen Albert18-Mar-05 4:14
    Arlen Albert18-Mar-05 4:14 
    GeneralRe: Here is HUGE speed improvement Pin
    Gautam Jain13-May-06 7:34
    Gautam Jain13-May-06 7:34 
    GeneralRe: Here is HUGE speed improvement Pin
    Jake Montgomery10-Jul-06 9:20
    Jake Montgomery10-Jul-06 9:20 
    GeneralRe: Here is HUGE speed improvement Pin
    a.mulay5-Oct-06 2:38
    a.mulay5-Oct-06 2:38 
    GeneralRe: Here is HUGE speed improvement Pin
    DKScherpy6-Nov-06 7:19
    DKScherpy6-Nov-06 7:19 
    GeneralRe: Here is HUGE speed improvement Pin
    a.mulay7-Nov-06 0:44
    a.mulay7-Nov-06 0:44 
    GeneralBugs for 24 bit. Pin
    guju4-May-11 3:43
    guju4-May-11 3:43 
    Questionwhere is my mistake? Pin
    廖楚江6-Dec-04 13:55
    廖楚江6-Dec-04 13:55 
    Questiondo u send theory of those filters to me? Pin
    Member 3084827-Jan-04 16:14
    Member 3084827-Jan-04 16:14 
    GeneralAwesome!! Pin
    WREY18-Nov-03 19:47
    WREY18-Nov-03 19:47 
    QuestionAlgorithm? Pin
    ylzhao17-Jan-03 1:04
    ylzhao17-Jan-03 1:04 
    AnswerRe: Algorithm? Pin
    Guy Bonneau18-Feb-04 3:24
    Guy Bonneau18-Feb-04 3:24 
    GeneralRe: Algorithm? Pin
    Guy Bonneau18-Feb-04 11:20
    Guy Bonneau18-Feb-04 11:20 
    QuestionFaster but less "accurate" version? Pin
    jerry0davis18-Apr-02 0:24
    jerry0davis18-Apr-02 0:24 
    AnswerRe: Faster but less &quot;accurate&quot; version? Pin
    peterchen29-Nov-03 22:51
    peterchen29-Nov-03 22:51 
    QuestionHow to use scailing with grayscale bitmap Pin
    21-Jan-02 19:44
    suss21-Jan-02 19:44 
    Questionsample code??? Pin
    30-Mar-01 15:54
    suss30-Mar-01 15:54 

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

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.