libjpeg库的简单使用使用----jpeg图片解压

libjpeg库其实已经可以满足我们日常处理日常简单图片之间的转换了。下面就来介绍一下jpeg库的解压和压缩过程。

首先来讲解压操作过程:

1、分配jpeg对象结构体空间,并初始化。

2、指定解压数据源。

3、获取解压文件信息。

4、为解压设定参数,包括图像大小和颜色空间。

5、开始解压缩。

6、取数据。

7、解压完毕。

8、释放资源和退出程序。


1、分配jpeg对象结构体空间、并初始化。

        解压缩过程中使用的JPEG对象是一个jpeg_decompress_struct的结构体。同时还需要定义一个用于错误处理的结构体对象,IJG中标准的错误结构体是jpeg_error_mgr。

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
        绑定jerr错误结构体至jpeg对象结构体。

    cinfo.err = jpeg_std_error(&jerr);

        这个标准的错误处理结构将使程序在出现错误时调用exit()退出程序,如果不希望使用标准的错误处理方式,则可以通过自定义退出函数的方法自定义错误处理结构。

        初始化cinfo结构体。

 jpeg_create_decompress(&cinfo);

2、指定解压数据源。

        利用标准C库的文件指针打开相关jpg文件。

     FILE * infile;
     if ((infile = fopen("test.jpg", "rb")) == NULL)
     {
          perror("fopen fail");
          return 0;
     }
     jpeg_stdio_src(&cinfo, infile);

3、获取解压文件信息。

        将图像的缺省信息填充到cinfo结构中以便程序使用。

    (void) jpeg_read_header(&cinfo, TRUE);
        此时,常见的可用信息包括图像的宽cinfo.image_width,高cinfo.image_height,色彩空间cinfo.jpeg_color_space,颜色通道数cinfo.num_components等。

4、为解压设定参数,包括图像大小和颜色空间。

        比如可以设定解出来的图像的大小,也就是与原图的比例。使用scale_num和scale_denom两个参数,解出来的图像大小就是scale_num/scale_denom,但是IJG当前仅支持1/1, 1/2, 1/4,和1/8这几种缩小比例。

        比如要取得1/2原图的图像,需要如下设定:

    cinfo.scale_num=1;
    cinfo.scale_denom=2;

也可以设定输出图像的色彩空间,即cinfo.out_color_space,可以把一个原本彩色的图像由真彩色JCS_RGB变为灰度JCS_GRAYSCALE。如:    

cinfo.out_color_space=JCS_GRAYSCALE;

5、开始解压缩。 

根据设定的解压缩参数进行图像解压缩操作。

(void) jpeg_start_decompress(&cinfo);
        在完成解压缩操作后,会将解压后的图像信息填充至cinfo结构中。比如,输出图像宽度cinfo.output_width,输出图像高度cinfo.output_height,每个像素中的颜色通道数cinfo.output_components(比如灰度为1,全彩色为3)等。

一般情况下,这些参数是在jpeg_start_decompress后才被填充到cinfo中的,如果希望在调用jpeg_start_decompress之前就获得这些参数,可以通过调用jpeg_calc_output_dimensions()的方法来实现。
    

6、取数据。

解开的数据是按照行取出的,数据像素按照scanline来存储,scanline是从左到右,从上到下的顺序,每个像素对应的各颜色或灰度通道数据是依次存储,比如一个24-bit RGB真彩色的图像中,一个scanline中的数据存储模式是R,G,B,R,G,B,R,G,B,...,每条scanline是一个JSAMPLE类型的数组,一般来说就是unsigned char,定义于jmorecfg.h中。除了JSAMPLE,图像还定义了JSAMPROW和JSAMPARRAY,分别表示一行JSAMPLE和一个2D的JSAMPLE数组。

        在此,我定义一个JSAMPARRAY类型的缓冲区变量来存放图像数据。

    JSAMPARRAY buffer;
        然后是计算每行需要的空间大小,比如RGB图像就是宽度×3,灰度图就是宽度×1
    row_stride = cinfo.output_width * cinfo.output_components;

为缓冲区分配空间,这里使用了libjpeg的内存管理器来完成分配。

JPOOL_IMAGE表示分配的内存空间将在调用jpeg_finish_compress,jpeg_finish_decompress,jpeg_abort后被释放,而如果此参数改为JPOOL_PERMANENT则表示内存将一直到JPEG对象被销毁时才被释放。

row_stride如上所说,是每行数据的实际大小。

最后一个参数是要分配多少行数据。此处只分配了一行。

buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
        output_scanline表示当前已经读取的行数,如此即可依次读出图像的所有数据,并填充到缓冲区中,参数1表示的是每次读取的行数。

    while(cinfo.output_scanline < cinfo.output_height)
    {
        (void) jpeg_read_scanlines(&cinfo, buffer, 1);
         //do something
    }


