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

基本思路:利用开源库libjpeg实现将bmp图像转换为jpeg图像,并可以设置jpeg压缩的质量因子。

实验注意事项:

1bmp数据存储时是按照BGR顺序。

2biHeight为正数时表示倒向的位图,读取的顺序为(从左->右,从下->上)

3Windows在进行行扫描的时候最小的单位为4个字节,所以当每行字节数不为4的正数倍时要对字节数进行调整。缺省是每行补0

4:图像位图头信息中的高宽是实际图像的像素点的个数,与存储时需要调整对其数据使其满足4字节的倍数无关。

预备知识:

1bmp格式

参照网址:http://blog.csdn.net/lesky/article/details/22188502

2:利用libjpeg实现jpeg压缩。

参照:http://hi.baidu.com/d_south/blog/item/621285d494e41c09a08bb706.html

3libjpeg参照:

库源文件获取:http://libjpeg.sourceforge.net/

编译:http://blog.csdn.net/subfate/article/details/7037159

实验内容

步骤一:读取bmp文件,并将数据调整为从从上到下、从左到右、RGB顺序。

1:读取bmp文件头和位图头信息


        FILE *fBmp;//bmp文件的句柄

        BITMAPFILEHEADER header;//存储文件头

        memset(&header, 0, sizeof(header));//文件头赋初始值

        BITMAPINFOHEADER infoheader;//位图信息头

        memset(&infoheader, 0, sizeof(infoheader));//赋初始值

        fBmp = fopen(BmpName ,"rb");// 打开要压缩的源文件

        fread(&header,sizeof(unsigned char),sizeof(header),fBmp);//读取头文件

        

        fread(&infoheader,sizeof(unsigned char),sizeof(infoheader),fBmp);//读取位图信息头

        m_iImageWidth = infoheader.biWidth;

         m_iImageHeight = infoheader.biHeight;

         m_iBitsPerPixel = infoheader.biBitCount;

        m_iBytesPerPixel=m_iBitsPerPixel/8;//每个像素点所占的字节数

        //m_iLineByteCnt=m_iImageWidth*m_iBytesPerPixel;

        m_iLineByteCnt=((m_iImageWidth*m_iBytesPerPixel+3)>>2)<<2;//调整每行的字节数为4的整数倍

 
重点:m_iLineByteCnt=((m_iImageWidth*m_iBytesPerPixel+3)>>2)<<2;//调整每行的字节数为4的整数倍

2:读取并调整数据的存储顺序

m_pLineData=new unsigned char [m_iLineByteCnt];//动态分配空间存储每行图像数据

        m_iImageDataSize=m_iLineByteCnt* m_iImageHeight;

        m_pImageData= new unsigned char[m_iImageDataSize];//动态分配空间存储图像数据

 if((m_iBytesPerPixel==3)&&( m_iImageHeight >0))//暂时只处理3通道bmp图像且倒向存储

 {

          for(int scanLine=0;scanLine<m_iImageHeight;scanLine++)

          {

                       fread(m_pLineData,sizeof(unsigned char),m_iLineByteCnt ,fBmp);//读取第一行数据

                       for(int tmpCol=0;tmpCol<m_iImageWidth;tmpCol++ ) 

                       {

                         m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+0]=m_pLineData[tmpCol*3+2];

                         m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+1]=m_pLineData[tmpCol*3+1];

                         m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+2]=m_pLineData[tmpCol*3+0];

                       }//调整数据存储顺序(BGR->RGB,从下到上->从上到下)

 

 

          }

 }


步骤二:对步骤一得到的数据进行jpeg压缩,将调用libjpeg库

1:参数的设置等准备

