将RGB数组在内存中压缩成JPEG文件

将RGB数组在内存中压缩成JPEG文件

0.   环境

1)       jpeg库: jpegsr9a  下载地址:http://www.ijg.org/

2)       编译环境: vs2008

3)       Opencv 2.1.0

1.   RGB数组来自BMP文件,直接输出在文件系统上

1.1 代码

void bmptojpg24(const char *strSourceFileName, constchar *strDestFileName)

{

   BITMAPFILEHEADER bfh;    // bmp文件头

   BITMAPINFOHEADER bih;    // bmp头信息

   RGBQUAD rq[256];         // 调色板

   int i=0,j=0;

   int nAdjust;// 用于字节对齐

   int nAdjust24;// 用于字节对齐

 

   BYTE *data=NULL;//new BYTE[bih.biWidth*bih.biHeight];

   BYTE *pData24= NULL;//newBYTE[bih.biWidth*bih.biHeight];

   int nComponent= 0;

 

   // 打开图像文件

   FILE *f= fopen(strSourceFileName,"rb");

   if (f==NULL)

   {

      printf("Open file error!\n");

      return;

   }

   // 读取文件头

   fread(&bfh,sizeof(bfh),1,f);

   // 读取图像信息

   fread(&bih,sizeof(bih),1,f);

   // 8位字节对齐

   nAdjust = bih.biWidth%4;

   if (nAdjust)nAdjust = 4-nAdjust;

   // 24位字节对齐

   nAdjust24 = bih.biWidth*3%4;

   if (nAdjust24)nAdjust24 = 4-nAdjust24;

 

   switch (bih.biBitCount)

   {

   case 8:

      if (bfh.bfOffBits-1024<54)

      {

         fclose(f);

         return;

      }

 

      data= new BYTE[(bih.biWidth+nAdjust)*bih.biHeight];

      pData24 = new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];

 

      // 定位调色板,并读取调色板

      fseek(f,bfh.bfOffBits-1024,SEEK_SET);

      fread(rq,sizeof(RGBQUAD),256,f);

      // 读取位图

      fread(data,bih.biWidth*bih.biHeight,1,f);

      fclose(f);

      nComponent = 3;

      for (j=0;j<bih.biHeight;j++) {

         for (i=0;i<bih.biWidth;i++)

         {

            pData24[j*(bih.biWidth*3+nAdjust24)+i*3] = rq[data[j*(bih.biWidth+nAdjust)+i]].rgbRed;

            pData24[j*(bih.biWidth*3+nAdjust24)+i*3+1] = rq[data[j*(bih.biWidth+nAdjust)+i]].rgbGreen;

            pData24[j*(bih.biWidth*3+nAdjust24)+i*3+2] = rq[data[j*(bih.biWidth+nAdjust)+i]].rgbBlue;

         }

      }

      break;

   case 24:

      {

         data= new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];

         pData24 = new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];

         fseek(f,bfh.bfOffBits,SEEK_SET); 

         fread(data,(bih.biWidth*3+nAdjust24)*bih.biHeight,1,f);

         fclose(f);

         for (j=0;j<bih.biHeight;j++){

            for (i = 0;i<bih.biWidth;i++)

            {

                pData24[j*(bih.biWidth*3+nAdjust24)+i*3]= data[j*(bih.biWidth*3+nAdjust24)+i*3+2];

                pData24[j*(bih.biWidth*3+nAdjust24)+i*3+1]= data[j*(bih.biWidth*3+nAdjust24)+i*3+1];

                pData24[j*(bih.biWidth*3+nAdjust24)+i*3+2]= data[j*(bih.biWidth*3+nAdjust24)+i*3];

            }

         }

         nComponent = 3;

         break;

      }

   default:

      fclose(f);

      return;

   }

 

   // 以上图像读取完毕

 

   cout<<"nAdjust24 = "<<nAdjust24<<endl;

 

   if(IsMemory)

   {

      IMGSTRUCT BMP;

      BMP.Img= pData24;

      BMP.height= bih.biHeight;

      BMP.width= bih.biWidth;

      BMP.nChannel= nComponent;

 

      //cout<<"pData24  is "<<strlen(pData24)<<endl;

      unsigned char *lpDstBuf = new BYTE[(bih.biWidth*3+nAdjust24)*bih.biHeight];

      memset(lpDstBuf,0,(bih.biWidth*3+nAdjust24)*bih.biHeight);

      unsigned long  dwDstBufSize ;

      int quality= 60;

 

      //cout<<"lpDstBuf is"<<strlen(lpDstBuf)<<endl;

      WriteJPEGtoMemory(&BMP,lpDstBuf,dwDstBufSize,quality);

 

      f=fopen(strDestFileName,"wb");

      if (f==NULL)

      {

         delete [] data;

         //delete [] pDataConv;

         return;

      }

      fwrite(lpDstBuf,dwDstBufSize,1,f);

      fclose(f);

      delete [] data;

      delete [] pData24;

      delete [] lpDstBuf;

   }

   else

   {

 

 

      struct jpeg_compress_structjcs;

      struct jpeg_error_mgrjem;

      jcs.err= jpeg_std_error(&jem);

 

      jpeg_create_compress(&jcs);

 

      f=fopen(strDestFileName,"wb");

      if (f==NULL)

      {

         delete [] data;

         //delete [] pDataConv;

         return;

      }

      jpeg_stdio_dest(&jcs, f);

      jcs.image_width= bih.biWidth;      // 为图的宽和高,单位为像素

      jcs.image_height= bih.biHeight;

      jcs.input_components= nComponent;      // 1,表示灰度图,如果是彩色位图,则为

      if (nComponent==1)

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

      else

         jcs.in_color_space = JCS_RGB;

 

      jpeg_set_defaults(&jcs);

      jpeg_set_quality(&jcs, 60, true);

 

      jpeg_start_compress(&jcs, TRUE);

 

      JSAMPROW row_pointer[1];       // 一行位图

      int row_stride;                // 每一行的字节数

 

      row_stride = jcs.image_width*nComponent;    // 如果不是索引图,此处需要乘以

 

      // 对每一行进行压缩

      while (jcs.next_scanline < jcs.image_height) {

         row_pointer[0] = & pData24[(jcs.image_height-jcs.next_scanline-1)* (row_stride+nAdjust24)];

         jpeg_write_scanlines(&jcs, row_pointer,1);

      }

 

      jpeg_finish_compress(&jcs);

 

      jpeg_destroy_compress(&jcs);

 

      fclose(f);

      delete [] data;

      delete [] pData24;

   }

}

