使用libjpeg-turbo库中兼容的libjpeg库解压一张jpg并缩放压缩保存到文件

概述:之前,安装了libjpeg-turbo库,它是兼容libjpeg库中的v8版本的。现在,先使用libjpeg库完成一张jpg图片的解压,缩放,压缩。之后再用libjpeg-turbo库实现相同功能,我们再对比它们的压缩速度。确定是不是turbo比libjpeg要快。今天,就是先一个libjpeg的使用demo了。

/**************分割线**********************/
这篇博客是我之前写的,现在发现了比较严重的错误,这里重新编辑一下把这个错误纠正一下,原博客内容不修改,我就是把他指出来,希望大家别和我犯相同错误。

1,我文章题目错误,我们只要安装了libjpeg-turbo库,那么其中兼容的只不过是libjpeg的API,其实它的本质已经是基于simd的了,我们只是上层代码看起来和用libjpeg库的代码相同(因为API相同),底层实现已经不同了。

2,在我的概述中,说libjpeg和turbo是错误的,至于为何会误解,是这样的原因:libjpeg-turbo库的API兼容libjpeg库的,我就误认为libjpeg-turbo就是包含了libjpeg库,因为libjoeg-turbo还有一个TruboJPEG API.我以为TruboJPEG是基于simd实现的,真正的turbo是TruboJPEG。后来看了官方的一个解释说明文档,才发现此问题,原来他们都是基于simd的,只不过libjpeg API是更底层更灵活的实现,TurboJPEG是基于libjpeg API更高一层的封装,本质还是libjpeg API。所以他们其实并没有本质的不同。所以他们的性能方面也是没有太大区别的。后面我还是要直接装一个libjpeg库和libjpeg-turbo库对比一下速度,同时我也会写一个TurboJPEG实现相同的功能的例子。

下面是官方的解释
使用libjpeg-turbo库中兼容的libjpeg库解压一张jpg并缩放压缩保存到文件_第1张图片

/*****************************************************/

1,废话不多说,直接代码,注释代码上都有(注意,gcc编译时,记得加上-ljpeg)。

#include 
#include 
#include 
#include 
#include 

typedef struct outfile_info {
  int outwidth;
  int outheight;
}outfile_info_t;

struct my_error_mgr {
    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr *my_error_ptr;

/*获取当前ms*/
static int get_timer_now ()
{
    struct timeval now;
    gettimeofday(&now, NULL);
    return(now.tv_sec * 1000 + now.tv_usec / 1000);
}

void my_error_exit (j_common_ptr cinfo)
{
    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
    my_error_ptr myerr = (my_error_ptr) cinfo->err;
    /* Always display the message. */
    /* We could postpone this until after returning, if we chose. */
    (*cinfo->err->output_message) (cinfo);
    /* Return control to the setjmp point */
    longjmp(myerr->setjmp_buffer, 1);
}

/*读取jpg文件并解压*/
unsigned char *read_jpeg_file(char *filename, outfile_info_t *info)
{
    struct jpeg_decompress_struct cinfo;
    struct my_error_mgr jerr;

    FILE *infile;
    JSAMPARRAY buffer;
    int row_stride;

    if (NULL == (infile = fopen(filename, "rb"))) {
        printf("can't open %s\n",filename);
        return NULL;
    }

    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);
        return NULL;
    }
    /*初始化*/
    jpeg_create_decompress(&cinfo);
    /*指定输入文件*/
    jpeg_stdio_src(&cinfo, infile);
    /*读取文件信息*/
    jpeg_read_header(&cinfo, TRUE);

  /*这里是设置缩放比列,这里设置1/4 表示原图1920*1080会缩放到480*270,若不设置则按原图大小尺寸*/
    cinfo.scale_num  = 1;
    cinfo.scale_denom = 4;
  /*解压*/
    jpeg_start_decompress(&cinfo);
    row_stride = cinfo.output_height * cinfo.output_width * cinfo.output_components;
    /*输出图像信息*/
    printf("output_width = %d\n", cinfo.output_width);
    printf("output_height = %d\n", cinfo.output_height);
    printf("output_components = %d\n", cinfo.output_components);
  info->outwidth = cinfo.output_width;
  info->outheight = cinfo.output_height;
  /*申请内存用于存储解压数据*/
    unsigned char *data = (unsigned char *)malloc(sizeof(unsigned char) * row_stride);
  /*逐行扫描获取解压信息*/
    JSAMPROW row_pointer[1];
    while (cinfo.output_scanline < cinfo.output_height) {
        row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.output_width*cinfo.output_components];
        jpeg_read_scanlines(&cinfo,row_pointer ,1);
    }
    /*完成解压*/
    jpeg_finish_decompress(&cinfo);
    /*销毁解压cinfo信息*/
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return data;
}

/*压缩图像并写入文件*/
int write_jpeg_file (char * filename, unsigned char* image_buffer, int quality,int image_height, int image_width)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE * outfile;
    JSAMPROW row_pointer[1];
    int row_stride;
    cinfo.err = jpeg_std_error(&jerr);
  /*压缩初始化*/
    jpeg_create_compress(&cinfo);
  /*创建并打开输出的图片文件*/
    if ((outfile = fopen(filename, "wb")) == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        return -1;
    }
    jpeg_stdio_dest(&cinfo, outfile);

  /*设置压缩各项图片参数*/
    cinfo.image_width = image_width;
    cinfo.image_height = image_height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);
  /*设置压缩质量*/
    jpeg_set_quality(&cinfo, quality, TRUE );
  /*开始压缩*/
    jpeg_start_compress(&cinfo, TRUE);
  /*逐行扫描压缩写入文件*/
    row_stride = image_width * 3;
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = & image_buffer[(cinfo.image_height-cinfo.next_scanline) * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }
  /*完成压缩*/
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
  fclose(outfile);
  /*释放存储的解压图像内容*/
  if (NULL != image_buffer) {
    free(image_buffer);
    image_buffer = NULL;
  }
    return 0;
}

void jp_test()
{
    char *file = "./test.jpg";
    int start = get_timer_now();
  outfile_info_t info;
    unsigned char *img_buffer = read_jpeg_file(file, &info);
    int end = get_timer_now();
    printf("read jpeg make time:%dms\n",end-start);
    if (NULL == img_buffer) {
        printf("read error\n");
        return;
    }
    printf("read success\n");
    int writestart = get_timer_now();
    char *outfile = "./outtest.jpg";
    if (0 != write_jpeg_file(outfile,img_buffer,80,info.outheight,info.outwidth)) {
        printf("write error\n");
        free(img_buffer);
       return;
    }
    int writeend = get_timer_now();
    printf("write make time:%dms\n",writeend-writestart);
}

int main()
{
  jp_test();
  return 0;
}

2,准备一张test.jpg图片,我的原图是1920*1080p执行程序。打印消息如下:
使用libjpeg-turbo库中兼容的libjpeg库解压一张jpg并缩放压缩保存到文件_第2张图片

同时还会在当前目录生成一个outtest.jpg图片。我们可以看到这张图片尺寸为原图片的1/4,480*270p。

这个demo就到这里了,Peace&Love!

你可能感兴趣的:(jpeg-turbo)