1. 程式人生 > >利用libjpeg庫解碼記憶體中的jpeg資料

利用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”標頭檔案。

    範例地址