본문 바로가기

Native/C++

CJpeglibExtension

[code]
/**
* @file JpeglibExtension.h
* @author cheol-dong choi <aucd29@gmail.com>
* @version 1.0
* @date April 9, 2009 13:26:31
* @section LICENSE
*
* Copyright (c) 2003-2010, cheol-dong choi, (http://www.sarangnamu.net)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* @section DESCRIPTION
*
*
* @section CHANGE_LOG
*
*/



#ifndef __CD_JPEGLIBEXTENSION_H__
#define __CD_JPEGLIBEXTENSION_H__

#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <stdio.h>
#include <string>

/* The maximum number of palette entries in palette-based images.
In the wonderful new world of gd 2.0, you can of course have
many more colors when using truecolor mode. */

#define gdMaxColors 256

extern "C"
{
#include "jpeglib.h"
}

#define MAXSIZE     2048                    /* Maximum size of thumbnail */
#define MINSIZE     1                     /* Minimum size of thumbnail */
#define DEFAULTSIZE 128                     /* Default size of thumbnail */

#define GRAY 128

#define RSZ_AUTO 0
#define RSZ_WIDTH 1
#define RSZ_HEIGHT 2
#define RSZ_FIX    3

#ifndef byte
typedef unsigned char byte;
#endif

struct my_error_mgr
{
    struct jpeg_error_mgr pub; /* "public" fields     */
    jmp_buf setjmp_buffer;     /* for return to caller */
};

typedef struct my_error_mgr * my_error_ptr;

static void my_error_exit(j_common_ptr cinfo)
{
    my_error_ptr myerr = (my_error_ptr) cinfo->err;
    char buf[JMSG_LENGTH_MAX];
    (*cinfo->err->format_message)(cinfo,buf);
    longjmp(myerr->setjmp_buffer, 1);
}

class CJpeglibExtension
{
public:
    CJpeglibExtension(void);

    ~CJpeglibExtension(void);

public:
    bool Read(const char* filename);

    bool Read(const char* szPath, const char* szName);

    bool Resize(int maxsize=DEFAULTSIZE, int which_dim=RSZ_AUTO);

    bool Matrix(int nCount=3);

    bool Write(const char *filename, int quality, bool bMatrix=false);

    void FreeMemory(bool bMatrix=false);

    byte* GetPalette() { return _palette; }

    byte* GetReadImage() { return _readImage; }

    int GetWidth() { return _width; }

    int GetHeight() { return _height; }

    bool IsDivide(int nDivCount, int& nX, int& nY);

protected:
    byte* _readImage;

    byte* _outimage;                 /* The current thumbnail image */

    byte* _palette;                 /* Global palette pointer     */

    int _width;                     /* Original image width        */

    int _height;                     /* Original image height     */

    int _background;                 /* Index's background color    */

    int _dwEffWidth;

    int _wBpp;

    int _biClrUsed;

    long _out_wide;                 /* Width of thumbnail image    */

    long _out_high;                 /* Height of thumbnail image */

    std::string _szFileName;
};

#endif
[/code]

[code]
/**
* @file JpeglibExtension.cpp
* @author cheol-dong choi <aucd29@gmail.com>
* @version 1.0
* @date April 9, 2009 13:26:27
* @section LICENSE
*
* Copyright (c) 2003-2010, cheol-dong choi, (http://www.sarangnamu.net)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* @section DESCRIPTION
*
*
* @section CHANGE_LOG
*
*/



#include "JpeglibExtension.h"

#include "RSLOGGER.H"

#if defined(_WIN32_WCE)
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif


CJpeglibExtension::CJpeglibExtension(void)
{
    _outimage = NULL;
    _readImage = NULL;
    _palette    = NULL;

    _width     = 0;                 /* Original image width        */
    _height     = 0;                 /* Original image height     */
    _background = 0;                 /* Index's background color    */
    _out_wide = 0;                 /* Width of thumbnail image    */
    _out_high = 0;                 /* Height of thumbnail image */

    _szFileName = "";
}

