1. 实验目的
(1)编译JPEG-8C参考软件。
(2)学会使用JPEG-8C提供的可执行文件进行简单的JPEG解压缩。
(3)在Microsoft Visual C++ 6.0环境下进行读写JPEG格式文件实验,了解并熟悉基本的JPEG文件解压缩和压缩处理方式。
2. 实验环境
(1)Windows XP OS
(2)IJG参考软件JPEG-8C
(3)Microsoft Visual C++ 6.0
3. 实验步骤
Ⅰ 下载及编译JPEG-8C参考软件
(1)下载JPEG-8C
登录IJG官方网站http://www.ijg.org/,根据网站提示下载Windows压缩格式的源代码包jpegsr8c.zip,这个版本是目前的最新版本。下载到硬盘上解压,将会在安装目录下出现文件夹jpeg-8c,里面包含了jpeg的源代码、说明使用文档以及一些测试图片。
(2)编译JPEG-8C参考软件
IJG支持多平台下的应用,不同平台下的编译安装细节都可以在install.txt中找到。在此,我以Microsoft Visual C++ 6.0作为平台进行编译。
① 开始编译前首先需要将jconfig.vc更名为jconfig.h 。
② 开始—运行—键入cmd,进入命令行模式。在命令行下进入到Microsoft Visual C++ 6.0的安装目录下的bin文件夹,在其目录下有一个名为vcvars32.bat的批处理文件,在命令行下运行这个批处理(键入vcvars32.bat,回车),这个批处理的作用是注册VC6.0相关的一些环境变量,这样在任何系统目录下都可以使用VC6.0提供的工具。然后不要关闭当前命令窗口,进入到IJG的安装目录./jpeg-8c下,执行命令NMAKE /f makefile.vc。也就是开始编译IJG库,在屏幕迅速闪过一些编译信息后,如果没有错误出现,IJG也就编译完成。编译完成后,IJG的安装目录下会出现若干文件,我们所需要的是一个叫做libjpeg.lib的静态库文件,在编译我们程序的时候链接使用。除此一般还要用到4个头文件,jconfig.h、jerror.h、jmorecfg.h、jpeglib.h。当然,目录下还会有一些可执行文件,是IJG提供的工具程序,稍后进行介绍。
(3)开发环境配置
在VC6.0下使用IJG之前首先要让VC能够找到那四个头文件并链接到libjpeg.lib的静态库文件,我们对开发环境做一下配置,如下:
① 进入VC6.0 — 工具 — 选项 — 目录 — include files下添加jpeg-8c的路径 — Library files下添加 jpeg-8c的路径
② Project — Add to Project — Files,添加libjpeg.lib到工程中去。
至此,配置步骤完成,于是就可以开始用IJG写程序了。
Ⅱ 使用参考软件提供的可执行文件进行JPEG解压缩
在jpeg-8c编译成功后,会生成5个可执行文件:cjpeg.exe、djpeg.exe、jpegtran.exe、 rdjpgcom.exe、wrjpgcom.exe。其中我们可以使用cjpeg.exe和djpeg.exe进行比较简单的JPEG解压缩操作。
① cjpeg.exe的简单使用
cjpeg [选项] 图像文件 jpg图像文件
通过该命令可以将图像文件压缩为jpg格式的图像,目前支持的图像文件格式有:PPM (PBMPLUS color format),PGM (PBMPLUS gray-scale format),BMP,GIF,and RLE (Utah Raster Toolkit format)。
我们可以通过选项-quality N(0~100)来设置压缩比率,如:cjpeg –quality 50 testimg.bmp testimg.jpg ,即以压缩率50%将testimg.bmp压缩为testimg.jpg 。
该命令的使用仍是在命令行模式下进入jpeg-8c目录下,键入命令实现。
② djpeg.exe的简单使用
djpeg [选项] jpg图像文件 jpg图像文件
通过该命令可以将jpg图像文件解压为所支持的图像格式。我们要通过选项来设定解压的格式,也可以使用-colors N(8以上)设定使用色彩的个数。
如:djpeg –bmp –colors 256 testimg.jpg testimg.bmp,即将testimg.jpg解压为testimg.bmp,每个色彩通道使用256个色彩值。
Ⅲ 读写JPEG格式文件
(1)JPEG图像的解压缩操作
解压缩操作过程如下:
①为JPEG对象分配空间并初始化
②指定解压缩数据源
③获取文件信息
④为解压缩设定参数,包括图像大小,颜色空间
⑤开始解压缩
⑥取出数据
⑦解压缩完毕
⑧释放资源
我们定义了一个函数read_JPEG_file (char * filename)实现解压缩操作,其形参是jpg格式的图像文件名(字符串),如果成功解压,函数将会返回值1,否则为0。源代码如下:
int read_JPEG_file (char * filename)
{ //定义解压缩过程中使用的JPEG结构体对象cinfo
struct jpeg_decompress_struct cinfo;
//定义一个用于错误处理的结构体对象jerr
struct jpeg_error_mgr jerr;
FILE * infile; //源文件
JSAMPLE * p; //临时指针
int i; //循环变量
JSAMPARRAY buffer;//JSAMPARRAY==2D的JSAMPLE数组
int row_stride; //图像每行的JSAMPLE数
//打开jpg源文件
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
//第一步:为JPEG对象分配空间并初始化
//将错误处理结构对象绑定在JPEG对象上
cinfo.err = jpeg_std_error(&jerr);
//初始化cinfo结构
jpeg_create_decompress(&cinfo);
//第二步:指定解压缩数据源
jpeg_stdio_src(&cinfo, infile);
//第三步:获取文件信息
(void) jpeg_read_header(&cinfo, TRUE);
//第四步:为解压缩设定参数
/* 没有特殊需要,不作任何设定 */
//第五步:开始解压缩
(void) jpeg_start_decompress(&cinfo);
//保存图像的尺寸
image_height = cinfo.output_height;
image_width = cinfo.output_width;
//输出缓存中每行的JSAMPLE数
row_stride = cinfo.output_width * cinfo.output_components;
//为缓冲区分配空间
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
image_buffer = (JSAMPLE *) malloc(row_stride*cinfo.output_height);
p=image_buffer; //记录image_buffer的首地址
//第六步:取出数据
while (cinfo.output_scanline < cinfo.output_height) {
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
for(i=0;i
p += row_stride;
}
//第七步:完成压缩
(void) jpeg_finish_decompress(&cinfo);
//第八步:释放JPEG解压缩对象
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 1;
}
(2)JPEG图像的压缩操作
压缩操作过程如下:
① 为JPEG对象分配空间并初始化
② 指定图像输出目标
③ 为压缩设定参数,包括图像大小,颜色空间
④ 开始压缩
⑤ 写入数据
⑥ 压缩完毕
⑦ 释放资源
我们定义了一个函数write_JPEG_file (char * filename, int quality)实现压缩操作,形参是目标文件名(字符串)和压缩率(0~100)。如果压缩成功,函数将会返回1值,否则,为0。源代码如下:
int write_JPEG_file (char * filename, int quality)
{
//定义压缩过程中使用的JPEG结构体对象
struct jpeg_compress_struct cinfo;
//将错误处理结构对象绑定在JPEG对象上
struct jpeg_error_mgr jerr;
FILE * outfile; //目标文件
JSAMPROW row_pointer[1]; //JSAMPROW == 1D的JSAMPLE数组
int row_stride;
//第一步:为JPEG对象分配空间并初始化
//将错误处理结构对象绑定在JPEG对象上
cinfo.err = jpeg_std_error(&jerr);
//初始化cinfo结构
jpeg_create_compress(&cinfo);
//第二步:指定压缩数据的输出目标
if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
jpeg_stdio_dest(&cinfo, outfile);
//第三步:为压缩设定参数
cinfo.image_width = image_width;
cinfo.image_height = image_height;
cinfo.input_components = 3; // 彩色图像设置为3,灰度图像设置为1
cinfo.in_color_space = JCS_RGB; //真彩色JCS_RGB,灰度图JCS_GRAYSCALE
//设定缺省设置
jpeg_set_defaults(&cinfo);
//设置压缩比quality
jpeg_set_quality(&cinfo, quality, TRUE);
//第四步:开始压缩
jpeg_start_compress(&cinfo, TRUE);
//第五步:写入数据
row_stride = image_width * 3;//彩色图像设置为3,灰度图像设置为1
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
//第六步:完成压缩
jpeg_finish_compress(&cinfo);
fclose(outfile);
//第七步:释放JPEG压缩对象
jpeg_destroy_compress(&cinfo);
return 1;
}
(3) 应用上述函数进行解压缩操作
源代码如下:
#include
#include
extern "C" {
#include "jpeglib.h"
}
JSAMPLE * image_buffer;//JSAMPLE==unsigned char
int image_height;
int image_width;
int read_JPEG_file (char * filename) ; //声明读JPG文件函数
int write_JPEG_file (char * filename, int quality) ;//声明写JPG文件函数
/* 主函数 */
int main(int argc, char *argv[])
{
int flag;
int Q;
if (argc != 3)
{
printf("Command Error!\n");
return -1;
}
printf("Hello,this is a JPEG code and decode program!\n");
printf("The input file's name is %s \n",argv[1]);
printf("The output file's name is %s \n",argv[2]);
flag = read_JPEG_file (argv[1]);
if(flag==0)
{
printf("向内存中读入jpg文件失败!\n");
return -1;
}
printf("向内存中读入jpg文件成功!\n");
printf("输入图像压缩比Q:");
scanf("%d",&Q);
flag = write_JPEG_file (argv[2], Q);
if(flag==0)
{
printf("向磁盘中写入jpg文件失败!\n");
return -1;
}
printf("向磁盘中写入jpg文件成功!\n");
free(image_buffer);
return 0;
}
(4) 运行程序
以上源代码成功编译链接后,将会生成可执行文件my_jpeg.exe,我们在命令行下执行此程序可将一个彩色jpg图像文件读入内存,设置压缩比后,重新写入磁盘上去。运行过程如下:
结果图像如下:
输入图像 输出图像
4. 实验总结
(1)通过本次实验,成功的安装了IJG提供的参考软件JPEG-8C。掌握了利用参考软件提供的应用程序进行简单的JPEG解压缩操作。
(2)通过对源代码包中的cjpeg.c、djpeg.c、example.c的参考,进行了JPEG文件的读写实验,同时了解了JPEG的基本系统
读写实验源代码、可执行程序以及测试图片参见附件:my_jpeg.cpp , my_jpeg.exe , test.jpg