原文链接:
http://www.cnblogs.com/tiandsp/archive/2012/12/03/2799561.html
jpg压缩原理可以参考这篇文章http://hi.baidu.com/tiandsp/item/f5a2dcde6ef1405bd73aae41,我很早以前转的一篇文章。
没有使用libjpeg的压缩代码可以看看这篇文章http://hi.baidu.com/tiandsp/item/9b5843c58a3b4474cfd4f841,也是我很早以前转的。
这次使用libjpeg库压缩和上一篇的解压正好对应起来,有好多函数名称我都是对称的起的,所以结合起来看效果更好。
和上一篇一样,只能处理24位和8位的图像。
代码如下:
#include <iostream>
#include <stdio.h>
extern "C"{
#include "jpeglib.h"
};
#pragma comment(lib,"jpeg.lib")
using namespace std;
#pragma pack(2) //两字节对齐,否则bmp_fileheader会占16Byte
struct bmp_fileheader
{
unsigned short bfType; //若不对齐,这个会占4Byte
unsigned long bfSize;
unsigned short bfReverved1;
unsigned short bfReverved2;
unsigned long bfOffBits;
};
struct bmp_infoheader
{
unsigned long biSize;
unsigned long biWidth;
unsigned long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXPelsPerMeter;
unsigned long biYpelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
};
FILE *input_file;
FILE *output_file;
struct bmp_fileheader bfh;
struct bmp_infoheader bih;
unsigned char *src_buffer;
unsigned char *dst_buffer;
void read_bmp_header()
{
fread(&bfh,sizeof(struct bmp_fileheader),1,input_file);
fread(&bih,sizeof(struct bmp_infoheader),1,input_file);
}
void read_bmp_data()
{
fseek(input_file,bfh.bfOffBits,SEEK_SET);
src_buffer=new unsigned char[bih.biWidth*bih.biHeight*bih.biBitCount/8];
fread(src_buffer,sizeof(unsigned char)*bih.biWidth*bih.biHeight*bih.biBitCount/8,1,input_file);
unsigned long width=bih.biWidth;
unsigned long height=bih.biHeight;
unsigned short depth=unsigned short(bih.biBitCount/8);
unsigned char *src_point;
unsigned char *dst_point;
dst_buffer=new unsigned char[width*height*depth];
src_point=src_buffer+width*depth*(height-1);
dst_point=dst_buffer+width*depth*(height-1);
for (unsigned long i=0;i<height;i++)
{
for (unsigned long j=0;j<width*depth;j+=depth)
{
if (depth==1) //处理灰度图
{
dst_point[j]=src_point[j];
}
if (depth==3) //处理彩色图
{
dst_point[j+2]=src_point[j+0];
dst_point[j+1]=src_point[j+1];
dst_point[j+0]=src_point[j+2];
}
}
dst_point-=width*depth;
src_point-=width*depth;
}
}
void synthese_jpeg()
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPARRAY buffer;
unsigned long width=bih.biWidth;
unsigned long height=bih.biHeight;
unsigned short depth=unsigned short(bih.biBitCount/8);
unsigned char *point;
cinfo.err=jpeg_std_error(&jerr); //libjpeg各种配置
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo,output_file);
cinfo.image_width=width;
cinfo.image_height=height;
cinfo.input_components=depth;
if (depth==1)
cinfo.in_color_space=JCS_GRAYSCALE;
else
cinfo.in_color_space=JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo,20,TRUE); //中间的值为压缩质量,越大质量越好
jpeg_start_compress(&cinfo,TRUE);
buffer=(*cinfo.mem->alloc_sarray)
((j_common_ptr)&cinfo,JPOOL_IMAGE,width*depth,1);
point=dst_buffer+width*depth*(height-1);
while (cinfo.next_scanline<height)
{
memcpy(*buffer,point,width*depth);
jpeg_write_scanlines(&cinfo,buffer,1);
point-=width*depth;
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
}
int main()
{
input_file=fopen("lena_gray.bmp","rb");
output_file=fopen("lena.jpg","wb");
read_bmp_header();
read_bmp_data();
synthese_jpeg();
fclose(input_file);
fclose(output_file);
delete[] src_buffer;
delete[] dst_buffer;
cout<<"good job."<<endl;
cin.get();
return 0;
}