C实现BMP转JPG 附源码

  • 时间:2019-7-13
  • 环境:ubuntu18.04+clion
  • 基本思路:利用libjpeg库实现将bmp图像转换为jpg图像,并可以设置jpg的质量因子。
  • 了解:BMP格式,参照网址:https://blog.csdn.net/lesky/article/details/2218850
  • 注意事项:
  • 1. RBG数据存储为bmp时,数据是逆序存放,并且不是RGB,而是BGR;当将RGB数据存储为jpg时,则不用,不用逆序,数据也还是RGB。
  • 2. 图像位图头信息中的Height为正数时表示倒向的位图,读取的顺序为(从左->右,从下->上),所以存为jpg需将数据顺序调换。
  • 3. Windows在进行行扫描的时候最小的单位为4个字节,所以当每行字节数不为4的整数倍时要对字节数进行调整,缺省是每行补0。图像位图头信息中的高宽是实际图像的像素点的个数,与存储时需要调整对其数据使其满足4字节的倍数无关。
  • 5.此例程适用于彩色位图,若为灰度图需对程序做相应的修改,有空我会完善程序并增加jpg转bmp部分代码。关于第四点中的windows行扫描最小单位为4字节这个部分我不清楚linux中有无行扫描最小单位一说,希望得到指点。

    此篇博客参考于:https://blog.csdn.net/lzhq28/article/details/7775957


     

    目录

     

    一、建立编译环境

    二、bmp转jpg压缩步骤

    步骤一:读取bmp文件,并将数据调整为从从上到下、从左到右、RGB顺序

    1.申请并初始化jpeg压缩对象,同时要指定错误处理器

    2.读取bmp文件头和位图信息

    3.读取数据并调整数据的存储顺序

    步骤二:对步骤一得到的数据进行jpeg压缩,将调用libjpeg库

    4.对得到的数据进行设置

    5.写入数据

    6.释放压缩过程申请资源

    完整代码


一、建立编译环境

编译libjpeg库

Jpeg库下载地址:http://www.ijg.org/files/

下载好先解压,打开终端,进入解压好的目录。

【./configure --enable -shared --enable-static】

【make】

【make install】

在完成转换功能的文件中加入#include ,编译时链接libjpeg库即可。

 

二、bmp转jpg压缩步骤

步骤一:读取bmp文件,并将数据调整为从从上到下、从左到右、RGB顺序

1.申请并初始化jpeg压缩对象,同时要指定错误处理器

    struct jpeg_compress_struct cinfo;
     // 声明错误处理器,并赋值给jcs.err域
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

2.读取bmp文件头和位图信息

    FILE *fd,*outfile;
    BITMAPFILEHEADER header;//存储文件头
    memset(&header, 0, sizeof(header));
    BITMAPINFOHEADER infoheader;//位图信息头
    memset(&infoheader, 0, sizeof(infoheader));
    long m_iImageWidth=0;
    long m_iImageHeight=0;
    WORD m_iBitsPerPixel=0;
    WORD m_iBytesPerPixel=0;
    int m_iLineByteCnt=0;//每行的字节数
    int m_iImageDataSize=0;//图像数据的总字节数

    // Read bmp image data
    fd = fopen(bmp_file, "rb");
    if(!fd)
    {
        printf("ERROR1: Can not open the image.\n");
        return -1;
    }
    fread(&header,sizeof(unsigned char),sizeof(header),fd);//读取头文件
    fread(&infoheader,sizeof(unsigned char),sizeof(infoheader),fd);//读取位图信息头
    m_iImageWidth = infoheader.biWidth;
    m_iImageHeight = infoheader.biHeight;
    m_iBitsPerPixel = infoheader.biBitCount;
    m_iBytesPerPixel = m_iBitsPerPixel/8;//每个像素点所占的字节数
    m_iLineByteCnt = ((m_iImageWidth * m_iBytesPerPixel+3)>>2)<<2;//调整每行的字节数为4的整数倍

3.读取数据并调整数据的存储顺序

    m_iImageDataSize = m_iLineByteCnt * m_iImageHeight;
    data = (unsigned char*)malloc(m_iImageDataSize);//分配总空间存储图像数据
    if(data == NULL)
    {
        printf("malloc error\r\n");
        return 0;
    }
    Line_data = (unsigned char*)malloc(m_iLineByteCnt);//每行图像数据所需空间
    if(Line_data == NULL)
    {
        printf("malloc error\r\n");
        return 0;
    }
if((3 == m_iBytesPerPixel)&&(m_iImageHeight)>0)
    {
        for(int scanline = 0;scanline < m_iImageHeight;scanline++)
        {
            ret = fread(Line_data, sizeof(unsigned char),m_iLineByteCnt,fd);
            if(ret == 0)
            {
                if(ferror(fd))
                {
                    printf("\nERROR2: Can not read the pixel data.\n");
                    free(Line_data);
                    fclose(fd);
                    return -1;
                }
            }
            for(int tmpCol = 0;tmpColRGB,从下到上->从上到下)
        }
    }

