libjpegを使って、jpegファイルのRGB値を読み込む拡張ライブラリを作ってみた。
ビルドでワーニングいっぱい。リークしてるかも…
libjpegの情報は以下のページを参考に(というかほぼそのまま…)。
拡張ライブラリの情報は以下のページを参考。
jpeg_loader.c
#include <ruby.h> #include <jpeglib.h> typedef struct { struct jpeg_source_mgr pub; JOCTET * buffer; unsigned long buffer_length; } memory_source_mgr, *memory_src_ptr; METHODDEF(void) memory_init_source(j_decompress_ptr cinfo) {} METHODDEF(void) memory_term_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; } } GLOBAL(void) jpeg_memory_src(j_decompress_ptr cinfo, void* data, unsigned long len) { memory_src_ptr src; if (cinfo->src == NULL) { 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; src->pub.term_source = memory_term_source; src->pub.bytes_in_buffer = len; src->pub.next_input_byte = (JOCTET*)data; } typedef struct _jpeg_source { JSAMPARRAY image; int width; int height; } jpeg_source; static void jpgldr_free(jpeg_source *p) { int i; for (i = 0; i < p->height; i++) { free(p->image[i]); } free(p->image); free(p); } static VALUE jpgldr_s_alloc(VALUE klass) { jpeg_source *p = ALLOC(jpeg_source); return Data_Wrap_Struct(klass, 0, jpgldr_free, p); } static VALUE jpgldr_initialize(VALUE self, VALUE string) { jpeg_source *p; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; unsigned long len; char *source; int i; Check_Type(string, T_STRING); Data_Get_Struct(self, jpeg_source, p); source = RSTRING(string)->ptr; len = RSTRING(string)->len; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_memory_src(&cinfo, source, len); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); p->width = cinfo.output_width; p->height = cinfo.output_height; p->image = (JSAMPARRAY) calloc(p->height, sizeof(JSAMPROW)); for (i = 0; i < p->height; i++) { p->image[i] = (JSAMPROW) calloc(3 * p->width, sizeof(JSAMPLE)); } while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, p->image + cinfo.output_scanline, cinfo.output_height - cinfo.output_scanline); } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return Qnil; } static VALUE jpgldr_get_width(VALUE self) { jpeg_source *p; Data_Get_Struct(self, jpeg_source, p); return INT2FIX(p->width); } static VALUE jpgldr_get_height(VALUE self) { jpeg_source *p; Data_Get_Struct(self, jpeg_source, p); return INT2FIX(p->height); } static VALUE jpgldr_rgb(VALUE self, VALUE x, VALUE y) { int ix, iy; jpeg_source *p; JSAMPLE r, g, b; ix = NUM2INT(x); iy = NUM2INT(y); Data_Get_Struct(self, jpeg_source, p); if(ix < 0 || iy < 0 || ix >= p->width || iy >= p->height) { return Qnil; } r = p->image[iy][ix * 3 + 0]; g = p->image[iy][ix * 3 + 1]; b = p->image[iy][ix * 3 + 2]; return rb_ary_new3(3, INT2FIX(r), INT2FIX(g), INT2FIX(b)); } static VALUE JpegSource; void Init_jpeg_loader() { JpegSource = rb_define_class("JpegSource", rb_cObject); rb_define_alloc_func(JpegSource, jpgldr_s_alloc); rb_define_private_method(JpegSource, "initialize", jpgldr_initialize, 1); rb_define_method(JpegSource, "width", jpgldr_get_width, 0); rb_define_method(JpegSource, "height", jpgldr_get_height, 0); rb_define_method(JpegSource, "rgb", jpgldr_rgb, 2); }
extconf
require 'mkmf' dir_config('jpeg') if have_header('jpeglib.h') and have_library('jpeg') create_makefile('jpeg_loader') end
使う
jpg_src = JpegSource.new(open("src.jpg").read) p jpg_src.rgb(145,145) #=> [1, 126, 254]