ext/rfreeimage/rfi_main.c in rfreeimage-0.1.0 vs ext/rfreeimage/rfi_main.c in rfreeimage-0.1.1
- old
+ new
@@ -4,10 +4,20 @@
static VALUE rb_mFI;
//static VALUE rb_eFI;
static VALUE Class_Image;
static VALUE Class_RFIError;
+__attribute__((constructor))
+static void __rfi_module_init() {
+ FreeImage_Initialise(FALSE);
+}
+
+__attribute__((destructor))
+static void __rfi_module_uninit() {
+ FreeImage_DeInitialise();
+}
+
static VALUE rb_rfi_version(VALUE self)
{
return rb_ary_new3(3, INT2NUM(FREEIMAGE_MAJOR_VERSION),
INT2NUM(FREEIMAGE_MINOR_VERSION), INT2NUM(FREEIMAGE_RELEASE_SERIAL));
}
@@ -18,18 +28,10 @@
const char *v = FreeImage_GetVersion();
result = rb_str_new(v, strlen(v));
return result;
}
-static VALUE
-file_arg_rescue(VALUE arg)
-{
- rb_raise(rb_eTypeError, "argument must be path name or open file (%s given)",
- rb_class2name(CLASS_OF(arg)));
- return(VALUE)0;
-}
-
struct native_image {
int w;
int h;
int bpp;
int stride;
@@ -58,70 +60,113 @@
static inline char *rfi_value_to_str(VALUE v)
{
char *filename;
long f_len;
+ Check_Type(v, T_STRING);
f_len = RSTRING_LEN(v);
filename = malloc(f_len + 1);
memcpy(filename, RSTRING_PTR(v), f_len);
filename[f_len] = 0;
return filename;
}
+static FIBITMAP *
+convert_bpp(FIBITMAP *orig, unsigned int bpp) {
+ FIBITMAP *h = NULL;
+ switch(bpp) {
+ case 8:
+ h = FreeImage_ConvertToGreyscale(orig);
+ break;
+ case 32:
+ h = FreeImage_ConvertTo32Bits(orig);
+ break;
+ }
+ return h;
+}
+
static void
rd_image(VALUE clazz, VALUE file, struct native_image *img, unsigned int bpp, BOOL ping)
{
char *filename;
+ int flags = 0;
FIBITMAP *h = NULL, *orig = NULL;
FREE_IMAGE_FORMAT in_fif;
- file = rb_rescue(rb_String, file, file_arg_rescue, file);
filename = rfi_value_to_str(file);
in_fif = FreeImage_GetFileType(filename, 0);
if (in_fif == FIF_UNKNOWN) {
free(filename);
rb_raise(rb_eIOError, "Invalid image file");
}
- orig = FreeImage_Load(in_fif, filename, ping ? FIF_LOAD_NOPIXELS : 0 );
+ if (ping) flags |= FIF_LOAD_NOPIXELS;
+ if (in_fif == FIF_JPEG) flags |= JPEG_EXIFROTATE;
+ orig = FreeImage_Load(in_fif, filename, flags);
free(filename);
if (!orig)
rb_raise(rb_eIOError, "Fail to load image file");
- if (FreeImage_GetBPP(orig) == bpp || bpp <= 0 || ping) {
+ if (ping) {
h = orig;
} else {
- switch(bpp) {
- case 8:
- h = FreeImage_ConvertTo8Bits(orig);
- break;
- case 24:
- h = FreeImage_ConvertTo24Bits(orig);
- break;
- case 32:
- h = FreeImage_ConvertTo32Bits(orig);
- break;
- default:
- rb_raise(rb_eArgError, "Invalid bpp");
- }
+ if (bpp <= 0) bpp = 32;
+ h = convert_bpp(orig, bpp);
FreeImage_Unload(orig);
+ if (!h) rb_raise(rb_eArgError, "Invalid bpp");
}
img->handle = h;
img->w = FreeImage_GetWidth(h);
img->h = FreeImage_GetHeight(h);
img->bpp = FreeImage_GetBPP(h);
- img->stride = FreeImage_GetLine(h);
+ img->stride = FreeImage_GetPitch(h);
img->fif = in_fif;
}
+static void
+rd_image_blob(VALUE clazz, VALUE blob, struct native_image *img, unsigned int bpp, BOOL ping)
+{
+ FIBITMAP *h = NULL, *orig = NULL;
+ FIMEMORY *fmh;
+ FREE_IMAGE_FORMAT in_fif;
+
+ Check_Type(blob, T_STRING);
+ fmh = FreeImage_OpenMemory((BYTE*)RSTRING_PTR(blob), RSTRING_LEN(blob));
+
+ in_fif = FreeImage_GetFileTypeFromMemory(fmh, 0);
+ if (in_fif == FIF_UNKNOWN) {
+ FreeImage_CloseMemory(fmh);
+ rb_raise(rb_eIOError, "Invalid image blob");
+ }
+
+ orig = FreeImage_LoadFromMemory(in_fif, fmh, ping ? FIF_LOAD_NOPIXELS : 0 );
+ FreeImage_CloseMemory(fmh);
+ if (!orig)
+ rb_raise(rb_eIOError, "Fail to load image from memory");
+
+ if (ping) {
+ h = orig;
+ } else {
+ if (bpp <= 0) bpp = 32;
+ h = convert_bpp(orig, bpp);
+ FreeImage_Unload(orig);
+ if (!h) rb_raise(rb_eArgError, "Invalid bpp");
+ }
+ img->handle = h;
+ img->w = FreeImage_GetWidth(h);
+ img->h = FreeImage_GetHeight(h);
+ img->bpp = FreeImage_GetBPP(h);
+ img->stride = FreeImage_GetPitch(h);
+ img->fif = in_fif;
+}
+
VALUE Image_initialize(int argc, VALUE *argv, VALUE self)
{
struct native_image* img;
/* unwrap */
Data_Get_Struct(self, struct native_image, img);
- memset(img, 0, sizeof(struct native_image));
switch (argc)
{
case 1:
rd_image(self, argv[0], img, 0, 0);
break;
@@ -147,20 +192,27 @@
FREE_IMAGE_FORMAT out_fif;
Data_Get_Struct(self, struct native_image, img);
RFI_CHECK_IMG(img);
- file = rb_rescue(rb_String, file, file_arg_rescue, file);
+ Check_Type(file, T_STRING);
filename = rfi_value_to_str(file);
out_fif = FreeImage_GetFIFFromFilename(filename);
if (out_fif == FIF_UNKNOWN) {
free(filename);
rb_raise(Class_RFIError, "Invalid format");
}
- result = FreeImage_Save(out_fif, img->handle, filename, 0);
+ if (out_fif == FIF_JPEG && img->bpp != 8 && img->bpp != 24) {
+ FIBITMAP *to_save = FreeImage_ConvertTo24Bits(img->handle);
+ result = FreeImage_Save(out_fif, to_save, filename, JPEG_BASELINE);
+ FreeImage_Unload(to_save);
+ } else {
+ result = FreeImage_Save(out_fif, img->handle, filename, 0);
+ }
+
free(filename);
if(!result)
rb_raise(rb_eIOError, "Fail to save image");
return Qnil;
@@ -217,15 +269,29 @@
VALUE Image_read_bytes(VALUE self)
{
struct native_image* img;
const char *p;
+ char *ptr;
+ unsigned stride_dst;
+ int i;
+ VALUE v;
Data_Get_Struct(self, struct native_image, img);
RFI_CHECK_IMG(img);
p = (const char*)FreeImage_GetBits(img->handle);
- return rb_str_new(p, img->stride * img->h);
+ stride_dst = img->w * (img->bpp / 8);
+ v = rb_str_new(NULL, stride_dst * img->h);
+
+ /* up-side-down */
+ ptr = RSTRING_PTR(v) + img->h * stride_dst;
+ for(i = 0; i < img->h; i++) {
+ ptr -= stride_dst;
+ memcpy(ptr, p, stride_dst);
+ p += img->stride;
+ }
+ return v;
}
VALUE Image_buffer_addr(VALUE self)
{
struct native_image* img;
@@ -249,11 +315,11 @@
{
struct native_image *new_img;
new_img = malloc(sizeof(struct native_image));
memset(new_img, 0, sizeof(struct native_image));
new_img->handle = nh;
- new_img->stride = FreeImage_GetLine(nh);
+ new_img->stride = FreeImage_GetPitch(nh);
new_img->bpp = FreeImage_GetBPP(nh);
new_img->w = FreeImage_GetWidth(nh);
new_img->h = FreeImage_GetHeight(nh);
return Data_Wrap_Struct(Class_Image, NULL, Image_free, new_img);
@@ -264,24 +330,16 @@
struct native_image *img;
FIBITMAP *nh;
int bpp = NUM2INT(_bpp);
Data_Get_Struct(self, struct native_image, img);
RFI_CHECK_IMG(img);
+ if (bpp == img->bpp)
+ return self;
- switch(bpp) {
- case 8:
- nh = FreeImage_ConvertTo8Bits(img->handle);
- break;
- case 24:
- nh = FreeImage_ConvertTo24Bits(img->handle);
- break;
- case 32:
- nh = FreeImage_ConvertTo32Bits(img->handle);
- break;
- default:
- rb_raise(rb_eArgError, "Invalid bpp");
- }
+ nh = convert_bpp(img->handle, bpp);
+ if (!nh) rb_raise(rb_eArgError, "Invalid bpp");
+
return rfi_get_image(nh);
}
VALUE Image_rotate(VALUE self, VALUE _angle)
{
@@ -340,22 +398,119 @@
nh = FreeImage_Copy(img->handle, left, top, right, bottom);
return rfi_get_image(nh);
}
+#define ALLOC_NEW_IMAGE(__v, img) \
+ VALUE __v = Image_alloc(Class_Image); \
+ struct native_image* img; \
+ Data_Get_Struct(__v, struct native_image, img) \
+
VALUE Image_ping(VALUE self, VALUE file)
{
- struct native_image* img = malloc(sizeof(struct native_image));
+ ALLOC_NEW_IMAGE(v, img);
+
rd_image(self, file, img, 0, 1);
+ if (img->handle)
+ FreeImage_Unload(img->handle);
+ img->handle = NULL;
+ return v;
+}
+
+VALUE Image_from_blob(int argc, VALUE *argv, VALUE self)
+{
+ ALLOC_NEW_IMAGE(v, img);
+
+ switch (argc)
+ {
+ case 1:
+ rd_image_blob(self, argv[0], img, 0, 0);
+ break;
+ case 2:
+ rd_image_blob(self, argv[0], img, NUM2INT(argv[1]), 0);
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
+ break;
+ }
+
+ return v;
+}
+
+VALUE Image_ping_blob(VALUE self, VALUE blob)
+{
+ ALLOC_NEW_IMAGE(v, img);
+
+ rd_image_blob(self, blob, img, 0, 1);
if (img->handle)
FreeImage_Unload(img->handle);
img->handle = NULL;
- return Data_Wrap_Struct(Class_Image, NULL, Image_free, img);
+ return v;
}
+/* draw */
+VALUE Image_draw_point(VALUE self, VALUE _x, VALUE _y, VALUE color, VALUE _size)
+{
+ struct native_image* img;
+ int x = NUM2INT(_x);
+ int y = NUM2INT(_y);
+ int size = NUM2INT(_size);
+ int hs = size / 2, i, j;
+ unsigned int bgra = NUM2UINT(color);
+ if (size < 0)
+ rb_raise(rb_eArgError, "Invalid point size: %d", size);
+ Data_Get_Struct(self, struct native_image, img);
+ RFI_CHECK_IMG(img);
+
+ for(i = -hs; i <= hs; i++) {
+ for(j = -hs; j <= hs; j++) {
+ if (i*i + j*j <= hs*hs)
+ FreeImage_SetPixelColor(img->handle, x + i, img->h - (y + j) - 1, (RGBQUAD*)&bgra);
+ }
+ }
+
+ return self;
+}
+
+VALUE Image_draw_rectangle(VALUE self, VALUE _x1, VALUE _y1,
+ VALUE _x2, VALUE _y2,
+ VALUE color, VALUE _width)
+{
+ struct native_image* img;
+ int x1 = NUM2INT(_x1);
+ int y1 = NUM2INT(_y1);
+ int x2 = NUM2INT(_x2);
+ int y2 = NUM2INT(_y2);
+ int size = NUM2INT(_width);
+ int hs = size / 2, i, j;
+ unsigned int bgra = NUM2UINT(color);
+ if (size < 0)
+ rb_raise(rb_eArgError, "Invalid line width: %d", size);
+ Data_Get_Struct(self, struct native_image, img);
+ RFI_CHECK_IMG(img);
+
+ for(i = -hs; i <= hs; i++) {
+ for(j = x1; j <= x2; j++) {
+ FreeImage_SetPixelColor(img->handle, j, img->h - (y1 + i) - 1, (RGBQUAD*)&bgra);
+ FreeImage_SetPixelColor(img->handle, j, img->h - (y2 + i) - 1, (RGBQUAD*)&bgra);
+ }
+ }
+
+ for(i = -hs; i <= hs; i++) {
+ for(j = y1; j <= y2; j++) {
+ FreeImage_SetPixelColor(img->handle, x1 + i, img->h - j - 1, (RGBQUAD*)&bgra);
+ FreeImage_SetPixelColor(img->handle, x2 + i, img->h - j - 1, (RGBQUAD*)&bgra);
+ }
+ }
+
+ return self;
+}
+
+
+
void Init_rfreeimage(void)
{
rb_mFI = rb_define_module("RFreeImage");
rb_define_module_function(rb_mFI, "freeimage_version", rb_rfi_version, 0);
rb_define_module_function(rb_mFI, "freeimage_string_version", rb_rfi_string_version, 0);
@@ -380,10 +535,13 @@
rb_define_method(Class_Image, "to_bpp", Image_to_bpp, 1);
rb_define_method(Class_Image, "rotate", Image_rotate, 1);
rb_define_method(Class_Image, "resize", Image_resize, 2);
rb_define_method(Class_Image, "crop", Image_crop, 4);
- rb_define_singleton_method(Class_Image, "ping", Image_ping, 1);
+ /* draw */
+ rb_define_method(Class_Image, "draw_point", Image_draw_point, 4);
+ rb_define_method(Class_Image, "draw_rectangle", Image_draw_rectangle, 4 + 2);
+ rb_define_singleton_method(Class_Image, "ping", Image_ping, 1);
+ rb_define_singleton_method(Class_Image, "from_blob", Image_from_blob, -1);
+ rb_define_singleton_method(Class_Image, "ping_blob", Image_ping_blob, 1);
}
-
-