7、解压完毕。

    (void) jpeg_finish_decompress(&cinfo);

8、释放资源和退出程序。
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
如果不再需要JPEG对象,则使用
    jpeg_destroy_decompress(&cinfo);
或
    jpeg_destroy(&cinfo);
而如果还希望继续使用JPEG对象,则可使用

    jpeg_abort_decompress(&cinfo);
或
    jpeg_abort(&cinfo);
完整例程:

//变量定义
     struct jpeg_decompress_struct cinfo;
     struct jpeg_error_mgr jerr;
     FILE * infile;
     JSAMPARRAY buffer;
     int row_stride;        

     //绑定标准错误处理结构
     cinfo.err = jpeg_std_error(&jerr);  

     //初始化JPEG对象
     jpeg_create_decompress(&cinfo);

     //指定图像文件
     if ((infile = fopen("sample.jpg", "rb")) == NULL)
     {
           perror("fopen fail");
           return;
     }
     jpeg_stdio_src(&cinfo, infile);

     //读取图像信息
     (void) jpeg_read_header(&cinfo, TRUE);

     //设定解压缩参数,此处我们将图像长宽缩小为原图的1/2
     cinfo.scale_num=1;
     cinfo.scale_denom=2;

     //开始解压缩图像
     (void) jpeg_start_decompress(&cinfo);

     //本程序功能是应用GDI+在客户区绘制图像
     CClientDC dc(this);
     Bitmap bm( cinfo.output_width , cinfo.output_height); 
     Graphics graphics(dc.GetSafeHdc());
     Graphics gdc(&bm);

     //分配缓冲区空间
     row_stride = cinfo.output_width * cinfo.output_components;
     buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

     //读取数据
     while (cinfo.output_scanline < cinfo.output_height)
     {
         (void) jpeg_read_scanlines(&cinfo, buffer, 1);
         //output_scanline是从1开始,所以需要减1
         int line=cinfo.output_scanline-1;
         for(int i=0;i<cinfo.output_width;i++)
         {
              //绘制位图,本例中假设读取的sample.jpg图像为RGB真彩色图像
              //因此,实际上cinfo.output_components就等于3,灰度图则需另作处理
              bm.SetPixel(i,line,Color(255,(BYTE)buffer[0][i*3],(BYTE)buffer[0][i*3+1],(BYTE)buffer[0][i*3+2]));
         }
     }
     //结束解压缩操作
     (void) jpeg_finish_decompress(&cinfo);

     //释放资源
     jpeg_destroy_decompress(&cinfo);
     fclose(infile);

     //在客户区绘制位图
     graphics.DrawImage(&bm,0,0);

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libjpeg是一种用C语言编写的 JPEG 图像压缩与解压,它提供了一些函数用于压缩和解压JPEG 图像。在使用 libjpeg 之前,需要先安装 libjpeg 。 安装方法: 在 Linux 中,可以使用以下命令安装 libjpeg : sudo apt-get install libjpeg-dev 在 Windows 中,可以从官网下载 libjpeg 并进行安装。 使用方法: 1. 引入头文件 在需要使用 libjpeg 的源文件中,需要包含以下头文件: #include <stdio.h> #include <stdlib.h> #include <jpeglib.h> 2. 定义结构体 使用 libjpeg 时需要定义一些结构体,例如: struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; 3. 初始化压缩器或解压器 在使用压缩或解压功能之前,需要分别初始化压缩器或解压器,例如: // 初始化压缩器 jpeg_create_compress(&cinfo); // 初始化解压jpeg_create_decompress(&cinfo); 4. 设置参数 在使用压缩或解压功能之前,需要设置一些参数,例如: // 设置压缩图像的宽度和高度 cinfo.image_width = width; cinfo.image_height = height; // 设置颜色空间 cinfo.in_color_space = JCS_RGB; // 设置压缩品质 jpeg_set_quality(&cinfo, quality, TRUE); 5. 执行压缩或解压 设置完参数之后,可以执行压缩或解压操作,例如: // 执行压缩 jpeg_start_compress(&cinfo, TRUE); jpeg_write_scanlines(&cinfo, buffer, height); jpeg_finish_compress(&cinfo); // 执行解压 jpeg_start_decompress(&cinfo); jpeg_read_scanlines(&cinfo, buffer, height); jpeg_finish_decompress(&cinfo); 6. 销毁结构体 使用完压缩或解压功能后,需要销毁相应的结构体,例如: // 销毁压缩器 jpeg_destroy_compress(&cinfo); // 销毁解压jpeg_destroy_decompress(&cinfo); 以上是 libjpeg 的基本使用方法,具体可以参考官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值