C实现jpg转换为BMP 附源文件

基本思路:

      利用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"<<endl;
              return;
        	}
        	fwrite(&header,sizeof(header),1,fNewBmp);//写入文件头
        	fwrite(&infoheader,sizeof(infoheader),1,fNewBmp);//写入位图信息头
 
//由于BMP扫描方式为从上到下,从左到右,window扫描要满足4字节的倍数。读data数据进行修改,存储为BGR顺序
        	int tmpRow=((infoheader.biWidth*3+3)>>2)<<2;//调整没行的字节数,使其是4的倍数
#ifdef DEBUG__
        	cout<<"((infoheader.biWidth*3+3)>>2)<<2 IS "<<(((infoheader.biWidth*3+3)>>2)<<2)<<endl;
       	 cout<<"infoheader.biWidth*3 IS "<<infoheader.biWidth*3<<endl;
#endif
       
       	jpgbuf = (unsigned char *) malloc(tmpRow);//动态分配缓存内存
        	memset(jpgbuf,0,tmpRow);//为缓存内存设置初值
 
        	for(int i=0;i<infoheader.biHeight;i++)
        	{
              for(int j=0;j<infoheader.biWidth;j++)//将从下到上从左到右读取数据,并将RGB顺寻装换为BGR顺序
              	{
              
                       jpgbuf[3*j+0]=data[(infoheader.biHeight-1-i)*row_stride+3*j+2];
                       jpgbuf[3*j+1]=data[(infoheader.biHeight-1-i)*row_stride+3*j+1];
                       jpgbuf[3*j+2]=data[(infoheader.biHeight-1-i)*row_stride+3*j+0];
#ifdef DEBUG__
                      // printf("data(%d,%d,%d),buf(%d,%d,%d)",data[(infoheader.biHeight-1-i)*row_stride+3*j+0],data[(infoheader.biHeight-1-i)*row_stride+3*j+1],data[(infoheader.biHeight-1-i)*row_stride+3*j+2], jpgbuf[3*j+0], jpgbuf[3*j+1], jpgbuf[3*j+2]);
                      
#endif
              	}
               fwrite(jpgbuf,sizeof(unsigned char),tmpRow,fNewBmp);//每行的数据写入文件中
        }
		

 

 源文件:

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<<endl;
        cout<<"header.bfSize IS "<<header.bfSize<<endl;
        cout<<"header.bfOffBits IS "<<header.bfOffBits<<endl;
        //printf("sizeof(data) IS %d.\n",cinfo.output_width* cinfo.output_components*cinfo.output_width );
#endif
 
//填充位图信息头
        	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"<<endl;
              return;
        }
        fwrite(&header,sizeof(header),1,fNewBmp);//写入文件头
        	fwrite(&infoheader,sizeof(infoheader),1,fNewBmp);//写入位图信息头
 
//由于BMP扫描方式为从上到下,从左到右,window扫描要满足4字节的倍数。读data数据进行修改,存储为BGR顺序
        int tmpRow=((infoheader.biWidth*3+3)>>2)<<2;//调整没行的字节数,使其是4的倍数
#ifdef DEBUG__
        cout<<"((infoheader.biWidth*3+3)>>2)<<2 IS "<<(((infoheader.biWidth*3+3)>>2)<<2)<<endl;
        cout<<"infoheader.biWidth*3 IS "<<infoheader.biWidth*3<<endl;
#endif
       
        jpgbuf = (unsigned char *) malloc(tmpRow);//动态分配缓存内存
        memset(jpgbuf,0,tmpRow);//为缓存内存设置初值
 
        for(int i=0;i<infoheader.biHeight;i++)
        {
              for(int j=0;j<infoheader.biWidth;j++)//将从下到上从左到右读取数据,并将RGB顺寻装换为BGR顺序
              {
              
                       jpgbuf[3*j+0]=data[(infoheader.biHeight-1-i)*row_stride+3*j+2];
                       jpgbuf[3*j+1]=data[(infoheader.biHeight-1-i)*row_stride+3*j+1];
                       jpgbuf[3*j+2]=data[(infoheader.biHeight-1-i)*row_stride+3*j+0];
#ifdef DEBUG__
                      // printf("data(%d,%d,%d),buf(%d,%d,%d)",data[(infoheader.biHeight-1-i)*row_stride+3*j+0],data[(infoheader.biHeight-1-i)*row_stride+3*j+1],data[(infoheader.biHeight-1-i)*row_stride+3*j+2], jpgbuf[3*j+0], jpgbuf[3*j+1], jpgbuf[3*j+2]);
                      
#endif
              }
               fwrite(jpgbuf,sizeof(unsigned char),tmpRow,fNewBmp);//每行的数据写入文件中
        }
        jpeg_finish_decompress(&cinfo);//完成解压过程
        jpeg_destroy_decompress(&cinfo);//释放cinfo
        fclose(fJpeg);
        free(data);
        free(jpgbuf);
        fclose(fNewBmp);
        return;
}


参考:

[置顶] 应用libjpeg提取jpeg质量因子          

C 实现BMP 转换为JPG 附源代码


 

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
用于将jpeg文件转换成为bmp文件, MICROSOFT FOUNDATION CLASS LIBRARY : JpgVSbmp ======================================================================== AppWizard has created this JpgVSbmp DLL for you. This DLL not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your DLL. This file contains a summary of what you will find in each of the files that make up your JpgVSbmp DLL. JpgVSbmp.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. JpgVSbmp.h This is the main header file for the DLL. It declares the CJpgVSbmpApp class. JpgVSbmp.cpp This is the main DLL source file. It contains the class CJpgVSbmpApp. JpgVSbmp.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. JpgVSbmp.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. res\JpgVSbmp.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file. JpgVSbmp.def This file contains information about the DLL that must be provided to run with Microsoft Windows. It defines parameters such as the name and description of the DLL. It also exports functions from the DLL. ///////////////////////////////////////////////////////////////////////////// Other standard files: StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named JpgVSbmp.pch and a precompiled types file named StdAfx.obj. Resource.h This is the standard header file, which defines new resource IDs. Microsoft Visual C++ reads and updates this file. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值