C实现BMP转JPG 附源码

一、建立编译环境

编译libjpeg库

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

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

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

【make】

【make install】

在完成转换功能的文件中加入#include <jpeglib.h>,编译时链接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;tmpCol<m_iImageWidth;tmpCol++)

            {
                data[(m_iImageHeight-1-scanline) * m_iLineByteCnt+tmpCol*3+0]=Line_data[tmpCol*3+2];
                data[(m_iImageHeight-1-scanline) * m_iLineByteCnt+tmpCol*3+1]=Line_data[tmpCol*3+1];
                data[(m_iImageHeight-1-scanline) * m_iLineByteCnt+tmpCol*3+2]=Line_data[tmpCol*3+0];
            }//调整数据存储顺序(BGR->RGB,从下到上->从上到下)
        }
    }

步骤二:对步骤一得到的数据进行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 <jzy2410723051@163.com><zzzzyjin@foxmail.com>
 *    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 <jzy2410723051@163.com><zzzzyjin@foxmail.com>
 *    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;tmpCol<m_iImageWidth;tmpCol++)

            {
                data[(m_iImageHeight-1-scanline) * m_iLineByteCnt+tmpCol*3+0]=Line_data[tmpCol*3+2];
                data[(m_iImageHeight-1-scanline) * m_iLineByteCnt+tmpCol*3+1]=Line_data[tmpCol*3+1];
                data[(m_iImageHeight-1-scanline) * m_iLineByteCnt+tmpCol*3+2]=Line_data[tmpCol*3+0];
            }//调整数据存储顺序(BGR->RGB,从下到上->从上到下)
        }
    }

    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 <jzy2410723051@163.com><zzzzyjin@foxmail.com>
 *    ChangeLog:  1, Release initial version on "2019年7月13日 18时45分30秒"
 *
 ********************************************************************************/
#ifndef BMPTOJPG_BMPTOJPG_H
#define BMPTOJPG_BMPTOJPG_H
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/timeb.h>
#include <jpeglib.h>

#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

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值