利用libjpeg库解码内存中的jpeg数据

在“VS2013编译libjpeg库”这篇文章中本人介绍了如何在VS中编译libjpeg库并提供了一个应用的范例,而这篇文章将在此基础上,介绍如何用libjpeg库来解码内存中的jpeg数据。

其实这个需求已经不新鲜了,网上也能找到别人提供的一些解决方法,之所以要再次写不过是因为本人觉得那些方法或多或少都有些不对的地方,或者说因为版本的迭代,本来是对的,现在有点问题。当然,本人并没有很费心思的自己去一行一行的看源代码,实现的过程基本是参考这篇文章来做的,所以这里只是提供怎么改,而为什么这么改则可参考上文。

OK,言归正传,下面正式进入主题。

要让libjpeg库能直接解码内存中的jpeg数据,首先想到的自然是修改其源码,让其提供一个这样的函数接口给我们调用,本人也正是这么干的。在“VS2013编译libjpeg库”这篇文章中我们是在生成“jpeg.sln”这个VS工程之后就直接双击进去编译生成“jpeg.lib”这个静态链接库,而我们在这里要实现对其源码的修改,所以在之前需要先改好再编译。修改的内容如下:

找到jdatasrc.c这个文件(从命名可以看出其跟输入数据相关),在my_source_mgr这个结构体的上方添加一个结构体(jpeg内存块描述相关)如下:

typedef struct{
	UINT8* img_buffer;
	long buffer_size;
	long pos;
}BUFF_JPG;

然后将my_source_mgr结构的定义修改如下:

typedef struct {
  struct jpeg_source_mgr pub;	/* public fields */
  union{
	  BUFF_JPG jpg;		/* jpeg image buffer */
	  FILE * infile;		/* source stream */
  };
  JOCTET * buffer;		/* start of buffer */
  boolean start_of_file;	/* have we gotten any data yet? */
} my_source_mgr;

接着在文件中定义相应的回调函数,可先用“Ctrl+F”查找“METHODDEF(boolean)”,然后添加在其上方,代码如下:

/*
* This function will read the jpeg memery block to fill the library buffer.
*/
METHODDEF(boolean)
jpg_fill_input_buffer (j_decompress_ptr cinfo)
{
  my_src_ptr src = (my_src_ptr) cinfo->src;
  size_t nbytes;

  if(src->jpg.img_buffer == NULL || src->jpg.pos >= src->jpg.buffer_size){
    nbytes = -1;
  }
  else {
    nbytes = (src->jpg.pos + INPUT_BUF_SIZE > src->jpg.buffer_size ? 	   	src->jpg.buffer_size - src->jpg.pos : INPUT_BUF_SIZE);
    memcpy(src->buffer, src->jpg.img_buffer + src->jpg.pos, nbytes);
    src->jpg.pos += nbytes;
  }

  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;
  }

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

  return TRUE;
}

做完上面这些,我们需要实现一个供用户用到解码内存中jpeg数据时初始化source
manager的接口,添加位置和上面类似,代码如下:

/*
* This function improve the library can use the jpeg memory block as source.
*/
GLOBAL(void)
jpeg_stdio_buffer_src (j_decompress_ptr cinfo, UINT8 * buffer, long size)
{
  my_src_ptr src;

  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 = jpg_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->infile = infile;
  src->jpg.img_buffer = buffer;
  src->jpg.buffer_size = size;
  src->jpg.pos = 0;
  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
  src->pub.next_input_byte = NULL; /* until buffer loaded */
}

这样我们在jdatasrc.c这个文件所要做的工作就做完了,其实修改的工作也可以说做的八九不离十了,只需要在jpeglib.h文件中将接口暴露出来即可,添加位置也是跟上面很类似的,不再赘述,代码如下:

EXTERN(void) jpeg_stdio_buffer_src JPP((j_decompress_ptr cinfo, UINT8 * buffer, long size));

做完上面这些就大功告成了,编译出来的jpeg.lib已经支持解码内存中的jpeg数据了,jpeg_stdio_buffer_src这个函数就是相应的接口。

下面本人还是提供一个范例,如果懒得去改的话也可以直接用这个范例里面本人编好的“lib”和修改过的“.h”头文件。

范例地址

时间: 2024-08-10 21:20:21

利用libjpeg库解码内存中的jpeg数据的相关文章

libjpeg库解码jpeg图像输出数据排列问题

上一篇文章我们谈到如何修改libjpeg库来解码内存中的jpeg数据这件事情,也确实做到了这一点,然而紧随其后的就发现了一个很蛋疼的问题.因为libjpeg库输出的图像像素是以r-g-b这样的顺序排列的,而在Windows平台上要去显示内存中的图像数据通常是在内存中创建一个位图对象bitmap,然后将要显示的图像数据拷到其相应的位置中,拷贝完成后显示图像.蛋疼的地方就在于bitmap的像素是以b-g-r这样的顺序排列的,这就要求我们在拷贝数据的时候要逐个像素点进行修改,这样做浪费的时间是跟图像的