步骤二:对步骤一得到的数据进行jpeg压缩,将调用libjpeg库

4.对得到的数据进行设置

需要注意的是,jpeg_set_defaults函数一定要等设置好图像宽、高、色彩通道数及色彩空间四个参数后才能调用,因为这个函数要用到这四个值,调用jpeg_set_defaults函数后,jpeglib库采用默认的设置对图像进行压缩,如果需要改变设置,如压缩质量,调用这个函数后,可以调用其它设置函数,如jpeg_set_quality函数。其实图像压缩时有好多参数可以设置,但大部分我们都用不着设置,只需调用jpeg_set_defaults函数值为默认值即可。

    jpeg_create_compress(&cinfo);//初始化jpeg压缩对象
    if ((outfile = fopen(jeg_file, "wb")) == NULL)
    {
        fprintf(stderr, "can't open %s\n", jeg_file);
        return -1;
    }
    jpeg_stdio_dest(&cinfo, outfile);  //指定压缩后的图像所存放的目标文件 ,二进制打开
    cinfo.image_width = m_iImageWidth;  //宽
    cinfo.image_height = m_iImageHeight;//高
    cinfo.input_components = depth; // 在此为3,表示彩色位图, 如果是灰度图,则为1
    cinfo.in_color_space = JCS_RGB;  //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像
    jpeg_set_defaults(&cinfo);   // 调用jpeg_set_defaults函数后,jpeglib库采用默认的设置对图像进行压缩
    jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE );  // jpeglib库采用默认的设置对图像进行压缩
    jpeg_start_compress(&cinfo, TRUE);

5.写入数据

    row_pointer = malloc(m_iImageDataSize);
    while (cinfo.next_scanline < cinfo.image_height)
    {
        for(int j=0;j< m_iLineByteCnt;j++)
        {
            Line_data[j]=data[cinfo.next_scanline*m_iLineByteCnt+j];
        }
        row_pointer[0]=Line_data;
        jpeg_write_scanlines(&cinfo, row_pointer, 1);

    }
    jpeg_finish_compress(&cinfo);

6.释放压缩过程申请资源

主要就是jpeg压缩对象及动态分配的数组,在这只介绍jpeg对象的释放,只需调用jpeg_destroy_compress这个函数即可,如下:

    jpeg_destroy_compress(&cinfo);

完整代码

/*********************************************************************************
 *    Copyright:  (C) 2019 zyjin
 *                  All rights reserved.
 *
 *    Filename:  main.c
 *    Description:  bmp to jpg
 *
 *    Created by zyjin on 19-7-13.
 *
 *    Version:  1.0.0(2019年7月13日)
 *    Author:  zyjin 
 *    ChangeLog:  1, Release initial version on "2019年7月13日 19时18分"
 *
 ********************************************************************************/
#include "bmptojpg.h"

int main(int argc,char *argv[])
{
    int JPEG_QUALITY = 100;
    const char *bmp_file = "/root/CLionProjects/BMPTOJPG/test.bmp";
    const char *jpg_file = "/root/CLionProjects/BMPTOJPG/test2.jpg";
    BmptoJpg(bmp_file,jpg_file, JPEG_QUALITY);
    printf("BMP To JPG done\r\n");

    return 1;
}
/*********************************************************************************
 *    Copyright:  (C) 2019 zyjin
 *                  All rights reserved.
 *
 *    Filename:  bmptojpg.c
 *    Description:  bmp to jpg
 *
 *    Created by zyjin on 19-7-13.
 *
 *    Version:  1.0.0(2019年7月13日)
 *    Author:  zyjin 
 *    ChangeLog:  1, Release initial version on "2019年7月13日 18时55分"
 *
 ********************************************************************************/