CJpeglibExtension::~CJpeglibExtension(void)
{
    FreeMemory();
}

// -----------------------------------------------------------

bool CJpeglibExtension::Read(const char* filename)
{
    struct jpeg_decompress_struct cinfo;
    struct my_error_mgr jerr;

    int f;
    int row_stride;
    FILE* infile;
    byte* ptr;

    FreeMemory();

    _szFileName = filename;

#if !defined(ANDROID)
    try
    {
#endif
        _palette = (byte*)calloc(1, 1768);

        if (_palette == NULL)
        {
#if !defined(ANDROID)
            throw "Out of memory!!";
#else
            ASSERT(0);
#endif
        }

        infile = fopen(filename,"rb");
        if (infile == NULL)
        {
#if !defined(ANDROID)
            throw "File not found!!";
#else
            ASSERT(0);
#endif
        }

        cinfo.err         = jpeg_std_error(&jerr.pub);
        jerr.pub.error_exit = my_error_exit;

        if (setjmp(jerr.setjmp_buffer))
        {
            jpeg_destroy_decompress(&cinfo);

            fclose(infile);
            delete[] _palette;

#if !defined(ANDROID)
            throw "setjmp";
#else
            ASSERT(0);
#endif
        }

        /* Now we can initialize the JPEG decompression object. */
        jpeg_create_decompress(&cinfo);
        jpeg_stdio_src(&cinfo,infile);
        jpeg_read_header(&cinfo,TRUE);

        /* setup parameters for decompression */
        cinfo.dct_method                = JDCT_ISLOW;
        cinfo.quantize_colors         = TRUE;
        cinfo.desired_number_of_colors = 256;
        cinfo.two_pass_quantize         = TRUE;

        /* Fix to greys if greyscale. (required to read greyscale JPEGs) */
        if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
        {
            cinfo.out_color_space         = JCS_GRAYSCALE;
            cinfo.desired_number_of_colors = 256;
            cinfo.quantize_colors         = FALSE;
            cinfo.two_pass_quantize         = FALSE;

            for(f=0; f<256; f++)
            {
                _palette[f] = _palette[256 + f] = _palette[512 + f] = f;
            }
        }

        _width     = cinfo.image_width;
        _height     = cinfo.image_height;
        _readImage = (byte*)calloc(1, _width * _height);

        if (_readImage == NULL)
        {
            longjmp(jerr.setjmp_buffer,1);
#if !defined(ANDROID)
            throw "Out of memory!!";
#else
            ASSERT(0);
#endif
        }

        jpeg_start_decompress(&cinfo);

        int wBpp = (cinfo.output_components * 8);

        // Make sure bits per pixel is valid
        if (wBpp <= 1)
        {
            _wBpp     = 1;
            _biClrUsed = 2;
        }
        else if (wBpp <= 4)
        {
            _wBpp     = 4;
            _biClrUsed = 16;
        }
        else if (wBpp <= 8)
        {
            _wBpp     = 8;
            _biClrUsed = 256;
        }
        else
        {
            _wBpp     = 24;
            _biClrUsed = 0;
        }

        // set the common image informations
        _dwEffWidth = ((((_wBpp * _width) + 31) / 32) * 4);

        /* read the palette (if greyscale, this has already been done) */
        if (cinfo.jpeg_color_space != JCS_GRAYSCALE)
        {
            for (f=0; f<cinfo.actual_number_of_colors; f++)
            {
                _palette[    f] = cinfo.colormap[0][f];
                _palette[256+f] = cinfo.colormap[1][f];
                _palette[512+f] = cinfo.colormap[2][f];
            }
        }

        if (cinfo.out_color_space == JCS_GRAYSCALE)
        {
            _biClrUsed = 256;
        }
        else
        {
            if (cinfo.quantize_colors)
            {
                _biClrUsed = cinfo.actual_number_of_colors;
            }
            else
            {
                _biClrUsed = 0;
            }
        }

        ptr         = _readImage;
        row_stride = _width;

        /* read the image */
        while (cinfo.output_scanline < (unsigned int)_height)
        {
            jpeg_read_scanlines(&cinfo, &ptr, 1);
            ptr += row_stride;
        }

        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);

        fclose(infile);

#if !defined(ANDROID)
    }
    catch (const char* e)
    {
        printf("Error!! %s\n", e);

        return false;
    }
