jpg与bmp图片格式都是以rgb像素为基础的,但是jpg在bmp的rgb的基础上进行了压缩。而且存储的方式是bgr,因此,在二者转换过程中需要转换对应的格式,而且只需要的到rgb再使用libjpeg库即可进行互相转换。
移植jpeg库
1.下载JPEG库的源代码 http://www.ijg.org/files/ JPEG官方网站
2.jpegsrc.v9a.tar.gz 为源码文件,需要往自己的linux中安装该库
在家目录解压源码文件
cp ./jpegsrc.v9a.tar.gz /home
cd /home
tar -xvf jpegsrc.v9a.tar.gz
mkdir jpeg_lib
配置文件:
cd jpeg-9a
./configure --prefix=/home/jpeg_lib
make
make install
cd …/jpeg_lib/lib
cp ./* /lib
3.编译命令:
gcc xxx.c -o xxx -I/home/gec/jpeg_lib/include -L/home/gec/jpeg_lib/lib -ljpeg
4.当需要用到库的时候在头文件中加入:这些头文件
#include
#include "jpeglib.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
利用jpeg库从jpg图片获得rgb:
//读取并转换jpeg像素点为rgb像素点
GLOBAL(int)read_JPEG_file (const char * filename)
{
//定义一个JPEG解码信息结构体
struct jpeg_decompress_struct cinfo;
//定义一个错误信息结构体
struct my_error_mgr jerr;
/* More stuff */
FILE * infile; /*定义源文件指针 标准IO的*/
JSAMPARRAY buffer; /*输出行缓冲*/
int row_stride; /*输出行缓冲的宽度 */
//打开源文件
if ((infile = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* 第一步:初始化JPEG解码对象*/
/* 我们开始初始化错误对象*/
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 0;
}
/*现在我们可以初始化解码对象了*/
jpeg_create_decompress(&cinfo);
/*把源文件与解码对象关联起来 */
jpeg_stdio_src(&cinfo, infile);
/*读取JPEG图片的头数据*/
(void) jpeg_read_header(&cinfo, TRUE);
/*开始解码*/
(void) jpeg_start_decompress(&cinfo);
//得到一行数据所占用的字节数
row_stride = cinfo.output_width * cinfo.output_components;
/*根据行字节数去分配堆空间*/
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
char *p=NULL;
bmp_width = cinfo.output_width;
bmp_height = cinfo.output_height;
int x=0,y=0;
unsigned char r=0;
unsigned char g=0;
unsigned char b=0;
rgb_buf = malloc(cinfo.output_width * cinfo.output_height * 3);
//重点 重点 重重点!!!! 解码就在这里进行了 上面的都是准备工作!!
while (cinfo.output_scanline < cinfo.output_height)
{
//解码一行JPEG图形的数据变成bmp数据并存放到buffer 中
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
p = buffer[0];
y = bmp_height - cinfo.output_scanline;
//取出RGB数据
for(x = 0 ; x < cinfo.output_width ; x++)
{
r = *p++;
g = *p++;
b = *p++;
//赋值到rgb_buf上
rgb_buf[bmp_width * y * 3 + x * 3] = b;
rgb_buf[bmp_width * y * 3 + x * 3 + 1] = g;
rgb_buf[bmp_width * y * 3 + x * 3 + 2] = r;
}
}
//结束解码对象
(void) jpeg_finish_decompress(&cinfo);
//销毁解码对象
jpeg_destroy_decompress(&cinfo);
//关闭文件
fclose(infile);
return 1;
}
把rgb写入到bmp文件中,并处理bmp文件头:
int fn_Make_Bmp()
{
int bmp_fd = open("./test.bmp" , O_RDWR | O_TRUNC | O_CREAT , 0777);
if(bmp_fd <= 0)
{
perror("");
return -1;
}
//处理bmp数据头
struct bitmap_header head_info;
memset(&head_info , 0 , 14);
head_info.type = BM;//BM = 19778
head_info.size = bmp_height * bmp_width * 3 + 54;
head_info.offbits = 54;
struct bitmap_info bmp_info;
memset(&bmp_info , 0 , 40);
bmp_info.size = 40;
bmp_info.width = bmp_width;
bmp_info.height = bmp_height;
bmp_info.planes = 1;
bmp_info.bit_count = 24;
bmp_info.size_img = bmp_height * bmp_width * 3;
bmp_info.X_pel = bmp_width;
bmp_info.Y_pel = bmp_height;
//写入
write(bmp_fd , &head_info , 14);
write(bmp_fd , &bmp_info , 40);
write(bmp_fd , rgb_buf , bmp_height * bmp_width * 3);
free(rgb_buf);
return 0;
}
获取所有的bmp像素,并且转换为jpg对应的bgr存储形式
int fn_Open_Bmp(const char * filename)
{
int bmp_fd = open(filename , O_RDWR);
if(bmp_fd <= 0)
{
perror("");
return -1;
}
//为头信息申请空间
struct bitmap_header * head_info = malloc(14);
struct bitmap_info * bmp_info = malloc(40);
if(head_info == NULL || bmp_info == NULL)
{
printf("申请bmp头信息空间失败\n");
return -1;
}
//读取bmp的头信息
read(bmp_fd , head_info , 14);
read(bmp_fd , bmp_info , 40);
bmp_w = bmp_info->width;
bmp_h = bmp_info->height;
printf("bmp_x = %d bmp_y = %d\n" , bmp_w , bmp_h);
//读取RGB信息
rgb_buf = malloc(bmp_w * bmp_h * 3);
if(rgb_buf == NULL)
{
printf("申请bmp_rgb空间失败\n");
return -1;
}
unsigned int ret = read(bmp_fd , rgb_buf , bmp_w * bmp_h * 3);
if(ret != bmp_w * bmp_h * 3)
{
printf("读取bmp_rgb失败\n");
return -1;
}
unsigned char tmp;
//把RGB转换成BGR
for(int i = 0 ; i < bmp_h ; i++)
{
for(int j = 0 ; j < bmp_w ; j++)
{
tmp = rgb_buf[bmp_w * i * 3 + j * 3];
rgb_buf[bmp_w * i * 3 + j * 3] = rgb_buf[bmp_w * i * 3 + j * 3 + 2];
rgb_buf[bmp_w * i * 3 + j * 3 + 2] = tmp;
}
}
free(bmp_info);
free(head_info);
close(bmp_fd);
return 0;
}
把bgr使用jpeg库进行压缩,并且存储到jpg文件中
GLOBAL(void)write_JPEG_file (const char * filename)
{
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);
if ((outfile = fopen(filename, "w+")) == 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 = bmp_w;
com_cinfo.image_height = bmp_h;
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的质量参数写为60比较合适
jpeg_set_quality(&com_cinfo , 60 , 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 = bmp_w * 3;/* JSAMPLEs per row in image_buffer 每一行的字节数*/
//对每一行进行压缩
while (com_cinfo.next_scanline < com_cinfo.image_height)
{
row_pointer[0] = & rgb_buf[(bmp_h - com_cinfo.next_scanline - 1) * 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! */
}