#include "bmptojpg.h"
#define a
#ifdef a
int BmptoJpg(const char *bmp_file, const char *jeg_file, int JPEG_QUALITY)
{
    FILE *fd,*outfile;
    int ret;
    int i = 0;
    unsigned char *data,*Line_data;
    int depth = 3;
    JSAMPROW * row_pointer;
    //long rgb_index = 0;
    struct jpeg_compress_struct cinfo;//申请并初始化jpeg压缩对象,同时要指定错误处理器
    struct jpeg_error_mgr jerr;// 声明错误处理器,并赋值给jcs.err域
    cinfo.err = jpeg_std_error(&jerr);

    BITMAPFILEHEADER header;//存储文件头
    memset(&header, 0, sizeof(header));
    BITMAPINFOHEADER infoheader;//位图信息头
    memset(&infoheader, 0, sizeof(infoheader));
    long m_iImageWidth=0;
    long m_iImageHeight=0;
    WORD m_iBitsPerPixel=0;
    WORD m_iBytesPerPixel=0;
    int m_iLineByteCnt=0;//每行的字节数
    int m_iImageDataSize=0;//图像数据的总字节数

    // Read bmp image data
    fd = fopen(bmp_file, "rb");
    if(!fd)
    {
        printf("ERROR1: Can not open the image.\n");
        return -1;
    }
    fread(&header,sizeof(unsigned char),sizeof(header),fd);//读取头文件
    fread(&infoheader,sizeof(unsigned char),sizeof(infoheader),fd);//读取位图信息头
    m_iImageWidth = infoheader.biWidth;
    m_iImageHeight = infoheader.biHeight;
    m_iBitsPerPixel = infoheader.biBitCount;

    //printf("%d   %d\r\n",sizeof(DWORD),sizeof(WORD));
    //printf("%d   %d\r\n",sizeof(header),sizeof(infoheader));
    //printf("%ld   %ld     %d  ",m_iImageWidth,m_iImageHeight,m_iBitsPerPixel);

    m_iBytesPerPixel = m_iBitsPerPixel/8;//每个像素点所占的字节数
    m_iLineByteCnt = (m_iImageWidth * m_iBytesPerPixel);
    //m_iLineByteCnt = ((m_iImageWidth * m_iBytesPerPixel+3)>>2)<<2;//调整每行的字节数为4的整数倍

    m_iImageDataSize = m_iLineByteCnt * m_iImageHeight;
    data = (unsigned char*)malloc(m_iImageDataSize);
    if(data == NULL)
    {
        printf("malloc error\r\n");
        return 0;
    }
    Line_data = (unsigned char*)malloc(m_iLineByteCnt);
    if(Line_data == NULL)
    {
        printf("malloc error\r\n");
        return 0;
    }
    if((3 == m_iBytesPerPixel)&&(m_iImageHeight)>0)
    {
        for(int scanline = 0;scanline < m_iImageHeight;scanline++)
        {
            ret = fread(Line_data, sizeof(unsigned char),m_iLineByteCnt,fd);
            if(ret == 0)
            {
                if(ferror(fd))
                {
                    printf("\nERROR2: Can not read the pixel data.\n");
                    free(Line_data);
                    fclose(fd);
                    return -1;
                }
            }
            for(int tmpCol = 0;tmpColRGB,从下到上->从上到下)
        }
    }

    jpeg_create_compress(&cinfo);//初始化jpeg压缩对象
    if ((outfile = fopen(jeg_file, "wb")) == NULL)
    {
        fprintf(stderr, "can't open %s\n", jeg_file);
        return -1;
    }
    jpeg_stdio_dest(&cinfo, outfile);  //指定压缩后的图像所存放的目标文件 ,二进制打开
    cinfo.image_width = m_iImageWidth;  //宽
    cinfo.image_height = m_iImageHeight;//高
    cinfo.input_components = depth; // 在此为3,表示彩色位图, 如果是灰度图,则为1
    cinfo.in_color_space = JCS_RGB;  //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像
    jpeg_set_defaults(&cinfo);   // 调用jpeg_set_defaults函数后,jpeglib库采用默认的设置对图像进行压缩
    jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE );  // jpeglib库采用默认的设置对图像进行压缩
    jpeg_start_compress(&cinfo, TRUE);
    //一次写入
    row_pointer = malloc(m_iImageDataSize);
    while (cinfo.next_scanline < cinfo.image_height)
    {
        for(int j=0;j< m_iLineByteCnt;j++)
        {
            Line_data[j]=data[cinfo.next_scanline*m_iLineByteCnt+j];
        }
        row_pointer[0]=Line_data;
        jpeg_write_scanlines(&cinfo, row_pointer, 1);

    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    free(row_pointer);
    free(data);
    free(Line_data);
    fclose(fd);
    fclose(outfile);
    return 0;
}
#endif
/*********************************************************************************
 *    Copyright:  (C) 2019 zyjin
 *                  All rights reserved.
 *
 *    Filename:  bmptojpg.h
 *    Description:  bmp to jpg
 *
 *    Created by zyjin on 19-7-13.
 *
 *    Version:  1.0.0(2019年7月13日)
 *    Author:  zyjin 
 *    ChangeLog:  1, Release initial version on "2019年7月13日 18时45分30秒"
 *
 ********************************************************************************/
#ifndef BMPTOJPG_BMPTOJPG_H
#define BMPTOJPG_BMPTOJPG_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DWORD unsigned int
#define WORD  unsigned short

typedef struct tagBITMAPFILEHEADER {
    WORD    bfType;
    WORD    bfReserved1;
    WORD    bfReserved2;
    WORD    bfSize;
    WORD    bbbb;
    WORD    bbba;
    WORD   bfOffBits;
} BITMAPFILEHEADER;// FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
    DWORD      biSize;
    DWORD      biWidth;
    DWORD      biHeight;
    WORD       biPlanes;
    WORD       biBitCount;
    DWORD      biCompression;
    DWORD      biSizeImage;
    DWORD      biXPelsPerMeter;
    DWORD      biYPelsPerMeter;
    DWORD      biClrUsed;
    DWORD      biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

int BmptoJpg(const char *bmp_file, const char *jeg_file, int JPEG_QUALITY);
#endif //BMPTOJPG_BMPTOJPG_H

 

你可能感兴趣的:(自我学习及整理,bmp,jpg)