1 /*
2 % Copyright (C) 2003 - 2018 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 % Copyright (C) 1991-1999 E. I. du Pont de Nemours and Company
5 %
6 % This program is covered by multiple licenses, which are described in
7 % Copyright.txt. You should have received a copy of Copyright.txt with this
8 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9 %
10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 %                                                                             %
12 %                                                                             %
13 %                         PPPP   EEEEE  RRRR   L                              %
14 %                         P   P  E      R   R  L                              %
15 %                         PPPP   EEE    RRRR   L                              %
16 %                         P      E      R  R   L                              %
17 %                         P      EEEEE  R   R  LLLLL                          %
18 %                                                                             %
19 %                  M   M   AAA    GGGG  IIIII   CCCC  K   K                   %
20 %                  MM MM  A   A  G        I    C      K  K                    %
21 %                  M M M  AAAAA  G GGG    I    C      KKK                     %
22 %                  M   M  A   A  G   G    I    C      K  K                    %
23 %                  M   M  A   A   GGGG  IIIII   CCCC  K   K                   %
24 %                                                                             %
25 %                                                                             %
26 %              Object-oriented Perl interface to GraphicsMagick               %
27 %                                                                             %
28 %                                                                             %
29 %                            Software Design                                  %
30 %                              Kyle Shorter                                   %
31 %                              John Cristy                                    %
32 %                             February 1997                                   %
33 %                                                                             %
34 %                                                                             %
35 %                                                                             %
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 %
38 % PerlMagick is an objected-oriented Perl interface to GraphicsMagick.  Use
39 % the module to read, manipulate, or write an image or image sequence from
40 % within a Perl script.  This makes PerlMagick suitable for Web CGI scripts.
41 %
42 */
43 
44 /*
45   Include declarations.
46 */
47 #define MAGICK_IMPLEMENTATION 1
48 #if !defined(WIN32)
49 #define MagickExport
50 #endif
51 
52 #ifdef __cplusplus
53 extern "C" {
54 #endif
55 #define PERL_NO_GET_CONTEXT  /* faster */
56 #include "EXTERN.h"
57 #include "perl.h"
58 #include "XSUB.h"
59 #include <math.h>
60 #define MAGICK_IMPLEMENTATION 1
61 #include <magick/api.h>
62 #include <magick/locale_c.h>
63 #undef tainted
64 #if !defined(WIN32)
65 #include <setjmp.h>
66 #else
67 #undef setjmp
68 #undef longjmp
69 #include <setjmpex.h>
70 #endif
71 
72 #ifdef __cplusplus
73 }
74 #endif
75 
76 /*
77   Define declarations.
78 */
79 #define ArrayReference  (char **) 4
80 #ifndef aTHX_
81 #define aTHX_
82 #define pTHX_
83 #define dTHX
84 #endif
85 #define DegreesToRadians(x) ((x)*3.14159265358979323846/180.0)
86 #define DoubleReference  (char **) 2
87 #define EndOf(array)  (&array[NumberOf(array)])
88 #define False  0
89 #define NullReference  (char **) 0
90 #define ImageReference  (char **) 3
91 #define IntegerReference  (char **) 1
92 #define MaxArguments  28
93 #define MY_CXT_KEY  PackageName "::ContextKey_" XS_VERSION
94 #ifndef START_MY_CXT
95 #define MY_CXT_INIT
96 #define MY_CXT  my_cxt
97 #define dMY_CXT
98 #endif
99 #ifndef na
100 #define na  PL_na
101 #endif
102 #define NumberOf(array)  (sizeof(array)/sizeof(*array))
103 #define PackageName   "Graphics::Magick"
104 #ifndef PerlIO_findFILE
105 #define PerlIO_findFILE(f)  (FILE *) (f)
106 #endif
107 #define StringReference  (char **) 0
108 #ifndef sv_undef
109 #define sv_undef  PL_sv_undef
110 #endif
111 #define True  1
112 
113 /*
114   Typedef and structure declarations.
115 */
116 typedef struct _Arguments
117 {
118   char
119     *method,
120     **type;
121 } Arguments;
122 
123 struct ArgumentList
124 {
125   long
126     int_reference;
127 
128   double
129     double_reference;
130 
131   char
132     *string_reference;
133 
134   Image
135     *image_reference;
136 
137   SV
138     *array_reference;
139 
140   size_t
141     length;
142 };
143 
144 typedef struct _my_cxt_t
145 {
146   jmp_buf
147     *error_jump;  /* long jump return for FATAL errors */
148 
149   SV
150     *error_list;  /* Perl variable for storing messages */
151 } my_cxt_t;
152 
153 struct PackageInfo
154 {
155   ImageInfo
156     *image_info;
157 
158   DrawInfo
159     *draw_info;
160 
161   QuantizeInfo
162     *quantize_info;
163 };
164 
165 typedef void
166   *Graphics__Magick;  /* data type for the Graphics::Magick package */
167 
168 /*
169   Static declarations.  The strings in this list must be expressed
170   in the exact same order as the equivalent enumeration.
171 */
172 static char
173   *AlignTypes[] =
174   {
175     "Undefined", "Left", "Center", "Right", (char *) NULL
176   },
177   *BooleanTypes[] =
178   {
179     "False", "True", (char *) NULL
180   },
181   *ChannelTypes[] =
182   {
183     "Undefined", "Red", "Cyan", "Green", "Magenta", "Blue", "Yellow",
184     "Opacity", "Black", "Matte", "All", "Gray", (char *) NULL
185   },
186   *ClassTypes[] =
187   {
188     "Undefined", "DirectClass", "PseudoClass", (char *) NULL
189   },
190   *ColorspaceTypes[] =
191   {
192     "Undefined", "RGB", "Gray", "Transparent", "OHTA", "XYZ", "YCC",
193     "YIQ", "YPbPr", "YUV", "CMYK", "sRGB", "HSL", "HWB", "LAB",  "CineonLog",
194     "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", (char *) NULL
195   },
196   *CompositeTypes[] =
197   {
198     "Undefined", "Over", "In", "Out", "Atop", "Xor", "Plus", "Minus",
199     "Add", "Subtract", "Difference", "Multiply", "Bumpmap", "Copy",
200     "CopyRed", "CopyGreen", "CopyBlue", "CopyOpacity", "Clear", "Dissolve",
201     "Displace", "Modulate", "Threshold", "No", "Darken", "Lighten",
202     "Hue", "Saturate", "Colorize", "Luminize", "Screen", "Overlay",
203     "CopyCyan", "CopyMagenta", "CopyYellow", "CopyBlack", "Divide",
204     "HardLight", "Exclusion", "ColorDodge", "ColorBurn", "SoftLight",
205     "LinearBurn", "LinearDodge", "LinearLight", "VividLight", "PinLight",
206     "HardMix",
207     (char *) NULL
208   },
209   *CompressionTypes[] =
210   {
211     "Undefined", "None", "BZip", "Fax", "Group4", "JPEG", "LosslessJPEG",
212     "LZW", "RLE", "Zip", "LZMA", "JPEG2000", "JBIG1", "JBIG2", "ZSTD",
213     "WebP",
214     (char *) NULL
215   },
216   *DecorationTypes[] =
217   {
218     "None", "Underline", "Overline", "LineThrough",
219     (char *) NULL
220   },
221   *DisposeTypes[] =
222   {
223     "Undefined", "None", "Background", "Previous", (char *) NULL
224   },
225   *EndianTypes[] =
226   {
227     "Undefined", "LSB", "MSB", "Native", (char *) NULL
228   },
229   *FilterTypess[] =
230   {
231     "Undefined", "Point", "Box", "Triangle", "Hermite", "Hanning",
232     "Hamming", "Blackman", "Gaussian", "Quadratic", "Cubic", "Catrom",
233     "Mitchell", "Lanczos", "Bessel", "Sinc", (char *) NULL
234   },
235   *GravityTypes[] =
236   {
237     "Forget", "NorthWest", "North", "NorthEast", "West", "Center",
238     "East", "SouthWest", "South", "SouthEast", "Static", (char *) NULL
239   },
240   *ImageTypes[] =
241   {
242     "Undefined", "Bilevel", "Grayscale", "GrayscaleMatte", "Palette",
243     "PaletteMatte", "TrueColor", "TrueColorMatte", "ColorSeparation",
244     "ColorSeparationMatte", "Optimize", (char *) NULL
245   },
246   *IntentTypes[] =
247   {
248     "Undefined", "Saturation", "Perceptual", "Absolute", "Relative",
249     (char *) NULL
250   },
251   *InterlaceTypes[] =
252   {
253     "Undefined", "None", "Line", "Plane", "Partition", (char *) NULL
254   },
255   *LogEventTypes[] =
256   {
257     "No", "Configure", "Annotate", "Render", "Transform", "Locale",
258     "Coder", "X11", "Cache", "Blob", "Deprecate", "User", "Resource",
259     "TemporaryFile", "Exception", "All", (char *) NULL
260   },
261   *MethodTypes[] =
262   {
263     "Point", "Replace", "Floodfill", "FillToBorder", "Reset", (char *) NULL
264   },
265   *ModeTypes[] =
266   {
267     "Undefined", "Frame", "Unframe", "Concatenate", (char *) NULL
268   },
269   *NoiseTypes[] =
270   {
271     "Uniform", "Gaussian", "Multiplicative", "Impulse", "Laplacian",
272     "Poisson", "Random", (char *) NULL
273   },
274   *PreviewTypes[] =
275   {
276     "Undefined", "Rotate", "Shear", "Roll", "Hue", "Saturation",
277     "Brightness", "Gamma", "Spiff", "Dull", "Grayscale", "Quantize",
278     "Despeckle", "ReduceNoise", "AddNoise", "Sharpen", "Blur",
279     "Threshold", "EdgeDetect", "Spread", "Solarize", "Shade", "Raise",
280     "Segment", "Swirl", "Implode", "Wave", "OilPaint", "Charcoal",
281     "JPEG", (char *) NULL
282   },
283   *PrimitiveTypes[] =
284   {
285     "Undefined", "point", "line", "rectangle", "roundRectangle", "arc",
286     "ellipse", "circle", "polyline", "polygon", "bezier", "path", "color",
287     "matte", "text", "image", (char *) NULL
288   },
289   *ResolutionTypes[] =
290   {
291     "Undefined", "PixelsPerInch", "PixelsPerCentimeter", (char *) NULL
292   },
293   *StretchTypes[] =
294   {
295     "Normal", "UltraCondensed", "ExtraCondensed", "Condensed",
296     "SemiCondensed", "SemiExpanded", "Expanded", "ExtraExpanded",
297     "UltraExpanded", "Any", (char *) NULL
298   },
299   *StyleTypes[] =
300   {
301     "Normal", "Italic", "Oblique", "Any", (char *) NULL
302   },
303   *VirtualPixelMethods[] =
304   {
305     "Undefined", "", "Constant", "Edge", "Mirror", "Tile",
306     (char *) NULL
307   };
308 
309 static struct
310   Methods
311   {
312     char
313       *name;
314 
315     Arguments
316       arguments[MaxArguments];
317   } Methods[] =
318   {
319     { "comment", { {"comment", StringReference} } },
320     { "label", { {"label", StringReference} } },
321     { "AddNoise", { {"noise", NoiseTypes} } },
322     { "Colorize", { {"fill", StringReference}, {"opacity", StringReference} } },
323     { "Border", { {"geometry", StringReference}, {"width", IntegerReference},
324       {"height", IntegerReference}, {"fill", StringReference},
325       {"color", StringReference} } },
326     { "Blur", { {"geometry", StringReference}, {"radius", DoubleReference},
327       {"sigma", DoubleReference} } },
328     { "Chop", { {"geometry", StringReference}, {"width", IntegerReference},
329       {"height", IntegerReference}, {"x", IntegerReference},
330       {"y", IntegerReference} } },
331     { "Crop", { {"geometry", StringReference}, {"width", IntegerReference},
332       {"height", IntegerReference}, {"x", IntegerReference},
333       {"y", IntegerReference} } },
334     { "Despeckle", { { NULL, NullReference } } },
335     { "Edge", { {"radius", DoubleReference} } },
336     { "Emboss", { {"geometry", StringReference}, {"radius", DoubleReference},
337       {"sigma", DoubleReference} } },
338     { "Enhance", { { NULL, NullReference } } },
339     { "Flip", { { NULL, NullReference } } },
340     { "Flop", { { NULL, NullReference } } },
341     { "Frame", { {"geometry", StringReference}, {"width", IntegerReference},
342       {"height", IntegerReference}, {"inner", IntegerReference},
343       {"outer", IntegerReference}, {"fill", StringReference},
344       {"color", StringReference} } },
345     { "Implode", { {"amount", DoubleReference} } },
346     { "Magnify", { { NULL, NullReference } } },
347     { "MedianFilter", { {"radius", DoubleReference} } },
348     { "Minify", { { NULL, NullReference } } },
349     { "OilPaint", { {"radius", DoubleReference} } },
350     { "ReduceNoise", { {"radius", DoubleReference} } },
351     { "Roll", { {"geometry", StringReference}, {"x", IntegerReference},
352       {"y", IntegerReference} } },
353     { "Rotate", { {"degrees", DoubleReference},
354       {"color", StringReference} } },
355     { "Sample", { {"geometry", StringReference}, {"width", IntegerReference},
356       {"height", IntegerReference} } },
357     { "Scale", { {"geometry", StringReference}, {"width", IntegerReference},
358       {"height", IntegerReference} } },
359     { "Shade", { {"geometry", StringReference}, {"azimuth", DoubleReference},
360       {"elevation", DoubleReference}, {"gray", BooleanTypes} } },
361     { "Sharpen", { {"geometry", StringReference}, {"radius", DoubleReference},
362       {"sigma", DoubleReference} } },
363     { "Shear", { {"geometry", StringReference}, {"x", IntegerReference},
364       {"y", DoubleReference}, {"color", StringReference} } },
365     { "Spread", { {"radius", IntegerReference} } },
366     { "Swirl", { {"degrees", DoubleReference} } },
367     { "Resize", { {"geometry", StringReference}, {"width", IntegerReference},
368       {"height", IntegerReference}, {"filter", FilterTypess},
369       {"blur", DoubleReference } } },
370     { "Zoom", { {"geometry", StringReference}, {"width", IntegerReference},
371       {"height", IntegerReference}, {"filter", FilterTypess},
372       {"blur", DoubleReference } } },
373     { "Annotate", { {"text", StringReference}, {"font", StringReference},
374       {"point", DoubleReference}, {"density", StringReference},
375       {"undercolor", StringReference}, {"stroke", StringReference},
376       {"fill", StringReference}, {"geometry", StringReference},
377       {"sans", StringReference}, {"x", IntegerReference},
378       {"y", IntegerReference}, {"gravity", GravityTypes},
379       {"translate", StringReference}, {"scale", StringReference},
380       {"rotate", DoubleReference}, {"skewX", DoubleReference},
381       {"skewY", DoubleReference}, {"strokewidth", IntegerReference},
382       {"antialias", BooleanTypes}, {"family", StringReference},
383       {"style", StyleTypes}, {"stretch", StretchTypes},
384       {"weight", IntegerReference}, {"align", AlignTypes},
385       {"encoding", StringReference}, {"affine", ArrayReference},
386       {"decorate", DecorationTypes}} },
387     { "ColorFloodfill", { {"geometry", StringReference},
388       {"x", IntegerReference}, {"y", IntegerReference},
389       {"fill", StringReference}, {"bordercolor", StringReference},
390       {"fuzz", DoubleReference} } },
391     { "Composite", { {"image", ImageReference}, {"compose", CompositeTypes},
392       {"geometry", StringReference}, {"x", IntegerReference},
393       {"y", IntegerReference}, {"gravity", GravityTypes},
394       {"opacity", DoubleReference}, {"tile", BooleanTypes},
395       {"rotate", DoubleReference}, {"color", StringReference},
396       {"mask", ImageReference} } },
397     { "Contrast", { {"sharp", BooleanTypes} } },
398     { "CycleColormap", { {"display", IntegerReference} } },
399     { "Draw", { {"primitive", PrimitiveTypes}, {"points", StringReference},
400       {"method", MethodTypes}, {"stroke", StringReference},
401       {"fill", StringReference}, {"strokewidth", DoubleReference},
402       {"font", StringReference}, {"bordercolor", StringReference},
403       {"x", DoubleReference}, {"y", DoubleReference},
404       {"translate", StringReference}, {"scale", StringReference},
405       {"rotate", DoubleReference}, {"skewX", DoubleReference},
406       {"skewY", DoubleReference}, {"tile", ImageReference},
407       {"pointsize", DoubleReference}, {"antialias", BooleanTypes},
408       {"density", StringReference}, {"linewidth", DoubleReference},
409       {"affine", ArrayReference} } },
410     { "Equalize", { { NULL, NullReference } } },
411     { "Gamma", { {"gamma", StringReference}, {"red", DoubleReference},
412       {"green", DoubleReference}, {"blue", DoubleReference} } },
413     { "Map", { {"image", ImageReference}, {"dither", BooleanTypes} } },
414     { "MatteFloodfill", { {"geometry", StringReference},
415       {"x", IntegerReference}, {"y", IntegerReference},
416       {"opacity", IntegerReference}, {"bordercolor", StringReference},
417       {"fuzz", DoubleReference} } },
418     { "Modulate", { {"factor", StringReference}, {"bright", DoubleReference},
419       {"saturation", DoubleReference}, {"hue", DoubleReference} } },
420     { "Negate", { {"gray", BooleanTypes} } },
421     { "Normalize", { { NULL, NullReference } } },
422     { "NumberColors", { { NULL, NullReference } } },
423     { "Opaque", { {"color", StringReference}, {"fill", StringReference},
424       {"fuzz", DoubleReference} } },
425     { "Quantize", { {"colors", IntegerReference}, {"tree", IntegerReference},
426       {"colorspace", ColorspaceTypes}, {"dither", BooleanTypes},
427       {"measure", BooleanTypes}, {"global", BooleanTypes} } },
428     { "Raise", { {"geometry", StringReference}, {"width", IntegerReference},
429       {"height", IntegerReference}, {"raise", BooleanTypes} } },
430     { "Segment", { {"geometry", StringReference}, {"cluster", DoubleReference},
431       {"smooth", DoubleReference}, {"colorspace", ColorspaceTypes},
432       {"verbose", BooleanTypes} } },
433     { "Signature", { { NULL, NullReference } } },
434     { "Solarize", { {"threshold", DoubleReference} } },
435     { "Sync", { { NULL, NullReference } } },
436     { "Texture", { {"texture", ImageReference} } },
437     { "Sans", { {"geometry", StringReference}, {"crop", StringReference},
438       {"filter", FilterTypess} } },
439     { "Transparent", { {"color", StringReference},
440       {"opacity", IntegerReference}, {"fuzz", DoubleReference} } },
441     { "Threshold", { {"threshold", StringReference} } },
442     { "Charcoal", { {"geometry", StringReference}, {"radius", DoubleReference},
443       {"sigma", DoubleReference} } },
444     { "Trim", { {"fuzz", DoubleReference} } },
445     { "Wave", { {"geometry", StringReference}, {"amplitude", DoubleReference},
446       {"wavelength", DoubleReference} } },
447     { "Channel", { {"channel", ChannelTypes} } },
448     { "Condense", { { NULL, NullReference } } },
449     { "Stereo", { {"image", ImageReference} } },
450     { "Stegano", { {"image", ImageReference}, {"offset", IntegerReference} } },
451     { "Deconstruct", { { NULL, NullReference } } },
452     { "GaussianBlur", { {"geometry", StringReference},
453       {"radius", DoubleReference}, {"sigma", DoubleReference} } },
454     { "Convolve", { {"coefficients", ArrayReference} } },
455     { "Profile", { {"name", StringReference}, {"profile", StringReference} } },
456     { "UnsharpMask", { {"geometry", StringReference},
457       {"radius", DoubleReference}, {"sigma", DoubleReference},
458       {"amount", DoubleReference}, {"threshold", DoubleReference} } },
459     { "MotionBlur", { {"geometry", StringReference},
460       {"radius", DoubleReference}, {"sigma", DoubleReference},
461       {"angle", DoubleReference} } },
462     { "OrderedDither", { { NULL, NullReference } } },
463     { "Shave", { {"geometry", StringReference}, {"width", IntegerReference},
464       {"height", IntegerReference} } },
465     { "Level", { {"level", StringReference}, {"black-point", DoubleReference},
466       {"mid-point", DoubleReference}, {"white-point", DoubleReference} } },
467     { "Clip", { { NULL, NullReference } } },
468     { "AffineTransform", { {"affine", ArrayReference},
469       {"translate", StringReference}, {"scale", StringReference},
470       {"rotate", DoubleReference}, {"skewX", DoubleReference},
471       {"skewY", DoubleReference} } },
472     { "Compare", { {"image", ImageReference} } },
473     { "AdaptiveThreshold", { {"geometry", StringReference},
474       {"width", IntegerReference}, {"height", IntegerReference},
475       {"offset", IntegerReference} } },
476   };
477 
478 #ifdef START_MY_CXT
479   START_MY_CXT
480 #else
481   static my_cxt_t
482     my_cxt = { (jmp_buf *) NULL, (SV *) NULL };
483 #endif
484 
485 /*
486   Forward declarations.
487 */
488 static Image
489   *SetupList(pTHX_ SV *,struct PackageInfo **,SV ***);
490 
491 static int
492   strEQcase(const char *,const char *);
493 
494 /*
495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496 %                                                                             %
497 %                                                                             %
498 %                                                                             %
499 %   C l o n e P a c k a g e I n f o                                           %
500 %                                                                             %
501 %                                                                             %
502 %                                                                             %
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 %
505 %  Method ClonePackageInfo makes a duplicate of the given info, or if info is
506 %  NULL, a new one.
507 %
508 %  The format of the ClonePackageInfo routine is:
509 %
510 %      struct PackageInfo *ClonePackageInfo(struct PackageInfo *info)
511 %
512 %  A description of each parameter follows:
513 %
514 %    o clone_info: Method ClonePackageInfo returns a duplicate of the given
515 %      info, or if info is NULL, a new one.
516 %
517 %    o info: a structure of type info.
518 %
519 %
520 */
ClonePackageInfo(struct PackageInfo * info)521 static struct PackageInfo *ClonePackageInfo(struct PackageInfo *info)
522 {
523   struct PackageInfo
524     *clone_info;
525 
526   clone_info=MagickAllocateMemory(struct PackageInfo *,sizeof(struct PackageInfo));
527   if (!info)
528     {
529       clone_info->image_info=CloneImageInfo((ImageInfo *) NULL);
530       clone_info->draw_info=
531         CloneDrawInfo(clone_info->image_info,(DrawInfo *) NULL);
532       clone_info->quantize_info=CloneQuantizeInfo((QuantizeInfo *) NULL);
533       return(clone_info);
534     }
535   *clone_info=(*info);
536   clone_info->image_info=CloneImageInfo(info->image_info);
537   clone_info->draw_info=CloneDrawInfo(info->image_info,info->draw_info);
538   clone_info->quantize_info=CloneQuantizeInfo(info->quantize_info);
539   return(clone_info);
540 }
541 
542 /*
543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
544 %                                                                             %
545 %                                                                             %
546 %                                                                             %
547 %   c o n s t a n t                                                           %
548 %                                                                             %
549 %                                                                             %
550 %                                                                             %
551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
552 %
553 %  Method constant returns a double value for the specified name.
554 %
555 %  The format of the constant routine is:
556 %
557 %      double constant(char *name,int sans)
558 %
559 %  A description of each parameter follows:
560 %
561 %    o value: Method constant returns a double value for the specified name.
562 %
563 %    o name: The name of the constant.
564 %
565 %    o sans: This integer value is not used.
566 %
567 %
568 */
constant(char * name,int sans)569 static double constant(char *name,int sans)
570 {
571   (void) sans;
572 
573   errno=0;
574   switch (*name)
575   {
576     case 'B':
577     {
578       if (strEQ(name,"BlobError"))
579         return(BlobError);
580       if (strEQ(name,"BlobWarning"))
581         return(BlobWarning);
582       break;
583     }
584     case 'C':
585     {
586       if (strEQ(name,"CacheError"))
587         return(CacheError);
588       if (strEQ(name,"CacheWarning"))
589         return(CacheWarning);
590       if (strEQ(name,"CoderError"))
591         return(CoderError);
592       if (strEQ(name,"CoderWarning"))
593         return(CoderWarning);
594       if (strEQ(name,"ConfigureError"))
595         return(ConfigureError);
596       if (strEQ(name,"ConfigureWarning"))
597         return(ConfigureWarning);
598       if (strEQ(name,"CorruptImageError"))
599         return(CorruptImageError);
600       if (strEQ(name,"CorruptImageWarning"))
601         return(CorruptImageWarning);
602       break;
603     }
604     case 'D':
605     {
606       if (strEQ(name,"DelegateError"))
607         return(DelegateError);
608       if (strEQ(name,"DelegateWarning"))
609         return(DelegateWarning);
610       if (strEQ(name,"DrawError"))
611         return(DrawError);
612       if (strEQ(name,"DrawWarning"))
613         return(DrawWarning);
614       break;
615     }
616     case 'E':
617     {
618       if (strEQ(name,"ErrorException"))
619         return(ErrorException);
620       break;
621     }
622     case 'F':
623     {
624       if (strEQ(name,"FatalErrorException"))
625         return(FatalErrorException);
626       if (strEQ(name,"FileOpenError"))
627         return(FileOpenError);
628       if (strEQ(name,"FileOpenWarning"))
629         return(FileOpenWarning);
630       break;
631     }
632     case 'I':
633     {
634       if (strEQ(name,"ImageError"))
635         return(ImageError);
636       if (strEQ(name,"ImageWarning"))
637         return(ImageWarning);
638       break;
639     }
640     case 'M':
641     {
642       if (strEQ(name,"MaxRGB"))
643         return(MaxRGB);
644       if (strEQ(name,"MissingDelegateError"))
645         return(MissingDelegateError);
646       if (strEQ(name,"MissingDelegateWarning"))
647         return(MissingDelegateWarning);
648       if (strEQ(name,"ModuleError"))
649         return(ModuleError);
650       if (strEQ(name,"ModuleWarning"))
651         return(ModuleWarning);
652       break;
653     }
654     case 'O':
655     {
656       if (strEQ(name,"Opaque"))
657         return(OpaqueOpacity);
658       if (strEQ(name,"OptionError"))
659         return(OptionError);
660       if (strEQ(name,"OptionWarning"))
661         return(OptionWarning);
662       break;
663     }
664     case 'R':
665     {
666       if (strEQ(name,"ResourceLimitError"))
667         return(ResourceLimitError);
668       if (strEQ(name,"ResourceLimitWarning"))
669         return(ResourceLimitWarning);
670       if (strEQ(name,"RegistryError"))
671         return(RegistryError);
672       if (strEQ(name,"RegistryWarning"))
673         return(RegistryWarning);
674       break;
675     }
676     case 'S':
677     {
678       if (strEQ(name,"StreamError"))
679         return(StreamError);
680       if (strEQ(name,"StreamWarning"))
681         return(StreamWarning);
682       if (strEQ(name,"Success"))
683         return(0);
684       break;
685     }
686     case 'T':
687     {
688       if (strEQ(name,"Transparent"))
689         return(TransparentOpacity);
690       if (strEQ(name,"TypeError"))
691         return(TypeError);
692       if (strEQ(name,"TypeWarning"))
693         return(TypeWarning);
694       break;
695     }
696     case 'W':
697     {
698       if (strEQ(name,"WarningException"))
699         return(WarningException);
700       break;
701     }
702     case 'X':
703     {
704       if (strEQ(name,"XServerError"))
705         return(XServerError);
706       if (strEQ(name,"XServerWarning"))
707         return(XServerWarning);
708       break;
709     }
710   }
711   errno=EINVAL;
712   return(0);
713 }
714 
715 /*
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 %                                                                             %
718 %                                                                             %
719 %                                                                             %
720 %   D e s t r o y P a c k a g e I n f o                                       %
721 %                                                                             %
722 %                                                                             %
723 %                                                                             %
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725 %
726 %  Method DestroyPackageInfo frees a previously created info structure.
727 %
728 %  The format of the DestroyPackageInfo routine is:
729 %
730 %      DestroyPackageInfo(struct PackageInfo *info)
731 %
732 %  A description of each parameter follows:
733 %
734 %    o info: a structure of type info.
735 %
736 %
737 */
DestroyPackageInfo(struct PackageInfo * info)738 static void DestroyPackageInfo(struct PackageInfo *info)
739 {
740   DestroyImageInfo(info->image_info);
741   DestroyDrawInfo(info->draw_info);
742   DestroyQuantizeInfo(info->quantize_info);
743   MagickFreeMemory(info);
744 }
745 
746 /*
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 %                                                                             %
749 %                                                                             %
750 %                                                                             %
751 %   G e t L i s t                                                             %
752 %                                                                             %
753 %                                                                             %
754 %                                                                             %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 %
757 %  Method GetList is recursively called by SetupList to traverse the
758 %  Graphics__Magick reference.  If building an reference_vector (see SetupList),
759 %  *current is the current position in *reference_vector and *last is the final
760 %  entry in *reference_vector.
761 %
762 %  The format of the GetList routine is:
763 %
764 %      GetList(info)
765 %
766 %  A description of each parameter follows:
767 %
768 %    o info: a structure of type info.
769 %
770 %
771 */
GetList(pTHX_ SV * reference,SV *** reference_vector,int * current,int * last)772 static Image *GetList(pTHX_ SV *reference,SV ***reference_vector,int *current,
773   int *last)
774 {
775   Image
776     *image;
777 
778   if (!reference)
779     return(NULL);
780   switch (SvTYPE(reference))
781   {
782     case SVt_PVAV:
783     {
784       AV
785         *av;
786 
787       Image
788         *head,
789         *previous;
790 
791       int
792         n;
793 
794       register int
795         i;
796 
797       /*
798         Array of images.
799       */
800       previous=(Image *) NULL;
801       head=(Image *) NULL;
802       av=(AV *) reference;
803       n=av_len(av);
804       for (i=0; i <= n; i++)
805       {
806         SV
807           **rv;
808 
809         rv=av_fetch(av,i,0);
810         if (rv && *rv && sv_isobject(*rv))
811           {
812             image=GetList(aTHX_ SvRV(*rv),reference_vector,current,last);
813             if (!image)
814               continue;
815             if (image == previous)
816               {
817                 ExceptionInfo
818                   exception;
819 
820                 GetExceptionInfo(&exception);
821                 image=CloneImage(image,0,0,True,&exception);
822                 if (exception.severity != UndefinedException)
823                   CatchException(&exception);
824                 DestroyExceptionInfo(&exception);
825                 if (image == (Image *) NULL)
826                   return(NULL);
827               }
828             image->previous=previous;
829             *(previous ? &previous->next : &head)=image;
830             for (previous=image; previous->next; previous=previous->next);
831           }
832       }
833       return(head);
834     }
835     case SVt_PVMG:
836     {
837       /*
838         Blessed scalar, one image.
839       */
840       image=(Image *) (magick_uintptr_t)SvIV(reference);
841       if (!image)
842         return(NULL);
843       image->previous=(Image *) NULL;
844       image->next=(Image *) NULL;
845       if (reference_vector)
846         {
847           if (*current == *last)
848             {
849               *last+=256;
850               if (*reference_vector)
851                 {
852                   MagickReallocMemory(SV **,*reference_vector,*last*sizeof(*reference_vector));
853                 }
854               else
855                 {
856                   *reference_vector=
857                     MagickAllocateMemory(SV **,*last*sizeof(*reference_vector));
858                 }
859             }
860           if (*reference_vector)
861             {
862               (*reference_vector)[*current]=reference;
863               (*reference_vector)[++(*current)]=NULL;
864             }
865       }
866       return(image);
867     }
868   }
869   (void) fprintf(stderr,"GetList: UnrecognizedType %ld\n",
870     (long) SvTYPE(reference));
871   return((Image *) NULL);
872 }
873 
874 /*
875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
876 %                                                                             %
877 %                                                                             %
878 %                                                                             %
879 %   G e t P a c k a g e I n f o                                               %
880 %                                                                             %
881 %                                                                             %
882 %                                                                             %
883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
884 %
885 %  Method GetPackageInfo looks up or creates an info structure for the given
886 %  Graphics__Magick reference.  If it does create a new one, the information in
887 %  package_info is used to initialize it.
888 %
889 %  The format of the GetPackageInfo routine is:
890 %
891 %      struct PackageInfo *GetPackageInfo(void *reference,
892 %        struct PackageInfo *package_info)
893 %
894 %  A description of each parameter follows:
895 %
896 %    o info: a structure of type info.
897 %
898 %
899 */
GetPackageInfo(pTHX_ void * reference,struct PackageInfo * package_info)900 static struct PackageInfo *GetPackageInfo(pTHX_ void *reference,
901   struct PackageInfo *package_info)
902 {
903   char
904     message[MaxTextExtent];
905 
906   struct PackageInfo
907     *clone_info;
908 
909   SV
910     *sv;
911 
912   FormatString(message,"%s::Ref%lx_%s",PackageName,(long) reference,
913    XS_VERSION);
914   sv=perl_get_sv(message,(TRUE | 0x02));
915   if (!sv)
916     {
917       MagickError(ResourceLimitError,UnableToGetPackageInfo,message);
918       return(package_info);
919     }
920   if (SvREFCNT(sv) == 0)
921     (void) SvREFCNT_inc(sv);
922   if (SvIOKp(sv) && (clone_info=(struct PackageInfo *) (magick_uintptr_t)SvIV(sv)))
923     return(clone_info);
924   clone_info=ClonePackageInfo(package_info);
925   sv_setiv(sv,(IV) (magick_uintptr_t)clone_info);
926   return(clone_info);
927 }
928 
929 /*
930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 %                                                                             %
932 %                                                                             %
933 %                                                                             %
934 %   L o o k u p S t r                                                         %
935 %                                                                             %
936 %                                                                             %
937 %                                                                             %
938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939 %
940 %  Method LookupStr searches through a list of strings matching it to string
941 %  and return its index in the list, or -1 for not found .
942 %
943 %  The format of the LookupStr routine is:
944 %
945 %      int LookupStr(char **list,const char *string)
946 %
947 %  A description of each parameter follows:
948 %
949 %    o status: Method LookupStr returns the index of string in the list
950 %      otherwise -1.
951 %
952 %    o list: a list of strings.
953 %
954 %    o string: a character string.
955 %
956 %
957 */
LookupStr(char ** list,const char * string)958 static int LookupStr(char **list,const char *string)
959 {
960   int
961     longest,
962     offset;
963 
964   register char
965     **p;
966 
967   offset=(-1);
968   longest=0;
969   for (p=list; *p; p++)
970     if (strEQcase(string,*p) > longest)
971       {
972         offset=p-list;
973         longest=strEQcase(string,*p);
974       }
975   return(offset);
976 }
977 
978 /*
979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 %                                                                             %
981 %                                                                             %
982 %                                                                             %
983 %   M a g i c k E r r o r H a n d l e r                                       %
984 %                                                                             %
985 %                                                                             %
986 %                                                                             %
987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 %
989 %  Method MagickErrorHandler replaces GraphicsMagick's fatal error handler.  This
990 %  stores the message in a Perl variable,and longjmp's to return the error to
991 %  Perl.  If the error_flag variable is set, it also calls the Perl warn
992 %  routine.  Note that this doesn't exit but returns control to Perl; the
993 %  Graphics::Magick handle may be left in a bad state.
994 %
995 %  The format of the MagickErrorHandler routine is:
996 %
997 %      MagickErrorHandler(const ExceptionType severity,const char *reason,
998 %        const char *qualifier)
999 %
1000 %  A description of each parameter follows:
1001 %
1002 %    o severity: The severity of the exception.
1003 %
1004 %    o reason: The reason of the exception.
1005 %
1006 %    o description: The exception description.
1007 %
1008 %
1009 */
MagickErrorHandler(const ExceptionType severity,const char * reason,const char * description)1010 static void MagickErrorHandler(const ExceptionType severity,const char *reason,
1011   const char *description)
1012 {
1013   char
1014     text[MaxTextExtent];
1015 
1016   dTHX;  /* perl context */
1017   dMY_CXT;
1018   errno=0;
1019   FormatString(text,"Exception %d: %.1024s%s%.1024s%s%s%.64s%s",severity,
1020     (reason ? GetLocaleExceptionMessage(severity,reason) : "ERROR"),
1021     description ? " (" : "",
1022     description ? GetLocaleExceptionMessage(severity,description) : "",
1023                 description ? ")" : "",errno ? " [" : "",errno ? strerror(errno) : "",
1024     errno? "]" : "");
1025   if ((MY_CXT.error_list == NULL) || (MY_CXT.error_jump == NULL))
1026     {
1027       /*
1028         Set up error buffer.
1029       */
1030       warn("%s",text);
1031       if (MY_CXT.error_jump == NULL)
1032         exit((int) severity % 100);
1033     }
1034   if (MY_CXT.error_list)
1035     {
1036       if (SvCUR(MY_CXT.error_list))
1037         sv_catpv(MY_CXT.error_list,"\n");
1038       sv_catpv(MY_CXT.error_list,text);
1039     }
1040   longjmp(*MY_CXT.error_jump,(int) severity);
1041 }
1042 
1043 /*
1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045 %                                                                             %
1046 %                                                                             %
1047 %                                                                             %
1048 %   M a g i c k W a r n i n g H a n d l e r                                   %
1049 %                                                                             %
1050 %                                                                             %
1051 %                                                                             %
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 %
1054 %  Method MagickWarningHandler replaces the GraphicsMagick warning handler.  This
1055 %  stores the (possibly multiple) reasons in a Perl variable for later
1056 %  returning.
1057 %
1058 %  The format of the MagickWarningHandler routine is:
1059 %
1060 %      MagickWarningHandler(const ExceptionType severity,const char *reason,
1061 %        const char *description)
1062 %
1063 %  A description of each parameter follows:
1064 %
1065 %    o severity: Specifies the numeric severity category.
1066 %
1067 %    o reason: The reason of the exception.
1068 %
1069 %    o description: Specifies any description to the reason.
1070 %
1071 %
1072 */
1073 
MagickWarningHandler(const ExceptionType severity,const char * reason,const char * description)1074 static void MagickWarningHandler(const ExceptionType severity,
1075   const char *reason,const char *description)
1076 {
1077   char
1078     text[MaxTextExtent];
1079 
1080   dTHX;  /* perl context */
1081   dMY_CXT;
1082   errno=0;
1083   if (!reason)
1084     return;
1085   FormatString(text,"Exception %d: %.1024s%s%.1024s%s%s%.64s%s",severity,
1086     (reason ? GetLocaleExceptionMessage(severity,reason) : "WARNING"),
1087     description ? " (" : "",
1088     description ? GetLocaleExceptionMessage(severity,description) : "",
1089     description ? ")" : "",errno ? " [" : "",errno ? strerror(errno) : "",
1090     errno? "]" : "");
1091   if (MY_CXT.error_list == NULL)
1092     {
1093       /*
1094         Set up reason buffer.
1095       */
1096       warn("%s",text);
1097       if (MY_CXT.error_list == NULL)
1098         return;
1099     }
1100   if (SvCUR(MY_CXT.error_list))
1101     sv_catpv(MY_CXT.error_list,"\n");  /* add \n separator between reasons */
1102   sv_catpv(MY_CXT.error_list,text);
1103 }
1104 
1105 /*
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107 %                                                                             %
1108 %                                                                             %
1109 %                                                                             %
1110 %   S e t A t t r i b u t e                                                   %
1111 %                                                                             %
1112 %                                                                             %
1113 %                                                                             %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 %
1116 %  Method SetAttribute sets the attribute to the value in sval.  This can
1117 %  change either or both of image or info.
1118 %
1119 %  The format of the SetAttribute routine is:
1120 %
1121 %      SetAttribute(struct PackageInfo *info,Image *image,char *attribute,
1122 %        SV *sval)
1123 %
1124 %  A description of each parameter follows:
1125 %
1126 %    o status: Method SetAttribute returns the index of string in the list
1127 %      otherwise -1.
1128 %
1129 %    o list: a list of strings.
1130 %
1131 %    o string: a character string.
1132 %
1133 %
1134 */
SetAttribute(pTHX_ struct PackageInfo * info,Image * image,char * attribute,SV * sval)1135 static void SetAttribute(pTHX_ struct PackageInfo *info,Image *image,
1136   char *attribute,SV *sval)
1137 {
1138   DoublePixelPacket
1139     pixel;
1140 
1141   ExceptionInfo
1142     exception;
1143 
1144   int
1145     sp;
1146 
1147   long
1148     x,
1149     y;
1150 
1151   PixelPacket
1152     *color,
1153     target_color;
1154 
1155   GetExceptionInfo(&exception);
1156   switch (*attribute)
1157   {
1158     case 'A':
1159     case 'a':
1160     {
1161       if (LocaleCompare(attribute,"adjoin") == 0)
1162         {
1163           sp=SvPOK(sval) ? LookupStr(BooleanTypes,SvPV(sval,na)) : SvIV(sval);
1164           if (sp < 0)
1165             {
1166               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1167               return;
1168             }
1169           if (info)
1170             info->image_info->adjoin=sp != 0;
1171           return;
1172         }
1173       if (LocaleCompare(attribute,"antialias") == 0)
1174         {
1175           sp=SvPOK(sval) ? LookupStr(BooleanTypes,SvPV(sval,na)) : SvIV(sval);
1176           if (sp < 0)
1177             {
1178               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1179               return;
1180             }
1181           if (info)
1182             {
1183               info->image_info->antialias=sp != 0;
1184               info->draw_info->text_antialias=sp != 0;
1185             }
1186           return;
1187         }
1188       if (LocaleCompare(attribute,"authenticate") == 0)
1189         {
1190           if (info)
1191             (void) CloneString(&info->image_info->authenticate,SvPV(sval,na));
1192           return;
1193         }
1194       MagickError(OptionError,UnrecognizedAttribute,attribute);
1195       break;
1196     }
1197     case 'B':
1198     case 'b':
1199     {
1200       if (LocaleCompare(attribute,"background") == 0)
1201         {
1202           (void) QueryColorDatabase(SvPV(sval,na),&target_color,
1203             image ? &image->exception : &exception);
1204           if (info)
1205             info->image_info->background_color=target_color;
1206           for ( ; image; image=image->next)
1207             image->background_color=target_color;
1208           return;
1209         }
1210       if (LocaleCompare(attribute,"blue-primary") == 0)
1211         {
1212           for ( ; image; image=image->next)
1213             (void) sscanf(SvPV(sval,na),"%lf%*[,/]%lf",
1214               &image->chromaticity.blue_primary.x,
1215               &image->chromaticity.blue_primary.y);
1216           return;
1217         }
1218       if (LocaleCompare(attribute,"bordercolor") == 0)
1219         {
1220           (void) QueryColorDatabase(SvPV(sval,na),&target_color,
1221             image ? &image->exception : &exception);
1222           if (info)
1223             {
1224               info->image_info->border_color=target_color;
1225               info->draw_info->border_color=target_color;
1226             }
1227           for ( ; image; image=image->next)
1228             image->border_color=target_color;
1229           return;
1230         }
1231       MagickError(OptionError,UnrecognizedAttribute,attribute);
1232       break;
1233     }
1234     case 'C':
1235     case 'c':
1236     {
1237       if (LocaleCompare(attribute,"cache-threshold") == 0)
1238         {
1239           SetMagickResourceLimit(MemoryResource,SvIV(sval));
1240           SetMagickResourceLimit(MapResource,2*SvIV(sval));
1241           return;
1242         }
1243       if (LocaleCompare(attribute,"clip-mask") == 0)
1244         {
1245           Image
1246             *clip_mask;
1247 
1248           clip_mask=SetupList(aTHX_ SvRV(sval),&info,(SV ***) NULL);
1249           for ( ; image; image=image->next)
1250             SetImageClipMask(image,clip_mask);
1251           return;
1252         }
1253       if (LocaleNCompare(attribute,"colormap",8) == 0)
1254         {
1255           for ( ; image; image=image->next)
1256           {
1257             int
1258               i;
1259 
1260             if (image->storage_class == DirectClass)
1261               continue;
1262             i=0;
1263             (void) sscanf(attribute,"%*[^[][%d",&i);
1264             if (i > (long) image->colors)
1265               i%=image->colors;
1266             if (strchr(SvPV(sval,na),',') == 0)
1267               QueryColorDatabase(SvPV(sval,na),image->colormap+i,
1268                 image ? &image->exception : &exception);
1269             else
1270               {
1271                 color=image->colormap+i;
1272                 pixel.red=color->red;
1273                 pixel.green=color->green;
1274                 pixel.blue=color->blue;
1275                 (void) sscanf(SvPV(sval,na),"%lf%*[,/]%lf%*[,/]%lf",&pixel.red,
1276                   &pixel.green,&pixel.blue);
1277                 color->red=(Quantum) ((pixel.red < 0) ? 0 :
1278                   (pixel.red > MaxRGB) ? MaxRGB : pixel.red+0.5);
1279                 color->green=(Quantum) ((pixel.green < 0) ? 0 :
1280                   (pixel.green > MaxRGB) ? MaxRGB : pixel.green+0.5);
1281                 color->blue=(Quantum) ((pixel.blue < 0) ? 0 :
1282                   (pixel.blue > MaxRGB) ? MaxRGB : pixel.blue+0.5);
1283               }
1284           }
1285           return;
1286         }
1287       if (LocaleCompare(attribute,"colorspace") == 0)
1288         {
1289           sp=SvPOK(sval) ? LookupStr(ColorspaceTypes,SvPV(sval,na)) :
1290             SvIV(sval);
1291           if (sp < 0)
1292             {
1293               MagickError(OptionError,UnrecognizedColorspace,SvPV(sval,na));
1294               return;
1295             }
1296           if (info)
1297             info->image_info->colorspace=(ColorspaceType) sp;
1298           for ( ; image; image=image->next)
1299             TransformColorspace(image,(ColorspaceType) sp);
1300           return;
1301         }
1302       if (LocaleCompare(attribute,"compression") == 0)
1303         {
1304           sp=SvPOK(sval) ? LookupStr(CompressionTypes,SvPV(sval,na)) :
1305             SvIV(sval);
1306           if (sp < 0)
1307             {
1308               MagickError(OptionError,UnrecognizedImageCompression,
1309                 SvPV(sval,na));
1310               return;
1311             }
1312           if (info)
1313             info->image_info->compression=(CompressionType) sp;
1314           for ( ; image; image=image->next)
1315             image->compression=(CompressionType) sp;
1316           return;
1317         }
1318       MagickError(OptionError,UnrecognizedAttribute,attribute);
1319       break;
1320     }
1321     case 'D':
1322     case 'd':
1323     {
1324       if (LocaleCompare(attribute,"debug") == 0)
1325         {
1326           SetLogEventMask(SvPV(sval,na));
1327           return;
1328         }
1329       if (LocaleCompare(attribute,"delay") == 0)
1330         {
1331           for ( ; image; image=image->next)
1332             image->delay=SvIV(sval);
1333           return;
1334         }
1335       if (LocaleCompare(attribute,"disk-limit") == 0)
1336         {
1337           SetMagickResourceLimit(DiskResource,SvIV(sval));
1338           return;
1339         }
1340       if (LocaleCompare(attribute,"density") == 0)
1341         {
1342           if (!IsGeometry(SvPV(sval,na)))
1343             {
1344               MagickError(OptionError,MissingGeometry,SvPV(sval,na));
1345               return;
1346             }
1347           if (info)
1348             {
1349               (void) CloneString(&info->image_info->density,SvPV(sval,na));
1350               (void) CloneString(&info->draw_info->density,SvPV(sval,na));
1351             }
1352           for ( ; image; image=image->next)
1353           {
1354             int
1355               count;
1356 
1357             count=sscanf(info->image_info->density,"%lfx%lf",
1358               &image->x_resolution,&image->y_resolution);
1359             if (count != 2)
1360               image->y_resolution=image->x_resolution;
1361           }
1362           return;
1363         }
1364       if (LocaleCompare(attribute,"depth") == 0)
1365         {
1366           if (info)
1367             info->image_info->depth=SvIV(sval);
1368           for ( ; image; image=image->next)
1369             SetImageDepth(image,SvIV(sval));
1370           return;
1371         }
1372       if (LocaleCompare(attribute,"dispose") == 0)
1373         {
1374           sp=SvPOK(sval) ? LookupStr(DisposeTypes,SvPV(sval,na)) : SvIV(sval);
1375           if (sp < 0)
1376             sp=SvIV(sval);
1377           if (sp < 0)
1378             {
1379               MagickError(OptionError,UnrecognizedDisposeMethod,
1380                 SvPV(sval,na));
1381               return;
1382             }
1383           for ( ; image; image=image->next)
1384             image->dispose=(DisposeType) sp;
1385           return;
1386         }
1387       if (LocaleCompare(attribute,"dither") == 0)
1388         {
1389           if (info)
1390             {
1391               sp=SvPOK(sval) ? LookupStr(BooleanTypes,SvPV(sval,na)) :
1392                 SvIV(sval);
1393               if (sp < 0)
1394                 {
1395                   MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1396                   return;
1397                 }
1398               info->image_info->dither=sp != 0;
1399             }
1400           return;
1401         }
1402       if (LocaleCompare(attribute,"display") == 0)
1403         {
1404           display:
1405           if (info)
1406             {
1407               (void) CloneString(&info->image_info->server_name,SvPV(sval,na));
1408               (void) CloneString(&info->draw_info->server_name,SvPV(sval,na));
1409             }
1410           return;
1411         }
1412       MagickError(OptionError,UnrecognizedAttribute,attribute);
1413       break;
1414     }
1415     case 'E':
1416     case 'e':
1417     {
1418       if (LocaleCompare(attribute,"endian") == 0)
1419         {
1420           sp=SvPOK(sval) ? LookupStr(EndianTypes,SvPV(sval,na)) : SvIV(sval);
1421           if (sp < 0)
1422             {
1423               MagickError(OptionError,UnrecognizedEndianType,SvPV(sval,na));
1424               return;
1425             }
1426           if (info)
1427             info->image_info->endian=(EndianType) sp;
1428           for ( ; image; image=image->next)
1429             image->endian=(EndianType) sp;
1430           return;
1431         }
1432       MagickError(OptionError,UnrecognizedAttribute,attribute);
1433       break;
1434     }
1435     case 'F':
1436     case 'f':
1437     {
1438       if (LocaleCompare(attribute,"filename") == 0)
1439         {
1440           if (info)
1441             (void) strncpy(info->image_info->filename,SvPV(sval,na),
1442               MaxTextExtent-1);
1443           for ( ; image; image=image->next)
1444             (void) strncpy(image->filename,SvPV(sval,na),MaxTextExtent-1);
1445           return;
1446         }
1447       if (LocaleCompare(attribute,"file") == 0)
1448         {
1449           if (info)
1450             info->image_info->file=PerlIO_findFILE(IoIFP(sv_2io(sval)));
1451           return;
1452         }
1453       if (LocaleCompare(attribute,"fill") == 0)
1454         {
1455           if (info)
1456             {
1457               (void) QueryColorDatabase(SvPV(sval,na),&info->draw_info->fill,
1458                 image ? &image->exception : &exception);
1459               (void) QueryColorDatabase(SvPV(sval,na),&info->image_info->pen,
1460                 image ? &image->exception : &exception);
1461             }
1462           return;
1463         }
1464       if (LocaleCompare(attribute,"font") == 0)
1465         {
1466           if (info)
1467             {
1468               (void) CloneString(&info->image_info->font,SvPV(sval,na));
1469               (void) CloneString(&info->draw_info->font,SvPV(sval,na));
1470             }
1471           return;
1472         }
1473       if (LocaleCompare(attribute,"fuzz") == 0)
1474         {
1475           if (info)
1476             info->image_info->fuzz=SvNV(sval);
1477           for ( ; image; image=image->next)
1478             image->fuzz=SvNV(sval);
1479           return;
1480         }
1481       MagickError(OptionError,UnrecognizedAttribute,attribute);
1482       break;
1483     }
1484     case 'G':
1485     case 'g':
1486     {
1487       if (LocaleCompare(attribute,"gamma") == 0)
1488         {
1489           for ( ; image; image=image->next)
1490             image->gamma=SvNV(sval);
1491           return;
1492         }
1493       if (LocaleCompare(attribute,"gravity") == 0)
1494         {
1495           sp=SvPOK(sval) ? LookupStr(GravityTypes,SvPV(sval,na)) :
1496             SvIV(sval);
1497           if (sp < 0)
1498             {
1499               MagickError(OptionError,UnrecognizedGravityType,SvPV(sval,na));
1500               return;
1501             }
1502           for ( ; image; image=image->next)
1503             image->gravity=(GravityType) sp;
1504           return;
1505         }
1506       if (LocaleCompare(attribute,"green-primary") == 0)
1507         {
1508           for ( ; image; image=image->next)
1509             (void) sscanf(SvPV(sval,na),"%lf%*[,/]%lf",
1510               &image->chromaticity.green_primary.x,
1511               &image->chromaticity.green_primary.y);
1512           return;
1513         }
1514       MagickError(OptionError,UnrecognizedAttribute,attribute);
1515       break;
1516     }
1517     case 'I':
1518     case 'i':
1519     {
1520       if (LocaleNCompare(attribute,"index",5) == 0)
1521         {
1522           long
1523             index;
1524 
1525           IndexPacket
1526             *indexes;
1527 
1528           register PixelPacket
1529             *p;
1530 
1531           for ( ; image; image=image->next)
1532           {
1533             if (image->storage_class != PseudoClass)
1534               continue;
1535             x=0;
1536             y=0;
1537             (void) sscanf(attribute,"%*[^[][%ld%*[,/]%ld",&x,&y);
1538             p=GetImagePixels(image,(long) (x % image->columns),
1539               (long) (y % image->rows),1,1);
1540             if (p == (PixelPacket *) NULL)
1541               break;
1542             indexes=AccessMutableIndexes(image);
1543             (void) sscanf(SvPV(sval,na),"%ld",&index);
1544             if ((index >= 0) && (index < (long) image->colors))
1545               *indexes=(IndexPacket) index;
1546             (void) SyncImagePixels(image);
1547           }
1548           return;
1549         }
1550       if (LocaleCompare(attribute,"iterations") == 0)
1551         {
1552   iterations:
1553           for ( ; image; image=image->next)
1554             image->iterations=SvIV(sval);
1555           return;
1556         }
1557       if (LocaleCompare(attribute,"interlace") == 0)
1558         {
1559           sp=SvPOK(sval) ? LookupStr(InterlaceTypes,SvPV(sval,na)) : SvIV(sval);
1560           if (sp < 0)
1561             {
1562               MagickError(OptionError,UnrecognizedInterlaceType,
1563                 SvPV(sval,na));
1564               return;
1565             }
1566           if (info)
1567             info->image_info->interlace=(InterlaceType) sp;
1568           for ( ; image; image=image->next)
1569             image->interlace=(InterlaceType) sp;
1570           return;
1571         }
1572       MagickError(OptionError,UnrecognizedAttribute,attribute);
1573       break;
1574     }
1575     case 'L':
1576     case 'l':
1577     {
1578       if (LocaleCompare(attribute,"loop") == 0)
1579         goto iterations;
1580       MagickError(OptionError,UnrecognizedAttribute,attribute);
1581       break;
1582     }
1583     case 'M':
1584     case 'm':
1585     {
1586       if (LocaleCompare(attribute,"magick") == 0)
1587         {
1588           if (info)
1589             {
1590               ExceptionInfo
1591                 exception;
1592 
1593               GetExceptionInfo(&exception);
1594               FormatString(info->image_info->filename,"%.1024s:",SvPV(sval,na));
1595               SetImageInfo(info->image_info,SETMAGICK_WRITE,&exception);
1596               if (*info->image_info->magick == '\0')
1597                 MagickError(OptionError,UnrecognizedImageFormat,
1598                   info->image_info->filename);
1599               else
1600                 for ( ; image; image=image->next)
1601                   (void) strncpy(image->magick,info->image_info->magick,
1602                     MaxTextExtent-1);
1603               DestroyExceptionInfo(&exception);
1604             }
1605           return;
1606         }
1607       if (LocaleCompare(attribute,"map-limit") == 0)
1608         {
1609           SetMagickResourceLimit(MapResource,SvIV(sval));
1610           return;
1611         }
1612       if (LocaleCompare(attribute,"mattecolor") == 0)
1613         {
1614           (void) QueryColorDatabase(SvPV(sval,na),&target_color,
1615             image ? &image->exception : &exception);
1616           if (info)
1617             info->image_info->matte_color=target_color;
1618           for ( ; image; image=image->next)
1619             image->matte_color=target_color;
1620           return;
1621         }
1622       if (LocaleCompare(attribute,"matte") == 0)
1623         {
1624           sp=SvPOK(sval) ? LookupStr(BooleanTypes,SvPV(sval,na)) : SvIV(sval);
1625           if (sp < 0)
1626             {
1627               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1628               return;
1629             }
1630           for ( ; image; image=image->next)
1631             image->matte=sp != 0;
1632           return;
1633         }
1634       if (LocaleCompare(attribute,"memory-limit") == 0)
1635         {
1636           SetMagickResourceLimit(MemoryResource,SvIV(sval));
1637           return;
1638         }
1639       if (LocaleCompare(attribute,"monochrome") == 0)
1640         {
1641           sp=SvPOK(sval) ? LookupStr(BooleanTypes,SvPV(sval,na)) : SvIV(sval);
1642           if (sp < 0)
1643             {
1644               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1645               return;
1646             }
1647           if (info)
1648             info->image_info->monochrome=sp != 0;
1649           return;
1650         }
1651       MagickError(OptionError,UnrecognizedAttribute,attribute);
1652       break;
1653     }
1654     case 'P':
1655     case 'p':
1656     {
1657       if (LocaleCompare(attribute,"page") == 0)
1658         {
1659           char
1660             *geometry;
1661 
1662           geometry=GetPageGeometry(SvPV(sval,na));
1663           if (info)
1664             (void) CloneString(&info->image_info->page,geometry);
1665           for ( ; image; image=image->next)
1666             (void) GetImageGeometry(image,geometry,False,&image->page);
1667           MagickFreeMemory(geometry);
1668           return;
1669         }
1670       if (LocaleCompare(attribute,"pen") == 0)
1671         {
1672           if (info)
1673             (void) QueryColorDatabase(SvPV(sval,na),&info->draw_info->fill,
1674               image ? &image->exception : &exception);
1675           return;
1676         }
1677       if (LocaleNCompare(attribute,"pixel",5) == 0)
1678         {
1679           register PixelPacket
1680             *p;
1681 
1682           for ( ; image; image=image->next)
1683           {
1684             x=0;
1685             y=0;
1686             (void) sscanf(attribute,"%*[^[][%ld%*[,/]%ld",&x,&y);
1687             p=GetImagePixels(image,(long) (x % image->columns),
1688               (long) (y % image->rows),1,1);
1689             if (p == (PixelPacket *) NULL)
1690               break;
1691             image->storage_class=DirectClass;
1692             if (strchr(SvPV(sval,na),',') == 0)
1693               QueryColorDatabase(SvPV(sval,na),p,
1694                 image ? &image->exception : &exception);
1695             else
1696               {
1697                 pixel.red=p->red;
1698                 pixel.green=p->green;
1699                 pixel.blue=p->blue;
1700                 pixel.opacity=p->opacity;
1701                 (void) sscanf(SvPV(sval,na),"%lf%*[,/]%lf%*[,/]%lf%*[,/]%lf",
1702                   &pixel.red,&pixel.green,&pixel.blue,&pixel.opacity);
1703                 p->red=(Quantum) ((pixel.red < 0) ? 0 :
1704                   (pixel.red > MaxRGB) ? MaxRGB : pixel.red+0.5);
1705                 p->green=(Quantum) ((pixel.green < 0) ? 0 :
1706                   (pixel.green > MaxRGB) ? MaxRGB : pixel.green+0.5);
1707                 p->blue=(Quantum) ((pixel.blue < 0) ? 0 :
1708                   (pixel.blue > MaxRGB) ? MaxRGB : pixel.blue+0.5);
1709                 p->opacity=(Quantum) ((pixel.opacity < 0) ? 0 :
1710                   (pixel.opacity > MaxRGB) ? MaxRGB : pixel.opacity+0.5);
1711               }
1712             (void) SyncImagePixels(image);
1713           }
1714           return;
1715         }
1716       if (LocaleCompare(attribute,"pointsize") == 0)
1717         {
1718           if (info)
1719             {
1720               (void) sscanf(SvPV(sval,na),"%lf",&info->image_info->pointsize);
1721               (void) sscanf(SvPV(sval,na),"%lf",&info->draw_info->pointsize);
1722             }
1723           return;
1724         }
1725       if (LocaleCompare(attribute,"preview") == 0)
1726         {
1727           sp=SvPOK(sval) ? LookupStr(PreviewTypes,SvPV(sval,na)) : SvIV(sval);
1728           if (sp < 0)
1729             {
1730               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1731               return;
1732             }
1733           if (info)
1734             info->image_info->preview_type=(PreviewType) sp;
1735           return;
1736         }
1737       MagickError(OptionError,UnrecognizedAttribute,attribute);
1738       break;
1739     }
1740     case 'Q':
1741     case 'q':
1742     {
1743       if (LocaleCompare(attribute,"quality") == 0)
1744         {
1745           if (info)
1746             info->image_info->quality=SvIV(sval);
1747           return;
1748         }
1749       MagickError(OptionError,UnrecognizedAttribute,attribute);
1750       break;
1751     }
1752     case 'R':
1753     case 'r':
1754     {
1755       if (LocaleCompare(attribute,"red-primary") == 0)
1756         {
1757           for ( ; image; image=image->next)
1758             (void) sscanf(SvPV(sval,na),"%lf%*[,/]%lf",
1759               &image->chromaticity.red_primary.x,
1760               &image->chromaticity.red_primary.y);
1761           return;
1762         }
1763       if (LocaleCompare(attribute,"render") == 0)
1764         {
1765           sp=SvPOK(sval) ? LookupStr(IntentTypes,SvPV(sval,na)) : SvIV(sval);
1766           if (sp < 0)
1767             {
1768               MagickError(OptionError,UnrecognizedIntentType,SvPV(sval,na));
1769               return;
1770             }
1771          for ( ; image; image=image->next)
1772            image->rendering_intent=(RenderingIntent) sp;
1773          return;
1774        }
1775       MagickError(OptionError,UnrecognizedAttribute,attribute);
1776       break;
1777     }
1778     case 'S':
1779     case 's':
1780     {
1781       if (LocaleCompare(attribute,"sampling-factor") == 0)
1782         {
1783           if (!IsGeometry(SvPV(sval,na)))
1784             {
1785               MagickError(OptionError,MissingGeometry,SvPV(sval,na));
1786               return;
1787             }
1788           if (info)
1789             (void) CloneString(&info->image_info->sampling_factor,
1790               SvPV(sval,na));
1791           return;
1792         }
1793       if (LocaleCompare(attribute,"scene") == 0)
1794         {
1795           for ( ; image; image=image->next)
1796             image->scene=SvIV(sval);
1797           return;
1798         }
1799       if (LocaleCompare(attribute,"subimage") == 0)
1800         {
1801           if (info)
1802             info->image_info->subimage=SvIV(sval);
1803           return;
1804         }
1805       if (LocaleCompare(attribute,"subrange") == 0)
1806         {
1807           if (info)
1808             info->image_info->subrange=SvIV(sval);
1809           return;
1810         }
1811       if (LocaleCompare(attribute,"server") == 0)
1812         goto display;
1813       if (LocaleCompare(attribute,"size") == 0)
1814         {
1815           if (info)
1816             {
1817               if (!IsGeometry(SvPV(sval,na)))
1818                 {
1819                   MagickError(OptionError,MissingGeometry,SvPV(sval,na));
1820                   return;
1821                 }
1822               (void) CloneString(&info->image_info->size,SvPV(sval,na));
1823             }
1824           return;
1825         }
1826       if (LocaleCompare(attribute,"stroke") == 0)
1827         {
1828           if (info)
1829             (void) QueryColorDatabase(SvPV(sval,na),&info->draw_info->stroke,
1830               image ? &image->exception : &exception);
1831           return;
1832         }
1833       MagickError(OptionError,UnrecognizedAttribute,attribute);
1834       break;
1835     }
1836     case 'T':
1837     case 't':
1838     {
1839       if (LocaleCompare(attribute,"tile") == 0)
1840         {
1841           if (info)
1842             (void) CloneString(&info->image_info->tile,SvPV(sval,na));
1843           return;
1844         }
1845       if (LocaleCompare(attribute,"texture") == 0)
1846         {
1847           if (info)
1848             (void) CloneString(&info->image_info->texture,SvPV(sval,na));
1849           return;
1850         }
1851       if (LocaleCompare(attribute,"type") == 0)
1852         {
1853           sp=SvPOK(sval) ? LookupStr(ImageTypes,SvPV(sval,na)) : SvIV(sval);
1854           if (sp < 0)
1855             {
1856               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1857               return;
1858             }
1859           if (info)
1860             info->image_info->type=(ImageType) sp;
1861           for ( ; image; image=image->next)
1862             SetImageType(image,(ImageType) sp);
1863           return;
1864         }
1865       MagickError(OptionError,UnrecognizedAttribute,attribute);
1866       break;
1867     }
1868     case 'U':
1869     case 'u':
1870     {
1871       if (LocaleCompare(attribute,"units") == 0)
1872         {
1873           sp=SvPOK(sval) ? LookupStr(ResolutionTypes,SvPV(sval,na)) :
1874             SvIV(sval);
1875           if (sp < 0)
1876             {
1877               MagickError(OptionError,MissingType,SvPV(sval,na));
1878               return;
1879             }
1880           if (info)
1881             info->image_info->units=(ResolutionType) sp;
1882           for ( ; image; image=image->next)
1883             image->units=(ResolutionType) sp;
1884           return;
1885         }
1886       MagickError(OptionError,UnrecognizedAttribute,attribute);
1887       break;
1888     }
1889     case 'V':
1890     case 'v':
1891     {
1892       if (LocaleCompare(attribute,"verbose") == 0)
1893         {
1894           sp=SvPOK(sval) ? LookupStr(BooleanTypes,SvPV(sval,na)) : SvIV(sval);
1895           if (sp < 0)
1896             {
1897               MagickError(OptionError,UnrecognizedType,SvPV(sval,na));
1898               return;
1899             }
1900           if (info)
1901             info->image_info->verbose=sp != 0;
1902           return;
1903         }
1904       if (LocaleCompare(attribute,"view") == 0)
1905         {
1906           if (info)
1907             (void) CloneString(&info->image_info->view,SvPV(sval,na));
1908           return;
1909         }
1910       if (LocaleCompare(attribute,"virtual-pixel") == 0)
1911         {
1912           sp=SvPOK(sval) ? LookupStr(VirtualPixelMethods,SvPV(sval,na)) :
1913             SvIV(sval);
1914           if (sp < 0)
1915             {
1916               MagickError(OptionError,UnrecognizedVirtualPixelMethod,
1917                 SvPV(sval,na));
1918               return;
1919             }
1920           for ( ; image; image=image->next)
1921             SetImageVirtualPixelMethod(image,(VirtualPixelMethod) sp);
1922           return;
1923         }
1924       MagickError(OptionError,UnrecognizedAttribute,attribute);
1925       break;
1926     }
1927     case 'W':
1928     case 'w':
1929     {
1930       if (LocaleCompare(attribute,"white-point") == 0)
1931         {
1932           for ( ; image; image=image->next)
1933             (void) sscanf(SvPV(sval,na),"%lf%*[,/]%lf",
1934               &image->chromaticity.white_point.x,
1935               &image->chromaticity.white_point.y);
1936           return;
1937         }
1938       MagickError(OptionError,UnrecognizedAttribute,attribute);
1939       break;
1940     }
1941     default:
1942     {
1943       MagickError(OptionError,UnrecognizedAttribute,attribute);
1944       break;
1945     }
1946   }
1947   DestroyExceptionInfo(&exception);
1948   if (image == (Image *) NULL)
1949     MagickError(OptionError,UnrecognizedAttribute,attribute);
1950   for ( ; image; image=image->next)
1951     (void) SetImageAttribute(image,attribute,SvPV(sval,na));
1952 }
1953 
1954 /*
1955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1956 %                                                                             %
1957 %                                                                             %
1958 %                                                                             %
1959 %   S e t u p L i s t                                                         %
1960 %                                                                             %
1961 %                                                                             %
1962 %                                                                             %
1963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964 %
1965 %  Method SetupList returns the list of all the images linked by their
1966 %  image->next and image->previous link lists for use with GraphicsMagick.  If
1967 %  info is non-NULL, an info structure is returned in *info.  If
1968 %  reference_vector is non-NULL,an array of SV* are returned in
1969 %  *reference_vector.  Reference_vector is used when the images are going to be
1970 %  replaced with new Image*'s.
1971 %
1972 %  The format of the SetupList routine is:
1973 %
1974 %      Image *SetupList(SV *reference,struct PackageInfo **info,
1975 %        SV ***reference_vector)
1976 %
1977 %  A description of each parameter follows:
1978 %
1979 %    o status: Method SetupList returns the index of string in the list
1980 %      otherwise -1.
1981 %
1982 %    o list: a list of strings.
1983 %
1984 %    o string: a character string.
1985 %
1986 %
1987 */
SetupList(pTHX_ SV * reference,struct PackageInfo ** info,SV *** reference_vector)1988 static Image *SetupList(pTHX_ SV *reference,struct PackageInfo **info,
1989   SV ***reference_vector)
1990 {
1991   Image
1992     *image;
1993 
1994   int
1995     current,
1996     last;
1997 
1998   if (reference_vector)
1999     *reference_vector=NULL;
2000   if (info)
2001     *info=NULL;
2002   current=0;
2003   last=0;
2004   image=GetList(aTHX_ reference,reference_vector,&current,&last);
2005   if (info && (SvTYPE(reference) == SVt_PVAV))
2006     *info=GetPackageInfo(aTHX_ (void *) reference,(struct PackageInfo *) NULL);
2007   return(image);
2008 }
2009 
2010 /*
2011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012 %                                                                             %
2013 %                                                                             %
2014 %                                                                             %
2015 %   s t r E Q c a s e                                                         %
2016 %                                                                             %
2017 %                                                                             %
2018 %                                                                             %
2019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020 %
2021 %  Method strEQcase compares two strings and returns 0 if they are the
2022 %  same or if the second string runs out first.  The comparison is case
2023 %  insensitive.
2024 %
2025 %  The format of the strEQcase routine is:
2026 %
2027 %      int strEQcase(const char *p,const char *q)
2028 %
2029 %  A description of each parameter follows:
2030 %
2031 %    o status: Method strEQcase returns zero if strings p and q are the
2032 %      same or if the second string runs out first.
2033 %
2034 %    o p: a character string.
2035 %
2036 %    o q: a character string.
2037 %
2038 %
2039 */
strEQcase(const char * p,const char * q)2040 static int strEQcase(const char *p,const char *q)
2041 {
2042   char
2043     c;
2044 
2045   register int
2046     i;
2047 
2048   for (i=0 ; (c=(*q)) != 0; i++)
2049   {
2050     if ((isUPPER(c) ? toLOWER(c) : c) != (isUPPER(*p) ? toLOWER(*p) : *p))
2051       return(0);
2052     p++;
2053     q++;
2054   }
2055   return(i);
2056 }
2057 
2058 /*
2059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2060 %                                                                             %
2061 %                                                                             %
2062 %                                                                             %
2063 %   G r a p h i c s : : M a g i c k                                           %
2064 %                                                                             %
2065 %                                                                             %
2066 %                                                                             %
2067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068 %
2069 %
2070 */
2071 MODULE = Graphics::Magick PACKAGE = Graphics::Magick
2072 
2073 PROTOTYPES: ENABLE
2074 
2075 BOOT:
2076   InitializeMagick(PackageName);
2077   SetWarningHandler(MagickWarningHandler);
2078   SetErrorHandler(MagickErrorHandler);
2079   { MY_CXT_INIT; }
2080 
2081 double
constant(name,argument)2082 constant(name,argument)
2083   char *name
2084   int argument
2085 
2086 #
2087 ###############################################################################
2088 #                                                                             #
2089 #                                                                             #
2090 #                                                                             #
2091 #   A n i m a t e                                                             #
2092 #                                                                             #
2093 #                                                                             #
2094 #                                                                             #
2095 ###############################################################################
2096 #
2097 #
2098 void
2099 Animate(ref,...)
2100   Graphics::Magick ref=NO_INIT
2101   ALIAS:
2102     AnimateImage  = 1
2103     animate       = 2
2104     animateimage  = 3
2105   PPCODE:
2106   {
2107     jmp_buf
2108       error_jmp;
2109 
2110     Image
2111       *image;
2112 
2113     register int
2114       i;
2115 
2116     struct PackageInfo
2117       *info,
2118       *package_info;
2119 
2120     SV
2121       *reference;
2122 
2123     volatile int
2124       status;
2125 
2126     dMY_CXT;
2127     MY_CXT.error_list=newSVpv("",0);
2128     package_info=(struct PackageInfo *) NULL;
2129     status=0;
2130     if (!sv_isobject(ST(0)))
2131       {
2132         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2133         goto MethodException;
2134       }
2135     reference=SvRV(ST(0));
2136     MY_CXT.error_jump=(&error_jmp);
2137     status=setjmp(error_jmp);
2138     if (status)
2139       goto MethodException;
2140     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2141     if (!image)
2142       {
2143         MagickError(OptionError,NoImagesDefined,NULL);
2144         goto MethodException;
2145       }
2146     package_info=ClonePackageInfo(info);
2147     if (items == 2)
2148       SetAttribute(aTHX_ package_info,NULL,"server",ST(1));
2149     else
2150       if (items > 2)
2151         for (i=2; i < items; i+=2)
2152           SetAttribute(aTHX_ package_info,image,SvPV(ST(i-1),na),ST(i));
2153     AnimateImages(package_info->image_info,image);
2154     (void) CatchImageException(image);
2155 
2156   MethodException:
2157     if (package_info)
2158       DestroyPackageInfo(package_info);
2159     sv_setiv(MY_CXT.error_list,(IV)
2160       (status ? status : SvCUR(MY_CXT.error_list) != 0));
2161     SvPOK_on(MY_CXT.error_list);
2162     ST(0)=sv_2mortal(MY_CXT.error_list);
2163     MY_CXT.error_list=NULL;
2164     MY_CXT.error_jump=NULL;
2165     XSRETURN(1);
2166   }
2167 
2168 #
2169 ###############################################################################
2170 #                                                                             #
2171 #                                                                             #
2172 #                                                                             #
2173 #   A p p e n d                                                               #
2174 #                                                                             #
2175 #                                                                             #
2176 #                                                                             #
2177 ###############################################################################
2178 #
2179 #
2180 void
Append(ref,...)2181 Append(ref,...)
2182   Graphics::Magick ref=NO_INIT
2183   ALIAS:
2184     AppendImage  = 1
2185     append       = 2
2186     appendimage  = 3
2187   PPCODE:
2188   {
2189     AV
2190       *av;
2191 
2192     char
2193       *attribute;
2194 
2195     ExceptionInfo
2196       exception;
2197 
2198     HV
2199       *hv;
2200 
2201     jmp_buf
2202       error_jmp;
2203 
2204     Image
2205       *image;
2206 
2207     int
2208       stack;
2209 
2210     register int
2211       i;
2212 
2213     struct PackageInfo
2214       *info;
2215 
2216     SV
2217       *av_reference,
2218       *reference,
2219       *rv,
2220       *sv;
2221 
2222     volatile int
2223       status;
2224 
2225     dMY_CXT;
2226     MY_CXT.error_list=newSVpv("",0);
2227     attribute=NULL;
2228     av=NULL;
2229     status=0;
2230     if (!sv_isobject(ST(0)))
2231       {
2232         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2233         goto MethodException;
2234       }
2235     reference=SvRV(ST(0));
2236     hv=SvSTASH(reference);
2237     av=newAV();
2238     av_reference=sv_2mortal(sv_bless(newRV((SV *) av),hv));
2239     SvREFCNT_dec(av);
2240     MY_CXT.error_jump=(&error_jmp);
2241     status=setjmp(error_jmp);
2242     if (status)
2243       goto MethodException;
2244     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2245     if (!image)
2246       {
2247         MagickError(OptionError,NoImagesDefined,NULL);
2248         goto MethodException;
2249       }
2250     info=GetPackageInfo(aTHX_ (void *) av,info);
2251     /*
2252       Get options.
2253     */
2254     stack=True;
2255     for (i=2; i < items; i+=2)
2256     {
2257       attribute=(char *) SvPV(ST(i-1),na);
2258       switch (*attribute)
2259       {
2260         case 'S':
2261         case 's':
2262         {
2263           if (LocaleCompare(attribute,"stack") == 0)
2264             {
2265               stack=LookupStr(BooleanTypes,SvPV(ST(i),na));
2266               if (stack < 0)
2267                 {
2268                   MagickError(OptionError,UnrecognizedType,SvPV(ST(i),na));
2269                   return;
2270                 }
2271               break;
2272             }
2273           MagickError(OptionError,UnrecognizedAttribute,attribute);
2274           break;
2275         }
2276         default:
2277         {
2278           MagickError(OptionError,UnrecognizedAttribute,attribute);
2279           break;
2280         }
2281       }
2282     }
2283     GetExceptionInfo(&exception);
2284     image=AppendImages(image,stack,&exception);
2285     if (exception.severity != UndefinedException)
2286       CatchException(&exception);
2287     DestroyExceptionInfo(&exception);
2288     for ( ; image; image=image->next)
2289     {
2290       sv=newSViv((IV) (magick_uintptr_t)image);
2291       rv=newRV(sv);
2292       av_push(av,sv_bless(rv,hv));
2293       SvREFCNT_dec(sv);
2294     }
2295     ST(0)=av_reference;
2296     MY_CXT.error_jump=NULL;
2297     SvREFCNT_dec(MY_CXT.error_list);  /* can't return warning messages */
2298     MY_CXT.error_list=NULL;
2299     XSRETURN(1);
2300 
2301   MethodException:
2302     MY_CXT.error_jump=NULL;
2303     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
2304     SvPOK_on(MY_CXT.error_list);
2305     ST(0)=sv_2mortal(MY_CXT.error_list);
2306     MY_CXT.error_list=NULL;
2307     MY_CXT.error_jump=NULL;
2308     XSRETURN(1);
2309   }
2310 
2311 #
2312 ###############################################################################
2313 #                                                                             #
2314 #                                                                             #
2315 #                                                                             #
2316 #   A v e r a g e                                                             #
2317 #                                                                             #
2318 #                                                                             #
2319 #                                                                             #
2320 ###############################################################################
2321 #
2322 #
2323 void
Average(ref)2324 Average(ref)
2325   Graphics::Magick ref=NO_INIT
2326   ALIAS:
2327     AverageImage   = 1
2328     average        = 2
2329     averageimage   = 3
2330   PPCODE:
2331   {
2332     AV
2333       *av;
2334 
2335     char
2336       *p;
2337 
2338     ExceptionInfo
2339       exception;
2340 
2341     HV
2342       *hv;
2343 
2344     jmp_buf
2345       error_jmp;
2346 
2347     Image
2348       *image;
2349 
2350     struct PackageInfo
2351       *info;
2352 
2353     SV
2354       *reference,
2355       *rv,
2356       *sv;
2357 
2358     volatile int
2359       status;
2360 
2361     dMY_CXT;
2362     MY_CXT.error_list=newSVpv("",0);
2363     status=0;
2364     if (!sv_isobject(ST(0)))
2365       {
2366         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2367         goto MethodException;
2368       }
2369     reference=SvRV(ST(0));
2370     hv=SvSTASH(reference);
2371     MY_CXT.error_jump=(&error_jmp);
2372     status=setjmp(error_jmp);
2373     if (status)
2374       goto MethodException;
2375     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2376     if (!image)
2377       {
2378         MagickError(OptionError,NoImagesDefined,NULL);
2379         goto MethodException;
2380       }
2381     GetExceptionInfo(&exception);
2382     image=AverageImages(image,&exception);
2383     if (exception.severity != UndefinedException)
2384       CatchException(&exception);
2385     DestroyExceptionInfo(&exception);
2386     /*
2387       Create blessed Perl array for the returned image.
2388     */
2389     av=newAV();
2390     ST(0)=sv_2mortal(sv_bless(newRV((SV *) av),hv));
2391     SvREFCNT_dec(av);
2392     sv=newSViv((IV) (magick_uintptr_t)image);
2393     rv=newRV(sv);
2394     av_push(av,sv_bless(rv,hv));
2395     SvREFCNT_dec(sv);
2396     info=GetPackageInfo(aTHX_ (void *) av,info);
2397     FormatString(info->image_info->filename,"average-%.*s",MaxTextExtent-9,
2398       ((p=strrchr(image->filename,'/')) ? p+1 : image->filename));
2399     (void) strncpy(image->filename,info->image_info->filename,MaxTextExtent-1);
2400     SetImageInfo(info->image_info,SETMAGICK_WRITE,&image->exception);
2401     SvREFCNT_dec(MY_CXT.error_list);
2402     MY_CXT.error_jump=NULL;
2403     XSRETURN(1);
2404 
2405   MethodException:
2406     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
2407     SvPOK_on(MY_CXT.error_list);  /* return messages in string context */
2408     ST(0)=sv_2mortal(MY_CXT.error_list);
2409     MY_CXT.error_list=NULL;
2410     MY_CXT.error_jump=NULL;
2411     XSRETURN(1);
2412   }
2413 
2414 #
2415 ###############################################################################
2416 #                                                                             #
2417 #                                                                             #
2418 #                                                                             #
2419 #   B l o b T o I m a g e                                                     #
2420 #                                                                             #
2421 #                                                                             #
2422 #                                                                             #
2423 ###############################################################################
2424 #
2425 #
2426 void
BlobToImage(ref,...)2427 BlobToImage(ref,...)
2428   Graphics::Magick ref=NO_INIT
2429   ALIAS:
2430     BlobToImage  = 1
2431     blobtoimage  = 2
2432     blobto       = 3
2433   PPCODE:
2434   {
2435     AV
2436       *av;
2437 
2438     char
2439       **keep,
2440       **list;
2441 
2442     ExceptionInfo
2443       exception;
2444 
2445     HV
2446       *hv;
2447 
2448     Image
2449       *image;
2450 
2451     int
2452       ac,
2453       n;
2454 
2455     jmp_buf
2456       error_jmp;
2457 
2458     register char
2459       **p;
2460 
2461     register int
2462       i;
2463 
2464     struct PackageInfo
2465       *info;
2466 
2467     STRLEN
2468       *length;
2469 
2470     SV
2471       *reference,
2472       *rv,
2473       *sv;
2474 
2475     volatile int
2476       number_images;
2477 
2478     dMY_CXT;
2479     MY_CXT.error_list=newSVpv("",0);
2480     number_images=0;
2481     ac=(items < 2) ? 1 : items-1;
2482     list=MagickAllocateMemory(char **,(ac+1)*sizeof(*list));
2483     length=MagickAllocateMemory(STRLEN *,(ac+1)*sizeof(length));
2484     if (!sv_isobject(ST(0)))
2485       {
2486         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2487         goto ReturnIt;
2488       }
2489     reference=SvRV(ST(0));
2490     hv=SvSTASH(reference);
2491     if (SvTYPE(reference) != SVt_PVAV)
2492       {
2493         MagickError(OptionError,ReferenceIsNotMyType,NULL);
2494         goto ReturnIt;
2495       }
2496     av=(AV *) reference;
2497     info=GetPackageInfo(aTHX_ (void *) av,(struct PackageInfo *) NULL);
2498     n=1;
2499     if (items <= 1)
2500       {
2501         MagickError(OptionError,NoBlobDefined,NULL);
2502         goto ReturnIt;
2503       }
2504     for (n=0, i=0; i < ac; i++)
2505     {
2506       list[n]=(char *) (SvPV(ST(i+1),length[n]));
2507       if ((items >= 3) && strEQcase((char *) SvPV(ST(i+1),na),"blob"))
2508         {
2509           list[n]=(char *) (SvPV(ST(i+2),length[n]));
2510           continue;
2511         }
2512       n++;
2513     }
2514     list[n]=(char *) NULL;
2515     keep=list;
2516     MY_CXT.error_jump=(&error_jmp);
2517     if (setjmp(error_jmp))
2518       goto ReturnIt;
2519     GetExceptionInfo(&exception);
2520     for (i=number_images=0; i < n; i++)
2521     {
2522       image=BlobToImage(info->image_info,list[i],length[i],&exception);
2523       if (exception.severity != UndefinedException)
2524         CatchException(&exception);
2525       for ( ; image; image=image->next)
2526       {
2527         sv=newSViv((IV) (magick_uintptr_t)image);
2528         rv=newRV(sv);
2529         av_push(av,sv_bless(rv,hv));
2530         SvREFCNT_dec(sv);
2531         number_images++;
2532       }
2533     }
2534     DestroyExceptionInfo(&exception);
2535     /*
2536       Free resources.
2537     */
2538     for (i=0; i < n; i++)
2539       if (list[i])
2540         for (p=keep; list[i] != *p++; )
2541           if (*p == NULL)
2542             {
2543               MagickFreeMemory(list[i]);
2544               break;
2545             }
2546 
2547   ReturnIt:
2548     MagickFreeMemory(list);
2549     MagickFreeMemory(length);
2550     sv_setiv(MY_CXT.error_list,(IV) number_images);
2551     SvPOK_on(MY_CXT.error_list);
2552     ST(0)=sv_2mortal(MY_CXT.error_list);
2553     MY_CXT.error_list=NULL;
2554     MY_CXT.error_jump=NULL;
2555     XSRETURN(1);
2556   }
2557 
2558 #
2559 ###############################################################################
2560 #                                                                             #
2561 #                                                                             #
2562 #                                                                             #
2563 #   C o a l e s c e                                                           #
2564 #                                                                             #
2565 #                                                                             #
2566 #                                                                             #
2567 ###############################################################################
2568 #
2569 #
2570 void
Coalesce(ref)2571 Coalesce(ref)
2572   Graphics::Magick ref=NO_INIT
2573   ALIAS:
2574     CoalesceImage   = 1
2575     coalesce        = 2
2576     coalesceimage   = 3
2577   PPCODE:
2578   {
2579     AV
2580       *av;
2581 
2582     ExceptionInfo
2583       exception;
2584 
2585     HV
2586       *hv;
2587 
2588     jmp_buf
2589       error_jmp;
2590 
2591     Image
2592       *image;
2593 
2594     struct PackageInfo
2595       *info;
2596 
2597     SV
2598       *av_reference,
2599       *reference,
2600       *rv,
2601       *sv;
2602 
2603     volatile int
2604       status;
2605 
2606     dMY_CXT;
2607     MY_CXT.error_list=newSVpv("",0);
2608     status=0;
2609     if (!sv_isobject(ST(0)))
2610       {
2611         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2612         goto MethodException;
2613       }
2614     reference=SvRV(ST(0));
2615     hv=SvSTASH(reference);
2616     av=newAV();
2617     av_reference=sv_2mortal(sv_bless(newRV((SV *) av),hv));
2618     SvREFCNT_dec(av);
2619     MY_CXT.error_jump=(&error_jmp);
2620     status=setjmp(error_jmp);
2621     if (status)
2622       goto MethodException;
2623     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2624     if (!image)
2625       {
2626         MagickError(OptionError,NoImagesDefined,NULL);
2627         goto MethodException;
2628       }
2629     GetExceptionInfo(&exception);
2630     image=CoalesceImages(image,&exception);
2631     if (exception.severity != UndefinedException)
2632       CatchException(&exception);
2633     DestroyExceptionInfo(&exception);
2634     for ( ; image; image=image->next)
2635     {
2636       sv=newSViv((IV) (magick_uintptr_t)image);
2637       rv=newRV(sv);
2638       av_push(av,sv_bless(rv,hv));
2639       SvREFCNT_dec(sv);
2640     }
2641     ST(0)=av_reference;
2642     MY_CXT.error_jump=NULL;
2643     SvREFCNT_dec(MY_CXT.error_list);
2644     MY_CXT.error_list=NULL;
2645     XSRETURN(1);
2646 
2647   MethodException:
2648     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
2649     SvPOK_on(MY_CXT.error_list);
2650     ST(0)=sv_2mortal(MY_CXT.error_list);
2651     MY_CXT.error_list=NULL;
2652     MY_CXT.error_jump=NULL;
2653     XSRETURN(1);
2654   }
2655 
2656 #
2657 ###############################################################################
2658 #                                                                             #
2659 #                                                                             #
2660 #                                                                             #
2661 #   C o p y                                                                   #
2662 #                                                                             #
2663 #                                                                             #
2664 #                                                                             #
2665 ###############################################################################
2666 #
2667 #
2668 void
Copy(ref)2669 Copy(ref)
2670   Graphics::Magick ref=NO_INIT
2671   ALIAS:
2672     CopyImage   = 1
2673     copy        = 2
2674     copyimage   = 3
2675     CloneImage  = 4
2676     clone       = 5
2677     cloneimage  = 6
2678     Clone  = 7
2679   PPCODE:
2680   {
2681     AV
2682       *av;
2683 
2684     ExceptionInfo
2685       exception;
2686 
2687     HV
2688       *hv;
2689 
2690     Image
2691       *clone,
2692       *image;
2693 
2694     jmp_buf
2695       error_jmp;
2696 
2697     struct PackageInfo
2698       *info;
2699 
2700     SV
2701       *reference,
2702       *rv,
2703       *sv;
2704 
2705     volatile int
2706       status;
2707 
2708     dMY_CXT;
2709     MY_CXT.error_list=newSVpv("",0);
2710     status=0;
2711     if (!sv_isobject(ST(0)))
2712       {
2713         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2714         goto MethodException;
2715       }
2716     reference=SvRV(ST(0));
2717     hv=SvSTASH(reference);
2718     MY_CXT.error_jump=(&error_jmp);
2719     status=setjmp(error_jmp);
2720     if (status)
2721       goto MethodException;
2722     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2723     if (image == (Image *) NULL)
2724       {
2725         MagickError(OptionError,NoImagesDefined,NULL);
2726         goto MethodException;
2727       }
2728     /*
2729       Create blessed Perl array for the returned image.
2730     */
2731     av=newAV();
2732     ST(0)=sv_2mortal(sv_bless(newRV((SV *) av),hv));
2733     SvREFCNT_dec(av);
2734     GetExceptionInfo(&exception);
2735     for ( ; image; image=image->next)
2736     {
2737       clone=CloneImage(image,0,0,True,&exception);
2738       if (exception.severity != UndefinedException)
2739         CatchException(&exception);
2740       sv=newSViv((IV) (magick_uintptr_t)clone);
2741       rv=newRV(sv);
2742       av_push(av,sv_bless(rv,hv));
2743       SvREFCNT_dec(sv);
2744     }
2745     DestroyExceptionInfo(&exception);
2746     info=GetPackageInfo(aTHX_ (void *) av,info);
2747     SvREFCNT_dec(MY_CXT.error_list);
2748     MY_CXT.error_jump=NULL;
2749     XSRETURN(1);
2750 
2751   MethodException:
2752     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
2753     SvPOK_on(MY_CXT.error_list);
2754     ST(0)=sv_2mortal(MY_CXT.error_list);
2755     MY_CXT.error_list=NULL;
2756     MY_CXT.error_jump=NULL;
2757     XSRETURN(1);
2758   }
2759 
2760 #
2761 ###############################################################################
2762 #                                                                             #
2763 #                                                                             #
2764 #                                                                             #
2765 #   D e s t r o y                                                             #
2766 #                                                                             #
2767 #                                                                             #
2768 #                                                                             #
2769 ###############################################################################
2770 #
2771 #
2772 void
DESTROY(ref)2773 DESTROY(ref)
2774   Graphics::Magick ref=NO_INIT
2775   PPCODE:
2776   {
2777     SV
2778       *reference;
2779 
2780     if (!sv_isobject(ST(0)))
2781       croak("ReferenceIsNotMyType");
2782     reference=SvRV(ST(0));
2783     switch (SvTYPE(reference))
2784     {
2785       case SVt_PVAV:
2786       {
2787         char
2788           message[MaxTextExtent];
2789 
2790         struct PackageInfo
2791           *info;
2792 
2793         SV
2794           *sv;
2795 
2796         /*
2797           Array (AV *) reference
2798         */
2799         FormatString(message,"%s::Ref%lx_%s",PackageName,(long) reference,
2800           XS_VERSION);
2801         sv=perl_get_sv(message,FALSE);
2802         if (sv)
2803           {
2804             if ((SvREFCNT(sv) == 1) && SvIOK(sv) &&
2805                 (info=(struct PackageInfo *) (magick_uintptr_t)SvIV(sv)))
2806               {
2807                 DestroyPackageInfo(info);
2808                 sv_setiv(sv,0);
2809               }
2810           }
2811         break;
2812       }
2813       case SVt_PVMG:
2814       {
2815         Image
2816           *image;
2817 
2818         /*
2819           Blessed scalar = (Image *) SvIV(reference)
2820         */
2821         image=(Image *) (magick_uintptr_t)SvIV(reference);
2822         if (image)
2823           {
2824             if (image->previous && image->previous->next == image)
2825               image->previous->next=0;
2826             if (image->next && image->next->previous == image)
2827               image->next->previous=0;
2828             DestroyImage(image);
2829             sv_setiv(reference,0);
2830           }
2831         break;
2832       }
2833       default:
2834         break;
2835     }
2836   }
2837 
2838 #
2839 ###############################################################################
2840 #                                                                             #
2841 #                                                                             #
2842 #                                                                             #
2843 #   D i s p l a y                                                             #
2844 #                                                                             #
2845 #                                                                             #
2846 #                                                                             #
2847 ###############################################################################
2848 #
2849 #
2850 void
Display(ref,...)2851 Display(ref,...)
2852   Graphics::Magick ref=NO_INIT
2853   ALIAS:
2854     DisplayImage  = 1
2855     display       = 2
2856     displayimage  = 3
2857   PPCODE:
2858   {
2859     jmp_buf
2860       error_jmp;
2861 
2862     Image
2863       *image;
2864 
2865     register int
2866       i;
2867 
2868     struct PackageInfo
2869       *info,
2870       *package_info;
2871 
2872     SV
2873       *reference;
2874 
2875     volatile int
2876       status;
2877 
2878     dMY_CXT;
2879     MY_CXT.error_list=newSVpv("",0);
2880     status=0;
2881     package_info=(struct PackageInfo *) NULL;
2882     if (!sv_isobject(ST(0)))
2883       {
2884         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2885         goto MethodException;
2886       }
2887     reference=SvRV(ST(0));
2888     MY_CXT.error_jump=(&error_jmp);
2889     status=setjmp(error_jmp);
2890     if (status)
2891       goto MethodException;
2892     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2893     if (image == (Image *) NULL)
2894       {
2895         MagickError(OptionError,NoImagesDefined,NULL);
2896         goto MethodException;
2897       }
2898     package_info=ClonePackageInfo(info);
2899     if (items == 2)
2900       SetAttribute(aTHX_ package_info,NULL,"server",ST(1));
2901     else
2902       if (items > 2)
2903         for (i=2; i < items; i+=2)
2904           SetAttribute(aTHX_ package_info,image,SvPV(ST(i-1),na),ST(i));
2905     DisplayImages(package_info->image_info,image);
2906     (void) CatchImageException(image);
2907 
2908   MethodException:
2909     if (package_info)
2910       DestroyPackageInfo(package_info);
2911     sv_setiv(MY_CXT.error_list,(IV) status);
2912     SvPOK_on(MY_CXT.error_list);
2913     ST(0)=sv_2mortal(MY_CXT.error_list);
2914     MY_CXT.error_list=NULL;
2915     MY_CXT.error_jump=NULL;
2916     XSRETURN(1);
2917   }
2918 
2919 #
2920 ###############################################################################
2921 #                                                                             #
2922 #                                                                             #
2923 #                                                                             #
2924 #   F l a t t e n                                                             #
2925 #                                                                             #
2926 #                                                                             #
2927 #                                                                             #
2928 ###############################################################################
2929 #
2930 #
2931 void
Flatten(ref)2932 Flatten(ref)
2933   Graphics::Magick ref=NO_INIT
2934   ALIAS:
2935     FlattenImage   = 1
2936     flatten        = 2
2937     flattenimage   = 3
2938   PPCODE:
2939   {
2940     AV
2941       *av;
2942 
2943     char
2944       *p;
2945 
2946     ExceptionInfo
2947       exception;
2948 
2949     HV
2950       *hv;
2951 
2952     jmp_buf
2953       error_jmp;
2954 
2955     Image
2956       *image;
2957 
2958     struct PackageInfo
2959       *info;
2960 
2961     SV
2962       *reference,
2963       *rv,
2964       *sv;
2965 
2966     volatile int
2967       status;
2968 
2969     dMY_CXT;
2970     MY_CXT.error_list=newSVpv("",0);
2971     status=0;
2972     if (!sv_isobject(ST(0)))
2973       {
2974         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
2975         goto MethodException;
2976       }
2977     reference=SvRV(ST(0));
2978     hv=SvSTASH(reference);
2979     MY_CXT.error_jump=(&error_jmp);
2980     status=setjmp(error_jmp);
2981     if (status)
2982       goto MethodException;
2983     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
2984     if (!image)
2985       {
2986         MagickError(OptionError,NoImagesDefined,NULL);
2987         goto MethodException;
2988       }
2989     GetExceptionInfo(&exception);
2990     image=FlattenImages(image,&exception);
2991     if (exception.severity != UndefinedException)
2992       CatchException(&exception);
2993     DestroyExceptionInfo(&exception);
2994     /*
2995       Create blessed Perl array for the returned image.
2996     */
2997     av=newAV();
2998     ST(0)=sv_2mortal(sv_bless(newRV((SV *) av),hv));
2999     SvREFCNT_dec(av);
3000     sv=newSViv((IV) (magick_uintptr_t)image);
3001     rv=newRV(sv);
3002     av_push(av,sv_bless(rv,hv));
3003     SvREFCNT_dec(sv);
3004     info=GetPackageInfo(aTHX_ (void *) av,info);
3005     FormatString(info->image_info->filename,"average-%.*s",MaxTextExtent-9,
3006       ((p=strrchr(image->filename,'/')) ? p+1 : image->filename));
3007     (void) strncpy(image->filename,info->image_info->filename,MaxTextExtent-1);
3008     SetImageInfo(info->image_info,SETMAGICK_WRITE,&image->exception);
3009     SvREFCNT_dec(MY_CXT.error_list);
3010     MY_CXT.error_jump=NULL;
3011     XSRETURN(1);
3012 
3013   MethodException:
3014     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
3015     SvPOK_on(MY_CXT.error_list);  /* return messages in string context */
3016     ST(0)=sv_2mortal(MY_CXT.error_list);
3017     MY_CXT.error_list=NULL;
3018     MY_CXT.error_jump=NULL;
3019     XSRETURN(1);
3020   }
3021 
3022 #
3023 ###############################################################################
3024 #                                                                             #
3025 #                                                                             #
3026 #                                                                             #
3027 #   G e t                                                                     #
3028 #                                                                             #
3029 #                                                                             #
3030 #                                                                             #
3031 ###############################################################################
3032 #
3033 #
3034 void
Get(ref,...)3035 Get(ref,...)
3036   Graphics::Magick ref=NO_INIT
3037   ALIAS:
3038     GetAttributes = 1
3039     GetAttribute  = 2
3040     get           = 3
3041     getattributes = 4
3042     getattribute  = 5
3043   PPCODE:
3044   {
3045     char
3046       *attribute,
3047       color[MaxTextExtent];
3048 
3049     const ImageAttribute
3050       *image_attribute;
3051 
3052     Image
3053       *image;
3054 
3055     const unsigned char *
3056       profile_info;
3057 
3058     size_t
3059       profile_length;
3060 
3061     int
3062       j;
3063 
3064     register int
3065       i;
3066 
3067     struct PackageInfo
3068       *info;
3069 
3070     SV
3071       *reference,
3072       *s;
3073 
3074     if (!sv_isobject(ST(0)))
3075       {
3076         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
3077         XSRETURN_EMPTY;
3078       }
3079     reference=SvRV(ST(0));
3080     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
3081     if (!image && !info)
3082       {
3083         MagickError(OptionError,ReferenceIsNotMyType,NULL);
3084         XSRETURN_EMPTY;
3085       }
3086     EXTEND(sp,items);
3087     for (i=1; i < items; i++)
3088     {
3089       attribute=(char *) SvPV(ST(i),na);
3090       s=NULL;
3091       switch (*attribute)
3092       {
3093         case 'A':
3094         case 'a':
3095         {
3096           if (LocaleCompare(attribute,"adjoin") == 0)
3097             {
3098               if (info)
3099                 s=newSViv((long) info->image_info->adjoin);
3100               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3101               continue;
3102             }
3103           if (LocaleCompare(attribute,"antialias") == 0)
3104             {
3105               if (info)
3106                 s=newSViv((long) info->image_info->antialias);
3107               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3108               continue;
3109             }
3110           if (LocaleCompare(attribute,"authenticate") == 0)
3111             {
3112               if (info)
3113                 s=newSVpv(info->image_info->authenticate,0);
3114               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3115               continue;
3116             }
3117           MagickError(OptionError,UnrecognizedAttribute,attribute);
3118           break;
3119         }
3120         case 'B':
3121         case 'b':
3122         {
3123           if (LocaleCompare(attribute,"background") == 0)
3124             {
3125               if (!image)
3126                 break;
3127               FormatString(color,"%u,%u,%u,%u",image->background_color.red,
3128                 image->background_color.green,image->background_color.blue,
3129                 image->background_color.opacity);
3130               s=newSVpv(color,0);
3131               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3132               continue;
3133             }
3134           if (LocaleCompare(attribute,"base-columns") == 0)
3135             {
3136               if (image)
3137                 s=newSViv((long) image->magick_columns);
3138               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3139               continue;
3140             }
3141           if (LocaleCompare(attribute,"base-filename") == 0)
3142             {
3143               if (image)
3144                 s=newSVpv(image->magick_filename,0);
3145               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3146               continue;
3147             }
3148           if (LocaleCompare(attribute,"base-height") == 0)
3149             {
3150               if (image)
3151                 s=newSViv((long) image->magick_rows);
3152               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3153               continue;
3154             }
3155           if (LocaleCompare(attribute,"base-rows") == 0)
3156             {
3157               if (image)
3158                 s=newSViv((long) image->magick_rows);
3159               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3160               continue;
3161             }
3162           if (LocaleCompare(attribute,"base-width") == 0)
3163             {
3164               if (image)
3165                 s=newSViv((long) image->magick_columns);
3166               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3167               continue;
3168             }
3169           if (LocaleCompare(attribute,"blue-primary") == 0)
3170             {
3171               if (!image)
3172                 break;
3173               FormatString(color,"%g,%g",image->chromaticity.blue_primary.x,
3174                 image->chromaticity.blue_primary.y);
3175               s=newSVpv(color,0);
3176               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3177               continue;
3178             }
3179           if (LocaleCompare(attribute,"bordercolor") == 0)
3180             {
3181               if (!image)
3182                 break;
3183               FormatString(color,"%u,%u,%u,%u",image->border_color.red,
3184                 image->border_color.green,image->border_color.blue,
3185                 image->border_color.opacity);
3186               s=newSVpv(color,0);
3187               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3188               continue;
3189             }
3190           MagickError(OptionError,UnrecognizedAttribute,attribute);
3191           break;
3192         }
3193         case 'C':
3194         case 'c':
3195         {
3196           if (LocaleCompare(attribute,"class") == 0)
3197             {
3198               if (!image)
3199                 break;
3200 #if defined(__cplusplus) || defined(c_plusplus)
3201               j=image->c_class;
3202 #else
3203               j=image->storage_class;
3204 #endif
3205               s=newSViv(j);
3206               if ((j >= 0) && (j < (long) NumberOf(ClassTypes)-1))
3207                 {
3208                   (void) sv_setpv(s,ClassTypes[j]);
3209                   SvIOK_on(s);
3210                 }
3211               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3212               continue;
3213             }
3214           if (LocaleCompare(attribute,"clip-mask") == 0)
3215             {
3216               if (image)
3217                 {
3218                   SV
3219                     *sv;
3220 
3221                   if (GetImageClipMask(image,&image->exception) == (Image *) NULL)
3222                     ClipImage(image);
3223                   sv=newSViv((IV) (magick_uintptr_t)GetImageClipMask(image,&image->exception));
3224                   s=sv_bless(newRV(sv),SvSTASH(reference));
3225                 }
3226               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3227               continue;
3228             }
3229           if (LocaleCompare(attribute,"compression") == 0)
3230             {
3231               j=info ? info->image_info->compression : image->compression;
3232               if (info)
3233                 if (info->image_info->compression == UndefinedCompression)
3234                   j=image->compression;
3235               s=newSViv(j);
3236               if ((j >= 0) && (j < (long) NumberOf(CompressionTypes)-1))
3237                 {
3238                   (void) sv_setpv(s,CompressionTypes[j]);
3239                   SvIOK_on(s);
3240                 }
3241               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3242               continue;
3243             }
3244           if (LocaleCompare(attribute,"colorspace") == 0)
3245             {
3246               j=image ? image->colorspace : RGBColorspace;
3247               s=newSViv(j);
3248               if ((j >= 0) && (j < (long) NumberOf(ColorspaceTypes)-1))
3249                 {
3250                   (void) sv_setpv(s,ColorspaceTypes[j]);
3251                   SvIOK_on(s);
3252                 }
3253               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3254               continue;
3255             }
3256           if (LocaleCompare(attribute,"colors") == 0)
3257             {
3258               if (image)
3259                 s=newSViv((long) GetNumberColors(image,(FILE *) NULL,
3260                   &image->exception));
3261               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3262               continue;
3263             }
3264           if (LocaleNCompare(attribute,"colormap",8) == 0)
3265             {
3266               if (!image || !image->colormap)
3267                 break;
3268               j=0;
3269               (void) sscanf(attribute,"%*[^[][%d",&j);
3270               if (j > (long) image->colors)
3271                 j%=image->colors;
3272               FormatString(color,"%u,%u,%u,%u",image->colormap[j].red,
3273                 image->colormap[j].green,image->colormap[j].blue,
3274                 image->colormap[j].opacity);
3275               s=newSVpv(color,0);
3276               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3277               continue;
3278             }
3279           if (LocaleCompare(attribute,"columns") == 0)
3280             {
3281               if (image)
3282                 s=newSViv((long) image->columns);
3283               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3284               continue;
3285             }
3286           if (LocaleCompare(attribute,"comment") == 0)
3287             {
3288               const ImageAttribute
3289                 *attribute;
3290 
3291               attribute=GetImageAttribute(image,"comment");
3292               if (attribute != (ImageAttribute *) NULL)
3293                 s=newSVpv(attribute->value,0);
3294               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3295               continue;
3296             }
3297           MagickError(OptionError,UnrecognizedAttribute,attribute);
3298           break;
3299         }
3300         case 'D':
3301         case 'd':
3302         {
3303           if (LocaleCompare(attribute,"density") == 0)
3304             {
3305               char
3306                 geometry[MaxTextExtent];
3307 
3308               if (!image)
3309                 break;
3310               FormatString(geometry,"%gx%g",image->x_resolution,
3311                 image->y_resolution);
3312               s=newSVpv(geometry,0);
3313               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3314               continue;
3315             }
3316           if (LocaleCompare(attribute,"dispose") == 0)
3317             {
3318               if (!image)
3319                 break;
3320 
3321               j=image->dispose;
3322               s=newSViv(j);
3323               if ((j >= 0) && (j < (long) NumberOf(DisposeTypes)-1))
3324                 {
3325                   (void) sv_setpv(s,DisposeTypes[j]);
3326                   SvIOK_on(s);
3327                 }
3328               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3329               continue;
3330             }
3331           if (LocaleCompare(attribute,"delay") == 0)
3332             {
3333               if (image)
3334                 s=newSViv((long) image->delay);
3335               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3336               continue;
3337             }
3338           if (LocaleCompare(attribute,"depth") == 0)
3339             {
3340               if (info)
3341                 s=newSViv((long) info->image_info->depth);
3342               if (image)
3343                 s=newSViv((long) GetImageDepth(image,&image->exception));
3344               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3345               continue;
3346             }
3347           if (LocaleCompare(attribute,"dither") == 0)
3348             {
3349               if (info)
3350                 s=newSViv((long) info->image_info->dither);
3351               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3352               continue;
3353             }
3354           if (LocaleCompare(attribute,"display") == 0)  /* same as server */
3355             {
3356               if (info && info->image_info->server_name)
3357                 s=newSVpv(info->image_info->server_name,0);
3358               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3359               continue;
3360             }
3361           if (LocaleCompare(attribute,"directory") == 0)
3362             {
3363               if (image && image->directory)
3364                 s=newSVpv(image->directory,0);
3365               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3366               continue;
3367             }
3368           MagickError(OptionError,UnrecognizedAttribute,attribute);
3369           break;
3370         }
3371         case 'E':
3372         case 'e':
3373         {
3374           if (LocaleCompare(attribute,"endian") == 0)
3375             {
3376               j=info ? info->image_info->endian : image->endian;
3377               s=newSViv(j);
3378               if ((j >= 0) && (j < (long) NumberOf(EndianTypes)-1))
3379                 {
3380                   (void) sv_setpv(s,EndianTypes[j]);
3381                   SvIOK_on(s);
3382                 }
3383               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3384               continue;
3385             }
3386           if (LocaleCompare(attribute,"error") == 0)
3387             {
3388               if (image)
3389                 s=newSVnv(image->error.mean_error_per_pixel);
3390               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3391               continue;
3392             }
3393           MagickError(OptionError,UnrecognizedAttribute,attribute);
3394           break;
3395         }
3396         case 'F':
3397         case 'f':
3398         {
3399           if (LocaleCompare(attribute,"filesize") == 0)
3400             {
3401               if (image)
3402                 s=newSViv((long) GetBlobSize(image));
3403               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3404               continue;
3405             }
3406           if (LocaleCompare(attribute,"filename") == 0)
3407             {
3408               if (image)
3409                 s=newSVpv(image->filename,0);
3410               else
3411                 if (info && info->image_info->filename[0])
3412                   s=newSVpv(info->image_info->filename,0);
3413               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3414               continue;
3415             }
3416           if (LocaleCompare(attribute,"filter") == 0)
3417             {
3418               j=image->filter;
3419               s=newSViv(j);
3420               if ((j >= 0) && (j < (long) NumberOf(FilterTypess)-1))
3421                 {
3422                   (void) sv_setpv(s,FilterTypess[j]);
3423                   SvIOK_on(s);
3424                 }
3425               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3426               continue;
3427             }
3428           if (LocaleCompare(attribute,"font") == 0)
3429             {
3430               if (info && info->image_info->font)
3431                 s=newSVpv(info->image_info->font,0);
3432               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3433               continue;
3434             }
3435           if (LocaleCompare(attribute,"format") == 0)
3436             {
3437               ExceptionInfo
3438                 exception;
3439 
3440               const MagickInfo
3441                 *magick_info;
3442 
3443               magick_info=(const MagickInfo *) NULL;
3444               if (info && (*info->image_info->magick != '\0'))
3445                 {
3446                   GetExceptionInfo(&exception);
3447                   magick_info=
3448                     GetMagickInfo(info->image_info->magick,&exception);
3449                   DestroyExceptionInfo(&exception);
3450                 }
3451               else
3452                 if (image)
3453                   magick_info=GetMagickInfo(image->magick,&image->exception);
3454                 if ((magick_info != (const MagickInfo *) NULL) &&
3455                     (*magick_info->description != '\0'))
3456                   s=newSVpv((char *) magick_info->description,0);
3457               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3458               continue;
3459             }
3460           if (LocaleCompare(attribute,"fuzz") == 0)
3461             {
3462               if (info)
3463                 s=newSVnv(info->image_info->fuzz);
3464               else
3465                 if (image)
3466                   s=newSVnv(image->fuzz);
3467               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3468               continue;
3469             }
3470           MagickError(OptionError,UnrecognizedAttribute,attribute);
3471           break;
3472         }
3473         case 'G':
3474         case 'g':
3475         {
3476           if (LocaleCompare(attribute,"gamma") == 0)
3477             {
3478               if (image)
3479                 s=newSVnv(image->gamma);
3480               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3481               continue;
3482             }
3483           if (LocaleCompare(attribute,"geometry") == 0)
3484             {
3485               if (image && image->geometry)
3486                 s=newSVpv(image->geometry,0);
3487               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3488               continue;
3489             }
3490           if (LocaleCompare(attribute,"gravity") == 0)
3491             {
3492               j=image->gravity;
3493               s=newSViv(j);
3494               if ((j >= 0) && (j < (long) NumberOf(GravityTypes)-1))
3495                 {
3496                   (void) sv_setpv(s,GravityTypes[j]);
3497                   SvIOK_on(s);
3498                 }
3499               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3500               continue;
3501             }
3502           if (LocaleCompare(attribute,"green-primary") == 0)
3503             {
3504               if (!image)
3505                 break;
3506               FormatString(color,"%g,%g",image->chromaticity.green_primary.x,
3507                 image->chromaticity.green_primary.y);
3508               s=newSVpv(color,0);
3509               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3510               continue;
3511             }
3512           MagickError(OptionError,UnrecognizedAttribute,attribute);
3513           break;
3514         }
3515         case 'H':
3516         case 'h':
3517         {
3518           if (LocaleCompare(attribute,"height") == 0)
3519             {
3520               if (image)
3521                 s=newSViv((long) image->rows);
3522               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3523               continue;
3524             }
3525           MagickError(OptionError,UnrecognizedAttribute,attribute);
3526           break;
3527         }
3528         case 'I':
3529         case 'i':
3530         {
3531           if (LocaleCompare(attribute,"icm") == 0)
3532             {
3533               if (image)
3534                 {
3535                   profile_info=GetImageProfile(image,"ICM",&profile_length);
3536                   s=newSVpv((const char *) profile_info,profile_length);
3537                 }
3538               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3539               continue;
3540             }
3541           if (LocaleCompare(attribute,"id") == 0)
3542             {
3543               if (image)
3544                 s=newSViv(SetMagickRegistry(ImageRegistryType,image,0,
3545                   &image->exception));
3546               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3547               continue;
3548             }
3549           if (LocaleNCompare(attribute,"index",5) == 0)
3550             {
3551               char
3552                 name[MaxTextExtent];
3553 
3554               const IndexPacket
3555                 *indexes;
3556 
3557               long
3558                 x,
3559                 y;
3560 
3561               if (!image)
3562                 break;
3563               if (image->storage_class != PseudoClass)
3564                 break;
3565               x=0;
3566               y=0;
3567               (void) sscanf(attribute,"%*[^[][%ld%*[,/]%ld",&x,&y);
3568               (void) AcquireImagePixels(image,(long) (x % image->columns),
3569                                         (long) (y % image->rows),1,1,&image->exception);
3570               indexes=AccessImmutableIndexes(image);
3571               FormatString(name,"%u",*indexes);
3572               s=newSVpv(name,0);
3573               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3574               continue;
3575             }
3576           if (LocaleCompare(attribute,"iptc") == 0)
3577             {
3578               if (image)
3579                 {
3580                   profile_info=GetImageProfile(image,"IPTC",&profile_length);
3581                   s=newSVpv((const char *) profile_info,profile_length);
3582                 }
3583               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3584               continue;
3585             }
3586           if (LocaleCompare(attribute,"iterations") == 0)  /* same as loop */
3587             {
3588               if (image)
3589                 s=newSViv((long) image->iterations);
3590               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3591               continue;
3592             }
3593           if (LocaleCompare(attribute,"interlace") == 0)
3594             {
3595               j=info ? info->image_info->interlace : image->interlace;
3596               s=newSViv(j);
3597               if ((j >= 0) && (j < (long) NumberOf(InterlaceTypes)-1))
3598                 {
3599                   (void) sv_setpv(s,InterlaceTypes[j]);
3600                   SvIOK_on(s);
3601                 }
3602               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3603               continue;
3604             }
3605           MagickError(OptionError,UnrecognizedAttribute,attribute);
3606           break;
3607         }
3608         case 'L':
3609         case 'l':
3610         {
3611           if (LocaleCompare(attribute,"label") == 0)
3612             {
3613               const ImageAttribute
3614                 *attribute;
3615 
3616               if (!image)
3617                 break;
3618               attribute=GetImageAttribute(image,"label");
3619               if (attribute != (ImageAttribute *) NULL)
3620                 s=newSVpv(attribute->value,0);
3621               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3622               continue;
3623             }
3624           if (LocaleCompare(attribute,"loop") == 0)  /* same as iterations */
3625             {
3626               if (image)
3627                 s=newSViv((long) image->iterations);
3628               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3629               continue;
3630             }
3631           MagickError(OptionError,UnrecognizedAttribute,attribute);
3632           break;
3633         }
3634         case 'M':
3635         case 'm':
3636         {
3637           if (LocaleCompare(attribute,"magick") == 0)
3638             {
3639               if (info && *info->image_info->magick)
3640                 s=newSVpv(info->image_info->magick,0);
3641               else
3642                 if (image)
3643                   s=newSVpv(image->magick,0);
3644               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3645               continue;
3646             }
3647           if (LocaleCompare(attribute,"maximum-error") == 0)
3648             {
3649               if (image)
3650                 s=newSVnv(image->error.normalized_maximum_error);
3651               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3652               continue;
3653             }
3654           if (LocaleCompare(attribute,"mean-error") == 0)
3655             {
3656               if (image)
3657                 s=newSVnv(image->error.normalized_mean_error);
3658               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3659               continue;
3660             }
3661           if (LocaleCompare(attribute,"monochrome") == 0)
3662             {
3663               if (!image)
3664                 continue;
3665               j=info ? info->image_info->monochrome :
3666                 IsMonochromeImage(image,&image->exception);
3667               s=newSViv(j);
3668               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3669               continue;
3670             }
3671           if (LocaleCompare(attribute,"mattecolor") == 0)
3672             {
3673               if (!image)
3674                 break;
3675               FormatString(color,"%u,%u,%u,%u",image->matte_color.red,
3676                 image->matte_color.green,image->matte_color.blue,
3677                 image->matte_color.opacity);
3678               s=newSVpv(color,0);
3679               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3680               continue;
3681             }
3682           if (LocaleCompare(attribute,"matte") == 0)
3683             {
3684               if (image)
3685                 s=newSViv((long) image->matte);
3686               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3687               continue;
3688             }
3689           if (LocaleCompare(attribute,"montage") == 0)
3690             {
3691               if (image && image->montage)
3692                 s=newSVpv(image->montage,0);
3693               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3694               continue;
3695             }
3696           MagickError(OptionError,UnrecognizedAttribute,attribute);
3697           break;
3698         }
3699         case 'P':
3700         case 'p':
3701         {
3702           if (LocaleCompare(attribute,"page") == 0)
3703             {
3704               if (info && info->image_info->page)
3705                 s=newSVpv(info->image_info->page,0);
3706               else
3707                 if (image)
3708                   {
3709                     char
3710                       geometry[MaxTextExtent];
3711 
3712                     FormatString(geometry,"%lux%lu%+ld%+ld",image->page.width,
3713                       image->page.height,image->page.x,image->page.y);
3714                     s=newSVpv(geometry,0);
3715                   }
3716               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3717               continue;
3718             }
3719           if (LocaleNCompare(attribute,"pixel",5) == 0)
3720             {
3721               char
3722                 name[MaxTextExtent];
3723 
3724               long
3725                 x,
3726                 y;
3727 
3728               PixelPacket
3729                 pixel;
3730 
3731               if (!image)
3732                 break;
3733               x=0;
3734               y=0;
3735               (void) sscanf(attribute,"%*[^[][%ld%*[,/]%ld",&x,&y);
3736               (void) AcquireOnePixelByReference(image,&pixel,(long) (x % image->columns),
3737                 (long) (y % image->rows),&image->exception);
3738               FormatString(name,"%u,%u,%u,%u",pixel.red,pixel.green,pixel.blue,
3739                 pixel.opacity);
3740               s=newSVpv(name,0);
3741               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3742               continue;
3743             }
3744           if (LocaleCompare(attribute,"pointsize") == 0)
3745             {
3746               if (info)
3747                 s=newSViv((long) info->image_info->pointsize);
3748               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3749               continue;
3750             }
3751           if (LocaleCompare(attribute,"preview") == 0)
3752             {
3753               s=newSViv(info->image_info->preview_type);
3754               if ((info->image_info->preview_type != UndefinedPreview) &&
3755                   (info->image_info->preview_type < (long) NumberOf(PreviewTypes)-1))
3756                 {
3757                   (void) sv_setpv(s,
3758                     PreviewTypes[info->image_info->preview_type]);
3759                   SvIOK_on(s);
3760                 }
3761               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3762               continue;
3763             }
3764           MagickError(OptionError,UnrecognizedAttribute,attribute);
3765           break;
3766         }
3767         case 'Q':
3768         case 'q':
3769         {
3770           if (LocaleCompare(attribute,"quality") == 0)
3771             {
3772               if (info)
3773                 s=newSViv((long) info->image_info->quality);
3774               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3775               continue;
3776             }
3777           MagickError(OptionError,UnrecognizedAttribute,attribute);
3778           break;
3779         }
3780         case 'R':
3781         case 'r':
3782         {
3783           if (LocaleCompare(attribute,"rendering-intent") == 0)
3784             {
3785               j=image->rendering_intent;
3786               s=newSViv(j);
3787               if ((j >= 0) && (j < (long) NumberOf(IntentTypes)-1))
3788                 {
3789                   (void) sv_setpv(s,IntentTypes[j]);
3790                   SvIOK_on(s);
3791                 }
3792               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3793               continue;
3794             }
3795           if (LocaleCompare(attribute,"red-primary") == 0)
3796             {
3797               if (!image)
3798                 break;
3799               FormatString(color,"%g,%g",image->chromaticity.red_primary.x,
3800                 image->chromaticity.red_primary.y);
3801               s=newSVpv(color,0);
3802               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3803               continue;
3804             }
3805           if (LocaleCompare(attribute,"rows") == 0)
3806             {
3807               if (image)
3808                 s=newSViv((long) image->rows);
3809               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3810               continue;
3811             }
3812           MagickError(OptionError,UnrecognizedAttribute,attribute);
3813           break;
3814         }
3815         case 'S':
3816         case 's':
3817         {
3818           if (LocaleCompare(attribute,"sampling-factor") == 0)
3819             {
3820               if (info && info->image_info->sampling_factor)
3821                 s=newSVpv(info->image_info->sampling_factor,0);
3822               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3823               continue;
3824             }
3825           if (LocaleCompare(attribute,"subimage") == 0)
3826             {
3827               if (info)
3828                 s=newSViv((long) info->image_info->subimage);
3829               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3830               continue;
3831             }
3832           if (LocaleCompare(attribute,"subrange") == 0)
3833             {
3834               if (info)
3835                 s=newSViv((long) info->image_info->subrange);
3836               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3837               continue;
3838             }
3839           if (LocaleCompare(attribute,"server") == 0)  /* same as display */
3840             {
3841               if (info && info->image_info->server_name)
3842                 s=newSVpv(info->image_info->server_name,0);
3843               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3844               continue;
3845             }
3846           if (LocaleCompare(attribute,"size") == 0)
3847             {
3848               if (info && info->image_info->size)
3849                 s=newSVpv(info->image_info->size,0);
3850               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3851               continue;
3852             }
3853           if (LocaleCompare(attribute,"scene") == 0)
3854             {
3855               if (image)
3856                 s=newSViv((long) image->scene);
3857               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3858               continue;
3859             }
3860           if (LocaleCompare(attribute,"signature") == 0)
3861             {
3862               const ImageAttribute
3863                 *attribute;
3864 
3865               if (!image)
3866                 break;
3867               (void) SignatureImage(image);
3868               attribute=GetImageAttribute(image,"signature");
3869               if (attribute != (ImageAttribute *) NULL)
3870                 s=newSVpv(attribute->value,0);
3871               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3872               continue;
3873             }
3874           MagickError(OptionError,UnrecognizedAttribute,attribute);
3875           break;
3876         }
3877         case 'T':
3878         case 't':
3879         {
3880           if (LocaleCompare(attribute,"taint") == 0)
3881             {
3882               if (image)
3883                 s=newSViv((long) IsTaintImage(image));
3884               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3885               continue;
3886             }
3887           if (LocaleCompare(attribute,"tile") == 0)
3888             {
3889               if (info && info->image_info->tile)
3890                 s=newSVpv(info->image_info->tile,0);
3891               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3892               continue;
3893             }
3894           if (LocaleCompare(attribute,"texture") == 0)
3895             {
3896               if (info && info->image_info->texture)
3897                 s=newSVpv(info->image_info->texture,0);
3898               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3899               continue;
3900             }
3901           if (LocaleCompare(attribute,"type") == 0)
3902             {
3903               if (!image)
3904                 break;
3905               j=(long) GetImageType(image,&image->exception);
3906               s=newSViv(j);
3907               if ((j >= 0) && (j < (long) NumberOf(ImageTypes)-1))
3908                 {
3909                   (void) sv_setpv(s,ImageTypes[j]);
3910                   SvIOK_on(s);
3911                 }
3912               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3913               continue;
3914             }
3915           MagickError(OptionError,UnrecognizedAttribute,attribute);
3916           break;
3917         }
3918         case 'U':
3919         case 'u':
3920         {
3921           if (LocaleCompare(attribute,"units") == 0)
3922             {
3923               j=info ? info->image_info->units : image->units;
3924               if (info)
3925                 if (info->image_info->units == UndefinedResolution)
3926                   j=image->units;
3927               if (j == UndefinedResolution)
3928                 s=newSVpv("undefined units",0);
3929               else
3930                 if (j == PixelsPerInchResolution)
3931                   s=newSVpv("pixels / inch",0);
3932                 else
3933                   s=newSVpv("pixels / centimeter",0);
3934               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3935               continue;
3936             }
3937           MagickError(OptionError,UnrecognizedAttribute,attribute);
3938           break;
3939         }
3940         case 'V':
3941         case 'v':
3942         {
3943           if (LocaleCompare(attribute,"verbose") == 0)
3944             {
3945               if (info)
3946                 s=newSViv((long) info->image_info->verbose);
3947               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3948               continue;
3949             }
3950           if (LocaleCompare(attribute,"view") == 0)
3951             {
3952               if (info && info->image_info->view)
3953                 s=newSVpv(info->image_info->view,0);
3954               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3955               continue;
3956             }
3957           if (LocaleCompare(attribute,"virtual-pixel") == 0)
3958             {
3959               if (!image)
3960                 break;
3961               j=(long) GetImageVirtualPixelMethod(image);
3962               s=newSViv(j);
3963               if ((j >= 0) && (j < (long) NumberOf(VirtualPixelMethods)-1))
3964                 {
3965                   (void) sv_setpv(s,VirtualPixelMethods[j]);
3966                   SvIOK_on(s);
3967                 }
3968               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3969               continue;
3970             }
3971           MagickError(OptionError,UnrecognizedAttribute,attribute);
3972           break;
3973         }
3974         case 'W':
3975         case 'w':
3976         {
3977           if (LocaleCompare(attribute,"white-point") == 0)
3978             {
3979               if (!image)
3980                 break;
3981               FormatString(color,"%g,%g",image->chromaticity.white_point.x,
3982                 image->chromaticity.white_point.y);
3983               s=newSVpv(color,0);
3984               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3985               continue;
3986             }
3987           if (LocaleCompare(attribute,"width") == 0)
3988             {
3989               if (image)
3990                 s=newSViv((long) image->columns);
3991               PUSHs(s ? sv_2mortal(s) : &sv_undef);
3992               continue;
3993             }
3994           MagickError(OptionError,UnrecognizedAttribute,attribute);
3995           break;
3996         }
3997         case 'X':
3998         case 'x':
3999         {
4000           if (LocaleCompare(attribute,"x-resolution") == 0)
4001             {
4002               if (image)
4003                 s=newSVnv(image->x_resolution);
4004               PUSHs(s ? sv_2mortal(s) : &sv_undef);
4005               continue;
4006             }
4007           MagickError(OptionError,UnrecognizedAttribute,attribute);
4008           break;
4009         }
4010         case 'Y':
4011         case 'y':
4012         {
4013           if (LocaleCompare(attribute,"y-resolution") == 0)
4014             {
4015               if (image)
4016                 s=newSVnv(image->y_resolution);
4017               PUSHs(s ? sv_2mortal(s) : &sv_undef);
4018               continue;
4019             }
4020           MagickError(OptionError,UnrecognizedAttribute,attribute);
4021           break;
4022         }
4023         default:
4024         {
4025           MagickError(OptionError,UnrecognizedAttribute,attribute);
4026           break;
4027         }
4028       }
4029       if (image == (Image *) NULL)
4030         MagickError(OptionError,UnrecognizedAttribute,attribute);
4031       else
4032         {
4033           image_attribute=GetImageAttribute(image,attribute);
4034           if (image_attribute == (ImageAttribute *) NULL)
4035             MagickError(OptionError,UnrecognizedAttribute,attribute);
4036           else
4037             {
4038               s=newSVpv(image_attribute->value,0);
4039               PUSHs(s ? sv_2mortal(s) : &sv_undef);
4040             }
4041         }
4042     }
4043   }
4044 
4045 #
4046 ###############################################################################
4047 #                                                                             #
4048 #                                                                             #
4049 #                                                                             #
4050 #   I m a g e T o B l o b                                                     #
4051 #                                                                             #
4052 #                                                                             #
4053 #                                                                             #
4054 ###############################################################################
4055 #
4056 #
4057 void
ImageToBlob(ref,...)4058 ImageToBlob(ref,...)
4059   Graphics::Magick ref=NO_INIT
4060   ALIAS:
4061     ImageToBlob  = 1
4062     imagetoblob  = 2
4063     toblob       = 3
4064     blob         = 4
4065   PPCODE:
4066   {
4067     char
4068       filename[MaxTextExtent];
4069 
4070     ExceptionInfo
4071       exception;
4072 
4073     Image
4074       *image,
4075       *next;
4076 
4077     int
4078       scene;
4079 
4080     register int
4081       i;
4082 
4083     jmp_buf
4084       error_jmp;
4085 
4086     struct PackageInfo
4087       *info,
4088       *package_info;
4089 
4090     size_t
4091       length;
4092 
4093     SV
4094       *reference;
4095 
4096     void
4097       *blob;
4098 
4099     dMY_CXT;
4100     MY_CXT.error_list=newSVpv("",0);
4101     package_info=(struct PackageInfo *) NULL;
4102     if (!sv_isobject(ST(0)))
4103       {
4104         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
4105         goto MethodException;
4106       }
4107     reference=SvRV(ST(0));
4108     MY_CXT.error_jump=(&error_jmp);
4109     if (setjmp(error_jmp))
4110       goto MethodException;
4111     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
4112     if (!image)
4113       {
4114         MagickError(OptionError,NoImagesDefined,NULL);
4115         goto MethodException;
4116       }
4117     package_info=ClonePackageInfo(info);
4118     for (i=2; i < items; i+=2)
4119       SetAttribute(aTHX_ package_info,image,SvPV(ST(i-1),na),ST(i));
4120     (void) strncpy(filename,package_info->image_info->filename,MaxTextExtent-1);
4121     scene=0;
4122     for (next=image; next; next=next->next)
4123     {
4124       (void) strncpy(next->filename,filename,MaxTextExtent-1);
4125       next->scene=scene++;
4126     }
4127     SetImageInfo(package_info->image_info,SETMAGICK_WRITE,&image->exception);
4128     EXTEND(sp,(long) GetImageListLength(image));
4129     GetExceptionInfo(&exception);
4130     for ( ; image; image=image->next)
4131     {
4132       length=0;
4133       blob=ImageToBlob(package_info->image_info,image,&length,&exception);
4134       if (exception.severity != UndefinedException)
4135         CatchException(&exception);
4136       if (blob != (char *) NULL)
4137         {
4138           PUSHs(sv_2mortal(newSVpv((const char *) blob,length)));
4139           MagickFreeMemory(blob);
4140         }
4141       if (package_info->image_info->adjoin)
4142         break;
4143     }
4144     DestroyExceptionInfo(&exception);
4145 
4146   MethodException:
4147     if (package_info)
4148       DestroyPackageInfo(package_info);
4149     SvREFCNT_dec(MY_CXT.error_list);  /* throw away all errors */
4150     MY_CXT.error_list=NULL;
4151   }
4152 
4153 #
4154 ###############################################################################
4155 #                                                                             #
4156 #                                                                             #
4157 #                                                                             #
4158 #   M o g r i f y                                                             #
4159 #                                                                             #
4160 #                                                                             #
4161 #                                                                             #
4162 ###############################################################################
4163 #
4164 #
4165 void
Mogrify(ref,...)4166 Mogrify(ref,...)
4167   Graphics::Magick ref=NO_INIT
4168   ALIAS:
4169     Comment            =   1
4170     CommentImage       =   2
4171     Label              =   3
4172     LabelImage         =   4
4173     AddNoise           =   5
4174     AddNoiseImage      =   6
4175     Colorize           =   7
4176     ColorizeImage      =   8
4177     Border             =   9
4178     BorderImage        =  10
4179     Blur               =  11
4180     BlurImage          =  12
4181     Chop               =  13
4182     ChopImage          =  14
4183     Crop               =  15
4184     CropImage          =  16
4185     Despeckle          =  17
4186     DespeckleImage     =  18
4187     Edge               =  19
4188     EdgeImage          =  20
4189     Emboss             =  21
4190     EmbossImage        =  22
4191     Enhance            =  23
4192     EnhanceImage       =  24
4193     Flip               =  25
4194     FlipImage          =  26
4195     Flop               =  27
4196     FlopImage          =  28
4197     Frame              =  29
4198     FrameImage         =  30
4199     Implode            =  31
4200     ImplodeImage       =  32
4201     Magnify            =  33
4202     MagnifyImage       =  34
4203     MedianFilter       =  35
4204     MedianFilterImage  =  36
4205     Minify             =  37
4206     MinifyImage        =  38
4207     OilPaint           =  39
4208     OilPaintImage      =  40
4209     ReduceNoise        =  41
4210     ReduceNoiseImage   =  42
4211     Roll               =  43
4212     RollImage          =  44
4213     Rotate             =  45
4214     RotateImage        =  46
4215     Sample             =  47
4216     SampleImage        =  48
4217     Scale              =  49
4218     ScaleImage         =  50
4219     Shade              =  51
4220     ShadeImage         =  52
4221     Sharpen            =  53
4222     SharpenImage       =  54
4223     Shear              =  55
4224     ShearImage         =  56
4225     Spread             =  57
4226     SpreadImage        =  58
4227     Swirl              =  59
4228     SwirlImage         =  60
4229     Resize             =  61
4230     ResizeImage        =  62
4231     Zoom               =  63
4232     ZoomImage          =  64
4233     Annotate           =  65
4234     AnnotateImage      =  66
4235     ColorFloodfill     =  67
4236     ColorFloodfillImage=  68
4237     Composite          =  69
4238     CompositeImage     =  70
4239     Contrast           =  71
4240     ContrastImage      =  72
4241     CycleColormap      =  73
4242     CycleColormapImage =  74
4243     Draw               =  75
4244     DrawImage          =  76
4245     Equalize           =  77
4246     EqualizeImage      =  78
4247     Gamma              =  79
4248     GammaImage         =  80
4249     Map                =  81
4250     MapImage           =  82
4251     MatteFloodfill     =  83
4252     MatteFloodfillImage=  84
4253     Modulate           =  85
4254     ModulateImage      =  86
4255     Negate             =  87
4256     NegateImage        =  88
4257     Normalize          =  89
4258     NormalizeImage     =  90
4259     NumberColors       =  91
4260     NumberColorsImage  =  92
4261     Opaque             =  93
4262     OpaqueImage        =  94
4263     Quantize           =  95
4264     QuantizeImage      =  96
4265     Raise              =  97
4266     RaiseImage         =  98
4267     Segment            =  99
4268     SegmentImage       = 100
4269     Signature          = 101
4270     SignatureImage     = 102
4271     Solarize           = 103
4272     SolarizeImage      = 104
4273     Sync               = 105
4274     SyncImage          = 106
4275     Texture            = 107
4276     TextureImage       = 108
4277     Sans               = 109
4278     SansImage          = 110
4279     Transparent        = 111
4280     TransparentImage   = 112
4281     Threshold          = 113
4282     ThresholdImage     = 114
4283     Charcoal           = 115
4284     CharcoalImage      = 116
4285     Trim               = 117
4286     TrimImage          = 118
4287     Wave               = 119
4288     WaveImage          = 120
4289     Channel            = 121
4290     ChannelImage       = 122
4291     Stereo             = 125
4292     StereoImage        = 126
4293     Stegano            = 127
4294     SteganoImage       = 128
4295     Deconstruct        = 129
4296     DeconstructImage   = 130
4297     GaussianBlur       = 131
4298     GaussianBlurImage  = 132
4299     Convolve           = 133
4300     ConvolveImage      = 134
4301     Profile            = 135
4302     ProfileImage       = 136
4303     UnsharpMask        = 137
4304     UnsharpMaskImage   = 138
4305     MotionBlur         = 139
4306     MotionBlurImage    = 140
4307     OrderedDither      = 141
4308     OrderedDitherImage = 142
4309     Shave              = 143
4310     ShaveImage         = 144
4311     Level              = 145
4312     LevelImage         = 146
4313     Clip               = 147
4314     ClipImage          = 148
4315     AffineTransform    = 149
4316     AffineTransformImage = 150
4317     Compare            = 151
4318     CompareImage       = 152
4319     AdaptiveThreshold  = 153
4320     AdaptiveThresholdImage = 154
4321     MogrifyRegion      = 666
4322   PPCODE:
4323   {
4324     AffineMatrix
4325       affine,
4326       current;
4327 
4328     char
4329       *attribute,
4330       /* absolute_geometry[MaxTextExtent], */
4331       attribute_flag[MaxArguments],
4332       message[MaxTextExtent],
4333       *value;
4334 
4335     double
4336       angle;
4337 
4338     ExceptionInfo
4339       exception;
4340 
4341     FrameInfo
4342       frame_info;
4343 
4344     jmp_buf
4345       error_jmp;
4346 
4347     Image
4348       *image,
4349       *next,
4350       *region_image;
4351 
4352     int
4353       base,
4354       flags,
4355       j,
4356       k,
4357       y;
4358 
4359     PixelPacket
4360       fill_color;
4361 
4362     RectangleInfo
4363       geometry,
4364       region_info;
4365 
4366     register int
4367       i,
4368       x;
4369 
4370     struct PackageInfo
4371       *info;
4372 
4373     struct Methods
4374       *rp;
4375 
4376     SV
4377       **pv,
4378       *reference,
4379       **reference_vector;
4380 
4381     struct ArgumentList
4382       argument_list[MaxArguments];
4383 
4384     volatile int
4385       number_images;
4386 
4387     dMY_CXT;
4388     MY_CXT.error_list=newSVpv("",0);
4389     reference_vector=NULL;
4390     region_image=NULL;
4391     number_images=0;
4392     base=2;
4393     if (!sv_isobject(ST(0)))
4394       {
4395         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
4396         goto ReturnIt;
4397       }
4398     reference=SvRV(ST(0));
4399     region_info.width=0;
4400     region_info.height=0;
4401     region_info.x=0;
4402     region_info.y=0;
4403     region_image=(Image *) NULL;
4404     image=SetupList(aTHX_ reference,&info,&reference_vector);
4405     if (ix && (ix != 666))
4406       {
4407         /*
4408           Called as Method(...)
4409         */
4410         ix=(ix+1)/2;
4411         rp=(&Methods[ix-1]);
4412         attribute=rp->name;
4413       }
4414     else
4415       {
4416         /*
4417           Called as Mogrify("Method",...)
4418         */
4419         attribute=(char *) SvPV(ST(1),na);
4420         if (ix)
4421           {
4422             /*flags=*/GetImageGeometry(image,attribute,False,&region_info);
4423             attribute=(char *) SvPV(ST(2),na);
4424             base++;
4425           }
4426         for (rp=Methods; ; rp++)
4427         {
4428           if (rp >= EndOf(Methods))
4429             {
4430               MagickError(OptionError,UnrecognizedPerlMagickMethod,attribute);
4431               goto ReturnIt;
4432             }
4433           if (strEQcase(attribute,rp->name))
4434             break;
4435         }
4436         ix=rp-Methods+1;
4437         base++;
4438       }
4439     if (!image)
4440       {
4441         MagickError(OptionError,NoImagesDefined,attribute);
4442         goto ReturnIt;
4443       }
4444     Zero(&argument_list,NumberOf(argument_list),struct ArgumentList);
4445     Zero(&attribute_flag,NumberOf(attribute_flag),char);
4446     for (i=base; (i < items) || ((i == items) && (base == items)); i+=2)
4447     {
4448       int
4449         longest;
4450 
4451       Arguments
4452         *pp,
4453         *qq;
4454 
4455       struct ArgumentList
4456         *al;
4457 
4458       SV
4459         *sv;
4460 
4461       longest=0;
4462       pp=(Arguments *) NULL;
4463       qq=rp->arguments;
4464       if (i == items)
4465         {
4466           pp=rp->arguments,
4467           sv=ST(i-1);
4468         }
4469       else
4470         for (sv=ST(i), attribute=(char *) SvPV(ST(i-1),na); ; qq++)
4471         {
4472           if ((qq >= EndOf(rp->arguments)) || (qq->method == NULL))
4473             break;
4474           if (strEQcase(attribute,qq->method) > longest)
4475             {
4476               pp=qq;
4477               longest=strEQcase(attribute,qq->method);
4478             }
4479         }
4480       if (pp == (Arguments *) NULL)
4481         {
4482           MagickError(OptionError,UnrecognizedOption,attribute);
4483           goto continue_outer_loop;
4484         }
4485       al=(&argument_list[pp-rp->arguments]);
4486       if (pp->type == IntegerReference)
4487         al->int_reference=SvIV(sv);
4488       else
4489         if (pp->type == StringReference)
4490           al->string_reference=(char *) SvPV(sv,al->length);
4491         else
4492           if (pp->type == DoubleReference)
4493             al->double_reference=SvNV(sv);
4494           else
4495             if (pp->type == ImageReference)
4496               {
4497                 if (!sv_isobject(sv) ||
4498                     !(al->image_reference=SetupList(aTHX_ SvRV(sv),
4499                      (struct PackageInfo **) NULL,(SV ***) NULL)))
4500                   {
4501                     MagickError(OptionError,ReferenceIsNotMyType,
4502                       PackageName);
4503                     goto ReturnIt;
4504                   }
4505               }
4506             else
4507               if (pp->type == ArrayReference)
4508                 al->array_reference=SvRV(sv);
4509               else
4510                 if (!SvPOK(sv))  /* not a string; just get number */
4511                   al->int_reference=SvIV(sv);
4512                 else
4513                   {
4514                     /*
4515                       Is a string; look up name.
4516                     */
4517                     al->int_reference=LookupStr(pp->type,SvPV(sv,na));
4518                     if ((al->int_reference < 0) &&
4519                         ((al->int_reference=SvIV(sv)) <= 0))
4520                       {
4521                         FormatString(message,"invalid %.60s value",pp->method);
4522                         MagickError(OptionError,message,attribute);
4523                         goto continue_outer_loop;
4524                       }
4525                   }
4526       attribute_flag[pp-rp->arguments]++;
4527       continue_outer_loop: ;
4528     }
4529     MY_CXT.error_jump=(&error_jmp);
4530     if (setjmp(error_jmp))
4531       goto ReturnIt;
4532     (void) memset((char *) &fill_color,0,sizeof(PixelPacket));
4533     pv=reference_vector;
4534     GetExceptionInfo(&exception);
4535     for (next=image; next; next=next->next)
4536     {
4537       image=next;
4538       SetGeometry(image,&geometry);
4539       if ((region_info.width*region_info.height) != 0)
4540         {
4541           region_image=image;
4542           image=CropImage(image,&region_info,&exception);
4543           if (exception.severity != UndefinedException)
4544             CatchException(&exception);
4545         }
4546       switch (ix)
4547       {
4548         default:
4549         {
4550           FormatString(message,"%ld",(long) ix);
4551           MagickError(OptionError,UnrecognizedPerlMagickMethod,message);
4552           goto ReturnIt;
4553         }
4554         case 1:  /* Comment */
4555         {
4556           if (!attribute_flag[0])
4557             argument_list[0].string_reference=(char *) NULL;
4558           (void) SetImageAttribute(image,"comment",(char *) NULL);
4559           (void) SetImageAttribute(image,"comment",
4560             argument_list[0].string_reference);
4561           break;
4562         }
4563         case 2:  /* Label */
4564         {
4565           if (!attribute_flag[0])
4566             argument_list[0].string_reference=(char *) NULL;
4567           (void) SetImageAttribute(image,"label",(char *) NULL);
4568           (void) SetImageAttribute(image,"label",
4569             argument_list[0].string_reference);
4570           break;
4571         }
4572         case 3:  /* AddNoise */
4573         {
4574           if (!attribute_flag[0])
4575             argument_list[0].int_reference=UniformNoise;
4576           image=AddNoiseImage(image,(NoiseType) argument_list[0].int_reference,
4577             &exception);
4578           break;
4579         }
4580         case 4:  /* Colorize */
4581         {
4582           PixelPacket
4583             target;
4584 
4585           (void) AcquireOnePixelByReference(image,&target,0,0,&exception);
4586           if (attribute_flag[0])
4587             (void) QueryColorDatabase(argument_list[0].string_reference,&target,
4588               &exception);
4589           if (!attribute_flag[1])
4590             argument_list[1].string_reference="100";
4591           image=ColorizeImage(image,argument_list[1].string_reference,target,
4592             &exception);
4593           break;
4594         }
4595         case 5:  /* Border */
4596         {
4597           if (attribute_flag[0])
4598             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4599               False,&geometry);
4600           if (attribute_flag[1])
4601             geometry.width=argument_list[1].int_reference;
4602           if (attribute_flag[2])
4603             geometry.height=argument_list[2].int_reference;
4604           if (attribute_flag[3])
4605             QueryColorDatabase(argument_list[3].string_reference,&fill_color,
4606               &exception);
4607           if (attribute_flag[4])
4608             QueryColorDatabase(argument_list[4].string_reference,&fill_color,
4609               &exception);
4610           if (attribute_flag[3] || attribute_flag[4])
4611             image->border_color=fill_color;
4612           image=BorderImage(image,&geometry,&exception);
4613           break;
4614         }
4615         case 6:  /* Blur */
4616         {
4617           double
4618             radius,
4619             sigma;
4620 
4621           radius=0.0;
4622           sigma=1.0;
4623           if (attribute_flag[1])
4624             radius=argument_list[1].double_reference;
4625           if (attribute_flag[2])
4626             sigma=argument_list[2].double_reference;
4627           if (attribute_flag[0])
4628             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
4629               &radius,&sigma);
4630           image=BlurImage(image,radius,sigma,&exception);
4631           break;
4632         }
4633         case 7:  /* Chop */
4634         {
4635           if (attribute_flag[0])
4636             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4637               False,&geometry);
4638           if (attribute_flag[1])
4639             geometry.width=argument_list[1].int_reference;
4640           if (attribute_flag[2])
4641             geometry.height=argument_list[2].int_reference;
4642           if (attribute_flag[3])
4643             geometry.x=argument_list[3].int_reference;
4644           if (attribute_flag[4])
4645             geometry.y=argument_list[4].int_reference;
4646           image=ChopImage(image,&geometry,&exception);
4647           break;
4648         }
4649         case 8:  /* Crop */
4650         {
4651           if (attribute_flag[0])
4652             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4653               False,&geometry);
4654           if (attribute_flag[1])
4655             geometry.width=argument_list[1].int_reference;
4656           if (attribute_flag[2])
4657             geometry.height=argument_list[2].int_reference;
4658           if (attribute_flag[3])
4659             geometry.x=argument_list[3].int_reference;
4660           if (attribute_flag[4])
4661             geometry.y=argument_list[4].int_reference;
4662           image=CropImage(image,&geometry,&exception);
4663           break;
4664         }
4665         case 9:  /* Despeckle */
4666         {
4667           image=DespeckleImage(image,&exception);
4668           break;
4669         }
4670         case 10:  /* Edge */
4671         {
4672           double
4673             radius;
4674 
4675           radius=0.0;
4676           if (attribute_flag[0])
4677             radius=argument_list[0].double_reference;
4678           image=EdgeImage(image,radius,&exception);
4679           break;
4680         }
4681         case 11:  /* Emboss */
4682         {
4683           double
4684             radius,
4685             sigma;
4686 
4687           radius=0.0;
4688           sigma=1.0;
4689           if (attribute_flag[1])
4690             radius=argument_list[1].double_reference;
4691           if (attribute_flag[2])
4692             sigma=argument_list[2].double_reference;
4693           if (attribute_flag[0])
4694             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
4695               &radius,&sigma);
4696           image=EmbossImage(image,radius,sigma,&exception);
4697           break;
4698         }
4699         case 12:  /* Enhance */
4700         {
4701           image=EnhanceImage(image,&exception);
4702           break;
4703         }
4704         case 13:  /* Flip */
4705         {
4706           image=FlipImage(image,&exception);
4707           break;
4708         }
4709         case 14:  /* Flop */
4710         {
4711           image=FlopImage(image,&exception);
4712           break;
4713         }
4714         case 15:  /* Frame */
4715         {
4716           if (attribute_flag[0])
4717             {
4718               /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4719                 False,&geometry);
4720               frame_info.width=geometry.width;
4721               frame_info.height=geometry.height;
4722               frame_info.outer_bevel=geometry.x;
4723               frame_info.inner_bevel=geometry.y;
4724             }
4725           if (attribute_flag[1])
4726             frame_info.width=argument_list[1].int_reference;
4727           if (attribute_flag[2])
4728             frame_info.height=argument_list[2].int_reference;
4729           if (attribute_flag[3])
4730             frame_info.inner_bevel=argument_list[3].int_reference;
4731           if (attribute_flag[4])
4732             frame_info.outer_bevel=argument_list[4].int_reference;
4733           if (attribute_flag[5])
4734             QueryColorDatabase(argument_list[5].string_reference,&fill_color,
4735               &exception);
4736           if (attribute_flag[6])
4737             QueryColorDatabase(argument_list[6].string_reference,&fill_color,
4738               &exception);
4739           frame_info.x=(long) frame_info.width;
4740           frame_info.y=(long) frame_info.height;
4741           frame_info.width=image->columns+2*frame_info.x;
4742           frame_info.height=image->rows+2*frame_info.y;
4743           if (attribute_flag[5] || attribute_flag[6])
4744             image->matte_color=fill_color;
4745           image=FrameImage(image,&frame_info,&exception);
4746           break;
4747         }
4748         case 16:  /* Implode */
4749         {
4750           if (!attribute_flag[0])
4751             argument_list[0].double_reference=0.5;
4752           image=ImplodeImage(image,argument_list[0].double_reference,
4753             &exception);
4754           break;
4755         }
4756         case 17:  /* Magnify */
4757         {
4758           image=MagnifyImage(image,&exception);
4759           break;
4760         }
4761         case 18:  /* MedianFilter */
4762         {
4763           if (!attribute_flag[0])
4764             argument_list[0].double_reference=0.0;
4765           image=MedianFilterImage(image,argument_list[0].double_reference,
4766             &exception);
4767           break;
4768         }
4769         case 19:  /* Minify */
4770         {
4771           image=MinifyImage(image,&exception);
4772           break;
4773         }
4774         case 20:  /* OilPaint */
4775         {
4776           if (!attribute_flag[0])
4777             argument_list[0].double_reference=0.0;
4778           image=OilPaintImage(image,argument_list[0].double_reference,
4779             &exception);
4780           break;
4781         }
4782         case 21:  /* ReduceNoise */
4783         {
4784           if (!attribute_flag[0])
4785             argument_list[0].double_reference=0.0;
4786           image=ReduceNoiseImage(image,argument_list[0].double_reference,
4787             &exception);
4788           break;
4789         }
4790         case 22:  /* Roll */
4791         {
4792           if (attribute_flag[0])
4793             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4794               False,&geometry);
4795           if (attribute_flag[1])
4796             geometry.x=argument_list[1].int_reference;
4797           if (attribute_flag[2])
4798             geometry.y=argument_list[2].int_reference;
4799           image=RollImage(image,geometry.x,geometry.y,&exception);
4800           break;
4801         }
4802         case 23:  /* Rotate */
4803         {
4804           if (!attribute_flag[0])
4805             argument_list[0].double_reference=90.0;
4806           if (attribute_flag[1])
4807             QueryColorDatabase(argument_list[1].string_reference,
4808               &image->background_color,&exception);
4809           image=RotateImage(image,argument_list[0].double_reference,&exception);
4810           break;
4811         }
4812         case 24:  /* Sample */
4813         {
4814           if (attribute_flag[0])
4815             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4816               True,&geometry);
4817           if (attribute_flag[1])
4818             geometry.width=argument_list[1].int_reference;
4819           if (attribute_flag[2])
4820             geometry.height=argument_list[2].int_reference;
4821           image=SampleImage(image,geometry.width,geometry.height,&exception);
4822           break;
4823         }
4824         case 25:  /* Scale */
4825         {
4826           if (attribute_flag[0])
4827             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4828               True,&geometry);
4829           if (attribute_flag[1])
4830             geometry.width=argument_list[1].int_reference;
4831           if (attribute_flag[2])
4832             geometry.height=argument_list[2].int_reference;
4833           image=ScaleImage(image,geometry.width,geometry.height,&exception);
4834           break;
4835         }
4836         case 26:  /* Shade */
4837         {
4838           double
4839             azimuth,
4840             elevation;
4841 
4842           azimuth=30.0;
4843           if (attribute_flag[1])
4844             azimuth=argument_list[1].double_reference;
4845           elevation=30.0;
4846           if (attribute_flag[2])
4847             elevation=argument_list[2].double_reference;
4848           if (attribute_flag[0])
4849             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",&azimuth,
4850               &elevation);
4851           image=ShadeImage(image,argument_list[3].int_reference,azimuth,
4852             elevation,&exception);
4853           break;
4854         }
4855         case 27:  /* Sharpen */
4856         {
4857           double
4858             radius,
4859             sigma;
4860 
4861           radius=0.0;
4862           sigma=1.0;
4863           if (attribute_flag[1])
4864             radius=argument_list[1].double_reference;
4865           if (attribute_flag[2])
4866             sigma=argument_list[2].double_reference;
4867           if (attribute_flag[0])
4868             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
4869               &radius,&sigma);
4870           image=SharpenImage(image,radius,sigma,&exception);
4871           break;
4872         }
4873         case 28:  /* Shear */
4874         {
4875           double
4876             x_shear,
4877             y_shear;
4878 
4879           x_shear=45.0;
4880           y_shear=45.0;
4881           if (attribute_flag[1])
4882             x_shear=argument_list[1].double_reference;
4883           if (attribute_flag[2])
4884             y_shear=argument_list[2].double_reference;
4885           if (attribute_flag[0])
4886             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",&x_shear,
4887               &y_shear);
4888           if (attribute_flag[3])
4889              QueryColorDatabase(argument_list[3].string_reference,
4890                &image->background_color,&exception);
4891           image=ShearImage(image,x_shear,y_shear,&exception);
4892           break;
4893         }
4894         case 29:  /* Spread */
4895         {
4896           if (!attribute_flag[0])
4897             argument_list[0].int_reference=1;
4898           image=SpreadImage(image,argument_list[0].int_reference,&exception);
4899           break;
4900         }
4901         case 30:  /* Swirl */
4902         {
4903           if (!attribute_flag[0])
4904             argument_list[0].double_reference=50.0;
4905           image=SwirlImage(image,argument_list[0].double_reference,&exception);
4906           break;
4907         }
4908         case 31:  /* Resize */
4909         case 32:  /* Zoom */
4910         {
4911           if (attribute_flag[0])
4912             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
4913               True,&geometry);
4914           if (attribute_flag[1])
4915             geometry.width=argument_list[1].int_reference;
4916           if (attribute_flag[2])
4917             geometry.height=argument_list[2].int_reference;
4918           if (!attribute_flag[3])
4919             argument_list[3].int_reference=(long) LanczosFilter;
4920           if (!attribute_flag[4])
4921             argument_list[4].double_reference=1.0;
4922           image=ResizeImage(image,geometry.width,geometry.height,
4923             (FilterTypes) argument_list[3].int_reference,
4924             argument_list[4].double_reference,&exception);
4925           break;
4926         }
4927         case 33:  /* Annotate */
4928         {
4929           DrawInfo
4930             *draw_info;
4931 
4932           draw_info=CloneDrawInfo(info ? info->image_info :
4933             (ImageInfo *) NULL,info ? info->draw_info : (DrawInfo *) NULL);
4934           if (attribute_flag[1])
4935             (void) CloneString(&draw_info->font,
4936               argument_list[1].string_reference);
4937           if (attribute_flag[2])
4938             draw_info->pointsize=argument_list[2].double_reference;
4939           if (attribute_flag[3])
4940             (void) CloneString(&draw_info->density,
4941               argument_list[3].string_reference);
4942           if (attribute_flag[0])
4943             (void) CloneString(&draw_info->text,
4944               argument_list[0].string_reference);
4945           if (attribute_flag[4])
4946             (void) QueryColorDatabase(argument_list[4].string_reference,
4947               &draw_info->undercolor,&exception);
4948           if (attribute_flag[5])
4949             (void) QueryColorDatabase(argument_list[5].string_reference,
4950               &draw_info->stroke,&exception);
4951           if (attribute_flag[6])
4952             (void) QueryColorDatabase(argument_list[6].string_reference,
4953               &draw_info->fill,&exception);
4954           if (attribute_flag[7])
4955             (void) CloneString(&draw_info->geometry,
4956               argument_list[7].string_reference);
4957           if (attribute_flag[9] || attribute_flag[10])
4958             {
4959               if (!attribute_flag[9])
4960                 argument_list[9].int_reference=0;
4961               if (!attribute_flag[10])
4962                 argument_list[10].int_reference=0;
4963               FormatString(message,"%+ld%+ld",argument_list[9].int_reference,
4964                 argument_list[10].int_reference);
4965               (void) CloneString(&draw_info->geometry,message);
4966             }
4967           if (attribute_flag[11])
4968             draw_info->gravity=(GravityType) argument_list[11].int_reference;
4969           if (attribute_flag[25])
4970             {
4971               AV
4972                 *av;
4973 
4974               av=(AV *) argument_list[25].array_reference;
4975               if (av_len(av) >= 1)
4976                 draw_info->affine.sx=(double) SvNV(*(av_fetch(av,0,0)));
4977               if (av_len(av) >= 2)
4978                 draw_info->affine.rx=(double) SvNV(*(av_fetch(av,1,0)));
4979               if (av_len(av) >= 3)
4980                 draw_info->affine.ry=(double) SvNV(*(av_fetch(av,2,0)));
4981               if (av_len(av) >= 4)
4982                 draw_info->affine.sy=(double) SvNV(*(av_fetch(av,3,0)));
4983               if (av_len(av) >= 5)
4984                 draw_info->affine.tx=(double) SvNV(*(av_fetch(av,4,0)));
4985               if (av_len(av) >= 6)
4986                 draw_info->affine.ty=(double) SvNV(*(av_fetch(av,5,0)));
4987             }
4988           for (j=12; j < 17; j++)
4989           {
4990             if (!attribute_flag[j])
4991               continue;
4992             value=argument_list[j].string_reference;
4993             angle=argument_list[j].double_reference;
4994             current=draw_info->affine;
4995             IdentityAffine(&affine);
4996             switch (j)
4997             {
4998               case 12:
4999               {
5000                 /*
5001                   Translate.
5002                 */
5003                 k=sscanf(value,"%lf%*[,/]%lf",&affine.tx,&affine.ty);
5004                 if (k == 1)
5005                   affine.ty=affine.tx;
5006                 break;
5007               }
5008               case 13:
5009               {
5010                 /*
5011                   Scale.
5012                 */
5013                 k=sscanf(value,"%lf%*[,/]%lf",&affine.sx,&affine.sy);
5014                 if (k == 1)
5015                   affine.sy=affine.sx;
5016                 break;
5017               }
5018               case 14:
5019               {
5020                 /*
5021                   Rotate.
5022                 */
5023                 if (angle == 0.0)
5024                   break;
5025                 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
5026                 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
5027                 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
5028                 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
5029                 break;
5030               }
5031               case 15:
5032               {
5033                 /*
5034                   SkewX.
5035                 */
5036                 affine.ry=tan(DegreesToRadians(fmod(angle,360.0)));
5037                 break;
5038               }
5039               case 16:
5040               {
5041                 /*
5042                   SkewY.
5043                 */
5044                 affine.rx=tan(DegreesToRadians(fmod(angle,360.0)));
5045                 break;
5046               }
5047             }
5048             draw_info->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
5049             draw_info->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
5050             draw_info->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
5051             draw_info->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
5052             draw_info->affine.tx=current.sx*affine.tx+current.ry*affine.ty+
5053               current.tx;
5054             draw_info->affine.ty=current.rx*affine.tx+current.sy*affine.ty+
5055               current.ty;
5056           }
5057           if (attribute_flag[17])
5058             draw_info->stroke_width=argument_list[17].int_reference;
5059           if (attribute_flag[18])
5060             draw_info->text_antialias=argument_list[18].int_reference != 0;
5061           if (attribute_flag[19])
5062             (void) CloneString(&draw_info->family,
5063               argument_list[19].string_reference);
5064           if (attribute_flag[20])
5065             draw_info->style=(StyleType) argument_list[20].int_reference;
5066           if (attribute_flag[21])
5067             draw_info->stretch=(StretchType) argument_list[21].int_reference;
5068           if (attribute_flag[22])
5069             draw_info->weight=argument_list[22].int_reference;
5070           if (attribute_flag[23])
5071             draw_info->align=(AlignType) argument_list[23].int_reference;
5072           if (attribute_flag[24])
5073             (void) CloneString(&draw_info->encoding,
5074               argument_list[24].string_reference);
5075           if (attribute_flag[26])
5076             draw_info->decorate=(DecorationType) argument_list[26].int_reference;
5077           AnnotateImage(image,draw_info);
5078           DestroyDrawInfo(draw_info);
5079           break;
5080         }
5081         case 34:  /* ColorFloodfill */
5082         {
5083           DrawInfo
5084             *draw_info;
5085 
5086           PixelPacket
5087             target;
5088 
5089           draw_info=CloneDrawInfo(info ? info->image_info :
5090             (ImageInfo *) NULL,info ? info->draw_info : (DrawInfo *) NULL);
5091           if (attribute_flag[0])
5092             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
5093               False,&geometry);
5094           if (attribute_flag[1])
5095             geometry.x=argument_list[1].int_reference;
5096           if (attribute_flag[2])
5097             geometry.y=argument_list[2].int_reference;
5098           if (attribute_flag[3])
5099             (void) QueryColorDatabase(argument_list[3].string_reference,
5100               &draw_info->fill,&exception);
5101           if (attribute_flag[4])
5102             QueryColorDatabase(argument_list[4].string_reference,&fill_color,
5103               &exception);
5104           (void) AcquireOnePixelByReference(image,&target,(long) (geometry.x % image->columns),
5105             (long) (geometry.y % image->rows),&exception);
5106           if (attribute_flag[4])
5107             target=fill_color;
5108           if (attribute_flag[5])
5109             image->fuzz=argument_list[5].double_reference;
5110           ColorFloodfillImage(image,draw_info,target,geometry.x,geometry.y,
5111             attribute_flag[4] ? FillToBorderMethod : FloodfillMethod);
5112           DestroyDrawInfo(draw_info);
5113           break;
5114         }
5115         case 35:  /* Composite */
5116         {
5117           char
5118             composite_geometry[MaxTextExtent];
5119 
5120           CompositeOperator
5121             compose;
5122 
5123           double
5124             opacity;
5125 
5126           Image
5127             *composite_image,
5128             *mask_image,
5129             *rotate_image;
5130 
5131           compose=OverCompositeOp;
5132           if (attribute_flag[0])
5133             composite_image=argument_list[0].image_reference;
5134           else
5135             {
5136               MagickError(OptionError,CompositeImageRequired,NULL);
5137               goto ReturnIt;
5138             }
5139           if (attribute_flag[1])
5140             compose=(CompositeOperator) argument_list[1].int_reference;
5141           opacity=OpaqueOpacity;
5142           if (attribute_flag[6])
5143             {
5144               opacity=argument_list[6].double_reference;
5145               if (compose == DissolveCompositeOp)
5146                 {
5147                   register PixelPacket
5148                     *q;
5149 
5150                   if (!composite_image->matte)
5151                     SetImageOpacity(composite_image,OpaqueOpacity);
5152                   for (y=0; y < (long) composite_image->rows; y++)
5153                     {
5154                       q=GetImagePixels(composite_image,0,y,
5155                                        composite_image->columns,1);
5156                       if (q == (PixelPacket *) NULL)
5157                         break;
5158                       for (x=(long) composite_image->columns; x > 0; x--)
5159                         {
5160                           q->opacity=(Quantum) ((opacity*(MaxRGB-q->opacity))/100.0);
5161                           q++;
5162                         }
5163                       if (!SyncImagePixels(composite_image))
5164                         break;
5165                     }
5166                 }
5167               else
5168                 {
5169                   if (opacity != OpaqueOpacity)
5170                     SetImageOpacity(composite_image,(unsigned int) opacity);
5171                 }
5172             }
5173           if (attribute_flag[9])
5174             QueryColorDatabase(argument_list[9].string_reference,
5175               &composite_image->background_color,&exception);
5176           rotate_image=(Image *) NULL;
5177           if (attribute_flag[8])
5178             {
5179                /*
5180                  Rotate image.
5181                */
5182                rotate_image=RotateImage(composite_image,
5183                  argument_list[8].double_reference,&exception);
5184                if (rotate_image == (Image *) NULL)
5185                  break;
5186             }
5187           if (attribute_flag[7] && argument_list[7].int_reference)
5188             {
5189               /*
5190                 Tile image on background.
5191               */
5192               for (y=0; y < (long) image->rows; y+=composite_image->rows)
5193                 for (x=0; x < (long) image->columns; x+=composite_image->columns)
5194                 {
5195                   if (attribute_flag[8])
5196                     (void) CompositeImage(image,compose,rotate_image,x,y);
5197                   else
5198                     (void) CompositeImage(image,compose,composite_image,x,y);
5199                   (void) CatchImageException(image);
5200                 }
5201               if (attribute_flag[8])
5202                 DestroyImage(rotate_image);
5203               break;
5204             }
5205           if (attribute_flag[2])
5206             /*flags=*/GetGeometry(argument_list[2].string_reference,&geometry.x,
5207               &geometry.y,&geometry.width,&geometry.height);
5208           if (attribute_flag[3])
5209             geometry.x=argument_list[3].int_reference;
5210           if (attribute_flag[4])
5211             geometry.y=argument_list[4].int_reference;
5212           if (attribute_flag[5])
5213             image->gravity=(GravityType) argument_list[5].int_reference;
5214           if (attribute_flag[10])
5215             {
5216               mask_image=argument_list[10].image_reference;
5217               SetImageType(composite_image,TrueColorMatteType);
5218               if (!composite_image->matte)
5219                 SetImageOpacity(composite_image,OpaqueOpacity);
5220               (void) CompositeImage(composite_image,CopyOpacityCompositeOp,
5221                 mask_image,0,0);
5222             }
5223           /*
5224             Composite image.
5225           */
5226           FormatString(composite_geometry,"%lux%lu%+ld%+ld",
5227             composite_image->columns,composite_image->rows,geometry.x,
5228             geometry.y);
5229           /*flags=*/GetImageGeometry(image,composite_geometry,False,&geometry);
5230           if (!attribute_flag[8])
5231             CompositeImage(image,compose,composite_image,geometry.x,geometry.y);
5232           else
5233             {
5234               /*
5235                 Rotate image.
5236               */
5237               geometry.x-=(long)
5238                 (rotate_image->columns-composite_image->columns)/2;
5239               geometry.y-=(long) (rotate_image->rows-composite_image->rows)/2;
5240               CompositeImage(image,compose,rotate_image,geometry.x,geometry.y);
5241               DestroyImage(rotate_image);
5242             }
5243           break;
5244         }
5245         case 36:  /* Contrast */
5246         {
5247           if (!attribute_flag[0])
5248             argument_list[0].int_reference=0;
5249           ContrastImage(image,argument_list[0].int_reference);
5250           break;
5251         }
5252         case 37:  /* CycleColormap */
5253         {
5254           if (!attribute_flag[0])
5255             argument_list[0].int_reference=6;
5256           CycleColormapImage(image,argument_list[0].int_reference);
5257           break;
5258         }
5259         case 38:  /* Draw */
5260         {
5261           DrawInfo
5262             *draw_info;
5263 
5264           draw_info=CloneDrawInfo(info ? info->image_info : (ImageInfo *) NULL,
5265             info ? info->draw_info : (DrawInfo *) NULL);
5266           draw_info->fill.opacity=TransparentOpacity;
5267           draw_info->stroke.opacity=OpaqueOpacity;
5268           (void) CloneString(&draw_info->primitive,"Point");
5269           if (attribute_flag[0] && (argument_list[0].int_reference > 0))
5270             (void) CloneString(&draw_info->primitive,
5271               PrimitiveTypes[argument_list[0].int_reference]);
5272           if (attribute_flag[1])
5273             {
5274               if (LocaleCompare(draw_info->primitive,"path") == 0)
5275                 {
5276                   (void) ConcatenateString(&draw_info->primitive," '");
5277                   ConcatenateString(&draw_info->primitive,
5278                     argument_list[1].string_reference);
5279                   (void) ConcatenateString(&draw_info->primitive,"'");
5280                 }
5281               else
5282                 {
5283                   (void) ConcatenateString(&draw_info->primitive," ");
5284                   ConcatenateString(&draw_info->primitive,
5285                     argument_list[1].string_reference);
5286                 }
5287             }
5288           if (attribute_flag[2])
5289             {
5290               (void) ConcatenateString(&draw_info->primitive," ");
5291               (void) ConcatenateString(&draw_info->primitive,
5292                 MethodTypes[argument_list[2].int_reference]);
5293             }
5294           if (attribute_flag[3])
5295             (void) QueryColorDatabase(argument_list[3].string_reference,
5296               &draw_info->stroke,&exception);
5297           if (attribute_flag[4])
5298             (void) QueryColorDatabase(argument_list[4].string_reference,
5299               &draw_info->fill,&exception);
5300           if (attribute_flag[5])
5301             draw_info->stroke_width=argument_list[5].double_reference;
5302           if (attribute_flag[6])
5303             (void) CloneString(&draw_info->font,
5304               argument_list[6].string_reference);
5305           if (attribute_flag[7])
5306             (void) QueryColorDatabase(argument_list[7].string_reference,
5307               &draw_info->border_color,&exception);
5308           if (attribute_flag[8])
5309             draw_info->affine.tx=argument_list[8].double_reference;
5310           if (attribute_flag[9])
5311             draw_info->affine.ty=argument_list[9].double_reference;
5312           if (attribute_flag[20])
5313             {
5314               AV
5315                 *av;
5316 
5317               av=(AV *) argument_list[20].array_reference;
5318               if (av_len(av) >= 1)
5319                 draw_info->affine.sx=(double) SvNV(*(av_fetch(av,0,0)));
5320               if (av_len(av) >= 2)
5321                 draw_info->affine.rx=(double) SvNV(*(av_fetch(av,1,0)));
5322               if (av_len(av) >= 3)
5323                 draw_info->affine.ry=(double) SvNV(*(av_fetch(av,2,0)));
5324               if (av_len(av) >= 4)
5325                 draw_info->affine.sy=(double) SvNV(*(av_fetch(av,3,0)));
5326               if (av_len(av) >= 5)
5327                 draw_info->affine.tx=(double) SvNV(*(av_fetch(av,4,0)));
5328               if (av_len(av) >= 6)
5329                 draw_info->affine.ty=(double) SvNV(*(av_fetch(av,5,0)));
5330             }
5331           for (j=10; j < 15; j++)
5332           {
5333             if (!attribute_flag[j])
5334               continue;
5335             value=argument_list[j].string_reference;
5336             angle=argument_list[j].double_reference;
5337             current=draw_info->affine;
5338             IdentityAffine(&affine);
5339             switch (j)
5340             {
5341               case 10:
5342               {
5343                 /*
5344                   Translate.
5345                 */
5346                 k=sscanf(value,"%lf%*[,/]%lf",&affine.tx,&affine.ty);
5347                 if (k == 1)
5348                   affine.ty=affine.tx;
5349                 break;
5350               }
5351               case 11:
5352               {
5353                 /*
5354                   Scale.
5355                 */
5356                 k=sscanf(value,"%lf%*[,/]%lf",&affine.sx,&affine.sy);
5357                 if (k == 1)
5358                   affine.sy=affine.sx;
5359                 break;
5360               }
5361               case 12:
5362               {
5363                 /*
5364                   Rotate.
5365                 */
5366                 if (angle == 0.0)
5367                   break;
5368                 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
5369                 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
5370                 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
5371                 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
5372                 break;
5373               }
5374               case 13:
5375               {
5376                 /*
5377                   SkewX.
5378                 */
5379                 affine.ry=tan(DegreesToRadians(fmod(angle,360.0)));
5380                 break;
5381               }
5382               case 14:
5383               {
5384                 /*
5385                   SkewY.
5386                 */
5387                 affine.rx=tan(DegreesToRadians(fmod(angle,360.0)));
5388                 break;
5389               }
5390             }
5391             draw_info->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
5392             draw_info->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
5393             draw_info->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
5394             draw_info->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
5395             draw_info->affine.tx=
5396               current.sx*affine.tx+current.ry*affine.ty+current.tx;
5397             draw_info->affine.ty=
5398               current.rx*affine.tx+current.sy*affine.ty+current.ty;
5399           }
5400           if (attribute_flag[15])
5401             draw_info->fill_pattern=
5402               CloneImage(argument_list[15].image_reference,0,0,True,&exception);
5403           if (attribute_flag[16])
5404             draw_info->pointsize=argument_list[16].double_reference;
5405           if (attribute_flag[17])
5406             {
5407               draw_info->stroke_antialias=argument_list[17].int_reference != 0;
5408               draw_info->text_antialias=argument_list[17].int_reference != 0;
5409             }
5410           if (attribute_flag[18])
5411             (void) CloneString(&draw_info->density,
5412               argument_list[18].string_reference);
5413           if (attribute_flag[19])
5414             draw_info->stroke_width=argument_list[19].double_reference;
5415           DrawImage(image,draw_info);
5416           DestroyDrawInfo(draw_info);
5417           break;
5418         }
5419         case 39:  /* Equalize */
5420         {
5421           EqualizeImage(image);
5422           break;
5423         }
5424         case 40:  /* Gamma */
5425         {
5426           if (!attribute_flag[1])
5427             argument_list[1].double_reference=1.0;
5428           if (!attribute_flag[2])
5429             argument_list[2].double_reference=1.0;
5430           if (!attribute_flag[3])
5431             argument_list[3].double_reference=1.0;
5432           if (!attribute_flag[0])
5433             {
5434               FormatString(message,"%g,%g,%g",
5435                 argument_list[1].double_reference,
5436                 argument_list[2].double_reference,
5437                 argument_list[3].double_reference);
5438               argument_list[0].string_reference=message;
5439             }
5440           GammaImage(image,argument_list[0].string_reference);
5441           break;
5442         }
5443         case 41:  /* Map */
5444         {
5445           if (!attribute_flag[1])
5446             argument_list[1].int_reference=1;
5447           if (!attribute_flag[0])
5448             {
5449               MagickError(OptionError,MapImageRequired,NULL);
5450               goto ReturnIt;
5451             }
5452           (void) MapImages(image,argument_list[0].image_reference,
5453             argument_list[1].int_reference);
5454           break;
5455         }
5456         case 42:  /* MatteFloodfill */
5457         {
5458           PixelPacket
5459             target;
5460 
5461           unsigned int
5462             opacity;
5463 
5464           if (attribute_flag[0])
5465             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
5466               False,&geometry);
5467           if (attribute_flag[1])
5468             geometry.x=argument_list[1].int_reference;
5469           if (attribute_flag[2])
5470             geometry.y=argument_list[2].int_reference;
5471           if (attribute_flag[4])
5472             QueryColorDatabase(argument_list[4].string_reference,&fill_color,
5473               &exception);
5474           opacity=TransparentOpacity;
5475           if (attribute_flag[3])
5476             opacity=argument_list[3].int_reference;
5477           if (!image->matte)
5478             SetImageOpacity(image,OpaqueOpacity);
5479           (void) AcquireOnePixelByReference(image,&target,(long) (geometry.x % image->columns),
5480             (long) (geometry.y % image->rows),&exception);
5481           if (attribute_flag[4])
5482             target=fill_color;
5483           if (attribute_flag[5])
5484             image->fuzz=argument_list[5].double_reference;
5485           MatteFloodfillImage(image,target,opacity,geometry.x,geometry.y,
5486             attribute_flag[4] ? FillToBorderMethod : FloodfillMethod);
5487           break;
5488         }
5489         case 43:  /* Modulate */
5490         {
5491           if (!attribute_flag[1])
5492             argument_list[1].double_reference=100.0;
5493           if (!attribute_flag[2])
5494             argument_list[2].double_reference=100.0;
5495           if (!attribute_flag[3])
5496             argument_list[3].double_reference=100.0;
5497           FormatString(message,"%g,%g,%g",
5498             argument_list[1].double_reference,
5499             argument_list[2].double_reference,
5500             argument_list[3].double_reference);
5501           if (!attribute_flag[0])
5502             argument_list[0].string_reference=message;
5503           ModulateImage(image,argument_list[0].string_reference);
5504           break;
5505         }
5506         case 44:  /* Negate */
5507         {
5508           if (!attribute_flag[0])
5509             argument_list[0].int_reference=0;
5510           NegateImage(image,argument_list[0].int_reference);
5511           break;
5512         }
5513         case 45:  /* Normalize */
5514         {
5515           NormalizeImage(image);
5516           break;
5517         }
5518         case 46:  /* NumberColors */
5519           break;
5520         case 47:  /* Opaque */
5521         {
5522           PixelPacket
5523             fill_color,
5524             target;
5525 
5526           (void) AcquireOnePixelByReference(image,&target,0,0,&exception);
5527           if (attribute_flag[0])
5528             (void) QueryColorDatabase(argument_list[0].string_reference,
5529               &target,&exception);
5530           (void) AcquireOnePixelByReference(image,&fill_color,0,0,&exception);
5531           if (attribute_flag[1])
5532             (void) QueryColorDatabase(argument_list[1].string_reference,
5533               &fill_color,&exception);
5534           if (attribute_flag[2])
5535             image->fuzz=argument_list[2].double_reference;
5536           OpaqueImage(image,target,fill_color);
5537           break;
5538         }
5539         case 48:  /* Quantize */
5540         {
5541           QuantizeInfo
5542             quantize_info;
5543 
5544           GetQuantizeInfo(&quantize_info);
5545           quantize_info.number_colors=
5546             attribute_flag[0] ? (unsigned long) argument_list[0].int_reference :
5547             (info ? info->quantize_info->number_colors :
5548              MaxRGB + 1U);
5549           quantize_info.tree_depth=attribute_flag[1] ?
5550             (unsigned int) argument_list[1].int_reference :
5551             (info ? info->quantize_info->tree_depth : 8U);
5552           quantize_info.colorspace=(ColorspaceType)
5553             (attribute_flag[2] ? (ColorspaceType) argument_list[2].int_reference :
5554             (info? info->quantize_info->colorspace : RGBColorspace));
5555           quantize_info.dither=attribute_flag[3] ?
5556             (unsigned int) argument_list[3].int_reference :
5557             (info ? info->quantize_info->dither : False);
5558           quantize_info.measure_error=attribute_flag[4] ?
5559             (unsigned int) argument_list[4].int_reference :
5560             (info ? info->quantize_info->measure_error : False);
5561           if (attribute_flag[5] && argument_list[5].int_reference)
5562             {
5563               (void) QuantizeImages(&quantize_info,image);
5564               goto ReturnIt;
5565             }
5566           if ((image->storage_class == DirectClass) ||
5567               (image->colors > quantize_info.number_colors) ||
5568               (quantize_info.colorspace == GRAYColorspace))
5569             (void) QuantizeImage(&quantize_info,image);
5570           else
5571             CompressImageColormap(image);
5572           break;
5573         }
5574         case 49:  /* Raise */
5575         {
5576           if (attribute_flag[0])
5577             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
5578               False,&geometry);
5579           if (attribute_flag[1])
5580             geometry.width=argument_list[1].int_reference;
5581           if (attribute_flag[2])
5582             geometry.height=argument_list[2].int_reference;
5583           if (!attribute_flag[3])
5584             argument_list[3].int_reference=1;
5585           RaiseImage(image,&geometry,argument_list[3].int_reference);
5586           break;
5587         }
5588         case 50:  /* Segment */
5589         {
5590           ColorspaceType
5591             colorspace;
5592 
5593           double
5594             cluster_threshold,
5595             smoothing_threshold;
5596 
5597           unsigned int
5598             verbose;
5599 
5600           cluster_threshold=1.0;
5601           smoothing_threshold=1.5;
5602           colorspace=RGBColorspace;
5603           verbose=False;
5604           if (attribute_flag[1])
5605             cluster_threshold=argument_list[1].double_reference;
5606           if (attribute_flag[2])
5607             smoothing_threshold=argument_list[2].double_reference;
5608           if (attribute_flag[0])
5609             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
5610               &cluster_threshold,&smoothing_threshold);
5611           if (attribute_flag[3])
5612             colorspace=(ColorspaceType) argument_list[3].int_reference;
5613           if (attribute_flag[4])
5614             verbose=argument_list[4].int_reference != 0;
5615           (void) SegmentImage(image,colorspace,verbose,cluster_threshold,
5616             smoothing_threshold);
5617           break;
5618         }
5619         case 51:  /* Signature */
5620         {
5621           (void) SignatureImage(image);
5622           break;
5623         }
5624         case 52:  /* Solarize */
5625         {
5626           if (!attribute_flag[0])
5627             argument_list[0].double_reference=50.0;
5628           SolarizeImage(image,argument_list[0].double_reference);
5629           break;
5630         }
5631         case 53:  /* Sync */
5632         {
5633           (void) SyncImage(image);
5634           break;
5635         }
5636         case 54:  /* Texture */
5637         {
5638           if (!attribute_flag[0])
5639             break;
5640           TextureImage(image,argument_list[0].image_reference);
5641           break;
5642         }
5643         case 55:  /* Sans */
5644           break;
5645         case 56:  /* Transparent */
5646         {
5647           PixelPacket
5648             target;
5649 
5650           unsigned int
5651             opacity;
5652 
5653           (void) AcquireOnePixelByReference(image,&target,0,0,&exception);
5654           if (attribute_flag[0])
5655             (void) QueryColorDatabase(argument_list[0].string_reference,
5656               &target,&exception);
5657           opacity=TransparentOpacity;
5658           if (attribute_flag[1])
5659             opacity=argument_list[1].int_reference;
5660           if (attribute_flag[2])
5661             image->fuzz=argument_list[2].double_reference;
5662           TransparentImage(image,target,opacity);
5663           break;
5664         }
5665         case 57:  /* Threshold */
5666         {
5667           double
5668             threshold;
5669 
5670           int
5671             count;
5672 
5673           if (!attribute_flag[0])
5674             argument_list[0].string_reference="50%";
5675           count=sscanf(argument_list[0].string_reference,"%lf",&threshold);
5676           if (count > 0)
5677             {
5678               if (strchr(argument_list[0].string_reference,'%') != (char *) NULL)
5679                   threshold *=  MaxRGB/100.0;
5680                 (void) ThresholdImage(image,threshold);
5681             }
5682           break;
5683         }
5684         case 58:  /* Charcoal */
5685         {
5686           double
5687             radius,
5688             sigma;
5689 
5690           radius=0.0;
5691           sigma=1.0;
5692           if (attribute_flag[1])
5693             radius=argument_list[1].double_reference;
5694           if (attribute_flag[2])
5695             sigma=argument_list[2].double_reference;
5696           if (attribute_flag[0])
5697             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
5698               &radius,&sigma);
5699           image=CharcoalImage(image,radius,sigma,&exception);
5700           break;
5701         }
5702         case 59:  /* Trim */
5703         {
5704           if (attribute_flag[0])
5705             image->fuzz=argument_list[0].double_reference;
5706           /*flags=*/GetGeometry("0x0",&geometry.x,&geometry.y,
5707             &geometry.width,&geometry.height);
5708           image=CropImage(image,&geometry,&exception);
5709           break;
5710         }
5711         case 60:  /* Wave */
5712         {
5713           double
5714             amplitude,
5715             wavelength;
5716 
5717           amplitude=25.0;
5718           wavelength=150.0;
5719           if (attribute_flag[1])
5720             amplitude=argument_list[1].double_reference;
5721           if (attribute_flag[2])
5722             wavelength=argument_list[2].double_reference;
5723           if (attribute_flag[0])
5724             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
5725               &amplitude,&wavelength);
5726           image=WaveImage(image,amplitude,wavelength,&exception);
5727           break;
5728         }
5729         case 61:  /* Channel */
5730         {
5731           if (!attribute_flag[0])
5732             argument_list[0].int_reference=1;
5733           ChannelImage(image,(ChannelType) argument_list[0].int_reference);
5734           break;
5735         }
5736         case 63:  /* Stereo */
5737         {
5738           if (!attribute_flag[0])
5739             {
5740               MagickError(OptionError,StereoImageRequired,NULL);
5741               goto ReturnIt;
5742             }
5743           image=StereoImage(image,argument_list[0].image_reference,&exception);
5744           break;
5745         }
5746         case 64:  /* Stegano */
5747         {
5748           if (!attribute_flag[1])
5749             argument_list[1].int_reference=0;
5750           if (!attribute_flag[0])
5751             {
5752               MagickError(OptionError,SteganoImageRequired,NULL);
5753               goto ReturnIt;
5754             }
5755           image->offset=argument_list[1].int_reference;
5756           image=SteganoImage(image,argument_list[0].image_reference,&exception);
5757           break;
5758         }
5759         case 65:  /* Deconstruct */
5760         {
5761           image=DeconstructImages(image,&exception);
5762           break;
5763         }
5764         case 66:  /* GaussianBlur */
5765         {
5766           double
5767             radius,
5768             sigma;
5769 
5770           radius=0.0;
5771           sigma=1.0;
5772           if (attribute_flag[1])
5773             radius=argument_list[1].double_reference;
5774           if (attribute_flag[2])
5775             sigma=argument_list[2].double_reference;
5776           if (attribute_flag[0])
5777             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
5778               &radius,&sigma);
5779           image=GaussianBlurImage(image,radius,sigma,&exception);
5780           break;
5781         }
5782         case 67:  /* Convolve */
5783         {
5784           AV
5785             *av;
5786 
5787           double
5788             *kernel;
5789 
5790           unsigned int
5791             radius;
5792 
5793           if (!attribute_flag[0])
5794             break;
5795           av=(AV *) argument_list[0].array_reference;
5796           radius=(unsigned int) sqrt(av_len(av)+1);
5797           kernel=MagickAllocateMemory(double *,radius*radius*sizeof(double));
5798           for (j=0; j < (av_len(av)+1); j++)
5799             kernel[j]=(double) SvNV(*(av_fetch(av,j,0)));
5800           for ( ; j < (long) (radius*radius); j++)
5801             kernel[j]=0.0;
5802           image=ConvolveImage(image,radius,kernel,&exception);
5803           MagickFreeMemory(kernel);
5804           break;
5805         }
5806         case 68:  /* Profile */
5807         {
5808           if (!attribute_flag[0])
5809             argument_list[0].string_reference="*";
5810           if (!attribute_flag[1])
5811             argument_list[1].string_reference=(char *) NULL;
5812           (void) ProfileImage(image,argument_list[0].string_reference,
5813             (unsigned char *) argument_list[1].string_reference,
5814             argument_list[1].length,True);
5815           break;
5816         }
5817         case 69:  /* UnsharpMask */
5818         {
5819           double
5820             amount,
5821             radius,
5822             sigma,
5823             threshold;
5824 
5825           radius=0.0;
5826           sigma=1.0;
5827           amount=1.0;
5828           threshold=0.05;
5829           if (attribute_flag[1])
5830             radius=argument_list[1].double_reference;
5831           if (attribute_flag[2])
5832             sigma=argument_list[2].double_reference;
5833           if (attribute_flag[3])
5834             amount=argument_list[3].double_reference;
5835           if (attribute_flag[4])
5836             threshold=argument_list[4].double_reference;
5837           if (attribute_flag[0])
5838             (void) sscanf(argument_list[0].string_reference,"%lfx%lf%lf%lf",
5839               &radius,&sigma,&amount,&threshold);
5840           image=UnsharpMaskImage(image,radius,sigma,amount,threshold,
5841             &exception);
5842           break;
5843         }
5844         case 70:  /* MotionBlur */
5845         {
5846           double
5847             angle,
5848             radius,
5849             sigma;
5850 
5851           radius=0.0;
5852           sigma=1.0;
5853           angle=1.0;
5854           if (attribute_flag[1])
5855             radius=argument_list[1].double_reference;
5856           if (attribute_flag[2])
5857             sigma=argument_list[2].double_reference;
5858           if (attribute_flag[3])
5859             angle=argument_list[3].double_reference;
5860           if (attribute_flag[0])
5861             (void) sscanf(argument_list[0].string_reference,"%lfx%lf",
5862               &radius,&sigma);
5863           image=MotionBlurImage(image,radius,sigma,angle,&exception);
5864           break;
5865         }
5866         case 71:  /* OrderedDither */
5867         {
5868           (void) OrderedDitherImage(image);
5869           break;
5870         }
5871         case 72:  /* Shave */
5872         {
5873           if (attribute_flag[0])
5874             /*flags=*/GetImageGeometry(image,argument_list[0].string_reference,
5875               False,&geometry);
5876           if (attribute_flag[1])
5877             geometry.width=argument_list[1].int_reference;
5878           if (attribute_flag[2])
5879             geometry.height=argument_list[2].int_reference;
5880           image=ShaveImage(image,&geometry,&exception);
5881           break;
5882         }
5883         case 73:  /* Level */
5884         {
5885           if (!attribute_flag[1])
5886             argument_list[1].double_reference=0.0;
5887           if (!attribute_flag[2])
5888             argument_list[2].double_reference=1.0;
5889           if (!attribute_flag[3])
5890             argument_list[3].double_reference=MaxRGB;
5891           if (!attribute_flag[0])
5892             {
5893               FormatString(message,"%g,%g,%g",
5894                 argument_list[1].double_reference,
5895                 argument_list[2].double_reference,
5896                 argument_list[3].double_reference);
5897               argument_list[0].string_reference=message;
5898             }
5899           LevelImage(image,argument_list[0].string_reference);
5900           break;
5901         }
5902         case 74:  /* Clip */
5903         {
5904           (void) ClipImage(image);
5905           break;
5906         }
5907         case 75:  /* AffineTransform */
5908         {
5909           DrawInfo
5910             *draw_info;
5911 
5912           draw_info=CloneDrawInfo(info ? info->image_info : (ImageInfo *) NULL,
5913             info ? info->draw_info : (DrawInfo *) NULL);
5914           if (attribute_flag[0])
5915             {
5916               AV
5917                 *av;
5918 
5919               av=(AV *) argument_list[0].array_reference;
5920               if (av_len(av) >= 1)
5921                 draw_info->affine.sx=(double) SvNV(*(av_fetch(av,0,0)));
5922               if (av_len(av) >= 2)
5923                 draw_info->affine.rx=(double) SvNV(*(av_fetch(av,1,0)));
5924               if (av_len(av) >= 3)
5925                 draw_info->affine.ry=(double) SvNV(*(av_fetch(av,2,0)));
5926               if (av_len(av) >= 4)
5927                 draw_info->affine.sy=(double) SvNV(*(av_fetch(av,3,0)));
5928               if (av_len(av) >= 5)
5929                 draw_info->affine.tx=(double) SvNV(*(av_fetch(av,4,0)));
5930               if (av_len(av) >= 6)
5931                 draw_info->affine.ty=(double) SvNV(*(av_fetch(av,5,0)));
5932             }
5933           for (j=1; j < 6; j++)
5934           {
5935             if (!attribute_flag[j])
5936               continue;
5937             value=argument_list[j].string_reference;
5938             angle=argument_list[j].double_reference;
5939             current=draw_info->affine;
5940             IdentityAffine(&affine);
5941             switch (j)
5942             {
5943               case 1:
5944               {
5945                 /*
5946                   Translate.
5947                 */
5948                 k=sscanf(value,"%lf%*[,/]%lf",&affine.tx,&affine.ty);
5949                 if (k == 1)
5950                   affine.ty=affine.tx;
5951                 break;
5952               }
5953               case 2:
5954               {
5955                 /*
5956                   Scale.
5957                 */
5958                 k=sscanf(value,"%lf%*[,/]%lf",&affine.sx,&affine.sy);
5959                 if (k == 1)
5960                   affine.sy=affine.sx;
5961                 break;
5962               }
5963               case 3:
5964               {
5965                 /*
5966                   Rotate.
5967                 */
5968                 if (angle == 0.0)
5969                   break;
5970                 affine.sx=cos(DegreesToRadians(fmod(angle,360.0)));
5971                 affine.rx=sin(DegreesToRadians(fmod(angle,360.0)));
5972                 affine.ry=(-sin(DegreesToRadians(fmod(angle,360.0))));
5973                 affine.sy=cos(DegreesToRadians(fmod(angle,360.0)));
5974                 break;
5975               }
5976               case 4:
5977               {
5978                 /*
5979                   SkewX.
5980                 */
5981                 affine.ry=tan(DegreesToRadians(fmod(angle,360.0)));
5982                 break;
5983               }
5984               case 5:
5985               {
5986                 /*
5987                   SkewY.
5988                 */
5989                 affine.rx=tan(DegreesToRadians(fmod(angle,360.0)));
5990                 break;
5991               }
5992             }
5993             draw_info->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
5994             draw_info->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
5995             draw_info->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
5996             draw_info->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
5997             draw_info->affine.tx=
5998               current.sx*affine.tx+current.ry*affine.ty+current.tx;
5999             draw_info->affine.ty=
6000               current.rx*affine.tx+current.sy*affine.ty+current.ty;
6001           }
6002           image=AffineTransformImage(image,&draw_info->affine,&exception);
6003           DestroyDrawInfo(draw_info);
6004           break;
6005         }
6006         case 76:  /* Compare */
6007         {
6008           if (!attribute_flag[0])
6009             {
6010               MagickError(OptionError,ReferenceImageRequired,NULL);
6011               goto ReturnIt;
6012             }
6013           (void) IsImagesEqual(image,argument_list[0].image_reference);
6014           break;
6015         }
6016         case 77:  /* AdaptiveThreshold */
6017         {
6018           double
6019             offset;
6020 
6021           unsigned long
6022             height,
6023             width;
6024 
6025           height=3;
6026           width=3;
6027           offset=0.0;
6028           if (attribute_flag[1])
6029             width=argument_list[1].int_reference;
6030           if (attribute_flag[2])
6031             height=argument_list[2].int_reference;
6032           if (attribute_flag[3])
6033             offset=argument_list[3].int_reference;;
6034           if (attribute_flag[0])
6035             {
6036               (void) sscanf(argument_list[0].string_reference,"%lux%lu%lf",
6037                 &width,&height,&offset);
6038                if (strchr(argument_list[0].string_reference,'%') != (char *) NULL)
6039                  offset*=(double) MaxRGB/100.0;
6040             }
6041           image=AdaptiveThresholdImage(image,width,height,offset,&exception);
6042           break;
6043         }
6044       }
6045       if (exception.severity != UndefinedException)
6046         CatchException(&exception);
6047       if (next != (Image *) NULL)
6048         (void) CatchImageException(next);
6049       if (region_image != (Image *) NULL)
6050         {
6051           /*unsigned int
6052             status;*/
6053 
6054           /*
6055             Composite region.
6056           */
6057           /*status=*/CompositeImage(region_image,CopyCompositeOp,image,
6058             region_info.x,region_info.y);
6059           (void) CatchImageException(region_image);
6060           DestroyImage(image);
6061           image=region_image;
6062         }
6063       if (image)
6064         {
6065           number_images++;
6066           if (next && (next != image))
6067             {
6068               image->next=next->next;
6069               next->previous=0;
6070               DestroyImage(next);
6071             }
6072           sv_setiv(*pv,(IV) (magick_uintptr_t)image);
6073           next=image;
6074         }
6075       if (*pv)
6076         pv++;
6077     }
6078     DestroyExceptionInfo(&exception);
6079 
6080   ReturnIt:
6081     MagickFreeMemory(reference_vector);
6082     sv_setiv(MY_CXT.error_list,(IV) number_images);
6083     SvPOK_on(MY_CXT.error_list);
6084     ST(0)=sv_2mortal(MY_CXT.error_list);
6085     MY_CXT.error_list=NULL;
6086     MY_CXT.error_jump=NULL;
6087     XSRETURN(1);
6088   }
6089 
6090 #
6091 ###############################################################################
6092 #                                                                             #
6093 #                                                                             #
6094 #                                                                             #
6095 #   M o n t a g e                                                             #
6096 #                                                                             #
6097 #                                                                             #
6098 #                                                                             #
6099 ###############################################################################
6100 #
6101 #
6102 void
Montage(ref,...)6103 Montage(ref,...)
6104   Graphics::Magick ref=NO_INIT
6105   ALIAS:
6106     MontageImage  = 1
6107     montage       = 2
6108     montageimage  = 3
6109   PPCODE:
6110   {
6111     AV
6112       *av;
6113 
6114     char
6115       *attribute;
6116 
6117     ExceptionInfo
6118       exception;
6119 
6120     HV
6121       *hv;
6122 
6123     Image
6124       *image,
6125       *next;
6126 
6127     int
6128       sp;
6129 
6130     jmp_buf
6131       error_jmp;
6132 
6133     MontageInfo
6134       *montage_info;
6135 
6136     PixelPacket
6137       transparent_color;
6138 
6139     register int
6140       i;
6141 
6142     struct PackageInfo
6143       *info;
6144 
6145     SV
6146       *av_reference,
6147       *reference,
6148       *rv,
6149       *sv;
6150 
6151     volatile int
6152       status;
6153 
6154     dMY_CXT;
6155     MY_CXT.error_list=newSVpv("",0);
6156     status=0;
6157     attribute=NULL;
6158     if (!sv_isobject(ST(0)))
6159       {
6160         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
6161         goto MethodException;
6162       }
6163     reference=SvRV(ST(0));
6164     hv=SvSTASH(reference);
6165     av=newAV();
6166     av_reference=sv_2mortal(sv_bless(newRV((SV *) av),hv));
6167     SvREFCNT_dec(av);
6168     MY_CXT.error_jump=(&error_jmp);
6169     status=setjmp(error_jmp);
6170     if (status)
6171       goto MethodException;
6172     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
6173     if (!image)
6174       {
6175         MagickError(OptionError,NoImagesDefined,NULL);
6176         goto MethodException;
6177       }
6178     /*
6179       Get options.
6180     */
6181     info=GetPackageInfo(aTHX_ (void *) av,info);
6182     montage_info=CloneMontageInfo(info->image_info,(MontageInfo *) NULL);
6183     GetExceptionInfo(&exception);
6184     (void) QueryColorDatabase("none",&transparent_color,&exception);
6185     for (i=2; i < items; i+=2)
6186     {
6187       attribute=(char *) SvPV(ST(i-1),na);
6188       switch (*attribute)
6189       {
6190         case 'B':
6191         case 'b':
6192         {
6193           if (LocaleCompare(attribute,"background") == 0)
6194             {
6195               (void) QueryColorDatabase(SvPV(ST(i),na),
6196                 &montage_info->background_color,&exception);
6197               break;
6198             }
6199           if (LocaleCompare(attribute,"bordercolor") == 0)
6200             {
6201               (void) QueryColorDatabase(SvPV(ST(i),na),
6202                 &montage_info->border_color,&exception);
6203               break;
6204             }
6205           if (LocaleCompare(attribute,"borderwidth") == 0)
6206             {
6207               montage_info->border_width=SvIV(ST(i));
6208               break;
6209             }
6210           MagickError(OptionError,UnrecognizedAttribute,attribute);
6211           break;
6212         }
6213         case 'C':
6214         case 'c':
6215         {
6216           if (LocaleCompare(attribute,"compose") == 0)
6217             {
6218               sp=!SvPOK(ST(i)) ? SvIV(ST(i)) :
6219                 LookupStr(CompositeTypes,SvPV(ST(i),na));
6220               if (sp < 0)
6221                 {
6222                   MagickError(OptionError,UnrecognizedType,
6223                     SvPV(ST(i),na));
6224                   break;
6225                 }
6226               for (next=image; next; next=next->next)
6227                 next->compose=(CompositeOperator) sp;
6228               break;
6229             }
6230           MagickError(OptionError,UnrecognizedAttribute,attribute);
6231           break;
6232         }
6233         case 'F':
6234         case 'f':
6235         {
6236           if (LocaleCompare(attribute,"fill") == 0)
6237             {
6238               (void) QueryColorDatabase(SvPV(ST(i),na),&montage_info->fill,
6239                 &exception);
6240               break;
6241             }
6242           if (LocaleCompare(attribute,"font") == 0)
6243             {
6244               (void) CloneString(&montage_info->font,SvPV(ST(i),na));
6245               break;
6246             }
6247           if (LocaleCompare(attribute,"frame") == 0)
6248             {
6249               char
6250                 *p;
6251 
6252               p=SvPV(ST(i),na);
6253               if (!IsGeometry(p))
6254                 {
6255                   MagickError(OptionError,MissingGeometry,p);
6256                   break;
6257                 }
6258               (void) CloneString(&montage_info->frame,p);
6259               if (*p == '\0')
6260                 montage_info->frame=(char *) NULL;
6261               break;
6262             }
6263           MagickError(OptionError,UnrecognizedAttribute,attribute);
6264           break;
6265         }
6266         case 'G':
6267         case 'g':
6268         {
6269           if (LocaleCompare(attribute,"geometry") == 0)
6270             {
6271               char
6272                 *p;
6273 
6274               p=SvPV(ST(i),na);
6275               if (!IsGeometry(p))
6276                 {
6277                   MagickError(OptionError,MissingGeometry,p);
6278                   break;
6279                 }
6280              (void) CloneString(&montage_info->geometry,p);
6281              if (*p == '\0')
6282                montage_info->geometry=(char *) NULL;
6283              break;
6284            }
6285          if (LocaleCompare(attribute,"gravity") == 0)
6286            {
6287              int
6288                in;
6289 
6290              in=!SvPOK(ST(i)) ? SvIV(ST(i)) :
6291                LookupStr(GravityTypes,SvPV(ST(i),na));
6292              if (in < 0)
6293                {
6294                  MagickError(OptionError,UnrecognizedType,SvPV(ST(i),na));
6295                  return;
6296                }
6297              montage_info->gravity=(GravityType) in;
6298              for (next=image; next; next=next->next)
6299                next->gravity=(GravityType) in;
6300              break;
6301            }
6302           MagickError(OptionError,UnrecognizedAttribute,attribute);
6303           break;
6304         }
6305         case 'L':
6306         case 'l':
6307         {
6308           if (LocaleCompare(attribute,"label") == 0)
6309             {
6310               for (next=image; next; next=next->next)
6311                 (void) SetImageAttribute(next,"label",SvPV(ST(i),na));
6312               break;
6313             }
6314           MagickError(OptionError,UnrecognizedAttribute,attribute);
6315           break;
6316         }
6317         case 'M':
6318         case 'm':
6319         {
6320           if (LocaleCompare(attribute,"mattecolor") == 0)
6321             {
6322               (void) QueryColorDatabase(SvPV(ST(i),na),
6323                 &montage_info->matte_color,&exception);
6324               break;
6325             }
6326           if (LocaleCompare(attribute,"mode") == 0)
6327             {
6328               int
6329                 in;
6330 
6331               in=!SvPOK(ST(i)) ? SvIV(ST(i)) :
6332                 LookupStr(ModeTypes,SvPV(ST(i),na));
6333               switch (in)
6334               {
6335                 default:
6336                 {
6337                   MagickError(OptionError,UnrecognizedModeType,
6338                     SvPV(ST(i),na));
6339                   break;
6340                 }
6341                 case FrameMode:
6342                 {
6343                   (void) CloneString(&montage_info->frame,"15x15+3+3");
6344                   montage_info->shadow=True;
6345                   break;
6346                 }
6347                 case UnframeMode:
6348                 {
6349                   montage_info->frame=(char *) NULL;
6350                   montage_info->shadow=False;
6351                   montage_info->border_width=0;
6352                   break;
6353                 }
6354                 case ConcatenateMode:
6355                 {
6356                   montage_info->frame=(char *) NULL;
6357                   montage_info->shadow=False;
6358                   (void) CloneString(&montage_info->geometry,"+0+0");
6359                   montage_info->border_width=0;
6360                 }
6361               }
6362               break;
6363             }
6364           MagickError(OptionError,UnrecognizedAttribute,attribute);
6365           break;
6366         }
6367         case 'P':
6368         case 'p':
6369         {
6370           if (LocaleCompare(attribute,"pointsize") == 0)
6371             {
6372               montage_info->pointsize=SvIV(ST(i));
6373               break;
6374             }
6375           MagickError(OptionError,UnrecognizedAttribute,attribute);
6376           break;
6377         }
6378         case 'S':
6379         case 's':
6380         {
6381           if (LocaleCompare(attribute,"shadow") == 0)
6382             {
6383               sp=!SvPOK(ST(i)) ? SvIV(ST(i)) :
6384                 LookupStr(BooleanTypes,SvPV(ST(i),na));
6385               if (sp < 0)
6386                 {
6387                   MagickError(OptionError,UnrecognizedType,SvPV(ST(i),na));
6388                   break;
6389                 }
6390              montage_info->shadow=sp != 0;
6391              break;
6392             }
6393           if (LocaleCompare(attribute,"stroke") == 0)
6394             {
6395               (void) QueryColorDatabase(SvPV(ST(i),na),&montage_info->stroke,
6396                 &exception);
6397               break;
6398             }
6399           MagickError(OptionError,UnrecognizedAttribute,attribute);
6400           break;
6401         }
6402         case 'T':
6403         case 't':
6404         {
6405           if (LocaleCompare(attribute,"texture") == 0)
6406             {
6407               (void) CloneString(&montage_info->texture,SvPV(ST(i),na));
6408               break;
6409             }
6410           if (LocaleCompare(attribute,"tile") == 0)
6411             {
6412               char *p=SvPV(ST(i),na);
6413               if (!IsGeometry(p))
6414                 {
6415                   MagickError(OptionError,MissingGeometry,p);
6416                   break;
6417                 }
6418               (void) CloneString(&montage_info->tile,p);
6419               if (*p == '\0')
6420                 montage_info->tile=(char *) NULL;
6421               break;
6422             }
6423           if (LocaleCompare(attribute,"title") == 0)
6424             {
6425               (void) CloneString(&montage_info->title,SvPV(ST(i),na));
6426               break;
6427             }
6428           if (LocaleCompare(attribute,"transparent") == 0)
6429             {
6430               (void) AcquireOnePixelByReference(image,&transparent_color,0,0,&exception);
6431               QueryColorDatabase(SvPV(ST(i),na),&transparent_color,
6432                 &exception);
6433               for (next=image; next; next=next->next)
6434                 TransparentImage(next,transparent_color,TransparentOpacity);
6435               break;
6436             }
6437           MagickError(OptionError,UnrecognizedAttribute,attribute);
6438           break;
6439         }
6440         default:
6441         {
6442           MagickError(OptionError,UnrecognizedAttribute,attribute);
6443           break;
6444         }
6445       }
6446     }
6447     image=MontageImages(image,montage_info,&exception);
6448     if (exception.severity != UndefinedException)
6449       CatchException(&exception);
6450     DestroyExceptionInfo(&exception);
6451     DestroyMontageInfo(montage_info);
6452     if (transparent_color.opacity != TransparentOpacity)
6453       for (next=image; next; next=next->next)
6454         TransparentImage(next,transparent_color,TransparentOpacity);
6455     for (  ; image; image=image->next)
6456     {
6457       sv=newSViv((IV) (magick_uintptr_t)image);
6458       rv=newRV(sv);
6459       av_push(av,sv_bless(rv,hv));
6460       SvREFCNT_dec(sv);
6461     }
6462     ST(0)=av_reference;
6463     MY_CXT.error_jump=NULL;
6464     SvREFCNT_dec(MY_CXT.error_list);
6465     MY_CXT.error_list=NULL;
6466     XSRETURN(1);
6467 
6468   MethodException:
6469     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
6470     SvPOK_on(MY_CXT.error_list);
6471     ST(0)=sv_2mortal(MY_CXT.error_list);
6472     MY_CXT.error_list=NULL;
6473     MY_CXT.error_jump=NULL;
6474     XSRETURN(1);
6475   }
6476 
6477 #
6478 ###############################################################################
6479 #                                                                             #
6480 #                                                                             #
6481 #                                                                             #
6482 #   M o r p h                                                                 #
6483 #                                                                             #
6484 #                                                                             #
6485 #                                                                             #
6486 ###############################################################################
6487 #
6488 #
6489 void
Morph(ref,...)6490 Morph(ref,...)
6491   Graphics::Magick ref=NO_INIT
6492   ALIAS:
6493     MorphImage  = 1
6494     morph       = 2
6495     morphimage  = 3
6496   PPCODE:
6497   {
6498     AV
6499       *av;
6500 
6501     char
6502       *attribute;
6503 
6504     ExceptionInfo
6505       exception;
6506 
6507     HV
6508       *hv;
6509 
6510     Image
6511       *image;
6512 
6513     jmp_buf
6514       error_jmp;
6515 
6516     int
6517       number_frames;
6518 
6519     register int
6520       i;
6521 
6522     struct PackageInfo
6523       *info;
6524 
6525     SV
6526       *av_reference,
6527       *reference,
6528       *rv,
6529       *sv;
6530 
6531     volatile int
6532       status;
6533 
6534     dMY_CXT;
6535     MY_CXT.error_list=newSVpv("",0);
6536     av=NULL;
6537     status=0;
6538     attribute=NULL;
6539     if (!sv_isobject(ST(0)))
6540       {
6541         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
6542         goto MethodException;
6543       }
6544     reference=SvRV(ST(0));
6545     hv=SvSTASH(reference);
6546     av=newAV();
6547     av_reference=sv_2mortal(sv_bless(newRV((SV *) av),hv));
6548     SvREFCNT_dec(av);
6549     MY_CXT.error_jump=(&error_jmp);
6550     status=setjmp(error_jmp);
6551     if (status)
6552       goto MethodException;
6553     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
6554     if (!image)
6555       {
6556         MagickError(OptionError,NoImagesDefined,NULL);
6557         goto MethodException;
6558       }
6559     info=GetPackageInfo(aTHX_ (void *) av,info);
6560     /*
6561       Get attribute.
6562     */
6563     number_frames=30;
6564     for (i=2; i < items; i+=2)
6565     {
6566       attribute=(char *) SvPV(ST(i-1),na);
6567       switch (*attribute)
6568       {
6569         case 'F':
6570         case 'f':
6571         {
6572           if (LocaleCompare(attribute,"frames") == 0)
6573             {
6574               number_frames=SvIV(ST(i));
6575               break;
6576             }
6577           MagickError(OptionError,UnrecognizedAttribute,attribute);
6578           break;
6579         }
6580         default:
6581         {
6582           MagickError(OptionError,UnrecognizedAttribute,attribute);
6583           break;
6584         }
6585       }
6586     }
6587     GetExceptionInfo(&exception);
6588     image=MorphImages(image,number_frames,&exception);
6589     if (exception.severity != UndefinedException)
6590       CatchException(&exception);
6591     DestroyExceptionInfo(&exception);
6592     for ( ; image; image=image->next)
6593     {
6594       sv=newSViv((IV) (magick_uintptr_t)image);
6595       rv=newRV(sv);
6596       av_push(av,sv_bless(rv,hv));
6597       SvREFCNT_dec(sv);
6598     }
6599     ST(0)=av_reference;
6600     MY_CXT.error_jump=NULL;
6601     SvREFCNT_dec(MY_CXT.error_list);  /* can't return warning messages */
6602     MY_CXT.error_list=NULL;
6603     XSRETURN(1);
6604 
6605   MethodException:
6606     MY_CXT.error_jump=NULL;
6607     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
6608     SvPOK_on(MY_CXT.error_list);
6609     ST(0)=sv_2mortal(MY_CXT.error_list);
6610     MY_CXT.error_list=NULL;
6611     MY_CXT.error_jump=NULL;
6612     XSRETURN(1);
6613   }
6614 
6615 #
6616 ###############################################################################
6617 #                                                                             #
6618 #                                                                             #
6619 #                                                                             #
6620 #   M o s a i c                                                               #
6621 #                                                                             #
6622 #                                                                             #
6623 #                                                                             #
6624 ###############################################################################
6625 #
6626 #
6627 void
Mosaic(ref)6628 Mosaic(ref)
6629   Graphics::Magick ref=NO_INIT
6630   ALIAS:
6631     MosaicImage   = 1
6632     mosaic        = 2
6633     mosaicimage   = 3
6634   PPCODE:
6635   {
6636     AV
6637       *av;
6638 
6639     ExceptionInfo
6640       exception;
6641 
6642     HV
6643       *hv;
6644 
6645     jmp_buf
6646       error_jmp;
6647 
6648     Image
6649       *image;
6650 
6651     struct PackageInfo
6652       *info;
6653 
6654     SV
6655       *reference,
6656       *rv,
6657       *sv;
6658 
6659     volatile int
6660       status;
6661 
6662     dMY_CXT;
6663     MY_CXT.error_list=newSVpv("",0);
6664     status=0;
6665     if (!sv_isobject(ST(0)))
6666       {
6667         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
6668         goto MethodException;
6669       }
6670     reference=SvRV(ST(0));
6671     hv=SvSTASH(reference);
6672     MY_CXT.error_jump=(&error_jmp);
6673     status=setjmp(error_jmp);
6674     if (status)
6675       goto MethodException;
6676     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
6677     if (!image)
6678       {
6679         MagickError(OptionError,NoImagesDefined,NULL);
6680         goto MethodException;
6681       }
6682     GetExceptionInfo(&exception);
6683     image=MosaicImages(image,&exception);
6684     if (exception.severity != UndefinedException)
6685       CatchException(&exception);
6686     /*
6687       Create blessed Perl array for the returned image.
6688     */
6689     av=newAV();
6690     ST(0)=sv_2mortal(sv_bless(newRV((SV *) av),hv));
6691     SvREFCNT_dec(av);
6692     sv=newSViv((IV) (magick_uintptr_t)image);
6693     rv=newRV(sv);
6694     av_push(av,sv_bless(rv,hv));
6695     SvREFCNT_dec(sv);
6696     info=GetPackageInfo(aTHX_ (void *) av,info);
6697     (void) strncpy(image->filename,info->image_info->filename,MaxTextExtent-1);
6698     SetImageInfo(info->image_info,SETMAGICK_WRITE,&image->exception);
6699     if (exception.severity != UndefinedException)
6700       CatchException(&exception);
6701     DestroyExceptionInfo(&exception);
6702     SvREFCNT_dec(MY_CXT.error_list);
6703     MY_CXT.error_jump=NULL;
6704     XSRETURN(1);
6705 
6706   MethodException:
6707     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
6708     SvPOK_on(MY_CXT.error_list);  /* return messages in string context */
6709     ST(0)=sv_2mortal(MY_CXT.error_list);
6710     MY_CXT.error_list=NULL;
6711     MY_CXT.error_jump=NULL;
6712     XSRETURN(1);
6713   }
6714 
6715 #
6716 ###############################################################################
6717 #                                                                             #
6718 #                                                                             #
6719 #                                                                             #
6720 #   P i n g                                                                   #
6721 #                                                                             #
6722 #                                                                             #
6723 #                                                                             #
6724 ###############################################################################
6725 #
6726 #
6727 void
Ping(ref,...)6728 Ping(ref,...)
6729   Graphics::Magick ref=NO_INIT
6730   ALIAS:
6731     PingImage  = 1
6732     ping       = 2
6733     pingimage  = 3
6734   PPCODE:
6735   {
6736     AV
6737       *av;
6738 
6739     char
6740       **keep,
6741       **list,
6742       message[MaxTextExtent];
6743 
6744     ExceptionInfo
6745       exception;
6746 
6747     /*
6748     HV
6749       *hv;
6750       */
6751 
6752     Image
6753       *image,
6754       *next;
6755 
6756     int
6757       ac,
6758       n;
6759 
6760     jmp_buf
6761       error_jmp;
6762 
6763     register char
6764       **p;
6765 
6766     register int
6767       i;
6768 
6769     struct PackageInfo
6770       *info,
6771       *package_info;
6772 
6773     SV
6774       *reference;
6775 
6776     unsigned int
6777       status;
6778 
6779     unsigned long
6780       count;
6781 
6782     dMY_CXT;
6783     MY_CXT.error_list=newSVpv("",0);
6784     package_info=(struct PackageInfo *) NULL;
6785     ac=(items < 2) ? 1 : items-1;
6786     list=MagickAllocateMemory(char **,(ac+1)*sizeof(*list));
6787     reference=SvRV(ST(0));
6788     /* hv= SvSTASH(reference); */
6789     av=(AV *) reference;
6790     info=GetPackageInfo(aTHX_ (void *) av,(struct PackageInfo *) NULL);
6791     package_info=ClonePackageInfo(info);
6792     n=1;
6793     if (items <= 1)
6794       *list=(char *) (*package_info->image_info->filename ?
6795         package_info->image_info->filename : "XC:black");
6796     else
6797       for (n=0, i=0; i < ac; i++)
6798       {
6799         STRLEN
6800           length;
6801 
6802         list[n]=(char *) SvPV(ST(i+1),length);
6803         if ((items >= 3) && strEQcase(list[n],"blob"))
6804           {
6805             package_info->image_info->blob=(void *) (SvPV(ST(i+2),length));
6806             package_info->image_info->length=(size_t) length;
6807             continue;
6808           }
6809         if ((items >= 3) && strEQcase(list[n],"filename"))
6810           continue;
6811         if ((items >= 3) && strEQcase(list[n],"file"))
6812           {
6813             package_info->image_info->file=
6814               PerlIO_findFILE(IoIFP(sv_2io(ST(i+2))));
6815             continue;
6816           }
6817         n++;
6818       }
6819     list[n]=(char *) NULL;
6820     keep=list;
6821     MY_CXT.error_jump=(&error_jmp);
6822     if (setjmp(error_jmp))
6823       goto ReturnIt;
6824     status=ExpandFilenames(&n,&list);
6825     if (status == False)
6826       {
6827         MagickError(ResourceLimitError,MemoryAllocationFailed,NULL);
6828         goto ReturnIt;
6829       }
6830     count=0;
6831     GetExceptionInfo(&exception);
6832     for (i=0; i < n; i++)
6833     {
6834       (void) strncpy(package_info->image_info->filename,list[i],
6835         MaxTextExtent-1);
6836       image=PingImage(package_info->image_info,&exception);
6837       if (exception.severity != UndefinedException)
6838         CatchException(&exception);
6839       count+=GetImageListLength(image);
6840       EXTEND(sp,4*count);
6841       for (next=image; next; next=next->next)
6842       {
6843         FormatString(message,"%lu",next->columns);
6844         PUSHs(sv_2mortal(newSVpv(message,0)));
6845         FormatString(message,"%lu",next->rows);
6846         PUSHs(sv_2mortal(newSVpv(message,0)));
6847         FormatString(message,"%lu",(unsigned long) GetBlobSize(next));
6848         PUSHs(sv_2mortal(newSVpv(message,0)));
6849         PUSHs(sv_2mortal(newSVpv(next->magick,0)));
6850       }
6851       DestroyImageList(image);
6852     }
6853     DestroyExceptionInfo(&exception);
6854     /*
6855       Free resources.
6856     */
6857     for (i=0; i < n; i++)
6858       if (list[i])
6859         for (p=keep; list[i] != *p++; )
6860           if (*p == NULL)
6861             {
6862               MagickFreeMemory(list[i]);
6863               break;
6864             }
6865 
6866   ReturnIt:
6867     if (package_info)
6868       DestroyPackageInfo(package_info);
6869     MagickFreeMemory(list);
6870     SvREFCNT_dec(MY_CXT.error_list);  /* throw away all errors */
6871     MY_CXT.error_list=NULL;
6872   }
6873 
6874 #
6875 ###############################################################################
6876 #                                                                             #
6877 #                                                                             #
6878 #                                                                             #
6879 #   Q u e r y C o l o r                                                       #
6880 #                                                                             #
6881 #                                                                             #
6882 #                                                                             #
6883 ###############################################################################
6884 #
6885 #
6886 void
QueryColor(ref,...)6887 QueryColor(ref,...)
6888   Graphics::Magick ref=NO_INIT
6889   ALIAS:
6890     querycolor = 1
6891   PPCODE:
6892   {
6893     char
6894       *name,
6895       message[MaxTextExtent];
6896 
6897     ExceptionInfo
6898       exception;
6899 
6900     PixelPacket
6901       color;
6902 
6903     register int
6904       i;
6905 
6906     dMY_CXT;
6907     MY_CXT.error_list=newSVpv("",0);
6908     if (items == 1)
6909       {
6910         char
6911           **colorlist;
6912 
6913         unsigned long
6914           colors;
6915 
6916         colorlist=GetColorList("*",&colors);
6917         EXTEND(sp,colors);
6918         for (i=0; i < (long) colors; i++)
6919         {
6920           PUSHs(sv_2mortal(newSVpv(colorlist[i],0)));
6921           MagickFreeMemory(colorlist[i]);
6922         }
6923         MagickFreeMemory(colorlist);
6924         goto MethodException;
6925       }
6926     EXTEND(sp,4*items);
6927     GetExceptionInfo(&exception);
6928     for (i=1; i < items; i++)
6929     {
6930       name=(char *) SvPV(ST(i),na);
6931       if (!QueryColorDatabase(name,&color,&exception))
6932         {
6933           PUSHs(&sv_undef);
6934           continue;
6935         }
6936       FormatString(message,"%u",color.red);
6937       PUSHs(sv_2mortal(newSVpv(message,0)));
6938       FormatString(message,"%u",color.green);
6939       PUSHs(sv_2mortal(newSVpv(message,0)));
6940       FormatString(message,"%u",color.blue);
6941       PUSHs(sv_2mortal(newSVpv(message,0)));
6942       FormatString(message,"%u",color.opacity);
6943       PUSHs(sv_2mortal(newSVpv(message,0)));
6944     }
6945     DestroyExceptionInfo(&exception);
6946 
6947   MethodException:
6948     SvREFCNT_dec(MY_CXT.error_list);
6949     MY_CXT.error_list=NULL;
6950   }
6951 
6952 #
6953 ###############################################################################
6954 #                                                                             #
6955 #                                                                             #
6956 #                                                                             #
6957 #   Q u e r y C o l o r N a m e                                               #
6958 #                                                                             #
6959 #                                                                             #
6960 #                                                                             #
6961 ###############################################################################
6962 #
6963 #
6964 void
QueryColorname(ref,...)6965 QueryColorname(ref,...)
6966   Graphics::Magick ref=NO_INIT
6967   ALIAS:
6968     querycolorname = 1
6969   PPCODE:
6970   {
6971     AV
6972       *av;
6973 
6974     char
6975       message[MaxTextExtent];
6976 
6977     ExceptionInfo
6978       exception;
6979 
6980     Image
6981       *image;
6982 
6983     PixelPacket
6984       target_color;
6985 
6986     register int
6987       i;
6988 
6989     struct PackageInfo
6990       *info;
6991 
6992     SV
6993       *reference;  /* reference is the SV* of ref=SvIV(reference) */
6994 
6995     dMY_CXT;
6996     MY_CXT.error_list=newSVpv("",0);
6997     reference=SvRV(ST(0));
6998     av=(AV *) reference;
6999     info=GetPackageInfo(aTHX_ (void *) av,(struct PackageInfo *) NULL);
7000     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
7001     EXTEND(sp,items);
7002     GetExceptionInfo(&exception);
7003     for (i=1; i < items; i++)
7004     {
7005       (void) QueryColorDatabase(SvPV(ST(i),na),&target_color,&exception);
7006       (void) QueryColorname(image,&target_color,SVGCompliance,message,
7007         &image->exception);
7008       PUSHs(sv_2mortal(newSVpv(message,0)));
7009     }
7010     DestroyExceptionInfo(&exception);
7011     SvREFCNT_dec(MY_CXT.error_list);
7012     MY_CXT.error_list=NULL;
7013   }
7014 
7015 #
7016 ###############################################################################
7017 #                                                                             #
7018 #                                                                             #
7019 #                                                                             #
7020 #   Q u e r y F o n t                                                         #
7021 #                                                                             #
7022 #                                                                             #
7023 #                                                                             #
7024 ###############################################################################
7025 #
7026 #
7027 void
QueryFont(ref,...)7028 QueryFont(ref,...)
7029   Graphics::Magick ref=NO_INIT
7030   ALIAS:
7031     queryfont = 1
7032   PPCODE:
7033   {
7034     char
7035       *name,
7036       message[MaxTextExtent];
7037 
7038     ExceptionInfo
7039       exception;
7040 
7041     register int
7042       i;
7043 
7044     volatile const TypeInfo
7045       *type_info;
7046 
7047     dMY_CXT;
7048     MY_CXT.error_list=newSVpv("",0);
7049     if (items == 1)
7050       {
7051         char
7052           **typelist;
7053 
7054         unsigned long
7055           types;
7056 
7057         typelist=GetTypeList("*",&types);
7058         EXTEND(sp,types);
7059         for (i=0; i < (long) types; i++)
7060         {
7061           PUSHs(sv_2mortal(newSVpv(typelist[i],0)));
7062           MagickFreeMemory(typelist[i]);
7063         }
7064         MagickFreeMemory(typelist);
7065         goto MethodException;
7066       }
7067     EXTEND(sp,10*items);
7068     GetExceptionInfo(&exception);
7069     for (i=1; i < items; i++)
7070     {
7071       name=(char *) SvPV(ST(i),na);
7072       type_info=GetTypeInfo(name,&exception);
7073       if (exception.severity != UndefinedException)
7074         CatchException(&exception);
7075       if (type_info == (TypeInfo *) NULL)
7076         {
7077           PUSHs(&sv_undef);
7078           continue;
7079         }
7080       if (type_info->name == (char *) NULL)
7081         PUSHs(&sv_undef);
7082       else
7083         PUSHs(sv_2mortal(newSVpv(type_info->name,0)));
7084       if (type_info->description == (char *) NULL)
7085         PUSHs(&sv_undef);
7086       else
7087         PUSHs(sv_2mortal(newSVpv(type_info->description,0)));
7088       if (type_info->family == (char *) NULL)
7089         PUSHs(&sv_undef);
7090       else
7091         PUSHs(sv_2mortal(newSVpv(type_info->family,0)));
7092       PUSHs(sv_2mortal(newSVpv(StyleTypes[(long) type_info->style],0)));
7093       PUSHs(sv_2mortal(newSVpv(StretchTypes[(long) type_info->stretch],0)));
7094       FormatString(message,"%lu",type_info->weight);
7095       PUSHs(sv_2mortal(newSVpv(message,0)));
7096       if (type_info->encoding == (char *) NULL)
7097         PUSHs(&sv_undef);
7098       else
7099         PUSHs(sv_2mortal(newSVpv(type_info->encoding,0)));
7100       if (type_info->foundry == (char *) NULL)
7101         PUSHs(&sv_undef);
7102       else
7103         PUSHs(sv_2mortal(newSVpv(type_info->foundry,0)));
7104       if (type_info->format == (char *) NULL)
7105         PUSHs(&sv_undef);
7106       else
7107         PUSHs(sv_2mortal(newSVpv(type_info->format,0)));
7108       if (type_info->metrics == (char *) NULL)
7109         PUSHs(&sv_undef);
7110       else
7111         PUSHs(sv_2mortal(newSVpv(type_info->metrics,0)));
7112       if (type_info->glyphs == (char *) NULL)
7113         PUSHs(&sv_undef);
7114       else
7115         PUSHs(sv_2mortal(newSVpv(type_info->glyphs,0)));
7116     }
7117     DestroyExceptionInfo(&exception);
7118 
7119   MethodException:
7120     SvREFCNT_dec(MY_CXT.error_list);
7121     MY_CXT.error_list=NULL;
7122   }
7123 
7124 #
7125 ###############################################################################
7126 #                                                                             #
7127 #                                                                             #
7128 #                                                                             #
7129 #   Q u e r y F o n t M e t r i c s                                           #
7130 #                                                                             #
7131 #                                                                             #
7132 #                                                                             #
7133 ###############################################################################
7134 #
7135 #
7136 void
QueryFontMetrics(ref,...)7137 QueryFontMetrics(ref,...)
7138   Graphics::Magick ref=NO_INIT
7139   ALIAS:
7140     queryfontmetrics = 1
7141   PPCODE:
7142   {
7143     AffineMatrix
7144       affine,
7145       current;
7146 
7147     AV
7148       *av;
7149 
7150     char
7151       *attribute,
7152       message[MaxTextExtent];
7153 
7154     double
7155       x,
7156       y;
7157 
7158     DrawInfo
7159       *draw_info;
7160 
7161     Image
7162       *image;
7163 
7164     register int
7165       i;
7166 
7167     struct PackageInfo
7168       *info;
7169 
7170     SV
7171       *reference;  /* reference is the SV* of ref=SvIV(reference) */
7172 
7173     TypeMetric
7174       metrics;
7175 
7176     unsigned int
7177       status;
7178 
7179     dMY_CXT;
7180     MY_CXT.error_list=newSVpv("",0);
7181     reference=SvRV(ST(0));
7182     av=(AV *) reference;
7183     info=GetPackageInfo(aTHX_ (void *) av,(struct PackageInfo *) NULL);
7184     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
7185     if (!image)
7186       {
7187         MagickError(OptionError,NoImagesDefined,NULL);
7188         goto MethodException;
7189       }
7190     draw_info=CloneDrawInfo(info->image_info,info->draw_info);
7191     CloneString(&draw_info->text,"");
7192     current=draw_info->affine;
7193     IdentityAffine(&affine);
7194     x=0.0;
7195     y=0.0;
7196     EXTEND(sp,7*items);
7197     for (i=2; i < items; i+=2)
7198     {
7199       attribute=(char *) SvPV(ST(i-1),na);
7200       switch (*attribute)
7201       {
7202         case 'd':
7203         case 'D':
7204         {
7205           if (LocaleCompare(attribute,"density") == 0)
7206             {
7207               CloneString(&draw_info->density,SvPV(ST(i),na));
7208               break;
7209             }
7210           MagickError(OptionError,UnrecognizedAttribute,attribute);
7211           break;
7212         }
7213         case 'e':
7214         case 'E':
7215         {
7216           if (LocaleCompare(attribute,"encoding") == 0)
7217             {
7218               CloneString(&draw_info->encoding,SvPV(ST(i),na));
7219               break;
7220             }
7221           MagickError(OptionError,UnrecognizedAttribute,attribute);
7222           break;
7223         }
7224         case 'f':
7225         case 'F':
7226         {
7227           if (LocaleCompare(attribute,"font") == 0)
7228             {
7229               CloneString(&draw_info->font,SvPV(ST(i),na));
7230               break;
7231             }
7232           MagickError(OptionError,UnrecognizedAttribute,attribute);
7233           break;
7234         }
7235         case 'g':
7236         case 'G':
7237         {
7238           if (LocaleCompare(attribute,"geometry") == 0)
7239             {
7240               CloneString(&draw_info->geometry,SvPV(ST(i),na));
7241               break;
7242             }
7243           if (LocaleCompare(attribute,"gravity") == 0)
7244             {
7245               draw_info->gravity=(GravityType)
7246                 LookupStr(GravityTypes,SvPV(ST(i),na));
7247               break;
7248             }
7249           MagickError(OptionError,UnrecognizedAttribute,attribute);
7250           break;
7251         }
7252         case 'p':
7253         case 'P':
7254         {
7255           if (LocaleCompare(attribute,"pointsize") == 0)
7256             {
7257               (void) sscanf(SvPV(ST(i),na),"%lf",&draw_info->pointsize);
7258               break;
7259             }
7260           MagickError(OptionError,UnrecognizedAttribute,attribute);
7261           break;
7262         }
7263         case 'r':
7264         case 'R':
7265         {
7266           if (LocaleCompare(attribute,"rotate") == 0)
7267             {
7268               (void) sscanf(SvPV(ST(i),na),"%lf%*[,/]%lf",&affine.rx,
7269                 &affine.ry);
7270               break;
7271             }
7272           MagickError(OptionError,UnrecognizedAttribute,attribute);
7273           break;
7274         }
7275         case 's':
7276         case 'S':
7277         {
7278           if (LocaleCompare(attribute,"scale") == 0)
7279             {
7280               (void) sscanf(SvPV(ST(i),na),"%lf%*[,/]%lf",&affine.sx,
7281                 &affine.sy);
7282               break;
7283             }
7284           if (LocaleCompare(attribute,"skew") == 0)
7285             {
7286               double
7287                 x_angle,
7288                 y_angle;
7289 
7290               x_angle=0.0;
7291               y_angle=0.0;
7292               (void) sscanf(SvPV(ST(i),na),"%lf%*[,/]%lf",&x_angle,&y_angle);
7293               affine.ry=tan(DegreesToRadians(fmod(x_angle,360.0)));
7294               affine.rx=tan(DegreesToRadians(fmod(y_angle,360.0)));
7295               break;
7296             }
7297           MagickError(OptionError,UnrecognizedAttribute,attribute);
7298           break;
7299         }
7300         case 't':
7301         case 'T':
7302         {
7303           if (LocaleCompare(attribute,"text") == 0)
7304             {
7305               CloneString(&draw_info->text,SvPV(ST(i),na));
7306               break;
7307             }
7308           if (LocaleCompare(attribute,"translate") == 0)
7309             {
7310               (void) sscanf(SvPV(ST(i),na),"%lf%*[,/]%lf",&affine.tx,
7311                 &affine.ty);
7312               break;
7313             }
7314           MagickError(OptionError,UnrecognizedAttribute,attribute);
7315           break;
7316         }
7317         case 'x':
7318         case 'X':
7319         {
7320           if (LocaleCompare(attribute,"x") == 0)
7321             {
7322               (void) sscanf(SvPV(ST(i),na),"%lf",&x);
7323               break;
7324             }
7325           MagickError(OptionError,UnrecognizedAttribute,attribute);
7326           break;
7327         }
7328         case 'y':
7329         case 'Y':
7330         {
7331           if (LocaleCompare(attribute,"y") == 0)
7332             {
7333               (void) sscanf(SvPV(ST(i),na),"%lf",&y);
7334               break;
7335             }
7336           MagickError(OptionError,UnrecognizedAttribute,attribute);
7337           break;
7338         }
7339         default:
7340         {
7341           MagickError(OptionError,UnrecognizedAttribute,attribute);
7342           break;
7343         }
7344       }
7345     }
7346     draw_info->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
7347     draw_info->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
7348     draw_info->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
7349     draw_info->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
7350     draw_info->affine.tx=current.sx*affine.tx+current.ry*affine.ty+current.tx;
7351     draw_info->affine.ty=current.rx*affine.tx+current.sy*affine.ty+current.ty;
7352     if (draw_info->geometry == (char *) NULL)
7353       {
7354         draw_info->geometry=AllocateString((char *) NULL);
7355         FormatString(draw_info->geometry,"%g,%g",x,y);
7356       }
7357     status=GetTypeMetrics(image,draw_info,&metrics);
7358     (void) CatchImageException(image);
7359     if (status == False)
7360       PUSHs(&sv_undef);
7361     else
7362       {
7363         FormatString(message,"%g",metrics.pixels_per_em.x);
7364         PUSHs(sv_2mortal(newSVpv(message,0)));
7365         FormatString(message,"%g",metrics.pixels_per_em.y);
7366         PUSHs(sv_2mortal(newSVpv(message,0)));
7367         FormatString(message,"%g",metrics.ascent);
7368         PUSHs(sv_2mortal(newSVpv(message,0)));
7369         FormatString(message,"%g",metrics.descent);
7370         PUSHs(sv_2mortal(newSVpv(message,0)));
7371         FormatString(message,"%g",metrics.width);
7372         PUSHs(sv_2mortal(newSVpv(message,0)));
7373         FormatString(message,"%g",metrics.height);
7374         PUSHs(sv_2mortal(newSVpv(message,0)));
7375         FormatString(message,"%g",metrics.max_advance);
7376         PUSHs(sv_2mortal(newSVpv(message,0)));
7377       }
7378     DestroyDrawInfo(draw_info);
7379 
7380   MethodException:
7381     SvREFCNT_dec(MY_CXT.error_list);
7382     MY_CXT.error_list=NULL;
7383   }
7384 
7385 #
7386 ###############################################################################
7387 #                                                                             #
7388 #                                                                             #
7389 #                                                                             #
7390 #   Q u e r y F o r m a t                                                     #
7391 #                                                                             #
7392 #                                                                             #
7393 #                                                                             #
7394 ###############################################################################
7395 #
7396 #
7397 void
QueryFormat(ref,...)7398 QueryFormat(ref,...)
7399   Graphics::Magick ref=NO_INIT
7400   ALIAS:
7401     queryformat = 1
7402   PPCODE:
7403   {
7404     char
7405       message[MaxTextExtent],
7406       *name;
7407 
7408     ExceptionInfo
7409       exception;
7410 
7411     register int
7412       i;
7413 
7414     volatile const MagickInfo
7415       *magick_info;
7416 
7417     dMY_CXT;
7418     MY_CXT.error_list=newSVpv("",0);
7419     GetExceptionInfo(&exception);
7420     if (items == 1)
7421       {
7422         register volatile const MagickInfo
7423           *p;
7424 
7425         magick_info=GetMagickInfo("*",&exception);
7426         if (magick_info == (const MagickInfo *) NULL)
7427           {
7428             PUSHs(&sv_undef);
7429             goto MethodException;
7430           }
7431         i=0;
7432         for (p=magick_info; p != (MagickInfo *) NULL; p=p->next)
7433           i++;
7434         EXTEND(sp,i);
7435         for (p=magick_info; p != (MagickInfo *) NULL; p=p->next)
7436         {
7437           if (p->stealth)
7438             continue;
7439           if (p->name == (char *) NULL)
7440             {
7441               PUSHs(&sv_undef);
7442               continue;
7443             }
7444           (void) strncpy(message,p->name,MaxTextExtent-1);
7445           LocaleLower(message);
7446           PUSHs(sv_2mortal(newSVpv(message,0)));
7447         }
7448         goto MethodException;
7449       }
7450     EXTEND(sp,8*items);
7451     for (i=1; i < items; i++)
7452     {
7453       name=(char *) SvPV(ST(i),na);
7454       magick_info=GetMagickInfo(name,&exception);
7455       if (exception.severity != UndefinedException)
7456         CatchException(&exception);
7457       if (magick_info == (const MagickInfo *) NULL)
7458         {
7459           PUSHs(&sv_undef);
7460           continue;
7461         }
7462       PUSHs(sv_2mortal(newSVpv(magick_info->adjoin ? "1" : "0",0)));
7463       PUSHs(sv_2mortal(newSVpv(magick_info->blob_support ? "1" : "0",0)));
7464       PUSHs(sv_2mortal(newSVpv(magick_info->raw ? "1" : "0",0)));
7465       PUSHs(sv_2mortal(newSVpv(magick_info->decoder ? "1" : "0",0)));
7466       PUSHs(sv_2mortal(newSVpv(magick_info->encoder ? "1" : "0",0)));
7467       if (magick_info->description == (char *) NULL)
7468         PUSHs(&sv_undef);
7469       else
7470         PUSHs(sv_2mortal(newSVpv(magick_info->description,0)));
7471       if (magick_info->module == (char *) NULL)
7472         PUSHs(&sv_undef);
7473       else
7474         PUSHs(sv_2mortal(newSVpv(magick_info->module,0)));
7475     }
7476     DestroyExceptionInfo(&exception);
7477 
7478   MethodException:
7479     SvREFCNT_dec(MY_CXT.error_list);
7480     MY_CXT.error_list=NULL;
7481   }
7482 
7483 #
7484 ###############################################################################
7485 #                                                                             #
7486 #                                                                             #
7487 #                                                                             #
7488 #   R e a d                                                                   #
7489 #                                                                             #
7490 #                                                                             #
7491 #                                                                             #
7492 ###############################################################################
7493 #
7494 #
7495 void
Read(ref,...)7496 Read(ref,...)
7497   Graphics::Magick ref=NO_INIT
7498   ALIAS:
7499     ReadImage  = 1
7500     read       = 2
7501     readimage  = 3
7502   PPCODE:
7503   {
7504     AV
7505       *av;
7506 
7507     char
7508       **keep,
7509       **list;
7510 
7511     ExceptionInfo
7512       exception;
7513 
7514     HV
7515       *hv;
7516 
7517     Image
7518       *image;
7519 
7520     int
7521       ac,
7522       n;
7523 
7524     jmp_buf
7525       error_jmp;
7526 
7527     register char
7528       **p;
7529 
7530     register int
7531       i;
7532 
7533     struct PackageInfo
7534       *info,
7535       *package_info;
7536 
7537     SV
7538       *reference,
7539       *rv,
7540       *sv;
7541 
7542     unsigned int
7543       status;
7544 
7545     volatile int
7546       number_images;
7547 
7548     dMY_CXT;
7549     MY_CXT.error_list=newSVpv("",0);
7550     package_info=(struct PackageInfo *) NULL;
7551     number_images=0;
7552     ac=(items < 2) ? 1 : items-1;
7553     list=MagickAllocateMemory(char **,(ac+1)*sizeof(*list));
7554     if (!sv_isobject(ST(0)))
7555       {
7556         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
7557         goto ReturnIt;
7558       }
7559     reference=SvRV(ST(0));
7560     hv=SvSTASH(reference);
7561     if (SvTYPE(reference) != SVt_PVAV)
7562       {
7563         MagickError(OptionError,ReferenceIsNotMyType,NULL);
7564         goto ReturnIt;
7565       }
7566     av=(AV *) reference;
7567     info=GetPackageInfo(aTHX_ (void *) av,(struct PackageInfo *) NULL);
7568     package_info=ClonePackageInfo(info);
7569     n=1;
7570     if (items <= 1)
7571       *list=(char *) (*package_info->image_info->filename ?
7572         package_info->image_info->filename : "XC:black");
7573     else
7574       for (n=0, i=0; i < ac; i++)
7575       {
7576         list[n]=(char *) SvPV(ST(i+1),na);
7577         if ((items >= 3) &&
7578             strEQcase(package_info->image_info->filename,"blob"))
7579           {
7580             STRLEN
7581               length;
7582 
7583             i++;
7584             package_info->image_info->blob=(void *) (SvPV(ST(i),length));
7585             package_info->image_info->length=length;
7586           }
7587         if ((items >= 3) && strEQcase(list[n],"filename"))
7588           continue;
7589         if ((items >= 3) && strEQcase(list[n],"file"))
7590           {
7591             package_info->image_info->file=
7592               PerlIO_findFILE(IoIFP(sv_2io(ST(i+2))));
7593             continue;
7594           }
7595         n++;
7596       }
7597     list[n]=(char *) NULL;
7598     keep=list;
7599     MY_CXT.error_jump=(&error_jmp);
7600     if (setjmp(error_jmp))
7601       goto ReturnIt;
7602     status=ExpandFilenames(&n,&list);
7603     if (status == False)
7604       {
7605         MagickError(ResourceLimitError,MemoryAllocationFailed,NULL);
7606         goto ReturnIt;
7607       }
7608     GetExceptionInfo(&exception);
7609     number_images=0;
7610     for (i=0; i < n; i++)
7611     {
7612       (void) strncpy(package_info->image_info->filename,list[i],
7613         MaxTextExtent-1);
7614       image=ReadImage(package_info->image_info,&exception);
7615       if (exception.severity != UndefinedException)
7616         CatchException(&exception);
7617       for ( ; image; image=image->next)
7618       {
7619         sv=newSViv((IV) (magick_uintptr_t)image);
7620         rv=newRV(sv);
7621         av_push(av,sv_bless(rv,hv));
7622         SvREFCNT_dec(sv);
7623         number_images++;
7624       }
7625     }
7626     DestroyExceptionInfo(&exception);
7627     /*
7628       Free resources.
7629     */
7630     for (i=0; i < n; i++)
7631       if (list[i])
7632         for (p=keep; list[i] != *p++; )
7633           if (*p == NULL)
7634             {
7635               MagickFreeMemory(list[i]);
7636               break;
7637             }
7638 
7639   ReturnIt:
7640     if (package_info)
7641       DestroyPackageInfo(package_info);
7642     MagickFreeMemory(list);
7643     sv_setiv(MY_CXT.error_list,(IV) number_images);
7644     SvPOK_on(MY_CXT.error_list);
7645     ST(0)=sv_2mortal(MY_CXT.error_list);
7646     MY_CXT.error_list=NULL;
7647     MY_CXT.error_jump=NULL;
7648     XSRETURN(1);
7649   }
7650 
7651 #
7652 ###############################################################################
7653 #                                                                             #
7654 #                                                                             #
7655 #                                                                             #
7656 #   R e m o t e                                                               #
7657 #                                                                             #
7658 #                                                                             #
7659 #                                                                             #
7660 ###############################################################################
7661 #
7662 #
7663 void
Remote(ref,...)7664 Remote(ref,...)
7665   Graphics::Magick ref=NO_INIT
7666   ALIAS:
7667     RemoteCommand  = 1
7668     remote         = 2
7669     remoteCommand  = 3
7670   PPCODE:
7671   {
7672     AV
7673       *av;
7674 
7675     SV
7676       *reference;
7677 
7678     /*struct PackageInfo
7679      *info;*/
7680 
7681     dMY_CXT;
7682     MY_CXT.error_list=newSVpv("",0);
7683     reference=SvRV(ST(0));
7684     av=(AV *) reference;
7685     /*info=*/GetPackageInfo(aTHX_ (void *) av,(struct PackageInfo *) NULL);
7686 #if defined(XlibSpecificationRelease)
7687     {
7688       Display
7689         *display;
7690 
7691       register int
7692         i;
7693 
7694       display=XOpenDisplay(info->image_info->server_name);
7695       for (i=1; i < items; i++)
7696         XRemoteCommand(display,(char *) NULL,(char *) SvPV(ST(i),na));
7697     }
7698 #endif
7699     SvREFCNT_dec(MY_CXT.error_list);    /* throw away all errors */
7700     MY_CXT.error_list=NULL;
7701   }
7702 
7703 #
7704 ###############################################################################
7705 #                                                                             #
7706 #                                                                             #
7707 #                                                                             #
7708 #   S e t                                                                     #
7709 #                                                                             #
7710 #                                                                             #
7711 #                                                                             #
7712 ###############################################################################
7713 #
7714 #
7715 void
Set(ref,...)7716 Set(ref,...)
7717   Graphics::Magick ref=NO_INIT
7718   ALIAS:
7719     SetAttributes  = 1
7720     SetAttribute   = 2
7721     set            = 3
7722     setattributes  = 4
7723     setattribute   = 5
7724   PPCODE:
7725   {
7726     Image
7727       *image;
7728 
7729     register int
7730       i;
7731 
7732     struct PackageInfo
7733       *info;
7734 
7735     SV
7736       *reference;  /* reference is the SV* of ref=SvIV(reference) */
7737 
7738     dMY_CXT;
7739     MY_CXT.error_list=newSVpv("",0);
7740     if (!sv_isobject(ST(0)))
7741       {
7742         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
7743         goto MethodException;
7744       }
7745     reference=SvRV(ST(0));
7746     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
7747     if (items == 2)
7748       SetAttribute(aTHX_ info,image,"size",ST(1));
7749     else
7750       for (i=2; i < items; i+=2)
7751         SetAttribute(aTHX_ info,image,SvPV(ST(i-1),na),ST(i));
7752 
7753   MethodException:
7754     sv_setiv(MY_CXT.error_list,(IV) (SvCUR(MY_CXT.error_list) != 0));
7755     SvPOK_on(MY_CXT.error_list);
7756     ST(0)=sv_2mortal(MY_CXT.error_list);
7757     MY_CXT.error_list=NULL;
7758     XSRETURN(1);
7759   }
7760 
7761 #
7762 ###############################################################################
7763 #                                                                             #
7764 #                                                                             #
7765 #                                                                             #
7766 #   T r a n s f o r m                                                         #
7767 #                                                                             #
7768 #                                                                             #
7769 #                                                                             #
7770 ###############################################################################
7771 #
7772 #
7773 void
Transform(ref,...)7774 Transform(ref,...)
7775   Graphics::Magick ref=NO_INIT
7776   ALIAS:
7777     TransformImage = 1
7778     transform      = 2
7779     transformimage = 3
7780   PPCODE:
7781   {
7782     AV
7783       *av;
7784 
7785     char
7786       *attribute,
7787       *crop_geometry,
7788       *geometry;
7789 
7790     ExceptionInfo
7791       exception;
7792 
7793     HV
7794       *hv;
7795 
7796     Image
7797       *clone,
7798       *image;
7799 
7800     jmp_buf
7801       error_jmp;
7802 
7803     register int
7804       i;
7805 
7806     struct PackageInfo
7807       *info;
7808 
7809     SV
7810       *av_reference,
7811       *reference,
7812       *rv,
7813       *sv;
7814 
7815     volatile int
7816       status;
7817 
7818     dMY_CXT;
7819     MY_CXT.error_list=newSVpv("",0);
7820     av=NULL;
7821     status=0;
7822     attribute=NULL;
7823     if (!sv_isobject(ST(0)))
7824       {
7825         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
7826         goto MethodException;
7827       }
7828     reference=SvRV(ST(0));
7829     hv=SvSTASH(reference);
7830     av=newAV();
7831     av_reference=sv_2mortal(sv_bless(newRV((SV *) av),hv));
7832     SvREFCNT_dec(av);
7833     MY_CXT.error_jump=(&error_jmp);
7834     status=setjmp(error_jmp);
7835     if (status)
7836       goto MethodException;
7837     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
7838     if (!image)
7839       {
7840         MagickError(OptionError,NoImagesDefined,NULL);
7841         goto MethodException;
7842       }
7843     info=GetPackageInfo(aTHX_ (void *) av,info);
7844     /*
7845       Get attribute.
7846     */
7847     crop_geometry=(char *) NULL;
7848     geometry=(char *) NULL;
7849     for (i=2; i < items; i+=2)
7850     {
7851       attribute=(char *) SvPV(ST(i-1),na);
7852       switch (*attribute)
7853       {
7854         case 'c':
7855         case 'C':
7856         {
7857           if (LocaleCompare(attribute,"crop") == 0)
7858             {
7859               crop_geometry=SvPV(ST(i),na);
7860               break;
7861             }
7862           MagickError(OptionError,UnrecognizedAttribute,attribute);
7863           break;
7864         }
7865         case 'g':
7866         case 'G':
7867         {
7868           if (LocaleCompare(attribute,"geometry") == 0)
7869             {
7870               geometry=SvPV(ST(i),na);
7871               break;
7872             }
7873           MagickError(OptionError,UnrecognizedAttribute,attribute);
7874           break;
7875         }
7876         default:
7877         {
7878           MagickError(OptionError,UnrecognizedAttribute,attribute);
7879           break;
7880         }
7881       }
7882     }
7883     GetExceptionInfo(&exception);
7884     for ( ; image; image=image->next)
7885     {
7886       clone=CloneImage(image,0,0,True,&exception);
7887       if (exception.severity != UndefinedException)
7888         CatchException(&exception);
7889       if (clone == (Image *) NULL)
7890         goto MethodException;
7891       TransformImage(&clone,crop_geometry,geometry);
7892       (void) CatchImageException(clone);
7893       for ( ; clone; clone=clone->next)
7894       {
7895         sv=newSViv((IV) (magick_uintptr_t)clone);
7896         rv=newRV(sv);
7897         av_push(av,sv_bless(rv,hv));
7898         SvREFCNT_dec(sv);
7899       }
7900     }
7901     DestroyExceptionInfo(&exception);
7902     ST(0)=av_reference;
7903     MY_CXT.error_jump=NULL;
7904     SvREFCNT_dec(MY_CXT.error_list);  /* can't return warning messages */
7905     MY_CXT.error_list=NULL;
7906     XSRETURN(1);
7907 
7908   MethodException:
7909     MY_CXT.error_jump=NULL;
7910     sv_setiv(MY_CXT.error_list,(IV) (status ? status : SvCUR(MY_CXT.error_list) != 0));
7911     SvPOK_on(MY_CXT.error_list);
7912     ST(0)=sv_2mortal(MY_CXT.error_list);
7913     MY_CXT.error_list=NULL;
7914     MY_CXT.error_jump=NULL;
7915     XSRETURN(1);
7916   }
7917 
7918 #
7919 ###############################################################################
7920 #                                                                             #
7921 #                                                                             #
7922 #                                                                             #
7923 #   W r i t e                                                                 #
7924 #                                                                             #
7925 #                                                                             #
7926 #                                                                             #
7927 ###############################################################################
7928 #
7929 #
7930 void
Write(ref,...)7931 Write(ref,...)
7932   Graphics::Magick ref=NO_INIT
7933   ALIAS:
7934     WriteImage    = 1
7935     write         = 2
7936     writeimage    = 3
7937   PPCODE:
7938   {
7939     char
7940       filename[MaxTextExtent];
7941 
7942     Image
7943       *image,
7944       *next;
7945 
7946     int
7947       scene;
7948 
7949     register int
7950       i;
7951 
7952     jmp_buf
7953       error_jmp;
7954 
7955     struct PackageInfo
7956       *info,
7957       *package_info;
7958 
7959     SV
7960       *reference;
7961 
7962     volatile int
7963       number_images;
7964 
7965     dMY_CXT;
7966     MY_CXT.error_list=newSVpv("",0);
7967     number_images=0;
7968     package_info=(struct PackageInfo *) NULL;
7969     if (!sv_isobject(ST(0)))
7970       {
7971         MagickError(OptionError,ReferenceIsNotMyType,PackageName);
7972         goto MethodException;
7973       }
7974     reference=SvRV(ST(0));
7975     MY_CXT.error_jump=(&error_jmp);
7976     if (setjmp(error_jmp))
7977       goto MethodException;
7978     image=SetupList(aTHX_ reference,&info,(SV ***) NULL);
7979     if (!image)
7980       {
7981         MagickError(OptionError,NoImagesDefined,NULL);
7982         goto MethodException;
7983       }
7984     package_info=ClonePackageInfo(info);
7985     if (items == 2)
7986       SetAttribute(aTHX_ package_info,NULL,"filename",ST(1));
7987     else
7988       if (items > 2)
7989         for (i=2; i < items; i+=2)
7990           SetAttribute(aTHX_ package_info,image,SvPV(ST(i-1),na),ST(i));
7991     (void) strncpy(filename,package_info->image_info->filename,MaxTextExtent-1);
7992     scene=0;
7993     for (next=image; next; next=next->next)
7994     {
7995       (void) strncpy(next->filename,filename,MaxTextExtent-1);
7996       next->scene=scene++;
7997     }
7998     (void) SetImageInfo(package_info->image_info,
7999                         (SETMAGICK_WRITE |
8000                          (!package_info->image_info->adjoin ? SETMAGICK_RECTIFY: 0U)),
8001                         &image->exception);
8002     for (next=image; next; next=next->next)
8003     {
8004       (void) WriteImage(package_info->image_info,next);
8005       (void) CatchImageException(next);
8006       number_images++;
8007       if (package_info->image_info->adjoin)
8008         break;
8009     }
8010     package_info->image_info->file=(FILE *) NULL;
8011 
8012   MethodException:
8013     if (package_info)
8014       DestroyPackageInfo(package_info);
8015     sv_setiv(MY_CXT.error_list,(IV) number_images);
8016     SvPOK_on(MY_CXT.error_list);
8017     ST(0)=sv_2mortal(MY_CXT.error_list);
8018     MY_CXT.error_list=NULL;
8019     MY_CXT.error_jump=NULL;
8020     XSRETURN(1);
8021   }
8022 
8023 # Local Variables:
8024 # mode: c
8025 # c-basic-offset: 2
8026 # fill-column: 78
8027 # End:
8028