Click here to Skip to main content
15,892,005 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 120K   51.5K   405  
An article on a library for image manipulation
/*
 *   Copyright (C) =USTC= Fu Li
 *
 *   Author   :  Fu Li
 *   Create   :  2003-4-8
 *   Home     :  http://www.crazy-bit.com/
 *   Mail     :  crazybitwps@hotmail.com
 *   History  :  
 */
#ifndef __FOO_OBJECT_SELECTION__2003_04_08__H__
#define __FOO_OBJECT_SELECTION__2003_04_08__H__
#include "ObjImage.h"
#include "PCL_interface_zoom.h"

//=============================================================================
/**
 *  Selection object (bitmap mask).
 *  it's a 8-bit gray image, 0xFF means pixel selected, otherwise unselected.
 */
class FCObjSelect : public FCObjImage
{
public:
    /** handle type. */
    enum RGN_TYPE
    {
        RGN_CREATE=0, /**< create a new selection */
        RGN_ADD=1,    /**< add selection into current selection */
        RGN_SUB=2,    /**< sub selection from current selection */
    };
public:
    /**
     *  @name Constructor.
     */
    //@{
    /// Create an empty selection.
    FCObjSelect ()
    {
        m_nZoom = ZOOM_UNSCAN ;
        m_nCurAnt = 0 ;
    }
    /// Copy constructor.
    FCObjSelect (const FCObjSelect& sel)
    {
        m_nZoom = ZOOM_UNSCAN ;
        m_nCurAnt = 0 ;
        *this = sel ;
    }
    //@}

    FCObjSelect& operator= (const FCObjSelect& sel)
    {
        if (&sel == this)
        {
            assert(false); return *this;
        }

        __SetSelectionEmpty(); // enable empty copy
        if (sel.HasSelected())
        {
            m_nZoom = sel.m_nZoom;
            m_nCurAnt = sel.m_nCurAnt;
            m_ptEdge = sel.m_ptEdge; // copy the edge point
            FCObjImage::operator=(sel);
        }
        return *this;
    }

    /// Is selection object valid.
    bool HasSelected() const {return IsValidImage();}

    /**
     *  Optimize selection.
     *  erase un-selected point around. the position of selection will be adjusted automatically.
     */
    void SelectionOptimize()
    {
        if (!HasSelected())
            return ;

        RECT     rcBound = {Width(), Height(), 0, 0} ;
        for (int y=0 ; y < Height() ; y++)
            for (int x=0 ; x < Width() ; x++)
                if (*GetBits(x,y) == 0xFF)
                {
                    if (x < rcBound.left)    rcBound.left = x ;
                    if (x > rcBound.right)   rcBound.right = x ;
                    if (y < rcBound.top)     rcBound.top = y ;
                    if (y > rcBound.bottom)  rcBound.bottom = y ;
                }

        // the selection is open, so we ++
        rcBound.right++ ; rcBound.bottom++ ;

        // the whole selection is empty
        if (IsRectEmpty(&rcBound))
        {
            __SetSelectionEmpty() ;
            return ;
        }

        // the selection can't be optimized
        const RECT   rcSel = {0, 0, Width(), Height()} ;
        if (memcmp (&rcSel, &rcBound, sizeof(RECT)) == 0) // rect is equal
            return ;

        // erase == get a sub block
        const POINT     ptOldPos = GetGraphObjPos() ;
        FCObjImage      imgSub ;
        GetSubBlock (&imgSub, rcBound) ;
        *static_cast<FCObjImage*>(this) = imgSub ;
        SetGraphObjPos (ptOldPos.x+rcBound.left, ptOldPos.y+rcBound.top) ;

        m_ptEdge.clear() ;
        m_nCurAnt = 0 ;
        m_nZoom = ZOOM_UNSCAN ; // force to re-calculate edge
    }