1.2    注意

代码中红色标记的代码:

由于BMP图片格式的原因,读入的RGB颜色顺序是BGR形式的,需要调整为RGB顺序:

pData24[j*(bih.biWidth*3+nAdjust24)+i*3]= data[j*(bih.biWidth*3+nAdjust24)+i*3+2];

                pData24[j*(bih.biWidth*3+nAdjust24)+i*3+1]= data[j*(bih.biWidth*3+nAdjust24)+i*3+1];

                pData24[j*(bih.biWidth*3+nAdjust24)+i*3+2]= data[j*(bih.biWidth*3+nAdjust24)+i*3];

 

由于BMP格式中,图片原点是存放在右下角的,所以需要将它颠倒为正序。

row_pointer[0] = & pData24[(jcs.image_height-jcs.next_scanline-1) *(row_stride+nAdjust24)];

2.   RGB数组来自opencv,直接输出在内存

2.1 代码

//直接将bayer格式的图片转化为RGB顺序

cvCvtColor(param.img, dst,CV_BayerBG2RGB);

//申请输出空间并且初始化

unsigned char  * out = new unsignedchar[size.width*size.height*3];

memset(out,0,size.width*size.height*3);

//JPEG长度

unsigned long  dwDstBufSize ;

//图像质量

int quality = 95;

// quality = 100,1024*768RGB图片压缩后是500KB左右

// quality = 95,1024*768RGB图片压缩后是200KB左右

