Click here to Skip to main content
15,897,518 members
Articles / Desktop Programming / MFC

ImageStone - A Powerful C++ Class Library for Image Manipulation

Rate me:
Please Sign up or sign in to vote.
4.81/5 (250 votes)
6 Dec 2011Zlib3 min read 121.8K   51.5K   405  
An article on a library for image manipulation
//-------------------------------------------------------------------------------------
/// Gauss blur (>=24 bit).
class FCEffectBlur_Gauss : public FCImageEffect
{
public:
    enum BLUR_COMPONENT
    {
        BLUR_COMPONENT_ALL = 1,
        BLUR_COMPONENT_ONLY_ALPHA = 2,
    };

    /**
        Constructor \n
        nSize >= 1 \n
        bCopyEdge - set false to blur border with alpha==0 \n
        blur_component - can be FCEffectBlur_Gauss::BLUR_COMPONENT_ALL or FCEffectBlur_Gauss::BLUR_COMPONENT_ONLY_ALPHA
    */
    FCEffectBlur_Gauss (int nSize, bool bCopyEdge, BLUR_COMPONENT blur_component=BLUR_COMPONENT_ALL)
    {
        m_copy_edge = (bCopyEdge ? 1 : 0) ;
        m_component = blur_component ;
        MakeKernel (((nSize >= 1) ? nSize : 1) / 2.0) ;
        m_padding = (int)m_kernel.size() / 2 ;
    }

protected:
    /// Derived class can modify pPixel that has been blured.
    virtual void OnFinishPixel (FCObjImage& img, int x, int y, BYTE* pPixel) {}

private:
    int      m_copy_edge ;
    BLUR_COMPONENT   m_component ;
    std::vector<double>   m_kernel ;
    int      m_padding ;

    int      m_bpp ; // 24 or 32
    RGBQUAD  * m_line_buf ;

private:
    enum
    {
        MAX_RADIUS = 100,
    };

    static void DivideWeight (std::vector<double>& ls)
    {
        double   t = 0 ;
        for (size_t i=0 ; i < ls.size() ; i++)
            t += ls[i] ;

        for (size_t i=0 ; i < ls.size() ; i++)
            ls[i] /= t ;
    }

    void MakeKernel (double fRadius)
    {
        m_kernel.reserve (2*MAX_RADIUS + 1) ;
        for (int i = -MAX_RADIUS ; i <= MAX_RADIUS ; i++)
        {
            double   t = i / fRadius ;
            m_kernel.push_back (exp (-t*t/2)) ;
        }

        // divide weight
        DivideWeight(m_kernel) ;

        // remove small weight
        double   max_precision = 1 / (2.0 * 255) ;
        double   fTotal = 0 ;
        for (int i=0 ; i < MAX_RADIUS ; i++)
        {
            fTotal += (2 * m_kernel.front()) ;

            if (fTotal < max_precision)
            {
                m_kernel.erase (m_kernel.begin()) ;
                m_kernel.pop_back() ;
            }
            else
            {
                break ;
            }
        }

        // correct sum
        DivideWeight(m_kernel) ;
    }

private:
    void BlurOnePixel (BYTE* pDest, const RGBQUAD* pSrc)
    {
        double   * pKer = &m_kernel[0] ;
        double   r=0, g=0, b=0, a=0 ;
        for (size_t i=0 ; i < m_kernel.size() ; i++, pSrc++)
        {
            if (PCL_A(pSrc))
            {
                double   aw = PCL_A(pSrc) * pKer[i] ;
                if (m_component != BLUR_COMPONENT_ONLY_ALPHA)
                {
                    b += (PCL_B(pSrc) * aw) ;
                    g += (PCL_G(pSrc) * aw) ;
                    r += (PCL_R(pSrc) * aw) ;
                }
                a += aw ;
            }
        }

        RGBQUAD   c ;
        PCL_A(&c) = FClamp0255(a) ;

        if (m_component == BLUR_COMPONENT_ONLY_ALPHA)
        {
            assert (m_bpp == 32) ;
            PCL_A(pDest) = PCL_A(&c) ;
        }
        else
        {
            if (PCL_A(&c))
            {
                PCL_B(&c) = FClamp0255(b/a) ;
                PCL_G(&c) = FClamp0255(g/a) ;
                PCL_R(&c) = FClamp0255(r/a) ;
            }
            FCColor::CopyPixelBPP (pDest, &c, m_bpp) ;
        }
    }

