将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);

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: libjpeg是一个流行的JPEG图像压缩和解压缩库,可以用于将JPEG图像转换为RGB888格式。 要使用libjpegJPEG图像转换为RGB888,首先需要安装libjpeg库并包含相关的头文件。 使用以下步骤可以实现此功能: 1. 打开JPEG图像文件,使用libjpeg的函数`jpeg_stdio_src`。 2. 调用`jpeg_read_header`函数获取JPEG图像的头文件信息。 3. 设置解压缩参数,包括输出格式。在本例,我们需要将JPEG图像解压缩RGB888格式,因此可以使用`jpeg_set_decompress_parms`函数来设置输出格式。 4. 使用`jpeg_start_decompress`函数开始解压缩过程。 5. 创建一个指向放置解压缩后像素数据的缓冲区的指针。在本例,我们需要将JPEG图像解压缩RGB888格式,因此缓冲区的大小应为图像宽度乘以图像高度乘以3。 6. 使用`jpeg_read_scanlines`函数逐行读取JPEG图像的像素数据,存储在缓冲区。 7. 解压缩完成后,调用`jpeg_finish_decompress`函数完成解压缩过程。 8. 将RGB888格式的像素数据存储在所需的格式,例如,在C语言,可以将像素数据存储在一个三维数组。 9. 最后,使用`jpeg_destroy_decompress`函数销毁解压缩对象。 通过以上步骤,我们可以使用libjpegJPEG图像转换为RGB888格式。 需要注意的是,以上只是实现此功能的基本步骤,实际使用时还需要添加错误处理和其他必要的功能来确保程序的正确性和稳定性。 ### 回答2: libjpeg是一个非常常用的JPEG图像解码库,它可以将JPEG图像解码为其他不同的格式,包括RGB888格式。下面是使用libjpegJPEG转换为RGB888的步骤: 1. 首先,需要安装libjpeg库,并在代码引入相关的头文件。 2. 创建一个jpeg_decompress_struct结构体对象,用于存储解码过程的相关参数。 3. 调用jpeg_CreateDecompress函数初始化jpeg_decompress_struct对象。 4. 使用jpeg_stdio_src函数将源JPEG文件关联到jpeg_decompress_struct对象。 5. 调用jpeg_read_header函数读取JPEG文件的头部信息。 6. 设置解码参数,包括解码模式和输出格式。对于RGB888格式,可以通过设置jpeg_decompress_struct的输出颜色空间和输出全色彩标志来实现。 7. 调用jpeg_start_decompress函数开始解码过程。 8. 使用jpeg_read_scanlines函数逐行读取解码后的RGB像素数据。 9. 将得到的RGB像素数据存储到目标RGB888格式的缓冲区。 10. 最后,调用jpeg_finish_decompress函数结束解码过程,并释放相关资源。 以上是使用libjpegJPEG图像转换为RGB888格式的简要步骤。具体的代码实现会更加复杂,需要进行各种错误处理和内存管理。但使用libjpeg库可以方便地完成这一任务,而无需自己从头开始实现JPEG解码算法。 ### 回答3: libjpeg是一个经典的JPEG图像压缩与解压缩库,可以用于将JPEG图像文件转换为RGB888格式。 使用libjpegJPEG图像转换为RGB888格式的过程如下: 首先,我们需要包含libjpeg库的头文件,并声明所需的变量。JPEG图像的压缩信息将存储在jpeg_decompress_struct结构体,而解压缩的输出数据将存储在jpeg_decompress_struct结构体的jd_output_components变量RGB888格式的数据需要通过指针指向一个unsigned char型的一维数组。 ``` #include <stdio.h> #include <jpeglib.h> int main() { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buffer; unsigned char *rgbData; ... } ``` 接着,我们需要使用libjpeg提供的函数初始化并打开JPEG文件,进行解压缩准备工作。 ``` cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); FILE *infile = fopen("input.jpg", "rb"); if (!infile) { return 0; } jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1); rgbData = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components); ``` 然后,我们需要使用libjpeg提供的函数逐行读取图像数据,并将其存储在我们之前声明的rgbData。 ``` int row = 0; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, buffer, 1); memcpy(rgbData + row * cinfo.output_width * cinfo.output_components, buffer[0], cinfo.output_width * cinfo.output_components); row++; } ``` 最后,我们完成转换后需要进行一些清理工作,关闭文件,释放内存等。 ``` jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); free(rgbData); fclose(infile); ``` 通过以上步骤,我们就可以使用libjpegJPEG图像转换为RGB888格式,最终结果存储在rgbData数组
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值