IMGSTRUCT BMP;

BMP.Img = (unsigned char*)dst->imageData;

BMP.height =size.height;

BMP.width = size.width;

BMP.nChannel = 3;

//out中存放是压缩以后jpeg文件的起始地址,dwDstBufSize是文件的长度

WriteJPEGtoMemory(&BMP,out,dwDstBufSize,quality);

 

// pbuf中图像数据JPEG编码到内存中, WriteJPEG的主要区别:用jpeg_mem_dest()替换jpeg_stdio_dest()

bool WriteJPEGtoMemory(IMGSTRUCT *pbuf,unsigned char *lpDstBuf, unsignedlong & dwDstBufSize,int quality)

{

   if (pbuf== NULL) {  

      // MessageBox(NULL,"WriteJPEGtoMemory() -- 传入的图像结构体指针为NULL", "错误", MB_ICONHAND);

      return FALSE;

   }

   if (pbuf->height <= 0 || pbuf->width <= 0 || pbuf->Img <= NULL){

      //MessageBox(NULL, "WriteJPEGtoMemory()-- 图像参数有误!", "错误", MB_ICONHAND);

      return FALSE;

   }

 

   int nbits;

   //定义压缩信息

   struct jpeg_compress_structcinfo;

   //定义错误信息

   struct my_error_mgrjerr;

 

   //JPEG文件压缩对象分配内存并对其初始化

   cinfo.err= jpeg_std_error(&jerr.pub);

   jerr.pub.error_exit = my_error_exit;

   if (setjmp(jerr.setjmp_buffer)){

      jpeg_destroy_compress(&cinfo);

      return FALSE;

   }

   jpeg_create_compress(&cinfo);

 

   //确定要用于输出压缩的jpeg的数据空间

   jpeg_mem_dest(&cinfo, &lpDstBuf,&dwDstBufSize); 

 

   //设置压缩参数

   cinfo.image_width  = pbuf->width;

   cinfo.image_height= pbuf->height;

   if (pbuf->nChannel == 1) {

      cinfo.input_components = nbits= 1; 

      cinfo.in_color_space = JCS_GRAYSCALE;

   }

   else if(pbuf->nChannel== 3) {

      cinfo.input_components = nbits= 3;

      cinfo.in_color_space = JCS_RGB;

   }

   else {

      //MessageBox(NULL,"WriteJPEGFile() -- 传入图像结构体颜色通道不正确!", "错误", MB_ICONHAND);

      jpeg_destroy_compress(&cinfo);

      return FALSE;

   }

 

   jpeg_set_defaults(&cinfo);

   jpeg_set_quality(&cinfo, quality,TRUE );

   //开始压缩

   jpeg_start_compress(&cinfo, TRUE);

 

 

   //JSAMPROW outRow[1];

   BYTE * outRow;

   int i= 0;

   //unsigned char *outRow;

   while (cinfo.next_scanline < cinfo.image_height) {

      outRow = pbuf->Img +(cinfo.next_scanline * pbuf->width * nbits);

      (void)jpeg_write_scanlines(&cinfo, &outRow,1);

      i++;

      //cout<<"i = "<<i<<endl;

 

   }

   cout<<"Memory~"<<endl;

   //完成压缩

   jpeg_finish_compress(&cinfo);

   //释放压缩对象

   jpeg_destroy_compress(&cinfo);

 

   outRow = NULL;

   return TRUE;

}

2.2    说明

由于这里是直接调用opencv的函数,将输入的RGB数组顺序调整正确了。所以在压缩的时候,直接使用

outRow = pbuf->Img + (cinfo.next_scanline* pbuf->width * nbits);

不用在调整顺序了。

在内存中取出这张的图片的时候,可以直接保存成文件。代码如下:

      f=fopen(strDestFileName,"wb");

      if (f==NULL)

      {

         delete [] data;

         //delete [] pDataConv;

         return;

      }

      fwrite(out,dwDstBufSize,1,f);

      fclose(f);

猜你喜欢

转载自blog.csdn.net/zzzzzqf/article/details/37570323