ext/RMagick/rmutil.c in rmagick-3.0.0 vs ext/RMagick/rmutil.c in rmagick-3.1.0
- old
+ new
@@ -227,10 +227,31 @@
}
}
/**
+ * Raise exception if ary argument was invalid type
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param ary the array
+ * @return the array that is converted type of argument object if needed
+ * @throw TypeError
+ */
+VALUE
+rm_check_ary_type(VALUE ary)
+{
+ VALUE checked = rb_check_array_type(ary);
+ if (NIL_P(checked))
+ {
+ rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" was given. (must respond to :to_ary)", rb_obj_class(ary));
+ }
+ return checked;
+}
+
+
+/**
* Raise an error if the image has been destroyed.
*
* No Ruby usage (internal function)
*
* @param obj the image
@@ -597,10 +618,25 @@
return NUM2QUANTUM(v);
}
/**
+ * Returns a pointer to an image structure initialized to default values
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param info the info
+ * @return the created image
+ */
+Image *
+rm_acquire_image(ImageInfo *info)
+{
+ return AcquireImage(info);
+}
+
+
+/**
* Send the "cur_image" method to the object. If 'img' is an ImageList, then
* cur_image is self[\@scene]. If 'img' is an image, then cur_image is simply
* 'self'.
*
* No Ruby usage (internal function)
@@ -619,16 +655,16 @@
* Map the color intensity to a named color.
*
* No Ruby usage (internal function)
*
* @param image the image
- * @param color the color intensity as a PixelPacket
+ * @param color the color intensity as a PixelColor
* @return the named color as a String
- * @see rm_pixelpacket_to_color_name_info
+ * @see rm_pixelcolor_to_color_name_info
*/
VALUE
-rm_pixelpacket_to_color_name(Image *image, PixelPacket *color)
+rm_pixelcolor_to_color_name(Image *image, PixelColor *color)
{
char name[MaxTextExtent];
ExceptionInfo *exception;
exception = AcquireExceptionInfo();
@@ -647,44 +683,72 @@
* No Ruby usage (internal function)
*
* Notes:
* - Simply create an Image from the Info, call QueryColorname, and then
* destroy the Image.
- * - If the Info structure is NULL, creates a new one.
* - The default depth is always used, and the matte value is set to False,
* which means "don't use the alpha channel".
*
* @param info the info
- * @param color the color intensity as a PixelPacket
+ * @param color the color intensity as a PixelColor
* @return the named color as a String
- * @see rm_pixelpacket_to_color_name
+ * @see rm_pixelcolor_to_color_name
*/
VALUE
-rm_pixelpacket_to_color_name_info(Info *info, PixelPacket *color)
+rm_pixelcolor_to_color_name_info(Info *info, PixelColor *color)
{
Image *image;
- Info *my_info;
VALUE color_name;
- my_info = info ? info : CloneImageInfo(NULL);
+ image = rm_acquire_image(info);
+ if (!image)
+ {
+ rb_raise(rb_eNoMemError, "not enough memory to continue.");
+ }
- image = AcquireImage(info);
image->matte = MagickFalse;
- color_name = rm_pixelpacket_to_color_name(image, color);
+ color_name = rm_pixelcolor_to_color_name(image, color);
(void) DestroyImage(image);
- if (!info)
- {
- (void) DestroyImageInfo(my_info);
- }
- RB_GC_GUARD(color_name);
-
return color_name;
}
+/**
+ * Initializes the MagickPixel structure.
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param image the image
+ * @param pp the MagickPixel
+ */
+void
+rm_init_magickpixel(const Image *image, MagickPixel *pp)
+{
+ GetMagickPixelPacket(image, pp);
+}
/**
+ * Initializes the MagickPixel structure to the specified color.
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param pp the MagickPixel
+ * @param color the color
+ */
+void
+rm_set_magickpixel(MagickPixel *pp, const char *color)
+{
+ ExceptionInfo *exception;
+
+ exception = AcquireExceptionInfo();
+ (void) QueryMagickColor(color, pp, exception);
+ // This exception is ignored because the color comes from places where we control
+ // the value and it is very unlikely that an exception will be thrown.
+ (void) DestroyExceptionInfo(exception);
+}
+
+/**
* Write a temporary copy of the image to the IM registry.
*
* No Ruby usage (internal function)
*
* Notes:
@@ -771,11 +835,11 @@
void
rm_not_implemented(void)
{
rb_raise(rb_eNotImpError, "the `%s' method is not supported by ImageMagick "
- MagickLibVersionText, rb_id2name(THIS_FUNC()));
+ MagickLibVersionText, rb_id2name(rb_frame_this_func()));
}
/**
* Create a new ImageMagickError object and raise an exception.
@@ -785,28 +849,25 @@
* Notes:
* - This funky technique allows me to safely add additional information to
* the ImageMagickError object in both 1.6.8 and 1.8.0.
*
* @param msg the error mesage
- * @param loc the location of the error
* @throw ImageMagickError
* @see www.ruby_talk.org/36408.
*/
void
-rm_magick_error(const char *msg, const char *loc)
+rm_magick_error(const char *msg)
{
- VALUE exc, mesg, extra;
+ VALUE exc, mesg;
mesg = rb_str_new2(msg);
- extra = loc ? rb_str_new2(loc) : Qnil;
- exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, extra);
+ exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, Qnil);
(void) rb_funcall(rb_cObject, rb_intern("raise"), 1, exc);
RB_GC_GUARD(exc);
RB_GC_GUARD(mesg);
- RB_GC_GUARD(extra);
}
/**
* Initialize a new ImageMagickError object - store the "loc" string in the
@@ -895,11 +956,10 @@
* @param images a list of images
* @param info the info
*/
void rm_set_user_artifact(Image *images, Info *info)
{
-#if defined(HAVE_SETIMAGEARTIFACT)
Image *image;
const char *value;
value = GetImageOption(info, "user");
if (value)
@@ -909,14 +969,10 @@
{
(void) SetImageArtifact(image, "user", value);
image = GetNextImageInList(image);
}
}
-#else
- images = images;
- info = info;
-#endif
}
/**
* Collect optional method arguments via Magick::OptionalMethodArguments.
@@ -951,11 +1007,10 @@
return;
}
-#if defined(HAVE_SETIMAGEARTIFACT)
/**
* Copy image options from the Info structure to the Image structure.
*
* No Ruby usage (internal function)
*
@@ -977,11 +1032,10 @@
property[MaxTextExtent-1] = '\0';
(void) SetImageArtifact(image, property, value);
}
}
}
-#endif
/**
* Propagate ImageInfo values to the Image
*
@@ -1011,11 +1065,11 @@
image->border_color = info->border_color;
}
if (info->colorspace != UndefinedColorspace)
{
- image->colorspace = info->colorspace;
+ SetImageColorspace(image, info->colorspace);
}
if (info->compression != UndefinedCompression)
{
image->compression = info->compression;
@@ -1107,16 +1161,14 @@
if (option)
{
image->transparent_color = info->transparent_color;
}
-#if defined(HAVE_ST_TYPE)
if (info->type != UndefinedType)
{
image->type = info->type;
}
-#endif
if (info->units != UndefinedResolution)
{
if (image->units != info->units)
{
@@ -1146,13 +1198,11 @@
}
image->units = info->units;
}
-#if defined(HAVE_SETIMAGEARTIFACT)
copy_options(image, info);
-#endif
}
/**
* Replicate old (ImageMagick < 6.3.2) EXIF:* functionality using
@@ -1443,37 +1493,44 @@
const char *tag,
const MagickOffsetType of,
const MagickSizeType sp,
void *client_data)
{
-#if !defined(_WIN32)
VALUE rval;
VALUE method, offset, span;
+// Default Ruby minimum stack size
+#define RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */
+
+ // Check stack length manually instead of ruby_stack_check() for old Ruby.
+ if (ruby_stack_length(NULL) > RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN)
+ {
+ // If there is not enough stack or the using stack size shows an abnormal value in Ruby,
+ // skip the callback and continue ImageMagick process.
+ return MagickTrue;
+ }
+
tag = tag; // defeat gcc message
#if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
offset = rb_ll2inum(of);
span = rb_ull2inum(sp);
#else
offset = rb_int2big((long)of);
span = rb_uint2big((unsigned long)sp);
#endif
- method = rb_str_new2(rb_id2name(THIS_FUNC()));
+ method = rb_id2str(rb_frame_this_func());
rval = rb_funcall((VALUE)client_data, rm_ID_call, 3, method, offset, span);
RB_GC_GUARD(rval);
RB_GC_GUARD(method);
RB_GC_GUARD(offset);
RB_GC_GUARD(span);
return RTEST(rval) ? MagickTrue : MagickFalse;
-#else
- return MagickTrue;
-#endif
}
/**
* Remove the ImageMagick links between images in an scene sequence.
@@ -1549,11 +1606,41 @@
(void) DestroyExceptionInfo(exception);
}
+#define ERROR_MSG_SIZE 1024
/**
+ * Formats the exception into the message buffer
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param severity information about the severity of the error
+ * @param reason the reason for the error
+ * @param description description of the error
+ * @param msg the buffer where the exception message should be formated in
+ */
+static void
+format_exception(const ExceptionType severity, const char *reason, const char *description, char *msg)
+{
+ int len;
+ memset(msg, 0, sizeof(ERROR_MSG_SIZE));
+
+#if defined(HAVE_SNPRINTF)
+ len = snprintf(msg, ERROR_MSG_SIZE, "%s%s%s",
+#else
+ len = sprintf(msg, "%.500s%s%.500s",
+#endif
+ GetLocaleExceptionMessage(severity, reason),
+ description ? ": " : "",
+ description ? GetLocaleExceptionMessage(severity, description) : "");
+
+ msg[len] = '\0';
+}
+
+
+/**
* Call handle_exception if there is an exception to handle.
*
* No Ruby usage (internal function)
*
* @param exception information about the exception
@@ -1584,63 +1671,54 @@
* @param description description of the warning
*/
void
rm_warning_handler(const ExceptionType severity, const char *reason, const char *description)
{
- ExceptionType dummy;
-
- rb_warning("RMagick: %s: `%s'", reason, description);
- dummy = severity;
- dummy = dummy;
+ rb_warning("RMagick: %s%s%s",
+ GetLocaleExceptionMessage(severity, reason),
+ description ? ": " : "",
+ description ? GetLocaleExceptionMessage(severity, description) : "");
}
/**
* Called from ImageMagick for a error.
*
* No Ruby usage (internal function)
*
- * @param severity information about the severity of the error (ignored)
+ * @param severity information about the severity of the error
* @param reason the reason for the error
* @param description description of the error
*/
void
rm_error_handler(const ExceptionType severity, const char *reason, const char *description)
{
- char msg[500];
- int len;
- ExceptionType dummy;
+ char msg[ERROR_MSG_SIZE];
- memset(msg, 0, sizeof(msg));
-#if defined(HAVE_SNPRINTF)
- len = snprintf(msg, sizeof(msg), "%s: `%s'", reason, description);
-#else
- len = sprintf(msg, "%.250s: `%.240s'", reason, description);
-#endif
- msg[len] = '\0';
+ format_exception(severity, reason, description, msg);
- rm_magick_error(msg, NULL);
- dummy = severity;
- dummy = dummy;
+ rm_magick_error(msg);
}
/**
* Called from ImageMagick for a fatal error.
*
* No Ruby usage (internal function)
*
* @param severity information about the severity of the error
* @param reason the reason for the error
- * @param description description of the error (ignored)
+ * @param description description of the error
* @throw FatalImageMagickError
*/
void
rm_fatal_error_handler(const ExceptionType severity, const char *reason, const char *description)
{
- rb_raise(Class_FatalImageMagickError, "%s", GetLocaleExceptionMessage(severity, reason));
- description = description;
+ rb_raise(Class_FatalImageMagickError, "%s%s%s",
+ GetLocaleExceptionMessage(severity, reason),
+ description ? ": " : "",
+ description ? GetLocaleExceptionMessage(severity, description) : "");
}
/**
* Called when rm_check_exception determines that we need to either issue a
@@ -1655,31 +1733,16 @@
* or DestroyOnError)
*/
static void
handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
{
+ char msg[ERROR_MSG_SIZE];
- char reason[500];
- char desc[500];
- char msg[sizeof(reason)+sizeof(desc)+20];
-
- memset(msg, 0, sizeof(msg));
-
-
// Handle simple warning
if (exception->severity < ErrorException)
{
-#if defined(HAVE_SNPRINTF)
- snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s",
-#else
- sprintf(msg, "RMagick: %.500s%s%.500s",
-#endif
- GetLocaleExceptionMessage(exception->severity, exception->reason),
- exception->description ? ": " : "",
- exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : "");
- msg[sizeof(msg)-1] = '\0';
- rb_warning("%s", msg);
+ rm_warning_handler(exception->severity, exception->reason, exception->description);
// Caller deletes ExceptionInfo...
return;
}
@@ -1700,44 +1763,15 @@
{
rm_split(imglist);
}
}
+ format_exception(exception->severity, exception->reason, exception->description, msg);
- // Clone the ExceptionInfo with all arguments on the stack.
- memset(reason, 0, sizeof(reason));
- memset(desc, 0, sizeof(desc));
-
- if (exception->reason)
- {
- strncpy(reason, exception->reason, sizeof(reason)-1);
- reason[sizeof(reason)-1] = '\0';
- }
- if (exception->description)
- {
- strncpy(desc, exception->description, sizeof(desc)-1);
- desc[sizeof(desc)-1] = '\0';
- }
-
-
-#if defined(HAVE_SNPRINTF)
- snprintf(msg, sizeof(msg)-1, "%s%s%s",
- GetLocaleExceptionMessage(exception->severity, reason),
- desc[0] ? ": " : "",
- desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
-#else
- sprintf(msg, "%.*s%s%.*s",
- sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason),
- desc[0] ? ": " : "",
- sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
-#endif
-
- msg[sizeof(msg)-1] = '\0';
-
(void) DestroyExceptionInfo(exception);
- rm_magick_error(msg, NULL);
+ rm_magick_error(msg);
}
/**
* RMagick expected a result. If it got NULL instead raise an exception.
@@ -1752,7 +1786,57 @@
{
if (!image)
{
rb_raise(rb_eRuntimeError, MagickPackageName " library function failed to return a result.");
}
+}
+
+
+/**
+ * Checks if an error should be raised for the exception.
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param exception information about the exception
+ * @param retention retention strategy for the exception in case there was no error
+ */
+MagickBooleanType
+rm_should_raise_exception(ExceptionInfo *exception, const ExceptionRetention retention)
+{
+ if (exception->severity < ErrorException)
+ {
+ if (exception->severity != UndefinedException)
+ {
+ rm_warning_handler(exception->severity, exception->reason, exception->description);
+ }
+
+ if (retention == DestroyExceptionRetention)
+ {
+ (void) DestroyExceptionInfo(exception);
+ }
+
+ return MagickFalse;
+ }
+
+ return MagickTrue;
+}
+
+
+/**
+ * Raises an exception.
+ *
+ * No Ruby usage (internal function)
+ *
+ * @param exception information about the exception
+ */
+void
+rm_raise_exception(ExceptionInfo *exception)
+{
+ char msg[ERROR_MSG_SIZE];
+
+ format_exception(exception->severity, exception->reason, exception->description, msg);
+
+ (void) DestroyExceptionInfo(exception);
+
+ rm_magick_error(msg);
}