Click here to Skip to main content
15,891,607 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 119.8K   51.5K   405  
An article on a library for image manipulation
/*
    Copyright (C) =USTC= Fu Li

    Author   :  Fu Li
    Create   :  2004-4-9
    Home     :  http://www.phoxo.com
    Mail     :  crazybitwps@hotmail.com

    This file is part of ImageStone

    The code distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    Redistribution and use the source code, with or without modification,
    must retain the above copyright.
*/
#ifndef IMAGE_CODEC_FREEIMAGE_2004_04_09_H
#define IMAGE_CODEC_FREEIMAGE_2004_04_09_H

//-------------------------------------------------------------------------------------
/**
    Read/Write image use FreeImage library (<B>Need FreeImage</B>).
*/
class FCImageCodec_FreeImage : public FCImageCodec
{
public:
    FCImageCodec_FreeImage() {FreeImage_Initialise(TRUE);}
    virtual ~FCImageCodec_FreeImage() {FreeImage_DeInitialise();}

private:
    struct FCAutoFIMEMORY
    {
        FIMEMORY   * m_mem ;
        FREE_IMAGE_FORMAT   m_format ;

        FCAutoFIMEMORY (const void* p, int nSize)
        {
            if (p && nSize)
            {
                m_mem = FreeImage_OpenMemory ((BYTE*)const_cast<void*>(p), nSize) ;
            }
            else
            {
                m_mem = 0 ;
            }
            m_format = (m_mem ? FreeImage_GetFileTypeFromMemory(m_mem) : FIF_UNKNOWN) ;
        }

        ~FCAutoFIMEMORY()
        {
            if (m_mem)
            {
                FreeImage_CloseMemory (m_mem) ;
            }
        }
    };

    struct FCAutoFIBITMAP
    {
        FIBITMAP   * m_bmp ;

        FCAutoFIBITMAP (FIBITMAP* pBmp) : m_bmp(pBmp) {}
        ~FCAutoFIBITMAP()
        {
            if (m_bmp)
            {
                FreeImage_Unload (m_bmp) ;
            }
        }
    };

    struct FCAutoFIMULTIBITMAP
    {
        FIMULTIBITMAP   * m_bmp ;

        FCAutoFIMULTIBITMAP (FIMULTIBITMAP* pBmp) : m_bmp(pBmp) {}
        ~FCAutoFIMULTIBITMAP()
        {
            if (m_bmp)
            {
                FreeImage_CloseMultiBitmap (m_bmp) ;
            }
        }
    };

    static void StoreFrame (FIBITMAP* pFIimage, std::vector<FCObjImage*>& rImageList)
    {
        FCObjImage   * pImg = new FCObjImage ;
        LoadImage (pFIimage, *pImg) ;

        if (pImg->IsValidImage())
        {
            rImageList.push_back (pImg) ;
        }
        else
        {
            delete pImg ;
        }
    }

    static void StoreMultiPage (FIMULTIBITMAP* pMulti, std::vector<FCObjImage*>& image_list, FCImageProperty& rProperty)
    {
        if (!pMulti)
            return ;

        for (int i=0 ; i < FreeImage_GetPageCount(pMulti) ; i++)
        {
            FIBITMAP   * pFrame = FreeImage_LockPage (pMulti, i) ;
            if (pFrame)
            {
                StoreFrame (pFrame, image_list) ;

                // save frame interval, in millisecond
                FITAG   * tag = 0 ;
                if (FreeImage_GetMetadata (FIMD_ANIMATION, pFrame, "FrameTime", &tag) && tag)
                {
                    rProperty.m_frame_delay.push_back (*(int*)FreeImage_GetTagValue(tag)) ;
                }

                FreeImage_UnlockPage (pMulti, pFrame, FALSE) ;
            }
        }
    }

    // Read file routine
    virtual bool LoadImageFile (const wchar_t* szFileName,
                                std::vector<FCObjImage*>& rImageList,
                                FCImageProperty& rImageProp)
    {
        std::string   fname = FC_W2A(szFileName) ;

        FREE_IMAGE_FORMAT   imgType = FreeImage_GetFileType (fname.c_str()) ;
        if (imgType == FIF_UNKNOWN)
            return false ;

        if ((imgType == FIF_GIF) || (imgType == FIF_TIFF) || (imgType == FIF_ICO))
        {
            FCAutoFIMULTIBITMAP   FI (FreeImage_OpenMultiBitmap (imgType, fname.c_str(), FALSE, TRUE)) ;
            StoreMultiPage (FI.m_bmp, rImageList, rImageProp) ;
        }
        else
        {
            FCAutoFIBITMAP   FI (FreeImage_Load (imgType, fname.c_str())) ;
            StoreFrame (FI.m_bmp, rImageList) ;
        }
        return (rImageList.size() != 0) ;
    }

    // Read memory routine
    virtual bool LoadImageMemory (const void* pStart, int nMemSize,
                                  std::vector<FCObjImage*>& rImageList,
                                  FCImageProperty& rImageProp)
    {
        FCAutoFIMEMORY   pMem (pStart, nMemSize) ;

        FREE_IMAGE_FORMAT   imgType = pMem.m_format ;
        if (imgType == FIF_UNKNOWN)
            return false ;

        if ((imgType == FIF_GIF) || (imgType == FIF_TIFF) || (imgType == FIF_ICO))
        {
            FCAutoFIMULTIBITMAP   FI (FreeImage_LoadMultiBitmapFromMemory (imgType, pMem.m_mem)) ;
            StoreMultiPage (FI.m_bmp, rImageList, rImageProp) ;
        }
        else
        {
            FCAutoFIBITMAP   FI (FreeImage_LoadFromMemory (imgType, pMem.m_mem)) ;
            StoreFrame (FI.m_bmp, rImageList) ;
        }
        return (rImageList.size() != 0) ;
    }