/使用IJP提供的libjpeg库对数据进行压缩///

 

        jpeg_create_compress (&cinfo);// 初始化jpeg压缩对象

 

        fJpeg=fopen(JpegName,"wb");

        

        if(!fJpeg)

        {

               printf("ERROR1: Can not open the jpeg  image   .\n"); 

        return NULL;  

        }       

         jpeg_stdio_dest(&cinfo, fJpeg);  //指定压缩后的图像所存放的目标文件 ,二进制打开

        

 

 

    //        设置压缩参数,主要参数有图像宽、高、色彩通道数(1:索引图像,3:其他), 

    //        色彩空间(JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像),压缩质量 

 

    cinfo.image_width = m_iImageWidth;              // 为图的宽和高,单位为像素 

    cinfo.image_height =  m_iImageHeight; 

    cinfo.input_components = 3;         // 在此为1,表示灰度图, 如果是彩色位图,则为3 

    cinfo.in_color_space = JCS_RGB;   //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像 

        

    jpeg_set_defaults(&cinfo);   // 调用jpeg_set_defaults函数后,jpeglib库采用默认的设置对图像进行压缩 

 

    jpeg_set_quality(&cinfo, QUALITY_FACTOR , TRUE ); // jpeglib库采用默认的设置对图像进行压缩

 

    jpeg_start_compress(&cinfo, TRUE);


2:逐行写入数据(核心)

    while (cinfo.next_scanline < cinfo.image_height)

        {

               for(int j=0;j<m_iLineByteCnt;j++)

               {

                m_pLineData[j]=m_pImageData[cinfo.next_scanline*m_iLineByteCnt+j];

               }

                row_pointer[0]=m_pLineData;

                jpeg_write_scanlines(&cinfo, row_pointer, 1);

 

        }

        jpeg_finish_compress(&cinfo);   


源代码:

 

unsigned char * BmpToJpeg(char * BmpName,char * JpegName,int QUALITY_FACTOR)

{

    FILE *fBmp;//bmp文件的句柄

        FILE *fJpeg;//目标jpeg文件的句柄

        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;//图像数据的总字节数

        unsigned char * m_pImageData;//存放RGB数据

        unsigned char * m_pLineData;//存储每行的数据

        struct jpeg_compress_struct cinfo;//申请并初始化jpeg压缩对象

        struct jpeg_error_mgr jerr;   

        JSAMPROW row_pointer[1];            // 一行位图, 指向JSAMPLE row[s]

        cinfo.err=jpeg_std_error (&jerr);

 

        fBmp = fopen(BmpName ,"rb");// 打开要压缩的源文件

        

        if(!fBmp)  

    {  

        printf("ERROR1: Can not open the bmp image.\n");  

        return NULL;  

    }  

 

        fread(&header,sizeof(unsigned char),sizeof(header),fBmp);//读取头文件

        

        fread(&infoheader,sizeof(unsigned char),sizeof(infoheader),fBmp);//读取位图信息头

 

        if(header.bfType != 0x4D42)

          {

                 cout<<"the type of img is not BMP"<<endl;

                       return NULL;

          }//通过头文件判断是否是bmp格式

        m_iImageWidth = infoheader.biWidth;

    m_iImageHeight = infoheader.biHeight;

    m_iBitsPerPixel = infoheader.biBitCount;

        m_iBytesPerPixel=m_iBitsPerPixel/8;//每个像素点所占的字节数

        //m_iLineByteCnt=m_iImageWidth*m_iBytesPerPixel;

        m_iLineByteCnt=((m_iImageWidth*m_iBytesPerPixel+3)>>2)<<2;//调整每行的字节数为4的整数倍

#ifdef DEBUG__

        cout<<"m_iLineByteCnt IS "<<m_iLineByteCnt<<endl;

#endif

        m_pLineData=new unsigned char [m_iLineByteCnt];//动态分配空间存储每行图像数据

        m_iImageDataSize=m_iLineByteCnt* m_iImageHeight;

        m_pImageData= new unsigned char[m_iImageDataSize];//动态分配空间存储图像数据

#ifdef DEBUG__

          cout<<"header.bfType IS "<<header.bfType<<endl;

          cout<<"infoheader.biSize IS "<<infoheader.biSize<<endl;

          cout<<"infoheader.biWidth IS "<<infoheader.biWidth<<endl;

          cout<<"infoheader.biHeight IS "<<infoheader.biHeight<<endl;

          cout<<"infoheader.biBitCount IS "<<infoheader.biBitCount<<endl;

          cout<<"m_iLineByteCnt IS "<<m_iLineByteCnt<<endl;

#endif

 if((m_iBytesPerPixel==3)&&( m_iImageHeight >0))//暂时只处理3通道bmp图像且倒向存储

 {

          for(int scanLine=0;scanLine<m_iImageHeight;scanLine++)

          {

                       fread(m_pLineData,sizeof(unsigned char),m_iLineByteCnt ,fBmp);//读取第一行数据

                       for(int tmpCol=0;tmpCol<m_iImageWidth;tmpCol++ ) 

                       {

                         m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+0]=m_pLineData[tmpCol*3+2];

                         m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+1]=m_pLineData[tmpCol*3+1];

                         m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+2]=m_pLineData[tmpCol*3+0];

#ifdef DEBUG__

        //      printf("(%d,%d,%d)(%d,%d,%d)",m_pLineData[tmpCol*3+0],m_pLineData[tmpCol*3*3+1],m_pLineData[tmpCol*3+2],m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+0],m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+1],m_pImageData[(m_iImageHeight-1-scanLine)*m_iLineByteCnt+tmpCol*3+2]);

#endif

 

                       }//调整数据存储顺序(BGR->RGB,从下到上->从上到下)

 

 

          }

 }