#endif

    return true;
}


//
// Read
//

bool CJpeglibExtension::Read(const char* szPath, const char* szName)
{
    LOG1("JpeglibExtension::Read\n");

    //
    // Method description
    // -------
    //
    //

    if (szPath == NULL || szName == NULL)
    {
        LOG3("ERROR::CJpeglibExtension::Read <szPath == NULL || szName == NULL>\n");

        return false;
    }

    std::string szFullPath;
    size_t i;

    szFullPath = szPath;
    i = strlen(szPath);

    if (szPath[i - 1] != '/' && szPath[i - 1] != '\\')
    {
        szFullPath += "/";
    }
    
    szFullPath += szName;

    return Read(szFullPath.c_str());
}


bool CJpeglibExtension::Write(const char *filename, int quality, bool bMatrix/*=true*/)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr     jerr;
    FILE     *out;
    JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s]         */
    int     row_stride;        /* physical row width in image buffer */

#if !defined(ANDROID)
    try
    {
#endif
        /* Step 1: Allocate and initialize JPEG compression object. */
        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_compress(&cinfo);

        /* Step 2: Specify data destination. */
        if (filename == NULL)
        {
#if !defined(ANDROID)
            throw "Invalid filename";
#else
            ASSERT(0);
#endif
        }

        if (filename)
        {
            out = fopen(filename, "wb");

            if (out == NULL)
            {
#if !defined(ANDROID)
                throw "can not open files";
#else
                ASSERT(0);
#endif
            }
        }

        jpeg_stdio_dest(&cinfo,out);

        /* Step 3: set parameters for compression */
        cinfo.image_width     = _out_wide; /* image width and height, in pix */
        cinfo.image_height     = _out_high;
        cinfo.input_components = 3;         /* # of color components per pix */
        cinfo.in_color_space = JCS_RGB; /* colorspace of input image     */

        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo,quality,FALSE);

        /* Step 4: Start compressor */
        jpeg_start_compress(&cinfo,TRUE);

        /* Step 5: while (scan lines remain to be written) */
        row_stride = _out_wide * 3;    /* JSAMPLEs per row in image_buffer */

        while (cinfo.next_scanline < cinfo.image_height)
        {
            row_pointer[0] = &_outimage[cinfo.next_scanline*row_stride];
            jpeg_write_scanlines(&cinfo,row_pointer,1);
        }

        /* Step 6: Finish compression */
        jpeg_finish_compress(&cinfo);

        fclose(out);

        /* Step 7: release JPEG compression object */
        jpeg_destroy_compress(&cinfo);

#if !defined(ANDROID)
    }
    catch (const char* e)
    {
        printf("Error!! %s\n", e);
        return false;
    }
#endif

    FreeMemory(bMatrix);

    return true;
}

