使用IJG JPEG库

来源:互联网 发布:java测试工程师 编辑:程序博客网 时间:2024/05/01 20:48

此文件描述如何在应用程序中使用IJG JPEG库。 如果你想编写一个使用该库的程序,请阅读它。

文件example.c提供了大量注释的框架代码来调用JPEG库。 另请参阅jpeglib.h(应用程序使用的include文件程序),以获取有关数据结构和函数参数列表的完整详细信息。当然库的源代码是最终的参考。

在尝试使用库进行编程之前,应至少阅读概述和基本用法部分。 有关高级功能的部分如果当你需要他们的时候可以查阅。

概述

        IJG JPEG库提供C函数来读、写JPEG压缩格式的图像文件。使用JPEG库的应用程序是以"scanline"为单位进行图象处理的。

        在JPEG处理中,图像质量与处理速度之间会有折衷。在解压缩处理中更是如此, 解压缩库提供了多种折衷实现,范围从非常高质量到快速预览操作。 在压缩方面,我们通常不提供低质量的选择,因为通常情况下压缩对时间要求不是很严格。 而且,低质量模式可能不满足JPEG标准的准确度要求;

JPEG压缩操作的粗略概述是:

Allocate and initialize a JPEG compression object                                        //分配和初始化compression结构
Specify the destination for the compressed data (eg, a file)                         //指定压缩后的数据存放的文件
Set parameters for compression, including image size & colorspace         //设置压缩参数,包括图像size和colorspace
jpeg_start_compress(...);                                                                              //启动压缩
while (scan lines remain to be written)                                                          //循环调用jpeg_write_scanlines(...),把将要压缩的图像数据从内存缓冲区中写入指定的文件
        jpeg_write_scanlines(...);
jpeg_finish_compress(...);                                                                             //压缩完成
Release the JPEG compression object                                                        //释放compression结构

        compression结构里保存有压缩参数和工作状态。我们使它的创建/销毁与图像的开始或结束压缩操作分开; 它可以被重复用于一系列图像压缩操作。 这使得对于具有相同压缩参数的图像序列设置变得更加容易。

类似地,JPEG解压缩操作的粗略概述是:

Allocate and initialize a JPEG decompression object                                  // 分配和初始化一个decompression结构
Specify the source of the compressed data (eg, a file)                               // 指定要解压缩的jpg文件
Call jpeg_read_header() to obtain image info                                              // 用jpeg_read_header获得jpg信息
Set parameters for decompression                                                             // 设置解压参数,比如放大、缩小
jpeg_start_decompress(...);                                                                         // 启动解压:jpeg_start_decompress
while (scan lines remain to be read)
        jpeg_read_scanlines(...);                                                                      // 循环调用jpeg_read_scanlines,把jpg文件解压缩后的数据读取到内存缓冲区中

jpeg_finish_decompress(...);                                                                       //解压完成
Release the JPEG decompression object                                                  // 释放decompression结构

       这与压缩概述相似,只是多了获得jpg信息这一步。这是有帮助的,因为当应用程序选择解压缩参数时,有关图像大小,颜色空间等的信息可能会用到。例如,应用程序
可以利用这些信息选择适合于屏幕大小的图像输出缩放比。

基本用法:

在介绍程序细节之前,有必要先了解一下JPEG库的图像数据格式。

 图像是像素的矩形阵列,每个像素具有相同数量的component。大多数应用程序将使用RGB数据(每个像素的component数为3)或灰度数据(每个像素的component数为1)。

像素的值都存放在scanlines中,从左到右依次摆放。 例如用于24位RGB颜色的R,G,B,R,G,B,R,G,B,...。 scanline是一个数据类型为JSAMPLE ---的数组,通常是“unsigned char”型的。也就是说scanlines存放的是整个图像的像素值数据,而一个scanline存放的是图像的一行数据。

压缩详细介绍:

1.分配和初始化compression结构。

       compression结构的类型为struct jpeg_compress_struct

        您还需要定义一个JPEG错误处理程序的结构,即“struct jpeg_error_mgr”(错误处理程序将会打印JPEG错误/警告消息,如果发生致命错误,它将调用exit()退出)。然后调用jpeg_std_error(),将其存储到compression结构的“err”字段中,最后调用jpeg_create_compress()来初始化compression结构的其余部分。

此步骤的代码:

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

jpeg_create_compress会分配少量内存,因此如果内存不足,它可能会失败。在这种情况下,它将通过错误处理程序退出; 这就是为什么必须首先初始化错误处理程序。

2.指定压缩后数据存放的文件

此步骤的代码:

    FILE * outfile;
    ...
    if ((outfile = fopen(filename, "wb")) == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        exit(1);
    }
    jpeg_stdio_dest(&cinfo, outfile);

警告:将二进制压缩数据不更改地传送到输出文件至关重要。 在非Unix系统上,stdio库可能执行换行或其他方式损坏二进制数据。 要抑制此行为,您可能需要使用“b”选项来fopen(如上所示)。

您也可以在步骤3设置其他参数时选择数据目的地。 但是您不能在调用jpeg_start_compress()和jpeg_finish_compress()之间更改目的地。

3.设置压缩参数,包括图像大小和色彩空间。

您必须通过在cinfo结构中设置以下字段来提供有关源图像的信息:

    image_width              //图像宽度,以像素为单位
    image_height             //图像高度,以像素为单位
    input_components    // 每个像素的component数
    in_color_space         //源图像的颜色空间,通常是RGB或灰度