    RGBQUAD GetRGBQUAD (const void* pPixel)
    {
        RGBQUAD   c = FCColor(0,0,0,0xFF) ; // default alpha is 255
        FCColor::CopyPixelBPP (&c, pPixel, m_bpp) ;
        return c ;
    }

    void FillPadding (RGBQUAD*& d, const void* pPixel)
    {
        for (int i=0 ; i < m_padding ; i++, d++)
        {
            *d = (m_copy_edge ? GetRGBQUAD(pPixel) : FCColor(0xFF,0xFF,0xFF,0)) ;
        }
    }

    void HorizonGetLine (FCObjImage& img, int y, RGBQUAD* d)
    {
        FillPadding (d, img.GetBits(0,y)) ;
        for (int x=0 ; x < img.Width() ; x++, d++)
        {
            *d = GetRGBQUAD(img.GetBits(x,y)) ;
        }
        FillPadding (d, img.GetBits(img.Width()-1,y)) ;
    }

    void VerticalGetLine (FCObjImage& img, int x, RGBQUAD* d)
    {
        FillPadding (d, img.GetBits(x,0)) ;
        for (int y=0 ; y < img.Height() ; y++, d++)
        {
            *d = GetRGBQUAD(img.GetBits(x,y)) ;
        }
        FillPadding (d, img.GetBits(x,img.Height()-1)) ;
    }

    void BlurVertical (FCObjImage& img, FCProgressObserver* pProgress)
    {
        for (int x=0 ; x < img.Width() ; x++)
        {
            VerticalGetLine (img, x, m_line_buf) ;

            RGBQUAD   * s = m_line_buf ;
            for (int y=0 ; y < img.Height() ; y++, s++)
            {
                BlurOnePixel (img.GetBits(x,y), s) ;
            }

            if (pProgress)
            {
                if (!pProgress->UpdateProgress (0)) // need call it for cancel process
                    break ;
            }
        }
    }

    void BlurHorizon (FCObjImage& img, FCProgressObserver* pProgress)
    {
        for (int y=0 ; y < img.Height() ; y++)
        {
            HorizonGetLine (img, y, m_line_buf) ;

            RGBQUAD   * s = m_line_buf ;
            for (int x=0 ; x < img.Width() ; x++, s++)
            {
                BYTE   * pPixel = img.GetBits(x,y) ;
                BlurOnePixel (pPixel, s) ;
                OnFinishPixel (img, x, y, pPixel) ;
            }

            if (pProgress)
            {
                if (!pProgress->UpdateProgress (100 * (y+1) / img.Height()))
                    break ;
            }
        }
    }

private:
    virtual PROCESS_TYPE QueryProcessType()
    {
        return PROCESS_TYPE_WHOLE ;
    }

    virtual void ProcessWholeImage (FCObjImage& img, FCProgressObserver* pProgress)
    {
        if (img.IsValidImage())
        {
            // prepare param
            m_bpp = img.ColorBits() ;

            int   w = img.Width() ;
            int   h = img.Height() ;
            int   nCount = ((w > h) ? w : h) + 2*m_padding + 2 ; // +2 is not necessary
            m_line_buf = new RGBQUAD[nCount] ;

            BlurVertical (img, pProgress) ;
            BlurHorizon (img, pProgress) ;

            delete[] m_line_buf ;
        }
    }
};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The zlib/libpng License


Written By
Team Leader PhoXo
China China
graduate from University of Science and Technology of China at 2002.

Now I work at www.phoxo.com.

Comments and Discussions