rmagick 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rmagick might be problematic. Click here for more details.
- data/ChangeLog +232 -0
- data/Makefile.in +28 -0
- data/README.html +404 -0
- data/README.txt +397 -0
- data/configure +8554 -0
- data/configure.ac +497 -0
- data/doc/comtasks.html +241 -0
- data/doc/constants.html +1195 -0
- data/doc/css/doc.css +299 -0
- data/doc/css/popup.css +34 -0
- data/doc/draw.html +3108 -0
- data/doc/ex/Adispatch.rb +43 -0
- data/doc/ex/Zconstitute.rb +9 -0
- data/doc/ex/adaptive_threshold.rb +19 -0
- data/doc/ex/add_noise.rb +18 -0
- data/doc/ex/affine.rb +48 -0
- data/doc/ex/affine_transform.rb +20 -0
- data/doc/ex/arc.rb +47 -0
- data/doc/ex/arcpath.rb +33 -0
- data/doc/ex/average.rb +15 -0
- data/doc/ex/axes.rb +64 -0
- data/doc/ex/bilevel_channel.rb +20 -0
- data/doc/ex/blur_image.rb +12 -0
- data/doc/ex/border.rb +10 -0
- data/doc/ex/bounding_box.rb +48 -0
- data/doc/ex/cbezier1.rb +40 -0
- data/doc/ex/cbezier2.rb +40 -0
- data/doc/ex/cbezier3.rb +40 -0
- data/doc/ex/cbezier4.rb +41 -0
- data/doc/ex/cbezier5.rb +41 -0
- data/doc/ex/cbezier6.rb +51 -0
- data/doc/ex/channel.rb +26 -0
- data/doc/ex/channel_threshold.rb +48 -0
- data/doc/ex/charcoal.rb +12 -0
- data/doc/ex/chop.rb +29 -0
- data/doc/ex/circle.rb +31 -0
- data/doc/ex/clip_path.rb +56 -0
- data/doc/ex/coalesce.rb +60 -0
- data/doc/ex/color_fill_to_border.rb +29 -0
- data/doc/ex/color_floodfill.rb +28 -0
- data/doc/ex/color_histogram.rb +60 -0
- data/doc/ex/color_reset.rb +11 -0
- data/doc/ex/colorize.rb +16 -0
- data/doc/ex/colors.rb +65 -0
- data/doc/ex/composite.rb +135 -0
- data/doc/ex/contrast.rb +37 -0
- data/doc/ex/crop.rb +31 -0
- data/doc/ex/crop_with_gravity.rb +46 -0
- data/doc/ex/cycle_colormap.rb +21 -0
- data/doc/ex/demo.rb +324 -0
- data/doc/ex/drawcomp.rb +42 -0
- data/doc/ex/drop_shadow.rb +60 -0
- data/doc/ex/edge.rb +11 -0
- data/doc/ex/ellipse.rb +43 -0
- data/doc/ex/emboss.rb +11 -0
- data/doc/ex/enhance.rb +28 -0
- data/doc/ex/equalize.rb +11 -0
- data/doc/ex/flatten_images.rb +38 -0
- data/doc/ex/flip.rb +11 -0
- data/doc/ex/flop.rb +11 -0
- data/doc/ex/fonts.rb +20 -0
- data/doc/ex/frame.rb +12 -0
- data/doc/ex/gaussian_blur.rb +11 -0
- data/doc/ex/get_multiline_type_metrics.rb +53 -0
- data/doc/ex/get_pixels.rb +48 -0
- data/doc/ex/get_type_metrics.rb +140 -0
- data/doc/ex/gradientfill.rb +27 -0
- data/doc/ex/grav.rb +44 -0
- data/doc/ex/gravity.rb +80 -0
- data/doc/ex/hatchfill.rb +27 -0
- data/doc/ex/images/Ballerina.jpg +0 -0
- data/doc/ex/images/Ballerina3.jpg +0 -0
- data/doc/ex/images/Button_0.gif +0 -0
- data/doc/ex/images/Button_1.gif +0 -0
- data/doc/ex/images/Button_2.gif +0 -0
- data/doc/ex/images/Button_3.gif +0 -0
- data/doc/ex/images/Button_4.gif +0 -0
- data/doc/ex/images/Button_5.gif +0 -0
- data/doc/ex/images/Button_6.gif +0 -0
- data/doc/ex/images/Button_7.gif +0 -0
- data/doc/ex/images/Button_8.gif +0 -0
- data/doc/ex/images/Button_9.gif +0 -0
- data/doc/ex/images/Button_A.gif +0 -0
- data/doc/ex/images/Button_B.gif +0 -0
- data/doc/ex/images/Button_C.gif +0 -0
- data/doc/ex/images/Button_D.gif +0 -0
- data/doc/ex/images/Button_E.gif +0 -0
- data/doc/ex/images/Button_F.gif +0 -0
- data/doc/ex/images/Button_G.gif +0 -0
- data/doc/ex/images/Button_H.gif +0 -0
- data/doc/ex/images/Button_I.gif +0 -0
- data/doc/ex/images/Button_J.gif +0 -0
- data/doc/ex/images/Button_K.gif +0 -0
- data/doc/ex/images/Button_L.gif +0 -0
- data/doc/ex/images/Button_M.gif +0 -0
- data/doc/ex/images/Button_N.gif +0 -0
- data/doc/ex/images/Button_O.gif +0 -0
- data/doc/ex/images/Button_P.gif +0 -0
- data/doc/ex/images/Button_Q.gif +0 -0
- data/doc/ex/images/Button_R.gif +0 -0
- data/doc/ex/images/Button_S.gif +0 -0
- data/doc/ex/images/Button_T.gif +0 -0
- data/doc/ex/images/Button_U.gif +0 -0
- data/doc/ex/images/Button_V.gif +0 -0
- data/doc/ex/images/Button_W.gif +0 -0
- data/doc/ex/images/Button_X.gif +0 -0
- data/doc/ex/images/Button_Y.gif +0 -0
- data/doc/ex/images/Button_Z.gif +0 -0
- data/doc/ex/images/Cheetah.jpg +0 -0
- data/doc/ex/images/Coffee.wmf +0 -0
- data/doc/ex/images/Flower_Hat.jpg +0 -0
- data/doc/ex/images/Gold_Statue.jpg +0 -0
- data/doc/ex/images/Hot_Air_Balloons.jpg +0 -0
- data/doc/ex/images/Hot_Air_Balloons_H.jpg +0 -0
- data/doc/ex/images/No.wmf +0 -0
- data/doc/ex/images/Polynesia.jpg +0 -0
- data/doc/ex/images/Red_Rocks.jpg +0 -0
- data/doc/ex/images/Shorts.jpg +0 -0
- data/doc/ex/images/Snake.wmf +0 -0
- data/doc/ex/images/Violin.jpg +0 -0
- data/doc/ex/images/graydient230x6.gif +0 -0
- data/doc/ex/images/logo400x83.gif +0 -0
- data/doc/ex/images/model.miff +0 -0
- data/doc/ex/images/notimplemented.gif +0 -0
- data/doc/ex/images/smile.miff +0 -0
- data/doc/ex/images/spin.gif +0 -0
- data/doc/ex/implode.rb +32 -0
- data/doc/ex/level.rb +12 -0
- data/doc/ex/level_channel.rb +33 -0
- data/doc/ex/line.rb +40 -0
- data/doc/ex/map.rb +28 -0
- data/doc/ex/map_f.rb +15 -0
- data/doc/ex/matte_fill_to_border.rb +42 -0
- data/doc/ex/matte_floodfill.rb +35 -0
- data/doc/ex/matte_replace.rb +42 -0
- data/doc/ex/median_filter.rb +28 -0
- data/doc/ex/modulate.rb +11 -0
- data/doc/ex/mono.rb +23 -0
- data/doc/ex/morph.rb +26 -0
- data/doc/ex/mosaic.rb +35 -0
- data/doc/ex/motion_blur.rb +11 -0
- data/doc/ex/negate.rb +11 -0
- data/doc/ex/negate_channel.rb +19 -0
- data/doc/ex/normalize.rb +11 -0
- data/doc/ex/oil_paint.rb +11 -0
- data/doc/ex/opacity.rb +38 -0
- data/doc/ex/opaque.rb +14 -0
- data/doc/ex/ordered_dither.rb +11 -0
- data/doc/ex/path.rb +62 -0
- data/doc/ex/pattern1.rb +25 -0
- data/doc/ex/pattern2.rb +26 -0
- data/doc/ex/polygon.rb +24 -0
- data/doc/ex/polyline.rb +23 -0
- data/doc/ex/posterize.rb +19 -0
- data/doc/ex/preview.rb +16 -0
- data/doc/ex/qbezierpath.rb +49 -0
- data/doc/ex/quantize-m.rb +25 -0
- data/doc/ex/radial_blur.rb +19 -0
- data/doc/ex/raise.rb +11 -0
- data/doc/ex/random_channel_threshold.rb +17 -0
- data/doc/ex/random_threshold_channel.rb +18 -0
- data/doc/ex/rectangle.rb +33 -0
- data/doc/ex/reduce_noise.rb +28 -0
- data/doc/ex/roll.rb +9 -0
- data/doc/ex/rotate.rb +43 -0
- data/doc/ex/rotate_f.rb +14 -0
- data/doc/ex/roundrect.rb +32 -0
- data/doc/ex/rubyname.rb +31 -0
- data/doc/ex/segment.rb +11 -0
- data/doc/ex/shade.rb +11 -0
- data/doc/ex/shave.rb +15 -0
- data/doc/ex/shear.rb +10 -0
- data/doc/ex/skewx.rb +50 -0
- data/doc/ex/skewy.rb +45 -0
- data/doc/ex/smile.rb +124 -0
- data/doc/ex/solarize.rb +11 -0
- data/doc/ex/splice.rb +16 -0
- data/doc/ex/spread.rb +11 -0
- data/doc/ex/stegano.rb +50 -0
- data/doc/ex/stroke_dasharray.rb +41 -0
- data/doc/ex/stroke_linecap.rb +44 -0
- data/doc/ex/stroke_linejoin.rb +48 -0
- data/doc/ex/stroke_width.rb +47 -0
- data/doc/ex/swirl.rb +17 -0
- data/doc/ex/text.rb +32 -0
- data/doc/ex/text_align.rb +36 -0
- data/doc/ex/text_antialias.rb +33 -0
- data/doc/ex/text_undercolor.rb +26 -0
- data/doc/ex/texture_fill_to_border.rb +34 -0
- data/doc/ex/texture_floodfill.rb +31 -0
- data/doc/ex/texturefill.rb +25 -0
- data/doc/ex/threshold.rb +13 -0
- data/doc/ex/to_blob.rb +14 -0
- data/doc/ex/translate.rb +37 -0
- data/doc/ex/transparent.rb +38 -0
- data/doc/ex/trim.rb +25 -0
- data/doc/ex/unsharp_mask.rb +28 -0
- data/doc/ex/viewex.rb +36 -0
- data/doc/ex/wave.rb +9 -0
- data/doc/ilist.html +1592 -0
- data/doc/image1.html +3009 -0
- data/doc/image2.html +2169 -0
- data/doc/image3.html +2815 -0
- data/doc/imageattrs.html +1319 -0
- data/doc/imusage.html +403 -0
- data/doc/index.html +418 -0
- data/doc/info.html +949 -0
- data/doc/magick.html +439 -0
- data/doc/scripts/doc.js +9 -0
- data/doc/struct.html +1334 -0
- data/doc/usage.html +1318 -0
- data/examples/describe.rb +44 -0
- data/examples/histogram.rb +289 -0
- data/examples/image_opacity.rb +29 -0
- data/examples/import_export.rb +31 -0
- data/examples/pattern_fill.rb +38 -0
- data/examples/rotating_text.rb +47 -0
- data/examples/thumbnail.rb +65 -0
- data/examples/vignette.rb +79 -0
- data/ext/RMagick/MANIFEST +239 -0
- data/ext/RMagick/extconf.rb.in +21 -0
- data/ext/RMagick/rmagick.h +938 -0
- data/ext/RMagick/rmagick_config.h.in +170 -0
- data/ext/RMagick/rmdraw.c +1308 -0
- data/ext/RMagick/rmfill.c +609 -0
- data/ext/RMagick/rmilist.c +685 -0
- data/ext/RMagick/rmimage.c +7980 -0
- data/ext/RMagick/rminfo.c +982 -0
- data/ext/RMagick/rmmain.c +1497 -0
- data/ext/RMagick/rmutil.c +2685 -0
- data/install.rb +1015 -0
- data/lib/RMagick.rb +1486 -0
- data/metaconfig.in +6 -0
- data/post-clean.rb +12 -0
- data/post-install.rb +36 -0
- data/post-setup.rb +245 -0
- data/rmagick.gemspec +22 -0
- data/uninstall.rb +71 -0
- metadata +286 -0
@@ -0,0 +1,2685 @@
|
|
1
|
+
/* $Id: rmutil.c,v 1.47 2004/12/25 18:59:03 rmagick Exp $ */
|
2
|
+
/*============================================================================\
|
3
|
+
| Copyright (C) 2004 by Timothy P. Hunter
|
4
|
+
| Name: rmutil.c
|
5
|
+
| Author: Tim Hunter
|
6
|
+
| Purpose: Utility functions for RMagick
|
7
|
+
\============================================================================*/
|
8
|
+
|
9
|
+
#include "rmagick.h"
|
10
|
+
|
11
|
+
static const char *Compliance_Const_Name(ComplianceType *);
|
12
|
+
static const char *StyleType_Const_Name(StyleType);
|
13
|
+
static const char *StretchType_Const_Name(StretchType);
|
14
|
+
static void Color_Name_to_PixelPacket(PixelPacket *, VALUE);
|
15
|
+
static VALUE Enum_type_values(VALUE);
|
16
|
+
static VALUE Enum_type_inspect(VALUE);
|
17
|
+
|
18
|
+
/*
|
19
|
+
Extern: magick_malloc, magick_free, magick_realloc
|
20
|
+
Purpose: ****Magick versions of standard memory routines.
|
21
|
+
Notes: use when managing memory that ****Magick may have
|
22
|
+
allocated or may free.
|
23
|
+
If malloc fails, it raises an exception
|
24
|
+
*/
|
25
|
+
void *magick_malloc(const size_t size)
|
26
|
+
{
|
27
|
+
void *ptr;
|
28
|
+
#if defined(HAVE_ACQUIREMAGICKMEMORY)
|
29
|
+
ptr = AcquireMagickMemory(size);
|
30
|
+
#else
|
31
|
+
ptr = AcquireMemory(size);
|
32
|
+
#endif
|
33
|
+
if (!ptr)
|
34
|
+
{
|
35
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
36
|
+
}
|
37
|
+
|
38
|
+
return ptr;
|
39
|
+
}
|
40
|
+
|
41
|
+
void magick_free(void *ptr)
|
42
|
+
{
|
43
|
+
#if defined(HAVE_ACQUIREMAGICKMEMORY)
|
44
|
+
RelinquishMagickMemory(ptr);
|
45
|
+
#else
|
46
|
+
void *v = ptr;
|
47
|
+
LiberateMemory(&v);
|
48
|
+
#endif
|
49
|
+
}
|
50
|
+
|
51
|
+
void *magick_realloc(void *ptr, const size_t size)
|
52
|
+
{
|
53
|
+
void *v;
|
54
|
+
#if defined(HAVE_ACQUIREMAGICKMEMORY)
|
55
|
+
v = ResizeMagickMemory(ptr, size);
|
56
|
+
#else
|
57
|
+
v = ptr;
|
58
|
+
ReacquireMemory(&v, size);
|
59
|
+
#endif
|
60
|
+
if (!v)
|
61
|
+
{
|
62
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
63
|
+
}
|
64
|
+
return v;
|
65
|
+
}
|
66
|
+
|
67
|
+
/*
|
68
|
+
Extern: magick_clone_string
|
69
|
+
Purpose: make a copy of a string in malloc'd memory
|
70
|
+
Notes: Any existing string pointed to by *new_str is freed.
|
71
|
+
CloneString asserts if no memory. No need to check
|
72
|
+
its return value.
|
73
|
+
|
74
|
+
*/
|
75
|
+
void magick_clone_string(char **new_str, const char *str)
|
76
|
+
{
|
77
|
+
CloneString(new_str, str);
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
/*
|
83
|
+
Extern: rm_string_value_ptr(VALUE*)
|
84
|
+
Purpose: emulate Ruby 1.8's rb_string_value_ptr
|
85
|
+
Notes: This is essentially 1.8's rb_string_value_ptr
|
86
|
+
with a few minor changes to make it work in 1.6.
|
87
|
+
Always called via STRING_PTR
|
88
|
+
*/
|
89
|
+
#if !defined StringValuePtr
|
90
|
+
char *
|
91
|
+
rm_string_value_ptr(volatile VALUE *ptr)
|
92
|
+
{
|
93
|
+
volatile VALUE s = *ptr;
|
94
|
+
|
95
|
+
// If VALUE is not a string, call to_str on it
|
96
|
+
if (TYPE(s) != T_STRING)
|
97
|
+
{
|
98
|
+
s = rb_str_to_str(s);
|
99
|
+
*ptr = s;
|
100
|
+
}
|
101
|
+
// If ptr == NULL, allocate a 1 char array
|
102
|
+
if (!RSTRING(s)->ptr)
|
103
|
+
{
|
104
|
+
RSTRING(s)->ptr = ALLOC_N(char, 1);
|
105
|
+
(RSTRING(s)->ptr)[0] = 0;
|
106
|
+
RSTRING(s)->orig = 0;
|
107
|
+
}
|
108
|
+
return RSTRING(s)->ptr;
|
109
|
+
}
|
110
|
+
#endif
|
111
|
+
|
112
|
+
/*
|
113
|
+
Extern: rm_string_value_ptr_len
|
114
|
+
Purpose: safe replacement for rb_str2cstr
|
115
|
+
Returns: stores string length in 2nd arg, returns ptr to C string
|
116
|
+
Notes: Uses rb/rm_string_value_ptr to ensure correct String
|
117
|
+
argument.
|
118
|
+
Always called via STRING_PTR_LEN
|
119
|
+
*/
|
120
|
+
char *rm_string_value_ptr_len(volatile VALUE *ptr, long *len)
|
121
|
+
{
|
122
|
+
volatile VALUE v = *ptr;
|
123
|
+
char *str;
|
124
|
+
|
125
|
+
str = STRING_PTR(v);
|
126
|
+
*ptr = v;
|
127
|
+
*len = RSTRING(v)->len;
|
128
|
+
return str;
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
/*
|
133
|
+
* Extern: rm_check_ary_len(ary, len)
|
134
|
+
* Purpose: raise exception if array too short
|
135
|
+
*/
|
136
|
+
void
|
137
|
+
rm_check_ary_len(VALUE ary, int len)
|
138
|
+
{
|
139
|
+
if (RARRAY(ary)->len < len)
|
140
|
+
{
|
141
|
+
rb_raise(rb_eIndexError, "not enough elements in array - expecting %d, got %d",
|
142
|
+
len, RARRAY(ary)->len);
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
/*
|
147
|
+
Extern: rm_check_frozen
|
148
|
+
Purpose: backport rb_check_frozen for 1.6.x releases
|
149
|
+
*/
|
150
|
+
void
|
151
|
+
rm_check_frozen(VALUE obj)
|
152
|
+
{
|
153
|
+
if (OBJ_FROZEN(obj))
|
154
|
+
{
|
155
|
+
rb_error_frozen(rb_class2name(CLASS_OF(obj)));
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
/*
|
161
|
+
Extern: rm_no_freeze(obj)
|
162
|
+
Purpose: overrides freeze in classes that can't be frozen.
|
163
|
+
*/
|
164
|
+
VALUE
|
165
|
+
rm_no_freeze(VALUE obj)
|
166
|
+
{
|
167
|
+
rb_raise(rb_eTypeError, "can't freeze %s", rb_class2name(CLASS_OF(obj)));
|
168
|
+
}
|
169
|
+
|
170
|
+
|
171
|
+
/*
|
172
|
+
* Extern: rm_obj_to_s(obj)
|
173
|
+
* Purpose: try to convert object to string by calling its `to_s' method
|
174
|
+
* Notes: Usually run via rb_rescue so TypeError or NoMethodError can be
|
175
|
+
* rescued. I use this instead of rb_str_to_str so that objects
|
176
|
+
* that don't have `to_str' but do have `to_s' can be converted.
|
177
|
+
*/
|
178
|
+
VALUE
|
179
|
+
rm_obj_to_s(VALUE obj)
|
180
|
+
{
|
181
|
+
return TYPE(obj) == T_STRING ? obj : rb_funcall(obj, ID_to_s, 0);
|
182
|
+
}
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
/*
|
187
|
+
* Static: arg_is_number
|
188
|
+
* Purpose: Try to convert the argument to a double,
|
189
|
+
* raise an exception if fail.
|
190
|
+
*/
|
191
|
+
static VALUE
|
192
|
+
arg_is_number(VALUE arg)
|
193
|
+
{
|
194
|
+
double d;
|
195
|
+
d = NUM2DBL(arg);
|
196
|
+
d = d; // satisfy icc
|
197
|
+
return arg;
|
198
|
+
}
|
199
|
+
|
200
|
+
|
201
|
+
/*
|
202
|
+
* Static: fuzz_arg_rescue
|
203
|
+
* Purpose: called when `rb_str_to_str' raised an exception below
|
204
|
+
*/
|
205
|
+
static VALUE
|
206
|
+
fuzz_arg_rescue(VALUE arg)
|
207
|
+
{
|
208
|
+
rb_raise(rb_eArgError, "argument must be a number or a string in the form 'NN%' (%s given)",
|
209
|
+
rb_class2name(CLASS_OF(arg)));
|
210
|
+
}
|
211
|
+
|
212
|
+
|
213
|
+
/*
|
214
|
+
* Extern: rm_fuzz_to_dbl(obj)
|
215
|
+
* Purpose: If the argument is a number, convert it to a double.
|
216
|
+
* Otherwise it's supposed to be a string in the form 'NN%'.
|
217
|
+
* Return a percentage of MaxRGB.
|
218
|
+
* Notes: Called from Image#fuzz= and Info#fuzz=
|
219
|
+
*/
|
220
|
+
double
|
221
|
+
rm_fuzz_to_dbl(VALUE fuzz_arg)
|
222
|
+
{
|
223
|
+
double fuzz;
|
224
|
+
char *fuzz_str, *end;
|
225
|
+
int not_num;
|
226
|
+
|
227
|
+
// Try to convert the argument to a number. If failure, sets not_num to non-zero.
|
228
|
+
rb_protect(arg_is_number, fuzz_arg, ¬_num);
|
229
|
+
|
230
|
+
if (not_num)
|
231
|
+
{
|
232
|
+
// Convert to string, issue error message if failure.
|
233
|
+
fuzz_arg = rb_rescue(rb_str_to_str, fuzz_arg, fuzz_arg_rescue, fuzz_arg);
|
234
|
+
fuzz_str = STRING_PTR(fuzz_arg);
|
235
|
+
fuzz = strtod(fuzz_str, &end);
|
236
|
+
if(*end == '%')
|
237
|
+
{
|
238
|
+
fuzz = (fuzz * MaxRGB) / 100;
|
239
|
+
}
|
240
|
+
else if(*end != '\0')
|
241
|
+
{
|
242
|
+
rb_raise(rb_eArgError, "expected percentage, got `%s'", fuzz_str);
|
243
|
+
}
|
244
|
+
}
|
245
|
+
else
|
246
|
+
{
|
247
|
+
fuzz = NUM2DBL(fuzz_arg);
|
248
|
+
}
|
249
|
+
|
250
|
+
return fuzz;
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
/*
|
255
|
+
Extern: ImageList_cur_image
|
256
|
+
Purpose: Sends the "cur_image" method to the object. If 'img'
|
257
|
+
is an ImageList, then cur_image is self[@scene].
|
258
|
+
If 'img' is an image, then cur_image is simply
|
259
|
+
'self'.
|
260
|
+
Returns: the return value from "cur_image"
|
261
|
+
*/
|
262
|
+
VALUE
|
263
|
+
ImageList_cur_image(VALUE img)
|
264
|
+
{
|
265
|
+
return rb_funcall(img, ID_cur_image, 0);
|
266
|
+
}
|
267
|
+
|
268
|
+
/*
|
269
|
+
Method: Magick::PrimaryInfo#to_s
|
270
|
+
Purpose: Create a string representation of a Magick::PrimaryInfo
|
271
|
+
*/
|
272
|
+
VALUE
|
273
|
+
PrimaryInfo_to_s(VALUE self)
|
274
|
+
{
|
275
|
+
PrimaryInfo pi;
|
276
|
+
char buff[100];
|
277
|
+
|
278
|
+
PrimaryInfo_to_PrimaryInfo(&pi, self);
|
279
|
+
sprintf(buff, "x=%g, y=%g, z=%g", pi.x, pi.y, pi.z);
|
280
|
+
return rb_str_new2(buff);
|
281
|
+
}
|
282
|
+
|
283
|
+
/*
|
284
|
+
Method: Magick::Chromaticity#to_s
|
285
|
+
Purpose: Create a string representation of a Magick::Chromaticity
|
286
|
+
*/
|
287
|
+
VALUE
|
288
|
+
ChromaticityInfo_to_s(VALUE self)
|
289
|
+
{
|
290
|
+
ChromaticityInfo ci;
|
291
|
+
char buff[200];
|
292
|
+
|
293
|
+
ChromaticityInfo_to_ChromaticityInfo(&ci, self);
|
294
|
+
sprintf(buff, "red_primary=(x=%g,y=%g) "
|
295
|
+
"green_primary=(x=%g,y=%g) "
|
296
|
+
"blue_primary=(x=%g,y=%g) "
|
297
|
+
"white_point=(x=%g,y=%g) ",
|
298
|
+
ci.red_primary.x, ci.red_primary.y,
|
299
|
+
ci.green_primary.x, ci.green_primary.y,
|
300
|
+
ci.blue_primary.x, ci.blue_primary.y,
|
301
|
+
ci.white_point.x, ci.white_point.y);
|
302
|
+
return rb_str_new2(buff);
|
303
|
+
}
|
304
|
+
|
305
|
+
/*
|
306
|
+
Method: Magick::Pixel#to_s
|
307
|
+
Purpose: Create a string representation of a Magick::Pixel
|
308
|
+
*/
|
309
|
+
VALUE
|
310
|
+
Pixel_to_s(VALUE self)
|
311
|
+
{
|
312
|
+
Pixel *pixel;
|
313
|
+
char buff[100];
|
314
|
+
|
315
|
+
Data_Get_Struct(self, Pixel, pixel);
|
316
|
+
sprintf(buff, "red=%d, green=%d, blue=%d, opacity=%d"
|
317
|
+
, pixel->red, pixel->green, pixel->blue, pixel->opacity);
|
318
|
+
return rb_str_new2(buff);
|
319
|
+
}
|
320
|
+
|
321
|
+
/*
|
322
|
+
Method: Magick::Pixel.from_color(string)
|
323
|
+
Purpose: Construct an Magick::Pixel corresponding to the given color name.
|
324
|
+
Notes: the "inverse" is Image *#to_color, b/c the conversion of a pixel
|
325
|
+
to a color name requires both a color depth and if the opacity
|
326
|
+
value has meaning (i.e. whether image->matte == True or not).
|
327
|
+
|
328
|
+
Also see Magick::Pixel#to_color, below.
|
329
|
+
*/
|
330
|
+
VALUE
|
331
|
+
Pixel_from_color(VALUE class, VALUE name)
|
332
|
+
{
|
333
|
+
PixelPacket pp;
|
334
|
+
ExceptionInfo exception;
|
335
|
+
boolean okay;
|
336
|
+
|
337
|
+
class = class; // defeat "never referenced" message from icc
|
338
|
+
|
339
|
+
GetExceptionInfo(&exception);
|
340
|
+
okay = QueryColorDatabase(STRING_PTR(name), &pp, &exception);
|
341
|
+
HANDLE_ERROR
|
342
|
+
if (!okay)
|
343
|
+
{
|
344
|
+
rb_raise(rb_eArgError, "invalid color name: %s", STRING_PTR(name));
|
345
|
+
}
|
346
|
+
|
347
|
+
return Pixel_from_PixelPacket(&pp);
|
348
|
+
}
|
349
|
+
|
350
|
+
/*
|
351
|
+
Method: Magick::Pixel#to_color(compliance=Magick::???Compliance,
|
352
|
+
matte=False
|
353
|
+
depth=QuantumDepth)
|
354
|
+
Purpose: return the color name corresponding to the pixel values
|
355
|
+
Notes: the conversion respects the value of the 'opacity' field
|
356
|
+
in the Pixel.
|
357
|
+
*/
|
358
|
+
VALUE
|
359
|
+
Pixel_to_color(int argc, VALUE *argv, VALUE self)
|
360
|
+
{
|
361
|
+
Info *info;
|
362
|
+
Image *image;
|
363
|
+
Pixel *pixel;
|
364
|
+
char name[MaxTextExtent];
|
365
|
+
ExceptionInfo exception;
|
366
|
+
ComplianceType compliance = AllCompliance;
|
367
|
+
unsigned int matte = False;
|
368
|
+
unsigned int depth = QuantumDepth;
|
369
|
+
|
370
|
+
switch (argc)
|
371
|
+
{
|
372
|
+
case 3:
|
373
|
+
depth = NUM2UINT(argv[2]);
|
374
|
+
|
375
|
+
// Ensure depth is appropriate for the way xMagick was compiled.
|
376
|
+
switch (depth)
|
377
|
+
{
|
378
|
+
case 8:
|
379
|
+
#if QuantumDepth == 16 || QuantumDepth == 32
|
380
|
+
case 16:
|
381
|
+
#endif
|
382
|
+
#if QuantumDepth == 32
|
383
|
+
case 32:
|
384
|
+
#endif
|
385
|
+
break;
|
386
|
+
default:
|
387
|
+
rb_raise(rb_eArgError, "invalid depth (%d)", depth);
|
388
|
+
break;
|
389
|
+
}
|
390
|
+
case 2:
|
391
|
+
matte = RTEST(argv[1]);
|
392
|
+
case 1:
|
393
|
+
VALUE_TO_ENUM(argv[0], compliance, ComplianceType);
|
394
|
+
case 0:
|
395
|
+
break;
|
396
|
+
default:
|
397
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 2)", argc);
|
398
|
+
}
|
399
|
+
|
400
|
+
Data_Get_Struct(self, Pixel, pixel);
|
401
|
+
|
402
|
+
info = CloneImageInfo(NULL);
|
403
|
+
image = AllocateImage(info);
|
404
|
+
image->depth = depth;
|
405
|
+
image->matte = matte;
|
406
|
+
DestroyImageInfo(info);
|
407
|
+
GetExceptionInfo(&exception);
|
408
|
+
(void) QueryColorname(image, pixel, compliance, name, &exception);
|
409
|
+
DestroyImage(image);
|
410
|
+
HANDLE_ERROR
|
411
|
+
|
412
|
+
// Always return a string, even if it's ""
|
413
|
+
return rb_str_new2(name);
|
414
|
+
}
|
415
|
+
|
416
|
+
/*
|
417
|
+
Method: Pixel#to_HSL
|
418
|
+
Purpose: Converts an RGB pixel to the array
|
419
|
+
[hue, saturation, luminosity].
|
420
|
+
*/
|
421
|
+
VALUE
|
422
|
+
Pixel_to_HSL(VALUE self)
|
423
|
+
{
|
424
|
+
Pixel *pixel;
|
425
|
+
double hue, saturation, luminosity;
|
426
|
+
volatile VALUE hsl;
|
427
|
+
|
428
|
+
Data_Get_Struct(self, Pixel, pixel);
|
429
|
+
TransformHSL(pixel->red, pixel->green, pixel->blue,
|
430
|
+
&hue, &saturation, &luminosity);
|
431
|
+
|
432
|
+
hsl = rb_ary_new3(3, rb_float_new(hue), rb_float_new(saturation),
|
433
|
+
rb_float_new(luminosity));
|
434
|
+
|
435
|
+
return hsl;
|
436
|
+
}
|
437
|
+
|
438
|
+
/*
|
439
|
+
Method: Pixel.from_HSL
|
440
|
+
Purpose: Constructs an RGB pixel from the array
|
441
|
+
[hue, saturation, luminosity].
|
442
|
+
*/
|
443
|
+
VALUE
|
444
|
+
Pixel_from_HSL(VALUE class, VALUE hsl)
|
445
|
+
{
|
446
|
+
PixelPacket rgb = {0};
|
447
|
+
double hue, saturation, luminosity;
|
448
|
+
|
449
|
+
class = class; // defeat "never referenced" message from icc
|
450
|
+
|
451
|
+
Check_Type(hsl, T_ARRAY);
|
452
|
+
|
453
|
+
hue = NUM2DBL(rb_ary_entry(hsl, 0));
|
454
|
+
saturation = NUM2DBL(rb_ary_entry(hsl, 1));
|
455
|
+
luminosity = NUM2DBL(rb_ary_entry(hsl, 2));
|
456
|
+
|
457
|
+
HSLTransform(hue, saturation, luminosity,
|
458
|
+
&rgb.red, &rgb.green, &rgb.blue);
|
459
|
+
return Pixel_from_PixelPacket(&rgb);
|
460
|
+
}
|
461
|
+
|
462
|
+
/*
|
463
|
+
Method: Pixel#fcmp(other[, fuzz[, colorspace]])
|
464
|
+
Purpose: Compare pixel values for equality
|
465
|
+
Notes: The colorspace value is ignored < 5.5.5
|
466
|
+
and > 5.5.7.
|
467
|
+
*/
|
468
|
+
VALUE
|
469
|
+
Pixel_fcmp(int argc, VALUE *argv, VALUE self)
|
470
|
+
{
|
471
|
+
#if defined(HAVE_FUZZYCOLORCOMPARE)
|
472
|
+
Image *image;
|
473
|
+
Info *info;
|
474
|
+
#endif
|
475
|
+
|
476
|
+
Pixel *this, *that;
|
477
|
+
ColorspaceType colorspace = RGBColorspace;
|
478
|
+
double fuzz = 0.0;
|
479
|
+
unsigned int equal;
|
480
|
+
|
481
|
+
switch (argc)
|
482
|
+
{
|
483
|
+
case 3:
|
484
|
+
VALUE_TO_ENUM(argv[2], colorspace, ColorspaceType);
|
485
|
+
case 2:
|
486
|
+
fuzz = NUM2DBL(argv[1]);
|
487
|
+
case 1:
|
488
|
+
// Allow 1 argument
|
489
|
+
break;
|
490
|
+
default:
|
491
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 to 3)", argc);
|
492
|
+
break;
|
493
|
+
}
|
494
|
+
|
495
|
+
Data_Get_Struct(self, Pixel, this);
|
496
|
+
Data_Get_Struct(argv[0], Pixel, that);
|
497
|
+
|
498
|
+
#if defined(HAVE_FUZZYCOLORCOMPARE)
|
499
|
+
// The FuzzyColorCompare function expects to get the
|
500
|
+
// colorspace and fuzz parameters from an Image structure.
|
501
|
+
|
502
|
+
info = CloneImageInfo(NULL);
|
503
|
+
if (!info)
|
504
|
+
{
|
505
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
506
|
+
}
|
507
|
+
|
508
|
+
image = AllocateImage(info);
|
509
|
+
if (!image)
|
510
|
+
{
|
511
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
512
|
+
}
|
513
|
+
DestroyImageInfo(info);
|
514
|
+
|
515
|
+
image->colorspace = colorspace;
|
516
|
+
image->fuzz = fuzz;
|
517
|
+
|
518
|
+
equal = FuzzyColorCompare(image, this, that);
|
519
|
+
DestroyImage(image);
|
520
|
+
|
521
|
+
#else
|
522
|
+
equal = FuzzyColorMatch(this, that, fuzz);
|
523
|
+
#endif
|
524
|
+
|
525
|
+
return equal ? Qtrue : Qfalse;
|
526
|
+
}
|
527
|
+
|
528
|
+
/*
|
529
|
+
Method: Pixel#intensity
|
530
|
+
Purpose: Return the "intensity" of a pixel
|
531
|
+
*/
|
532
|
+
VALUE
|
533
|
+
Pixel_intensity(VALUE self)
|
534
|
+
{
|
535
|
+
Pixel *pixel;
|
536
|
+
unsigned long intensity;
|
537
|
+
|
538
|
+
Data_Get_Struct(self, Pixel, pixel);
|
539
|
+
|
540
|
+
intensity = (unsigned long)
|
541
|
+
(0.299*pixel->red) + (0.587*pixel->green) + (0.114*pixel->blue);
|
542
|
+
|
543
|
+
return ULONG2NUM(intensity);
|
544
|
+
}
|
545
|
+
|
546
|
+
|
547
|
+
/*
|
548
|
+
Methods: Pixel RGBA attribute accessors
|
549
|
+
Purpose: Get/set Pixel attributes
|
550
|
+
Note: Pixel is Observable. Setters call changed, notify_observers
|
551
|
+
Note: Setters return their argument values for backward compatibility
|
552
|
+
to when Pixel was a Struct class.
|
553
|
+
*/
|
554
|
+
|
555
|
+
DEF_ATTR_READER(Pixel, red, int)
|
556
|
+
DEF_ATTR_READER(Pixel, green, int)
|
557
|
+
DEF_ATTR_READER(Pixel, blue, int)
|
558
|
+
DEF_ATTR_READER(Pixel, opacity, int)
|
559
|
+
DEF_PIXEL_CHANNEL_WRITER(red)
|
560
|
+
DEF_PIXEL_CHANNEL_WRITER(green)
|
561
|
+
DEF_PIXEL_CHANNEL_WRITER(blue)
|
562
|
+
DEF_PIXEL_CHANNEL_WRITER(opacity)
|
563
|
+
|
564
|
+
|
565
|
+
/*
|
566
|
+
Method: Pixel#<=>
|
567
|
+
Purpose: Support Comparable mixin
|
568
|
+
*/
|
569
|
+
VALUE Pixel_spaceship(VALUE self, VALUE other)
|
570
|
+
{
|
571
|
+
Pixel *this, *that;
|
572
|
+
|
573
|
+
Data_Get_Struct(self, Pixel, this);
|
574
|
+
Data_Get_Struct(other, Pixel, that);
|
575
|
+
|
576
|
+
if (this->red != that->red)
|
577
|
+
{
|
578
|
+
return INT2NUM((this->red - that->red)/abs(this->red - that->red));
|
579
|
+
}
|
580
|
+
else if(this->green != that->green)
|
581
|
+
{
|
582
|
+
return INT2NUM((this->green - that->green)/abs(this->green - that->green));
|
583
|
+
}
|
584
|
+
else if(this->blue != that->blue)
|
585
|
+
{
|
586
|
+
return INT2NUM((this->blue - that->blue)/abs(this->blue - that->blue));
|
587
|
+
}
|
588
|
+
else if(this->opacity != that->opacity)
|
589
|
+
{
|
590
|
+
return INT2NUM((this->opacity - that->opacity)/abs(this->opacity - that->opacity));
|
591
|
+
}
|
592
|
+
|
593
|
+
// Values are equal, check class.
|
594
|
+
|
595
|
+
return rb_funcall(CLASS_OF(self), rb_intern("<=>"), 1, CLASS_OF(other));
|
596
|
+
|
597
|
+
}
|
598
|
+
|
599
|
+
|
600
|
+
/*
|
601
|
+
Static: destroy_Pixel
|
602
|
+
Purpose: Free the storage associated with a Pixel object
|
603
|
+
*/
|
604
|
+
static void
|
605
|
+
destroy_Pixel(Pixel *pixel)
|
606
|
+
{
|
607
|
+
xfree(pixel);
|
608
|
+
}
|
609
|
+
|
610
|
+
|
611
|
+
#if defined(HAVE_RB_DEFINE_ALLOC_FUNC)
|
612
|
+
/*
|
613
|
+
Extern: Pixel_alloc
|
614
|
+
Purpose: Allocate a Pixel object
|
615
|
+
*/
|
616
|
+
VALUE
|
617
|
+
Pixel_alloc(VALUE class)
|
618
|
+
{
|
619
|
+
Pixel *pixel;
|
620
|
+
|
621
|
+
pixel = ALLOC(Pixel);
|
622
|
+
memset(pixel, '\0', sizeof(Pixel));
|
623
|
+
return Data_Wrap_Struct(class, NULL, destroy_Pixel, pixel);
|
624
|
+
}
|
625
|
+
|
626
|
+
#else
|
627
|
+
|
628
|
+
/*
|
629
|
+
Method: Pixel.new
|
630
|
+
Purpose: Construct a new Pixel object
|
631
|
+
*/
|
632
|
+
VALUE
|
633
|
+
Pixel_new(int argc, VALUE *argv, VALUE class)
|
634
|
+
{
|
635
|
+
Pixel *pixel;
|
636
|
+
volatile VALUE pixel_obj;
|
637
|
+
|
638
|
+
pixel = ALLOC(Pixel);
|
639
|
+
memset(pixel, '\0', sizeof(Pixel));
|
640
|
+
pixel_obj = Data_Wrap_Struct(class, NULL, destroy_Pixel, pixel);
|
641
|
+
|
642
|
+
rb_obj_call_init(pixel_obj, argc, argv);
|
643
|
+
return pixel_obj;
|
644
|
+
}
|
645
|
+
#endif
|
646
|
+
|
647
|
+
|
648
|
+
/*
|
649
|
+
Method: Pixel#initialize(red=0,green=0,blue=0,opacity=0)
|
650
|
+
Notes: For backward compatibility, arguments may be nil.
|
651
|
+
*/
|
652
|
+
VALUE
|
653
|
+
Pixel_initialize(int argc, VALUE *argv, VALUE self)
|
654
|
+
{
|
655
|
+
Pixel *pixel;
|
656
|
+
|
657
|
+
Data_Get_Struct(self, Pixel, pixel);
|
658
|
+
|
659
|
+
switch(argc)
|
660
|
+
{
|
661
|
+
case 4:
|
662
|
+
if (argv[3] != Qnil)
|
663
|
+
{
|
664
|
+
pixel->opacity = (Quantum) NUM2UINT(argv[3]);
|
665
|
+
}
|
666
|
+
case 3:
|
667
|
+
if (argv[2] != Qnil)
|
668
|
+
{
|
669
|
+
pixel->blue = (Quantum) NUM2UINT(argv[2]);
|
670
|
+
}
|
671
|
+
case 2:
|
672
|
+
if (argv[1] != Qnil)
|
673
|
+
{
|
674
|
+
pixel->green = (Quantum) NUM2UINT(argv[1]);
|
675
|
+
}
|
676
|
+
case 1:
|
677
|
+
if (argv[0] != Qnil)
|
678
|
+
{
|
679
|
+
pixel->red = (Quantum) NUM2UINT(argv[0]);
|
680
|
+
}
|
681
|
+
case 0:
|
682
|
+
break;
|
683
|
+
default:
|
684
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 4)", argc);
|
685
|
+
}
|
686
|
+
|
687
|
+
return self;
|
688
|
+
}
|
689
|
+
|
690
|
+
|
691
|
+
/*
|
692
|
+
Method: Pixel#===
|
693
|
+
Purpose: "Case equal" operator for Pixel
|
694
|
+
*/
|
695
|
+
|
696
|
+
VALUE Pixel_case_eq(VALUE self, VALUE other)
|
697
|
+
{
|
698
|
+
Pixel *this, *that;
|
699
|
+
|
700
|
+
if (CLASS_OF(self) == CLASS_OF(other))
|
701
|
+
{
|
702
|
+
Data_Get_Struct(self, Pixel, this);
|
703
|
+
Data_Get_Struct(other, Pixel, that);
|
704
|
+
return (this->red == that->red
|
705
|
+
&& this->blue == that->blue
|
706
|
+
&& this->green == that->green
|
707
|
+
&& this->opacity == that->opacity) ? Qtrue : Qfalse;
|
708
|
+
}
|
709
|
+
|
710
|
+
return Qfalse;
|
711
|
+
}
|
712
|
+
|
713
|
+
|
714
|
+
VALUE
|
715
|
+
Pixel_dup(VALUE self)
|
716
|
+
{
|
717
|
+
Pixel *pixel;
|
718
|
+
volatile VALUE dup;
|
719
|
+
|
720
|
+
pixel = ALLOC(Pixel);
|
721
|
+
memset(pixel, '\0', sizeof(Pixel));
|
722
|
+
dup = Data_Wrap_Struct(CLASS_OF(self), NULL, destroy_Pixel, pixel);
|
723
|
+
if (rb_obj_tainted(self))
|
724
|
+
{
|
725
|
+
rb_obj_taint(dup);
|
726
|
+
}
|
727
|
+
return rb_funcall(dup, ID_initialize_copy, 1, self);
|
728
|
+
}
|
729
|
+
|
730
|
+
|
731
|
+
/*
|
732
|
+
Method: Pixel#clone
|
733
|
+
Notes: see dup, init_copy
|
734
|
+
*/
|
735
|
+
VALUE
|
736
|
+
Pixel_clone(VALUE self)
|
737
|
+
{
|
738
|
+
volatile VALUE clone;
|
739
|
+
|
740
|
+
clone = Pixel_dup(self);
|
741
|
+
if (OBJ_FROZEN(self))
|
742
|
+
{
|
743
|
+
rb_obj_freeze(clone);
|
744
|
+
}
|
745
|
+
|
746
|
+
return clone;
|
747
|
+
}
|
748
|
+
|
749
|
+
|
750
|
+
/*
|
751
|
+
Method: Pixel#initialize_copy
|
752
|
+
Purpose: initialize clone, dup methods
|
753
|
+
*/
|
754
|
+
VALUE Pixel_init_copy(VALUE self, VALUE orig)
|
755
|
+
{
|
756
|
+
Pixel *copy, *original;
|
757
|
+
|
758
|
+
Data_Get_Struct(orig, Pixel, original);
|
759
|
+
Data_Get_Struct(self, Pixel, copy);
|
760
|
+
|
761
|
+
*copy = *original;
|
762
|
+
|
763
|
+
return self;
|
764
|
+
}
|
765
|
+
|
766
|
+
|
767
|
+
|
768
|
+
/*
|
769
|
+
Method: Magick::Rectangle#to_s
|
770
|
+
Purpose: Create a string representation of a Magick::Rectangle
|
771
|
+
*/
|
772
|
+
VALUE
|
773
|
+
RectangleInfo_to_s(VALUE self)
|
774
|
+
{
|
775
|
+
RectangleInfo rect;
|
776
|
+
char buff[100];
|
777
|
+
|
778
|
+
Rectangle_to_RectangleInfo(&rect, self);
|
779
|
+
sprintf(buff, "width=%lu, height=%lu, x=%ld, y=%ld"
|
780
|
+
, rect.width, rect.height, rect.x, rect.y);
|
781
|
+
return rb_str_new2(buff);
|
782
|
+
}
|
783
|
+
|
784
|
+
/*
|
785
|
+
Method: Magick::SegmentInfo#to_s
|
786
|
+
Purpose: Create a string representation of a Magick::Segment
|
787
|
+
*/
|
788
|
+
VALUE
|
789
|
+
SegmentInfo_to_s(VALUE self)
|
790
|
+
{
|
791
|
+
SegmentInfo segment;
|
792
|
+
char buff[100];
|
793
|
+
|
794
|
+
Segment_to_SegmentInfo(&segment, self);
|
795
|
+
sprintf(buff, "x1=%g, y1=%g, x2=%g, y2=%g"
|
796
|
+
, segment.x1, segment.y1, segment.x2, segment.y2);
|
797
|
+
return rb_str_new2(buff);
|
798
|
+
}
|
799
|
+
|
800
|
+
/*
|
801
|
+
Extern: PixelPacket_to_Color_Name
|
802
|
+
Purpose: Map the color intensity to a named color
|
803
|
+
Returns: the named color as a String
|
804
|
+
Notes: See below for the equivalent function that accepts an Info
|
805
|
+
structure instead of an Image.
|
806
|
+
*/
|
807
|
+
VALUE
|
808
|
+
PixelPacket_to_Color_Name(Image *image, PixelPacket *color)
|
809
|
+
{
|
810
|
+
char name[MaxTextExtent];
|
811
|
+
ExceptionInfo exception;
|
812
|
+
|
813
|
+
GetExceptionInfo(&exception);
|
814
|
+
|
815
|
+
(void) QueryColorname(image, color, X11Compliance, name, &exception);
|
816
|
+
HANDLE_ERROR_IMG(image)
|
817
|
+
|
818
|
+
return rb_str_new2(name);
|
819
|
+
}
|
820
|
+
|
821
|
+
/*
|
822
|
+
Extern: PixelPacket_to_Color_Name_Info
|
823
|
+
Purpose: Map the color intensity to a named color
|
824
|
+
Returns: the named color as a String
|
825
|
+
Notes: Accepts an Info structure instead of an Image (see above).
|
826
|
+
Simply create an Image from the Info, call QueryColorname,
|
827
|
+
and then destroy the Image.
|
828
|
+
If the Info structure is NULL, creates a new one.
|
829
|
+
|
830
|
+
Note that the default depth is always used, and the matte
|
831
|
+
value is set to False, which means "don't use the alpha channel".
|
832
|
+
*/
|
833
|
+
VALUE
|
834
|
+
PixelPacket_to_Color_Name_Info(Info *info, PixelPacket *color)
|
835
|
+
{
|
836
|
+
Image *image;
|
837
|
+
Info *my_info;
|
838
|
+
volatile VALUE color_name;
|
839
|
+
|
840
|
+
my_info = info ? info : CloneImageInfo(NULL);
|
841
|
+
|
842
|
+
image = AllocateImage(info);
|
843
|
+
image->matte = False;
|
844
|
+
color_name = PixelPacket_to_Color_Name(image, color);
|
845
|
+
DestroyImage(image);
|
846
|
+
if (!info)
|
847
|
+
{
|
848
|
+
DestroyImageInfo(my_info);
|
849
|
+
}
|
850
|
+
|
851
|
+
return color_name;
|
852
|
+
}
|
853
|
+
|
854
|
+
/*
|
855
|
+
Static: Color_Name_to_PixelPacket
|
856
|
+
Purpose: Convert a color name to a PixelPacket
|
857
|
+
Raises: ArgumentError
|
858
|
+
*/
|
859
|
+
static void
|
860
|
+
Color_Name_to_PixelPacket(PixelPacket *color, VALUE name_arg)
|
861
|
+
{
|
862
|
+
boolean okay;
|
863
|
+
char *name;
|
864
|
+
ExceptionInfo exception;
|
865
|
+
|
866
|
+
GetExceptionInfo(&exception);
|
867
|
+
name = STRING_PTR(name_arg);
|
868
|
+
okay = QueryColorDatabase(name, color, &exception);
|
869
|
+
DestroyExceptionInfo(&exception);
|
870
|
+
if (!okay)
|
871
|
+
{
|
872
|
+
rb_raise(rb_eArgError, "invalid color name %s", name);
|
873
|
+
}
|
874
|
+
}
|
875
|
+
|
876
|
+
/*
|
877
|
+
Extern: AffineMatrix_to_AffineMatrix
|
878
|
+
Purpose: Convert a Magick::AffineMatrix object to a AffineMatrix structure.
|
879
|
+
Notes: If not initialized, the defaults are [sx,rx,ry,sy,tx,ty] = [1,0,0,1,0,0]
|
880
|
+
*/
|
881
|
+
void
|
882
|
+
AffineMatrix_to_AffineMatrix(AffineMatrix *am, VALUE st)
|
883
|
+
{
|
884
|
+
volatile VALUE values, v;
|
885
|
+
|
886
|
+
if (CLASS_OF(st) != Class_AffineMatrix)
|
887
|
+
{
|
888
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
889
|
+
rb_class2name(CLASS_OF(st)));
|
890
|
+
}
|
891
|
+
values = rb_funcall(st, ID_values, 0);
|
892
|
+
v = rb_ary_entry(values, 0);
|
893
|
+
am->sx = v == Qnil ? 1.0 : NUM2DBL(v);
|
894
|
+
v = rb_ary_entry(values, 1);
|
895
|
+
am->rx = v == Qnil ? 0.0 : NUM2DBL(v);
|
896
|
+
v = rb_ary_entry(values, 2);
|
897
|
+
am->ry = v == Qnil ? 0.0 : NUM2DBL(v);
|
898
|
+
v = rb_ary_entry(values, 3);
|
899
|
+
am->sy = v == Qnil ? 1.0 : NUM2DBL(v);
|
900
|
+
v = rb_ary_entry(values, 4);
|
901
|
+
am->tx = v == Qnil ? 0.0 : NUM2DBL(v);
|
902
|
+
v = rb_ary_entry(values, 4);
|
903
|
+
am->ty = v == Qnil ? 0.0 : NUM2DBL(v);
|
904
|
+
}
|
905
|
+
|
906
|
+
|
907
|
+
/*
|
908
|
+
Extern: ClassType_new
|
909
|
+
Purpose: Construct a ClassType enum object for the specified value
|
910
|
+
*/
|
911
|
+
VALUE
|
912
|
+
ClassType_new(ClassType cls)
|
913
|
+
{
|
914
|
+
const char *name;
|
915
|
+
|
916
|
+
switch(cls)
|
917
|
+
{
|
918
|
+
default:
|
919
|
+
case UndefinedClass:
|
920
|
+
name = "UndefineClass";
|
921
|
+
break;
|
922
|
+
case DirectClass:
|
923
|
+
name = "DirectClass";
|
924
|
+
break;
|
925
|
+
case PseudoClass:
|
926
|
+
name = "PseudoClass";
|
927
|
+
break;
|
928
|
+
}
|
929
|
+
|
930
|
+
return rm_enum_new(Class_ClassType, ID2SYM(rb_intern(name)), INT2FIX(cls));
|
931
|
+
}
|
932
|
+
|
933
|
+
|
934
|
+
/*
|
935
|
+
Extern: ColorspaceType_new
|
936
|
+
Purpose: construct a ColorspaceType enum object for the specified value
|
937
|
+
*/
|
938
|
+
VALUE
|
939
|
+
ColorspaceType_new(ColorspaceType cs)
|
940
|
+
{
|
941
|
+
const char *name;
|
942
|
+
|
943
|
+
switch(cs)
|
944
|
+
{
|
945
|
+
default:
|
946
|
+
case UndefinedColorspace:
|
947
|
+
name = "UndefinedColorspace";
|
948
|
+
break;
|
949
|
+
case RGBColorspace:
|
950
|
+
name = "RGBColorspace";
|
951
|
+
break;
|
952
|
+
case GRAYColorspace:
|
953
|
+
name = "GRAYColorspace";
|
954
|
+
break;
|
955
|
+
case TransparentColorspace:
|
956
|
+
name = "TransparentColorspace";
|
957
|
+
break;
|
958
|
+
case OHTAColorspace:
|
959
|
+
name = "OHTAColorspace";
|
960
|
+
break;
|
961
|
+
case XYZColorspace:
|
962
|
+
name = "XYZColorspace";
|
963
|
+
break;
|
964
|
+
case YCbCrColorspace:
|
965
|
+
name = "YCbCrColorspace";
|
966
|
+
break;
|
967
|
+
case YCCColorspace:
|
968
|
+
name = "YCCColorspace";
|
969
|
+
break;
|
970
|
+
case YIQColorspace:
|
971
|
+
name = "YIQColorspace";
|
972
|
+
break;
|
973
|
+
case YPbPrColorspace:
|
974
|
+
name = "YPbPrColorspace";
|
975
|
+
break;
|
976
|
+
case YUVColorspace:
|
977
|
+
name = "YUVColorspace";
|
978
|
+
break;
|
979
|
+
case CMYKColorspace:
|
980
|
+
name = "CMYKColorspace";
|
981
|
+
break;
|
982
|
+
case sRGBColorspace:
|
983
|
+
name = "sRGBColorspace";
|
984
|
+
break;
|
985
|
+
#if defined(HAVE_HSLCOLORSPACE)
|
986
|
+
case HSLColorspace:
|
987
|
+
name = "HSLColorspace";
|
988
|
+
break;
|
989
|
+
#endif
|
990
|
+
#if defined(HAVE_HWBCOLORSPACE)
|
991
|
+
case HWBColorspace:
|
992
|
+
name = "HWBColorspace";
|
993
|
+
break;
|
994
|
+
#endif
|
995
|
+
}
|
996
|
+
|
997
|
+
return rm_enum_new(Class_ColorspaceType, ID2SYM(rb_intern(name)), INT2FIX(cs));
|
998
|
+
|
999
|
+
}
|
1000
|
+
|
1001
|
+
/*
|
1002
|
+
* Static: ComplianceType_new
|
1003
|
+
Purpose: construct a ComplianceType enum object for the specified value
|
1004
|
+
*/
|
1005
|
+
static VALUE
|
1006
|
+
ComplianceType_new(ComplianceType compliance)
|
1007
|
+
{
|
1008
|
+
const char *name;
|
1009
|
+
|
1010
|
+
// Turn off undefined bits
|
1011
|
+
compliance &= (SVGCompliance|X11Compliance|XPMCompliance);
|
1012
|
+
name = Compliance_Const_Name(&compliance);
|
1013
|
+
return rm_enum_new(Class_ComplianceType, ID2SYM(rb_intern(name)), INT2FIX(compliance));
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
/*
|
1017
|
+
* External: CompressionType_new
|
1018
|
+
Purpose: Construct a CompressionTYpe enum object for the specified value
|
1019
|
+
*/
|
1020
|
+
VALUE
|
1021
|
+
CompressionType_new(CompressionType ct)
|
1022
|
+
{
|
1023
|
+
const char *name;
|
1024
|
+
|
1025
|
+
switch (ct)
|
1026
|
+
{
|
1027
|
+
default:
|
1028
|
+
case UndefinedCompression:
|
1029
|
+
name = "UndefinedCompression";
|
1030
|
+
break;
|
1031
|
+
case NoCompression:
|
1032
|
+
name = "NoCompression";
|
1033
|
+
break;
|
1034
|
+
case BZipCompression:
|
1035
|
+
name = "BZipCompression";
|
1036
|
+
break;
|
1037
|
+
case FaxCompression:
|
1038
|
+
name = "FaxCompression";
|
1039
|
+
break;
|
1040
|
+
case Group4Compression:
|
1041
|
+
name = "Group4Compression";
|
1042
|
+
break;
|
1043
|
+
case JPEGCompression:
|
1044
|
+
name = "JPEGCompression";
|
1045
|
+
break;
|
1046
|
+
case LosslessJPEGCompression:
|
1047
|
+
name = "LosslessJPEGCompression";
|
1048
|
+
break;
|
1049
|
+
case LZWCompression:
|
1050
|
+
name = "LZWCompression";
|
1051
|
+
break;
|
1052
|
+
case RLECompression:
|
1053
|
+
name = "RLECompression";
|
1054
|
+
break;
|
1055
|
+
case ZipCompression:
|
1056
|
+
name = "ZipCompression";
|
1057
|
+
break;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
return rm_enum_new(Class_CompressionType, ID2SYM(rb_intern(name)), INT2FIX(ct));
|
1061
|
+
}
|
1062
|
+
|
1063
|
+
/*
|
1064
|
+
External: FilterTypes#new
|
1065
|
+
Purpose: Construct an FilterTypes enum object for the specified value
|
1066
|
+
*/
|
1067
|
+
VALUE
|
1068
|
+
FilterTypes_new(FilterTypes type)
|
1069
|
+
{
|
1070
|
+
const char *name;
|
1071
|
+
|
1072
|
+
switch(type)
|
1073
|
+
{
|
1074
|
+
default:
|
1075
|
+
case UndefinedFilter:
|
1076
|
+
name = "UndefinedFilter";
|
1077
|
+
break;
|
1078
|
+
case PointFilter:
|
1079
|
+
name = "PointFilter";
|
1080
|
+
break;
|
1081
|
+
case BoxFilter:
|
1082
|
+
name = "BoxFilter";
|
1083
|
+
break;
|
1084
|
+
case TriangleFilter:
|
1085
|
+
name = "TriangleFilter";
|
1086
|
+
break;
|
1087
|
+
case HermiteFilter:
|
1088
|
+
name = "HermiteFilter";
|
1089
|
+
break;
|
1090
|
+
case HanningFilter:
|
1091
|
+
name = "HanningFilter";
|
1092
|
+
break;
|
1093
|
+
case HammingFilter:
|
1094
|
+
name = "HammingFilter";
|
1095
|
+
break;
|
1096
|
+
case BlackmanFilter:
|
1097
|
+
name = "BlackmanFilter";
|
1098
|
+
break;
|
1099
|
+
case GaussianFilter:
|
1100
|
+
name = "GaussianFilter";
|
1101
|
+
break;
|
1102
|
+
case QuadraticFilter:
|
1103
|
+
name = "QuadraticFilter";
|
1104
|
+
break;
|
1105
|
+
case CubicFilter:
|
1106
|
+
name = "CubicFilter";
|
1107
|
+
break;
|
1108
|
+
case CatromFilter:
|
1109
|
+
name = "CatromFilter";
|
1110
|
+
break;
|
1111
|
+
case MitchellFilter:
|
1112
|
+
name = "MitchellFilter";
|
1113
|
+
break;
|
1114
|
+
case LanczosFilter:
|
1115
|
+
name = "LanczosFilter";
|
1116
|
+
break;
|
1117
|
+
case BesselFilter:
|
1118
|
+
name = "BesselFilter";
|
1119
|
+
break;
|
1120
|
+
case SincFilter:
|
1121
|
+
name = "SincFilter";
|
1122
|
+
break;
|
1123
|
+
|
1124
|
+
}
|
1125
|
+
return rm_enum_new(Class_FilterTypes, ID2SYM(rb_intern(name)), INT2FIX(type));
|
1126
|
+
}
|
1127
|
+
|
1128
|
+
|
1129
|
+
|
1130
|
+
/*
|
1131
|
+
External: EndianType#new
|
1132
|
+
Purpose: Construct an EndianType enum object
|
1133
|
+
*/
|
1134
|
+
VALUE
|
1135
|
+
EndianType_new(EndianType type)
|
1136
|
+
{
|
1137
|
+
const char *name;
|
1138
|
+
|
1139
|
+
switch(type)
|
1140
|
+
{
|
1141
|
+
default:
|
1142
|
+
case UndefinedEndian:
|
1143
|
+
name = "UndefinedEndian";
|
1144
|
+
break;
|
1145
|
+
case LSBEndian:
|
1146
|
+
name = "LSBEndian";
|
1147
|
+
break;
|
1148
|
+
case MSBEndian:
|
1149
|
+
name = "MSBEndian";
|
1150
|
+
break;
|
1151
|
+
}
|
1152
|
+
|
1153
|
+
return rm_enum_new(Class_EndianType, ID2SYM(rb_intern(name)), INT2FIX(type));
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
|
1157
|
+
/*
|
1158
|
+
External: ImageType#new
|
1159
|
+
Purpose: Construct an ImageType enum object for the specified value
|
1160
|
+
*/
|
1161
|
+
VALUE
|
1162
|
+
ImageType_new(ImageType type)
|
1163
|
+
{
|
1164
|
+
const char *name;
|
1165
|
+
|
1166
|
+
switch(type)
|
1167
|
+
{
|
1168
|
+
default:
|
1169
|
+
case UndefinedType:
|
1170
|
+
name = "UndefinedType";
|
1171
|
+
break;
|
1172
|
+
case BilevelType:
|
1173
|
+
name = "BilevelType";
|
1174
|
+
break;
|
1175
|
+
case GrayscaleType:
|
1176
|
+
name = "GrayscaleType";
|
1177
|
+
break;
|
1178
|
+
case GrayscaleMatteType:
|
1179
|
+
name = "GrayscaleMatteType";
|
1180
|
+
break;
|
1181
|
+
case PaletteType:
|
1182
|
+
name = "PaletteType";
|
1183
|
+
break;
|
1184
|
+
case PaletteMatteType:
|
1185
|
+
name = "PaletteMatteType";
|
1186
|
+
break;
|
1187
|
+
case TrueColorType:
|
1188
|
+
name = "TrueColorType";
|
1189
|
+
break;
|
1190
|
+
case TrueColorMatteType:
|
1191
|
+
name = "TrueColorMatteType";
|
1192
|
+
break;
|
1193
|
+
case ColorSeparationType:
|
1194
|
+
name = "ColorSeparationType";
|
1195
|
+
break;
|
1196
|
+
case ColorSeparationMatteType:
|
1197
|
+
name = "ColorSeparationMatteType";
|
1198
|
+
break;
|
1199
|
+
case OptimizeType:
|
1200
|
+
name = "OptimizeType";
|
1201
|
+
break;
|
1202
|
+
}
|
1203
|
+
|
1204
|
+
return rm_enum_new(Class_ImageType, ID2SYM(rb_intern(name)), INT2FIX(type));
|
1205
|
+
}
|
1206
|
+
|
1207
|
+
/*
|
1208
|
+
External: InterlaceType_new
|
1209
|
+
Purpose: Construct an InterlaceType enum object for the specified value.
|
1210
|
+
*/
|
1211
|
+
VALUE
|
1212
|
+
InterlaceType_new(InterlaceType interlace)
|
1213
|
+
{
|
1214
|
+
const char *name;
|
1215
|
+
|
1216
|
+
switch(interlace)
|
1217
|
+
{
|
1218
|
+
default:
|
1219
|
+
case UndefinedInterlace:
|
1220
|
+
name = "UndefinedInterlace";
|
1221
|
+
break;
|
1222
|
+
case NoInterlace:
|
1223
|
+
name = "NoInterlace";
|
1224
|
+
break;
|
1225
|
+
case LineInterlace:
|
1226
|
+
name = "LineInterlace";
|
1227
|
+
break;
|
1228
|
+
case PlaneInterlace:
|
1229
|
+
name = "PlaneInterlace";
|
1230
|
+
break;
|
1231
|
+
case PartitionInterlace:
|
1232
|
+
name = "PartitionInterlace";
|
1233
|
+
break;
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
return rm_enum_new(Class_InterlaceType, ID2SYM(rb_intern(name)), INT2FIX(interlace));
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
/*
|
1240
|
+
External: RenderingIntent_new
|
1241
|
+
Purpose: Construct an RenderingIntent enum object for the specified value.
|
1242
|
+
*/
|
1243
|
+
VALUE
|
1244
|
+
RenderingIntent_new(RenderingIntent intent)
|
1245
|
+
{
|
1246
|
+
const char *name;
|
1247
|
+
|
1248
|
+
switch(intent)
|
1249
|
+
{
|
1250
|
+
default:
|
1251
|
+
case UndefinedIntent:
|
1252
|
+
name = "UndefinedIntent";
|
1253
|
+
break;
|
1254
|
+
case SaturationIntent:
|
1255
|
+
name = "SaturationIntent";
|
1256
|
+
break;
|
1257
|
+
case PerceptualIntent:
|
1258
|
+
name = "PerceptualIntent";
|
1259
|
+
break;
|
1260
|
+
case AbsoluteIntent:
|
1261
|
+
name = "AbsoluteIntent";
|
1262
|
+
break;
|
1263
|
+
case RelativeIntent:
|
1264
|
+
name = "RelativeIntent";
|
1265
|
+
break;
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
return rm_enum_new(Class_RenderingIntent, ID2SYM(rb_intern(name)), INT2FIX(intent));
|
1269
|
+
}
|
1270
|
+
|
1271
|
+
/*
|
1272
|
+
External: ResolutionType_new
|
1273
|
+
Purpose: Construct an ResolutionType enum object for the specified value.
|
1274
|
+
*/
|
1275
|
+
VALUE
|
1276
|
+
ResolutionType_new(ResolutionType type)
|
1277
|
+
{
|
1278
|
+
const char *name;
|
1279
|
+
|
1280
|
+
switch(type)
|
1281
|
+
{
|
1282
|
+
default:
|
1283
|
+
case UndefinedResolution:
|
1284
|
+
name = "UndefinedResolution";
|
1285
|
+
break;
|
1286
|
+
case PixelsPerInchResolution:
|
1287
|
+
name = "PixelsPerInchResolution";
|
1288
|
+
break;
|
1289
|
+
case PixelsPerCentimeterResolution:
|
1290
|
+
name = "PixelsPerCentimeterResolution";
|
1291
|
+
break;
|
1292
|
+
}
|
1293
|
+
return rm_enum_new(Class_ResolutionType, ID2SYM(rb_intern(name)), INT2FIX(type));
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
/*
|
1297
|
+
External: Color_from_ColorInfo
|
1298
|
+
Purpose: Convert a ColorInfo structure to a Magick::Color
|
1299
|
+
*/
|
1300
|
+
VALUE
|
1301
|
+
Color_from_ColorInfo(const ColorInfo *ci)
|
1302
|
+
{
|
1303
|
+
ComplianceType compliance_type;
|
1304
|
+
volatile VALUE name;
|
1305
|
+
volatile VALUE compliance;
|
1306
|
+
volatile VALUE color;
|
1307
|
+
|
1308
|
+
name = rb_str_new2(ci->name);
|
1309
|
+
|
1310
|
+
compliance_type = ci->compliance;
|
1311
|
+
compliance = ComplianceType_new(compliance_type);
|
1312
|
+
color = Pixel_from_PixelPacket((PixelPacket *)(&(ci->color)));
|
1313
|
+
|
1314
|
+
return rb_funcall(Class_Color, ID_new, 3
|
1315
|
+
, name, compliance, color);
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
|
1319
|
+
/*
|
1320
|
+
External: Color_to_ColorInfo
|
1321
|
+
Purpose: Convert a Magick::Color to a ColorInfo structure
|
1322
|
+
*/
|
1323
|
+
void
|
1324
|
+
Color_to_ColorInfo(ColorInfo *ci, VALUE st)
|
1325
|
+
{
|
1326
|
+
Pixel *pixel;
|
1327
|
+
volatile VALUE members, m;
|
1328
|
+
|
1329
|
+
if (CLASS_OF(st) != Class_Color)
|
1330
|
+
{
|
1331
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1332
|
+
rb_class2name(CLASS_OF(st)));
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
memset(ci, '\0', sizeof(ColorInfo));
|
1336
|
+
|
1337
|
+
members = rb_funcall(st, ID_values, 0);
|
1338
|
+
|
1339
|
+
m = rb_ary_entry(members, 0);
|
1340
|
+
if (m != Qnil)
|
1341
|
+
{
|
1342
|
+
CloneString((char **)&(ci->name), STRING_PTR(m));
|
1343
|
+
}
|
1344
|
+
m = rb_ary_entry(members, 1);
|
1345
|
+
if (m != Qnil)
|
1346
|
+
{
|
1347
|
+
VALUE_TO_ENUM(m, ci->compliance, ComplianceType);
|
1348
|
+
}
|
1349
|
+
m = rb_ary_entry(members, 2);
|
1350
|
+
if (m != Qnil)
|
1351
|
+
{
|
1352
|
+
Data_Get_Struct(m, Pixel, pixel);
|
1353
|
+
ci->color = *pixel;
|
1354
|
+
}
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
/*
|
1358
|
+
Static: destroy_ColorInfo
|
1359
|
+
Purpose: free the storage allocated by Color_to_ColorInfo, above.
|
1360
|
+
*/
|
1361
|
+
static void
|
1362
|
+
destroy_ColorInfo(ColorInfo *ci)
|
1363
|
+
{
|
1364
|
+
magick_free((void*)ci->name);
|
1365
|
+
ci->name = NULL;
|
1366
|
+
}
|
1367
|
+
|
1368
|
+
/*
|
1369
|
+
Method: Color#to_s
|
1370
|
+
Purpose: Return a string representation of a Magick::Color object
|
1371
|
+
*/
|
1372
|
+
VALUE
|
1373
|
+
Color_to_s(VALUE self)
|
1374
|
+
{
|
1375
|
+
ColorInfo ci;
|
1376
|
+
char buff[1024];
|
1377
|
+
|
1378
|
+
Color_to_ColorInfo(&ci, self);
|
1379
|
+
sprintf(buff, "name=%s, compliance=%s, "
|
1380
|
+
"color.red=%d, color.green=%d, color.blue=%d, color.opacity=%d ",
|
1381
|
+
ci.name,
|
1382
|
+
Compliance_Const_Name(&ci.compliance),
|
1383
|
+
ci.color.red, ci.color.green, ci.color.blue, ci.color.opacity);
|
1384
|
+
|
1385
|
+
destroy_ColorInfo(&ci);
|
1386
|
+
return rb_str_new2(buff);
|
1387
|
+
}
|
1388
|
+
|
1389
|
+
/*
|
1390
|
+
Extern: Pixel_from_PixelPacket
|
1391
|
+
Purpose: Create a Magick::Pixel object from a PixelPacket structure.
|
1392
|
+
Notes: bypasses normal Pixel.new, Pixel#initialize methods
|
1393
|
+
*/
|
1394
|
+
VALUE
|
1395
|
+
Pixel_from_PixelPacket(PixelPacket *pp)
|
1396
|
+
{
|
1397
|
+
Pixel *pixel;
|
1398
|
+
|
1399
|
+
pixel = ALLOC(Pixel);
|
1400
|
+
*pixel = *pp;
|
1401
|
+
return Data_Wrap_Struct(Class_Pixel, NULL, destroy_Pixel, pixel);
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
|
1405
|
+
/*
|
1406
|
+
* Static: color_arg_rescue
|
1407
|
+
* Purpose: raise ArgumentError if the color name cannot be converted
|
1408
|
+
* to a string via rb_str_to_str.
|
1409
|
+
*/
|
1410
|
+
static VALUE
|
1411
|
+
color_arg_rescue(VALUE arg)
|
1412
|
+
{
|
1413
|
+
rb_raise(rb_eTypeError, "argument must be color name or pixel (%s given)",
|
1414
|
+
rb_class2name(CLASS_OF(arg)));
|
1415
|
+
}
|
1416
|
+
|
1417
|
+
/*
|
1418
|
+
Extern: Color_to_PixelPacket
|
1419
|
+
Purpose: Convert either a String color name or
|
1420
|
+
a Magick::Pixel to a PixelPacket
|
1421
|
+
*/
|
1422
|
+
void
|
1423
|
+
Color_to_PixelPacket(PixelPacket *pp, VALUE color)
|
1424
|
+
{
|
1425
|
+
Pixel *pixel;
|
1426
|
+
|
1427
|
+
// Allow color name or Pixel
|
1428
|
+
if (CLASS_OF(color) == Class_Pixel)
|
1429
|
+
{
|
1430
|
+
Data_Get_Struct(color, Pixel, pixel);
|
1431
|
+
*pp = *pixel;
|
1432
|
+
}
|
1433
|
+
else
|
1434
|
+
{
|
1435
|
+
// require 'to_str' here instead of just 'to_s'.
|
1436
|
+
color = rb_rescue(rb_str_to_str, color, color_arg_rescue, color);
|
1437
|
+
Color_Name_to_PixelPacket(pp, color);
|
1438
|
+
}
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
/*
|
1442
|
+
Extern: PrimaryInfo_from_PrimaryInfo(pp)
|
1443
|
+
Purpose: Create a Magick::PrimaryInfo object from a PrimaryInfo structure.
|
1444
|
+
*/
|
1445
|
+
VALUE
|
1446
|
+
PrimaryInfo_from_PrimaryInfo(PrimaryInfo *p)
|
1447
|
+
{
|
1448
|
+
return rb_funcall(Class_Primary, ID_new, 3
|
1449
|
+
, INT2FIX(p->x), INT2FIX(p->y), INT2FIX(p->z));
|
1450
|
+
}
|
1451
|
+
|
1452
|
+
/*
|
1453
|
+
Extern: PrimaryInfo_to_PrimaryInfo
|
1454
|
+
Purpose: Convert a Magick::PrimaryInfo object to a PrimaryInfo structure
|
1455
|
+
*/
|
1456
|
+
void
|
1457
|
+
PrimaryInfo_to_PrimaryInfo(PrimaryInfo *pi, VALUE sp)
|
1458
|
+
{
|
1459
|
+
volatile VALUE members, m;
|
1460
|
+
|
1461
|
+
if (CLASS_OF(sp) != Class_Primary)
|
1462
|
+
{
|
1463
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1464
|
+
rb_class2name(CLASS_OF(sp)));
|
1465
|
+
}
|
1466
|
+
members = rb_funcall(sp, ID_values, 0);
|
1467
|
+
m = rb_ary_entry(members, 0);
|
1468
|
+
pi->x = m == Qnil ? 0 : FIX2INT(m);
|
1469
|
+
m = rb_ary_entry(members, 1);
|
1470
|
+
pi->y = m == Qnil ? 0 : FIX2INT(m);
|
1471
|
+
m = rb_ary_entry(members, 2);
|
1472
|
+
pi->z = m == Qnil ? 0 : FIX2INT(m);
|
1473
|
+
}
|
1474
|
+
|
1475
|
+
/*
|
1476
|
+
Extern: PointInfo_to_Point(pp)
|
1477
|
+
Purpose: Create a Magick::Point object from a PointInfo structure.
|
1478
|
+
*/
|
1479
|
+
VALUE
|
1480
|
+
PointInfo_to_Point(PointInfo *p)
|
1481
|
+
{
|
1482
|
+
return rb_funcall(Class_Point, ID_new, 2
|
1483
|
+
, INT2FIX(p->x), INT2FIX(p->y));
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
/*
|
1487
|
+
Extern: Point_to_PointInfo
|
1488
|
+
Purpose: Convert a Magick::Point object to a PointInfo structure
|
1489
|
+
*/
|
1490
|
+
void
|
1491
|
+
Point_to_PointInfo(PointInfo *pi, VALUE sp)
|
1492
|
+
{
|
1493
|
+
volatile VALUE members, m;
|
1494
|
+
|
1495
|
+
if (CLASS_OF(sp) != Class_Point)
|
1496
|
+
{
|
1497
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1498
|
+
rb_class2name(CLASS_OF(sp)));
|
1499
|
+
}
|
1500
|
+
members = rb_funcall(sp, ID_values, 0);
|
1501
|
+
m = rb_ary_entry(members, 0);
|
1502
|
+
pi->x = m == Qnil ? 0 : FIX2INT(m);
|
1503
|
+
m = rb_ary_entry(members, 1);
|
1504
|
+
pi->y = m == Qnil ? 0 : FIX2INT(m);
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
|
1508
|
+
|
1509
|
+
/*
|
1510
|
+
Extern: ChromaticityInfo_new(pp)
|
1511
|
+
Purpose: Create a Magick::ChromaticityInfo object from a
|
1512
|
+
ChromaticityInfo structure.
|
1513
|
+
*/
|
1514
|
+
VALUE
|
1515
|
+
ChromaticityInfo_new(ChromaticityInfo *ci)
|
1516
|
+
{
|
1517
|
+
volatile VALUE red_primary;
|
1518
|
+
volatile VALUE green_primary;
|
1519
|
+
volatile VALUE blue_primary;
|
1520
|
+
volatile VALUE white_point;
|
1521
|
+
|
1522
|
+
red_primary = PrimaryInfo_from_PrimaryInfo(&ci->red_primary);
|
1523
|
+
green_primary = PrimaryInfo_from_PrimaryInfo(&ci->green_primary);
|
1524
|
+
blue_primary = PrimaryInfo_from_PrimaryInfo(&ci->blue_primary);
|
1525
|
+
white_point = PrimaryInfo_from_PrimaryInfo(&ci->white_point);
|
1526
|
+
|
1527
|
+
return rb_funcall(Class_Chromaticity, ID_new, 4
|
1528
|
+
, red_primary, green_primary, blue_primary, white_point);
|
1529
|
+
}
|
1530
|
+
|
1531
|
+
/*
|
1532
|
+
Extern: ChromaticityInfo_to_ChromaticityInfo
|
1533
|
+
Purpose: Extract the elements from a Magick::ChromaticityInfo
|
1534
|
+
and store in a ChromaticityInfo structure.
|
1535
|
+
*/
|
1536
|
+
void
|
1537
|
+
ChromaticityInfo_to_ChromaticityInfo(ChromaticityInfo *ci, VALUE chrom)
|
1538
|
+
{
|
1539
|
+
volatile VALUE chrom_members;
|
1540
|
+
volatile VALUE red_primary, green_primary, blue_primary, white_point;
|
1541
|
+
volatile VALUE entry_members, x, y;
|
1542
|
+
ID values_id;
|
1543
|
+
|
1544
|
+
if (CLASS_OF(chrom) != Class_Chromaticity)
|
1545
|
+
{
|
1546
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1547
|
+
rb_class2name(CLASS_OF(chrom)));
|
1548
|
+
}
|
1549
|
+
values_id = ID_values;
|
1550
|
+
|
1551
|
+
// Get the struct members in an array
|
1552
|
+
chrom_members = rb_funcall(chrom, values_id, 0);
|
1553
|
+
red_primary = rb_ary_entry(chrom_members, 0);
|
1554
|
+
green_primary = rb_ary_entry(chrom_members, 1);
|
1555
|
+
blue_primary = rb_ary_entry(chrom_members, 2);
|
1556
|
+
white_point = rb_ary_entry(chrom_members, 3);
|
1557
|
+
|
1558
|
+
// Get the red_primary PrimaryInfo members in an array
|
1559
|
+
entry_members = rb_funcall(red_primary, values_id, 0);
|
1560
|
+
x = rb_ary_entry(entry_members, 0); // red_primary.x
|
1561
|
+
ci->red_primary.x = x == Qnil ? 0.0 : NUM2DBL(x);
|
1562
|
+
y = rb_ary_entry(entry_members, 1); // red_primary.y
|
1563
|
+
ci->red_primary.y = y == Qnil ? 0.0 : NUM2DBL(y);
|
1564
|
+
ci->red_primary.z = 0.0;
|
1565
|
+
|
1566
|
+
// Get the green_primary PrimaryInfo members in an array
|
1567
|
+
entry_members = rb_funcall(green_primary, values_id, 0);
|
1568
|
+
x = rb_ary_entry(entry_members, 0); // green_primary.x
|
1569
|
+
ci->green_primary.x = x == Qnil ? 0.0 : NUM2DBL(x);
|
1570
|
+
y = rb_ary_entry(entry_members, 1); // green_primary.y
|
1571
|
+
ci->green_primary.y = y == Qnil ? 0.0 : NUM2DBL(y);
|
1572
|
+
ci->green_primary.z = 0.0;
|
1573
|
+
|
1574
|
+
// Get the blue_primary PrimaryInfo members in an array
|
1575
|
+
entry_members = rb_funcall(blue_primary, values_id, 0);
|
1576
|
+
x = rb_ary_entry(entry_members, 0); // blue_primary.x
|
1577
|
+
ci->blue_primary.x = x == Qnil ? 0.0 : NUM2DBL(x);
|
1578
|
+
y = rb_ary_entry(entry_members, 1); // blue_primary.y
|
1579
|
+
ci->blue_primary.y = y == Qnil ? 0.0 : NUM2DBL(y);
|
1580
|
+
ci->blue_primary.z = 0.0;
|
1581
|
+
|
1582
|
+
// Get the white_point PrimaryInfo members in an array
|
1583
|
+
entry_members = rb_funcall(white_point, values_id, 0);
|
1584
|
+
x = rb_ary_entry(entry_members, 0); // white_point.x
|
1585
|
+
ci->white_point.x = x == Qnil ? 0.0 : NUM2DBL(x);
|
1586
|
+
y = rb_ary_entry(entry_members, 1); // white_point.y
|
1587
|
+
ci->white_point.y = y == Qnil ? 0.0 : NUM2DBL(y);
|
1588
|
+
ci->white_point.z = 0.0;
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
/*
|
1592
|
+
External: Rectangle_from_RectangleInfo
|
1593
|
+
Purpose: Convert a RectangleInfo structure to a Magick::Rectangle
|
1594
|
+
*/
|
1595
|
+
VALUE
|
1596
|
+
Rectangle_from_RectangleInfo(RectangleInfo *rect)
|
1597
|
+
{
|
1598
|
+
volatile VALUE width;
|
1599
|
+
volatile VALUE height;
|
1600
|
+
volatile VALUE x, y;
|
1601
|
+
|
1602
|
+
width = UINT2NUM(rect->width);
|
1603
|
+
height = UINT2NUM(rect->height);
|
1604
|
+
x = INT2NUM(rect->x);
|
1605
|
+
y = INT2NUM(rect->y);
|
1606
|
+
return rb_funcall(Class_Rectangle, ID_new, 4
|
1607
|
+
, width, height, x, y);
|
1608
|
+
}
|
1609
|
+
|
1610
|
+
/*
|
1611
|
+
External: Rectangle_to_RectangleInfo
|
1612
|
+
Purpose: Convert a Magick::Rectangle to a RectangleInfo structure.
|
1613
|
+
*/
|
1614
|
+
void
|
1615
|
+
Rectangle_to_RectangleInfo(RectangleInfo *rect, VALUE sr)
|
1616
|
+
{
|
1617
|
+
volatile VALUE members, m;
|
1618
|
+
|
1619
|
+
if (CLASS_OF(sr) != Class_Rectangle)
|
1620
|
+
{
|
1621
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1622
|
+
rb_class2name(CLASS_OF(sr)));
|
1623
|
+
}
|
1624
|
+
members = rb_funcall(sr, ID_values, 0);
|
1625
|
+
m = rb_ary_entry(members, 0);
|
1626
|
+
rect->width = m == Qnil ? 0 : NUM2ULONG(m);
|
1627
|
+
m = rb_ary_entry(members, 1);
|
1628
|
+
rect->height = m == Qnil ? 0 : NUM2ULONG(m);
|
1629
|
+
m = rb_ary_entry(members, 2);
|
1630
|
+
rect->x = m == Qnil ? 0 : NUM2LONG (m);
|
1631
|
+
m = rb_ary_entry(members, 3);
|
1632
|
+
rect->y = m == Qnil ? 0 : NUM2LONG (m);
|
1633
|
+
}
|
1634
|
+
|
1635
|
+
/*
|
1636
|
+
External: Segment_from_SegmentInfo
|
1637
|
+
Purpose: Convert a SegmentInfo structure to a Magick::Segment
|
1638
|
+
*/
|
1639
|
+
VALUE
|
1640
|
+
Segment_from_SegmentInfo(SegmentInfo *segment)
|
1641
|
+
{
|
1642
|
+
volatile VALUE x1, y1, x2, y2;
|
1643
|
+
|
1644
|
+
x1 = rb_float_new(segment->x1);
|
1645
|
+
y1 = rb_float_new(segment->y1);
|
1646
|
+
x2 = rb_float_new(segment->x2);
|
1647
|
+
y2 = rb_float_new(segment->y2);
|
1648
|
+
return rb_funcall(Class_Segment, ID_new, 4, x1, y1, x2, y2);
|
1649
|
+
}
|
1650
|
+
|
1651
|
+
/*
|
1652
|
+
External: Segment_to_SegmentInfo
|
1653
|
+
Purpose: Convert a Magick::Segment to a SegmentInfo structure.
|
1654
|
+
*/
|
1655
|
+
void
|
1656
|
+
Segment_to_SegmentInfo(SegmentInfo *segment, VALUE s)
|
1657
|
+
{
|
1658
|
+
volatile VALUE members, m;
|
1659
|
+
|
1660
|
+
if (CLASS_OF(s) != Class_Segment)
|
1661
|
+
{
|
1662
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1663
|
+
rb_class2name(CLASS_OF(s)));
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
members = rb_funcall(s, ID_values, 0);
|
1667
|
+
m = rb_ary_entry(members, 0);
|
1668
|
+
segment->x1 = m == Qnil ? 0.0 : NUM2DBL(m);
|
1669
|
+
m = rb_ary_entry(members, 1);
|
1670
|
+
segment->y1 = m == Qnil ? 0.0 : NUM2DBL(m);
|
1671
|
+
m = rb_ary_entry(members, 2);
|
1672
|
+
segment->x2 = m == Qnil ? 0.0 : NUM2DBL(m);
|
1673
|
+
m = rb_ary_entry(members, 3);
|
1674
|
+
segment->y2 = m == Qnil ? 0.0 : NUM2DBL(m);
|
1675
|
+
}
|
1676
|
+
|
1677
|
+
/*
|
1678
|
+
Static: StretchType_new
|
1679
|
+
Purpose: Construct a StretchType enum for a specified StretchType value
|
1680
|
+
*/
|
1681
|
+
static VALUE
|
1682
|
+
StretchType_new(StretchType stretch)
|
1683
|
+
{
|
1684
|
+
const char *name;
|
1685
|
+
|
1686
|
+
name = StretchType_Const_Name(stretch);
|
1687
|
+
return rm_enum_new(Class_StretchType, ID2SYM(rb_intern(name)), INT2FIX(stretch));
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
|
1691
|
+
/*
|
1692
|
+
Static: StyleType_new
|
1693
|
+
Purpose: Construct a StyleType enum for a specified StyleType value
|
1694
|
+
*/
|
1695
|
+
static VALUE
|
1696
|
+
StyleType_new(StyleType style)
|
1697
|
+
{
|
1698
|
+
const char *name;
|
1699
|
+
|
1700
|
+
name = StyleType_Const_Name(style);
|
1701
|
+
return rm_enum_new(Class_StyleType, ID2SYM(rb_intern(name)), INT2FIX(style));
|
1702
|
+
}
|
1703
|
+
|
1704
|
+
/*
|
1705
|
+
External: Font_from_TypeInfo
|
1706
|
+
Purpose: Convert a TypeInfo structure to a Magick::Font
|
1707
|
+
*/
|
1708
|
+
VALUE
|
1709
|
+
Font_from_TypeInfo(TypeInfo *ti)
|
1710
|
+
{
|
1711
|
+
volatile VALUE name, description, family;
|
1712
|
+
volatile VALUE style, stretch, weight;
|
1713
|
+
volatile VALUE encoding, foundry, format;
|
1714
|
+
|
1715
|
+
name = rb_str_new2(ti->name);
|
1716
|
+
description = rb_str_new2(ti->description);
|
1717
|
+
family = rb_str_new2(ti->family);
|
1718
|
+
style = StyleType_new(ti->style);
|
1719
|
+
stretch = StretchType_new(ti->stretch);
|
1720
|
+
weight = INT2NUM(ti->weight);
|
1721
|
+
encoding = ti->encoding ? rb_str_new2(ti->encoding) : Qnil;
|
1722
|
+
foundry = ti->foundry ? rb_str_new2(ti->foundry) : Qnil;
|
1723
|
+
format = ti->format ? rb_str_new2(ti->format) : Qnil;
|
1724
|
+
|
1725
|
+
return rb_funcall(Class_Font, ID_new, 9
|
1726
|
+
, name, description, family, style
|
1727
|
+
, stretch, weight, encoding, foundry, format);
|
1728
|
+
}
|
1729
|
+
|
1730
|
+
/*
|
1731
|
+
External: Font_to_TypeInfo
|
1732
|
+
Purpose: Convert a Magick::Font to a TypeInfo structure
|
1733
|
+
*/
|
1734
|
+
void
|
1735
|
+
Font_to_TypeInfo(TypeInfo *ti, VALUE st)
|
1736
|
+
{
|
1737
|
+
volatile VALUE members, m;
|
1738
|
+
|
1739
|
+
if (CLASS_OF(st) != Class_Font)
|
1740
|
+
{
|
1741
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1742
|
+
rb_class2name(CLASS_OF(st)));
|
1743
|
+
}
|
1744
|
+
|
1745
|
+
memset(ti, '\0', sizeof(TypeInfo));
|
1746
|
+
|
1747
|
+
members = rb_funcall(st, ID_values, 0);
|
1748
|
+
m = rb_ary_entry(members, 0);
|
1749
|
+
if (m != Qnil)
|
1750
|
+
{
|
1751
|
+
CloneString((char **)&(ti->name), STRING_PTR(m));
|
1752
|
+
}
|
1753
|
+
m = rb_ary_entry(members, 1);
|
1754
|
+
if (m != Qnil)
|
1755
|
+
{
|
1756
|
+
CloneString((char **)&(ti->description), STRING_PTR(m));
|
1757
|
+
}
|
1758
|
+
m = rb_ary_entry(members, 2);
|
1759
|
+
if (m != Qnil)
|
1760
|
+
{
|
1761
|
+
CloneString((char **)&(ti->family), STRING_PTR(m));
|
1762
|
+
}
|
1763
|
+
m = rb_ary_entry(members, 3); ti->style = m == Qnil ? 0 : FIX2INT(m);
|
1764
|
+
m = rb_ary_entry(members, 4); ti->stretch = m == Qnil ? 0 : FIX2INT(m);
|
1765
|
+
m = rb_ary_entry(members, 5); ti->weight = m == Qnil ? 0 : FIX2INT(m);
|
1766
|
+
|
1767
|
+
m = rb_ary_entry(members, 6);
|
1768
|
+
if (m != Qnil)
|
1769
|
+
CloneString((char **)&(ti->encoding), STRING_PTR(m));
|
1770
|
+
m = rb_ary_entry(members, 7);
|
1771
|
+
if (m != Qnil)
|
1772
|
+
CloneString((char **)&(ti->foundry), STRING_PTR(m));
|
1773
|
+
m = rb_ary_entry(members, 8);
|
1774
|
+
if (m != Qnil)
|
1775
|
+
CloneString((char **)&(ti->format), STRING_PTR(m));
|
1776
|
+
}
|
1777
|
+
|
1778
|
+
|
1779
|
+
/*
|
1780
|
+
Static: destroy_TypeInfo
|
1781
|
+
Purpose: free the storage allocated by Font_to_TypeInfo, above.
|
1782
|
+
*/
|
1783
|
+
static void
|
1784
|
+
destroy_TypeInfo(TypeInfo *ti)
|
1785
|
+
{
|
1786
|
+
magick_free((void*)ti->name);
|
1787
|
+
ti->name = NULL;
|
1788
|
+
magick_free((void*)ti->description);
|
1789
|
+
ti->description = NULL;
|
1790
|
+
magick_free((void*)ti->family);
|
1791
|
+
ti->family = NULL;
|
1792
|
+
magick_free((void*)ti->encoding);
|
1793
|
+
ti->encoding = NULL;
|
1794
|
+
magick_free((void*)ti->foundry);
|
1795
|
+
ti->foundry = NULL;
|
1796
|
+
magick_free((void*)ti->format);
|
1797
|
+
ti->format = NULL;
|
1798
|
+
}
|
1799
|
+
|
1800
|
+
/*
|
1801
|
+
External: Font_to_s
|
1802
|
+
Purpose: implement the Font#to_s method
|
1803
|
+
*/
|
1804
|
+
VALUE
|
1805
|
+
Font_to_s(VALUE self)
|
1806
|
+
{
|
1807
|
+
TypeInfo ti;
|
1808
|
+
char weight[20];
|
1809
|
+
char buff[1024];
|
1810
|
+
|
1811
|
+
Font_to_TypeInfo(&ti, self);
|
1812
|
+
|
1813
|
+
switch (ti.weight)
|
1814
|
+
{
|
1815
|
+
case 400:
|
1816
|
+
strcpy(weight, "NormalWeight");
|
1817
|
+
break;
|
1818
|
+
case 700:
|
1819
|
+
strcpy(weight, "BoldWeight");
|
1820
|
+
break;
|
1821
|
+
default:
|
1822
|
+
sprintf(weight, "%lu", ti.weight);
|
1823
|
+
break;
|
1824
|
+
}
|
1825
|
+
|
1826
|
+
sprintf(buff, "name=%s, description=%s, "
|
1827
|
+
"family=%s, style=%s, stretch=%s, weight=%s, "
|
1828
|
+
"encoding=%s, foundry=%s, format=%s",
|
1829
|
+
ti.name,
|
1830
|
+
ti.description,
|
1831
|
+
ti.family,
|
1832
|
+
StyleType_Const_Name(ti.style),
|
1833
|
+
StretchType_Const_Name(ti.stretch),
|
1834
|
+
weight,
|
1835
|
+
ti.encoding ? ti.encoding : "",
|
1836
|
+
ti.foundry ? ti.foundry : "",
|
1837
|
+
ti.format ? ti.format : "");
|
1838
|
+
|
1839
|
+
destroy_TypeInfo(&ti);
|
1840
|
+
return rb_str_new2(buff);
|
1841
|
+
|
1842
|
+
}
|
1843
|
+
|
1844
|
+
/*
|
1845
|
+
External: TypeMetric_from_TypeMetric
|
1846
|
+
Purpose: Convert a TypeMetric structure to a Magick::TypeMetric
|
1847
|
+
*/
|
1848
|
+
VALUE
|
1849
|
+
TypeMetric_from_TypeMetric(TypeMetric *tm)
|
1850
|
+
{
|
1851
|
+
volatile VALUE pixels_per_em;
|
1852
|
+
volatile VALUE ascent, descent;
|
1853
|
+
volatile VALUE width, height, max_advance;
|
1854
|
+
volatile VALUE bounds, underline_position, underline_thickness;
|
1855
|
+
|
1856
|
+
pixels_per_em = PointInfo_to_Point(&tm->pixels_per_em);
|
1857
|
+
ascent = rb_float_new(tm->ascent);
|
1858
|
+
descent = rb_float_new(tm->descent);
|
1859
|
+
width = rb_float_new(tm->width);
|
1860
|
+
height = rb_float_new(tm->height);
|
1861
|
+
max_advance = rb_float_new(tm->max_advance);
|
1862
|
+
bounds = Segment_from_SegmentInfo(&tm->bounds);
|
1863
|
+
underline_position = rb_float_new(tm->underline_position);
|
1864
|
+
underline_thickness = rb_float_new(tm->underline_position);
|
1865
|
+
|
1866
|
+
return rb_funcall(Class_TypeMetric, ID_new, 9
|
1867
|
+
, pixels_per_em, ascent, descent, width
|
1868
|
+
, height, max_advance, bounds
|
1869
|
+
, underline_position, underline_thickness);
|
1870
|
+
}
|
1871
|
+
|
1872
|
+
/*
|
1873
|
+
External: TypeMetric_to_TypeMetric
|
1874
|
+
Purpose: Convert a Magick::TypeMetric to a TypeMetric structure.
|
1875
|
+
*/
|
1876
|
+
void
|
1877
|
+
TypeMetric_to_TypeMetric(TypeMetric *tm, VALUE st)
|
1878
|
+
{
|
1879
|
+
volatile VALUE members, m;
|
1880
|
+
volatile VALUE pixels_per_em;
|
1881
|
+
|
1882
|
+
if (CLASS_OF(st) != Class_TypeMetric)
|
1883
|
+
{
|
1884
|
+
rb_raise(rb_eTypeError, "type mismatch: %s given",
|
1885
|
+
rb_class2name(CLASS_OF(st)));
|
1886
|
+
}
|
1887
|
+
members = rb_funcall(st, ID_values, 0);
|
1888
|
+
|
1889
|
+
pixels_per_em = rb_ary_entry(members, 0);
|
1890
|
+
Point_to_PointInfo(&tm->pixels_per_em, pixels_per_em);
|
1891
|
+
|
1892
|
+
m = rb_ary_entry(members, 1);
|
1893
|
+
tm->ascent = m == Qnil ? 0.0 : NUM2DBL(m);
|
1894
|
+
m = rb_ary_entry(members, 2);
|
1895
|
+
tm->descent = m == Qnil ? 0.0 : NUM2DBL(m);
|
1896
|
+
m = rb_ary_entry(members, 3);
|
1897
|
+
tm->width = m == Qnil ? 0.0 : NUM2DBL(m);
|
1898
|
+
m = rb_ary_entry(members, 4);
|
1899
|
+
tm->height = m == Qnil ? 0.0 : NUM2DBL(m);
|
1900
|
+
m = rb_ary_entry(members, 5);
|
1901
|
+
tm->max_advance = m == Qnil ? 0.0 : NUM2DBL(m);
|
1902
|
+
|
1903
|
+
m = rb_ary_entry(members, 6);
|
1904
|
+
Segment_to_SegmentInfo(&tm->bounds, m);
|
1905
|
+
|
1906
|
+
m = rb_ary_entry(members, 7);
|
1907
|
+
tm->underline_position = m == Qnil ? 0.0 : NUM2DBL(m);
|
1908
|
+
m = rb_ary_entry(members, 8);
|
1909
|
+
tm->underline_thickness = m == Qnil ? 0.0 : NUM2DBL(m);
|
1910
|
+
}
|
1911
|
+
|
1912
|
+
/*
|
1913
|
+
Method: Magick::TypeMetric#to_s
|
1914
|
+
Purpose: Create a string representation of a Magick::TypeMetric
|
1915
|
+
*/
|
1916
|
+
VALUE
|
1917
|
+
TypeMetric_to_s(VALUE self)
|
1918
|
+
{
|
1919
|
+
TypeMetric tm;
|
1920
|
+
char buff[200];
|
1921
|
+
|
1922
|
+
TypeMetric_to_TypeMetric(&tm, self);
|
1923
|
+
sprintf(buff, "pixels_per_em=(x=%g,y=%g) "
|
1924
|
+
"ascent=%g descent=%g width=%g height=%g max_advance=%g "
|
1925
|
+
"bounds.x1=%g bounds.y1=%g bounds.x2=%g bounds.y2=%g "
|
1926
|
+
"underline_position=%g underline_thickness=%g",
|
1927
|
+
tm.pixels_per_em.x, tm.pixels_per_em.y,
|
1928
|
+
tm.ascent, tm.descent, tm.width, tm.height, tm.max_advance,
|
1929
|
+
tm.bounds.x1, tm.bounds.y1, tm.bounds.x2, tm.bounds.y2,
|
1930
|
+
tm.underline_position, tm.underline_thickness);
|
1931
|
+
return rb_str_new2(buff);
|
1932
|
+
}
|
1933
|
+
|
1934
|
+
|
1935
|
+
/*
|
1936
|
+
* Extern: rm_define_enum_type
|
1937
|
+
* Purpose: set up a subclass of Enum
|
1938
|
+
*/
|
1939
|
+
VALUE rm_define_enum_type(char *tag)
|
1940
|
+
{
|
1941
|
+
VALUE class;
|
1942
|
+
|
1943
|
+
class = rb_define_class_under(Module_Magick, tag, Class_Enum);\
|
1944
|
+
|
1945
|
+
rb_define_singleton_method(class, "values", Enum_type_values, 0);
|
1946
|
+
rb_define_method(class, "initialize", Enum_type_initialize, 2);
|
1947
|
+
RUBY16(rb_enable_super(class, "initialize");)
|
1948
|
+
rb_define_method(class, "inspect", Enum_type_inspect, 0);
|
1949
|
+
return class;
|
1950
|
+
}
|
1951
|
+
|
1952
|
+
|
1953
|
+
#if defined(HAVE_RB_DEFINE_ALLOC_FUNC)
|
1954
|
+
/*
|
1955
|
+
Extern: rm_enum_new (1.8)
|
1956
|
+
Purpose: Construct a new Enum subclass instance
|
1957
|
+
*/
|
1958
|
+
VALUE rm_enum_new(VALUE class, VALUE sym, VALUE val)
|
1959
|
+
{
|
1960
|
+
VALUE argv[2];
|
1961
|
+
|
1962
|
+
argv[0] = sym;
|
1963
|
+
argv[1] = val;
|
1964
|
+
return rb_class_new_instance(2, argv, class);
|
1965
|
+
}
|
1966
|
+
|
1967
|
+
/*
|
1968
|
+
Extern: Enum_alloc (1.8)
|
1969
|
+
Purpose: Enum class alloc function
|
1970
|
+
*/
|
1971
|
+
VALUE Enum_alloc(VALUE class)
|
1972
|
+
{
|
1973
|
+
MagickEnum *magick_enum;
|
1974
|
+
|
1975
|
+
return Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
|
1976
|
+
}
|
1977
|
+
|
1978
|
+
|
1979
|
+
#else
|
1980
|
+
/*
|
1981
|
+
Extern: rm_enum_new (1.6)
|
1982
|
+
Purpose: Construct a new Enum subclass instance
|
1983
|
+
*/
|
1984
|
+
VALUE rm_enum_new(VALUE class, VALUE sym, VALUE val)
|
1985
|
+
{
|
1986
|
+
return Enum_new(class, sym, val);
|
1987
|
+
}
|
1988
|
+
|
1989
|
+
/*
|
1990
|
+
Method: Enum.new
|
1991
|
+
Purpose: Construct a new Enum object
|
1992
|
+
Notes: `class' can be an Enum subclass
|
1993
|
+
*/
|
1994
|
+
VALUE Enum_new(VALUE class, VALUE sym, VALUE val)
|
1995
|
+
{
|
1996
|
+
volatile VALUE new_enum;
|
1997
|
+
VALUE argv[2];
|
1998
|
+
MagickEnum *magick_enum;
|
1999
|
+
|
2000
|
+
new_enum = Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
|
2001
|
+
argv[0] = sym;
|
2002
|
+
argv[1] = val;
|
2003
|
+
|
2004
|
+
rb_obj_call_init(new_enum, 2, argv);
|
2005
|
+
return new_enum;
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
#endif
|
2009
|
+
|
2010
|
+
/*
|
2011
|
+
Method: Enum#initialize
|
2012
|
+
Purpose: Initialize a new Enum instance
|
2013
|
+
*/
|
2014
|
+
VALUE Enum_initialize(VALUE self, VALUE sym, VALUE val)
|
2015
|
+
{
|
2016
|
+
MagickEnum *magick_enum;
|
2017
|
+
|
2018
|
+
Data_Get_Struct(self, MagickEnum, magick_enum);
|
2019
|
+
magick_enum->id = rb_to_id(sym); /* convert symbol to ID */
|
2020
|
+
magick_enum->val = NUM2INT(val);
|
2021
|
+
|
2022
|
+
return self;
|
2023
|
+
}
|
2024
|
+
|
2025
|
+
|
2026
|
+
/*
|
2027
|
+
Method: Enum#to_s
|
2028
|
+
Purpose: Return the name of an enum
|
2029
|
+
*/
|
2030
|
+
VALUE Enum_to_s(VALUE self)
|
2031
|
+
{
|
2032
|
+
MagickEnum *magick_enum;
|
2033
|
+
|
2034
|
+
Data_Get_Struct(self, MagickEnum, magick_enum);
|
2035
|
+
return rb_str_new2(rb_id2name(magick_enum->id));
|
2036
|
+
}
|
2037
|
+
|
2038
|
+
|
2039
|
+
/*
|
2040
|
+
Method: Enum#to_i
|
2041
|
+
Purpose: Return the value of an enum
|
2042
|
+
*/
|
2043
|
+
VALUE Enum_to_i(VALUE self)
|
2044
|
+
{
|
2045
|
+
MagickEnum *magick_enum;
|
2046
|
+
|
2047
|
+
Data_Get_Struct(self, MagickEnum, magick_enum);
|
2048
|
+
return INT2NUM(magick_enum->val);
|
2049
|
+
}
|
2050
|
+
|
2051
|
+
|
2052
|
+
/*
|
2053
|
+
Method: Enum#<=>
|
2054
|
+
Purpose: Support Comparable module in Enum
|
2055
|
+
Returns: -1, 0, 1, or nil
|
2056
|
+
Notes: Enums must be instances of the same class to be equal.
|
2057
|
+
*/
|
2058
|
+
VALUE Enum_spaceship(VALUE self, VALUE other)
|
2059
|
+
{
|
2060
|
+
MagickEnum *this, *that;
|
2061
|
+
|
2062
|
+
Data_Get_Struct(self, MagickEnum, this);
|
2063
|
+
Data_Get_Struct(other, MagickEnum, that);
|
2064
|
+
|
2065
|
+
if (this->val > that->val)
|
2066
|
+
{
|
2067
|
+
return INT2FIX(1);
|
2068
|
+
}
|
2069
|
+
else if (this->val < that->val)
|
2070
|
+
{
|
2071
|
+
return INT2FIX(-1);
|
2072
|
+
}
|
2073
|
+
|
2074
|
+
// Values are equal, check class.
|
2075
|
+
|
2076
|
+
return rb_funcall(CLASS_OF(self), ID_spaceship, 1, CLASS_OF(other));
|
2077
|
+
}
|
2078
|
+
|
2079
|
+
|
2080
|
+
/*
|
2081
|
+
Method: Enum#===
|
2082
|
+
Purpose: "Case equal" operator for Enum
|
2083
|
+
Returns: true or false
|
2084
|
+
Notes: Yes, I know "case equal" is a misnomer.
|
2085
|
+
*/
|
2086
|
+
VALUE Enum_case_eq(VALUE self, VALUE other)
|
2087
|
+
{
|
2088
|
+
MagickEnum *this, *that;
|
2089
|
+
|
2090
|
+
if (CLASS_OF(self) == CLASS_OF(other))
|
2091
|
+
{
|
2092
|
+
Data_Get_Struct(self, MagickEnum, this);
|
2093
|
+
Data_Get_Struct(other, MagickEnum, that);
|
2094
|
+
return this->val == that->val ? Qtrue : Qfalse;
|
2095
|
+
}
|
2096
|
+
|
2097
|
+
return Qfalse;
|
2098
|
+
}
|
2099
|
+
|
2100
|
+
|
2101
|
+
/*
|
2102
|
+
* Method: xxx#initialize
|
2103
|
+
* Purpose: initialize method for all Enum subclasses
|
2104
|
+
*/
|
2105
|
+
VALUE Enum_type_initialize(VALUE self, VALUE sym, VALUE val)
|
2106
|
+
{
|
2107
|
+
volatile VALUE super_argv[2];
|
2108
|
+
volatile VALUE enumerators;
|
2109
|
+
|
2110
|
+
super_argv[0] = sym;
|
2111
|
+
super_argv[1] = val;
|
2112
|
+
rb_call_super(2, (VALUE *)super_argv);
|
2113
|
+
|
2114
|
+
if (rb_cvar_defined(CLASS_OF(self), ID_enumerators) != Qtrue)
|
2115
|
+
{
|
2116
|
+
RUBY18(rb_cvar_set(CLASS_OF(self), ID_enumerators, rb_ary_new(), 0));
|
2117
|
+
RUBY16(rb_cvar_set(CLASS_OF(self), ID_enumerators, rb_ary_new()));
|
2118
|
+
}
|
2119
|
+
|
2120
|
+
enumerators = rb_cvar_get(CLASS_OF(self), ID_enumerators);
|
2121
|
+
rb_ary_push(enumerators, self);
|
2122
|
+
|
2123
|
+
return self;
|
2124
|
+
}
|
2125
|
+
|
2126
|
+
|
2127
|
+
/*
|
2128
|
+
* Method: xxx#inspect
|
2129
|
+
* Purpose: Enum subclass #inspect
|
2130
|
+
*/
|
2131
|
+
static VALUE Enum_type_inspect(VALUE self)
|
2132
|
+
{
|
2133
|
+
char str[100];
|
2134
|
+
MagickEnum *magick_enum;
|
2135
|
+
|
2136
|
+
Data_Get_Struct(self, MagickEnum, magick_enum);
|
2137
|
+
sprintf(str, "%.32s=%d", rb_id2name(magick_enum->id), magick_enum->val);
|
2138
|
+
|
2139
|
+
return rb_str_new2(str);
|
2140
|
+
}
|
2141
|
+
|
2142
|
+
|
2143
|
+
/*
|
2144
|
+
* Method: xxx.each
|
2145
|
+
* Purpose: singleton iterator over enumerators list
|
2146
|
+
* Notes: defined for each Enum subclass
|
2147
|
+
*/
|
2148
|
+
static VALUE Enum_type_values(VALUE class)
|
2149
|
+
{
|
2150
|
+
volatile VALUE enumerators;
|
2151
|
+
int x;
|
2152
|
+
|
2153
|
+
enumerators = rb_cvar_get(class, ID_enumerators);
|
2154
|
+
|
2155
|
+
for (x = 0; x < RARRAY(enumerators)->len; x++)
|
2156
|
+
{
|
2157
|
+
rb_yield(rb_ary_entry(enumerators, x));
|
2158
|
+
}
|
2159
|
+
|
2160
|
+
return class;
|
2161
|
+
}
|
2162
|
+
|
2163
|
+
|
2164
|
+
/*
|
2165
|
+
Static: Compliance_Const_Name
|
2166
|
+
Purpose: Return the string representation of a ComplianceType value
|
2167
|
+
Notes: xMagick will OR multiple compliance types so we have to
|
2168
|
+
arbitrarily pick one name. Set the compliance argument
|
2169
|
+
to the selected value.
|
2170
|
+
*/
|
2171
|
+
static const char *
|
2172
|
+
Compliance_Const_Name(ComplianceType *c)
|
2173
|
+
{
|
2174
|
+
if ((*c & (SVGCompliance|X11Compliance|XPMCompliance))
|
2175
|
+
== (SVGCompliance|X11Compliance|XPMCompliance))
|
2176
|
+
{
|
2177
|
+
return "AllCompliance";
|
2178
|
+
}
|
2179
|
+
else if (*c & SVGCompliance)
|
2180
|
+
{
|
2181
|
+
*c = SVGCompliance;
|
2182
|
+
return "SVGCompliance";
|
2183
|
+
}
|
2184
|
+
else if (*c & X11Compliance)
|
2185
|
+
{
|
2186
|
+
*c = X11Compliance;
|
2187
|
+
return "X11Compliance";
|
2188
|
+
}
|
2189
|
+
else if (*c & XPMCompliance)
|
2190
|
+
{
|
2191
|
+
*c = XPMCompliance;
|
2192
|
+
return "XPMCompliance";
|
2193
|
+
}
|
2194
|
+
#if defined(HAVE_NOCOMPLIANCE)
|
2195
|
+
else if (*c != NoCompliance)
|
2196
|
+
{
|
2197
|
+
return "unknown";
|
2198
|
+
}
|
2199
|
+
else
|
2200
|
+
{
|
2201
|
+
*c = NoCompliance;
|
2202
|
+
return "NoCompliance";
|
2203
|
+
}
|
2204
|
+
#else
|
2205
|
+
else if (*c != UnknownCompliance)
|
2206
|
+
{
|
2207
|
+
return "unknown";
|
2208
|
+
}
|
2209
|
+
else
|
2210
|
+
{
|
2211
|
+
*c = UnknownCompliance;
|
2212
|
+
return "UnknownCompliance";
|
2213
|
+
}
|
2214
|
+
#endif
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
|
2218
|
+
#if defined(HAVE_GETIMAGESTATISTICS)
|
2219
|
+
/*
|
2220
|
+
Extern: Statistics_new(stats)
|
2221
|
+
Purpose: Create a Magick::Statistics object from an
|
2222
|
+
ImageStatistics structure.
|
2223
|
+
*/
|
2224
|
+
VALUE
|
2225
|
+
Statistics_new(ImageStatistics *stats)
|
2226
|
+
{
|
2227
|
+
volatile VALUE red, green, blue, opacity;
|
2228
|
+
volatile VALUE min, max, mean, stddev, var;
|
2229
|
+
|
2230
|
+
min = rb_float_new(stats->red.minimum);
|
2231
|
+
max = rb_float_new(stats->red.maximum);
|
2232
|
+
mean = rb_float_new(stats->red.mean);
|
2233
|
+
stddev = rb_float_new(stats->red.standard_deviation);
|
2234
|
+
var = rb_float_new(stats->red.variance);
|
2235
|
+
red = rb_funcall(Class_StatisticsChannel, ID_new, 5, max, min, mean, stddev, var);
|
2236
|
+
|
2237
|
+
min = rb_float_new(stats->green.minimum);
|
2238
|
+
max = rb_float_new(stats->green.maximum);
|
2239
|
+
mean = rb_float_new(stats->green.mean);
|
2240
|
+
stddev = rb_float_new(stats->green.standard_deviation);
|
2241
|
+
var = rb_float_new(stats->green.variance);
|
2242
|
+
green = rb_funcall(Class_StatisticsChannel, ID_new, 5, max, min, mean, stddev, var);
|
2243
|
+
|
2244
|
+
min = rb_float_new(stats->blue.minimum);
|
2245
|
+
max = rb_float_new(stats->blue.maximum);
|
2246
|
+
mean = rb_float_new(stats->blue.mean);
|
2247
|
+
stddev = rb_float_new(stats->blue.standard_deviation);
|
2248
|
+
var = rb_float_new(stats->blue.variance);
|
2249
|
+
blue = rb_funcall(Class_StatisticsChannel, ID_new, 5, max, min, mean, stddev, var);
|
2250
|
+
|
2251
|
+
min = rb_float_new(stats->opacity.minimum);
|
2252
|
+
max = rb_float_new(stats->opacity.maximum);
|
2253
|
+
mean = rb_float_new(stats->opacity.mean);
|
2254
|
+
stddev = rb_float_new(stats->opacity.standard_deviation);
|
2255
|
+
var = rb_float_new(stats->opacity.variance);
|
2256
|
+
opacity = rb_funcall(Class_StatisticsChannel, ID_new, 5, max, min, mean, stddev, var);
|
2257
|
+
|
2258
|
+
return rb_funcall(Class_Statistics, ID_new, 4, red, green, blue, opacity);
|
2259
|
+
|
2260
|
+
}
|
2261
|
+
#endif // HAVE_GETIMAGESTATISTICS
|
2262
|
+
|
2263
|
+
|
2264
|
+
/*
|
2265
|
+
Static: StretchType_Const_Name
|
2266
|
+
Purpose: Return the string representation of a StretchType value
|
2267
|
+
*/
|
2268
|
+
static const char *
|
2269
|
+
StretchType_Const_Name(StretchType stretch)
|
2270
|
+
{
|
2271
|
+
switch (stretch)
|
2272
|
+
{
|
2273
|
+
case NormalStretch:
|
2274
|
+
return "NormalStretch";
|
2275
|
+
case UltraCondensedStretch:
|
2276
|
+
return "UltraCondensedStretch";
|
2277
|
+
case ExtraCondensedStretch:
|
2278
|
+
return "ExtraCondensedStretch";
|
2279
|
+
case CondensedStretch:
|
2280
|
+
return "CondensedStretch";
|
2281
|
+
case SemiCondensedStretch:
|
2282
|
+
return "SemiCondensedStretch";
|
2283
|
+
case SemiExpandedStretch:
|
2284
|
+
return "SemiExpandedStretch";
|
2285
|
+
case ExpandedStretch:
|
2286
|
+
return "ExpandedStretch";
|
2287
|
+
case ExtraExpandedStretch:
|
2288
|
+
return "ExtraExpandedStretch";
|
2289
|
+
case UltraExpandedStretch:
|
2290
|
+
return "UltraExpandedStretch";
|
2291
|
+
case AnyStretch:
|
2292
|
+
return "AnyStretch";
|
2293
|
+
default:
|
2294
|
+
return "unknown";
|
2295
|
+
}
|
2296
|
+
}
|
2297
|
+
|
2298
|
+
|
2299
|
+
/*
|
2300
|
+
Static: StyleType_Const_Name
|
2301
|
+
Purpose: Return the string representation of a StyleType value
|
2302
|
+
*/
|
2303
|
+
static const char *
|
2304
|
+
StyleType_Const_Name(StyleType style)
|
2305
|
+
{
|
2306
|
+
switch (style)
|
2307
|
+
{
|
2308
|
+
case NormalStyle:
|
2309
|
+
return "NormalStyle";
|
2310
|
+
case ItalicStyle:
|
2311
|
+
return "ItalicStyle";
|
2312
|
+
case ObliqueStyle:
|
2313
|
+
return "ObliqueStyle";
|
2314
|
+
case AnyStyle:
|
2315
|
+
return "AnyStyle";
|
2316
|
+
default:
|
2317
|
+
return "unknown";
|
2318
|
+
}
|
2319
|
+
}
|
2320
|
+
|
2321
|
+
|
2322
|
+
/*
|
2323
|
+
External: write_temp_image
|
2324
|
+
Purpose: Write a temporary copy of the image to the IM registry
|
2325
|
+
Returns: the "filename" of the registered image
|
2326
|
+
Notes: The `tmpnam' argument must point to an char array
|
2327
|
+
of size MaxTextExtent.
|
2328
|
+
*/
|
2329
|
+
void
|
2330
|
+
rm_write_temp_image(Image *image, char *tmpnam)
|
2331
|
+
{
|
2332
|
+
long registry_id;
|
2333
|
+
|
2334
|
+
registry_id = SetMagickRegistry(ImageRegistryType, image, sizeof(Image), &image->exception);
|
2335
|
+
if (registry_id < 0)
|
2336
|
+
{
|
2337
|
+
rb_raise(rb_eRuntimeError, "SetMagickRegistry failed.");
|
2338
|
+
}
|
2339
|
+
HANDLE_ERROR_IMG(image)
|
2340
|
+
|
2341
|
+
sprintf(tmpnam, "mpri:%ld", registry_id);
|
2342
|
+
}
|
2343
|
+
|
2344
|
+
/*
|
2345
|
+
External: delete_temp_image
|
2346
|
+
Purpose: Delete the temporary image from the registry
|
2347
|
+
Returns: void
|
2348
|
+
*/
|
2349
|
+
|
2350
|
+
void
|
2351
|
+
rm_delete_temp_image(char *tmpnam)
|
2352
|
+
{
|
2353
|
+
long registry_id = -1;
|
2354
|
+
|
2355
|
+
sscanf(tmpnam, "mpri:%ld", ®istry_id);
|
2356
|
+
if (registry_id >= 0)
|
2357
|
+
{
|
2358
|
+
(void) DeleteMagickRegistry(registry_id);
|
2359
|
+
}
|
2360
|
+
}
|
2361
|
+
|
2362
|
+
/*
|
2363
|
+
External: rm_not_implemented
|
2364
|
+
Purpose: raise NotImplementedError
|
2365
|
+
Notes: Called when a xMagick API is not available.
|
2366
|
+
Replaces Ruby's rb_notimplement function.
|
2367
|
+
Notes: The MagickPackageName macro is not available
|
2368
|
+
until 5.5.7. Use MAGICKNAME instead.
|
2369
|
+
*/
|
2370
|
+
void
|
2371
|
+
rm_not_implemented(void)
|
2372
|
+
{
|
2373
|
+
|
2374
|
+
rb_raise(rb_eNotImpError, "the `%s' method is not supported by "
|
2375
|
+
Q(MAGICKNAME) " " MagickLibVersionText
|
2376
|
+
, rb_id2name(rb_frame_last_func()));
|
2377
|
+
}
|
2378
|
+
|
2379
|
+
/*
|
2380
|
+
Static: raise_error(msg, loc)
|
2381
|
+
Purpose: create a new ImageMagickError object and raise an exception
|
2382
|
+
Notes: does not return
|
2383
|
+
This funky technique allows me to safely add additional
|
2384
|
+
information to the ImageMagickError object in both 1.6.8 and
|
2385
|
+
1.8.0. See www.ruby_talk.org/36408.
|
2386
|
+
*/
|
2387
|
+
static void
|
2388
|
+
raise_error(const char *msg, const char *loc)
|
2389
|
+
{
|
2390
|
+
volatile VALUE exc, mesg, extra;
|
2391
|
+
|
2392
|
+
mesg = rb_str_new2(msg);
|
2393
|
+
extra = loc ? rb_str_new2(loc) : Qnil;
|
2394
|
+
|
2395
|
+
exc = rb_funcall(Class_ImageMagickError, ID_new, 2, mesg, extra);
|
2396
|
+
rb_funcall(rb_cObject, rb_intern("raise"), 1, exc);
|
2397
|
+
}
|
2398
|
+
|
2399
|
+
|
2400
|
+
/*
|
2401
|
+
Method: ImageMagickError#initialize(msg, loc)
|
2402
|
+
Purpose: initialize a new ImageMagickError object - store
|
2403
|
+
the "loc" string in the @magick_location instance variable
|
2404
|
+
*/
|
2405
|
+
VALUE
|
2406
|
+
ImageMagickError_initialize(int argc, VALUE *argv, VALUE self)
|
2407
|
+
{
|
2408
|
+
volatile VALUE super_argv[1] = {(VALUE)0};
|
2409
|
+
int super_argc = 0;
|
2410
|
+
volatile VALUE extra = Qnil;
|
2411
|
+
|
2412
|
+
switch(argc)
|
2413
|
+
{
|
2414
|
+
case 2:
|
2415
|
+
extra = argv[1];
|
2416
|
+
case 1:
|
2417
|
+
super_argv[0] = argv[0];
|
2418
|
+
super_argc = 1;
|
2419
|
+
case 0:
|
2420
|
+
break;
|
2421
|
+
default:
|
2422
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 2)", argc);
|
2423
|
+
}
|
2424
|
+
|
2425
|
+
rb_call_super(super_argc, (VALUE *)super_argv);
|
2426
|
+
rb_iv_set(self, "@"MAGICK_LOC, extra);
|
2427
|
+
|
2428
|
+
|
2429
|
+
return self;
|
2430
|
+
}
|
2431
|
+
|
2432
|
+
/*
|
2433
|
+
* Extern: get_geometry
|
2434
|
+
* Purpose: Get the values from a Geometry object and return
|
2435
|
+
* them in C variables.
|
2436
|
+
*/
|
2437
|
+
void
|
2438
|
+
rm_get_geometry(
|
2439
|
+
VALUE geom,
|
2440
|
+
long *x,
|
2441
|
+
long *y,
|
2442
|
+
unsigned long *width,
|
2443
|
+
unsigned long *height,
|
2444
|
+
int *flag)
|
2445
|
+
{
|
2446
|
+
VALUE v;
|
2447
|
+
|
2448
|
+
v = rb_funcall(geom, ID_x, 0);
|
2449
|
+
*x = NUM2LONG(v);
|
2450
|
+
v = rb_funcall(geom, ID_y, 0);
|
2451
|
+
*y = NUM2LONG(v);
|
2452
|
+
v = rb_funcall(geom, ID_width, 0);
|
2453
|
+
*width = NUM2ULONG(v);
|
2454
|
+
v = rb_funcall(geom, ID_height, 0);
|
2455
|
+
*height = NUM2ULONG(v);
|
2456
|
+
|
2457
|
+
// Getting the flag field is a bit more difficult since it's
|
2458
|
+
// supposed to be an instance of the GeometryValue Enum class. We
|
2459
|
+
// may not know the VALUE for the GeometryValue class, and we
|
2460
|
+
// need to check that the flag field is an instance of that class.
|
2461
|
+
if (flag)
|
2462
|
+
{
|
2463
|
+
MagickEnum *magick_enum;
|
2464
|
+
|
2465
|
+
v = rb_funcall(geom, ID_flag, 0);
|
2466
|
+
if (!Class_GeometryValue)
|
2467
|
+
{
|
2468
|
+
Class_GeometryValue = rb_const_get(Module_Magick, ID_GeometryValue);
|
2469
|
+
}
|
2470
|
+
if (CLASS_OF(v) != Class_GeometryValue)
|
2471
|
+
{
|
2472
|
+
rb_raise(rb_eTypeError, "wrong enumeration type - expected %s, got %s"
|
2473
|
+
, rb_class2name(Class_GeometryValue),rb_class2name(CLASS_OF(v)));
|
2474
|
+
}
|
2475
|
+
Data_Get_Struct(v, MagickEnum, magick_enum);
|
2476
|
+
*flag = magick_enum->val;
|
2477
|
+
}
|
2478
|
+
|
2479
|
+
}
|
2480
|
+
|
2481
|
+
|
2482
|
+
/*
|
2483
|
+
Static: magick_error_handler
|
2484
|
+
Purpose: Build error or warning message string. If the error
|
2485
|
+
is severe, raise the ImageMagickError exception,
|
2486
|
+
otherwise print an optional warning.
|
2487
|
+
*/
|
2488
|
+
static void
|
2489
|
+
magick_error_handler(
|
2490
|
+
ExceptionType severity,
|
2491
|
+
const char *reason,
|
2492
|
+
const char *description
|
2493
|
+
#if defined(HAVE_EXCEPTIONINFO_MODULE)
|
2494
|
+
,
|
2495
|
+
const char *module,
|
2496
|
+
const char *function,
|
2497
|
+
unsigned long line
|
2498
|
+
#endif
|
2499
|
+
)
|
2500
|
+
{
|
2501
|
+
char msg[1024];
|
2502
|
+
|
2503
|
+
if (severity > WarningException)
|
2504
|
+
{
|
2505
|
+
#if defined(HAVE_SNPRINTF)
|
2506
|
+
snprintf(msg, sizeof(msg)-1,
|
2507
|
+
#else
|
2508
|
+
sprintf(msg,
|
2509
|
+
#endif
|
2510
|
+
"%s%s%s",
|
2511
|
+
GET_MSG(severity, reason),
|
2512
|
+
description ? ": " : "",
|
2513
|
+
description ? GET_MSG(severity, description) : "");
|
2514
|
+
|
2515
|
+
#if defined(HAVE_EXCEPTIONINFO_MODULE)
|
2516
|
+
{
|
2517
|
+
char extra[100];
|
2518
|
+
|
2519
|
+
#if defined(HAVE_SNPRINTF)
|
2520
|
+
snprintf(extra, sizeof(extra)-1, "%s at %s:%lu", function, module, line);
|
2521
|
+
#else
|
2522
|
+
sprintf(extra, "%s at %s:%lu", function, module, line);
|
2523
|
+
#endif
|
2524
|
+
raise_error(msg, extra);
|
2525
|
+
}
|
2526
|
+
#else
|
2527
|
+
raise_error(msg, NULL);
|
2528
|
+
#endif
|
2529
|
+
}
|
2530
|
+
else if (severity != UndefinedException)
|
2531
|
+
{
|
2532
|
+
#if defined(HAVE_SNPRINTF)
|
2533
|
+
snprintf(msg, sizeof(msg)-1,
|
2534
|
+
#else
|
2535
|
+
sprintf(msg,
|
2536
|
+
#endif
|
2537
|
+
"RMagick: %s%s%s",
|
2538
|
+
GET_MSG(severity, reason),
|
2539
|
+
description ? ": " : "",
|
2540
|
+
description ? GET_MSG(severity, description) : "");
|
2541
|
+
rb_warning(msg);
|
2542
|
+
}
|
2543
|
+
}
|
2544
|
+
|
2545
|
+
|
2546
|
+
/*
|
2547
|
+
Extern: handle_error
|
2548
|
+
Purpose: Called from RMagick routines to issue warning messages
|
2549
|
+
and raise the ImageMagickError exception.
|
2550
|
+
Notes: In order to free up memory before calling raise, this
|
2551
|
+
routine copies the ExceptionInfo data to local storage
|
2552
|
+
and then calls DestroyExceptionInfo before raising
|
2553
|
+
the error.
|
2554
|
+
|
2555
|
+
If the exception is an error, DOES NOT RETURN!
|
2556
|
+
*/
|
2557
|
+
void
|
2558
|
+
rm_handle_error(ExceptionInfo *ex)
|
2559
|
+
{
|
2560
|
+
#define RM_MAX_ERROR_CLAUSE 250
|
2561
|
+
ExceptionType sev = ex->severity;
|
2562
|
+
char reason[RM_MAX_ERROR_CLAUSE+1];
|
2563
|
+
char desc[RM_MAX_ERROR_CLAUSE+1];
|
2564
|
+
|
2565
|
+
#if defined(HAVE_EXCEPTIONINFO_MODULE)
|
2566
|
+
char module[RM_MAX_ERROR_CLAUSE+1], function[RM_MAX_ERROR_CLAUSE+1];
|
2567
|
+
unsigned long line;
|
2568
|
+
#endif
|
2569
|
+
|
2570
|
+
reason[0] = '\0';
|
2571
|
+
desc[0] = '\0';
|
2572
|
+
|
2573
|
+
if (sev == UndefinedException)
|
2574
|
+
{
|
2575
|
+
return;
|
2576
|
+
}
|
2577
|
+
if (ex->reason)
|
2578
|
+
{
|
2579
|
+
strncpy(reason, ex->reason, RM_MAX_ERROR_CLAUSE);
|
2580
|
+
reason[250] = '\0';
|
2581
|
+
}
|
2582
|
+
if (ex->description)
|
2583
|
+
{
|
2584
|
+
strncpy(desc, ex->description, RM_MAX_ERROR_CLAUSE);
|
2585
|
+
desc[250] = '\0';
|
2586
|
+
}
|
2587
|
+
|
2588
|
+
#if defined(HAVE_EXCEPTIONINFO_MODULE)
|
2589
|
+
module[0] = '\0';
|
2590
|
+
function[0] = '\0';
|
2591
|
+
|
2592
|
+
if (ex->module)
|
2593
|
+
{
|
2594
|
+
strncpy(module, ex->module, RM_MAX_ERROR_CLAUSE);
|
2595
|
+
module[250] = '\0';
|
2596
|
+
}
|
2597
|
+
if (ex->function)
|
2598
|
+
{
|
2599
|
+
strncpy(function, ex->function, RM_MAX_ERROR_CLAUSE);
|
2600
|
+
function[250] = '\0';
|
2601
|
+
}
|
2602
|
+
line = ex->line;
|
2603
|
+
#endif
|
2604
|
+
|
2605
|
+
// Let ImageMagick reclaim its storage
|
2606
|
+
DestroyExceptionInfo(ex);
|
2607
|
+
// Reset the severity. If the exception structure is in an
|
2608
|
+
// Image and this exception is rescued and the Image reused,
|
2609
|
+
// we need the Image to be pristine!
|
2610
|
+
GetExceptionInfo(ex);
|
2611
|
+
|
2612
|
+
#if !defined(HAVE_EXCEPTIONINFO_MODULE)
|
2613
|
+
magick_error_handler(sev, reason, desc);
|
2614
|
+
#else
|
2615
|
+
magick_error_handler(sev, reason, desc, module, function, line);
|
2616
|
+
#endif
|
2617
|
+
}
|
2618
|
+
|
2619
|
+
/*
|
2620
|
+
Extern: handle_all_errors
|
2621
|
+
Purpose: Examine all the images in a sequence. If any
|
2622
|
+
image has an error, raise an exception. Otherwise
|
2623
|
+
if any image has a warning, issue a warning message.
|
2624
|
+
*/
|
2625
|
+
void rm_handle_all_errors(Image *seq)
|
2626
|
+
{
|
2627
|
+
Image *badboy = NULL;
|
2628
|
+
Image *image = seq;
|
2629
|
+
|
2630
|
+
while (image)
|
2631
|
+
{
|
2632
|
+
if (image->exception.severity != UndefinedException)
|
2633
|
+
{
|
2634
|
+
// Stop at the 1st image with an error
|
2635
|
+
if (image->exception.severity > WarningException)
|
2636
|
+
{
|
2637
|
+
badboy = image;
|
2638
|
+
break;
|
2639
|
+
}
|
2640
|
+
else if (!badboy)
|
2641
|
+
{
|
2642
|
+
badboy = image;
|
2643
|
+
}
|
2644
|
+
}
|
2645
|
+
image = GET_NEXT_IMAGE(image);
|
2646
|
+
}
|
2647
|
+
|
2648
|
+
if (badboy)
|
2649
|
+
{
|
2650
|
+
if (badboy->exception.severity > WarningException)
|
2651
|
+
{
|
2652
|
+
rm_split(seq);
|
2653
|
+
}
|
2654
|
+
rm_handle_error(&badboy->exception);
|
2655
|
+
}
|
2656
|
+
}
|
2657
|
+
|
2658
|
+
|
2659
|
+
/*
|
2660
|
+
Extern: unseq
|
2661
|
+
Purpose: Remove the ImageMagick links between images in an scene
|
2662
|
+
sequence.
|
2663
|
+
Notes: The images remain grouped via the ImageList
|
2664
|
+
*/
|
2665
|
+
void
|
2666
|
+
rm_split(Image *image)
|
2667
|
+
{
|
2668
|
+
|
2669
|
+
if (!image)
|
2670
|
+
{
|
2671
|
+
rb_bug("RMagick FATAL: unseq called with NULL argument.");
|
2672
|
+
}
|
2673
|
+
while (image)
|
2674
|
+
{
|
2675
|
+
#if HAVE_REMOVEFIRSTIMAGEFROMLIST
|
2676
|
+
(void) RemoveFirstImageFromList(&image);
|
2677
|
+
#else
|
2678
|
+
Image *next;
|
2679
|
+
|
2680
|
+
next = GET_NEXT_IMAGE(image);
|
2681
|
+
image->previous = image->next = NULL;
|
2682
|
+
image = next;
|
2683
|
+
#endif
|
2684
|
+
}
|
2685
|
+
}
|