ext/RMagick/rmimage.c in rmagick-1.9.3 vs ext/RMagick/rmimage.c in rmagick-1.10.0
- old
+ new
@@ -1,8 +1,8 @@
-/* $Id: rmimage.c,v 1.123 2005/09/26 23:37:04 rmagick Exp $ */
+/* $Id: rmimage.c,v 1.139 2006/01/18 00:22:33 rmagick Exp $ */
/*============================================================================\
-| Copyright (C) 2005 by Timothy P. Hunter
+| Copyright (C) 2006 by Timothy P. Hunter
| Name: rmimage.c
| Author: Tim Hunter
| Purpose: Image class method definitions for RMagick
\============================================================================*/
@@ -24,11 +24,11 @@
typedef unsigned int (thresholder_t)(Image *, const char *);
typedef Image *(xformer_t)(const Image *, const RectangleInfo *, ExceptionInfo *);
static VALUE effect_image(VALUE, int, VALUE *, effector_t *);
static VALUE rd_image(VALUE, VALUE, reader_t);
-static VALUE scale_image(int, int, VALUE *, VALUE, scaler_t *);
+static VALUE scale(int, int, VALUE *, VALUE, scaler_t *);
static VALUE cropper(int, int, VALUE *, VALUE);
static VALUE xform_image(int, VALUE, VALUE, VALUE, VALUE, VALUE, xformer_t);
static VALUE threshold_image(int, VALUE *, VALUE, thresholder_t);
static VALUE array_from_images(Image *);
static ChannelType extract_channels(int *, VALUE *);
@@ -45,11 +45,10 @@
Returns: a new image
*/
VALUE
Image_adaptive_threshold(int argc, VALUE *argv, VALUE self)
{
-#ifdef HAVE_ADAPTIVETHRESHOLDIMAGE
Image *image, *new_image;
unsigned long width = 3, height = 3, offset = 0;
ExceptionInfo exception;
switch (argc)
@@ -70,14 +69,10 @@
GetExceptionInfo(&exception);
new_image = AdaptiveThresholdImage(image, width, height, offset, &exception);
HANDLE_ERROR
return rm_image_new(new_image);
-#else
- rm_not_implemented();
- return (VALUE)0;
-#endif
}
/*
Method: Image#add_noise(noise_type)
Purpose: add random noise to a copy of the image
@@ -85,23 +80,65 @@
*/
VALUE
Image_add_noise(VALUE self, VALUE noise)
{
Image *image, *new_image;
- NoiseType nt;
+ NoiseType noise_type;
ExceptionInfo exception;
Data_Get_Struct(self, Image, image);
+
GetExceptionInfo(&exception);
+ VALUE_TO_ENUM(noise, noise_type, NoiseType);
- VALUE_TO_ENUM(noise, nt, NoiseType);
- new_image = AddNoiseImage(image, nt, &exception);
+ new_image = AddNoiseImage(image, noise_type, &exception);
HANDLE_ERROR
return rm_image_new(new_image);
}
/*
+ Method: Image#add_noise_channel(noise_type[,channel...])
+ Purpose: add random noise to a copy of the image
+ Returns: a new image
+*/
+VALUE
+Image_add_noise_channel(int argc, VALUE *argv, VALUE self)
+{
+#if defined(HAVE_ADDNOISEIMAGECHANNEL)
+ Image *image, *new_image;
+ NoiseType noise_type;
+ ExceptionInfo exception;
+ ChannelType channels;
+
+ channels = extract_channels(&argc, argv);
+
+ // There must be 1 remaining argument.
+ if (argc == 0)
+ {
+ rb_raise(rb_eArgError, "missing noise type argument");
+ }
+ else if (argc > 1)
+ {
+ raise_ChannelType_error(argv[argc-1]);
+ }
+
+ Data_Get_Struct(self, Image, image);
+ GetExceptionInfo(&exception);
+ VALUE_TO_ENUM(argv[0], noise_type, NoiseType);
+ channels &= ~OpacityChannel;
+
+ new_image = AddNoiseImageChannel(image, channels, noise_type, &exception);
+ HANDLE_ERROR
+ return rm_image_new(new_image);
+
+#else
+ rm_not_implemented();
+ return (VALUE)0;
+#endif
+}
+
+/*
Method: Image#affine_transform(affine_matrix)
Purpose: transforms an image as dictated by the affine matrix argument
Returns: a new image
*/
VALUE
@@ -632,11 +669,11 @@
rb_ary_store(ary, 1, ULONG2NUM(rect.height));
rb_ary_store(ary, 2, self);
return rb_yield(ary);
-#elif defined(HAVE_GETMAGICKGEOMETRY)
+#else
Image *image;
char *geometry;
unsigned int flags;
long x, y;
unsigned long width, height;
@@ -661,13 +698,10 @@
rb_ary_store(ary, 1, ULONG2NUM(height));
rb_ary_store(ary, 2, self);
return rb_yield(ary);
-#else
- rm_not_implemented();
- return (VALUE)0;
#endif
}
/*
@@ -1244,21 +1278,21 @@
profile = rb_str_new2(str);
DestroyString(str);
}
#else /* !defined(HAVE_ACQUIRESTRINGINFO) */
- const char *str;
+ const unsigned char *str;
size_t length;
Data_Get_Struct(self, Image, image);
profile = Qnil; /* Assume no profile defined */
length = 0;
str = GetImageProfile(image, "icc", &length);
if (str)
{
- profile = rb_str_new(str, length);
+ profile = rb_str_new((char *)str, length);
}
#endif
#else
@@ -1353,11 +1387,11 @@
{
(void) SetImageProfile(image, "icc", NULL, 0);
}
else
{
- prof = STRING_PTR_LEN(profile, prof_l);
+ prof = (unsigned char *)STRING_PTR_LEN(profile, prof_l);
(void) SetImageProfile(image, "icc", prof, (size_t)prof_l);
}
#endif /* defined(HAVE_SETIMAGEPROFILE) */
#else
@@ -2111,11 +2145,15 @@
{
rb_raise(rb_eNoMemError, "not enough memory to continue.");
}
image->columns = width;
image->rows = height;
+#if defined(HAVE_SETIMAGEBACKGROUNDCOLOR)
+ SetImageBackgroundColor(image);
+#else
SetImage(image, OpaqueOpacity);
+#endif
okay = ImportImagePixels(image, 0, 0, width, height, map, stg_type, (void *)pixels.v);
if (!okay)
{
// Save exception info, delete the image, then raise the exception.
exception = image->exception;
@@ -2975,54 +3013,69 @@
{
Image *image;
rm_check_frozen(self);
Data_Get_Struct(self, Image, image);
+
+#if defined(HAVE_SETIMAGEBACKGROUNDCOLOR)
+ SetImageBackgroundColor(image);
+#else
SetImage(image, OpaqueOpacity);
+#endif
return self;
}
/*
- Method: Image#export_pixels
+ Method: Image#export_pixels(x=0, y=0, cols=self.columns, rows=self.rows, map="RGB")
Purpose: extract image pixels in the form of an array
*/
VALUE
-Image_export_pixels(
- VALUE self,
- VALUE x_arg,
- VALUE y_arg,
- VALUE cols_arg,
- VALUE rows_arg,
- VALUE map_arg)
+Image_export_pixels(int argc, VALUE *argv, VALUE self)
{
#if defined(HAVE_EXPORTIMAGEPIXELS)
Image *image;
- long x_off, y_off;
+ long x_off = 0L, y_off = 0L;
unsigned long cols, rows;
unsigned long n, npixels;
unsigned int okay;
- char *map;
+ char *map = "RGB";
volatile unsigned int *pixels;
volatile VALUE ary;
ExceptionInfo exception;
Data_Get_Struct(self, Image, image);
- x_off = NUM2LONG(x_arg);
- y_off = NUM2LONG(y_arg);
- cols = NUM2ULONG(cols_arg);
- rows = NUM2ULONG(rows_arg);
+ cols = image->columns;
+ rows = image->rows;
+ switch (argc)
+ {
+ case 5:
+ map = STRING_PTR(argv[4]);
+ case 4:
+ rows = NUM2ULONG(argv[3]);
+ case 3:
+ cols = NUM2ULONG(argv[2]);
+ case 2:
+ y_off = NUM2LONG(argv[1]);
+ case 1:
+ x_off = NUM2LONG(argv[0]);
+ case 0:
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 to 5)", argc);
+ break;
+ }
+
if ( x_off < 0 || x_off > image->columns
|| y_off < 0 || y_off > image->rows
|| cols == 0 || rows == 0)
{
rb_raise(rb_eArgError, "invalid extract geometry");
}
- map = STRING_PTR(map_arg);
npixels = cols * rows * strlen(map);
pixels = ALLOC_N(unsigned int, npixels);
if (!pixels) // app recovered from exception
{
@@ -3056,10 +3109,122 @@
return (VALUE)0;
#endif
}
/*
+ Method: Image#export_pixels_to_str(x=0, y=0, cols=self.columns,
+ rows=self.rows, map="RGB", type=Magick::CharPixel)
+ Purpose: extract image pixels to a Ruby string
+*/
+VALUE
+Image_export_pixels_to_str(int argc, VALUE *argv, VALUE self)
+{
+#if defined(HAVE_EXPORTIMAGEPIXELS)
+ Image *image;
+ long x_off = 0L, y_off = 0L;
+ unsigned long cols, rows;
+ unsigned long npixels;
+ size_t sz;
+ unsigned int okay;
+ char *map = "RGB";
+ StorageType type = CharPixel;
+ volatile VALUE string;
+ char *str;
+ ExceptionInfo exception;
+
+ Data_Get_Struct(self, Image, image);
+ cols = image->columns;
+ rows = image->rows;
+
+ switch (argc)
+ {
+ case 6:
+ VALUE_TO_ENUM(argv[5], type, StorageType);
+ case 5:
+ map = STRING_PTR(argv[4]);
+ case 4:
+ rows = NUM2ULONG(argv[3]);
+ case 3:
+ cols = NUM2ULONG(argv[2]);
+ case 2:
+ y_off = NUM2LONG(argv[1]);
+ case 1:
+ x_off = NUM2LONG(argv[0]);
+ case 0:
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 to 6)", argc);
+ break;
+ }
+
+ if ( x_off < 0 || x_off > image->columns
+ || y_off < 0 || y_off > image->rows
+ || cols == 0 || rows == 0)
+ {
+ rb_raise(rb_eArgError, "invalid extract geometry");
+ }
+
+
+ npixels = cols * rows * strlen(map);
+ switch (type)
+ {
+ case CharPixel:
+ sz = sizeof(unsigned char);
+ break;
+ case ShortPixel:
+ sz = sizeof(unsigned short);
+ break;
+ case DoublePixel:
+ sz = sizeof(double);
+ break;
+ case FloatPixel:
+ sz = sizeof(float);
+ break;
+ case IntegerPixel:
+ sz = sizeof(unsigned int);
+ break;
+ case LongPixel:
+ sz = sizeof(unsigned long);
+ break;
+#if defined(HAVE_QUANTUMPIXEL)
+ case QuantumPixel:
+ sz = sizeof(Quantum);
+ break;
+#endif
+ case UndefinedPixel:
+ default:
+ rb_raise(rb_eArgError, "undefined storage type");
+ break;
+ }
+
+ // Allocate a string long enough to hold the exported pixel data.
+ // Get a pointer to the buffer.
+ string = rb_str_new2("");
+ rb_str_resize(string, (long)(sz * npixels));
+ str = STRING_PTR(string);
+
+ GetExceptionInfo(&exception);
+
+ okay = ExportImagePixels(image, x_off, y_off, cols, rows, map, type, (void *)str, &exception);
+ if (!okay)
+ {
+ // Let GC have the string buffer.
+ rb_str_resize(string, 0);
+ HANDLE_ERROR
+ // Should never get here...
+ rb_raise(rb_eStandardError, "ExportImagePixels failed with no explanation.");
+ }
+
+ return string;
+
+#else
+ rm_not_implemented();
+ return (VALUE)0;
+#endif
+}
+
+/*
Method: Image#extract_info, extract_info=
Purpose: the extract_info attribute accessors
*/
VALUE
Image_extract_info(VALUE self)
@@ -3758,11 +3923,11 @@
*/
VALUE
Image_import_pixels(int argc, VALUE *argv, VALUE self)
{
#if defined(HAVE_IMPORTIMAGEPIXELS)
- Image *image, *clone_image;
+ Image *image;
long x_off, y_off;
unsigned long cols, rows;
unsigned long npixels;
long n, buffer_l;
char *map;
@@ -3770,11 +3935,10 @@
StorageType stg_type = CharPixel;
size_t type_sz, map_l;
volatile int *pixels = NULL;
volatile void *buffer;
unsigned int okay;
- ExceptionInfo exception;
rm_check_frozen(self);
switch (argc)
{
@@ -3881,35 +4045,25 @@
buffer = (void *) pixels;
stg_type = IntegerPixel;
}
- // Import into a clone - ImportImagePixels destroys the input image if an error occurs.
- GetExceptionInfo(&exception);
- clone_image = CloneImage(image, 0, 0, True, &exception);
- HANDLE_ERROR
+ okay = ImportImagePixels(image, x_off, y_off, cols, rows, map, stg_type, (const void *)buffer);
- okay = ImportImagePixels(clone_image, x_off, y_off, cols, rows, map, stg_type, (const void *)buffer);
-
- // Free pixel array before checking for errors. If an error occurred, ImportImagePixels
- // destroyed the clone image, so we don't have to.
+ // Free pixel array before checking for errors.
if (pixels)
{
xfree((void *)pixels);
}
if (!okay)
{
- HANDLE_ERROR_IMG(clone_image)
+ HANDLE_ERROR_IMG(image)
// Shouldn't get here...
rb_raise(rb_eStandardError, "ImportImagePixels failed with no explanation.");
}
- // Everything worked. Replace the image with the clone and destroy the original.
- DATA_PTR(self) = clone_image;
- DestroyImage(image);
-
return self;
#else
rm_not_implemented();
return (VALUE)0;
@@ -3940,15 +4094,11 @@
x += sprintf(buffer+x, "%s=>", image->magick_filename);
}
// Print current filename.
x += sprintf(buffer+x, "%s", image->filename);
// Print scene number.
-#if defined(HAVE_GETNEXTIMAGEINLIST)
if ((GetPreviousImageInList(image) != NULL) && (GetNextImageInList(image) != NULL) && image->scene > 0)
-#else
- if ((image->previous || image->next) && image->scene > 0)
-#endif
{
x += sprintf(buffer+x, "[%lu]", image->scene);
}
// Print format
x += sprintf(buffer+x, " %s ", image->magick);
@@ -4121,11 +4271,11 @@
profile = Qnil; /* Assume no profile defined */
prof = GetImageProfile(image, "iptc", &length);
if (prof)
{
- profile = rb_str_new(prof, (long) length);
+ profile = rb_str_new((char *)prof, (long) length);
}
#endif
#else
@@ -4218,11 +4368,11 @@
{
(void) SetImageProfile(image, "iptc", NULL, 0);
}
else
{
- prof = STRING_PTR_LEN(profile, prof_l);
+ prof = (unsigned char *)STRING_PTR_LEN(profile, prof_l);
(void) SetImageProfile(image, "iptc", prof, (size_t)prof_l);
}
#endif
#else
@@ -4309,11 +4459,10 @@
Notes: black and white are 0-MaxRGB, mid is 0-10.
*/
VALUE
Image_level_channel(int argc, VALUE *argv, VALUE self)
{
-#ifdef HAVE_LEVELIMAGECHANNEL
Image *image, *new_image;
double black_point = 0.0, mid_point = 1.0, white_point = (double)MaxRGB;
ChannelType channel;
ExceptionInfo exception;
@@ -4351,14 +4500,10 @@
, black_point
, mid_point
, white_point);
HANDLE_ERROR_IMG(new_image)
return rm_image_new(new_image);
-#else
- rm_not_implemented();
- return (VALUE)0;
-#endif
}
/*
Method: Image._load
Purpose: implement marshalling
@@ -4983,11 +5128,15 @@
// If the caller did not supply a fill argument, call SetImage to fill the
// image using the background color. The background color can be set by
// specifying it when creating the Info parm block.
if (!fill)
{
+#if defined(HAVE_SETIMAGEBACKGROUNDCOLOR)
+ SetImageBackgroundColor(image);
+#else
SetImage(image, OpaqueOpacity);
+#endif
}
// fillobj.fill(self)
else
{
(void) rb_funcall(fill, ID_fill, 1, self);
@@ -5252,27 +5401,58 @@
HANDLE_ERROR
return r ? Qtrue : Qfalse;
}
/*
- Method: Image#ordered_dither
- Purpose: call OrderedDitherImage
+ Method: Image#ordered_dither(order=2)
+ Purpose: perform ordered dither on image
+ Notes: order must be 2, 3, or 4
+ I don't call OrderedDitherImages anymore. Sometime after
+ IM 6.0.0 it quit working. IM and GM use the routines I use
+ below to implement the "ordered-dither" option.
*/
VALUE
-Image_ordered_dither(VALUE self)
+Image_ordered_dither(int argc, VALUE *argv, VALUE self)
{
Image *image, *new_image;
+ int order;
+ const char *thresholds = "2x2";
ExceptionInfo exception;
+ if (argc > 1)
+ {
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
+ }
+ if (argc == 1)
+ {
+ order = NUM2INT(argv[0]);
+ if (order == 3)
+ {
+ thresholds = "3x3";
+ }
+ else if (order == 4)
+ {
+ thresholds = "4x4";
+ }
+ else if (order != 2)
+ {
+ rb_raise(rb_eArgError, "order must be 2, 3, or 4 (%d given)", order);
+ }
+ }
+
+
Data_Get_Struct(self, Image, image);
GetExceptionInfo(&exception);
new_image = CloneImage(image, 0, 0, True, &exception);
HANDLE_ERROR
-
- (void) OrderedDitherImage(new_image);
- HANDLE_ERROR_IMG(new_image)
+#if defined(HAVE_RANDOMTHRESHOLDIMAGECHANNEL)
+ (void) RandomThresholdImageChannel(new_image, AllChannels, thresholds, &exception);
+#else
+ (void) RandomChannelThresholdImage(new_image, "all", thresholds, &exception);
+#endif
+ HANDLE_ERROR
return rm_image_new(new_image);
}
/*
Method: Image#orientation
@@ -6172,22 +6352,15 @@
Image *image, *next;
// Orphan the image, create an Image object, add it to the array.
image_ary = rb_ary_new();
- #ifdef HAVE_REMOVEFIRSTIMAGEFROMLIST
+ next = NULL;
next = next; // defeat "never referenced" message from icc
while (images)
{
image = RemoveFirstImageFromList(&images);
-
- #else
- for (image = images; image; image = next)
- {
- next = images->next;
- image->next = image->previous = NULL;
- #endif
image_obj = rm_image_new(image);
rb_ary_push(image_ary, image_obj);
}
return image_ary;
@@ -6256,11 +6429,11 @@
{
Image *image, *new_image;
double scale;
FilterTypes filter;
unsigned long rows, columns;
- double blur;
+ double blur, drows, dcols;
ExceptionInfo exception;
Data_Get_Struct(self, Image, image);
// Set up defaults
@@ -6276,15 +6449,29 @@
case 3:
VALUE_TO_ENUM(argv[2], filter, FilterTypes);
case 2:
rows = NUM2ULONG(argv[1]);
columns = NUM2ULONG(argv[0]);
+ if (columns == 0 || rows == 0)
+ {
+ rb_raise(rb_eArgError, "invalid result dimension (%lu, %lu given)", columns, rows);
+ }
break;
case 1:
scale = NUM2DBL(argv[0]);
- rows = scale * image->rows;
- columns = scale * image->columns;
+ if (scale < 0.0)
+ {
+ rb_raise(rb_eArgError, "invalid scale value (%g given)", scale);
+ }
+ drows = scale * image->rows + 0.5;
+ dcols = scale * image->columns + 0.5;
+ if (drows > ULONG_MAX || dcols > ULONG_MAX)
+ {
+ rb_raise(rb_eRangeError, "resulting image too big");
+ }
+ rows = (unsigned long) drows;
+ columns = (unsigned long) dcols;
break;
default:
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 to 4)", argc);
break;
}
@@ -6384,18 +6571,18 @@
sample!: self, sampled
*/
VALUE
Image_sample(int argc, VALUE *argv, VALUE self)
{
- return scale_image(False, argc, argv, self, SampleImage);
+ return scale(False, argc, argv, self, SampleImage);
}
VALUE
Image_sample_bang(int argc, VALUE *argv, VALUE self)
{
rm_check_frozen(self);
- return scale_image(True, argc, argv, self, SampleImage);
+ return scale(True, argc, argv, self, SampleImage);
}
/*
Method: Image#scale(scale) or (cols, rows)
Image#scale!
@@ -6404,54 +6591,60 @@
scale!: self, scaled
*/
VALUE
Image_scale(int argc, VALUE *argv, VALUE self)
{
- return scale_image(False, argc, argv, self, ScaleImage);
+ return scale(False, argc, argv, self, ScaleImage);
}
VALUE
Image_scale_bang(int argc, VALUE *argv, VALUE self)
{
rm_check_frozen(self);
- return scale_image(True, argc, argv, self, ScaleImage);
+ return scale(True, argc, argv, self, ScaleImage);
}
/*
- Static: scale_image
+ Static: scale
Purpose: Call ScaleImage or SampleImage
Arguments: if 1 argument > 0, multiply current size by this much
if 2 arguments, (cols, rows)
*/
static VALUE
-scale_image(int bang, int argc, VALUE *argv, VALUE self, scaler_t *scaler)
+scale(int bang, int argc, VALUE *argv, VALUE self, scaler_t *scaler)
{
Image *image, *new_image;
unsigned long columns, rows;
- double scale;
+ double scale, drows, dcols;
ExceptionInfo exception;
Data_Get_Struct(self, Image, image);
switch (argc)
{
case 2:
columns = NUM2ULONG(argv[0]);
rows = NUM2ULONG(argv[1]);
- if (columns <= 0 || rows <= 0)
+ if (columns == 0 || rows == 0)
{
- rb_raise(rb_eArgError, "invalid scale given (%dl, %dl given)", columns, rows);
+ rb_raise(rb_eArgError, "invalid result dimension (%lu, %lu given)", columns, rows);
}
break;
case 1:
scale = NUM2DBL(argv[0]);
if (scale <= 0)
{
rb_raise(rb_eArgError, "invalid scale value (%g given)", scale);
}
- rows = image->rows * scale;
- columns = image->columns * scale;
+ drows = scale * image->rows + 0.5;
+ dcols = scale * image->columns + 0.5;
+ if (drows > ULONG_MAX || dcols > ULONG_MAX)
+ {
+ rb_raise(rb_eRangeError, "resulting image too big");
+ }
+ rows = (unsigned long) drows;
+ columns = (unsigned long) dcols;
break;
default:
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
break;
}
@@ -7551,28 +7744,41 @@
Notes: Uses BoxFilter, blur attribute of input image
*/
static VALUE
thumbnail(int bang, int argc, VALUE *argv, VALUE self)
{
-#ifdef HAVE_THUMBNAILIMAGE
Image *image, *new_image;
unsigned long columns, rows;
- double scale;
+ double scale, drows, dcols;
ExceptionInfo exception;
Data_Get_Struct(self, Image, image);
switch (argc)
{
case 2:
columns = NUM2ULONG(argv[0]);
rows = NUM2ULONG(argv[1]);
+ if (columns == 0 || rows == 0)
+ {
+ rb_raise(rb_eArgError, "invalid result dimension (%lu, %lu given)", columns, rows);
+ }
break;
case 1:
scale = NUM2DBL(argv[0]);
- rows = scale * image->rows;
- columns = scale * image->columns;
+ if (scale < 0.0)
+ {
+ rb_raise(rb_eArgError, "invalid scale value (%g given)", scale);
+ }
+ drows = scale * image->rows + 0.5;
+ dcols = scale * image->columns + 0.5;
+ if (drows > ULONG_MAX || dcols > ULONG_MAX)
+ {
+ rb_raise(rb_eRangeError, "resulting image too big");
+ }
+ rows = (unsigned long) drows;
+ columns = (unsigned long) dcols;
break;
default:
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
break;
}
@@ -7587,14 +7793,10 @@
DestroyImage(image);
return self;
}
return rm_image_new(new_image);
-#else
- rm_not_implemented();
- return (VALUE)0;
-#endif
}
VALUE
Image_thumbnail(int argc, VALUE *argv, VALUE self)
{
@@ -7770,10 +7972,11 @@
VALUE
Image_to_blob(VALUE self)
{
Image *image;
Info *info;
+ const MagickInfo *magick_info;
volatile VALUE info_obj;
volatile VALUE blob_str;
void *blob = NULL;
size_t length = 2048; // Do what Magick++ does
ExceptionInfo exception;
@@ -7805,10 +8008,24 @@
return Qnil;
}
strncpy(image->magick, info->magick, sizeof(info->magick)-1);
}
+ // Fix #2844 - libjpeg exits when image is 0x0
+ magick_info = GetMagickInfo(image->magick, &exception);
+ HANDLE_ERROR
+ if (magick_info)
+ {
+ if ( (!rm_strcasecmp(magick_info->name, "JPEG")
+ || !rm_strcasecmp(magick_info->name, "JPG"))
+ && (image->rows == 0 || image->columns == 0))
+ {
+ rb_raise(rb_eRuntimeError, "Can't convert %lux%lu %.4s image to a blob"
+ , image->columns, image->rows, magick_info->name);
+ }
+ }
+
blob = ImageToBlob(info, image, &length, &exception);
HANDLE_ERROR
if (length == 0 || !blob)
{
return Qnil;
@@ -8133,10 +8350,64 @@
#endif
}
/*
+ Method: Image#vignette(horz_radius, vert_radius, radius, sigma);
+ Purpose: soften the edges of an image
+ Notes: The outer edges of the image are replaced by the background color.
+*/
+VALUE
+Image_vignette(int argc, VALUE *argv, VALUE self)
+{
+#if defined(HAVE_VIGNETTEIMAGE)
+ Image *image, *new_image;
+ long horz_radius, vert_radius;
+ double radius = 0.0, sigma = 10.0;
+ ExceptionInfo exception;
+
+ Data_Get_Struct(self, Image, image);
+
+ horz_radius = image->columns * 0.10 + 0.5;
+ vert_radius = image->rows * 0.10 + 0.5;
+
+ switch (argc)
+ {
+ case 4:
+ sigma = NUM2DBL(argv[3]);
+ case 3:
+ radius = NUM2DBL(argv[2]);
+ case 2:
+ vert_radius = NUM2INT(argv[1]);
+ case 1:
+ horz_radius = NUM2INT(argv[0]);
+ case 0:
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 4)", argc);
+ break;
+ }
+
+ GetExceptionInfo(&exception);
+
+ new_image = VignetteImage(image, radius, sigma, horz_radius, vert_radius, &exception);
+ HANDLE_ERROR
+ if (!new_image)
+ {
+ rb_raise(rb_eRuntimeError, "VignetteImage failed");
+ }
+
+ return rm_image_new(new_image);
+
+#else
+ rm_not_implemented();
+ return (VALUE)0;
+#endif
+}
+
+
+/*
Method: Image#virtual_pixel_method
Purpose: get the VirtualPixelMethod for the image
*/
VALUE
Image_virtual_pixel_method(VALUE self)
@@ -8530,15 +8801,17 @@
VALUE_TO_ENUM(arg, ch_arg, ChannelType);
channels |= ch_arg;
*argc -= 1;
}
-#if defined(HAVE_ALLCHANNELS)
if (channels == 0)
{
+#if defined(HAVE_ALLCHANNELS)
channels = AllChannels;
- }
+#else
+ channels = 0xff;
#endif
+ }
return channels;
}