    // save to file routine
    virtual bool SaveImageFile (const wchar_t* szFileName,
                                const std::vector<const FCObjImage*>& rImageList,
                                const FCImageProperty& rImageProp)
    {
        if (rImageList.empty() || !rImageList[0]->IsValidImage())
            return false ;
        const FCObjImage   & img = *rImageList[0] ;

        // is the FreeImage support
        FREE_IMAGE_FORMAT   imgFormat = FreeImage_GetFIFFromFilename (FC_W2A(szFileName).c_str()) ;
        if (imgFormat == FIF_UNKNOWN)
            return false ;
        if (!FreeImage_FIFSupportsWriting(imgFormat) || !FreeImage_FIFSupportsExportBPP(imgFormat, img.ColorBits()))
            return false ;

        // create FreeImage object
        FCAutoFIBITMAP   FI (AllocateFreeImage (img)) ;
        if (!FI.m_bmp)
            return false ;

        // save flag
        int   nFlag = 0 ;
        if ((imgFormat == FIF_GIF) && (img.ColorBits() == 8))
        {
            // gif transparency
            if (rImageProp.m_SaveFlag != -1)
            {
                std::vector<BYTE>   aTab (256, (BYTE)0xFF) ;
                aTab[FClamp0255(rImageProp.m_SaveFlag)] = 0 ;
                FreeImage_SetTransparent (FI.m_bmp, true) ;
                FreeImage_SetTransparencyTable (FI.m_bmp, &aTab[0], 256) ;
            }
        }
        else if (imgFormat == FIF_JPEG)
        {
            nFlag = ((rImageProp.m_SaveFlag == -1) ? 90 : rImageProp.m_SaveFlag) ;
        }

        // save image file
        return (FreeImage_Save (imgFormat, FI.m_bmp, FC_W2A(szFileName).c_str(), nFlag) ? true : false) ;
    }

    std::string FC_W2A (const wchar_t* pws)
    {
        std::string   s ;
        if (pws)
        {
#if (defined(_WIN32) || defined(__WIN32__))
            int   nByte = WideCharToMultiByte(CP_THREAD_ACP, 0, pws, -1, NULL, 0, NULL, NULL) ;
            if (nByte)
            {
                std::vector<char>   p (nByte+1) ;
                WideCharToMultiByte(CP_THREAD_ACP, 0, pws, -1, &p[0], nByte, NULL, NULL) ;
                s = &p[0] ;
            }
#else
            size_t   nBytes = (wcslen(pws) + 1) * sizeof(wchar_t) ;
            std::vector<char>   p (nBytes, (char)0) ;
            wcstombs (&p[0], pws, nBytes) ;
            s = &p[0] ;
#endif
        }
        return s ;
    }

    // ImageStone --> FreeImage.
    static FIBITMAP* AllocateFreeImage (const FCObjImage& img)
    {
        if (!img.IsValidImage())
            return 0 ;

        // create FreeImage object
        FIBITMAP   * pFIimg = FreeImage_Allocate (img.Width(), img.Height(), img.ColorBits()) ;
        if (!pFIimg)
            return 0 ;

        // set pixel
        memcpy (FreeImage_GetBits(pFIimg), img.GetMemStart(), img.GetPitch()*img.Height()) ;

        // set palette
        if (img.ColorBits() <= 8)
        {
            RGBQUAD   pPal[256] ;
            img.GetColorTable (pPal) ;
            memcpy (FreeImage_GetPalette(pFIimg), pPal, FreeImage_GetColorsUsed(pFIimg) * sizeof(RGBQUAD)) ;
        }

        // clear, default is 2835 = 72dpi
        FreeImage_SetDotsPerMeterX (pFIimg, 0) ;
        FreeImage_SetDotsPerMeterY (pFIimg, 0) ;

        return pFIimg ;
    }

    // FreeImage --> ImageStone.
    static void LoadImage (FIBITMAP* pFrame, FCObjImage& img)
    {
        if (!pFrame)
        {
            img.Destroy() ;
            return ;
        }

        FIBITMAP  * pBMP = pFrame ;
        bool      bDeleteBMP = false ;

        switch (FreeImage_GetBPP(pFrame))
        {
            case 1 :
            case 4 :
            case 8 :
            case 16 :
                if (FreeImage_IsTransparent(pFrame))
                {
                    pBMP = FreeImage_ConvertTo32Bits(pFrame) ;
                }
                else
                {
                    pBMP = FreeImage_ConvertTo24Bits(pFrame) ;
                }
                bDeleteBMP = true ;
                break;

            case 24 :
            case 32 :
                break;
        }

        // create frame
        img.Create (FreeImage_GetWidth(pBMP), FreeImage_GetHeight(pBMP), FreeImage_GetBPP(pBMP)) ;
        if (img.IsValidImage())
        {
            memcpy (img.GetMemStart(), FreeImage_GetBits(pBMP), img.GetPitch()*img.Height()) ;
        }

        if (bDeleteBMP)
        {
            FreeImage_Unload (pBMP) ;
        }
    }
};

#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