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.

Files changed (239) hide show
  1. data/ChangeLog +232 -0
  2. data/Makefile.in +28 -0
  3. data/README.html +404 -0
  4. data/README.txt +397 -0
  5. data/configure +8554 -0
  6. data/configure.ac +497 -0
  7. data/doc/comtasks.html +241 -0
  8. data/doc/constants.html +1195 -0
  9. data/doc/css/doc.css +299 -0
  10. data/doc/css/popup.css +34 -0
  11. data/doc/draw.html +3108 -0
  12. data/doc/ex/Adispatch.rb +43 -0
  13. data/doc/ex/Zconstitute.rb +9 -0
  14. data/doc/ex/adaptive_threshold.rb +19 -0
  15. data/doc/ex/add_noise.rb +18 -0
  16. data/doc/ex/affine.rb +48 -0
  17. data/doc/ex/affine_transform.rb +20 -0
  18. data/doc/ex/arc.rb +47 -0
  19. data/doc/ex/arcpath.rb +33 -0
  20. data/doc/ex/average.rb +15 -0
  21. data/doc/ex/axes.rb +64 -0
  22. data/doc/ex/bilevel_channel.rb +20 -0
  23. data/doc/ex/blur_image.rb +12 -0
  24. data/doc/ex/border.rb +10 -0
  25. data/doc/ex/bounding_box.rb +48 -0
  26. data/doc/ex/cbezier1.rb +40 -0
  27. data/doc/ex/cbezier2.rb +40 -0
  28. data/doc/ex/cbezier3.rb +40 -0
  29. data/doc/ex/cbezier4.rb +41 -0
  30. data/doc/ex/cbezier5.rb +41 -0
  31. data/doc/ex/cbezier6.rb +51 -0
  32. data/doc/ex/channel.rb +26 -0
  33. data/doc/ex/channel_threshold.rb +48 -0
  34. data/doc/ex/charcoal.rb +12 -0
  35. data/doc/ex/chop.rb +29 -0
  36. data/doc/ex/circle.rb +31 -0
  37. data/doc/ex/clip_path.rb +56 -0
  38. data/doc/ex/coalesce.rb +60 -0
  39. data/doc/ex/color_fill_to_border.rb +29 -0
  40. data/doc/ex/color_floodfill.rb +28 -0
  41. data/doc/ex/color_histogram.rb +60 -0
  42. data/doc/ex/color_reset.rb +11 -0
  43. data/doc/ex/colorize.rb +16 -0
  44. data/doc/ex/colors.rb +65 -0
  45. data/doc/ex/composite.rb +135 -0
  46. data/doc/ex/contrast.rb +37 -0
  47. data/doc/ex/crop.rb +31 -0
  48. data/doc/ex/crop_with_gravity.rb +46 -0
  49. data/doc/ex/cycle_colormap.rb +21 -0
  50. data/doc/ex/demo.rb +324 -0
  51. data/doc/ex/drawcomp.rb +42 -0
  52. data/doc/ex/drop_shadow.rb +60 -0
  53. data/doc/ex/edge.rb +11 -0
  54. data/doc/ex/ellipse.rb +43 -0
  55. data/doc/ex/emboss.rb +11 -0
  56. data/doc/ex/enhance.rb +28 -0
  57. data/doc/ex/equalize.rb +11 -0
  58. data/doc/ex/flatten_images.rb +38 -0
  59. data/doc/ex/flip.rb +11 -0
  60. data/doc/ex/flop.rb +11 -0
  61. data/doc/ex/fonts.rb +20 -0
  62. data/doc/ex/frame.rb +12 -0
  63. data/doc/ex/gaussian_blur.rb +11 -0
  64. data/doc/ex/get_multiline_type_metrics.rb +53 -0
  65. data/doc/ex/get_pixels.rb +48 -0
  66. data/doc/ex/get_type_metrics.rb +140 -0
  67. data/doc/ex/gradientfill.rb +27 -0
  68. data/doc/ex/grav.rb +44 -0
  69. data/doc/ex/gravity.rb +80 -0
  70. data/doc/ex/hatchfill.rb +27 -0
  71. data/doc/ex/images/Ballerina.jpg +0 -0
  72. data/doc/ex/images/Ballerina3.jpg +0 -0
  73. data/doc/ex/images/Button_0.gif +0 -0
  74. data/doc/ex/images/Button_1.gif +0 -0
  75. data/doc/ex/images/Button_2.gif +0 -0
  76. data/doc/ex/images/Button_3.gif +0 -0
  77. data/doc/ex/images/Button_4.gif +0 -0
  78. data/doc/ex/images/Button_5.gif +0 -0
  79. data/doc/ex/images/Button_6.gif +0 -0
  80. data/doc/ex/images/Button_7.gif +0 -0
  81. data/doc/ex/images/Button_8.gif +0 -0
  82. data/doc/ex/images/Button_9.gif +0 -0
  83. data/doc/ex/images/Button_A.gif +0 -0
  84. data/doc/ex/images/Button_B.gif +0 -0
  85. data/doc/ex/images/Button_C.gif +0 -0
  86. data/doc/ex/images/Button_D.gif +0 -0
  87. data/doc/ex/images/Button_E.gif +0 -0
  88. data/doc/ex/images/Button_F.gif +0 -0
  89. data/doc/ex/images/Button_G.gif +0 -0
  90. data/doc/ex/images/Button_H.gif +0 -0
  91. data/doc/ex/images/Button_I.gif +0 -0
  92. data/doc/ex/images/Button_J.gif +0 -0
  93. data/doc/ex/images/Button_K.gif +0 -0
  94. data/doc/ex/images/Button_L.gif +0 -0
  95. data/doc/ex/images/Button_M.gif +0 -0
  96. data/doc/ex/images/Button_N.gif +0 -0
  97. data/doc/ex/images/Button_O.gif +0 -0
  98. data/doc/ex/images/Button_P.gif +0 -0
  99. data/doc/ex/images/Button_Q.gif +0 -0
  100. data/doc/ex/images/Button_R.gif +0 -0
  101. data/doc/ex/images/Button_S.gif +0 -0
  102. data/doc/ex/images/Button_T.gif +0 -0
  103. data/doc/ex/images/Button_U.gif +0 -0
  104. data/doc/ex/images/Button_V.gif +0 -0
  105. data/doc/ex/images/Button_W.gif +0 -0
  106. data/doc/ex/images/Button_X.gif +0 -0
  107. data/doc/ex/images/Button_Y.gif +0 -0
  108. data/doc/ex/images/Button_Z.gif +0 -0
  109. data/doc/ex/images/Cheetah.jpg +0 -0
  110. data/doc/ex/images/Coffee.wmf +0 -0
  111. data/doc/ex/images/Flower_Hat.jpg +0 -0
  112. data/doc/ex/images/Gold_Statue.jpg +0 -0
  113. data/doc/ex/images/Hot_Air_Balloons.jpg +0 -0
  114. data/doc/ex/images/Hot_Air_Balloons_H.jpg +0 -0
  115. data/doc/ex/images/No.wmf +0 -0
  116. data/doc/ex/images/Polynesia.jpg +0 -0
  117. data/doc/ex/images/Red_Rocks.jpg +0 -0
  118. data/doc/ex/images/Shorts.jpg +0 -0
  119. data/doc/ex/images/Snake.wmf +0 -0
  120. data/doc/ex/images/Violin.jpg +0 -0
  121. data/doc/ex/images/graydient230x6.gif +0 -0
  122. data/doc/ex/images/logo400x83.gif +0 -0
  123. data/doc/ex/images/model.miff +0 -0
  124. data/doc/ex/images/notimplemented.gif +0 -0
  125. data/doc/ex/images/smile.miff +0 -0
  126. data/doc/ex/images/spin.gif +0 -0
  127. data/doc/ex/implode.rb +32 -0
  128. data/doc/ex/level.rb +12 -0
  129. data/doc/ex/level_channel.rb +33 -0
  130. data/doc/ex/line.rb +40 -0
  131. data/doc/ex/map.rb +28 -0
  132. data/doc/ex/map_f.rb +15 -0
  133. data/doc/ex/matte_fill_to_border.rb +42 -0
  134. data/doc/ex/matte_floodfill.rb +35 -0
  135. data/doc/ex/matte_replace.rb +42 -0
  136. data/doc/ex/median_filter.rb +28 -0
  137. data/doc/ex/modulate.rb +11 -0
  138. data/doc/ex/mono.rb +23 -0
  139. data/doc/ex/morph.rb +26 -0
  140. data/doc/ex/mosaic.rb +35 -0
  141. data/doc/ex/motion_blur.rb +11 -0
  142. data/doc/ex/negate.rb +11 -0
  143. data/doc/ex/negate_channel.rb +19 -0
  144. data/doc/ex/normalize.rb +11 -0
  145. data/doc/ex/oil_paint.rb +11 -0
  146. data/doc/ex/opacity.rb +38 -0
  147. data/doc/ex/opaque.rb +14 -0
  148. data/doc/ex/ordered_dither.rb +11 -0
  149. data/doc/ex/path.rb +62 -0
  150. data/doc/ex/pattern1.rb +25 -0
  151. data/doc/ex/pattern2.rb +26 -0
  152. data/doc/ex/polygon.rb +24 -0
  153. data/doc/ex/polyline.rb +23 -0
  154. data/doc/ex/posterize.rb +19 -0
  155. data/doc/ex/preview.rb +16 -0
  156. data/doc/ex/qbezierpath.rb +49 -0
  157. data/doc/ex/quantize-m.rb +25 -0
  158. data/doc/ex/radial_blur.rb +19 -0
  159. data/doc/ex/raise.rb +11 -0
  160. data/doc/ex/random_channel_threshold.rb +17 -0
  161. data/doc/ex/random_threshold_channel.rb +18 -0
  162. data/doc/ex/rectangle.rb +33 -0
  163. data/doc/ex/reduce_noise.rb +28 -0
  164. data/doc/ex/roll.rb +9 -0
  165. data/doc/ex/rotate.rb +43 -0
  166. data/doc/ex/rotate_f.rb +14 -0
  167. data/doc/ex/roundrect.rb +32 -0
  168. data/doc/ex/rubyname.rb +31 -0
  169. data/doc/ex/segment.rb +11 -0
  170. data/doc/ex/shade.rb +11 -0
  171. data/doc/ex/shave.rb +15 -0
  172. data/doc/ex/shear.rb +10 -0
  173. data/doc/ex/skewx.rb +50 -0
  174. data/doc/ex/skewy.rb +45 -0
  175. data/doc/ex/smile.rb +124 -0
  176. data/doc/ex/solarize.rb +11 -0
  177. data/doc/ex/splice.rb +16 -0
  178. data/doc/ex/spread.rb +11 -0
  179. data/doc/ex/stegano.rb +50 -0
  180. data/doc/ex/stroke_dasharray.rb +41 -0
  181. data/doc/ex/stroke_linecap.rb +44 -0
  182. data/doc/ex/stroke_linejoin.rb +48 -0
  183. data/doc/ex/stroke_width.rb +47 -0
  184. data/doc/ex/swirl.rb +17 -0
  185. data/doc/ex/text.rb +32 -0
  186. data/doc/ex/text_align.rb +36 -0
  187. data/doc/ex/text_antialias.rb +33 -0
  188. data/doc/ex/text_undercolor.rb +26 -0
  189. data/doc/ex/texture_fill_to_border.rb +34 -0
  190. data/doc/ex/texture_floodfill.rb +31 -0
  191. data/doc/ex/texturefill.rb +25 -0
  192. data/doc/ex/threshold.rb +13 -0
  193. data/doc/ex/to_blob.rb +14 -0
  194. data/doc/ex/translate.rb +37 -0
  195. data/doc/ex/transparent.rb +38 -0
  196. data/doc/ex/trim.rb +25 -0
  197. data/doc/ex/unsharp_mask.rb +28 -0
  198. data/doc/ex/viewex.rb +36 -0
  199. data/doc/ex/wave.rb +9 -0
  200. data/doc/ilist.html +1592 -0
  201. data/doc/image1.html +3009 -0
  202. data/doc/image2.html +2169 -0
  203. data/doc/image3.html +2815 -0
  204. data/doc/imageattrs.html +1319 -0
  205. data/doc/imusage.html +403 -0
  206. data/doc/index.html +418 -0
  207. data/doc/info.html +949 -0
  208. data/doc/magick.html +439 -0
  209. data/doc/scripts/doc.js +9 -0
  210. data/doc/struct.html +1334 -0
  211. data/doc/usage.html +1318 -0
  212. data/examples/describe.rb +44 -0
  213. data/examples/histogram.rb +289 -0
  214. data/examples/image_opacity.rb +29 -0
  215. data/examples/import_export.rb +31 -0
  216. data/examples/pattern_fill.rb +38 -0
  217. data/examples/rotating_text.rb +47 -0
  218. data/examples/thumbnail.rb +65 -0
  219. data/examples/vignette.rb +79 -0
  220. data/ext/RMagick/MANIFEST +239 -0
  221. data/ext/RMagick/extconf.rb.in +21 -0
  222. data/ext/RMagick/rmagick.h +938 -0
  223. data/ext/RMagick/rmagick_config.h.in +170 -0
  224. data/ext/RMagick/rmdraw.c +1308 -0
  225. data/ext/RMagick/rmfill.c +609 -0
  226. data/ext/RMagick/rmilist.c +685 -0
  227. data/ext/RMagick/rmimage.c +7980 -0
  228. data/ext/RMagick/rminfo.c +982 -0
  229. data/ext/RMagick/rmmain.c +1497 -0
  230. data/ext/RMagick/rmutil.c +2685 -0
  231. data/install.rb +1015 -0
  232. data/lib/RMagick.rb +1486 -0
  233. data/metaconfig.in +6 -0
  234. data/post-clean.rb +12 -0
  235. data/post-install.rb +36 -0
  236. data/post-setup.rb +245 -0
  237. data/rmagick.gemspec +22 -0
  238. data/uninstall.rb +71 -0
  239. 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, &not_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", &registry_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
+ }