注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

回首望星辰

See you in the next world

 
 
 

日志

 
 

简单修改libjpeg源代码,实现内存内bmp图像的压缩解压缩  

2009-04-21 16:54:07|  分类: 图形图像开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

改写声明函数
EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, char* outdata, int *pSize));

jdatadst.cpp文件第87行empty_output_buffer (j_compress_ptr cinfo)函数
memcpy(dest->outdata+dest->nOutOffset,dest->buffer,OUTPUT_BUF_SIZE);// 由JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE)改写
dest->nOutOffset+=OUTPUT_BUF_SIZE;
*(dest->pSize)=dest->nOutOffset;

jdatadst.cpp文件第114行term_destination (j_compress_ptr cinfo)
memcpy(dest->outdata+dest->nOutOffset,dest->buffer,datacount);      // 由JFWRITE(dest->outfile, dest->buffer, datacount)改写
dest->nOutOffset+=datacount;
*(dest->pSize)=dest->nOutOffset;

重新编译工程,这样我们就实现了压缩bmp位图到内存中,当然,调用jpeg_stdio_dest之前,我们需要先分配足够的内存,并把内存指针传递给jpeg_stdio_dest函数,
好了,我们再分析libjpeg在解压缩jpg图像时,是怎样从jpg文件读入图像数据的。

我们先看我们在解压缩图像时调用的与文件操作有关的函数,如下:
jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)。
在该函数的实现代码中找到了my_src_ptr结构,并且,我们发现与文件操作有关的该结构的成员变量为infile,参考上面内容,我们搜索infile,搜索结果如下:
Find all "infile", Subfolders, Find Results 1, "Entire Solution"
  E:\VS2005\libjpeg\libjpeg\jpeglib.h(911):EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
  E:\VS2005\libjpeg\libjpeg\jdatasrc.cpp(28):  FILE * infile;  /* source stream */
  E:\VS2005\libjpeg\libjpeg\jdatasrc.cpp(95):  nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
  E:\VS2005\libjpeg\libjpeg\jdatasrc.cpp(182):jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
  E:\VS2005\libjpeg\libjpeg\jdatasrc.cpp(209):  src->infile = infile;
  Matching lines: 5    Matching files: 2    Total files searched: 57

根据上面的经验,我们考虑,除了将FILE *类型变量改为char *类型的变量外,还要添加两个变量,图像大小的变量及图像偏移量,这跟图像压缩时差不多,所不同的是,
图像压缩时,图像大小是由libjpeg库返回,所以在调用是提供给libjpeg库的是个指针,而在解压缩时,图像数据大小是由调用者通过变量(不是指针)提供给libjpeg库。
由于我详细讲解了图像压缩时的我们所做的工作,我想读者朋友们很容易就能理解解压缩时所做的更改,下面我只列出我们所改写的代码,就不再详细讲解了。

jpeglib.h 第911行
EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, char * indata,int nSize));

jdatasrc.cpp 第33行
/* Expanded data source object for stdio input */

typedef struct {
  struct jpeg_source_mgr pub; /* public fields */

  char * indata;  /* source stream */
  int nInOffset;
  int nSize;
  JOCTET * buffer;  /* start of buffer */
  boolean start_of_file; /* have we gotten any data yet? */
} my_source_mgr;

jdatasrc.cpp 第183行
GLOBAL(void)
jpeg_stdio_src (j_decompress_ptr cinfo, char * indata, int nSize)
{
  my_src_ptr src;

  /* The source object and input buffer are made permanent so that a series
   * of JPEG images can be read from the same file by calling jpeg_stdio_src
   * only before the first one.  (If we discarded the buffer at the end of
   * one image, we''d likely lose the start of the next one.)
   * This makes it unsafe to use this manager and a different source
   * manager serially with the same JPEG object.  Caveat programmer.
   */
  if (cinfo->src == NULL) { /* first time for this JPEG object? */
    cinfo->src = (struct jpeg_source_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
      SIZEOF(my_source_mgr));
    src = (my_src_ptr) cinfo->src;
    src->buffer = (JOCTET *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
      INPUT_BUF_SIZE * SIZEOF(JOCTET));
  }

  src = (my_src_ptr) cinfo->src;
  src->pub.init_source = init_source;
  src->pub.fill_input_buffer = fill_input_buffer;
  src->pub.skip_input_data = skip_input_data;
  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
  src->pub.term_source = term_source;
  src->indata = indata;   // 新添加行
  src->nSize = nSize;   // 新添加
  src->nInOffset = 0;   // 新添加
  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
  src->pub.next_input_byte = NULL; /* until buffer loaded */
}