in_color_space字段必须分配一个J_COLOR_SPACE枚举常量,通常为JCS_RGB或JCS_GRAYSCALE。

JPEG还具有大量的压缩参数,决定图像的编码方式。 大多数应用程序不需要知道所有的这些参数。 可以通过调用jpeg_set_defaults()将所有参数设置为合理的默认值;

24位RGB源图像的典型代码是:

    cinfo.image_width = Width;   
    cinfo.image_height = Height;
    cinfo.input_components = 3;  
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);

4.  开始压缩

在指定数据目的地并设置所有必需的源图像信息和其他参数后,调用jpeg_start_compress()开始压缩。

代码如下:

jpeg_start_compress(&cinfo, TRUE);

“TRUE”参数确保将写入完整的JPEG交换数据流。一旦你调用了jpeg_start_compress(),你不能改变任何JPEG参数或cinfo结构体字段,直到完成压缩循环。

5.把压缩的图像数据从内存缓冲区中写入指定的文件

现在可以通过调用jpeg_write_scanlines()一次或多次写入所有需要的图像数据。在大多数应用中,一次只传递一个scanline是方便的。

图像数据应以从上到下的scanline顺序写入。

cinfo结构体的next_scanline字段表示到目前为止写入的scanline数量。 通常你可以使用这个变量作为循环计数器,所以循环代码可以这么写,“while(cinfo.next_scanline <cinfo.image_height)”。

源图像是3字节RGB像素情况下的代码:

    JSAMPROW row_pointer[1];      //该数组用于指向源图像每一行数据的首地址
    int row_stride;          

    row_stride = image_width * 3;    //源图像一行的字节数

    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);    //第三个参数1表示每次写入一行的数据
    }

jpeg_write_scanlines()返回实际写入的scanline数。 这通常等于传入的数字,因此可以忽略返回值。

6.压缩完成

在所有图像数据已经写入之后,调用jpeg_finish_compress()来完成压缩循环。 此步骤是必要的,以表示已将最后一个数据缓冲区写入数据目标。jpeg_finish_compress()也释放相关联的工作内存。

代码如下:

    jpeg_finish_compress(&cinfo);

完成压缩循环后,您可以按照下面讨论的方式处理cinfo结构体,也可以使用它压缩另一个图像。 这时,根据不同的情况返回步骤2,3或4。 如果不更改指定文件,新的数据流将写入同一文件。 如果不更改任何JPEG参数,新数据流将使用与之前相同的参数写入。

7.释放cinfo结构。

当你使用完一个cinfo结构,通过调用jpeg_destroy_compress()来销毁它。 这将释放它占有的所有内存。 或者你可以调用jpeg_destroy(),该函数适用于压缩或解压缩结构

代码如下:

    jpeg_destroy_compress(&cinfo);

解压缩详细介绍:

1.分配和初始化decompression结构。

该步骤代码:

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

2.指定要解压缩的jpg文件

此步骤的典型代码如下:
    FILE * infile;
    ...
    if ((infile = fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        exit(1);
    }
    jpeg_stdio_src(&cinfo, infile);

3.调用jpeg_read_header()获取jpg图像信息

代码如下:

    jpeg_read_header(&cinfo, TRUE);

这将读取jpg文件头部信息,文件头部包含图像尺寸和其他信息。 返回时,这些信息会存储在cinfo结构中。 应用程序在选择解压缩参数之前可能会用到此信息。

如果您只想查找jpg文件的图像尺寸和其他信息,完成这步后可以调用jpeg_destroy(),然后选择新数据源并读取它的头部信息。

4.设置解压缩参数

注意,每次调用jpeg_read_header()都会设置所有默认值。如果默认值满足要求,可以跳过这一步。如果您希望在开始解压缩之前更改这些默认值,如 图像缩放比或者选择各种速度/质量权衡,在“解压缩参数选择”一节给出了详细说明。

5.开始解压

参数设置好后,调用jpeg_start_decompress()开始解压缩。 这将初始化内部状态,分配工作内存,并准备返回数据。

代码如下:
    jpeg_start_decompress(&cinfo);

在调用之后,解压输出的图像信息会存放在cinfo结构相应的字段中;有用的字段包括:

    output_width       
    output_height
    out_color_components   
    output_components            //输出的每个像素占的字节数
    colormap      
    actual_number_of_colors       
通常,您将需要分配数据缓冲区来保存解压缩的图像数据。 您需要为每个scanline分配的字节数为:output_width * output_components。解压缩的图像数据包含output_height个scanline。

6.把jpg文件解压缩后的数据读取到内存缓冲区中

现在,您可以通过调用jpeg_read_scanlines()一次或多次读取解压缩的图像数据。 在每次调用时,传入要读取的最大scanline数; 返回值是实际读取的行数。
在cinfo结构的output_scanline字段中保持到目前为止返回的scanline的数量。 通常你可以使用这个变量作为循环计数器,所以循环测试可以这样写
“while(cinfo.output_scanline <cinfo.output_height)”。

7.解压完成

在读取所有图像数据之后,调用jpeg_finish_decompress()来完成解压缩循环,释放工作内存。

代码如下:

    jpeg_finish_decompress(&cinfo);

8.释放cinfo结构

当你使用完一个解压缩结构,通过调用jpeg_destroy_decompress()或jpeg_destroy()销毁它。

代码如下:
    jpeg_destroy_decompress(&cinfo);

写代码时可以参阅example.c文件。


2 0
原创粉丝点击