bool CJpeglibExtension::Resize(int maxsize, int resize_dim)
{
    register int a, b, x, yp, yw;
    long y, sw, sh, lastyp;
    int c, pixwide, pixhigh;
    int tmp, tr, tg, tb, tn;
    int xypos;

#if !defined(ANDROID)
    try
    {
#endif
        if (_readImage == NULL)
        {
#if !defined(ANDROID)
            throw "Please read file!!";
#else
            ASSERT(0);
#endif

            return false;
        }

        byte* palr = GetPalette();
        byte* palg = GetPalette() + 256;
        byte* palb = GetPalette() + 512;

        /* The resize dimension wasn't provided... */
        if (!resize_dim)
        {
            if (_width <= _height)
            {
                /* Picture is square or portraity */
                resize_dim = RSZ_HEIGHT;
            }
            else
            {
                /* Picture is landscapey */
                resize_dim = RSZ_WIDTH;
            }
        }

        switch(resize_dim)
        {
        case RSZ_FIX:
            sh = sw = maxsize;
            break;

        case RSZ_HEIGHT:
            sh = maxsize;
            sw = (int)( (maxsize * ((double)_width)) / ((double)_height) );
            break;

        case RSZ_WIDTH:
            sw = maxsize;
            sh = (int)( (maxsize * ((double)_height)) / ((double)_width) );
            break;

        default:
            /* WE SHOULD NEVER GET HERE! */
            sw = sh = 0;
            break;
        }

        /* This is a kludge. */
        if (sw == 0) sw += 1;
        if (sh == 0) sh += 1;

        _out_wide = sw;
        _out_high = sh;

        /* Reserve the amount of memory we will need. */
        _outimage = (byte*)calloc(1, (sw * sh * 3));
        if (_outimage == NULL)
        {
#if !defined(ANDROID)
            throw "Out of memory!!";
#else
            ASSERT(0);
#endif
        }

        for (x=0; x<(sw * sh * 3); x++)
        {
            _outimage[x] = GRAY;
        }

        /* It has been reduced. */
        if (_width > sw)
        {
            lastyp = -1;
            pixhigh = (int)( ((float)_height) / ((float)sh) + 0.5 );
            pixwide = (int)( ((float)_width) / ((float)sw) + 0.5 );
            pixhigh++;
            pixwide++;

            for(y=0; y < _height; y++)
            {
                yp = (y * sh) / _height;

                if (yp != lastyp)
                {
                    yw = (y * _width);

                    /* we try to resample a bit. get that pentium RSN :) */
                    for (x=0; x < _width; x++,yw++)
                    {
                        tr = 0;
                        tg = 0;
                        tb = 0;
                        tn = 0;

                        for (b=0; (b < pixhigh) && (y+b < _height); b++)
                        {
                            for (a=0; (a < pixwide) && (x + a < _width); a++)
                            {
                                tmp = *(_readImage + yw + a + b * _width);
                                tr += palr[tmp];
                                tg += palg[tmp];
                                tb += palb[tmp];
                                tn++;
                            }
                        }

                        xypos = 3 * (((x * sw) / _width) + yp * sw);

                        tr /= tn;
                        tg /= tn;
                        tb /= tn;

                        _outimage[xypos] = tr;
                        _outimage[xypos+1] = tg;
                        _outimage[xypos+2] = tb;
                    }

                    lastyp = yp;
                }
            }
        }
        else
        {
            /* we just leave it the same size */

            _out_wide = _width;
            _out_high = _height;

            for (y=0; y < _height; y++)
            {
                for (x=0; x < _width; x++)
                {
                    c = _readImage[y * _width + x];
                    _outimage[3 * (y * _width + x)]     = palr[c];
                    _outimage[3 * (y * _width + x) + 1] = palg[c];
                    _outimage[3 * (y * _width + x) + 2] = palb[c];
                }
            }
        }
#if !defined(ANDROID)
    }
    catch (const char* e)
    {
        printf("Error!! %s\n", e);
        return false;
    }
#endif

    return true;
}

