基於libjpeg庫實現JPEG圖片壓縮程式碼實現(程式碼普適性強)
本文先把程式碼貼上,後續會講解原理及實現過程
1、從官網上下載jpeg原始碼,編譯成庫(本人在windows下編譯),編譯方法網上很多,這裡不敘述。
2、新增庫檔案和jpeglib.h、jmorecfg.h、jconfig.h至工程中
3、程式碼實現(VS2013)
#define JPEG_QUALITY 97 //它的大小決定jpg的質量好壞
//#include <atlbase.h>#include <afxwin.h>
#include <iostream>
#include<ctime>
using namespace std;
extern "C" {
#include "jpeglib.h"
#include "jmorecfg.h"
#include "jconfig.h"
#include "jerror.h"
}
typedef struct /**** BMP file header structure ****/
{
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data */
} BITMAPFILEHEADER1;
typedef struct /**** BMP file info structure ****/
{
unsigned int biSize; /* Size of info header */
int biWidth; /* Width of image */
int biHeight; /* Height of image */
unsigned short biPlanes; /* Number of color planes */
unsigned short biBitCount; /* Number of bits per pixel */
unsigned int biCompression; /* Type of compression to use */
unsigned int biSizeImage; /* Size of image data */
int biXPelsPerMeter; /* X pixels per meter */
int biYPelsPerMeter; /* Y pixels per meter */
unsigned int biClrUsed; /* Number of colors used */
unsigned int biClrImportant; /* Number of important colors */
} BITMAPINFOHEADER1;
typedef struct tagRGBQUAD1{
BYTE rgbBlue;//藍色的亮度(值範圍為0-255)
BYTE rgbGreen;//綠色的亮度(值範圍為0-255)
BYTE rgbRed;//紅色的亮度(值範圍為0-255)
BYTE rgbReserved;//保留,必須為0
}RGBQUAD1;
/*bmp格式圖片,輸出jpeg的名字,質量因子*/
void bmptojpg(const char *strSourceFileName, const char *strDestFileName, int quality){
BITMAPFILEHEADER bfh;// bmp檔案頭
BITMAPINFOHEADER bih;// bmp頭資訊
RGBQUAD rq[256];// 調色盤
int nAdjust;// 用於位元組對齊
BYTE *data = NULL;//new BYTE[bih.biWidth*bih.biHeight];
//BYTE *pDataConv = NULL;//new BYTE[bih.biWidth*bih.biHeight];
int nComponent = 0;
// 開啟影象檔案
FILE *fp = fopen(strSourceFileName, "rb");
if (fp == NULL)
{
printf("Open file error!\n");
return;
}
// 讀取檔案頭
fread(&bfh, sizeof(bfh), 1, fp);
// 讀取影象資訊
fread(&bih, sizeof(bih), 1, fp);
switch (bih.biBitCount)
{
case 8://灰度圖
if (bfh.bfOffBits - 1024<54)
{
fclose(fp);
return;
}
// 8位位元組對齊
nAdjust = bih.biWidth % 4;
if (nAdjust) nAdjust = 4 - nAdjust;
data = new BYTE[(bih.biWidth + nAdjust)*bih.biHeight];
//pDataConv = new BYTE[bih.biWidth*bih.biHeight];
// 定位調色盤,並讀取調色盤
fseek(fp, bfh.bfOffBits - 1024, SEEK_SET);
fread(rq, sizeof(RGBQUAD), 256, fp);
// 讀取點陣圖
fread(data, (bih.biWidth + nAdjust)*bih.biHeight, 1, fp);
fclose(fp);
nComponent = 1;
break;
case 24://RGB
{
// 8位位元組對齊
nAdjust = bih.biWidth * 3 % 4;
if (nAdjust) nAdjust = 4 - nAdjust;
data = new BYTE[(bih.biWidth * 3 + nAdjust)*bih.biHeight];
//pDataConv = new BYTE[bih.biWidth*bih.biHeight*3];
fseek(fp, bfh.bfOffBits, SEEK_SET);
fread(data, (bih.biWidth * 3 + nAdjust)*bih.biHeight, 1, fp);
fclose(fp);
for (int j = 0; j<bih.biHeight; j++){
for (int i = 0; i<bih.biWidth; i++)
{
BYTE red = data[j*(bih.biWidth * 3 + nAdjust) + i * 3];
data[j*(bih.biWidth * 3 + nAdjust) + i * 3] = data[j*(bih.biWidth * 3 + nAdjust) + i * 3 + 2];
data[j*(bih.biWidth * 3 + nAdjust) + i * 3 + 2] = red;
}
}
nComponent = 3;
break;
}
default:
fclose(fp);
return;
}
struct jpeg_compress_struct jcs;
struct jpeg_error_mgr jem;
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
fp = fopen(strDestFileName, "wb");
if (fp == NULL)
{
fprintf(stderr, "can't open %s\n", strDestFileName);
delete[] data;
//delete [] pDataConv;
return;
}
jpeg_stdio_dest(&jcs, fp);
jcs.image_width = bih.biWidth; // 為圖的寬和高,單位為畫素
jcs.image_height = bih.biHeight;
jcs.input_components = nComponent;// 1,表示灰度圖, 如果是彩色點陣圖,則為3
if (nComponent == 1)
jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度圖,JCS_RGB表示彩色影象
else
jcs.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcs);//compression parameter selection 更新引數
// 影象取樣率,預設為2 * 2
jcs.comp_info[0].v_samp_factor = 1;
jcs.comp_info[0].h_samp_factor = 1;
jpeg_set_quality(&jcs, quality, true);
//start = clock();
jcs.dct_method = JDCT_ISLOW;
//jcs.dct_method = JDCT_IFAST;
//jcs.dct_method = JDCT_FLOAT;
//finish = clock();
//cout << finish - start << "/" << CLOCKS_PER_SEC << " (s) " << endl;
//jcs.dct_method = JDCT_FASTEST;
jpeg_start_compress(&jcs, TRUE);//一旦呼叫了該介面,便不能修改任何引數
JSAMPROW row_pointer[1];// 一行點陣圖
int row_stride;// 每一行的位元組數
row_stride = jcs.image_width*nComponent;// 如果不是索引圖,此處需要乘以3
// 對每一掃描行進行壓縮
while (jcs.next_scanline < jcs.image_height) {
row_pointer[0] = &data[(jcs.image_height - jcs.next_scanline - 1) * (row_stride + nAdjust)];//與官方文件裡的區別:這裡生成的圖片是正的,官方是倒的
jpeg_write_scanlines(&jcs, row_pointer, 1);//1表示一行
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);//jpeg_abort_compress(&jcs),jpeg_abort(&jcs)
fclose(fp);
delete[] data;
}
int main(int argc, char* argv[])
{
bmptojpg("f6.bmp", "3_11.jpg", 100);
//getchar();
return 0;
}