rmagick 2.8.0 → 2.9.0
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 +10 -2
- data/README.html +7 -7
- data/doc/comtasks.html +2 -2
- data/doc/constants.html +5 -5
- data/doc/draw.html +131 -20
- data/doc/ex/InitialCoords.rb +1 -1
- data/doc/ex/NewCoordSys.rb +2 -2
- data/doc/ex/OrigCoordSys.rb +1 -1
- data/doc/ex/RotateScale.rb +2 -2
- data/doc/ex/Skew.rb +2 -2
- data/doc/ex/ViewBox.rb +1 -1
- data/doc/ex/arc.rb +4 -2
- data/doc/ex/arcs02.rb +1 -1
- data/doc/ex/bounding_box.rb +3 -0
- data/doc/ex/cbezier1.rb +2 -0
- data/doc/ex/cbezier2.rb +2 -0
- data/doc/ex/cbezier3.rb +2 -0
- data/doc/ex/cbezier4.rb +2 -0
- data/doc/ex/cbezier5.rb +2 -0
- data/doc/ex/cbezier6.rb +2 -0
- data/doc/ex/channel.rb +1 -0
- data/doc/ex/circle.rb +2 -0
- data/doc/ex/cubic01.rb +1 -1
- data/doc/ex/cubic02.rb +1 -1
- data/doc/ex/ellipse.rb +2 -0
- data/doc/ex/font_styles.rb +12 -10
- data/doc/ex/get_type_metrics.rb +2 -0
- data/doc/ex/grav.rb +2 -0
- data/doc/ex/image.rb +1 -1
- data/doc/ex/line.rb +2 -0
- data/doc/ex/opacity.rb +6 -4
- data/doc/ex/path.rb +2 -0
- data/doc/ex/polaroid.rb +2 -0
- data/doc/ex/qbezierpath.rb +3 -0
- data/doc/ex/rectangle.rb +2 -0
- data/doc/ex/rotate.rb +2 -0
- data/doc/ex/roundrect.rb +2 -0
- data/doc/ex/skewx.rb +2 -0
- data/doc/ex/skewy.rb +2 -0
- data/doc/ex/stroke_dasharray.rb +2 -0
- data/doc/ex/stroke_width.rb +2 -0
- data/doc/ex/text.rb +3 -2
- data/doc/ex/text01.rb +1 -1
- data/doc/ex/text_styles.rb +1 -1
- data/doc/ex/text_undercolor.rb +2 -0
- data/doc/ex/translate.rb +3 -1
- data/doc/ilist.html +2 -2
- data/doc/image1.html +2 -2
- data/doc/image2.html +2 -2
- data/doc/image3.html +37 -6
- data/doc/imageattrs.html +2 -2
- data/doc/imusage.html +3 -3
- data/doc/index.html +3 -3
- data/doc/info.html +2 -2
- data/doc/magick.html +2 -2
- data/doc/optequiv.html +24 -2
- data/doc/rvg.html +2 -2
- data/doc/rvgclip.html +2 -2
- data/doc/rvggroup.html +2 -2
- data/doc/rvgimage.html +2 -2
- data/doc/rvgpattern.html +2 -2
- data/doc/rvgshape.html +2 -2
- data/doc/rvgstyle.html +2 -2
- data/doc/rvgtext.html +2 -2
- data/doc/rvgtspan.html +2 -2
- data/doc/rvgtut.html +2 -2
- data/doc/rvguse.html +2 -2
- data/doc/rvgxform.html +2 -2
- data/doc/struct.html +2 -2
- data/doc/usage.html +6 -4
- data/ext/RMagick/MANIFEST +6 -1
- data/ext/RMagick/extconf.rb +18 -2
- data/ext/RMagick/rmagick.c +312 -0
- data/ext/RMagick/rmagick.h +137 -61
- data/ext/RMagick/rmdraw.c +271 -377
- data/ext/RMagick/rmenum.c +1016 -0
- data/ext/RMagick/rmimage.c +172 -16
- data/ext/RMagick/rminfo.c +5 -5
- data/ext/RMagick/rmmain.c +50 -303
- data/ext/RMagick/rmmontage.c +386 -0
- data/ext/RMagick/rmpixel.c +816 -0
- data/ext/RMagick/rmstruct.c +887 -0
- data/ext/RMagick/rmutil.c +25 -2634
- data/lib/RMagick.rb +46 -2
- data/lib/rvg/misc.rb +5 -4
- data/lib/rvg/stylable.rb +7 -1
- data/rmagick.gemspec +1 -1
- metadata +7 -2
@@ -0,0 +1,386 @@
|
|
1
|
+
/* $Id: rmmontage.c,v 1.3 2009/01/01 23:22:45 rmagick Exp $ */
|
2
|
+
/*============================================================================\
|
3
|
+
| Copyright (C) 2008 by Timothy P. Hunter
|
4
|
+
| Name: rmdraw.c
|
5
|
+
| Author: Tim Hunter
|
6
|
+
| Purpose: Contains Montage class methods.
|
7
|
+
\============================================================================*/
|
8
|
+
|
9
|
+
#include "rmagick.h"
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
/*
|
16
|
+
Static: destroy_Montage
|
17
|
+
Purpose: destory the MontageInfo struct and free the Montage struct
|
18
|
+
Notes: if the Magick::Montage#texture method wrote a texture file,
|
19
|
+
the file is deleted here.
|
20
|
+
*/
|
21
|
+
static void
|
22
|
+
destroy_Montage(void *obj)
|
23
|
+
{
|
24
|
+
Montage *montage = obj;
|
25
|
+
|
26
|
+
// If we saved a temporary texture image, delete it now.
|
27
|
+
if (montage->info && montage->info->texture != NULL)
|
28
|
+
{
|
29
|
+
rm_delete_temp_image(montage->info->texture);
|
30
|
+
magick_free(montage->info->texture);
|
31
|
+
montage->info->texture = NULL;
|
32
|
+
}
|
33
|
+
if (montage->info)
|
34
|
+
{
|
35
|
+
(void) DestroyMontageInfo(montage->info);
|
36
|
+
montage->info = NULL;
|
37
|
+
}
|
38
|
+
xfree(montage);
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
/*
|
43
|
+
Method: Montage.new
|
44
|
+
Purpose: Create a new Montage object
|
45
|
+
*/
|
46
|
+
VALUE
|
47
|
+
Montage_alloc(VALUE class)
|
48
|
+
{
|
49
|
+
MontageInfo *montage_info;
|
50
|
+
Montage *montage;
|
51
|
+
Info *image_info;
|
52
|
+
volatile VALUE montage_obj;
|
53
|
+
|
54
|
+
// DO NOT call rm_info_new - we don't want to support an Info parm block.
|
55
|
+
image_info = CloneImageInfo(NULL);
|
56
|
+
if (!image_info)
|
57
|
+
{
|
58
|
+
rb_raise(rb_eNoMemError, "not enough memory to initialize Info object");
|
59
|
+
}
|
60
|
+
|
61
|
+
montage_info = CloneMontageInfo(image_info, NULL);
|
62
|
+
(void) (void) DestroyImageInfo(image_info);
|
63
|
+
|
64
|
+
if (!montage_info)
|
65
|
+
{
|
66
|
+
rb_raise(rb_eNoMemError, "not enough memory to initialize Magick::Montage object");
|
67
|
+
}
|
68
|
+
|
69
|
+
montage = ALLOC(Montage);
|
70
|
+
montage->info = montage_info;
|
71
|
+
montage->compose = OverCompositeOp;
|
72
|
+
montage_obj = Data_Wrap_Struct(class, NULL, destroy_Montage, montage);
|
73
|
+
|
74
|
+
return montage_obj;
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
/*
|
79
|
+
Method: Magick::Montage#background_color(color-name)
|
80
|
+
Purpose: set background_color value
|
81
|
+
*/
|
82
|
+
VALUE
|
83
|
+
Montage_background_color_eq(VALUE self, VALUE color)
|
84
|
+
{
|
85
|
+
Montage *montage;
|
86
|
+
|
87
|
+
Data_Get_Struct(self, Montage, montage);
|
88
|
+
Color_to_PixelPacket(&montage->info->background_color, color);
|
89
|
+
return self;
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
/*
|
94
|
+
Method: Magick::Montage#border_color(color-name)
|
95
|
+
Purpose: set border_color value
|
96
|
+
*/
|
97
|
+
VALUE
|
98
|
+
Montage_border_color_eq(VALUE self, VALUE color)
|
99
|
+
{
|
100
|
+
Montage *montage;
|
101
|
+
|
102
|
+
Data_Get_Struct(self, Montage, montage);
|
103
|
+
Color_to_PixelPacket(&montage->info->border_color, color);
|
104
|
+
return self;
|
105
|
+
}
|
106
|
+
|
107
|
+
|
108
|
+
/*
|
109
|
+
Method: Magick::Montage#border_width(width)
|
110
|
+
Purpose: set border_width value
|
111
|
+
*/
|
112
|
+
VALUE
|
113
|
+
Montage_border_width_eq(VALUE self, VALUE width)
|
114
|
+
{
|
115
|
+
Montage *montage;
|
116
|
+
|
117
|
+
Data_Get_Struct(self, Montage, montage);
|
118
|
+
montage->info->border_width = NUM2ULONG(width);
|
119
|
+
return self;
|
120
|
+
}
|
121
|
+
|
122
|
+
|
123
|
+
/*
|
124
|
+
Method: Magick::Montage#compose(width)
|
125
|
+
Purpose: set a composition operator
|
126
|
+
*/
|
127
|
+
VALUE
|
128
|
+
Montage_compose_eq(VALUE self, VALUE compose)
|
129
|
+
{
|
130
|
+
Montage *montage;
|
131
|
+
|
132
|
+
Data_Get_Struct(self, Montage, montage);
|
133
|
+
VALUE_TO_ENUM(compose, montage->compose, CompositeOperator);
|
134
|
+
return self;
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
/*
|
139
|
+
Method: Magick::Montage#filename(name)
|
140
|
+
Purpose: set filename value
|
141
|
+
*/
|
142
|
+
VALUE
|
143
|
+
Montage_filename_eq(VALUE self, VALUE filename)
|
144
|
+
{
|
145
|
+
Montage *montage;
|
146
|
+
|
147
|
+
Data_Get_Struct(self, Montage, montage);
|
148
|
+
strncpy(montage->info->filename, StringValuePtr(filename), MaxTextExtent-1);
|
149
|
+
return self;
|
150
|
+
}
|
151
|
+
|
152
|
+
|
153
|
+
/*
|
154
|
+
Method: Magick::Montage#fill(color-name)
|
155
|
+
Purpose: set fill value
|
156
|
+
*/
|
157
|
+
VALUE
|
158
|
+
Montage_fill_eq(VALUE self, VALUE color)
|
159
|
+
{
|
160
|
+
Montage *montage;
|
161
|
+
|
162
|
+
Data_Get_Struct(self, Montage, montage);
|
163
|
+
Color_to_PixelPacket(&montage->info->fill, color);
|
164
|
+
return self;
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
/*
|
169
|
+
Method: Magick::Montage#font(font-name)
|
170
|
+
Purpose: set font value
|
171
|
+
*/
|
172
|
+
VALUE
|
173
|
+
Montage_font_eq(VALUE self, VALUE font)
|
174
|
+
{
|
175
|
+
Montage *montage;
|
176
|
+
|
177
|
+
Data_Get_Struct(self, Montage, montage);
|
178
|
+
magick_clone_string(&montage->info->font, StringValuePtr(font));
|
179
|
+
|
180
|
+
return self;
|
181
|
+
}
|
182
|
+
|
183
|
+
|
184
|
+
/*
|
185
|
+
Method: Magick::Montage#frame(frame-geometry)
|
186
|
+
Purpose: set frame value
|
187
|
+
Notes: The geometry is a string in the form:
|
188
|
+
<width>x<height>+<outer-bevel-width>+<inner-bevel-width>
|
189
|
+
or a Geometry object
|
190
|
+
*/
|
191
|
+
VALUE
|
192
|
+
Montage_frame_eq(VALUE self, VALUE frame_arg)
|
193
|
+
{
|
194
|
+
Montage *montage;
|
195
|
+
volatile VALUE frame;
|
196
|
+
|
197
|
+
Data_Get_Struct(self, Montage, montage);
|
198
|
+
frame = rm_to_s(frame_arg);
|
199
|
+
magick_clone_string(&montage->info->frame, StringValuePtr(frame));
|
200
|
+
|
201
|
+
return self;
|
202
|
+
}
|
203
|
+
|
204
|
+
|
205
|
+
/*
|
206
|
+
Method: Magick::Montage#geometry(geometry)
|
207
|
+
Purpose: set geometry value
|
208
|
+
*/
|
209
|
+
VALUE
|
210
|
+
Montage_geometry_eq(VALUE self, VALUE geometry_arg)
|
211
|
+
{
|
212
|
+
Montage *montage;
|
213
|
+
volatile VALUE geometry;
|
214
|
+
|
215
|
+
Data_Get_Struct(self, Montage, montage);
|
216
|
+
geometry = rm_to_s(geometry_arg);
|
217
|
+
magick_clone_string(&montage->info->geometry, StringValuePtr(geometry));
|
218
|
+
|
219
|
+
return self;
|
220
|
+
}
|
221
|
+
|
222
|
+
|
223
|
+
/*
|
224
|
+
Method: Magick::Montage#gravity(gravity-type)
|
225
|
+
Purpose: set gravity value
|
226
|
+
*/
|
227
|
+
VALUE
|
228
|
+
Montage_gravity_eq(VALUE self, VALUE gravity)
|
229
|
+
{
|
230
|
+
Montage *montage;
|
231
|
+
|
232
|
+
Data_Get_Struct(self, Montage, montage);
|
233
|
+
VALUE_TO_ENUM(gravity, montage->info->gravity, GravityType);
|
234
|
+
return self;
|
235
|
+
}
|
236
|
+
|
237
|
+
|
238
|
+
/*
|
239
|
+
Method: Magick::Montage#initialize
|
240
|
+
Purpose: Place-holder
|
241
|
+
*/
|
242
|
+
VALUE
|
243
|
+
Montage_initialize(VALUE self)
|
244
|
+
{
|
245
|
+
// Nothing to do!
|
246
|
+
return self;
|
247
|
+
}
|
248
|
+
|
249
|
+
|
250
|
+
/*
|
251
|
+
Method: Magick::Montage#matte_color(color-name)
|
252
|
+
Purpose: set matte_color value
|
253
|
+
*/
|
254
|
+
VALUE
|
255
|
+
Montage_matte_color_eq(VALUE self, VALUE color)
|
256
|
+
{
|
257
|
+
Montage *montage;
|
258
|
+
|
259
|
+
Data_Get_Struct(self, Montage, montage);
|
260
|
+
Color_to_PixelPacket(&montage->info->matte_color, color);
|
261
|
+
return self;
|
262
|
+
}
|
263
|
+
|
264
|
+
|
265
|
+
/*
|
266
|
+
Method: Magick::Montage#pointsize=size
|
267
|
+
Purpose: set pointsize value
|
268
|
+
*/
|
269
|
+
VALUE
|
270
|
+
Montage_pointsize_eq(VALUE self, VALUE size)
|
271
|
+
{
|
272
|
+
Montage *montage;
|
273
|
+
|
274
|
+
Data_Get_Struct(self, Montage, montage);
|
275
|
+
montage->info->pointsize = NUM2DBL(size);
|
276
|
+
return self;
|
277
|
+
}
|
278
|
+
|
279
|
+
|
280
|
+
/*
|
281
|
+
Method: Magick::Montage#shadow=shadow
|
282
|
+
Purpose: set shadow value
|
283
|
+
*/
|
284
|
+
VALUE
|
285
|
+
Montage_shadow_eq(VALUE self, VALUE shadow)
|
286
|
+
{
|
287
|
+
Montage *montage;
|
288
|
+
|
289
|
+
Data_Get_Struct(self, Montage, montage);
|
290
|
+
montage->info->shadow = (MagickBooleanType) RTEST(shadow);
|
291
|
+
return self;
|
292
|
+
}
|
293
|
+
|
294
|
+
|
295
|
+
/*
|
296
|
+
Method: Magick::Montage#stroke(color-name)
|
297
|
+
Purpose: set stroke value
|
298
|
+
*/
|
299
|
+
VALUE
|
300
|
+
Montage_stroke_eq(VALUE self, VALUE color)
|
301
|
+
{
|
302
|
+
Montage *montage;
|
303
|
+
|
304
|
+
Data_Get_Struct(self, Montage, montage);
|
305
|
+
Color_to_PixelPacket(&montage->info->stroke, color);
|
306
|
+
return self;
|
307
|
+
}
|
308
|
+
|
309
|
+
|
310
|
+
/*
|
311
|
+
Method: Montage#texture(texture-image)
|
312
|
+
Purpose: set texture value
|
313
|
+
*/
|
314
|
+
VALUE
|
315
|
+
Montage_texture_eq(VALUE self, VALUE texture)
|
316
|
+
{
|
317
|
+
Montage *montage;
|
318
|
+
Image *texture_image;
|
319
|
+
char temp_name[MaxTextExtent];
|
320
|
+
|
321
|
+
Data_Get_Struct(self, Montage, montage);
|
322
|
+
|
323
|
+
// If we had a previously defined temp texture image,
|
324
|
+
// remove it now in preparation for this new one.
|
325
|
+
if (montage->info->texture)
|
326
|
+
{
|
327
|
+
rm_delete_temp_image(montage->info->texture);
|
328
|
+
magick_free(montage->info->texture);
|
329
|
+
montage->info->texture = NULL;
|
330
|
+
}
|
331
|
+
|
332
|
+
texture = rm_cur_image(texture);
|
333
|
+
texture_image = rm_check_destroyed(texture);
|
334
|
+
|
335
|
+
// Write a temp copy of the image & save its name.
|
336
|
+
rm_write_temp_image(texture_image, temp_name);
|
337
|
+
magick_clone_string(&montage->info->texture, temp_name);
|
338
|
+
|
339
|
+
return self;
|
340
|
+
}
|
341
|
+
|
342
|
+
|
343
|
+
/*
|
344
|
+
Method: Magick::Montage#tile(tile)
|
345
|
+
Purpose: set tile value
|
346
|
+
*/
|
347
|
+
VALUE
|
348
|
+
Montage_tile_eq(VALUE self, VALUE tile_arg)
|
349
|
+
{
|
350
|
+
Montage *montage;
|
351
|
+
volatile VALUE tile;
|
352
|
+
|
353
|
+
Data_Get_Struct(self, Montage, montage);
|
354
|
+
tile = rm_to_s(tile_arg);
|
355
|
+
magick_clone_string(&montage->info->tile, StringValuePtr(tile));
|
356
|
+
|
357
|
+
return self;
|
358
|
+
}
|
359
|
+
|
360
|
+
|
361
|
+
/*
|
362
|
+
Method: Magick::Montage#title(title)
|
363
|
+
Purpose: set title value
|
364
|
+
*/
|
365
|
+
VALUE
|
366
|
+
Montage_title_eq(VALUE self, VALUE title)
|
367
|
+
{
|
368
|
+
Montage *montage;
|
369
|
+
|
370
|
+
Data_Get_Struct(self, Montage, montage);
|
371
|
+
magick_clone_string(&montage->info->title, StringValuePtr(title));
|
372
|
+
return self;
|
373
|
+
}
|
374
|
+
|
375
|
+
|
376
|
+
/*
|
377
|
+
Extern: rm_montage_new()
|
378
|
+
Purpose: Return a new Magick::Montage object
|
379
|
+
*/
|
380
|
+
|
381
|
+
VALUE
|
382
|
+
rm_montage_new(void)
|
383
|
+
{
|
384
|
+
return Montage_initialize(Montage_alloc(Class_Montage));
|
385
|
+
}
|
386
|
+
|
@@ -0,0 +1,816 @@
|
|
1
|
+
/* $Id: rmpixel.c,v 1.2 2008/12/27 00:15:56 rmagick Exp $ */
|
2
|
+
/*============================================================================\
|
3
|
+
| Copyright (C) 2008 by Timothy P. Hunter
|
4
|
+
| Name: rmpixel.c
|
5
|
+
| Author: Tim Hunter
|
6
|
+
| Purpose: Contains Pixel class methods.
|
7
|
+
\============================================================================*/
|
8
|
+
|
9
|
+
#include "rmagick.h"
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
static void Color_Name_to_PixelPacket(PixelPacket *, VALUE);
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
/*
|
20
|
+
Extern: destroy_Pixel
|
21
|
+
Purpose: Free the storage associated with a Pixel object
|
22
|
+
*/
|
23
|
+
void
|
24
|
+
destroy_Pixel(Pixel *pixel)
|
25
|
+
{
|
26
|
+
xfree(pixel);
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
/*
|
31
|
+
Methods: Pixel RGBA attribute accessors
|
32
|
+
Purpose: Get/set Pixel attributes
|
33
|
+
Note: Pixel is Observable. Setters call changed, notify_observers
|
34
|
+
Note: Setters return their argument values for backward compatibility
|
35
|
+
to when Pixel was a Struct class.
|
36
|
+
*/
|
37
|
+
DEF_ATTR_READER(Pixel, red, int)
|
38
|
+
DEF_ATTR_READER(Pixel, green, int)
|
39
|
+
DEF_ATTR_READER(Pixel, blue, int)
|
40
|
+
DEF_ATTR_READER(Pixel, opacity, int)
|
41
|
+
DEF_PIXEL_CHANNEL_WRITER(red)
|
42
|
+
DEF_PIXEL_CHANNEL_WRITER(green)
|
43
|
+
DEF_PIXEL_CHANNEL_WRITER(blue)
|
44
|
+
DEF_PIXEL_CHANNEL_WRITER(opacity)
|
45
|
+
|
46
|
+
|
47
|
+
/*
|
48
|
+
Methods: Pixel CMYK attribute accessors
|
49
|
+
Purpose: Get/set Pixel attributes
|
50
|
+
Note: Pixel is Observable. Setters call changed, notify_observers
|
51
|
+
Note: Setters return their argument values for backward compatibility
|
52
|
+
to when Pixel was a Struct class.
|
53
|
+
*/
|
54
|
+
DEF_PIXEL_CMYK_CHANNEL_ACCESSOR(cyan, red)
|
55
|
+
DEF_PIXEL_CMYK_CHANNEL_ACCESSOR(magenta, green)
|
56
|
+
DEF_PIXEL_CMYK_CHANNEL_ACCESSOR(yellow, blue)
|
57
|
+
DEF_PIXEL_CMYK_CHANNEL_ACCESSOR(black, opacity)
|
58
|
+
|
59
|
+
|
60
|
+
/*
|
61
|
+
* Static: color_arg_rescue
|
62
|
+
* Purpose: raise ArgumentError if the color name cannot be converted
|
63
|
+
* to a string via rb_str_to_str.
|
64
|
+
*/
|
65
|
+
static VALUE
|
66
|
+
color_arg_rescue(VALUE arg)
|
67
|
+
{
|
68
|
+
rb_raise(rb_eTypeError, "argument must be color name or pixel (%s given)",
|
69
|
+
rb_class2name(CLASS_OF(arg)));
|
70
|
+
return (VALUE)0;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
/*
|
75
|
+
Extern: Color_to_PixelPacket
|
76
|
+
Purpose: Convert either a String color name or
|
77
|
+
a Magick::Pixel to a PixelPacket
|
78
|
+
*/
|
79
|
+
void
|
80
|
+
Color_to_PixelPacket(PixelPacket *pp, VALUE color)
|
81
|
+
{
|
82
|
+
Pixel *pixel;
|
83
|
+
|
84
|
+
// Allow color name or Pixel
|
85
|
+
if (CLASS_OF(color) == Class_Pixel)
|
86
|
+
{
|
87
|
+
Data_Get_Struct(color, Pixel, pixel);
|
88
|
+
*pp = *pixel;
|
89
|
+
}
|
90
|
+
else
|
91
|
+
{
|
92
|
+
// require 'to_str' here instead of just 'to_s'.
|
93
|
+
color = rb_rescue(rb_str_to_str, color, color_arg_rescue, color);
|
94
|
+
Color_Name_to_PixelPacket(pp, color);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
|
99
|
+
/*
|
100
|
+
Static: Color_Name_to_PixelPacket
|
101
|
+
Purpose: Convert a color name to a PixelPacket
|
102
|
+
Raises: ArgumentError
|
103
|
+
*/
|
104
|
+
static void
|
105
|
+
Color_Name_to_PixelPacket(PixelPacket *color, VALUE name_arg)
|
106
|
+
{
|
107
|
+
MagickBooleanType okay;
|
108
|
+
char *name;
|
109
|
+
ExceptionInfo exception;
|
110
|
+
|
111
|
+
GetExceptionInfo(&exception);
|
112
|
+
name = StringValuePtr(name_arg);
|
113
|
+
okay = QueryColorDatabase(name, color, &exception);
|
114
|
+
(void) DestroyExceptionInfo(&exception);
|
115
|
+
if (!okay)
|
116
|
+
{
|
117
|
+
rb_raise(rb_eArgError, "invalid color name %s", name);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
/*
|
124
|
+
Extern: Pixel_alloc
|
125
|
+
Purpose: Allocate a Pixel object
|
126
|
+
*/
|
127
|
+
VALUE
|
128
|
+
Pixel_alloc(VALUE class)
|
129
|
+
{
|
130
|
+
Pixel *pixel;
|
131
|
+
|
132
|
+
pixel = ALLOC(Pixel);
|
133
|
+
memset(pixel, '\0', sizeof(Pixel));
|
134
|
+
return Data_Wrap_Struct(class, NULL, destroy_Pixel, pixel);
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
/*
|
139
|
+
Method: Pixel#===
|
140
|
+
Purpose: "Case equal" operator for Pixel
|
141
|
+
*/
|
142
|
+
|
143
|
+
VALUE
|
144
|
+
Pixel_case_eq(VALUE self, VALUE other)
|
145
|
+
{
|
146
|
+
Pixel *this, *that;
|
147
|
+
|
148
|
+
if (CLASS_OF(self) == CLASS_OF(other))
|
149
|
+
{
|
150
|
+
Data_Get_Struct(self, Pixel, this);
|
151
|
+
Data_Get_Struct(other, Pixel, that);
|
152
|
+
return (this->red == that->red
|
153
|
+
&& this->blue == that->blue
|
154
|
+
&& this->green == that->green
|
155
|
+
&& this->opacity == that->opacity) ? Qtrue : Qfalse;
|
156
|
+
}
|
157
|
+
|
158
|
+
return Qfalse;
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
/*
|
163
|
+
Method: Pixel#clone
|
164
|
+
Notes: see dup, init_copy
|
165
|
+
*/
|
166
|
+
VALUE
|
167
|
+
Pixel_clone(VALUE self)
|
168
|
+
{
|
169
|
+
volatile VALUE clone;
|
170
|
+
|
171
|
+
clone = Pixel_dup(self);
|
172
|
+
if (OBJ_FROZEN(self))
|
173
|
+
{
|
174
|
+
OBJ_FREEZE(clone);
|
175
|
+
}
|
176
|
+
|
177
|
+
return clone;
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
VALUE
|
182
|
+
Pixel_dup(VALUE self)
|
183
|
+
{
|
184
|
+
Pixel *pixel;
|
185
|
+
volatile VALUE dup;
|
186
|
+
|
187
|
+
pixel = ALLOC(Pixel);
|
188
|
+
memset(pixel, '\0', sizeof(Pixel));
|
189
|
+
dup = Data_Wrap_Struct(CLASS_OF(self), NULL, destroy_Pixel, pixel);
|
190
|
+
if (rb_obj_tainted(self))
|
191
|
+
{
|
192
|
+
(void) rb_obj_taint(dup);
|
193
|
+
}
|
194
|
+
return rb_funcall(dup, rm_ID_initialize_copy, 1, self);
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
/*
|
199
|
+
Method: Pixel#eql?
|
200
|
+
Purpose: For use with Hash
|
201
|
+
*/
|
202
|
+
VALUE
|
203
|
+
Pixel_eql_q(VALUE self, VALUE other)
|
204
|
+
{
|
205
|
+
return NUM2INT(Pixel_spaceship(self, other)) == 0 ? Qtrue : Qfalse;
|
206
|
+
}
|
207
|
+
|
208
|
+
|
209
|
+
/*
|
210
|
+
Method: Pixel#fcmp(other[, fuzz[, colorspace]])
|
211
|
+
Purpose: Compare pixel values for equality
|
212
|
+
*/
|
213
|
+
VALUE
|
214
|
+
Pixel_fcmp(int argc, VALUE *argv, VALUE self)
|
215
|
+
{
|
216
|
+
Image *image;
|
217
|
+
Info *info;
|
218
|
+
|
219
|
+
Pixel *this, *that;
|
220
|
+
ColorspaceType colorspace = RGBColorspace;
|
221
|
+
double fuzz = 0.0;
|
222
|
+
unsigned int equal;
|
223
|
+
|
224
|
+
switch (argc)
|
225
|
+
{
|
226
|
+
case 3:
|
227
|
+
VALUE_TO_ENUM(argv[2], colorspace, ColorspaceType);
|
228
|
+
case 2:
|
229
|
+
fuzz = NUM2DBL(argv[1]);
|
230
|
+
case 1:
|
231
|
+
// Allow 1 argument
|
232
|
+
break;
|
233
|
+
default:
|
234
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 to 3)", argc);
|
235
|
+
break;
|
236
|
+
}
|
237
|
+
|
238
|
+
Data_Get_Struct(self, Pixel, this);
|
239
|
+
Data_Get_Struct(argv[0], Pixel, that);
|
240
|
+
|
241
|
+
// The IsColorSimilar function expects to get the
|
242
|
+
// colorspace and fuzz parameters from an Image structure.
|
243
|
+
|
244
|
+
info = CloneImageInfo(NULL);
|
245
|
+
if (!info)
|
246
|
+
{
|
247
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
248
|
+
}
|
249
|
+
|
250
|
+
image = AcquireImage(info);
|
251
|
+
|
252
|
+
// Delete Info now in case we have to raise an exception
|
253
|
+
(void) DestroyImageInfo(info);
|
254
|
+
|
255
|
+
if (!image)
|
256
|
+
{
|
257
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
258
|
+
}
|
259
|
+
|
260
|
+
image->colorspace = colorspace;
|
261
|
+
image->fuzz = fuzz;
|
262
|
+
|
263
|
+
equal = IsColorSimilar(image, this, that);
|
264
|
+
(void) DestroyImage(image);
|
265
|
+
|
266
|
+
return equal ? Qtrue : Qfalse;
|
267
|
+
}
|
268
|
+
|
269
|
+
|
270
|
+
/*
|
271
|
+
Method: Magick::Pixel.from_color(string)
|
272
|
+
Purpose: Construct an Magick::Pixel corresponding to the given color name.
|
273
|
+
Notes: the "inverse" is Image *#to_color, b/c the conversion of a pixel
|
274
|
+
to a color name requires both a color depth and if the opacity
|
275
|
+
value has meaning (i.e. whether image->matte == True or not).
|
276
|
+
|
277
|
+
Also see Magick::Pixel#to_color, below.
|
278
|
+
*/
|
279
|
+
VALUE
|
280
|
+
Pixel_from_color(VALUE class, VALUE name)
|
281
|
+
{
|
282
|
+
PixelPacket pp;
|
283
|
+
ExceptionInfo exception;
|
284
|
+
MagickBooleanType okay;
|
285
|
+
|
286
|
+
class = class; // defeat "never referenced" message from icc
|
287
|
+
|
288
|
+
GetExceptionInfo(&exception);
|
289
|
+
okay = QueryColorDatabase(StringValuePtr(name), &pp, &exception);
|
290
|
+
CHECK_EXCEPTION()
|
291
|
+
(void) DestroyExceptionInfo(&exception);
|
292
|
+
|
293
|
+
if (!okay)
|
294
|
+
{
|
295
|
+
rb_raise(rb_eArgError, "invalid color name: %s", StringValuePtr(name));
|
296
|
+
}
|
297
|
+
|
298
|
+
return Pixel_from_PixelPacket(&pp);
|
299
|
+
}
|
300
|
+
|
301
|
+
|
302
|
+
/*
|
303
|
+
Method: Pixel#from_hsla(hue, saturation, lightness, alpha=1)
|
304
|
+
Purpose: Replace brain-dead from_HSL, above.
|
305
|
+
Notes: 0 <= hue < 360, 0 <= saturation <= 1, 0 <= lightness <= 1
|
306
|
+
0 <= alpha <= 1 (0 is transparent, 1 is opaque)
|
307
|
+
*/
|
308
|
+
VALUE
|
309
|
+
Pixel_from_hsla(int argc, VALUE *argv, VALUE class)
|
310
|
+
{
|
311
|
+
double h, s, l, a = 1.0;
|
312
|
+
MagickPixelPacket pp;
|
313
|
+
ExceptionInfo exception;
|
314
|
+
char name[50];
|
315
|
+
MagickBooleanType alpha = MagickFalse;
|
316
|
+
|
317
|
+
class = class; // defeat "unused parameter" message.
|
318
|
+
|
319
|
+
switch (argc)
|
320
|
+
{
|
321
|
+
case 4:
|
322
|
+
a = NUM2DBL(argv[3]);
|
323
|
+
alpha = MagickTrue;
|
324
|
+
case 3:
|
325
|
+
l = NUM2DBL(argv[2]);
|
326
|
+
s = NUM2DBL(argv[1]);
|
327
|
+
h = NUM2DBL(argv[0]);
|
328
|
+
break;
|
329
|
+
default:
|
330
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 3 or 4)", argc);
|
331
|
+
break;
|
332
|
+
}
|
333
|
+
|
334
|
+
if (alpha && (a < 0.0 || a > 1.0))
|
335
|
+
{
|
336
|
+
rb_raise(rb_eRangeError, "alpha %g out of range [0.0, 1.0]", a);
|
337
|
+
}
|
338
|
+
if (l < 0.0 || l > 100.0)
|
339
|
+
{
|
340
|
+
rb_raise(rb_eRangeError, "lightness %g out of range [0.0, 100.0]", l);
|
341
|
+
}
|
342
|
+
if (s < 0.0 || s > 100.0)
|
343
|
+
{
|
344
|
+
rb_raise(rb_eRangeError, "saturation %g out of range [0.0, 100.0]", s);
|
345
|
+
}
|
346
|
+
if (h < 0.0 || h >= 360.0)
|
347
|
+
{
|
348
|
+
rb_raise(rb_eRangeError, "hue %g out of range [0.0, 360.0)", h);
|
349
|
+
}
|
350
|
+
|
351
|
+
memset(name, 0, sizeof(name));
|
352
|
+
if (alpha)
|
353
|
+
{
|
354
|
+
sprintf(name, "hsla(%-2.1f,%-2.1f,%-2.1f,%-2.1f)", h, s, l, a);
|
355
|
+
}
|
356
|
+
else
|
357
|
+
{
|
358
|
+
sprintf(name, "hsl(%-2.1f,%-2.1f,%-2.1f)", h, s, l);
|
359
|
+
}
|
360
|
+
|
361
|
+
GetExceptionInfo(&exception);
|
362
|
+
|
363
|
+
(void) QueryMagickColor(name, &pp, &exception);
|
364
|
+
CHECK_EXCEPTION()
|
365
|
+
|
366
|
+
(void) DestroyExceptionInfo(&exception);
|
367
|
+
|
368
|
+
return Pixel_from_MagickPixelPacket(&pp);
|
369
|
+
}
|
370
|
+
|
371
|
+
|
372
|
+
/*
|
373
|
+
Method: Pixel.from_HSL *** DEPRECATED ***
|
374
|
+
Purpose: Constructs an RGB pixel from the array
|
375
|
+
[hue, saturation, luminosity].
|
376
|
+
*/
|
377
|
+
VALUE
|
378
|
+
Pixel_from_HSL(VALUE class, VALUE hsl)
|
379
|
+
{
|
380
|
+
PixelPacket rgb;
|
381
|
+
double hue, saturation, luminosity;
|
382
|
+
|
383
|
+
class = class; // defeat "never referenced" message from icc
|
384
|
+
memset(&rgb, 0, sizeof(rgb));
|
385
|
+
|
386
|
+
hsl = rb_Array(hsl); // Ensure array
|
387
|
+
if (RARRAY_LEN(hsl) < 3)
|
388
|
+
{
|
389
|
+
rb_raise(rb_eArgError, "array argument must have at least 3 elements");
|
390
|
+
}
|
391
|
+
|
392
|
+
hue = NUM2DBL(rb_ary_entry(hsl, 0));
|
393
|
+
saturation = NUM2DBL(rb_ary_entry(hsl, 1));
|
394
|
+
luminosity = NUM2DBL(rb_ary_entry(hsl, 2));
|
395
|
+
|
396
|
+
#if defined(HAVE_CONVERTHSLTORGB)
|
397
|
+
rb_warning("Pixel#from_HSL is deprecated; use from_hsla");
|
398
|
+
ConvertHSLToRGB(hue, saturation, luminosity,
|
399
|
+
&rgb.red, &rgb.green, &rgb.blue);
|
400
|
+
#else
|
401
|
+
HSLTransform(hue, saturation, luminosity,
|
402
|
+
&rgb.red, &rgb.green, &rgb.blue);
|
403
|
+
#endif
|
404
|
+
return Pixel_from_PixelPacket(&rgb);
|
405
|
+
}
|
406
|
+
|
407
|
+
|
408
|
+
/*
|
409
|
+
Static: Pixel_from_MagickPixelPacket
|
410
|
+
Purpose: Create a Magick::Pixel object from a MagickPixelPacket structure.
|
411
|
+
Notes: bypasses normal Pixel.new, Pixel#initialize methods
|
412
|
+
*/
|
413
|
+
VALUE
|
414
|
+
Pixel_from_MagickPixelPacket(const MagickPixelPacket *pp)
|
415
|
+
{
|
416
|
+
Pixel *pixel;
|
417
|
+
|
418
|
+
pixel = ALLOC(Pixel);
|
419
|
+
pixel->red = ROUND_TO_QUANTUM(pp->red);
|
420
|
+
pixel->green = ROUND_TO_QUANTUM(pp->green);
|
421
|
+
pixel->blue = ROUND_TO_QUANTUM(pp->blue);
|
422
|
+
pixel->opacity = ROUND_TO_QUANTUM(pp->opacity);
|
423
|
+
|
424
|
+
return Data_Wrap_Struct(Class_Pixel, NULL, destroy_Pixel, pixel);
|
425
|
+
}
|
426
|
+
|
427
|
+
|
428
|
+
/*
|
429
|
+
Extern: Pixel_from_PixelPacket
|
430
|
+
Purpose: Create a Magick::Pixel object from a PixelPacket structure.
|
431
|
+
Notes: bypasses normal Pixel.new, Pixel#initialize methods
|
432
|
+
*/
|
433
|
+
VALUE
|
434
|
+
Pixel_from_PixelPacket(const PixelPacket *pp)
|
435
|
+
{
|
436
|
+
Pixel *pixel;
|
437
|
+
|
438
|
+
pixel = ALLOC(Pixel);
|
439
|
+
*pixel = *pp;
|
440
|
+
return Data_Wrap_Struct(Class_Pixel, NULL, destroy_Pixel, pixel);
|
441
|
+
}
|
442
|
+
|
443
|
+
|
444
|
+
/*
|
445
|
+
Method: Pixel#hash
|
446
|
+
Notes: INT2FIX left-shifts 1 bit. Sacrifice 1 bit
|
447
|
+
from the opacity attribute to the FIXNUM_FLAG.
|
448
|
+
*/
|
449
|
+
VALUE
|
450
|
+
Pixel_hash(VALUE self)
|
451
|
+
{
|
452
|
+
Pixel *pixel;
|
453
|
+
unsigned int hash;
|
454
|
+
|
455
|
+
Data_Get_Struct(self, Pixel, pixel);
|
456
|
+
|
457
|
+
hash = ScaleQuantumToChar(pixel->red) << 24;
|
458
|
+
hash += ScaleQuantumToChar(pixel->green) << 16;
|
459
|
+
hash += ScaleQuantumToChar(pixel->blue) << 8;
|
460
|
+
hash += ScaleQuantumToChar(pixel->opacity);
|
461
|
+
hash >>= 1;
|
462
|
+
|
463
|
+
return INT2FIX(hash);
|
464
|
+
|
465
|
+
}
|
466
|
+
|
467
|
+
|
468
|
+
/*
|
469
|
+
Method: Pixel#initialize_copy
|
470
|
+
Purpose: initialize clone, dup methods
|
471
|
+
*/
|
472
|
+
VALUE
|
473
|
+
Pixel_init_copy(VALUE self, VALUE orig)
|
474
|
+
{
|
475
|
+
Pixel *copy, *original;
|
476
|
+
|
477
|
+
Data_Get_Struct(orig, Pixel, original);
|
478
|
+
Data_Get_Struct(self, Pixel, copy);
|
479
|
+
|
480
|
+
*copy = *original;
|
481
|
+
|
482
|
+
return self;
|
483
|
+
}
|
484
|
+
|
485
|
+
|
486
|
+
/*
|
487
|
+
Method: Pixel#initialize(red=0,green=0,blue=0,opacity=0)
|
488
|
+
Notes: For backward compatibility, arguments may be nil.
|
489
|
+
*/
|
490
|
+
VALUE
|
491
|
+
Pixel_initialize(int argc, VALUE *argv, VALUE self)
|
492
|
+
{
|
493
|
+
Pixel *pixel;
|
494
|
+
|
495
|
+
Data_Get_Struct(self, Pixel, pixel);
|
496
|
+
|
497
|
+
switch(argc)
|
498
|
+
{
|
499
|
+
case 4:
|
500
|
+
if (argv[3] != Qnil)
|
501
|
+
{
|
502
|
+
pixel->opacity = APP2QUANTUM(argv[3]);
|
503
|
+
}
|
504
|
+
case 3:
|
505
|
+
if (argv[2] != Qnil)
|
506
|
+
{
|
507
|
+
pixel->blue = APP2QUANTUM(argv[2]);
|
508
|
+
}
|
509
|
+
case 2:
|
510
|
+
if (argv[1] != Qnil)
|
511
|
+
{
|
512
|
+
pixel->green = APP2QUANTUM(argv[1]);
|
513
|
+
}
|
514
|
+
case 1:
|
515
|
+
if (argv[0] != Qnil)
|
516
|
+
{
|
517
|
+
pixel->red = APP2QUANTUM(argv[0]);
|
518
|
+
}
|
519
|
+
case 0:
|
520
|
+
break;
|
521
|
+
default:
|
522
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 4)", argc);
|
523
|
+
}
|
524
|
+
|
525
|
+
return self;
|
526
|
+
}
|
527
|
+
|
528
|
+
|
529
|
+
/*
|
530
|
+
Method: Pixel#intensity
|
531
|
+
Purpose: Return the "intensity" of a pixel
|
532
|
+
*/
|
533
|
+
VALUE
|
534
|
+
Pixel_intensity(VALUE self)
|
535
|
+
{
|
536
|
+
Pixel *pixel;
|
537
|
+
Quantum intensity;
|
538
|
+
|
539
|
+
Data_Get_Struct(self, Pixel, pixel);
|
540
|
+
|
541
|
+
intensity = ROUND_TO_QUANTUM((0.299*pixel->red)
|
542
|
+
+ (0.587*pixel->green)
|
543
|
+
+ (0.114*pixel->blue));
|
544
|
+
|
545
|
+
return QUANTUM2NUM((unsigned long) intensity);
|
546
|
+
}
|
547
|
+
|
548
|
+
|
549
|
+
/*
|
550
|
+
Method: Pixel#marshal_dump
|
551
|
+
Purpose: Support Marshal.dump
|
552
|
+
*/
|
553
|
+
VALUE
|
554
|
+
Pixel_marshal_dump(VALUE self)
|
555
|
+
{
|
556
|
+
Pixel *pixel;
|
557
|
+
volatile VALUE dpixel;
|
558
|
+
|
559
|
+
Data_Get_Struct(self, Pixel, pixel);
|
560
|
+
dpixel = rb_hash_new();
|
561
|
+
rb_hash_aset(dpixel, CSTR2SYM("red"), QUANTUM2NUM(pixel->red));
|
562
|
+
rb_hash_aset(dpixel, CSTR2SYM("green"), QUANTUM2NUM(pixel->green));
|
563
|
+
rb_hash_aset(dpixel, CSTR2SYM("blue"), QUANTUM2NUM(pixel->blue));
|
564
|
+
rb_hash_aset(dpixel, CSTR2SYM("opacity"), QUANTUM2NUM(pixel->opacity));
|
565
|
+
return dpixel;
|
566
|
+
}
|
567
|
+
|
568
|
+
|
569
|
+
/*
|
570
|
+
Method: Pixel#marshal_load
|
571
|
+
Purpose: Support Marshal.load
|
572
|
+
*/
|
573
|
+
VALUE
|
574
|
+
Pixel_marshal_load(VALUE self, VALUE dpixel)
|
575
|
+
{
|
576
|
+
Pixel *pixel;
|
577
|
+
|
578
|
+
Data_Get_Struct(self, Pixel, pixel);
|
579
|
+
pixel->red = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("red")));
|
580
|
+
pixel->green = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("green")));
|
581
|
+
pixel->blue = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("blue")));
|
582
|
+
pixel->opacity = NUM2QUANTUM(rb_hash_aref(dpixel, CSTR2SYM("opacity")));
|
583
|
+
return self;
|
584
|
+
}
|
585
|
+
|
586
|
+
|
587
|
+
/*
|
588
|
+
Method: Pixel#<=>
|
589
|
+
Purpose: Support Comparable mixin
|
590
|
+
*/
|
591
|
+
VALUE
|
592
|
+
Pixel_spaceship(VALUE self, VALUE other)
|
593
|
+
{
|
594
|
+
Pixel *this, *that;
|
595
|
+
|
596
|
+
Data_Get_Struct(self, Pixel, this);
|
597
|
+
Data_Get_Struct(other, Pixel, that);
|
598
|
+
|
599
|
+
if (this->red != that->red)
|
600
|
+
{
|
601
|
+
return INT2NUM((this->red - that->red)/abs(this->red - that->red));
|
602
|
+
}
|
603
|
+
else if(this->green != that->green)
|
604
|
+
{
|
605
|
+
return INT2NUM((this->green - that->green)/abs(this->green - that->green));
|
606
|
+
}
|
607
|
+
else if(this->blue != that->blue)
|
608
|
+
{
|
609
|
+
return INT2NUM((this->blue - that->blue)/abs(this->blue - that->blue));
|
610
|
+
}
|
611
|
+
else if(this->opacity != that->opacity)
|
612
|
+
{
|
613
|
+
return INT2NUM((this->opacity - that->opacity)/abs(this->opacity - that->opacity));
|
614
|
+
}
|
615
|
+
|
616
|
+
// Values are equal, check class.
|
617
|
+
|
618
|
+
return rb_funcall(CLASS_OF(self), rb_intern("<=>"), 1, CLASS_OF(other));
|
619
|
+
|
620
|
+
}
|
621
|
+
|
622
|
+
|
623
|
+
/*
|
624
|
+
Method: Pixel#to_hsla()
|
625
|
+
Purpose: Replace brain-dead to_HSL, above.
|
626
|
+
Notes: Returns [hue, saturation, lightness, alpha] in the same ranges as from_hsla()
|
627
|
+
*/
|
628
|
+
VALUE
|
629
|
+
Pixel_to_hsla(VALUE self)
|
630
|
+
{
|
631
|
+
double hue, sat, lum, alpha;
|
632
|
+
Pixel *pixel;
|
633
|
+
volatile VALUE hsla;
|
634
|
+
|
635
|
+
Data_Get_Struct(self, Pixel, pixel);
|
636
|
+
|
637
|
+
#if defined(HAVE_CONVERTRGBTOHSL)
|
638
|
+
ConvertRGBToHSL(pixel->red, pixel->green, pixel->blue, &hue, &sat, &lum);
|
639
|
+
#else
|
640
|
+
TransformHSL(pixel->red, pixel->green, pixel->blue, &hue, &sat, &lum);
|
641
|
+
#endif
|
642
|
+
hue *= 360.0;
|
643
|
+
sat *= 100.0;
|
644
|
+
lum *= 100.0;
|
645
|
+
|
646
|
+
if (pixel->opacity == OpaqueOpacity)
|
647
|
+
{
|
648
|
+
alpha = 1.0;
|
649
|
+
}
|
650
|
+
else if (pixel->opacity == TransparentOpacity)
|
651
|
+
{
|
652
|
+
alpha = 0.0;
|
653
|
+
}
|
654
|
+
else
|
655
|
+
{
|
656
|
+
alpha = ROUND_TO_QUANTUM(QuantumRange - (pixel->opacity / QuantumRange));
|
657
|
+
}
|
658
|
+
|
659
|
+
hsla = rb_ary_new3(4, rb_float_new(hue), rb_float_new(sat), rb_float_new(lum), rb_float_new(alpha));
|
660
|
+
return hsla;
|
661
|
+
}
|
662
|
+
|
663
|
+
/*
|
664
|
+
Method: Pixel#to_HSL *** DEPRECATED ***
|
665
|
+
Purpose: Converts an RGB pixel to the array
|
666
|
+
[hue, saturation, luminosity].
|
667
|
+
*/
|
668
|
+
VALUE
|
669
|
+
Pixel_to_HSL(VALUE self)
|
670
|
+
{
|
671
|
+
Pixel *pixel;
|
672
|
+
double hue, saturation, luminosity;
|
673
|
+
volatile VALUE hsl;
|
674
|
+
|
675
|
+
Data_Get_Struct(self, Pixel, pixel);
|
676
|
+
#if defined(HAVE_CONVERTRGBTOHSL)
|
677
|
+
rb_warning("Pixel#to_HSL is deprecated; use to_hsla");
|
678
|
+
ConvertRGBToHSL(pixel->red, pixel->green, pixel->blue, &hue, &saturation, &luminosity);
|
679
|
+
#else
|
680
|
+
TransformHSL(pixel->red, pixel->green, pixel->blue, &hue, &saturation, &luminosity);
|
681
|
+
#endif
|
682
|
+
|
683
|
+
hsl = rb_ary_new3(3, rb_float_new(hue), rb_float_new(saturation),
|
684
|
+
rb_float_new(luminosity));
|
685
|
+
|
686
|
+
return hsl;
|
687
|
+
}
|
688
|
+
|
689
|
+
|
690
|
+
/*
|
691
|
+
Method: Magick::Pixel#to_color(compliance=AllCompliance, matte=false,
|
692
|
+
depth=QuantumDepth, hex=false)
|
693
|
+
Purpose: return the color name corresponding to the pixel values
|
694
|
+
Notes: the conversion respects the value of the 'opacity' field
|
695
|
+
in the Pixel.
|
696
|
+
*/
|
697
|
+
VALUE
|
698
|
+
Pixel_to_color(int argc, VALUE *argv, VALUE self)
|
699
|
+
{
|
700
|
+
Info *info;
|
701
|
+
Image *image;
|
702
|
+
Pixel *pixel;
|
703
|
+
MagickPixelPacket mpp;
|
704
|
+
MagickBooleanType hex = MagickFalse;
|
705
|
+
char name[MaxTextExtent];
|
706
|
+
ExceptionInfo exception;
|
707
|
+
ComplianceType compliance = AllCompliance;
|
708
|
+
unsigned int matte = MagickFalse;
|
709
|
+
unsigned int depth = QuantumDepth;
|
710
|
+
|
711
|
+
switch (argc)
|
712
|
+
{
|
713
|
+
case 4:
|
714
|
+
hex = RTEST(argv[3]);
|
715
|
+
case 3:
|
716
|
+
depth = NUM2UINT(argv[2]);
|
717
|
+
|
718
|
+
// Ensure depth is appropriate for the way xMagick was compiled.
|
719
|
+
switch (depth)
|
720
|
+
{
|
721
|
+
case 8:
|
722
|
+
#if QuantumDepth == 16 || QuantumDepth == 32
|
723
|
+
case 16:
|
724
|
+
#endif
|
725
|
+
#if QuantumDepth == 32
|
726
|
+
case 32:
|
727
|
+
#endif
|
728
|
+
break;
|
729
|
+
default:
|
730
|
+
rb_raise(rb_eArgError, "invalid depth (%d)", depth);
|
731
|
+
break;
|
732
|
+
}
|
733
|
+
case 2:
|
734
|
+
matte = RTEST(argv[1]);
|
735
|
+
case 1:
|
736
|
+
VALUE_TO_ENUM(argv[0], compliance, ComplianceType);
|
737
|
+
case 0:
|
738
|
+
break;
|
739
|
+
default:
|
740
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 2)", argc);
|
741
|
+
}
|
742
|
+
|
743
|
+
Data_Get_Struct(self, Pixel, pixel);
|
744
|
+
|
745
|
+
info = CloneImageInfo(NULL);
|
746
|
+
image = AcquireImage(info);
|
747
|
+
image->depth = depth;
|
748
|
+
image->matte = matte;
|
749
|
+
(void) DestroyImageInfo(info);
|
750
|
+
|
751
|
+
GetMagickPixelPacket(image, &mpp);
|
752
|
+
rm_set_magick_pixel_packet(pixel, NULL, &mpp);
|
753
|
+
|
754
|
+
GetExceptionInfo(&exception);
|
755
|
+
|
756
|
+
#if defined(HAVE_NEW_QUERYMAGICKCOLORNAME)
|
757
|
+
// Support for hex-format color names moved out of QueryMagickColorname
|
758
|
+
// in 6.4.1-9. The 'hex' argument was removed as well.
|
759
|
+
if (hex)
|
760
|
+
{
|
761
|
+
if (compliance == XPMCompliance)
|
762
|
+
{
|
763
|
+
mpp.matte = MagickFalse;
|
764
|
+
mpp.depth = (unsigned long) min(1.0 * image->depth, 16.0);
|
765
|
+
}
|
766
|
+
(void) GetColorTuple(&mpp, MagickTrue, name);
|
767
|
+
}
|
768
|
+
else
|
769
|
+
{
|
770
|
+
(void) QueryMagickColorname(image, &mpp, compliance, name, &exception);
|
771
|
+
}
|
772
|
+
#else
|
773
|
+
(void) QueryMagickColorname(image, &mpp, compliance, hex, name, &exception);
|
774
|
+
#endif
|
775
|
+
(void) DestroyImage(image);
|
776
|
+
CHECK_EXCEPTION()
|
777
|
+
(void) DestroyExceptionInfo(&exception);
|
778
|
+
|
779
|
+
// Always return a string, even if it's ""
|
780
|
+
return rb_str_new2(name);
|
781
|
+
}
|
782
|
+
|
783
|
+
|
784
|
+
/*
|
785
|
+
Method: Magick::Pixel#to_s
|
786
|
+
Purpose: Create a string representation of a Magick::Pixel
|
787
|
+
*/
|
788
|
+
VALUE
|
789
|
+
Pixel_to_s(VALUE self)
|
790
|
+
{
|
791
|
+
Pixel *pixel;
|
792
|
+
char buff[100];
|
793
|
+
|
794
|
+
Data_Get_Struct(self, Pixel, pixel);
|
795
|
+
sprintf(buff, "red=" QuantumFormat ", green=" QuantumFormat ", blue=" QuantumFormat ", opacity=" QuantumFormat
|
796
|
+
, pixel->red, pixel->green, pixel->blue, pixel->opacity);
|
797
|
+
return rb_str_new2(buff);
|
798
|
+
}
|
799
|
+
|
800
|
+
|
801
|
+
/*
|
802
|
+
Static: rm_set_magick_pixel_packet
|
803
|
+
Purpose: Convert a PixelPacket to a MagickPixelPacket
|
804
|
+
Notes: Same code as the private function SetMagickPixelPacket
|
805
|
+
in ImageMagick.
|
806
|
+
*/
|
807
|
+
void
|
808
|
+
rm_set_magick_pixel_packet(Pixel *pixel, IndexPacket *index_packet, MagickPixelPacket *pp)
|
809
|
+
{
|
810
|
+
pp->red = (MagickRealType) pixel->red;
|
811
|
+
pp->green = (MagickRealType) pixel->green;
|
812
|
+
pp->blue = (MagickRealType) pixel->blue;
|
813
|
+
pp->opacity = (MagickRealType) (pp->matte ? pixel->opacity : OpaqueOpacity);
|
814
|
+
pp->index = (MagickRealType) ((pp->colorspace == CMYKColorspace) && (index_packet ? *index_packet : 0));
|
815
|
+
}
|
816
|
+
|