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 <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 datafd = 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,表示彩色位圖, 如果是灰度圖,則為1cinfo.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 datafd = 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,表示彩色位圖, 如果是灰度圖,則為1cinfo.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 shorttypedef 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?
總結
以上是生活随笔為你收集整理的C实现BMP转JPG 附源码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 引用 各类相册制作代码
- 下一篇: 喜报丨内蒙古谱尼医学获批开展临床基因扩增