ext/rfreeimage/rfi_main.c in rfreeimage-0.1.6 vs ext/rfreeimage/rfi_main.c in rfreeimage-0.1.7

- old
+ new

@@ -83,11 +83,12 @@ } return h; } static void -rd_image(VALUE clazz, VALUE file, struct native_image *img, unsigned int bpp, BOOL ping) +rd_image(VALUE clazz, VALUE file, struct native_image *img, unsigned int bpp, BOOL ping, + int max_size_hint) { char *filename; int flags = 0; FIBITMAP *h = NULL, *orig = NULL; FREE_IMAGE_FORMAT in_fif; @@ -97,12 +98,15 @@ in_fif = FreeImage_GetFileType(filename, 0); if (in_fif == FIF_UNKNOWN) { free(filename); rb_raise(rb_eIOError, "Invalid image file"); } + if (max_size_hint < 0 || max_size_hint > 65535) + rb_raise(rb_eArgError, "Invalid max_size_hint"); if (ping) flags |= FIF_LOAD_NOPIXELS; + if (!ping) flags |= max_size_hint << 16; // use JPEG_ACCURATE to keep sync with opencv if (in_fif == FIF_JPEG) flags |= JPEG_EXIFROTATE | JPEG_ACCURATE; orig = FreeImage_Load(in_fif, filename, flags); free(filename); @@ -123,11 +127,11 @@ 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) +rd_image_blob(VALUE clazz, VALUE blob, struct native_image *img, unsigned int bpp, BOOL ping, int max_size_hint) { FIBITMAP *h = NULL, *orig = NULL; FIMEMORY *fmh; int flags = 0; FREE_IMAGE_FORMAT in_fif; @@ -138,12 +142,15 @@ in_fif = FreeImage_GetFileTypeFromMemory(fmh, 0); if (in_fif == FIF_UNKNOWN) { FreeImage_CloseMemory(fmh); rb_raise(rb_eIOError, "Invalid image blob"); } + if (max_size_hint < 0 || max_size_hint > 65535) + rb_raise(rb_eArgError, "Invalid max_size_hint"); if (ping) flags |= FIF_LOAD_NOPIXELS; + if (!ping) flags |= max_size_hint << 16; if (in_fif == FIF_JPEG) flags |= JPEG_EXIFROTATE | JPEG_ACCURATE; orig = FreeImage_LoadFromMemory(in_fif, fmh, flags); FreeImage_CloseMemory(fmh); if (!orig) @@ -172,15 +179,18 @@ Data_Get_Struct(self, struct native_image, img); switch (argc) { case 1: - rd_image(self, argv[0], img, 0, 0); + rd_image(self, argv[0], img, 0, 0, 0); break; case 2: - rd_image(self, argv[0], img, NUM2INT(argv[1]), 0); + rd_image(self, argv[0], img, NUM2INT(argv[1]), 0, 0); break; + case 3: + rd_image(self, argv[0], img, NUM2INT(argv[1]), 0, NUM2INT(argv[2])); + break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); break; } @@ -435,10 +445,64 @@ nh = FreeImage_Rescale(img->handle, w, h, f); return rfi_get_image(nh); } +VALUE Image_downscale(VALUE self, VALUE max_size) { + // down-sample resize + struct native_image *img; + FIBITMAP *nh; + int i; + int j; + int w; + int h; + int scale; + int mlen; + int msize = NUM2INT(max_size); + + Data_Get_Struct(self, struct native_image, img); + RFI_CHECK_IMG(img); + + mlen = img->w > img->h ? img->w : img->h; + if (msize <= 0 || msize >= mlen) { + nh = FreeImage_Copy(img->handle, 0, 0, img->w, img->h); + } else { + unsigned char *ph; + unsigned char *pnh; + int dst_stride; + if (img->bpp != 8 && img->bpp != 32) + rb_raise(rb_eArgError, "bpp not supported"); + + scale = (mlen + msize - 1) / msize; + w = img->w / scale; + h = img->h / scale; + nh = FreeImage_Allocate(w, h, img->bpp, 0, 0, 0); + if (!nh) + rb_raise(rb_eArgError, "fail to allocate image"); + + ph = FreeImage_GetBits(img->handle); + pnh = FreeImage_GetBits(nh); + dst_stride = FreeImage_GetPitch(nh); + if (img->bpp == 8) { + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) + *(pnh + j) = *(ph + j * scale); + ph += img->stride * scale; + pnh += dst_stride; + } + } else if (img->bpp == 32) { + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) + *((unsigned int*)pnh + j) = *((unsigned int*)ph + j * scale); + ph += img->stride * scale; + pnh += dst_stride; + } + } + } + return rfi_get_image(nh); +} + VALUE Image_crop(VALUE self, VALUE _left, VALUE _top, VALUE _right, VALUE _bottom) { struct native_image *img; FIBITMAP *nh; int left = NUM2INT(_left); @@ -464,11 +528,11 @@ VALUE Image_ping(VALUE self, VALUE file) { ALLOC_NEW_IMAGE(v, img); - rd_image(self, file, img, 0, 1); + rd_image(self, file, img, 0, 1, 0); if (img->handle) FreeImage_Unload(img->handle); img->handle = NULL; return v; @@ -479,15 +543,18 @@ ALLOC_NEW_IMAGE(v, img); switch (argc) { case 1: - rd_image_blob(self, argv[0], img, 0, 0); + rd_image_blob(self, argv[0], img, 0, 0, 0); break; case 2: - rd_image_blob(self, argv[0], img, NUM2INT(argv[1]), 0); + rd_image_blob(self, argv[0], img, NUM2INT(argv[1]), 0, 0); break; + case 3: + rd_image_blob(self, argv[0], img, NUM2INT(argv[1]), 0, NUM2INT(argv[2])); + break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); break; } @@ -496,11 +563,11 @@ VALUE Image_ping_blob(VALUE self, VALUE blob) { ALLOC_NEW_IMAGE(v, img); - rd_image_blob(self, blob, img, 0, 1); + rd_image_blob(self, blob, img, 0, 1, 0); if (img->handle) FreeImage_Unload(img->handle); img->handle = NULL; return v; @@ -633,9 +700,10 @@ rb_define_method(Class_Image, "release", Image_release, 0); 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, "rescale", Image_rescale, 3); + rb_define_method(Class_Image, "downscale", Image_downscale, 1); rb_define_method(Class_Image, "crop", Image_crop, 4); rb_define_method(Class_Image, "to_blob", Image_to_blob, 1); /* draw */ rb_define_method(Class_Image, "draw_point", Image_draw_point, 4);