利用libjpeg库实现jpg与bmp图片互转指南

jpg与bmp图片互转指南

一、原理:

​ jpg与bmp图片格式都是以rgb像素为基础的,但是jpg在bmp的rgb的基础上进行了压缩。而且存储的方式是bgr,因此,在二者转换过程中需要转换对应的格式,而且只需要的到rgb再使用libjpeg库即可进行互相转换。

二、转换工具: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转为bmp

利用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转jpeg

获取所有的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! */

}

你可能感兴趣的:(图片格式转换,C/C++,linux)