rmagick 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rmagick might be problematic. Click here for more details.
- data/ChangeLog +232 -0
- data/Makefile.in +28 -0
- data/README.html +404 -0
- data/README.txt +397 -0
- data/configure +8554 -0
- data/configure.ac +497 -0
- data/doc/comtasks.html +241 -0
- data/doc/constants.html +1195 -0
- data/doc/css/doc.css +299 -0
- data/doc/css/popup.css +34 -0
- data/doc/draw.html +3108 -0
- data/doc/ex/Adispatch.rb +43 -0
- data/doc/ex/Zconstitute.rb +9 -0
- data/doc/ex/adaptive_threshold.rb +19 -0
- data/doc/ex/add_noise.rb +18 -0
- data/doc/ex/affine.rb +48 -0
- data/doc/ex/affine_transform.rb +20 -0
- data/doc/ex/arc.rb +47 -0
- data/doc/ex/arcpath.rb +33 -0
- data/doc/ex/average.rb +15 -0
- data/doc/ex/axes.rb +64 -0
- data/doc/ex/bilevel_channel.rb +20 -0
- data/doc/ex/blur_image.rb +12 -0
- data/doc/ex/border.rb +10 -0
- data/doc/ex/bounding_box.rb +48 -0
- data/doc/ex/cbezier1.rb +40 -0
- data/doc/ex/cbezier2.rb +40 -0
- data/doc/ex/cbezier3.rb +40 -0
- data/doc/ex/cbezier4.rb +41 -0
- data/doc/ex/cbezier5.rb +41 -0
- data/doc/ex/cbezier6.rb +51 -0
- data/doc/ex/channel.rb +26 -0
- data/doc/ex/channel_threshold.rb +48 -0
- data/doc/ex/charcoal.rb +12 -0
- data/doc/ex/chop.rb +29 -0
- data/doc/ex/circle.rb +31 -0
- data/doc/ex/clip_path.rb +56 -0
- data/doc/ex/coalesce.rb +60 -0
- data/doc/ex/color_fill_to_border.rb +29 -0
- data/doc/ex/color_floodfill.rb +28 -0
- data/doc/ex/color_histogram.rb +60 -0
- data/doc/ex/color_reset.rb +11 -0
- data/doc/ex/colorize.rb +16 -0
- data/doc/ex/colors.rb +65 -0
- data/doc/ex/composite.rb +135 -0
- data/doc/ex/contrast.rb +37 -0
- data/doc/ex/crop.rb +31 -0
- data/doc/ex/crop_with_gravity.rb +46 -0
- data/doc/ex/cycle_colormap.rb +21 -0
- data/doc/ex/demo.rb +324 -0
- data/doc/ex/drawcomp.rb +42 -0
- data/doc/ex/drop_shadow.rb +60 -0
- data/doc/ex/edge.rb +11 -0
- data/doc/ex/ellipse.rb +43 -0
- data/doc/ex/emboss.rb +11 -0
- data/doc/ex/enhance.rb +28 -0
- data/doc/ex/equalize.rb +11 -0
- data/doc/ex/flatten_images.rb +38 -0
- data/doc/ex/flip.rb +11 -0
- data/doc/ex/flop.rb +11 -0
- data/doc/ex/fonts.rb +20 -0
- data/doc/ex/frame.rb +12 -0
- data/doc/ex/gaussian_blur.rb +11 -0
- data/doc/ex/get_multiline_type_metrics.rb +53 -0
- data/doc/ex/get_pixels.rb +48 -0
- data/doc/ex/get_type_metrics.rb +140 -0
- data/doc/ex/gradientfill.rb +27 -0
- data/doc/ex/grav.rb +44 -0
- data/doc/ex/gravity.rb +80 -0
- data/doc/ex/hatchfill.rb +27 -0
- data/doc/ex/images/Ballerina.jpg +0 -0
- data/doc/ex/images/Ballerina3.jpg +0 -0
- data/doc/ex/images/Button_0.gif +0 -0
- data/doc/ex/images/Button_1.gif +0 -0
- data/doc/ex/images/Button_2.gif +0 -0
- data/doc/ex/images/Button_3.gif +0 -0
- data/doc/ex/images/Button_4.gif +0 -0
- data/doc/ex/images/Button_5.gif +0 -0
- data/doc/ex/images/Button_6.gif +0 -0
- data/doc/ex/images/Button_7.gif +0 -0
- data/doc/ex/images/Button_8.gif +0 -0
- data/doc/ex/images/Button_9.gif +0 -0
- data/doc/ex/images/Button_A.gif +0 -0
- data/doc/ex/images/Button_B.gif +0 -0
- data/doc/ex/images/Button_C.gif +0 -0
- data/doc/ex/images/Button_D.gif +0 -0
- data/doc/ex/images/Button_E.gif +0 -0
- data/doc/ex/images/Button_F.gif +0 -0
- data/doc/ex/images/Button_G.gif +0 -0
- data/doc/ex/images/Button_H.gif +0 -0
- data/doc/ex/images/Button_I.gif +0 -0
- data/doc/ex/images/Button_J.gif +0 -0
- data/doc/ex/images/Button_K.gif +0 -0
- data/doc/ex/images/Button_L.gif +0 -0
- data/doc/ex/images/Button_M.gif +0 -0
- data/doc/ex/images/Button_N.gif +0 -0
- data/doc/ex/images/Button_O.gif +0 -0
- data/doc/ex/images/Button_P.gif +0 -0
- data/doc/ex/images/Button_Q.gif +0 -0
- data/doc/ex/images/Button_R.gif +0 -0
- data/doc/ex/images/Button_S.gif +0 -0
- data/doc/ex/images/Button_T.gif +0 -0
- data/doc/ex/images/Button_U.gif +0 -0
- data/doc/ex/images/Button_V.gif +0 -0
- data/doc/ex/images/Button_W.gif +0 -0
- data/doc/ex/images/Button_X.gif +0 -0
- data/doc/ex/images/Button_Y.gif +0 -0
- data/doc/ex/images/Button_Z.gif +0 -0
- data/doc/ex/images/Cheetah.jpg +0 -0
- data/doc/ex/images/Coffee.wmf +0 -0
- data/doc/ex/images/Flower_Hat.jpg +0 -0
- data/doc/ex/images/Gold_Statue.jpg +0 -0
- data/doc/ex/images/Hot_Air_Balloons.jpg +0 -0
- data/doc/ex/images/Hot_Air_Balloons_H.jpg +0 -0
- data/doc/ex/images/No.wmf +0 -0
- data/doc/ex/images/Polynesia.jpg +0 -0
- data/doc/ex/images/Red_Rocks.jpg +0 -0
- data/doc/ex/images/Shorts.jpg +0 -0
- data/doc/ex/images/Snake.wmf +0 -0
- data/doc/ex/images/Violin.jpg +0 -0
- data/doc/ex/images/graydient230x6.gif +0 -0
- data/doc/ex/images/logo400x83.gif +0 -0
- data/doc/ex/images/model.miff +0 -0
- data/doc/ex/images/notimplemented.gif +0 -0
- data/doc/ex/images/smile.miff +0 -0
- data/doc/ex/images/spin.gif +0 -0
- data/doc/ex/implode.rb +32 -0
- data/doc/ex/level.rb +12 -0
- data/doc/ex/level_channel.rb +33 -0
- data/doc/ex/line.rb +40 -0
- data/doc/ex/map.rb +28 -0
- data/doc/ex/map_f.rb +15 -0
- data/doc/ex/matte_fill_to_border.rb +42 -0
- data/doc/ex/matte_floodfill.rb +35 -0
- data/doc/ex/matte_replace.rb +42 -0
- data/doc/ex/median_filter.rb +28 -0
- data/doc/ex/modulate.rb +11 -0
- data/doc/ex/mono.rb +23 -0
- data/doc/ex/morph.rb +26 -0
- data/doc/ex/mosaic.rb +35 -0
- data/doc/ex/motion_blur.rb +11 -0
- data/doc/ex/negate.rb +11 -0
- data/doc/ex/negate_channel.rb +19 -0
- data/doc/ex/normalize.rb +11 -0
- data/doc/ex/oil_paint.rb +11 -0
- data/doc/ex/opacity.rb +38 -0
- data/doc/ex/opaque.rb +14 -0
- data/doc/ex/ordered_dither.rb +11 -0
- data/doc/ex/path.rb +62 -0
- data/doc/ex/pattern1.rb +25 -0
- data/doc/ex/pattern2.rb +26 -0
- data/doc/ex/polygon.rb +24 -0
- data/doc/ex/polyline.rb +23 -0
- data/doc/ex/posterize.rb +19 -0
- data/doc/ex/preview.rb +16 -0
- data/doc/ex/qbezierpath.rb +49 -0
- data/doc/ex/quantize-m.rb +25 -0
- data/doc/ex/radial_blur.rb +19 -0
- data/doc/ex/raise.rb +11 -0
- data/doc/ex/random_channel_threshold.rb +17 -0
- data/doc/ex/random_threshold_channel.rb +18 -0
- data/doc/ex/rectangle.rb +33 -0
- data/doc/ex/reduce_noise.rb +28 -0
- data/doc/ex/roll.rb +9 -0
- data/doc/ex/rotate.rb +43 -0
- data/doc/ex/rotate_f.rb +14 -0
- data/doc/ex/roundrect.rb +32 -0
- data/doc/ex/rubyname.rb +31 -0
- data/doc/ex/segment.rb +11 -0
- data/doc/ex/shade.rb +11 -0
- data/doc/ex/shave.rb +15 -0
- data/doc/ex/shear.rb +10 -0
- data/doc/ex/skewx.rb +50 -0
- data/doc/ex/skewy.rb +45 -0
- data/doc/ex/smile.rb +124 -0
- data/doc/ex/solarize.rb +11 -0
- data/doc/ex/splice.rb +16 -0
- data/doc/ex/spread.rb +11 -0
- data/doc/ex/stegano.rb +50 -0
- data/doc/ex/stroke_dasharray.rb +41 -0
- data/doc/ex/stroke_linecap.rb +44 -0
- data/doc/ex/stroke_linejoin.rb +48 -0
- data/doc/ex/stroke_width.rb +47 -0
- data/doc/ex/swirl.rb +17 -0
- data/doc/ex/text.rb +32 -0
- data/doc/ex/text_align.rb +36 -0
- data/doc/ex/text_antialias.rb +33 -0
- data/doc/ex/text_undercolor.rb +26 -0
- data/doc/ex/texture_fill_to_border.rb +34 -0
- data/doc/ex/texture_floodfill.rb +31 -0
- data/doc/ex/texturefill.rb +25 -0
- data/doc/ex/threshold.rb +13 -0
- data/doc/ex/to_blob.rb +14 -0
- data/doc/ex/translate.rb +37 -0
- data/doc/ex/transparent.rb +38 -0
- data/doc/ex/trim.rb +25 -0
- data/doc/ex/unsharp_mask.rb +28 -0
- data/doc/ex/viewex.rb +36 -0
- data/doc/ex/wave.rb +9 -0
- data/doc/ilist.html +1592 -0
- data/doc/image1.html +3009 -0
- data/doc/image2.html +2169 -0
- data/doc/image3.html +2815 -0
- data/doc/imageattrs.html +1319 -0
- data/doc/imusage.html +403 -0
- data/doc/index.html +418 -0
- data/doc/info.html +949 -0
- data/doc/magick.html +439 -0
- data/doc/scripts/doc.js +9 -0
- data/doc/struct.html +1334 -0
- data/doc/usage.html +1318 -0
- data/examples/describe.rb +44 -0
- data/examples/histogram.rb +289 -0
- data/examples/image_opacity.rb +29 -0
- data/examples/import_export.rb +31 -0
- data/examples/pattern_fill.rb +38 -0
- data/examples/rotating_text.rb +47 -0
- data/examples/thumbnail.rb +65 -0
- data/examples/vignette.rb +79 -0
- data/ext/RMagick/MANIFEST +239 -0
- data/ext/RMagick/extconf.rb.in +21 -0
- data/ext/RMagick/rmagick.h +938 -0
- data/ext/RMagick/rmagick_config.h.in +170 -0
- data/ext/RMagick/rmdraw.c +1308 -0
- data/ext/RMagick/rmfill.c +609 -0
- data/ext/RMagick/rmilist.c +685 -0
- data/ext/RMagick/rmimage.c +7980 -0
- data/ext/RMagick/rminfo.c +982 -0
- data/ext/RMagick/rmmain.c +1497 -0
- data/ext/RMagick/rmutil.c +2685 -0
- data/install.rb +1015 -0
- data/lib/RMagick.rb +1486 -0
- data/metaconfig.in +6 -0
- data/post-clean.rb +12 -0
- data/post-install.rb +36 -0
- data/post-setup.rb +245 -0
- data/rmagick.gemspec +22 -0
- data/uninstall.rb +71 -0
- metadata +286 -0
@@ -0,0 +1,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
|
+
}
|