ext/RMagick/rminfo.c in rmagick-1.15.17 vs ext/RMagick/rminfo.c in rmagick-2.0.0

- old
+ new

@@ -1,166 +1,317 @@ -/* $Id: rminfo.c,v 1.45.2.2.2.3 2008/09/10 23:22:46 rmagick Exp $ */ +/* $Id: rminfo.c,v 1.67 2007/10/28 23:43:24 rmagick Exp $ */ /*============================================================================\ -| Copyright (C) 2008 by Timothy P. Hunter +| Copyright (C) 2007 by Timothy P. Hunter | Name: rminfo.c | Author: Tim Hunter | Purpose: Info class method definitions for RMagick. \============================================================================*/ #include "rmagick.h" -static VALUE get_option(VALUE, char *); -static VALUE set_option(VALUE, char *, VALUE); -DEF_ATTR_ACCESSOR(Info, antialias, bool) + /* - * Method: value = Info[format, key] - * Purpose: get the value of an option set by Info[]= + Method: Info#get_option + Purpose: Return the value of the specified option */ -#define MAX_FORMAT_LEN 60 - -VALUE -Info_aref(VALUE self, VALUE format, VALUE key) +static VALUE +get_option(VALUE self, const char *key) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; - char *format_p, *key_p; - long format_l, key_l; const char *value; - char fkey[MaxTextExtent]; - format_p = STRING_PTR_LEN(format, format_l); - key_p = STRING_PTR_LEN(key, key_l); + Data_Get_Struct(self, Info, info); - if (format_l > MAX_FORMAT_LEN || format_l + key_l > MaxTextExtent-1) + value = GetImageOption(info, key); + if (value) { - rb_raise(rb_eArgError, "can't reference %.60s:%.1024s - too long", format_p, key_p); + return rb_str_new2(value); } + return Qnil; +} - sprintf(fkey, "%.60s:%.*s", STRING_PTR(format), (int)(MaxTextExtent-61), STRING_PTR(key)); +/* + Method: Info#set_option + Purpose: Set the specified option to this value. + If the value is nil just unset any current value +*/ +static VALUE +set_option(VALUE self, const char *key, VALUE string) +{ + Info *info; + char *value; Data_Get_Struct(self, Info, info); - value = GetImageOption(info, fkey); - if (!value) + + if (NIL_P(string)) { - return Qnil; + (void) RemoveImageOption(info, key); } + else + { + value = StringValuePtr(string); + (void) SetImageOption(info, key, value); + } + return self; +} - return rb_str_new2(value); -#elif defined(HAVE_ADDDEFINITIONS) +/* + Static: set_color_option + Purpose: Set a color name as the value of the specified option + Note: Call QueryColorDatabase to validate color name +*/ +static VALUE set_color_option(VALUE self, const char *option, VALUE color) +{ Info *info; + char *name; + PixelPacket pp; + ExceptionInfo exception; + MagickBooleanType okay; + + Data_Get_Struct(self, Info, info); + + if (NIL_P(color)) + { + (void) RemoveImageOption(info, option); + } + else + { + GetExceptionInfo(&exception); + name = StringValuePtr(color); + okay = QueryColorDatabase(name, &pp, &exception); + (void) DestroyExceptionInfo(&exception); + if (!okay) + { + rb_raise(rb_eArgError, "invalid color name `%s'", name); + } + + (void) RemoveImageOption(info, option); + (void) SetImageOption(info, option, name); + } + + return self; +} + + +/* + Static: get_dbl_option(obj, option) + Purpose: Get an Image::Info option floating-point value + Notes: Convert the string value to a float +*/ +static VALUE get_dbl_option(VALUE self, const char *option) +{ + Info *info; const char *value; + double d; + long n; Data_Get_Struct(self, Info, info); - value = AccessDefinition(info, STRING_PTR(format), STRING_PTR(key)); + value = GetImageOption(info, option); if (!value) { return Qnil; } - return rb_str_new2(value); -#else - rm_not_implemented(); - return (VALUE)0; -#endif + d = atof(value); + n = (long) floor(d); + return d == (double)n ? LONG2NUM(n) : rb_float_new(d); } /* - Method: Info[format, key] = value - Purpose: Call AddDefinitions (GM) or SetImageOption (IM) - Note: Essentially the same function as Info#define but paired - with Info#[]= + Static: set_dbl_option(obj, option, value) + Purpose: Set an Image::Info option to a floating-point value + Notes: SetImageOption expects the value to be a string. */ +static VALUE set_dbl_option(VALUE self, const char *option, VALUE value) +{ + Info *info; + char buff[50]; + double d; + long n; + int len; + + Data_Get_Struct(self, Info, info); + + if (NIL_P(value)) + { + (void) RemoveImageOption(info, option); + } + else + { + d = NUM2DBL(value); + n = floor(d); + if (d == n) + { + len = sprintf(buff, "%-10ld", n); + } + else + { + len = sprintf(buff, "%-10.2f", d); + } + memset(buff+len, '\0', sizeof(buff)-len); + (void) RemoveImageOption(info, option); + (void) SetImageOption(info, option, buff); + } + + return self; +} + + +DEF_ATTR_ACCESSOR(Info, antialias, bool) + +/* + Method: value = Info[format, key] + value = Info[key] + Purpose: get the value of an option set by Info[]= + The 2 argument form is the original form. Added support for a + single argument after ImageMagick started using Set/GetImageOption + for options that aren't represented by fields in the ImageInfo + structure. +*/ +#define MAX_FORMAT_LEN 60 + VALUE -Info_aset(VALUE self, VALUE format, VALUE key, VALUE value) +Info_aref(int argc, VALUE *argv, VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; - char *format_p, *key_p, *value_p = ""; + char *format_p, *key_p; long format_l, key_l; - char ckey[MaxTextExtent]; - unsigned int okay; + const char *value; + char fkey[MaxTextExtent]; + switch (argc) + { + case 2: + format_p = rb_str2cstr(argv[0], &format_l); + key_p = rb_str2cstr(argv[1], &key_l); + if (format_l > MAX_FORMAT_LEN || format_l + key_l > MaxTextExtent-1) + { + rb_raise(rb_eArgError, "can't reference %.60s:%.1024s - too long", format_p, key_p); + } - Data_Get_Struct(self, Info, info); + sprintf(fkey, "%.60s:%.*s", format_p, (int)(MaxTextExtent-61), key_p); + break; - format_p = STRING_PTR_LEN(format, format_l); - key_p = STRING_PTR_LEN(key, key_l); + case 1: + strncpy(fkey, StringValuePtr(argv[0]), sizeof(fkey)-1); + fkey[sizeof(fkey)-1] = '\0'; + break; - /* Allow any argument that supports to_s */ - value = rb_funcall(value, rm_ID_to_s, 0); - value_p = STRING_PTR(value); + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc); + break; - if (format_l > MAX_FORMAT_LEN || format_l+key_l > MaxTextExtent-1) - { - rb_raise(rb_eArgError, "%.60s:%.1024s not defined - too long", format_p, key_p); } - (void) sprintf(ckey, "%.60s:%.*s", format_p, (int)(sizeof(ckey)-MAX_FORMAT_LEN), key_p); - - okay = SetImageOption(info, ckey, value_p); - if (!okay) + Data_Get_Struct(self, Info, info); + value = GetImageOption(info, fkey); + if (!value) { - rb_warn("%.60s:%.1024s not defined - SetImageOption failed.", format_p, key_p); return Qnil; } - return self; + return rb_str_new2(value); +} -#elif defined(HAVE_ADDDEFINITIONS) + +/* + Method: Info[format, key] = value + Purpose: Call SetImageOption + Note: Essentially the same function as Info#define but paired with Info#[]= + If the value is nil it is equivalent to #undefine. + + The 2 argument form is the original form. Added support for a + single argument after ImageMagick started using Set/GetImageOption + for options that aren't represented by fields in the ImageInfo + structure. +*/ +VALUE +Info_aset(int argc, VALUE *argv, VALUE self) +{ Info *info; - char *format_p, *key_p, *value_p = NULL; - long format_l, key_l, value_l = 0; + volatile VALUE value; + char *format_p, *key_p, *value_p = ""; + long format_l, key_l; + char ckey[MaxTextExtent]; unsigned int okay; - ExceptionInfo exception; - char definitions[MaxTextExtent*2];/* Make this buffer longer than the buffer used */ - /* for SetImageOptions since AddDefinitions cats */ - /* the value onto the format:key pair. */ + Data_Get_Struct(self, Info, info); - format_p = STRING_PTR_LEN(format, format_l); - key_p = STRING_PTR_LEN(key, key_l); - value = rb_funcall(value, rm_ID_to_s, 0); - value_p = STRING_PTR_LEN(value, value_l); - - if ((3 + format_l + key_l + value_l) > sizeof(definitions)) + switch (argc) { - rb_raise(rb_eArgError, "%.60s:%.1024s not defined - too long", format_p, key_p); + case 3: + format_p = rb_str2cstr(argv[0], &format_l); + key_p = rb_str2cstr(argv[1], &key_l); + + if (format_l > MAX_FORMAT_LEN || format_l+key_l > MaxTextExtent-1) + { + rb_raise(rb_eArgError, "%.60s:%.1024s not defined - too long", format_p, key_p); + } + + (void) sprintf(ckey, "%.60s:%.*s", format_p, (int)(sizeof(ckey)-MAX_FORMAT_LEN), key_p); + + value = argv[2]; + break; + + case 2: + strncpy(ckey, StringValuePtr(argv[0]), sizeof(ckey)-1); + ckey[sizeof(ckey)-1] = '\0'; + + value = argv[1]; + break; + + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 3)", argc); + break; } - (void)sprintf(definitions, "%s:%s=", format_p, key_p); - if (value_l > 0) + + if (NIL_P(value)) { - strcat(definitions, value_p); + (void) RemoveImageOption(info, ckey); } - - GetExceptionInfo(&exception); - okay = AddDefinitions(info, definitions, &exception); - CHECK_EXCEPTION() - (void) DestroyExceptionInfo(&exception); - - if (!okay) + else { - rb_warn("%.60s:%.1024s not defined - AddDefinitions failed.", format_p, key_p); - return Qnil; + /* Allow any argument that supports to_s */ + value = rb_funcall(value, rm_ID_to_s, 0); + value_p = StringValuePtr(value); + + (void) RemoveImageOption(info, ckey); + okay = SetImageOption(info, ckey, value_p); + if (!okay) + { + rb_warn("`%s' not defined - SetImageOption failed.", ckey); + return Qnil; + } } + return self; +} -#else - rm_not_implemented(); - return (VALUE)0; -#endif + +VALUE +Info_attenuate(VALUE self) +{ + return get_dbl_option(self, "attenuate"); } VALUE +Info_attenuate_eq(VALUE self, VALUE value) +{ + return set_dbl_option(self, "attenuate", value); +} + + +VALUE Info_authenticate(VALUE self) { Info *info; Data_Get_Struct(self, Info, info); @@ -184,11 +335,11 @@ Data_Get_Struct(self, Info, info); if (!NIL_P(passwd)) { - passwd_p = STRING_PTR_LEN(passwd, passwd_len); + passwd_p = rb_str2cstr(passwd, &passwd_len); } if (info->authenticate) { magick_free(info->authenticate); @@ -269,11 +420,10 @@ Thanks: Douglas Sellers */ VALUE Info_channel(int argc, VALUE *argv, VALUE self) { -#if defined(HAVE_IMAGEINFO_CHANNEL) Info *info; ChannelType channels; channels = extract_channels(&argc, argv); @@ -285,14 +435,10 @@ Data_Get_Struct(self, Info, info); info->channel = channels; return self; -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#colorspace @@ -353,124 +499,65 @@ return self; } /* Method: Info#define(format, key[, value]) - Purpose: Call AddDefinitions (GM) or SetImageOption (IM) + Purpose: Call SetImageOption Note: The only method in Info that is not an attribute accessor. */ VALUE Info_define(int argc, VALUE *argv, VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; char *format, *key, *value = ""; long format_l, key_l; char ckey[100]; unsigned int okay; volatile VALUE fmt_arg; Data_Get_Struct(self, Info, info); - switch(argc) + switch (argc) { case 3: /* Allow any argument that supports to_s */ fmt_arg = rb_funcall(argv[2], rm_ID_to_s, 0); - value = STRING_PTR(fmt_arg); + value = StringValuePtr(fmt_arg); case 2: - key = STRING_PTR_LEN(argv[1], key_l); - format = STRING_PTR_LEN(argv[0], format_l); + key = rb_str2cstr(argv[1], &key_l); + format = rb_str2cstr(argv[0], &format_l); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 3)", argc); } - if (2 + format_l + key_l > (int)sizeof(ckey)) + if (2 + format_l + key_l > (long)sizeof(ckey)) { rb_raise(rb_eArgError, "%.20s:%.20s not defined - format or key too long", format, key); } (void) sprintf(ckey, "%s:%s", format, key); + (void) RemoveImageOption(info, ckey); okay = SetImageOption(info, ckey, value); if (!okay) { rb_warn("%.20s=\"%.78s\" not defined - SetImageOption failed.", ckey, value); return Qnil; } return self; - -#elif defined(HAVE_ADDDEFINITIONS) - Info *info; - char *format, *key, *value = NULL; - long format_l, key_l, value_l = 0; - unsigned int okay; - volatile VALUE fmt_arg; - ExceptionInfo exception; - char definitions[200]; /* Make this buffer longer than the buffer used */ - /* for SetImageOptions since AddDefinitions cats */ - /* the value onto the format:key pair. */ - - Data_Get_Struct(self, Info, info); - - switch(argc) - { - case 3: - /* Allow any argument that supports to_s */ - fmt_arg = rb_funcall(argv[2], rm_ID_to_s, 0); - value = STRING_PTR_LEN(fmt_arg, value_l); - /* Fall through */ - case 2: - key = STRING_PTR_LEN(argv[1], key_l); - format = STRING_PTR_LEN(argv[0], format_l); - break; - default: - rb_raise(rb_eArgError, "wrong number of arguments (%d for 2 or 3)", argc); - break; - } - - - if ((3 + format_l + key_l + value_l) > sizeof(definitions)) - { - rb_raise(rb_eArgError, "%.20s:%.20s not defined - too long", format, key); - } - (void)sprintf(definitions, "%s:%s=", format, key); - if (value) - { - strcat(definitions, value); - } - - GetExceptionInfo(&exception); - okay = AddDefinitions(info, definitions, &exception); - CHECK_EXCEPTION() - (void) DestroyExceptionInfo(&exception); - - if (!okay) - { - rb_warn("%.*s not defined - AddDefinitions failed.", sizeof(definitions), definitions); - return Qnil; - } - - return self; - -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#delay Purpose: Get the delay attribute Notes: Convert from string to numeric */ VALUE Info_delay(VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; const char *delay; char *p; long d; @@ -485,38 +572,31 @@ rb_raise(rb_eRangeError, "failed to convert %s to Numeric", delay); } return LONG2NUM(d); } return Qnil; -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* * Will raise an exception if `arg' can't be converted to an int. */ -#if defined(HAVE_SETIMAGEOPTION) static VALUE arg_is_integer(VALUE arg) { int d = NUM2INT(arg); d = d; // satisfy icc return arg; } -#endif /* Method: Info#delay= Purpose: Set the delay attribute Notes: Convert from numeric value to string. */ VALUE Info_delay_eq(VALUE self, VALUE string) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; int delay; int not_num; char dstr[20]; @@ -534,17 +614,14 @@ { rb_raise(rb_eTypeError, "failed to convert %s into Integer", rb_class2name(CLASS_OF(string))); } delay = NUM2INT(string); sprintf(dstr, "%d", delay); + (void) RemoveImageOption(info, "delay"); (void) SetImageOption(info, "delay", dstr); } return self; -#else - rm_not_implemented(); - return (VALUE)0; -#endif } DEF_ATTR_READER(Info, density, str) /* @@ -559,19 +636,19 @@ volatile VALUE density; char *dens; Data_Get_Struct(self, Info, info); - if(NIL_P(density_arg)) + if (NIL_P(density_arg)) { magick_free(info->density); info->density = NULL; return self; } density = rb_funcall(density_arg, rm_ID_to_s, 0); - dens = STRING_PTR(density); + dens = StringValuePtr(density); if (!IsGeometry(dens)) { rb_raise(rb_eArgError, "invalid density geometry: %s", dens); } @@ -596,16 +673,19 @@ Data_Get_Struct(self, Info, info); d = NUM2ULONG(depth); switch (d) { case 8: // always okay -#if QuantumDepth == 16 || QuantumDepth == 32 +#if QuantumDepth == 16 || QuantumDepth == 32 || QuantumDepth == 64 case 16: -#endif -#if QuantumDepth == 32 +#if QuantumDepth == 32 || QuantumDepth == 64 case 32: +#if QuantumDepth == 64 + case 64: #endif +#endif +#endif break; default: rb_raise(rb_eArgError, "invalid depth (%lu)", d); break; } @@ -617,35 +697,32 @@ /* Method: Info#dispose Purpose: Retrieve a dispose option string and convert it to a DisposeType enumerator */ -#if defined(HAVE_SETIMAGEOPTION) static struct { char *string; char *enum_name; DisposeType enumerator; } Dispose_Option[] = { - { "Background", "BackgroundDispose", BackgroundDispose }, - { "None", "NoneDispose", NoneDispose }, - { "Previous", "PreviousDispose", PreviousDispose }, - { "Undefined", "UndefinedDispose", UndefinedDispose }, - { "0", "UndefinedDispose", UndefinedDispose }, - { "1", "NoneDispose", NoneDispose }, - { "2", "BackgroundDispose", BackgroundDispose }, - { "3", "PreviousDispose", PreviousDispose }, - }; -#define N_DISPOSE_OPTIONS (sizeof(Dispose_Option)/sizeof(Dispose_Option[0])) -#endif + { "Background", "BackgroundDispose", BackgroundDispose}, + { "None", "NoneDispose", NoneDispose}, + { "Previous", "PreviousDispose", PreviousDispose}, + { "Undefined", "UndefinedDispose", UndefinedDispose}, + { "0", "UndefinedDispose", UndefinedDispose}, + { "1", "NoneDispose", NoneDispose}, + { "2", "BackgroundDispose", BackgroundDispose}, + { "3", "PreviousDispose", PreviousDispose}, +}; +#define N_DISPOSE_OPTIONS (int)(sizeof(Dispose_Option)/sizeof(Dispose_Option[0])) VALUE Info_dispose(VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; - unsigned int x; + int x; ID dispose_id; const char *dispose; Data_Get_Struct(self, Info, info); @@ -664,29 +741,24 @@ } } } return rb_const_get(Module_Magick, dispose_id); -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#dispose= Purpose: Convert a DisposeType enumerator into the equivalent dispose option string */ VALUE Info_dispose_eq(VALUE self, VALUE disp) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; DisposeType dispose; char *option; - unsigned int x; + int x; Data_Get_Struct(self, Info, info); if (NIL_P(disp)) { @@ -695,31 +767,25 @@ } VALUE_TO_ENUM(disp, dispose, DisposeType); option = "Undefined"; - for(x = 0; x < N_DISPOSE_OPTIONS; x++) + for (x = 0; x < N_DISPOSE_OPTIONS; x++) { if (dispose == Dispose_Option[x].enumerator) { option = Dispose_Option[x].string; break; } } (void) SetImageOption(info, "dispose", option); return self; - -#else - rm_not_implemented(); - return (VALUE)0; -#endif } DEF_ATTR_ACCESSOR(Info, dither, bool) -#ifdef HAVE_IMAGE_EXTRACT_INFO /* Method: aString=Info#extract Info#extract=aString Purpose: Get/set the extract string, e.g. "200x200+100+100" @@ -743,105 +809,23 @@ info->extract = NULL; return self; } extract = rb_funcall(extract_arg, rm_ID_to_s, 0); - extr = STRING_PTR(extract); + extr = StringValuePtr(extract); if (!IsGeometry(extr)) { rb_raise(rb_eArgError, "invalid extract geometry: %s", extr); } magick_clone_string(&info->extract, extr); return self; } -/* - Method: aString=Info#tile - Info#tile=aString - Purpose: Get/set the "tile" string, e.g. "200x200+100+100" - Raise: ArgumentError - Notes: defined for IM 5.5.6 and later. Actually these are effectively - aliases for extract & extract= but with warning messages. -*/ -VALUE -Info_tile(VALUE self) -{ - rb_warning("RMagick: tile is deprecated in this release of ImageMagick. Use extract instead."); - return Info_extract(self); -} -VALUE -Info_tile_eq(VALUE self, VALUE tile) -{ - rb_warning("RMagick: tile= is deprecated in this release of ImageMagick. Use extract= instead."); - return Info_extract_eq(self, tile); -} - -#else - /* - Method: aString=Info#extract - Info#extract=aString - Purpose: Get/set the extract string, e.g. "200x200+100+100" - Raise: ArgumentError - Notes: defined for IM 5.5.6 and later -*/ -VALUE -Info_extract(VALUE self) -{ - rm_not_implemented(); - return (VALUE)0; -} -VALUE -Info_extract_eq(VALUE self, VALUE extr) -{ - rm_not_implemented(); - return (VALUE)0; -} - -/* - Method: aString = Info#tile - Info#tile=aString - Purpose: Get/set the tile string, e.g. "200x200+100+100" - Raise: ArgumentError - Notes: defined for IM 5.5.5 and earlier, before the tile field was - deprecated and replaced by extract -*/ -DEF_ATTR_READER(Info, tile, str) - -VALUE -Info_tile_eq(VALUE self, VALUE tile_arg) -{ - Info *info; - char *til; - volatile VALUE tile; - - Data_Get_Struct(self, Info, info); - - if (NIL_P(tile_arg)) - { - magick_free(info->tile); - info->tile = NULL; - return self; - } - - tile = rb_funcall(tile_arg, rm_ID_to_s, 0); - til = STRING_PTR(tile); - if (!IsGeometry(til)) - { - rb_raise(rb_eArgError, "invalid tile geometry: %s", til); - } - - magick_clone_string(&info->tile, til); - - return self; -} -#endif - -/* Methods: aString=Info#filename Info#filename=aString Purpose: Get/set the "filename" Notes: Only used for Image#capture Returns "" if filename not set @@ -862,67 +846,43 @@ char *fname; Data_Get_Struct(self, Info, info); // Allow "nil" - remove current filename - if (NIL_P(filename) || STRING_PTR(filename) == NULL) + if (NIL_P(filename) || StringValuePtr(filename) == NULL) { info->filename[0] = '\0'; } else { // Otherwise copy in filename - fname = STRING_PTR(filename); + fname = StringValuePtr(filename); strncpy(info->filename, fname, MaxTextExtent); } return self; } /* Method: Info#fill - Purpose: return the fill (a.k.a pen) color as a String - Note: Compare with Image#fill! + Purpose: return the fill color as a String */ VALUE Info_fill(VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) - Info *info; - const char *fill; - - Data_Get_Struct(self, Info, info); - fill = GetImageOption(info, "fill"); - return fill ? rb_str_new2(fill) : Qnil; -#else - Info *info; - - Data_Get_Struct(self, Info, info); - return PixelPacket_to_Color_Name_Info(info, &info->pen); -#endif + return get_option(self, "fill"); } /* Method: Info#fill=<aString> - Purpose: set the fill (a.k.a. pen) color + Purpose: set the fill color Raises: ArgumentError */ VALUE Info_fill_eq(VALUE self, VALUE color) { - Info *info; - - Data_Get_Struct(self, Info, info); - Color_to_PixelPacket(&info->pen, color); - -#if defined(HAVE_SETIMAGEOPTION) - // Color_to_PixelPacket will raise an exception if `color' isn't a real color. - (void) RemoveImageOption(info, "fill"); - (void) SetImageOption(info, "fill", STRING_PTR(color)); -#endif - - return self; + return set_color_option(self, "fill", color); } /* Methods: aString=Info#font @@ -936,18 +896,18 @@ { Info *info; char *font; Data_Get_Struct(self, Info, info); - if (NIL_P(font_arg) || STRING_PTR(font_arg) == NULL) + if (NIL_P(font_arg) || StringValuePtr(font_arg) == NULL) { magick_free(info->font); info->font = NULL; } else { - font = STRING_PTR(font_arg); + font = StringValuePtr(font_arg); magick_clone_string(&info->font, font); } return self; } @@ -988,11 +948,11 @@ Data_Get_Struct(self, Info, info); GetExceptionInfo(&exception); - mgk = STRING_PTR(magick); + mgk = StringValuePtr(magick); m = GetMagickInfo(mgk, &exception); CHECK_EXCEPTION() (void) DestroyExceptionInfo(&exception); if (!m) @@ -1023,37 +983,34 @@ /* Method: Info#gravity Purpose: Return the value of the gravity option as a GravityType enumerator */ -#if defined(HAVE_SETIMAGEOPTION) static struct { char *string; char *enum_name; GravityType enumerator; } Gravity_Option[] = { - { "Undefined", "UndefinedGravity", UndefinedGravity }, - { "None", "UndefinedGravity", UndefinedGravity }, - { "Center", "CenterGravity", CenterGravity }, + { "Undefined", "UndefinedGravity", UndefinedGravity}, + { "None", "UndefinedGravity", UndefinedGravity}, + { "Center", "CenterGravity", CenterGravity}, { "East", "EastGravity", EastGravity}, - { "Forget", "ForgetGravity", ForgetGravity }, - { "NorthEast", "NorthEastGravity", NorthEastGravity }, - { "North", "NorthGravity", NorthGravity }, - { "NorthWest", "NorthWestGravity", NorthWestGravity }, - { "SouthEast", "SouthEastGravity", SouthEastGravity }, - { "South", "SouthGravity", SouthGravity }, - { "SouthWest", "SouthWestGravity", SouthWestGravity }, - { "West", "WestGravity", WestGravity }, - { "Static", "StaticGravity", StaticGravity } - }; -#define N_GRAVITY_OPTIONS (sizeof(Gravity_Option)/sizeof(Gravity_Option[0])) -#endif + { "Forget", "ForgetGravity", ForgetGravity}, + { "NorthEast", "NorthEastGravity", NorthEastGravity}, + { "North", "NorthGravity", NorthGravity}, + { "NorthWest", "NorthWestGravity", NorthWestGravity}, + { "SouthEast", "SouthEastGravity", SouthEastGravity}, + { "South", "SouthGravity", SouthGravity}, + { "SouthWest", "SouthWestGravity", SouthWestGravity}, + { "West", "WestGravity", WestGravity}, + { "Static", "StaticGravity", StaticGravity} +}; +#define N_GRAVITY_OPTIONS (int)(sizeof(Gravity_Option)/sizeof(Gravity_Option[0])) VALUE Info_gravity(VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; const char *gravity; int x; ID gravity_id; @@ -1074,26 +1031,20 @@ } } } return rb_const_get(Module_Magick, gravity_id); - -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#gravity= Purpose: Convert a GravityType enum to a gravity option name and store in the Info structure */ VALUE Info_gravity_eq(VALUE self, VALUE grav) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; GravityType gravity; char *option; int x; @@ -1106,26 +1057,21 @@ } VALUE_TO_ENUM(grav, gravity, GravityType); option = "Undefined"; - for(x = 0; x < N_GRAVITY_OPTIONS; x++) + for (x = 0; x < N_GRAVITY_OPTIONS; x++) { if (gravity == Gravity_Option[x].enumerator) { option = Gravity_Option[x].string; break; } } (void) SetImageOption(info, "gravity", option); return self; - -#else - rm_not_implemented(); - return (VALUE)0; -#endif } DEF_ATTR_ACCESSOR(Info, group, long) @@ -1224,11 +1170,10 @@ Notes: See Image_monitor_eq */ VALUE Info_monitor_eq(VALUE self, VALUE monitor) { -#if defined(HAVE_SETIMAGEPROGRESSMONITOR) Info *info; Data_Get_Struct(self, Info, info); if (NIL_P(monitor)) @@ -1240,59 +1185,30 @@ (void) SetImageInfoProgressMonitor(info, rm_progress_monitor, (void *)monitor); } return self; -#else - rm_not_implemented(); - return (VALUE)0; -#endif } DEF_ATTR_ACCESSOR(Info, monochrome, bool) -#ifdef HAVE_IMAGEINFO_NUMBER_SCENES DEF_ATTR_ACCESSOR(Info, number_scenes, ulong) -#else /* - Methods: num = Info#number_scenes - Info#number_scenes = num - Purpose: alias for subrange when IM < 5.5.6 -*/ -VALUE -Info_number_scenes(VALUE self) -{ - return Info_subrange(self); -} - -VALUE -Info_number_scenes_eq(VALUE self, VALUE nscenes) -{ - return Info_subrange_eq(self, nscenes); -} -#endif - -/* Method: Info#orientation Purpose: Return the orientation attribute as an OrientationType enum value. */ VALUE Info_orientation(VALUE self) { -#if defined(HAVE_IMAGEINFO_ORIENTATION) Info *info; Data_Get_Struct(self, Info, info); return OrientationType_new(info->orientation); -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#Orientation= @@ -1300,43 +1216,32 @@ Raises: ArgumentError */ VALUE Info_orientation_eq(VALUE self, VALUE inter) { -#if defined(HAVE_IMAGEINFO_ORIENTATION) Info *info; Data_Get_Struct(self, Info, info); VALUE_TO_ENUM(inter, info->orientation, OrientationType); return self; -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#origin Purpose: Return origin geometry */ VALUE Info_origin(VALUE self) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; const char *origin; Data_Get_Struct(self, Info, info); origin = GetImageOption(info, "origin"); return origin ? rb_str_new2(origin) : Qnil; - -#else - rm_not_implemented(); - return (VALUE)0; -#endif } /* Method: Info#origin=+-x+-y @@ -1344,11 +1249,10 @@ as a geometry string. */ VALUE Info_origin_eq(VALUE self, VALUE origin_arg) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; volatile VALUE origin_str; char *origin; Data_Get_Struct(self, Info, info); @@ -1358,39 +1262,30 @@ (void) RemoveImageOption(info, "origin"); return self; } origin_str = rb_funcall(origin_arg, rm_ID_to_s, 0); - origin = GetPageGeometry(STRING_PTR(origin_str)); + origin = GetPageGeometry(StringValuePtr(origin_str)); if (IsGeometry(origin) == MagickFalse) { rb_raise(rb_eArgError, "invalid origin geometry: %s", origin); } (void) SetImageOption(info, "origin", origin); return self; - -#else - rm_not_implemented(); - return (VALUE)0; -#endif } VALUE Info_page(VALUE self) { Info *info; const char *page; Data_Get_Struct(self, Info, info); -#if defined(HAVE_SETIMAGEOPTION) page = GetImageOption(info, "page"); -#else - page = (const char *)info->page; -#endif return page ? rb_str_new2(page) : Qnil; } /* @@ -1410,21 +1305,19 @@ magick_free(info->page); info->page = NULL; return self; } geom_str = rb_funcall(page_arg, rm_ID_to_s, 0); - geometry=GetPageGeometry(STRING_PTR(geom_str)); + geometry=GetPageGeometry(StringValuePtr(geom_str)); if (*geometry == '\0') { magick_free(info->page); info->page = NULL; return self; } magick_clone_string(&info->page, geometry); -#if defined(HAVE_SETIMAGEOPTION) - (void) SetImageOption(info, "page", STRING_PTR(geom_str)); -#endif + (void) SetImageOption(info, "page", StringValuePtr(geom_str)); return self; } DEF_ATTR_ACCESSOR(Info, pointsize, dbl) @@ -1460,11 +1353,11 @@ Data_Get_Struct(self, Info, info); if (!NIL_P(sampling_factor)) { - sampling_factor_p = STRING_PTR_LEN(sampling_factor, sampling_factor_len); + sampling_factor_p = rb_str2cstr(sampling_factor, &sampling_factor_len); } if (info->sampling_factor) { magick_free(info->sampling_factor); @@ -1476,91 +1369,11 @@ } return self; } -#ifdef HAVE_IMAGEINFO_NUMBER_SCENES - -// Info#scene, scene= is the IM >= 5.5.6 version of the now-deprecated -// subimage accessors. DEF_ATTR_ACCESSOR(Info, scene, ulong) - -/* - Methods: num=Info#subimage - Info#subimage=num - Purpose: Get/set the "subimage" value, for IM >= 5.5.6 - Raises: ArgumentError - Notes: synonyms for Info#scene, Info#scene= -*/ -VALUE -Info_subimage(VALUE self) -{ - rb_warning("RMagick: subimage is deprecated in this release of ImageMagick. Use scene instead."); - return Info_scene(self); -} - -VALUE -Info_subimage_eq(VALUE self, VALUE subimage) -{ - rb_warning("RMagick: subimage= is deprecated in this release of ImageMagick. Use scene= instead."); - return Info_scene_eq(self, subimage); -} - -/* - Methods: num=Info#subrange - Info#subrange=num - Purpose: Get/set the "subrange" value, for IM >= 5.5.6 - Raises: ArgumentError - Notes: synonyms for Info#number_scenes, Info#number_scenes= -*/ -VALUE -Info_subrange(VALUE self) -{ - rb_warning("RMagick: subrange is deprecated in this release of ImageMagick. Use number_scenes instead."); - return Info_number_scenes(self); -} - -VALUE -Info_subrange_eq(VALUE self, VALUE subrange) -{ - rb_warning("RMagick: subrange= is deprecated in this release of ImageMagick. Use number_scenes= instead."); - return Info_number_scenes_eq(self, subrange); -} - -#else - -/* - Methods: num=Info#scene - Info#scene=num - Purpose: Get/set the scene number, for IM < 5.5.6 - Raises: ArgumentError - Notes: synonyms for Info#subimage, Info#subimage= -*/ -VALUE -Info_scene(VALUE self) -{ - Info *info; - - Data_Get_Struct(self, Info, info); - return UINT2NUM(info->subimage); -} - -VALUE -Info_scene_eq(VALUE self, VALUE scene) -{ - Info *info; - - Data_Get_Struct(self, Info, info); - info->subimage = NUM2ULONG(scene); - return self; -} - -DEF_ATTR_ACCESSOR(Info, subimage, ulong) -DEF_ATTR_ACCESSOR(Info, subrange, ulong) - -#endif - DEF_ATTR_READER(Info, server_name, str) /* Method: Info#server_name=<aString> Purpose: Set the server name @@ -1570,18 +1383,18 @@ { Info *info; char *server; Data_Get_Struct(self, Info, info); - if (NIL_P(server_arg) || STRING_PTR(server_arg) == NULL) + if (NIL_P(server_arg) || StringValuePtr(server_arg) == NULL) { magick_free(info->server_name); info->server_name = NULL; } else { - server = STRING_PTR(server_arg); + server = StringValuePtr(server_arg); magick_clone_string(&info->server_name, server); } return self; } @@ -1608,11 +1421,11 @@ info->size = NULL; return self; } size = rb_funcall(size_arg, rm_ID_to_s, 0); - sz = STRING_PTR(size); + sz = StringValuePtr(size); if (!IsGeometry(sz)) { rb_raise(rb_eArgError, "invalid size geometry: %s", sz); } @@ -1621,10 +1434,56 @@ return self; } /* + Method: Info#stroke + Purpose: return the stroke color as a String +*/ +VALUE +Info_stroke(VALUE self) +{ + return get_option(self, "stroke"); +} + +/* + Method: Info#stroke=<aString> + Purpose: set the stroke color + Raises: ArgumentError +*/ +VALUE +Info_stroke_eq(VALUE self, VALUE color) +{ + return set_color_option(self, "stroke", color); +} + + +/* + Method: Info#stroke_width + Purpose: Support for caption: format + Notes: Supported >= 6.3.2-6 +*/ +VALUE +Info_stroke_width(VALUE self) +{ + return get_dbl_option(self, "strokewidth"); +} + + +/* + Method: Info#stroke_width= + Purpose: Support for caption: format + Notes: Supported >= 6.3.2-6 +*/ +VALUE +Info_stroke_width_eq(VALUE self, VALUE stroke_width) +{ + return set_dbl_option(self, "strokewidth", stroke_width); +} + + +/* Method: Image::Info#texture=texture_image Purpose: Set name of texture to tile onto the image background */ VALUE Info_texture_eq(VALUE self, VALUE texture) @@ -1648,35 +1507,83 @@ { return self; } // Create a temp copy of the texture and store its name in the texture field - Data_Get_Struct(texture, Image, image); + image = rm_check_destroyed(texture); rm_write_temp_image(image, name); magick_clone_string(&info->texture, name); return self; } /* + Method: Image::Info#tile_offset= geometry + Purpose: info.tile_offset = [+/-]x[+/-]y +*/ +VALUE +Info_tile_offset_eq(VALUE self, VALUE offset) +{ + Info *info; + volatile VALUE offset_str; + char *tile_offset; + + offset_str = rb_funcall(offset, rm_ID_to_s, 0); + tile_offset = StringValuePtr(offset_str); + if (!IsGeometry(tile_offset)) + { + rb_raise(rb_eArgError, "invalid tile offset geometry: %s", tile_offset); + } + + Data_Get_Struct(self, Info, info); + + (void) DeleteImageOption(info, "tile-offset"); + (void) SetImageOption(info, "tile-offset", tile_offset); + return self; +} + + +/* + Method: Image::Info#tile_offset + Purpose: returns tile_offset attribute values +*/ +VALUE +Info_tile_offset(VALUE self) +{ + Info *info; + const char *tile_offset; + + Data_Get_Struct(self, Info, info); + + tile_offset = GetImageOption(info, "tile-offset"); + + if (!tile_offset) + { + return Qnil; + } + + return rb_str_new2(tile_offset); +} + + +/* Method: Info#undefine Purpose: Undefine image option */ VALUE Info_undefine(VALUE self, VALUE format, VALUE key) { -#if defined(HAVE_SETIMAGEOPTION) Info *info; char *format_p, *key_p; long format_l, key_l; char fkey[MaxTextExtent]; - format_p = STRING_PTR_LEN(format, format_l); - key_p = STRING_PTR_LEN(key, key_l); + format_p = rb_str2cstr(format, &format_l); + key_p = rb_str2cstr(key, &key_l); if (format_l > MAX_FORMAT_LEN || format_l + key_l > MaxTextExtent) { rb_raise(rb_eArgError, "can't undefine %.60s:%.1024s - too long", format_p, key_p); } @@ -1685,41 +1592,34 @@ Data_Get_Struct(self, Info, info); /* Depending on the IM version, RemoveImageOption returns either */ /* char * or MagickBooleanType. Ignore the return value. */ (void) RemoveImageOption(info, fkey); + return self; +} -#elif defined(HAVE_ADDDEFINITIONS) - Info *info; - unsigned int okay; - char *format_p, *key_p; - long format_l, key_l; - char fkey[MaxTextExtent]; - format_p = STRING_PTR_LEN(format, format_l); - key_p = STRING_PTR_LEN(key, key_l); +/* + Method: Info#undercolor + Purpose: return the undercolor color as a String +*/ +VALUE +Info_undercolor(VALUE self) +{ + return get_option(self, "undercolor"); +} - if (format_l > MAX_FORMAT_LEN || format_l + key_l > MaxTextExtent) - { - rb_raise(rb_eArgError, "can't undefine %.60s:%.1024s - too long", format_p, key_p); - } - - sprintf(fkey, "%.60s:%.*s", format_p, MaxTextExtent-61, key_p); - - Data_Get_Struct(self, Info, info); - okay = RemoveDefinitions(info, fkey); - if (!okay) - { - rb_raise(rb_eArgError, "no such key: `%s'", fkey); - } - return self; - -#else - rm_not_implemented(); - return (VALUE)0; -#endif +/* + Method: Info#undercolor=<aString> + Purpose: set the undercolor color + Raises: ArgumentError +*/ +VALUE +Info_undercolor_eq(VALUE self, VALUE color) +{ + return set_color_option(self, "undercolor", color); } /* Method: Info#units Purpose: Get the resolution type @@ -1760,18 +1660,18 @@ Info *info; char *view; Data_Get_Struct(self, Info, info); - if (NIL_P(view_arg) || STRING_PTR(view_arg) == NULL) + if (NIL_P(view_arg) || StringValuePtr(view_arg) == NULL) { - magick_free(info->view); - info->view = NULL; + magick_free(info->view); + info->view = NULL; } else { - view = STRING_PTR(view_arg); + view = StringValuePtr(view_arg); magick_clone_string(&info->view, view); } return self; } @@ -1794,44 +1694,12 @@ } (void) DestroyImageInfo(info); } -/* - Method: Info.new - Purpose: Create an Info object by calling CloneInfo -*/ -#if !defined(HAVE_RB_DEFINE_ALLOC_FUNC) -VALUE -Info_new(VALUE class) -{ - Info *info; - volatile VALUE new_obj; - info = CloneImageInfo(NULL); - if (!info) - { - rb_raise(rb_eNoMemError, "not enough memory to initialize Info object"); - } - new_obj = Data_Wrap_Struct(class, NULL, destroy_Info, info); - rb_obj_call_init(new_obj, 0, NULL); - return new_obj; -} - /* - Extern: rm_info_new - Purpose: provide a Info.new method for internal use - Notes: takes no parameters, but runs the parm block if present -*/ -VALUE -rm_info_new() -{ - return Info_new(Class_Info); -} -#else - -/* Extern: Info_alloc Purpose: Create an ImageInfo object */ VALUE Info_alloc(VALUE class) @@ -1845,25 +1713,27 @@ rb_raise(rb_eNoMemError, "not enough memory to initialize Info object"); } info_obj = Data_Wrap_Struct(class, NULL, destroy_Info, info); return info_obj; } + + /* Extern: rm_info_new Purpose: provide a Info.new method for internal use Notes: takes no parameters, but runs the parm block if present */ VALUE -rm_info_new(void) +rm_info_new() { volatile VALUE info_obj; info_obj = Info_alloc(Class_Info); return Info_initialize(info_obj); } -#endif + /* Method: Info#initialize Purpose: If an initializer block is present, run it. */ VALUE @@ -1873,63 +1743,7 @@ { // Run the block in self's context (void) rb_obj_instance_eval(0, NULL, self); } return self; -} - - -/* - Method: Info#get_option - Purpose: Return the value of the specified option -*/ -static VALUE -get_option(VALUE self, char *key) -{ -#if defined(HAVE_SETIMAGEOPTION) - Info *info; - const char *value; - - Data_Get_Struct(self, Info, info); - - value = GetImageOption(info, key); - if (value) - { - return rb_str_new2(value); - } - return Qnil; -#else - rm_not_implemented(); - return (VALUE)0; -#endif -} - -/* - Method: Info#set_option - Purpose: Set the specified option to this value. - If the value is nil just unset any current value -*/ -static VALUE -set_option(VALUE self, char *key, VALUE string) -{ -#if defined(HAVE_SETIMAGEOPTION) - Info *info; - char *value; - - Data_Get_Struct(self, Info, info); - - if (NIL_P(string)) - { - (void) RemoveImageOption(info, key); - } - else - { - value = STRING_PTR(string); - (void) SetImageOption(info, key, value); - } - return self; -#else - rm_not_implemented(); - return (VALUE)0; -#endif }