libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。
官网:http://www.ijg.org/
源码:http://www.ijg.org/files/jpegsrc.v9b.tar.gz
实验上位机:itop-4412
移植步骤:
./configure --host=arm-linux --prefix=/opt/crosstool/arm-2009q3/arm-none-linux-gnueabi/libc/usrmake -----(安装到交叉编译工具标准c库的目录下)
make install
上面安装到编译器中,同时也要安装到根文件系统中
/configure --host=arm-linux --prefix=/opt/lrdfs/usr --- (我的根文件放在/opt/lrdfs下)
make install
压缩:
输入RGB数据,输出jpeg数据
(参考example.c中的代码)
/*
* image_buffer : rgb数据
* filename: 输出jpg的文件名
* quality : 压缩质量
*/
GLOBAL(void)
write_JPEG_file (char * filename, int quality, unsigned char *image_buffer)
{
struct jpeg_compress_struct com_cinfo;
struct jpeg_error_mgr com_jerr;
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] 一行位图 */
int row_stride; /* physical row width in image buffer */
/* Step 1: 申请并初始化jpeg压缩对象,同时要指定错误处理器
*/
com_cinfo.err = jpeg_std_error(&com_jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&com_cinfo);
/* Step 2: 指定压缩后的图像所存放的目标文件,注意目标文件应以二进制模式打开
*/
if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&com_cinfo, outfile);
/* Step 3: 设置压缩参数 */
/* image width and height, in pixels */
com_cinfo.image_width = img_width;
com_cinfo.image_height = img_height;
com_cinfo.input_components = 3; /* 3表示彩色位图,如果是灰度图则为1 */
com_cinfo.in_color_space = JCS_RGB; /* JCS_RGB表示彩色图像 */
/* jpeg_set_defaults函数一定要等设置好图像宽、高、色彩通道数计色彩空间四个参数后才能调用,因为这个函数要用到这四个值,调用jpeg_set_defaults函数后,libjpeg库采用默认的设置对图像进行压缩,如果需要改变设置,如压缩质量,调用这个函数后,可以调用其它设置函数,如jpeg_set_quality函数。其实图像压缩时有好多参数可以设置,但大部分我们都用不着设置,只需调用jpeg_set_defaults函数值为默认值即可。 */
jpeg_set_defaults(&com_cinfo);
jpeg_set_quality(&com_cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* jpeg_start_compress,然后可以对每一行进行压缩,也可以对若干行进行压缩,甚至可以对整个的图像进行一次压缩,压缩完成后,要调用jpeg_finish_compress函数*/
/* Step 4: Start compressor */
jpeg_start_compress(&com_cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
row_stride = img_width * 3; /* JSAMPLEs per row in image_buffer 每一行的字节数*/
//对每一行进行压缩
while (com_cinfo.next_scanline < com_cinfo.image_height) {
row_pointer[0] = & image_buffer[com_cinfo.next_scanline * row_stride]; // image_buffer指向要压缩的数据
jpeg_write_scanlines(&com_cinfo, row_pointer, 1);
}
/*最后就是释放压缩工作过程中所申请的资源了*/
/* Step 6: Finish compression */
jpeg_finish_compress(&com_cinfo);
fclose(outfile);
/* Step 7: release JPEG compression object */
jpeg_destroy_compress(&com_cinfo);
/* And we're done! */
}
解压:输入:jpg文件,输出:rgb数据
/* jpg_buffer : jpg文件数据
* file_info : jpg文件的状态信息
*/
int jpg_depress(unsigned char *jpg_buffer, struct stat file_info )
{
//2 声明解压缩结构体,以及错误管理结构体
struct jpeg_decompress_struct cinfo; //解压结构体
struct jpeg_error_mgr jerr;
// 使用缺省的出错处理来初始化解压缩结构体
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
// 配置该cinfo,使其从jpg_buffer中读取jpg_size个字节
// 这些数据必须是完整的JPEG数据
jpeg_mem_src(&cinfo, jpg_buffer, file_info.st_size);
// 读取JPEG文件的头,并判断其格式是否合法
int ret = jpeg_read_header(&cinfo, true);
if(ret != 1)
{
fprintf(stderr, "[%d]: jpeg_read_header failed: "
"%s\n", __LINE__, strerror(errno));
exit(1);
}
// 开始解压
jpeg_start_decompress(&cinfo);
imageinfo.width = cinfo.output_width;
imageinfo.height = cinfo.output_height;
imageinfo.pixel_size = cinfo.output_components;
int row_stride = imageinfo.width * imageinfo.pixel_size;
// 根据图片的尺寸大小,分配一块相应的内存bmp_buffer
// 用来存放从jpg_buffer解压出来的图像数据
bmp_size = imageinfo.width *
imageinfo.height * imageinfo.pixel_size;
bmp_buffer = (unsigned char *)calloc(1, bmp_size);
// 循环地将图片的每一行读出并解压到bmp_buffer中
int line = 0;
while(cinfo.output_scanline < cinfo.output_height)
{
unsigned char *buffer_array[1];
buffer_array[0] = bmp_buffer +
(cinfo.output_scanline) * row_stride;
jpeg_read_scanlines(&cinfo, buffer_array, 1);
}
// 解压完了,将jpeg相关的资源释放掉
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
free(jpg_buffer);
return 0;
}
一点题外话:
一、YUV420格式
先Y,后V,中间是U。其中的Y是w * h,U和V是w/2 * (h/2)
如果w = 4,h = 2,则:
yyyy
yyyy
uu
vv
内存则是:yyyyyyyyuuvv
需要占用的内存:w * h * 3 / 2
采样规律是:每个像素点都采样Y,奇数行采样1/2个U,不采样V,偶数行采样1/2个V,不采样U
二、YUV422格式
本格式使用较为广泛
每两个点为一组,共占用4个字节
YUYVYUYV…
对于每一组YUYV,前面一个Y和本组中的UV组成第一个点,第二个Y和本组中的UV组成第二个点
所以,在内存中,宽高分别为w * 2、h。
如果w = 4,h = 2,则:
YUYVYUYV
YUYVYUYV
需要占用的内存:w * h * 2
三、UYUY422格式
本格式和YUYV422一样,只是YUV的位置不一样罢了
每组中YUV的排列顺序为:UYUV
需要占用的内存:w * h * 2