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,685 @@
1
+ /* $Id: rmilist.c,v 1.20 2004/12/05 22:36:11 rmagick Exp $ */
2
+ /*============================================================================\
3
+ | Copyright (C) 2004 by Timothy P. Hunter
4
+ | Name: rmilist.c
5
+ | Author: Tim Hunter
6
+ | Purpose: ImageList class method definitions for RMagick
7
+ \============================================================================*/
8
+
9
+ #include "rmagick.h"
10
+
11
+
12
+ /*
13
+ Method: ImageList#animate(<delay>)
14
+ Purpose: repeatedly display the images in the images array to an XWindow
15
+ screen. The "delay" argument is the number of 1/100ths of a
16
+ second (0 to 65535) to delay between images.
17
+ */
18
+
19
+ VALUE
20
+ ImageList_animate(int argc, VALUE *argv, VALUE self)
21
+ {
22
+ Image *images;
23
+ Info *info;
24
+ volatile VALUE info_obj;
25
+
26
+ // Convert the images array to an images sequence.
27
+ images = rm_images_from_imagelist(self);
28
+
29
+ if (argc > 1)
30
+ {
31
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
32
+ }
33
+ if (argc == 1)
34
+ {
35
+ Image *img;
36
+ unsigned int delay;
37
+
38
+ delay = NUM2UINT(argv[0]);
39
+ for (img = images; img; img = GET_NEXT_IMAGE(img))
40
+ {
41
+ img->delay = delay;
42
+ }
43
+ }
44
+
45
+
46
+ // Create a new Info object to use with this call
47
+ info_obj = rm_info_new();
48
+ Data_Get_Struct(info_obj, Info, info);
49
+
50
+ (void) AnimateImages(info, images);
51
+ rm_handle_all_errors(images);
52
+ rm_split(images);
53
+
54
+ return self;
55
+ }
56
+
57
+ /*
58
+ Method: ImageList#append(stack)
59
+ Purpose: Append all the images by calling ImageAppend
60
+ Returns: an Frame object for the result
61
+ */
62
+ VALUE
63
+ ImageList_append(VALUE self, VALUE stack_arg)
64
+ {
65
+ Image *images, *result;
66
+ unsigned int stack;
67
+ ExceptionInfo exception;
68
+
69
+ // Convert the image array to an image sequence.
70
+ images = rm_images_from_imagelist(self);
71
+
72
+ // If stack == true, stack rectangular images top-to-bottom,
73
+ // otherwise left-to-right.
74
+ stack = RTEST(stack_arg);
75
+
76
+ GetExceptionInfo(&exception);
77
+ result = AppendImages(images, stack, &exception);
78
+ HANDLE_ERROR
79
+ rm_split(images);
80
+
81
+ return rm_image_new(result);
82
+ }
83
+
84
+ /*
85
+ Method: ImageList#average
86
+ Purpose: Average all images together by calling AverageImages
87
+ Returns: an Frame object for the averaged image
88
+ */
89
+ VALUE
90
+ ImageList_average(VALUE self)
91
+ {
92
+ Image *images, *result;
93
+ ExceptionInfo exception;
94
+
95
+ // Convert the images array to an images sequence.
96
+ images = rm_images_from_imagelist(self);
97
+
98
+ GetExceptionInfo(&exception);
99
+ result = AverageImages(images, &exception);
100
+ rm_handle_all_errors(images);
101
+ rm_split(images);
102
+
103
+ return rm_image_new(result);
104
+ }
105
+
106
+ /*
107
+ Method: ImageList#coalesce
108
+ Purpose: call CoalesceImages
109
+ Returns: a new Image with the coalesced image sequence
110
+ stored in the images array
111
+ Notes: respects the delay, matte, and start_loop fields
112
+ in each image.
113
+ */
114
+ VALUE
115
+ ImageList_coalesce(VALUE self)
116
+ {
117
+ Image *images, *results;
118
+ ExceptionInfo exception;
119
+
120
+ // Convert the image array to an image sequence.
121
+ images = rm_images_from_imagelist(self);
122
+
123
+ GetExceptionInfo(&exception);
124
+ results = CoalesceImages(images, &exception);
125
+ HANDLE_ERROR
126
+ rm_split(images);
127
+
128
+ return rm_imagelist_from_images(results);
129
+ }
130
+
131
+
132
+ /*
133
+ Method: ImageList#deconstruct
134
+ Purpose: compares each image with the next in a sequence and returns
135
+ the maximum bounding region of any pixel differences it
136
+ discovers.
137
+ Returns: a new imagelist
138
+ */
139
+ VALUE
140
+ ImageList_deconstruct(VALUE self)
141
+ {
142
+ Image *new_images, *images;
143
+ ExceptionInfo exception;
144
+
145
+ images = rm_images_from_imagelist(self);
146
+ GetExceptionInfo(&exception);
147
+ new_images = DeconstructImages(images, &exception);
148
+ HANDLE_ERROR
149
+ rm_split(images);
150
+
151
+ return rm_imagelist_from_images(new_images);
152
+ }
153
+
154
+ /*
155
+ Method: ImageList#display
156
+ Purpose: Display all the images to an X window screen.
157
+ */
158
+ VALUE
159
+ ImageList_display(VALUE self)
160
+ {
161
+ Image *images;
162
+ Info *info;
163
+ volatile VALUE info_obj;
164
+ unsigned int ok;
165
+
166
+ // Convert the images array to an images sequence.
167
+ images = rm_images_from_imagelist(self);
168
+
169
+ // Create a new Info object to use with this call
170
+ info_obj = rm_info_new();
171
+ Data_Get_Struct(info_obj, Info, info);
172
+
173
+ ok = DisplayImages(info, images);
174
+ if (!ok)
175
+ {
176
+ rm_handle_all_errors(images);
177
+ }
178
+ rm_split(images);
179
+
180
+ return self;
181
+ }
182
+
183
+ /*
184
+ Method: ImageList#flatten_images
185
+ Purpose: merge all the images into a single image
186
+ Returns: the new image
187
+ Notes: Can't use "flatten" because that's an Array method
188
+ */
189
+ VALUE
190
+ ImageList_flatten_images(VALUE self)
191
+ {
192
+ Image *images, *new_image;
193
+ ExceptionInfo exception;
194
+
195
+ images = rm_images_from_imagelist(self);
196
+ GetExceptionInfo(&exception);
197
+ new_image = FlattenImages(images, &exception);
198
+ HANDLE_ERROR
199
+ rm_split(images);
200
+
201
+ return rm_image_new(new_image);
202
+ }
203
+
204
+
205
+ /*
206
+ Method: ImageList#map
207
+ Purpose: Call MapImages
208
+ Returns: a new ImageList with mapped images. @scene is set to self.scene
209
+ */
210
+ VALUE
211
+ ImageList_map(VALUE self, VALUE map_image, VALUE dither_arg)
212
+ {
213
+ Image *images, *clone_images = NULL;
214
+ Image *map;
215
+ unsigned int dither;
216
+ volatile VALUE image, scene, new_imagelist;
217
+ ExceptionInfo exception;
218
+
219
+ image = ImageList_cur_image(map_image);
220
+ Data_Get_Struct(image, Image, map);
221
+
222
+ if (rm_imagelist_length(self) == 0)
223
+ {
224
+ rb_raise(rb_eArgError, "no images in this image list");
225
+ }
226
+
227
+ // Convert image array to image sequence, clone image sequence.
228
+ images = rm_images_from_imagelist(self);
229
+ GetExceptionInfo(&exception);
230
+ clone_images = CloneImageList(images, &exception);
231
+ HANDLE_ERROR
232
+ rm_split(images);
233
+
234
+ // Call ImageMagick
235
+ dither = !(dither_arg == Qfalse || dither_arg == Qnil);
236
+ (void) MapImages(clone_images, map, dither);
237
+ HANDLE_ERROR_IMG(clone_images)
238
+
239
+ // Set @scene in new ImageList object to same value as in self.
240
+ new_imagelist = rm_imagelist_from_images(clone_images);
241
+ scene = rb_iv_get(self, "@scene");
242
+ (void) rm_imagelist_scene_eq(new_imagelist, scene);
243
+
244
+ return new_imagelist;
245
+ }
246
+
247
+ /*
248
+ Method: ImageList#montage <{parm block}>
249
+ Purpose: Call MontageImages
250
+ Notes: Creates Montage object, yields to block if present
251
+ in Montage object's scope.
252
+ */
253
+ VALUE
254
+ ImageList_montage(VALUE self)
255
+ {
256
+ volatile VALUE montage_obj;
257
+ Montage *montage;
258
+ Image *montage_seq, *image_list;
259
+ ExceptionInfo exception;
260
+
261
+ // Create a new instance of the Magick::Montage class
262
+ montage_obj = rm_montage_new();
263
+ if (rb_block_given_p())
264
+ {
265
+ // Run the block in the instance's context, allowing the app to modify the
266
+ // object's attributes.
267
+ rb_obj_instance_eval(0, NULL, montage_obj);
268
+ }
269
+
270
+ Data_Get_Struct(montage_obj, Montage, montage);
271
+
272
+ image_list = rm_images_from_imagelist(self);
273
+
274
+ // If app specified a non-default composition operator, use it for all images.
275
+ if (montage->compose != UndefinedCompositeOp)
276
+ {
277
+ Image *i;
278
+ for (i = image_list; i; i = GET_NEXT_IMAGE(i))
279
+ {
280
+ i->compose = montage->compose;
281
+ }
282
+ }
283
+
284
+ GetExceptionInfo(&exception);
285
+
286
+ // MontageImage can return more than one image.
287
+ montage_seq = MontageImages(image_list, montage->info, &exception);
288
+ HANDLE_ERROR
289
+ rm_split(image_list);
290
+
291
+ return rm_imagelist_from_images(montage_seq);
292
+ }
293
+
294
+ /*
295
+ Method: ImageList#morph(number_images)
296
+ Purpose: requires a minimum of two images. The first image is
297
+ transformed into the second by a number of intervening images
298
+ as specified by "number_images".
299
+ Returns: a new Image with the images array set to the morph sequence.
300
+ @scenes = 0
301
+ */
302
+ VALUE
303
+ ImageList_morph(VALUE self, VALUE nimages)
304
+ {
305
+ Image *images, *new_images;
306
+ ExceptionInfo exception;
307
+ unsigned long number_images;
308
+
309
+ if (rm_imagelist_length(self) < 1)
310
+ {
311
+ rb_raise(rb_eArgError, "no images in this image list");
312
+ }
313
+ number_images = NUM2ULONG(nimages);
314
+ if (number_images <= 0)
315
+ {
316
+ rb_raise(rb_eArgError, "number of intervening images must be > 0");
317
+ }
318
+
319
+ images = rm_images_from_imagelist(self);
320
+ GetExceptionInfo(&exception);
321
+ new_images = MorphImages(images, number_images, &exception);
322
+ HANDLE_ERROR
323
+
324
+ return rm_imagelist_from_images(new_images);
325
+ }
326
+
327
+ /*
328
+ Method: ImageList#mosaic
329
+ Purpose: merge all the images into a single image
330
+ Returns: the new image
331
+ */
332
+ VALUE
333
+ ImageList_mosaic(VALUE self)
334
+ {
335
+ Image *images, *new_image;
336
+ ExceptionInfo exception;
337
+
338
+ images = rm_images_from_imagelist(self);
339
+ GetExceptionInfo(&exception);
340
+ new_image = MosaicImages(images, &exception);
341
+ HANDLE_ERROR
342
+ rm_split(images);
343
+
344
+ return rm_image_new(new_image);
345
+ }
346
+
347
+ /*
348
+ External: rm_imagelist_new
349
+ Purpose: create a new ImageList object with no images
350
+ Notes: this simply calls ImageList.new() in RMagick.rb
351
+ */
352
+ VALUE
353
+ rm_imagelist_new()
354
+ {
355
+ return rb_funcall(Class_ImageList, ID_new, 0);
356
+ }
357
+
358
+
359
+
360
+ /*
361
+ Extern: rm_imagelist_from_images
362
+ Purpose: Construct a new imagelist object from a list of images
363
+ Notes: Sets @scene to 0.
364
+ */
365
+ VALUE
366
+ rm_imagelist_from_images(Image *images)
367
+ {
368
+ volatile VALUE new_imagelist;
369
+ #if defined(HAVE_REMOVEFIRSTIMAGEFROMLIST)
370
+ Image *image;
371
+
372
+ new_imagelist = rm_imagelist_new();
373
+
374
+ while (images)
375
+ {
376
+ image = RemoveFirstImageFromList(&images);
377
+ rm_imagelist_push(new_imagelist, rm_image_new(image));
378
+ }
379
+ #else
380
+ Image *image, *next;
381
+
382
+ new_imagelist = rm_imagelist_new();
383
+
384
+ for (image = images; image; image = next)
385
+ {
386
+ next = GET_NEXT_IMAGE(image);
387
+ image->previous = image->next = NULL;
388
+ rm_imagelist_push(new_imagelist, rm_image_new(image));
389
+ }
390
+ #endif
391
+
392
+ rb_iv_set(new_imagelist, "@scene", INT2FIX(0));
393
+ return new_imagelist;
394
+ }
395
+
396
+
397
+ /*
398
+ Extern: rm_images_from_imagelist
399
+ Purpose: Convert an array of Image *s to an ImageMagick scene
400
+ sequence (i.e. a doubly-linked list of Images)
401
+ Returns: a pointer to the head of the scene sequence list
402
+ */
403
+ Image *
404
+ rm_images_from_imagelist(VALUE imagelist)
405
+ {
406
+ long x, len;
407
+ Image *head = NULL;
408
+ #if !defined(HAVE_APPENDIMAGETOLIST)
409
+ Image *tail = NULL;
410
+ #endif
411
+
412
+ Check_Type(imagelist, T_ARRAY);
413
+ len = rm_imagelist_length(imagelist);
414
+ if (len == 0)
415
+ {
416
+ rb_raise(rb_eArgError, "no images in this image list");
417
+ }
418
+
419
+ for (x = 0; x < len; x++)
420
+ {
421
+ Image *image;
422
+
423
+ Data_Get_Struct(rb_ary_entry(imagelist, x), Image, image);
424
+ #if defined(HAVE_APPENDIMAGETOLIST)
425
+ AppendImageToList(&head, image);
426
+ #else
427
+ if (!head)
428
+ {
429
+ head = image;
430
+ }
431
+ else
432
+ {
433
+ image->previous = tail;
434
+ tail->next = image;
435
+ }
436
+ tail = image;
437
+ #endif
438
+ }
439
+
440
+ return head;
441
+ }
442
+
443
+
444
+ /*
445
+ * Extern: rm_imagelist_scene_eq(imagelist, scene)
446
+ * Purpose: @scene attribute writer
447
+ */
448
+ VALUE
449
+ rm_imagelist_scene_eq(VALUE imagelist, VALUE scene)
450
+ {
451
+ rm_check_frozen(imagelist);
452
+ rb_iv_set(imagelist, "@scene", scene);
453
+ return scene;
454
+ }
455
+
456
+ /*
457
+ External: rm_imagelist_length
458
+ Purpose: return the # of images in an imagelist
459
+ */
460
+ int
461
+ rm_imagelist_length(VALUE imagelist)
462
+ {
463
+ volatile VALUE len;
464
+
465
+ len = rb_funcall(imagelist, ID_length, 0);
466
+ return FIX2INT(len);
467
+ }
468
+
469
+ /*
470
+ External: rm_imagelist_push
471
+ Purpose: push an image onto the end of the imagelist
472
+ */
473
+ void
474
+ rm_imagelist_push(VALUE imagelist, VALUE image)
475
+ {
476
+ rm_check_frozen(imagelist);
477
+ (void) rb_funcall(imagelist, ID_push, 1, image);
478
+ }
479
+
480
+ /*
481
+ Method: ImageList#quantize(<number_colors<, colorspace<, dither<, tree_depth<, measure_error>>>>>)
482
+ defaults: 256, Magick::RGBColorspace, true, 0, false
483
+ Purpose: call QuantizeImages
484
+ Returns: a new ImageList with quantized images. 'scene' is set to the same
485
+ value as self.scene
486
+ */
487
+ VALUE
488
+ ImageList_quantize(int argc, VALUE *argv, VALUE self)
489
+ {
490
+ Image *images, *new_images;
491
+ Image *new_image;
492
+ QuantizeInfo quantize_info;
493
+ ExceptionInfo exception;
494
+ volatile VALUE new_imagelist, scene;
495
+
496
+ GetQuantizeInfo(&quantize_info);
497
+
498
+ switch (argc)
499
+ {
500
+ case 5:
501
+ quantize_info.measure_error = RTEST(argv[4]);
502
+ case 4:
503
+ quantize_info.tree_depth = NUM2INT(argv[3]);
504
+ case 3:
505
+ quantize_info.dither = RTEST(argv[2]);
506
+ case 2:
507
+ VALUE_TO_ENUM(argv[1], quantize_info.colorspace, ColorspaceType);
508
+ case 1:
509
+ quantize_info.number_colors = NUM2INT(argv[0]);
510
+ case 0:
511
+ break;
512
+ default:
513
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 5)", argc);
514
+ break;
515
+ }
516
+
517
+ if (rm_imagelist_length(self) == 0)
518
+ {
519
+ rb_raise(rb_eArgError, "no images in this image list");
520
+ }
521
+
522
+ // Convert image array to image sequence, clone image sequence.
523
+ GetExceptionInfo(&exception);
524
+ images = rm_images_from_imagelist(self);
525
+ new_images = CloneImageList(images, &exception);
526
+ HANDLE_ERROR
527
+ rm_split(images);
528
+
529
+ QuantizeImages(&quantize_info, new_images);
530
+
531
+ // Create new ImageList object, convert mapped image sequence to images,
532
+ // append to images array.
533
+ new_imagelist = rm_imagelist_new();
534
+ while ((new_image = ShiftImageList(&new_images)))
535
+ {
536
+ rm_imagelist_push(new_imagelist, rm_image_new(new_image));
537
+ }
538
+
539
+ // Set @scene in new ImageList object to same value as in self.
540
+ scene = rb_iv_get(self, "@scene");
541
+ rb_iv_set(new_imagelist, "@scene", scene);
542
+
543
+ return new_imagelist;
544
+ }
545
+
546
+ /*
547
+ Method: ImageList#to_blob
548
+ Purpose: returns the imagelist as a blob (a String)
549
+ Notes: runs an info parm block if present - the user can
550
+ specify the image format and depth
551
+ */
552
+ VALUE
553
+ ImageList_to_blob(VALUE self)
554
+ {
555
+ Image *images;
556
+ Info *info;
557
+ volatile VALUE info_obj;
558
+ void *blob = NULL;
559
+ size_t length = 0;
560
+ ExceptionInfo exception;
561
+
562
+ info_obj = rm_info_new();
563
+ Data_Get_Struct(info_obj, Info, info);
564
+
565
+ // Convert the images array to an images sequence.
566
+ images = rm_images_from_imagelist(self);
567
+
568
+ GetExceptionInfo(&exception);
569
+ (void) SetImageInfo(info, True, &exception);
570
+ HANDLE_ERROR
571
+ if (*info->magick != '\0')
572
+ {
573
+ Image *img;
574
+ for (img = images; img; img = GET_NEXT_IMAGE(img))
575
+ {
576
+ strncpy(img->magick, info->magick, sizeof(info->magick)-1);
577
+ }
578
+ }
579
+
580
+ // Unconditionally request multi-images support. The worst that
581
+ // can happen is that there's only one image or the format
582
+ // doesn't support multi-image files.
583
+ info->adjoin = True;
584
+ GetExceptionInfo(&exception);
585
+ blob = ImageToBlob(info, images, &length, &exception);
586
+ HANDLE_ERROR
587
+ rm_split(images);
588
+
589
+ return (blob && length) ? rb_str_new(blob, length) : Qnil;
590
+ }
591
+
592
+
593
+ /*
594
+ * Static: file_arg_rescue
595
+ * Purpose: called when `arg_to_str' raised an exception
596
+ */
597
+ static VALUE file_arg_rescue(VALUE arg)
598
+ {
599
+ rb_raise(rb_eTypeError, "argument must be path name or open file (%s given)",
600
+ rb_class2name(CLASS_OF(arg)));
601
+ }
602
+
603
+
604
+ /*
605
+ Method: ImageList#write(file)
606
+ Purpose: Write all the images to the specified file. If the file format
607
+ supports multi-image files, and the @images array contains more
608
+ than one image, then the images will be written as a single
609
+ multi-image file. Otherwise each image will be written to a
610
+ separate file. Returns self.
611
+ */
612
+ VALUE
613
+ ImageList_write(VALUE self, VALUE file)
614
+ {
615
+ Image *images, *img;
616
+ Info *info;
617
+ const MagickInfo *m;
618
+ volatile VALUE info_obj;
619
+ char *filename;
620
+ long filenameL;
621
+ int scene;
622
+ ExceptionInfo exception;
623
+
624
+ info_obj = rm_info_new();
625
+ Data_Get_Struct(info_obj, Info, info);
626
+
627
+
628
+ // Convert the images array to an images sequence.
629
+ images = rm_images_from_imagelist(self);
630
+
631
+ if (TYPE(file) == T_FILE)
632
+ {
633
+ OpenFile *fptr;
634
+
635
+ // Ensure file is open - raise error if not
636
+ GetOpenFile(file, fptr);
637
+ info->file = GetReadFile(fptr);
638
+ }
639
+ else
640
+ {
641
+ // Convert arg to string. Catch exceptions.
642
+ file = rb_rescue(rm_obj_to_s, file, file_arg_rescue, file);
643
+
644
+ // Copy the filename to the Info and to the Image.
645
+ filename = STRING_PTR_LEN(file, filenameL);
646
+ filenameL = min(filenameL, MaxTextExtent-1);
647
+ memcpy(info->filename, filename, (size_t)filenameL);
648
+ info->filename[filenameL] = '\0';
649
+ info->file = NULL;
650
+ }
651
+
652
+ // Copy the filename into each images. Set a scene number to be used if
653
+ // writing multiple files. (Ref: ImageMagick's utilities/convert.c
654
+ for (scene = 0, img = images; img; img = GET_NEXT_IMAGE(img))
655
+ {
656
+ img->scene = scene++;
657
+ strcpy(img->filename, info->filename);
658
+ }
659
+
660
+ GetExceptionInfo(&exception);
661
+ (void) SetImageInfo(info, True, &exception);
662
+
663
+ // Find out if the format supports multi-images files.
664
+ m = GetMagickInfo(info->magick, &exception);
665
+ HANDLE_ERROR
666
+
667
+ // Tell WriteImage if we want a multi-images file.
668
+ if (rm_imagelist_length(self) > 1 && m->adjoin)
669
+ {
670
+ info->adjoin = True;
671
+ }
672
+
673
+ for (img = images; img; img = GET_NEXT_IMAGE(img))
674
+ {
675
+ (void) WriteImage(info, img);
676
+ rm_handle_all_errors(images);
677
+ if (info->adjoin)
678
+ {
679
+ break;
680
+ }
681
+ }
682
+
683
+ rm_split(images);
684
+ return self;
685
+ }