    /**
     *  Calculate edge point by nZoom.
     *  edge point's coordinate relative to top-left of selection object.
     */
    void RecalculateEdge (int nZoom, bool bForceRecalculate)
    {
        if (!HasSelected())
        {
            m_ptEdge.clear() ;
            m_nCurAnt = 0 ;
            m_nZoom = ZOOM_UNSCAN ;
            return ;
        }

        if (!bForceRecalculate)
            if (m_nZoom == nZoom)
                return ;

        m_ptEdge.clear() ;
        m_nCurAnt = 0 ;
        m_nZoom = nZoom ;
        if ((m_nZoom == ZOOM_UNSCAN) || (m_nZoom == 0))
            return ;

        // search edge point
        FCObjImage   EdgeImg (Width(), Height(), 8) ;
        int          nEdgeNum = 0 ;

        // is edge point : current is selected around is non-selected
        // brim point must be edge point
        for (int y=0 ; y < Height() ; y++)
            for (int x=0 ; x < Width() ; x++)
                if (*GetBits(x,y) == 0xFF)
                    if ((y == 0)          || (*GetBits(x,y-1) == 0) || // up
                        (y == Height()-1) || (*GetBits(x,y+1) == 0) || // down
                        (x == 0)          || (*GetBits(x-1,y) == 0) || // left
                        (x == Width()-1)  || (*GetBits(x+1,y) == 0) || // right
                        (*GetBits(x+1,y-1) == 0) || // right-up
                        (*GetBits(x+1,y+1) == 0) || // right-down
                        (*GetBits(x-1,y+1) == 0) || // left-down
                        (*GetBits(x-1,y-1) == 0)) // left-up
                    {
                        *EdgeImg.GetBits(x,y) = 0xFF ;
                        nEdgeNum++ ;
                    }

        // no edge point
        if (nEdgeNum == 0)
            return ;

        if (m_nZoom <= -1)
        {
            // deflate, only div
            FCObjImage   imgHash (Width()/-m_nZoom+2, Height()/-m_nZoom+2, 8) ;
            for (int y=0 ; y < Height() ; y++)
                for (int x=0 ; x < Width() ; x++)
                    if (*EdgeImg.GetBits(x,y) == 0xFF)
                    {
                        POINT   pt = {x/-m_nZoom, y/-m_nZoom} ;
                        BYTE    * pHash = imgHash.GetBits (pt.x, pt.y) ;
                        if (*pHash == 0) // some point --> one point
                        {
                            *pHash = 0xFF ;
                            m_ptEdge.push_back (pt) ;
                        }
                    }
        }
        else
        {
            // inflate, we should insert some point
            const int   nNewW = Width() * m_nZoom,
                        nNewH = Height() * m_nZoom ;

            // calculate x/y table
            PCL_array<int>   pX (nNewW),
                             pY (nNewH) ;
            int              x, y ;
            for (y=0 ; y < nNewH ; y++)
                {pY[y] = y / m_nZoom; assert (pY[y] < Height());}
            for (x=0 ; x < nNewW ; x++)
                {pX[x] = x / m_nZoom; assert (pX[x] < Width());}

            // search edge
            for (y=0 ; y < nNewH ; y++)
                for (x=0 ; x < nNewW ; x++)
                    if (*EdgeImg.GetBits (pX[x],pY[y]) == 0xFF)
                    {
                        // still edge point after inflate
                        int   cr = *GetBits (pX[x],pY[y]) ;
                        if ((y == 0)       || (*GetBits(pX[x],pY[y-1]) != cr) || // up
                            (y == nNewH-1) || (*GetBits(pX[x],pY[y+1]) != cr) || // down
                            (x == 0)       || (*GetBits(pX[x-1],pY[y]) != cr) || // left
                            (x == nNewW-1) || (*GetBits(pX[x+1],pY[y]) != cr)) // right
    //                      (*(pPixel + 1 + dwPitch) == 0) || // right-up
    //                      (*(pPixel + 1 - dwPitch) == 0) || // right-down
    //                      (*(pPixel - 1 - dwPitch) == 0) || // left-down
    //                      (*(pPixel - 1 + dwPitch) == 0)) // left_up
                        {
                            POINT   pt = {x,y} ;
                            m_ptEdge.push_back (pt) ;
                        }
                    }
        }
    }

private:
    enum
    {
        ZOOM_UNSCAN = 0x7FFF,
    };

    // internal. set selection empty
    void __SetSelectionEmpty()
    {
        FCObjImage::Destroy() ;
        m_ptEdge.clear() ;
        m_nZoom = ZOOM_UNSCAN ;
        m_nCurAnt = 0 ;
    }

private:
    int     m_nZoom ;
    int     m_nCurAnt ; // [0..7]
    std::deque<POINT>   m_ptEdge ; // scaled edge point

friend class FCWin32 ;
};

//===================================================================
// inline implement
//===================================================================

#endif

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