C# 操作地址 从内存中读取写入数据(初级)

本示例以植物大战僵尸为例, 实现功能为 每1秒让阳光刷新为 9999.本示例使用的游戏版本为 [植物大战僵尸2010年度版], 使用的辅助查看内存地址的工具是  CE. 由于每次启动游戏, 游戏中阳光地址都是变的, 唯一不变的基址1, 我们要通过CE工具找到基址1的地址, 可以算出阳光的地址. 基址2的地址 = 基址1中的值 + 偏移1; 阳光的的地址 = 基址2中的值 + 偏移2; 以下为简单示例:  窗口界面一个按钮 和 一个定时器 using System; using System.Co

caffe使用MemoryDataLayer从内存中加载数据

最近在搞caffe的应用,因为很多时候我们需要进行服务器来进行特征的抽取,所以我们需要很将单张图片丢入caffe的网络进行一次传递,这样就诞生了一个从内存中如何加载数据进入caffe的需求,这里我直接贴出代码来先: #include <boost/make_shared.hpp> // these need to be included after boost on OS X #include <string> // NOLINT(build/include_order) #inc

C# 将内存中的datatable数据导出为Excel(方法一,以文件流方式导出)【转载】

上次做了以Excel文件为数据源,进行数据导入,今天,给大家分享一下如何将内存中的datatable以文件流的方式导出为Excel文件,而且个人觉得这个方法非常不错,高效,简单. 技术要点:1.创建文件流,用于写最终的文件StreamWriter sw = new StreamWriter(fileName, false,Encoding.GetEncoding("gb2312")); 2.使用  StringBuilder类把数据组合为长字符串插入到excel文件中,sb.Appen

如何将内存中的位图数据绘制在DC上

假如你定义了一个位图类,里面包含位图头,位图信息头,调色板,位图数据.然后你按照位图的格式将位图文件读入你的类中,现在你知道了位图的全部信息了.主要信息包含在位图信息头里面,数据则在位图数据缓冲里面.现在的问题是,在Windows下面如何将一张位图画出来,而且现在是如何从数据缓存里面绘画出位图.  一般情况,我们都是直接绘制在dc里面,而不是绑定到子控件,让子控件自己绘画,比如picture控件之类的,我觉得提供绘制在dc里面的接口更具有广泛性. 现在我知道两种从内存数据绘制彩色位图的2种方法.

C# 将内存中的datatable数据导出为Excel(方法二,创建Excel对象导出)【转载】

上次写了一个用文件流方式将Datatable导出Excel的方法,这个方法有局限性,比如没法对Excel进行一些增加列颜色等简单的操作,现在,给大家介绍另外一种方法,用微软的Excel类.既然要用到类,那必须是你的机子要装上Excel才行呢. public  void DataTabletoExcel(System.Data.DataTable[] tmpDataTable,string date1,string date2) { string saveFileName = ""; S

【转】VS2013编译libjpeg库

原文地址:http://blog.csdn.net/weixinhum/article/details/42718959 现在,很多图像处理工具和开源库都给出了图像解码的函数接口,然而有时这些接口并不能完全满足我们的需求,比如如果我们想直接去解码内存中的JPEG数据就没有这样的接口. 由于之前做的项目刚刚好设备传过来的图像数据就是JPEG格式的,如果将每帧图像数据都保存成文件然后再借助开源库提供的接口去读入文件会显得很掉价,所以做了一些直接解码内存中JPEG数据的研究.经过对比发现libjpeg

VS2013编译libjpeg库

现在,很多图像处理工具和开源库都给出了图像解码的函数接口,然而有时这些接口并不能完全满足我们的需求,比如如果我们想直接去解码内存中的JPEG数据就没有这样的接口. 由于之前做的项目刚刚好设备传过来的图像数据就是JPEG格式的,如果将每帧图像数据都保存成文件然后再借助开源库提供的接口去读入文件会显得很掉价,所以做了一些直接解码内存中JPEG数据的研究.经过对比发现libjpeg库对JPEG图像的编解码支持甚好,而且相对于OpenCV库,复杂度小很多,是故就决定动手来实现我自己想要的接口. 所谓"巧

VC++使用CImage在内存中Jpeg转换Bmp图片

VC++中Jpeg与Bmp图片格式互转应该是会经常遇到,Jpeg相比Bmp在图片大小上有很大优势. 本文重点介绍使用现有的CImage类在内存中进行转换,不需要保存为文件,也不需要引入第三方库. Libjpeg库在8以后也支持了内存读取和转换,不过使用起来较为麻烦,还需要手动编译,用CImage类完全可以实现,代码更简洁. 实现方法: VC++对Jpeg.Png图片的操作主要使用CImage,相信很多人用过CImage的Load和Save函数从文件读取或保存Jpeg或Png格式的文件,这两个重载