基本思路:
利用libjpeg库实现对jpg文件的解压缩,并将数据按bmp(从下到上,从左到右,BGR)存储保存)。
注意事项:
1:bmp数据存储时是按照BGR顺序
2:biHeight为正数时表示倒向的位图,读取的顺序为(从左->右,从下->上)
3:Windows在进行行扫描的时候最小的单位为4个字节,所以当每行字节数不为4的正数倍时要对字节数进行调整。缺省是每行补0
4:图像位图头信息中的高宽是实际图像的像素点的个数,与存储时需要调整对其数据使其满足4字节的倍数无关
实验内容:
步骤一:利用libjpeg库实现对jpg文件的解压缩并提取数据
FILE *fJpeg;//目标jpeg文件的句柄
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);//声明并初始化解压缩对象
row_stride = cinfo.output_width * cinfo.output_components; //计算每行所需的空间,字节为单位
while (cinfo.output_scanline < cinfo.output_height)
{
int line=cinfo.output_scanline;//当前行数
(void) jpeg_read_scanlines(&cinfo, &jpgbuf, 1);//执行该操作读取第line行数据,cinfo.output_scanline将加一,指向下一个要扫描的行
for(int i=0;i< cinfo.output_width;i++)//循环将存储在jpgbuf缓存区的数据放入data中
{
data[line*row_stride+i*cinfo.output_components+0]=jpgbuf[i*3];
data[line*row_stride+i*cinfo.output_components+1]=jpgbuf[i*3+1];
data[line*row_stride+i*cinfo.output_components+2]=jpgbuf[i*3+2];
}
}
fJpeg=fopen(JpegName,"rb");//二进制模式读取jpeg文件
jpeg_stdio_src(&cinfo, fJpeg);//指定解压对象的源文件
jpeg_read_header(&cinfo, TRUE);//读取文件信息,将图像的缺省的信息填充到cinfo结构中比便程序使用
jpeg_start_decompress(&cinfo);//开始接压缩
data=(unsigned char *)malloc(cinfo.output_width* cinfo.output_components*cinfo.output_width);//动态分配数据存储内存
memset(data,0,cinfo.output_width*cinfo.output_width*cinfo.output_components);//设置图像数据初值为0
jpgbuf = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);//动态分配缓存内存
memset(jpgbuf,0,cinfo.output_width*cinfo.output_components);//为缓存内存设置初值
步骤二:对将数据写入bmp文件中(必须按bmp文件存储数据的顺序进行存储)
//填充位图信息头
infoheader.biSize=sizeof(infoheader);//位图信息头结构的长度,为40
infoheader.biBitCount=24;//设置为真彩图
infoheader.biHeight=cinfo.image_height;
infoheader.biWidth=cinfo.image_width;
infoheader.biCompression=BI_RGB;//一般默认为BI_RGB格式表示不压缩
infoheader.biPlanes=1;//表示不用考虑
infoheader.biXPelsPerMeter=0;
infoheader.biYPelsPerMeter=0;
infoheader.biClrUsed=0;//在MSDN中队RGB位图定义可知默认值为0
//将文件 头和位图信息头写入文件中
fNewBmp=fopen(NewBmpName,"wb");//二进制写的形式打开文件
if(!fNewBmp)
{
cout<<"cannot open the NewBmpFile"<>2)<<2;//调整没行的字节数,使其是4的倍数
#ifdef DEBUG__
cout<<"((infoheader.biWidth*3+3)>>2)<<2 IS "<<(((infoheader.biWidth*3+3)>>2)<<2)<
源文件:
void JpegToBmp( char *JpegName,char * NewBmpName)//将读取jpeg中的数据并保存为BMP格式的文件,生成的都是24位真彩图,不需要调色板
{
FILE *fNewBmp;//存储生成的Bmp文件的句柄
FILE *fJpeg;//目标jpeg文件的句柄
unsigned char *data; //存放解压后的数据
unsigned char *jpgbuf; //存放解压后一行图像数据
BITMAPFILEHEADER header;//存储文件头
memset(&header, 0, sizeof(header));//文件头赋初始值
BITMAPINFOHEADER infoheader;//位图信息头
memset(&infoheader, 0, sizeof(infoheader));//赋初始值
int row_stride; //定义每行的字节数
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);//声明并初始化解压缩对象
fJpeg=fopen(JpegName,"rb");//二进制模式读取jpeg文件
if(fJpeg==NULL) //二进制模式读取
{
printf("error: cannot open the file\n");
return ;
}//打开jpeg图片
jpeg_stdio_src(&cinfo, fJpeg);//指定解压对象的源文件
jpeg_read_header(&cinfo, TRUE);//读取文件信息,将图像的缺省的信息填充到cinfo结构中比便程序使用
jpeg_start_decompress(&cinfo);//开始接压缩
data=(unsigned char *)malloc(cinfo.output_width* cinfo.output_components*cinfo.output_width);//动态分配数据存储内存
memset(data,0,cinfo.output_width*cinfo.output_width*cinfo.output_components);//设置图像数据初值为0
jpgbuf = (unsigned char *) malloc(cinfo.output_width *cinfo.output_components);//动态分配缓存内存
memset(jpgbuf,0,cinfo.output_width*cinfo.output_components);//为缓存内存设置初值
row_stride = cinfo.output_width * cinfo.output_components; //计算每行所需的空间,字节为单位
while (cinfo.output_scanline < cinfo.output_height)
{
int line=cinfo.output_scanline;//当前行数
(void) jpeg_read_scanlines(&cinfo, &jpgbuf, 1);//执行该操作读取第line行数据,cinfo.output_scanline将加一,指向下一个要扫描的行
for(int i=0;i< cinfo.output_width;i++)//循环将存储在jpgbuf缓存区的数据放入data中
{
data[line*row_stride+i*cinfo.output_components+0]=jpgbuf[i*3];
data[line*row_stride+i*cinfo.output_components+1]=jpgbuf[i*3+1];
data[line*row_stride+i*cinfo.output_components+2]=jpgbuf[i*3+2];
#ifdef SHOWDATA__
printf("(%d,%d,%d),(%d,%d)",jpgbuf[i*3],jpgbuf[i*3+1],jpgbuf[i*3+2],line,i);//打印图像数据
#endif
}
}
free(jpgbuf);
//填充文件头信息
header.bfType= 0x4D42;//设置为“BM”
header.bfSize=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+cinfo.output_width* cinfo.output_components*cinfo.output_width ;
header.bfOffBits=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
#ifdef DEBUG__
cout<<"header.bfType IS "<<(char)header.bfType<>2)<<2;//调整没行的字节数,使其是4的倍数
#ifdef DEBUG__
cout<<"((infoheader.biWidth*3+3)>>2)<<2 IS "<<(((infoheader.biWidth*3+3)>>2)<<2)<
参考: