IT笔记 · 2013年12月14日

libjpeg 的一个使用例子

看着libjpeg的文档说明,写了个例子,备忘。

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

class Sbuffer
{
public:
    Sbuffer();
    ~Sbuffer();
    bool SetSize(int size);
    inline unsigned char* GetBuffer(){ return buffer_; }
private:
    int size_;
    unsigned char* buffer_;
};

Sbuffer::Sbuffer():size_(0), buffer_(NULL){}
Sbuffer::~Sbuffer()
{
    if(buffer_){
        delete[] buffer_;
        buffer_ = NULL;
        size_ = 0;
    }
}
bool Sbuffer::SetSize(int size)
{
    if(size > size_){
        if(buffer_){
            delete[] buffer_;
            buffer_ = NULL;
        }
        size_ = 0;
        buffer_ = new unsigned char[size];
        if(NULL == buffer_){
            TRACE("Sbuffer::SetSize new failed");
            return false;
        }
        size_ = size;
        return true;
    }
    return true;
}

static int reduce_jpeg(const char* filename)
{
    int image_new_width = 0;
    int image_new_height = 0;
    int image_new_components = 0;
    J_COLOR_SPACE image_new_colorspace = JCS_UNKNOWN;

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    FILE* infile;

    if((infile = fopen(filename, "rb")) == NULL) {
        return -1;
    }

    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, infile);
    //get jpeg info
    jpeg_read_header(&cinfo, TRUE);

    //set parameters
    cinfo.scale_num = 1;
    cinfo.scale_denom = 2;//reduce image 1/2

    jpeg_start_decompress(&cinfo);

    //restore
    image_new_width = cinfo.output_width;
    image_new_height = cinfo.output_height;
    image_new_components = cinfo.output_components;
    image_new_colorspace = cinfo.out_color_space;

    int buffer_len = cinfo.output_width * cinfo.output_components * cinfo.output_height;

    static Sbuffer s_buffer;
    s_buffer.SetSize(buffer_len * sizeof(JSAMPLE));
    JSAMPLE* image_buffer = static_cast<JSAMPLE*>(s_buffer.GetBuffer());
    if(NULL == image_buffer){
        fclose(infile);
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        return -1;
    }
    memset(image_buffer, 0, buffer_len*sizeof(JSAMPLE));

    int row_stride = cinfo.output_width * cinfo.output_components;
    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
    JSAMPLE* image_buffer_cur_pos = image_buffer; 
    while(cinfo.output_scanline < cinfo.output_height){
        jpeg_read_scanlines(&cinfo, buffer , 1);
        memcpy((void*)image_buffer_cur_pos, (const void*)buffer[0], row_stride*sizeof(JSAMPLE) );
        image_buffer_cur_pos += row_stride;
    }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);


    ///////////////////////////////////////////
    //save
    struct jpeg_compress_struct cinfo_save;
    struct jpeg_error_mgr jerr_save;
    cinfo_save.err = jpeg_std_error(&jerr_save);

    FILE* outfile = fopen(filename, "wb");
    if(NULL == outfile){
        return -1;          
    }
    jpeg_create_compress(&cinfo_save);
    jpeg_stdio_dest(&cinfo_save, outfile);
    cinfo_save.image_width = image_new_width;
    cinfo_save.image_height = image_new_height;
    cinfo_save.input_components = image_new_components;
    cinfo_save.in_color_space = image_new_colorspace;

    jpeg_set_defaults(&cinfo_save);
    jpeg_set_quality(&cinfo_save, 80, true);

    jpeg_start_compress(&cinfo_save, TRUE);

    JSAMPROW row_pointer[1];
    row_stride = cinfo_save.image_width * cinfo_save.input_components;  
    while(cinfo_save.next_scanline < cinfo_save.image_height){
        row_pointer[0] = &image_buffer[ cinfo_save.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo_save, row_pointer, 1);

    }

    jpeg_finish_compress(&cinfo_save);
    jpeg_destroy_compress(&cinfo_save);
    fclose(outfile);
    image_buffer = NULL;
    return 1;
}