/使用IJP提供的libjpeg库对数据进行压缩///

 

        jpeg_create_compress (&cinfo);// 初始化jpeg压缩对象

 

        fJpeg=fopen(JpegName,"wb");

        

        if(!fJpeg)

        {

               printf("ERROR1: Can not open the jpeg  image   .\n"); 

        return NULL;  

        }       

         jpeg_stdio_dest(&cinfo, fJpeg);  //指定压缩后的图像所存放的目标文件 ,二进制打开

        

 

 

    //        设置压缩参数,主要参数有图像宽、高、色彩通道数(1:索引图像,3:其他), 

    //        色彩空间(JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像),压缩质量 

 

       cinfo.image_width = m_iImageWidth;              // 为图的宽和高,单位为像素 

    cinfo.image_height =  m_iImageHeight; 

    cinfo.input_components = 3;         // 在此为1,表示灰度图, 如果是彩色位图,则为3 

    cinfo.in_color_space = JCS_RGB;   //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像 

        

    jpeg_set_defaults(&cinfo);   // 调用jpeg_set_defaults函数后,jpeglib库采用默认的设置对图像进行压缩 

 

     jpeg_set_quality(&cinfo, QUALITY_FACTOR , TRUE ); // jpeglib库采用默认的设置对图像进行压缩

 

        jpeg_start_compress(&cinfo, TRUE);

 

        while (cinfo.next_scanline < cinfo.image_height)

        {

#ifdef DEBUG__         

               //cout<<"cinfo.next_scanline before jpeg_write_scanlines IS "<<cinfo.next_scanline<<endl;

#endif

               for(int j=0;j<m_iLineByteCnt;j++)

               {

                m_pLineData[j]=m_pImageData[cinfo.next_scanline*m_iLineByteCnt+j];

               }

                row_pointer[0]=m_pLineData;

                jpeg_write_scanlines(&cinfo, row_pointer, 1);

#ifdef DEBUG__

                //cout<<"cinfo.next_scanline after jpeg_write_scanlines IS "<<cinfo.next_scanline<<endl;

#endif

 

        }

 jpeg_finish_compress(&cinfo);   

 

        free(m_pLineData);//释放内存

        fclose(fJpeg);

        fclose(fBmp);

 

        return  m_pImageData;//返回存储RGB的数据的指针

}

相关文章:

           [置顶] C实现jpg转换为BMP 附源文件

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


    

 

 

 

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值