//
// Matrix
//
bool CJpeglibExtension::Matrix(int nCount/*=3*/)
{
    if (!_width || !_height)
        return false;

    std::string szExtension;

    //
    // Find extension
    //
    szExtension = strrchr(_szFileName.c_str(), '.');

    //
    // Checking extension
    //
    if (szExtension != ".jpg" && szExtension != ".jpeg")
        return false;

    int nWidth, nHeight;

    if (!IsDivide(nCount, nWidth, nHeight))
    {
        ASSERT(0);
    }

    nWidth = static_cast<int>(_width / nCount);
    nHeight = static_cast<int>(_height / nCount);

    printf("resize Information Width: %d, height: %d\n", nWidth, nHeight);

    register int x;
    long y;
    int c;

#if !defined(ANDROID)
    try
    {
#endif
        if (_readImage == NULL)
#if !defined(ANDROID)
            throw "Please read file!!";
#else
            ASSERT(0);
#endif

        byte* palr = GetPalette();
        byte* palg = GetPalette() + 256;
        byte* palb = GetPalette() + 512;

        if (_outimage)
            free(_outimage);

        _out_wide = nWidth;
        _out_high = nHeight;
        _outimage = (byte*)calloc(1, (nWidth * nHeight * 3));

        if (_outimage == NULL)
#if !defined(ANDROID)
            throw "Out of memory!!";
#else
            ASSERT(0);
#endif

        int nImageCount = 1;
        int nXPos = 0, nYPos = 0, nPos = 0;

        //
        // Matrix 형태로 이미지를 자르기 위해서 몇등분을 할지 입력값을 받은 다음
        // 해당 개수 만큼 가로/세로 로 자르게 된다.
        //
        for (int h=1; h<=nCount; ++h)
        {
            for (int w=1; w<=nCount; ++w)
            {
                //
                // Initialize Memory
                //
                for (x=0; x<(nWidth * nHeight * 3); x++)
                {
                    _outimage[x] = GRAY;
                }

                printf("Image Filling Area(xPos:%d, yPos:%d)\n", nXPos, nYPos);

                //
                // Fill Memory
                //
                for (y=nYPos; y < (nHeight * h); ++y)
                {
                    for (x=nXPos; x < (nWidth * w); ++x)
                    {
                        c = _readImage[y * _width + x];

                        nPos = (y - nYPos) * nWidth + (x - nXPos);

                        _outimage[3 * nPos]     = palr[c];
                        _outimage[3 * nPos + 1] = palg[c];
                        _outimage[3 * nPos + 2] = palb[c];
                    }
                }

                std::string szFileName;
                char szNumber[8] = {0};

                //
                // Name setting
                //
                sprintf(szNumber, "%03d", nImageCount);
                szFileName = _szFileName.substr(0, _szFileName.size() - szExtension.size());
                szFileName += "_split";
                szFileName += szNumber;
                szFileName += szExtension;

                ++nImageCount;

                //
                // Write Jpeg file
                //
                Write(szFileName.c_str(), 70, true);

                nXPos += nWidth;
            }

            nXPos = 0;
            nYPos += nHeight;
        }

        FreeMemory();

#if !defined(ANDROID)
    }
    catch (const char* e)
    {
        printf("ERROR : %s\n", e);

        return false;
    }
#endif

    return true;
}


void CJpeglibExtension::FreeMemory(bool bMatrix/*=false*/)
{
    if (bMatrix)
        return ;

    if (_outimage != NULL)
    {
        free(_outimage);
    }

    if (_readImage != NULL)
    {
        free(_readImage);
    }

    if (_palette != NULL)
    {
        free(_palette);
    }

    _outimage = NULL;
    _readImage = NULL;
    _palette    = NULL;
}


//
// IsDivide
//
bool CJpeglibExtension::IsDivide(int nDivCount, int& nX, int& nY)
{
    //LOG1("JpeglibExtension::IsDivide\n");

    if (_width == 0 || _height == 0)
        return false;

    nX = _width % nDivCount;
    nY = _height % nDivCount;

    printf("Image Information Width: %d, Height: %d\n", _width, _height);
    printf("Image Divide Value : w:%d, h:%d\n", nX, nY);

    bool bRes = true;

    if (nX != 0)
    {
        nX = (int(_width / nDivCount) + 1) * nDivCount;

        printf("Image New Size Value : w:%d\n", nX);

        bRes = false;
    }

    if (nY != 0)
    {
        nY = (int(_height / nDivCount) + 1) * nDivCount;

        printf("Image New Size Value : h:%d\n", nY);

        bRes = false;
    }

    return bRes;
}
[/code]

'Native > C++' 카테고리의 다른 글

pcre  (0) 2013.10.02
Visual C++ 2005 map<string, string> problem  (0) 2013.10.02
library 만들기  (0) 2013.10.02
error msg  (0) 2013.10.02
mutable  (0) 2013.10.02