IJG JPEGライブラリでメモリ上のJPEGを展開する [開発]
JPEGの圧縮・展開ライブラリのスタンダードといえばやはり IJG(http://www.ijg.org/) のJPEGライブラリになるが意外とどこにも載っていないメモリ上のJPEGイメージの展開方法を。
一応 libjpeg のドキュメントには応用すればメモリ上のJPEGも簡単に展開できるよー、みたいな意味の事は書いてあるけどサンプルは載ってない(まあ実際簡単なんだけど)。
まあそういうわけでファイルからの読み込みの初期化部分を調べる。
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
FILE * infile; /* source stream */
JOCTET * buffer; /* start of buffer */
boolean start_of_file; /* have we gotten any data yet? */
} my_source_mgr;
GLOBAL(void)
jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
{
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 = 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->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}
以上が初期化部分。my_source_mgr構造体を確保し、JPEG展開オブジェクト j_decompress.pub の各関数ポインタを設定している。
で、infileにコピーしたファイルの内容をそれぞれの関数で読み込んだりスキップしたりしているわけです。
この部分を参考にメモリ上のデータから直接JPEGデータを受け取れる関数・構造体を作ってみる。
/* メモリソースからのJPEG展開用マネージャ */
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
JOCTET * buffer;
unsigned long buffer_length;
} memory_source_mgr;
typedef memory_source_mgr *memory_src_ptr;
GLOBAL(void)
jpeg_memory_src (j_decompress_ptr cinfo, void* data, unsigned long len)
{
memory_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(memory_source_mgr));
src = (memory_src_ptr) cinfo->src;
src->buffer = (JOCTET *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
len * sizeof(JOCTET));
}
src = (memory_src_ptr) cinfo->src;
src->pub.init_source = memory_init_source;
src->pub.fill_input_buffer = memory_fill_input_buffer;
src->pub.skip_input_data = memory_skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = memory_term_source;
src->pub.bytes_in_buffer = len;
src->pub.next_input_byte = (JOCTET*)data;
}
こんな感じ。で、memory_xxxx を更に作りこむ。とはいっても通常版で行っているファイル操作などは一切必要なくなるので遥かに簡単。
METHODDEF(void) memory_init_source (j_decompress_ptr cinfo)
{
}
METHODDEF(boolean) memory_fill_input_buffer (j_decompress_ptr cinfo)
{
memory_src_ptr src = (memory_src_ptr) cinfo->src;
src->buffer[0] = (JOCTET) 0xFF;
src->buffer[1] = (JOCTET) JPEG_EOI;
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = 2;
return TRUE;
}
METHODDEF(void) memory_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
memory_src_ptr src = (memory_src_ptr) cinfo->src;
if (num_bytes > 0) {
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
METHODDEF(void) memory_term_source (j_decompress_ptr cinfo)
{
}
以上。本来 src->buffer にバッファを用意し、ファイルから切り出したりバイト数を管理したり色々やっている所だけど全部メモリ上にあるとして書けばこれだけで済む。
後は通常の使い方と同じく jpeg_stdio_src() で画像ソースを設定している所を jpeg_memory_src() に置き換えてメモリを渡してやるとメモリ上のデータから直接展開ができる。
トラックバック 2
仕事で必要がありIJGのlibjpegを漁ってみたところ、基本的にstdio経由の入出力しか実装されていないことが判明しげんなり。 libjpeg.docに簡単な説明があるものの、参考になるコードがあまり見つからずどん詰まりしていたところで、 http://blog.so-net.ne…[続く]
You are going to let the fear of poverty govern your life and your reward will be that you will eat, but you will not live.







よろしい!
by sfighter (2006-06-23 10:18)
このソースそのまま自作のオープンソースソフトに取り込みたいのですが、よろしでしょうか? tueda@wolf.dog.cxまでご連絡いただけると幸いです。
by tueda (2011-03-04 19:28)