jdatasrc.cpp 第91行
METHODDEF(boolean)
fill_input_buffer (j_decompress_ptr cinfo)
{
  my_src_ptr src = (my_src_ptr) cinfo->src;
  size_t nbytes;

  //nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
  nbytes = src->nSize-src->nInOffset;
  if (nbytes>INPUT_BUF_SIZE) nbytes = INPUT_BUF_SIZE;


  if (nbytes <= 0) {
    if (src->start_of_file) /* Treat empty input file as fatal error */
      ERREXIT(cinfo, JERR_INPUT_EMPTY);
    WARNMS(cinfo, JWRN_JPEG_EOF);
    /* Insert a fake EOI marker */
    src->buffer[0] = (JOCTET) 0xFF;
    src->buffer[1] = (JOCTET) JPEG_EOI;
    nbytes = 2;
  }

  memcpy(src->buffer,src->indata+src->nInOffset,nbytes);
  src->nInOffset+=nbytes;

  src->pub.next_input_byte = src->buffer;
  src->pub.bytes_in_buffer = nbytes;
  src->start_of_file = FALSE;

  return TRUE;
}

至此,libjpeg库的源代码中所有要改的东西我们都已经完成,剩下的事情就是我们编写一段测试程序测试一下。

三、编写测试代码

    对于libjpeg库的详细的调用步骤,请参照我的文章《利用jpeglib压缩图像为jpg格式》,上面详细介绍了利用libjpeg库
进行图像压缩和解压缩的步骤,在编写本例的测试代码时,我们在上次提供的测试代码的基础上进行改进,如下:

    无论压缩还是解压缩,与原来的libjpeg库调用不同的地方都只有一处,就是jpeg_stdio_dest和jpeg_stdio_src这两个函数的调用,
调用原来的libjpeg库时,需要为这两个函数提供已经打开的jpg文件句柄,而对于新的libjpeg库,不需要打开jpg文件了,压缩时,
我们需要提供足够大的内存区给libjpeg 库,解压缩时,只需要把存放有jpeg格式图像的内存区提供给libjpeg库就行了,下面详细介绍
对于改写后的jpeg_stdio_dest和jpeg_stdio_src这两个函数的调用方法。

    1、jpeg_stdio_dest
     函数的原形为:void jpeg_stdio_dest(j_compress_ptr cinfo, char * outData, int *pSize);
     这里,outData指向我们提供给libjpeg库用于存放压缩后图像数据的内存区,这块内存要在我们调用该函数前申请好,大家可以看到,
我们在libjpeg库内没有对该内存区进行越界访问检查并且要足够大,否则会出现内存越界访问的危险,当整个图像压缩工作完成后,pSize
返回jpg图像数据的大小。测试代码如下:
  char outdata[1000000]; // 用于缓存,这里设置为1000K,实际使用时可以采用动态申请的方式
  int nSize; // 用于存放压缩完后图像数据的大小

                ..........
                jpeg_stdio_dest(&jcs, outdata,&nSize);
                ..........

    2、jpeg_stdio_src
     函数的原形为:void jpeg_stdio_src(j_decompress_ptr cinfo, char * inData,int nSize);
     这里,inData指向我们将要进行解压缩的jpg数据,该数据我们可以直接从jpg文件中读取,也可以是通过libjpeg库在内存中直接压缩
生成的数据,nSize 当然是这个jpg数据的大小。测试代码如下:
 ..............
        char indata[1000000]; // 用于存放解压缩前的图像数据,该数据直接从jpg文件读取
        FILE *f = fopen(strSourceFileName,"rb");
 if (f==NULL)
 {
  printf("Open file error!\n");
  return;
 }
 int nSize = fread(outdata,1,1000000,f); // 读取jpg图像数据,nSize为实际读取的图像数据大小
 fclose(f);
 // 下面代码用于解压缩,从本行开始解压缩
 jpeg_stdio_src(&cinfo, outdata,nSize);
 .............


 

  评论这张
 
阅读(2151)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017