]> granicus.if.org Git - imagemagick/blob - MagickWand/operation.c
Basic changes in prep for "magick" command
[imagemagick] / MagickWand / operation.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %          OOO   PPPP   EEEE  RRRR    AA   TTTTT  III   OOO   N   N           %
7 %         O   O  P   P  E     R   R  A  A    T     I   O   O  NN  N           %
8 %         O   O  PPPP   EEE   RRRR   AAAA    T     I   O   O  N N N           %
9 %         O   O  P      E     R R    A  A    T     I   O   O  N  NN           %
10 %          OOO   P      EEEE  R  RR  A  A    T    III   OOO   N   N           %
11 %                                                                             %
12 %                                                                             %
13 %                         CLI Magick Option Methods                           %
14 %                                                                             %
15 %                              Dragon Computing                               %
16 %                              Anthony Thyssen                                %
17 %                               September 2011                                %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % Apply the given options (settings, and simple, or sequence operations) to
37 % the given image(s) according to the current "image_info", "draw_info", and
38 % "quantize_info" settings, stored in a special CLI Image Wand.
39 %
40 % The final goal is to allow the execution in a strict one option at a time
41 % manner that is needed for 'pipelining and file scripting' of options in
42 % IMv7.
43 %
44 % Anthony Thyssen, September 2011
45 */
46 \f
47 /*
48   Include declarations.
49 */
50 #include "MagickWand/studio.h"
51 #include "MagickWand/MagickWand.h"
52 #include "MagickWand/magick-wand-private.h"
53 #include "MagickWand/operation.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/thread-private.h"
56 #include "MagickCore/string-private.h"
57 \f
58 /*
59   Define declarations.
60 */
61 #define UndefinedCompressionQuality  0UL
62 /*
63   Constant declaration. (temporary exports)
64 */
65 static const char
66   BackgroundColor[] = "#fff",  /* white */
67   BorderColor[] = "#dfdfdf",  /* sRGB gray */
68   MatteColor[] = "#bdbdbd";  /* slightly darker gray */
69 \f
70 /*
71 ** Function to report on the progress of image operations
72 */
73 static MagickBooleanType MonitorProgress(const char *text,
74   const MagickOffsetType offset,const MagickSizeType extent,
75   void *wand_unused(client_data))
76 {
77   char
78     message[MaxTextExtent],
79     tag[MaxTextExtent];
80
81   const char
82     *locale_message;
83
84   register char
85     *p;
86
87   if (extent < 2)
88     return(MagickTrue);
89   (void) CopyMagickMemory(tag,text,MaxTextExtent);
90   p=strrchr(tag,'/');
91   if (p != (char *) NULL)
92     *p='\0';
93   (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
94   locale_message=GetLocaleMessage(message);
95   if (locale_message == message)
96     locale_message=tag;
97   if (p == (char *) NULL)
98     (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
99       locale_message,(long) offset,(unsigned long) extent,(long)
100       (100L*offset/(extent-1)));
101   else
102     (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
103       locale_message,p+1,(long) offset,(unsigned long) extent,(long)
104       (100L*offset/(extent-1)));
105   if (offset == (MagickOffsetType) (extent-1))
106     (void) FormatLocaleFile(stderr,"\n");
107   (void) fflush(stderr);
108   return(MagickTrue);
109 }
110
111 /*
112 ** GetImageCache() will read an image into a image cache if not already
113 ** present then return the image that is in the cache under that filename.
114 */
115 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
116   ExceptionInfo *exception)
117 {
118   char
119     key[MaxTextExtent];
120
121   ExceptionInfo
122     *sans_exception;
123
124   Image
125     *image;
126
127   ImageInfo
128     *read_info;
129
130   (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
131   sans_exception=AcquireExceptionInfo();
132   image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
133   sans_exception=DestroyExceptionInfo(sans_exception);
134   if (image != (Image *) NULL)
135     return(image);
136   read_info=CloneImageInfo(image_info);
137   (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
138   image=ReadImage(read_info,exception);
139   read_info=DestroyImageInfo(read_info);
140   if (image != (Image *) NULL)
141     (void) SetImageRegistry(ImageRegistryType,key,image,exception);
142   return(image);
143 }
144
145 /*
146   SparseColorOption() parse the complex -sparse-color argument into an
147   an array of floating point values than call SparseColorImage().
148   Argument is a complex mix of floating-point pixel coodinates, and color
149   specifications (or direct floating point numbers).  The number of floats
150   needed to represent a color varies depending on teh current channel
151   setting.
152 */
153 static Image *SparseColorOption(const Image *image,
154   const SparseColorMethod method,const char *arguments,
155   ExceptionInfo *exception)
156 {
157   char
158     token[MaxTextExtent];
159
160   const char
161     *p;
162
163   double
164     *sparse_arguments;
165
166   Image
167     *sparse_image;
168
169   PixelInfo
170     color;
171
172   MagickBooleanType
173     error;
174
175   register size_t
176     x;
177
178   size_t
179     number_arguments,
180     number_colors;
181
182   assert(image != (Image *) NULL);
183   assert(image->signature == MagickSignature);
184   if (image->debug != MagickFalse)
185     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
186   assert(exception != (ExceptionInfo *) NULL);
187   assert(exception->signature == MagickSignature);
188   /*
189     Limit channels according to image - and add up number of color channel.
190   */
191   number_colors=0;
192   if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
193     number_colors++;
194   if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
195     number_colors++;
196   if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
197     number_colors++;
198   if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
199       (image->colorspace == CMYKColorspace))
200     number_colors++;
201   if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
202       (image->matte != MagickFalse))
203     number_colors++;
204
205   /*
206     Read string, to determine number of arguments needed,
207   */
208   p=arguments;
209   x=0;
210   while( *p != '\0' )
211   {
212     GetMagickToken(p,&p,token);
213     if ( token[0] == ',' ) continue;
214     if ( isalpha((int) token[0]) || token[0] == '#' )
215       x += number_colors;  /* color argument found */
216     else {
217       x++;   /* floating point argument */
218     }
219   }
220   error=MagickTrue;
221   /* control points and color values */
222   error = ( x % (2+number_colors) != 0 ) ? MagickTrue : MagickFalse;
223   number_arguments=x;
224   if ( error ) {
225     (void) ThrowMagickException(exception,GetMagickModule(),
226                OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
227                "Invalid number of Arguments");
228     return( (Image *)NULL);
229   }
230
231   /* Allocate and fill in the floating point arguments */
232   sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
233     sizeof(*sparse_arguments));
234   if (sparse_arguments == (double *) NULL) {
235     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
236       "MemoryAllocationFailed","%s","SparseColorOption");
237     return( (Image *)NULL);
238   }
239   (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
240     sizeof(*sparse_arguments));
241   p=arguments;
242   x=0;
243   while( *p != '\0' && x < number_arguments ) {
244     /* X coordinate */
245     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
246     if ( token[0] == '\0' ) break;
247     if ( isalpha((int) token[0]) || token[0] == '#' ) {
248       (void) ThrowMagickException(exception,GetMagickModule(),
249             OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
250             "Color found, instead of X-coord");
251       error = MagickTrue;
252       break;
253     }
254     sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
255     /* Y coordinate */
256     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
257     if ( token[0] == '\0' ) break;
258     if ( isalpha((int) token[0]) || token[0] == '#' ) {
259       (void) ThrowMagickException(exception,GetMagickModule(),
260             OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
261             "Color found, instead of Y-coord");
262       error = MagickTrue;
263       break;
264     }
265     sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
266     /* color name or function given in string argument */
267     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
268     if ( token[0] == '\0' ) break;
269     if ( isalpha((int) token[0]) || token[0] == '#' ) {
270       /* Color string given */
271       (void) QueryColorCompliance(token,AllCompliance,&color,
272                 exception);
273       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
274         sparse_arguments[x++] = QuantumScale*color.red;
275       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
276         sparse_arguments[x++] = QuantumScale*color.green;
277       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
278         sparse_arguments[x++] = QuantumScale*color.blue;
279       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
280           (image->colorspace == CMYKColorspace))
281         sparse_arguments[x++] = QuantumScale*color.black;
282       if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
283           (image->matte != MagickFalse))
284         sparse_arguments[x++] = QuantumScale*color.alpha;
285     }
286     else {
287       /* Colors given as a set of floating point values - experimental */
288       /* NB: token contains the first floating point value to use! */
289       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
290         {
291         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
292         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
293           break;
294         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
295         token[0] = ','; /* used this token - get another */
296       }
297       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
298         {
299         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
300         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
301           break;
302         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
303         token[0] = ','; /* used this token - get another */
304       }
305       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
306         {
307         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
308         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
309           break;
310         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
311         token[0] = ','; /* used this token - get another */
312       }
313       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
314           (image->colorspace == CMYKColorspace))
315         {
316         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
317         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
318           break;
319         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
320         token[0] = ','; /* used this token - get another */
321       }
322       if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
323           (image->matte != MagickFalse))
324         {
325         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
326         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
327           break;
328         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
329         token[0] = ','; /* used this token - get another */
330       }
331     }
332   }
333   if ( number_arguments != x && !error ) {
334     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
335       "InvalidArgument","`%s': %s","sparse-color","Argument Parsing Error");
336     sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
337     return( (Image *)NULL);
338   }
339   if ( error )
340     return( (Image *)NULL);
341
342   /* Call the Sparse Color Interpolation function with the parsed arguments */
343   sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
344     exception);
345   sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
346   return( sparse_image );
347 }
348 \f
349 /*
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 %                                                                             %
352 %                                                                             %
353 %                                                                             %
354 +   W a n d S e t t i n g O p t i o n I n f o                                 %
355 %                                                                             %
356 %                                                                             %
357 %                                                                             %
358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359 %
360 %  WandSettingOptionInfo() applies a single settings option into a CLI wand
361 %  holding the image_info, draw_info, quantize_info structures that will be
362 %  used when processing the images also found within the wand.
363 %
364 %  These options do no require images to be present in the wand for them to be
365 %  able to be set, in which case they will be applied to
366 %
367 %  Options handled by this function are listed in CommandOptions[] of
368 %  "option.c" that is one of "SettingOptionFlags" option flags.
369 %
370 %  The format of the WandSettingOptionInfo method is:
371 %
372 %    void WandSettingOptionInfo(MagickWand *wand,const char *option,
373 %               const char *arg)
374 %
375 %  A description of each parameter follows:
376 %
377 %    o wand: structure holding settings to be applied
378 %
379 %    o option: The option string to be set
380 %
381 %    o arg: The single argument used to set this option.
382 %           If NULL the setting is reset to its default value.
383 %           For boolean (no argument) settings false=NULL, true=any_string
384 %
385 % Example usage...
386 %
387 %    WandSettingOptionInfo(wand, "background", MagickTrue, "Red");
388 %    WandSettingOptionInfo(wand, "adjoin", "true");
389 %    WandSettingOptionInfo(wand, "adjoin", NULL);
390 %
391 % Or for handling command line arguments EG: +/-option ["arg"]
392 %
393 %    argc,argv
394 %    i=index in argv
395 %
396 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
397 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
398 %    if ( (flags & SettingOptionFlags) != 0 )
399 %      WandSettingOptionInfo(wand, argv[i]+1,
400 %            (((*argv[i])!='-') ? (char *)NULL
401 %                   : (count>0) ? argv[i+1] : "true") );
402 %    i += count+1;
403 %
404 */
405 WandExport void WandSettingOptionInfo(MagickWand *wand,const char *option,
406      const char *arg)
407 {
408   assert(wand != (MagickWand *) NULL);
409   assert(wand->signature == WandSignature);
410   assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
411   if (wand->debug != MagickFalse)
412     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
413
414 #define image_info      (wand->image_info)
415 #define draw_info       (wand->draw_info)
416 #define quantize_info   (wand->quantize_info)
417 #define exception       (wand->exception)
418 #define IfSetOption     (arg!=(char *)NULL)
419 #define ArgOption(def)  (IfSetOption?arg:(const char *)(def))
420 #define ArgBoolean      (IfSetOption?MagickTrue:MagickFalse)
421
422   switch (*option)
423   {
424     case 'a':
425     {
426       if (LocaleCompare("adjoin",option) == 0)
427         {
428           image_info->adjoin = ArgBoolean;
429           break;
430         }
431       if (LocaleCompare("affine",option) == 0)
432         {
433           /* DEPRECIATED: draw_info setting only: for -draw and -transform */
434           if (IfSetOption)
435             (void) ParseAffineGeometry(arg,&draw_info->affine,exception);
436           else
437             GetAffineMatrix(&draw_info->affine);
438           break;
439         }
440       if (LocaleCompare("antialias",option) == 0)
441         {
442           image_info->antialias =
443             draw_info->stroke_antialias =
444               draw_info->text_antialias = ArgBoolean;
445           break;
446         }
447       if (LocaleCompare("attenuate",option+1) == 0)
448         {
449           (void) SetImageOption(image_info,option,ArgOption(NULL));
450           break;
451         }
452       if (LocaleCompare("authenticate",option) == 0)
453         {
454           (void) SetImageOption(image_info,option,ArgOption(NULL));
455           break;
456         }
457       break;
458     }
459     case 'b':
460     {
461       if (LocaleCompare("background",option) == 0)
462         {
463           /* FUTURE: both image_info attribute & ImageOption in use!
464              image_info only used directly for generating new images.
465              SyncImageSettings() used to set per-image attribute.
466
467              FUTURE: if image_info->background_color is not set then
468              we should fall back to image
469              Note that +background, means fall-back to image background
470              and only if not set fall back to BackgroundColor const.
471           */
472           (void) SetImageOption(image_info,option,ArgOption(NULL));
473           (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance,
474              &image_info->background_color,exception);
475           break;
476         }
477       if (LocaleCompare("bias",option) == 0)
478         {
479           /* FUTURE: bias OBSOLETED, replaced by "convolve:bias"
480              as it is actually rarely used except in direct convolve operations
481              Usage outside a direct convolve operation is actally non-sensible!
482
483              SyncImageSettings() used to set per-image attribute.
484           */
485           (void) SetImageOption(image_info,option,ArgOption("0"));
486           break;
487         }
488       if (LocaleCompare("black-point-compensation",option) == 0)
489         {
490           /* Used as a image chromaticity setting
491              SyncImageSettings() used to set per-image attribute.
492           */
493           (void) SetImageOption(image_info,option,
494                IfSetOption ? "true" : "false" );
495           break;
496         }
497       if (LocaleCompare("blue-primary",option) == 0)
498         {
499           /* Image chromaticity X,Y  NB: Y=X if Y not defined
500              Used by many coders including PNG
501              SyncImageSettings() used to set per-image attribute.
502           */
503           (void) SetImageOption(image_info,option,ArgOption("0.0"));
504           break;
505         }
506       if (LocaleCompare("bordercolor",option) == 0)
507         {
508           /* FUTURE: both image_info attribute & ImageOption in use!
509              SyncImageSettings() used to set per-image attribute.
510           */
511           if (IfSetOption)
512             {
513               (void) SetImageOption(image_info,option,arg);
514               (void) QueryColorCompliance(arg,AllCompliance,
515                   &image_info->border_color,exception);
516               (void) QueryColorCompliance(arg,AllCompliance,
517                   &draw_info->border_color,exception);
518               break;
519             }
520           (void) DeleteImageOption(image_info,option);
521           (void) QueryColorCompliance(BorderColor,AllCompliance,
522             &image_info->border_color,exception);
523           (void) QueryColorCompliance(BorderColor,AllCompliance,
524             &draw_info->border_color,exception);
525           break;
526         }
527       if (LocaleCompare("box",option) == 0)
528         {
529           /* DEPRECIATED - now "undercolor" */
530           WandSettingOptionInfo(wand,"undercolor",arg);
531           break;
532         }
533       break;
534     }
535     case 'c':
536     {
537       if (LocaleCompare("cache",option) == 0)
538         {
539           MagickSizeType
540             limit;
541
542           limit=MagickResourceInfinity;
543           if (LocaleCompare("unlimited",arg) != 0)
544             limit=(MagickSizeType) SiPrefixToDoubleInterval(arg,100.0);
545           (void) SetMagickResourceLimit(MemoryResource,limit);
546           (void) SetMagickResourceLimit(MapResource,2*limit);
547           break;
548         }
549       if (LocaleCompare("caption",option) == 0)
550         {
551           (void) SetImageOption(image_info,option,ArgOption(NULL));
552           break;
553         }
554       if (LocaleCompare("channel",option) == 0)
555         {
556           /* This is applied to images in SimpleImageOperator!!!
557              FUTURE: move it to SyncImageSettings() - or alternative
558           */
559           image_info->channel=(ChannelType) (
560                IfSetOption ? ParseChannelOption(arg) : DefaultChannels );
561           break;
562         }
563       if (LocaleCompare("colorspace",option) == 0)
564         {
565           /* Setting used for new images via AquireImage()
566              But also used as a SimpleImageOperator
567              Undefined colorspace means don't modify images on
568              read or as a operation */
569           image_info->colorspace=(ColorspaceType) ParseCommandOption(
570                MagickColorspaceOptions,MagickFalse,ArgOption("undefined"));
571           break;
572         }
573       if (LocaleCompare("comment",option) == 0)
574         {
575           (void) SetImageOption(image_info,option,ArgOption(NULL));
576           break;
577         }
578       if (LocaleCompare("compose",option) == 0)
579         {
580           /* FUTURE: image_info should be used,
581              SyncImageSettings() used to set per-image attribute. - REMOVE
582
583              This setting should NOT be used to set image 'compose'
584              "-layer" operators shoud use image_info if defined otherwise
585              they should use a per-image compose setting.
586           */
587           (void) SetImageOption(image_info,option,ArgOption(NULL));
588           image_info->compose=(CompositeOperator) ParseCommandOption(
589                MagickComposeOptions,MagickFalse,ArgOption("undefined"));
590           break;
591         }
592       if (LocaleCompare("compress",option) == 0)
593         {
594           /* FUTURE: What should be used?  image_info  or ImageOption ???
595              The former is more efficent, but Crisy prefers the latter!
596              SyncImageSettings() used to set per-image attribute.
597
598              The coders appears to use image_info, not Image_Option
599              however the image attribute (for save) is set from the
600              ImageOption!
601
602              Note that "undefined" is a different setting to "none".
603           */
604           (void) SetImageOption(image_info,option,ArgOption(NULL));
605           image_info->compression=(CompressionType) ParseCommandOption(
606                 MagickCompressOptions,MagickFalse,ArgOption("undefined"));
607           break;
608         }
609       break;
610     }
611     case 'd':
612     {
613       if (LocaleCompare("debug",option) == 0)
614         {
615           /* SyncImageSettings() used to set per-image attribute. */
616           (void) SetLogEventMask(ArgOption("none"));
617           image_info->debug=IsEventLogging(); /* extract logging*/
618           wand->debug=IsEventLogging();
619           break;
620         }
621       if (LocaleCompare("define",option) == 0)
622         {
623           /* DefineImageOption() equals SetImageOption() but with '='
624              It does not however set individual image options.
625              -set will set individual image options as well!
626           */
627           if (LocaleNCompare(arg,"registry:",9) == 0)
628             {
629               if (IfSetOption)
630                 (void) DefineImageRegistry(StringRegistryType,arg+9,
631                     exception);
632               else
633                 (void) DeleteImageRegistry(arg+9);
634               break;
635             }
636           if (IfSetOption)
637             (void) DefineImageOption(image_info,arg);
638           else
639             (void) DeleteImageOption(image_info,arg);
640           break;
641         }
642       if (LocaleCompare("delay",option) == 0)
643         {
644           /* Only used for new images via AcquireImage()
645              FUTURE: Option should also be used for "-morph" (color morphing)
646           */
647           (void) SetImageOption(image_info,option,ArgOption("0"));
648           break;
649         }
650       if (LocaleCompare("density",option) == 0)
651         {
652           /* FUTURE: strings used in image_info attr and draw_info!
653              Basically as density can be in a XxY form!
654
655              SyncImageSettings() used to set per-image attribute.
656           */
657           (void) SetImageOption(image_info,option,ArgOption(NULL));
658           (void) CloneString(&image_info->density,ArgOption(NULL));
659           (void) CloneString(&draw_info->density,image_info->density);
660           break;
661         }
662       if (LocaleCompare("depth",option) == 0)
663         {
664           /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
665              SyncImageSettings() used to set per-image attribute.
666           */
667           image_info->depth=IfSetOption?StringToUnsignedLong(arg)
668                                        :MAGICKCORE_QUANTUM_DEPTH;
669           break;
670         }
671       if (LocaleCompare("direction",option) == 0)
672         {
673           /* Image Option is only used to set draw_info */
674           (void) SetImageOption(image_info,option,ArgOption("undefined"));
675           draw_info->direction=(DirectionType) ParseCommandOption(
676                          MagickDirectionOptions,MagickFalse,
677                          ArgOption("undefined"));
678           break;
679         }
680       if (LocaleCompare("display",option) == 0)
681         {
682           (void) CloneString(&image_info->server_name,ArgOption(NULL));
683           (void) CloneString(&draw_info->server_name,image_info->server_name);
684           break;
685         }
686       if (LocaleCompare("dispose",option) == 0)
687         {
688           /* only used in setting new images */
689           (void) SetImageOption(image_info,option,ArgOption("undefined"));
690           break;
691         }
692       if (LocaleCompare("dither",option) == 0)
693         {
694           /* image_info attr (on/off), quantize_info attr (on/off)
695              but also ImageInfo and quantize_info method!
696              FUTURE: merge the duality of the dithering options
697           */
698           image_info->dither = quantize_info->dither = ArgBoolean;
699           (void) SetImageOption(image_info,option,ArgOption("none"));
700           quantize_info->dither_method=(DitherMethod) ParseCommandOption(
701                     MagickDitherOptions,MagickFalse,ArgOption("none"));
702           if (quantize_info->dither_method == NoDitherMethod)
703             image_info->dither = quantize_info->dither = MagickFalse;
704           break;
705         }
706       break;
707     }
708     case 'e':
709     {
710       if (LocaleCompare("encoding",option) == 0)
711         {
712           (void) CloneString(&draw_info->encoding,ArgOption("undefined"));
713           (void) SetImageOption(image_info,option,draw_info->encoding);
714           break;
715         }
716       if (LocaleCompare("endian",option) == 0)
717         {
718           /* Both image_info attr and ImageInfo */
719           (void) SetImageOption(image_info,option,ArgOption("undefined"));
720           image_info->endian=(EndianType) ParseCommandOption(
721               MagickEndianOptions,MagickFalse,ArgOption("undefined"));
722           break;
723         }
724       if (LocaleCompare("extract",option) == 0)
725         {
726           (void) CloneString(&image_info->extract,ArgOption(NULL));
727           break;
728         }
729       break;
730     }
731     case 'f':
732     {
733       if (LocaleCompare("family",option) == 0)
734         {
735           (void) CloneString(&draw_info->family,ArgOption(NULL));
736           break;
737         }
738       if (LocaleCompare("fill",option) == 0)
739         {
740           /* Set "fill" OR "fill-pattern" in draw_info
741              The original fill color is preserved if a fill-pattern is given.
742              That way it does not effect other operations that directly using
743              the fill color and, can be retored using "+tile".
744           */
745           const char
746             *value;
747
748           MagickBooleanType
749             status;
750
751           ExceptionInfo
752             *sans;
753
754           PixelInfo
755             color;
756
757           value = ArgOption("none");
758           (void) SetImageOption(image_info,option,value);
759           if (draw_info->fill_pattern != (Image *) NULL)
760             draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
761
762           /* is it a color or a image? -- ignore exceptions */
763           sans=AcquireExceptionInfo();
764           status=QueryColorCompliance(value,AllCompliance,&color,sans);
765           sans=DestroyExceptionInfo(sans);
766
767           if (status == MagickFalse)
768             draw_info->fill_pattern=GetImageCache(image_info,value,exception);
769           else
770             draw_info->fill=color;
771           break;
772         }
773       if (LocaleCompare("filter",option) == 0)
774         {
775           /* SyncImageSettings() used to set per-image attribute. */
776           (void) SetImageOption(image_info,option,ArgOption("undefined"));
777           break;
778         }
779       if (LocaleCompare("font",option) == 0)
780         {
781           (void) CloneString(&draw_info->font,ArgOption(NULL));
782           (void) CloneString(&image_info->font,draw_info->font);
783           break;
784         }
785       if (LocaleCompare("format",option) == 0)
786         {
787           /* FUTURE: why the ping test, you could set ping after this! */
788           /*
789           register const char
790             *q;
791
792           for (q=strchr(arg,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
793             if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
794               image_info->ping=MagickFalse;
795           */
796           (void) SetImageOption(image_info,option,ArgOption(NULL));
797           break;
798         }
799       if (LocaleCompare("fuzz",option) == 0)
800         {
801           /* Option used to set image fuzz! unless blank canvas (from color)
802              Image attribute used for color compare operations
803              SyncImageSettings() used to set per-image attribute.
804
805              Can't find anything else using image_info->fuzz directly!
806           */
807           if (IfSetOption)
808             {
809               image_info->fuzz=StringToDoubleInterval(arg,(double)
810                 QuantumRange+1.0);
811               (void) SetImageOption(image_info,option,arg);
812               break;
813             }
814           image_info->fuzz=0.0;
815           (void) SetImageOption(image_info,option,"0");
816           break;
817         }
818       break;
819     }
820     case 'g':
821     {
822       if (LocaleCompare("gravity",option) == 0)
823         {
824           /* SyncImageSettings() used to set per-image attribute. */
825           (void) SetImageOption(image_info,option,ArgOption("none"));
826           draw_info->gravity=(GravityType) ParseCommandOption(
827                    MagickGravityOptions,MagickFalse,ArgOption("none"));
828           break;
829         }
830       if (LocaleCompare("green-primary",option) == 0)
831         {
832           /* Image chromaticity X,Y  NB: Y=X if Y not defined
833              SyncImageSettings() used to set per-image attribute.
834              Used directly by many coders
835           */
836           (void) SetImageOption(image_info,option,ArgOption("0.0"));
837           break;
838         }
839       break;
840     }
841     case 'i':
842     {
843       if (LocaleCompare("intent",option) == 0)
844         {
845           /* Only used by coders: MIFF, MPC, BMP, PNG
846              and for image profile call to AcquireTransformThreadSet()
847              SyncImageSettings() used to set per-image attribute.
848           */
849           (void) SetImageOption(image_info,option,ArgOption("undefined"));
850           break;
851         }
852       if (LocaleCompare("interlace",option) == 0)
853         {
854           /* image_info is directly used by coders (so why an image setting?)
855              SyncImageSettings() used to set per-image attribute.
856           */
857           (void) SetImageOption(image_info,option,ArgOption("undefined"));
858           image_info->interlace=(InterlaceType) ParseCommandOption(
859                 MagickInterlaceOptions,MagickFalse,ArgOption("undefined"));
860           break;
861         }
862       if (LocaleCompare("interline-spacing",option) == 0)
863         {
864           (void) SetImageOption(image_info,option, ArgOption(NULL));
865           draw_info->interline_spacing=StringToDouble(ArgOption("0"),
866                (char **) NULL);
867           break;
868         }
869       if (LocaleCompare("interpolate",option) == 0)
870         {
871           /* SyncImageSettings() used to set per-image attribute. */
872           (void) SetImageOption(image_info,option,ArgOption("undefined"));
873           break;
874         }
875       if (LocaleCompare("interword-spacing",option) == 0)
876         {
877           (void) SetImageOption(image_info,option, ArgOption(NULL));
878           draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
879           break;
880         }
881       break;
882     }
883     case 'k':
884     {
885       if (LocaleCompare("kerning",option) == 0)
886         {
887           (void) SetImageOption(image_info,option,ArgOption(NULL));
888           draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
889           break;
890         }
891       break;
892     }
893     case 'l':
894     {
895       if (LocaleCompare("label",option) == 0)
896         {
897           /* only used for new images - not in SyncImageOptions() */
898           (void) SetImageOption(image_info,option,ArgOption(NULL));
899           break;
900         }
901       if (LocaleCompare("list",option) == 0)
902         {
903           ssize_t
904             list;
905
906           /* FUTURE: This is not really a Setting Option, but a Special
907            * The bulk of this should be turned into a MagickCore function
908            */
909           list=ParseCommandOption(MagickListOptions,MagickFalse,
910                ArgOption("list"));
911           switch (list)
912           {
913             case MagickCoderOptions:
914             {
915               (void) ListCoderInfo((FILE *) NULL,exception);
916               break;
917             }
918             case MagickColorOptions:
919             {
920               (void) ListColorInfo((FILE *) NULL,exception);
921               break;
922             }
923             case MagickConfigureOptions:
924             {
925               (void) ListConfigureInfo((FILE *) NULL,exception);
926               break;
927             }
928             case MagickDelegateOptions:
929             {
930               (void) ListDelegateInfo((FILE *) NULL,exception);
931               break;
932             }
933             case MagickFontOptions:
934             {
935               (void) ListTypeInfo((FILE *) NULL,exception);
936               break;
937             }
938             case MagickFormatOptions:
939             {
940               (void) ListMagickInfo((FILE *) NULL,exception);
941               break;
942             }
943             case MagickLocaleOptions:
944             {
945               (void) ListLocaleInfo((FILE *) NULL,exception);
946               break;
947             }
948             case MagickLogOptions:
949             {
950               (void) ListLogInfo((FILE *) NULL,exception);
951               break;
952             }
953             case MagickMagicOptions:
954             {
955               (void) ListMagicInfo((FILE *) NULL,exception);
956               break;
957             }
958             case MagickMimeOptions:
959             {
960               (void) ListMimeInfo((FILE *) NULL,exception);
961               break;
962             }
963             case MagickModuleOptions:
964             {
965               (void) ListModuleInfo((FILE *) NULL,exception);
966               break;
967             }
968             case MagickPolicyOptions:
969             {
970               (void) ListPolicyInfo((FILE *) NULL,exception);
971               break;
972             }
973             case MagickResourceOptions:
974             {
975               (void) ListMagickResourceInfo((FILE *) NULL,exception);
976               break;
977             }
978             case MagickThresholdOptions:
979             {
980               (void) ListThresholdMaps((FILE *) NULL,exception);
981               break;
982             }
983             default:
984             {
985               (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
986                 exception);
987               break;
988             }
989           }
990           break;
991         }
992       if (LocaleCompare("log",option) == 0)
993         {
994           if (IfSetOption)
995             (void) SetLogFormat(arg);
996           break;
997         }
998       if (LocaleCompare("loop",option) == 0)
999         {
1000           /* SyncImageSettings() used to set per-image attribute. */
1001           (void) SetImageOption(image_info,option,ArgOption("0"));
1002           break;
1003         }
1004       break;
1005     }
1006     case 'm':
1007     {
1008       if (LocaleCompare("mattecolor",option) == 0)
1009         {
1010           /* SyncImageSettings() used to set per-image attribute. */
1011           (void) SetImageOption(image_info,option,ArgOption(NULL));
1012           (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance,
1013              &image_info->matte_color,exception);
1014           break;
1015         }
1016       if (LocaleCompare("monitor",option) == 0)
1017         {
1018           (void) SetImageInfoProgressMonitor(image_info, IfSetOption?
1019                 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1020           break;
1021         }
1022       if (LocaleCompare("monochrome",option) == 0)
1023         {
1024           /* Setting (for some input coders)
1025              But also a special 'type' operator
1026           */
1027           image_info->monochrome= ArgBoolean;
1028           break;
1029         }
1030       break;
1031     }
1032     case 'o':
1033     {
1034       if (LocaleCompare("orient",option) == 0)
1035         {
1036           /* Is not used when defining for new images.
1037              This makes it more of a 'operation' than a setting
1038              FUTURE: make set meta-data operator instead.
1039              SyncImageSettings() used to set per-image attribute.
1040           */
1041           (void) SetImageOption(image_info,option, ArgOption(NULL));
1042           image_info->orientation=(InterlaceType) ParseCommandOption(
1043             MagickOrientationOptions,MagickFalse,ArgOption("undefined"));
1044           break;
1045         }
1046     }
1047     case 'p':
1048     {
1049       if (LocaleCompare("page",option) == 0)
1050         {
1051           /* Only used for new images and image generators
1052              SyncImageSettings() used to set per-image attribute. ?????
1053              That last is WRONG!!!!
1054           */
1055           char
1056             *canonical_page,
1057             page[MaxTextExtent];
1058
1059           const char
1060             *image_option;
1061
1062           MagickStatusType
1063             flags;
1064
1065           RectangleInfo
1066             geometry;
1067
1068           if (!IfSetOption)
1069             {
1070               (void) DeleteImageOption(image_info,option);
1071               (void) CloneString(&image_info->page,(char *) NULL);
1072               break;
1073             }
1074           (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1075           image_option=GetImageOption(image_info,"page");
1076           if (image_option != (const char *) NULL)
1077             flags=ParseAbsoluteGeometry(image_option,&geometry);
1078           canonical_page=GetPageGeometry(arg);
1079           flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1080           canonical_page=DestroyString(canonical_page);
1081           (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1082             (unsigned long) geometry.width,(unsigned long) geometry.height);
1083           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1084             (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1085               (unsigned long) geometry.width,(unsigned long) geometry.height,
1086               (long) geometry.x,(long) geometry.y);
1087           (void) SetImageOption(image_info,option,page);
1088           (void) CloneString(&image_info->page,page);
1089           break;
1090         }
1091       if (LocaleCompare("ping",option) == 0)
1092         {
1093           image_info->ping = ArgBoolean;
1094           break;
1095         }
1096       if (LocaleCompare("pointsize",option) == 0)
1097         {
1098           image_info->pointsize=draw_info->pointsize=
1099                    StringToDouble(ArgOption("12"),(char **) NULL);
1100           break;
1101         }
1102       if (LocaleCompare("precision",option) == 0)
1103         {
1104           (void) SetMagickPrecision(StringToInteger(ArgOption("-1")));
1105           break;
1106         }
1107       /* FUTURE: Only the 'preview' coder appears to use this
1108        * Depreciate the coder?  Leaving only the 'preview' operator.
1109       if (LocaleCompare("preview",option) == 0)
1110         {
1111           image_info->preview_type=UndefinedPreview;
1112           if (IfSetOption)
1113             image_info->preview_type=(PreviewType) ParseCommandOption(
1114                 MagickPreviewOptions,MagickFalse,arg);
1115           break;
1116         }
1117       */
1118       break;
1119     }
1120     case 'q':
1121     {
1122       if (LocaleCompare("quality",option) == 0)
1123         {
1124           (void) SetImageOption(image_info,option,ArgOption(NULL));
1125           image_info->quality=UndefinedCompressionQuality;
1126           if (IfSetOption)
1127             image_info->quality=StringToUnsignedLong(arg);
1128           break;
1129         }
1130       if (LocaleCompare("quantize",option) == 0)
1131         {
1132           /* Just a set direct in quantize_info */
1133           quantize_info->colorspace=UndefinedColorspace;
1134           if (IfSetOption)
1135             quantize_info->colorspace=(ColorspaceType) ParseCommandOption(
1136                  MagickColorspaceOptions,MagickFalse,arg);
1137           break;
1138         }
1139       if (LocaleCompare("quiet",option) == 0)
1140         {
1141           /* FUTURE: if two -quiet is performed you can not do +quiet! */
1142           static WarningHandler
1143             warning_handler = (WarningHandler) NULL;
1144
1145           WarningHandler
1146             tmp = SetWarningHandler((WarningHandler) NULL);
1147
1148           if ( tmp != (WarningHandler) NULL)
1149             warning_handler = tmp; /* remember the old handler */
1150           if (!IfSetOption)        /* set the old handler */
1151             warning_handler=SetWarningHandler(warning_handler);
1152           break;
1153         }
1154       break;
1155     }
1156     case 'r':
1157     {
1158       if (LocaleCompare("red-primary",option) == 0)
1159         {
1160           /* Image chromaticity X,Y  NB: Y=X if Y not defined
1161              Used by many coders
1162              SyncImageSettings() used to set per-image attribute.
1163           */
1164           (void) SetImageOption(image_info,option,ArgOption("0.0"));
1165           break;
1166         }
1167       if (LocaleCompare("render",option) == 0)
1168         {
1169           /* draw_info only setting */
1170           draw_info->render= IfSetOption ? MagickFalse : MagickTrue;
1171           break;
1172         }
1173       break;
1174     }
1175     case 's':
1176     {
1177       if (LocaleCompare("sampling-factor",option) == 0)
1178         {
1179           /* FUTURE: should be converted to jpeg:sampling_factor */
1180           (void) CloneString(&image_info->sampling_factor,ArgOption(NULL));
1181           break;
1182         }
1183       if (LocaleCompare("scene",option) == 0)
1184         {
1185           /* SyncImageSettings() used to set per-image attribute.
1186              What ??? Why ????
1187           */
1188           (void) SetImageOption(image_info,option,ArgOption(NULL));
1189           image_info->scene=StringToUnsignedLong(ArgOption("0"));
1190           break;
1191         }
1192       if (LocaleCompare("seed",option) == 0)
1193         {
1194           SeedPseudoRandomGenerator(
1195                IfSetOption ? (size_t) StringToUnsignedLong(arg)
1196                            : (size_t) time((time_t *) NULL) );
1197           break;
1198         }
1199       if (LocaleCompare("size",option) == 0)
1200         {
1201           /* FUTURE: string in image_info -- convert to Option ???
1202              Look at the special handling for "size" in SetImageOption()
1203            */
1204           (void) CloneString(&image_info->size,ArgOption(NULL));
1205           break;
1206         }
1207       if (LocaleCompare("stretch",option) == 0)
1208         {
1209           draw_info->stretch=(StretchType) ParseCommandOption(
1210               MagickStretchOptions,MagickFalse,ArgOption("undefined"));
1211           break;
1212         }
1213       if (LocaleCompare("stroke",option) == 0)
1214         {
1215           /* set stroke color OR stroke-pattern
1216              UPDATE: ensure stroke color is not destroyed is a pattern
1217              is given. Just in case the color is also used for other purposes.
1218            */
1219           const char
1220             *value;
1221
1222           MagickBooleanType
1223             status;
1224
1225           ExceptionInfo
1226             *sans;
1227
1228           PixelInfo
1229             color;
1230
1231           value = ArgOption("none");
1232           (void) SetImageOption(image_info,option,value);
1233           if (draw_info->stroke_pattern != (Image *) NULL)
1234             draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
1235
1236           /* is it a color or a image? -- ignore exceptions */
1237           sans=AcquireExceptionInfo();
1238           status=QueryColorCompliance(value,AllCompliance,&color,sans);
1239           sans=DestroyExceptionInfo(sans);
1240
1241           if (status == MagickFalse)
1242             draw_info->stroke_pattern=GetImageCache(image_info,value,exception);
1243           else
1244             draw_info->stroke=color;
1245           break;
1246         }
1247       if (LocaleCompare("strokewidth",option) == 0)
1248         {
1249           (void) SetImageOption(image_info,option,ArgOption(NULL));
1250           draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1251                (char **) NULL);
1252           break;
1253         }
1254       if (LocaleCompare("style",option) == 0)
1255         {
1256           draw_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1257                MagickFalse,ArgOption("undefined"));
1258           break;
1259         }
1260       if (LocaleCompare("synchronize",option) == 0)
1261         {
1262           image_info->synchronize = ArgBoolean;
1263           break;
1264         }
1265       break;
1266     }
1267     case 't':
1268     {
1269       if (LocaleCompare("taint",option) == 0)
1270         {
1271           /* SyncImageSettings() used to set per-image attribute. */
1272           (void) SetImageOption(image_info,option,
1273                IfSetOption ? "true" : "false");
1274           break;
1275         }
1276       if (LocaleCompare("texture",option) == 0)
1277         {
1278           /* FUTURE: move image_info string to option splay-tree */
1279           (void) CloneString(&image_info->texture,ArgOption(NULL));
1280           break;
1281         }
1282       if (LocaleCompare("tile",option) == 0)
1283         {
1284           draw_info->fill_pattern=IfSetOption
1285                                  ?GetImageCache(image_info,arg,exception)
1286                                  :DestroyImage(draw_info->fill_pattern);
1287           break;
1288         }
1289       if (LocaleCompare("tile-offset",option) == 0)
1290         {
1291           /* SyncImageSettings() used to set per-image attribute. ??? */
1292           (void) SetImageOption(image_info,option,ArgOption("0"));
1293           break;
1294         }
1295       if (LocaleCompare("transparent-color",option) == 0)
1296         {
1297           /* FUTURE: both image_info attribute & ImageOption in use!
1298              image_info only used for generating new images.
1299              SyncImageSettings() used to set per-image attribute.
1300
1301              Note that +transparent-color, means fall-back to image
1302              attribute so ImageOption is deleted, not set to a default.
1303           */
1304           (void) SetImageOption(image_info,option,ArgOption(NULL));
1305           (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1306               &image_info->transparent_color,exception);
1307           break;
1308         }
1309       if (LocaleCompare("treedepth",option) == 0)
1310         {
1311           (void) SetImageOption(image_info,option,ArgOption(NULL));
1312           quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1313           break;
1314         }
1315       if (LocaleCompare("type",option) == 0)
1316         {
1317           /* SyncImageSettings() used to set per-image attribute. */
1318           (void) SetImageOption(image_info,option,ArgOption(NULL));
1319           image_info->type=(ImageType) ParseCommandOption(MagickTypeOptions,
1320                  MagickFalse,ArgOption("undefined"));
1321           break;
1322         }
1323       break;
1324     }
1325     case 'u':
1326     {
1327       if (LocaleCompare("undercolor",option) == 0)
1328         {
1329           (void) SetImageOption(image_info,option,ArgOption(NULL));
1330           (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1331                &draw_info->undercolor,exception);
1332           break;
1333         }
1334       if (LocaleCompare("units",option) == 0)
1335         {
1336           /* SyncImageSettings() used to set per-image attribute.
1337              Should this effect draw_info X and Y resolution?
1338              FUTURE: this probably should be part of the density setting
1339           */
1340           (void) SetImageOption(image_info,option,ArgOption(NULL));
1341           image_info->units=(ResolutionType) ParseCommandOption(
1342                 MagickResolutionOptions,MagickFalse,ArgOption("undefined"));
1343           break;
1344         }
1345       break;
1346     }
1347     case 'v':
1348     {
1349       if (LocaleCompare("verbose",option) == 0)
1350         {
1351           /* FUTURE: Also an image artifact, set in Simple Operators.
1352              But artifact is only used in verbose output.
1353           */
1354           (void) SetImageOption(image_info,option,ArgOption(NULL));
1355           image_info->verbose= ArgBoolean;
1356           image_info->ping=MagickFalse; /* verbose can't be a ping */
1357           break;
1358         }
1359       if (LocaleCompare("view",option) == 0)
1360         {
1361           /* FUTURE: Convert from image_info to ImageOption
1362              Only used by coder FPX
1363           */
1364           (void) CloneString(&image_info->view,ArgOption(NULL));
1365           break;
1366         }
1367       if (LocaleCompare("virtual-pixel",option) == 0)
1368         {
1369           /* SyncImageSettings() used to set per-image attribute.
1370              This is VERY deep in the image caching structure.
1371           */
1372           (void) SetImageOption(image_info,option,ArgOption(NULL));
1373           break;
1374         }
1375       break;
1376     }
1377     case 'w':
1378     {
1379       if (LocaleCompare("weight",option) == 0)
1380         {
1381           /* Just what does using a font 'weight' do ???
1382              There is no "-list weight" output (reference manual says there is)
1383           */
1384           if (!IfSetOption)
1385             break;
1386           draw_info->weight=StringToUnsignedLong(arg);
1387           if (LocaleCompare(arg,"all") == 0)
1388             draw_info->weight=0;
1389           if (LocaleCompare(arg,"bold") == 0)
1390             draw_info->weight=700;
1391           if (LocaleCompare(arg,"bolder") == 0)
1392             if (draw_info->weight <= 800)
1393               draw_info->weight+=100;
1394           if (LocaleCompare(arg,"lighter") == 0)
1395             if (draw_info->weight >= 100)
1396               draw_info->weight-=100;
1397           if (LocaleCompare(arg,"normal") == 0)
1398             draw_info->weight=400;
1399           break;
1400         }
1401       if (LocaleCompare("white-point",option) == 0)
1402         {
1403           /* Used as a image chromaticity setting
1404              SyncImageSettings() used to set per-image attribute.
1405           */
1406           (void) SetImageOption(image_info,option,ArgOption("0.0"));
1407           break;
1408         }
1409       break;
1410     }
1411     default:
1412       break;
1413   }
1414 #undef image_info
1415 #undef draw_info
1416 #undef quantize_info
1417 #undef exception
1418 #undef IfSetOption
1419 #undef ArgOption
1420 #undef ArgBoolean
1421
1422   return;
1423 }
1424 \f
1425 /*
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 %                                                                             %
1428 %                                                                             %
1429 %                                                                             %
1430 +     W a n d S i m p l e O p e r a t o r I m a g e s                         %
1431 %                                                                             %
1432 %                                                                             %
1433 %                                                                             %
1434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1435 %
1436 %  WandSimpleOperatorImages() applys one simple image operation given to all
1437 %  the images in the current wand,  with the settings that are saved in the
1438 %  CLI wand.
1439 %
1440 %  It is assumed that any per-image settings are up-to-date with respect to
1441 %  extra settings that have been saved in the wand.
1442 %
1443 %  The format of the WandSimpleOperatorImage method is:
1444 %
1445 %    void WandSimpleOperatorImages(MagickWand *wand,
1446 %        const MagickBooleanType plus_alt_op, const char *option,
1447 %        const char *arg1, const char *arg2)
1448 %
1449 %  A description of each parameter follows:
1450 %
1451 %    o wand: structure holding settings to be applied
1452 %
1453 %    o plus_alt_op:  request the 'plus' or alturnative form of the operation
1454 %
1455 %    o option:  The option string for the operation
1456 %
1457 %    o arg1, arg2: optional argument strings to the operation
1458 %
1459 % Any problems will be added to the 'exception' entry of the given wand.
1460 %
1461 % Example usage...
1462 %
1463 %  WandSimpleOperatorImages(wand, MagickFalse,"crop","100x100+20+30",NULL);
1464 %  WandSimpleOperatorImages(wand, MagickTrue, "repage",NULL,NULL);
1465 %  WandSimpleOperatorImages(wand, MagickTrue, "distort","SRT","45");
1466 %  if ( wand->exception->severity != UndefinedException ) {
1467 %    CatchException(exception);
1468 %    exit(1);
1469 %  }
1470 %
1471 % Or for handling command line arguments EG: +/-option ["arg"]
1472 %
1473 %    argc,argv
1474 %    i=index in argv
1475 %
1476 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
1477 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
1478 %    if ( (flags & SimpleOperatorOptionFlag) != 0 )
1479 %      WandSimpleOperatorImages(wand,
1480 %          ((*argv[i])=='+')?MagickTrue:MagickFalse,argv[i]+1,
1481 %          count>=1 ? argv[i+1] : (char *)NULL,
1482 %          count>=2 ? argv[i+2] : (char *)NULL );
1483 %    i += count+1;
1484 %
1485 */
1486
1487 /*
1488   Internal subrountine to apply one simple image operation to the current
1489   image pointed to by the wand.
1490
1491   The image in the list may be modified in three different ways...
1492     * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1493     * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1494     * one image replace by a list of images (-separate and -crop only!)
1495
1496   In each case the result replaces the original image in the list, as well as
1497   the pointer to the modified image (last image added if replaced by a list
1498   of images) is returned.
1499
1500   As the image pointed to may be replaced, the first image in the list may
1501   also change.  GetFirstImageInList() should be used by caller if they wish
1502   return the Image pointer to the first image in list.
1503 */
1504 static void WandSimpleOperatorImage(MagickWand *wand,
1505   const MagickBooleanType plus_alt_op, const char *option,
1506   const char *arg1, const char *arg2)
1507 {
1508   Image *
1509     new_image;
1510
1511   GeometryInfo
1512     geometry_info;
1513
1514   RectangleInfo
1515     geometry;
1516
1517   MagickStatusType
1518     flags;
1519
1520 #define image_info      (wand->image_info)
1521 #define draw_info       (wand->draw_info)
1522 #define quantize_info   (wand->quantize_info)
1523 #define image           (wand->images)
1524 #define exception       (wand->exception)
1525 #define normal_op       (plus_alt_op?MagickFalse:MagickTrue)
1526
1527   assert(image_info != (const ImageInfo *) NULL);
1528   assert(image_info->signature == MagickSignature);
1529   assert(draw_info != (DrawInfo *) NULL);      /* ensure it is a CLI wand */
1530   assert(image != (Image *) NULL);             /* there is an image */
1531   assert(image->signature == MagickSignature); /* and is a valid image */
1532
1533   if (wand->debug != MagickFalse)
1534     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
1535
1536   SetGeometryInfo(&geometry_info);
1537
1538   new_image = (Image *)NULL; /* the replacement image, if not null at end */
1539
1540   /* FUTURE: We may need somthing a little more optimized than this!
1541      Perhaps, do the 'sync' if 'settings tainted' before next operator.
1542   */
1543   (void) SyncImageSettings(image_info,image,exception);
1544
1545   switch (*option)
1546   {
1547     case 'a':
1548     {
1549       if (LocaleCompare("adaptive-blur",option) == 0)
1550         {
1551           flags=ParseGeometry(arg1,&geometry_info);
1552           if ((flags & SigmaValue) == 0)
1553             geometry_info.sigma=1.0;
1554           if ((flags & XiValue) == 0)
1555             geometry_info.xi=0.0;
1556           new_image=AdaptiveBlurImage(image,geometry_info.rho,
1557             geometry_info.sigma,geometry_info.xi,exception);
1558           break;
1559         }
1560       if (LocaleCompare("adaptive-resize",option) == 0)
1561         {
1562           (void) ParseRegionGeometry(image,arg1,&geometry,exception);
1563           new_image=AdaptiveResizeImage(image,geometry.width,geometry.height,
1564                exception);
1565           break;
1566         }
1567       if (LocaleCompare("adaptive-sharpen",option) == 0)
1568         {
1569           flags=ParseGeometry(arg1,&geometry_info);
1570           if ((flags & SigmaValue) == 0)
1571             geometry_info.sigma=1.0;
1572           if ((flags & XiValue) == 0)
1573             geometry_info.xi=0.0;
1574           new_image=AdaptiveSharpenImage(image,geometry_info.rho,
1575             geometry_info.sigma,geometry_info.xi,exception);
1576           break;
1577         }
1578       if (LocaleCompare("alpha",option) == 0)
1579         {
1580           AlphaChannelType
1581             alpha_type;
1582
1583           alpha_type=(AlphaChannelType) ParseCommandOption(MagickAlphaOptions,
1584             MagickFalse,arg1);
1585           (void) SetImageAlphaChannel(image,alpha_type,exception);
1586           break;
1587         }
1588       if (LocaleCompare("annotate",option) == 0)
1589         {
1590           char
1591             *text,
1592             geometry[MaxTextExtent];
1593
1594           SetGeometryInfo(&geometry_info);
1595           flags=ParseGeometry(arg1,&geometry_info);
1596           if ((flags & SigmaValue) == 0)
1597             geometry_info.sigma=geometry_info.rho;
1598           text=InterpretImageProperties(image_info,image,arg2,
1599             exception);
1600           if (text == (char *) NULL)
1601             break;
1602           (void) CloneString(&draw_info->text,text);
1603           text=DestroyString(text);
1604           (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1605             geometry_info.xi,geometry_info.psi);
1606           (void) CloneString(&draw_info->geometry,geometry);
1607           draw_info->affine.sx=cos(DegreesToRadians(
1608             fmod(geometry_info.rho,360.0)));
1609           draw_info->affine.rx=sin(DegreesToRadians(
1610             fmod(geometry_info.rho,360.0)));
1611           draw_info->affine.ry=(-sin(DegreesToRadians(
1612             fmod(geometry_info.sigma,360.0))));
1613           draw_info->affine.sy=cos(DegreesToRadians(
1614             fmod(geometry_info.sigma,360.0)));
1615           (void) AnnotateImage(image,draw_info,exception);
1616           GetAffineMatrix(&draw_info->affine);
1617           break;
1618         }
1619       if (LocaleCompare("auto-gamma",option) == 0)
1620         {
1621           (void) AutoGammaImage(image,exception);
1622           break;
1623         }
1624       if (LocaleCompare("auto-level",option) == 0)
1625         {
1626           (void) AutoLevelImage(image,exception);
1627           break;
1628         }
1629       if (LocaleCompare("auto-orient",option) == 0)
1630         {
1631           switch (image->orientation)
1632           {
1633             case TopRightOrientation:
1634             {
1635               new_image=FlopImage(image,exception);
1636               break;
1637             }
1638             case BottomRightOrientation:
1639             {
1640               new_image=RotateImage(image,180.0,exception);
1641               break;
1642             }
1643             case BottomLeftOrientation:
1644             {
1645               new_image=FlipImage(image,exception);
1646               break;
1647             }
1648             case LeftTopOrientation:
1649             {
1650               new_image=TransposeImage(image,exception);
1651               break;
1652             }
1653             case RightTopOrientation:
1654             {
1655               new_image=RotateImage(image,90.0,exception);
1656               break;
1657             }
1658             case RightBottomOrientation:
1659             {
1660               new_image=TransverseImage(image,exception);
1661               break;
1662             }
1663             case LeftBottomOrientation:
1664             {
1665               new_image=RotateImage(image,270.0,exception);
1666               break;
1667             }
1668             default:
1669               break;
1670           }
1671           if (new_image != (Image *) NULL)
1672             new_image->orientation=TopLeftOrientation;
1673           break;
1674         }
1675       break;
1676     }
1677     case 'b':
1678     {
1679       if (LocaleCompare("black-threshold",option) == 0)
1680         {
1681           (void) BlackThresholdImage(image,arg1,exception);
1682           break;
1683         }
1684       if (LocaleCompare("blue-shift",option) == 0)
1685         {
1686           geometry_info.rho=1.5;
1687           if (plus_alt_op == MagickFalse)
1688             flags=ParseGeometry(arg1,&geometry_info);
1689           new_image=BlueShiftImage(image,geometry_info.rho,exception);
1690           break;
1691         }
1692       if (LocaleCompare("blur",option) == 0)
1693         {
1694           /* FUTURE: use of "bias" in a blur is non-sensible */
1695           flags=ParseGeometry(arg1,&geometry_info);
1696           if ((flags & SigmaValue) == 0)
1697             geometry_info.sigma=1.0;
1698           if ((flags & XiValue) == 0)
1699             geometry_info.xi=0.0;
1700           new_image=BlurImage(image,geometry_info.rho,
1701             geometry_info.sigma,geometry_info.xi,exception);
1702           break;
1703         }
1704       if (LocaleCompare("border",option) == 0)
1705         {
1706           CompositeOperator
1707             compose;
1708
1709           const char*
1710             value;
1711
1712           value=GetImageOption(image_info,"compose");
1713           if (value != (const char *) NULL)
1714             compose=(CompositeOperator) ParseCommandOption(
1715                  MagickComposeOptions,MagickFalse,value);
1716           else
1717             compose=OverCompositeOp;  /* use Over not image->compose */
1718
1719           flags=ParsePageGeometry(image,arg1,&geometry,exception);
1720           if ((flags & SigmaValue) == 0)
1721             geometry.height=geometry.width;
1722           new_image=BorderImage(image,&geometry,compose,exception);
1723           break;
1724         }
1725       if (LocaleCompare("brightness-contrast",option) == 0)
1726         {
1727           double
1728             brightness,
1729             contrast;
1730
1731           GeometryInfo
1732             geometry_info;
1733
1734           MagickStatusType
1735             flags;
1736
1737           flags=ParseGeometry(arg1,&geometry_info);
1738           brightness=geometry_info.rho;
1739           contrast=0.0;
1740           if ((flags & SigmaValue) != 0)
1741             contrast=geometry_info.sigma;
1742           (void) BrightnessContrastImage(image,brightness,contrast,
1743             exception);
1744           break;
1745         }
1746       break;
1747     }
1748     case 'c':
1749     {
1750       if (LocaleCompare("cdl",option) == 0)
1751         {
1752           char
1753             *color_correction_collection;
1754
1755           /*
1756             Color correct with a color decision list.
1757           */
1758           color_correction_collection=FileToString(arg1,~0,exception);
1759           if (color_correction_collection == (char *) NULL)
1760             break;
1761           (void) ColorDecisionListImage(image,color_correction_collection,
1762             exception);
1763           break;
1764         }
1765       if (LocaleCompare("channel",option) == 0)
1766         {
1767           /* The "channel" setting has already been set
1768              FUTURE: This probably should be part of WandSettingOptionInfo()
1769              or SyncImageSettings().
1770           */
1771           SetPixelChannelMapMask(image,image_info->channel);
1772           break;
1773         }
1774       if (LocaleCompare("charcoal",option) == 0)
1775         {
1776           flags=ParseGeometry(arg1,&geometry_info);
1777           if ((flags & SigmaValue) == 0)
1778             geometry_info.sigma=1.0;
1779           if ((flags & XiValue) == 0)
1780             geometry_info.xi=1.0;
1781           new_image=CharcoalImage(image,geometry_info.rho,
1782             geometry_info.sigma,geometry_info.xi,exception);
1783           break;
1784         }
1785       if (LocaleCompare("chop",option) == 0)
1786         {
1787           (void) ParseGravityGeometry(image,arg1,&geometry,exception);
1788           new_image=ChopImage(image,&geometry,exception);
1789           break;
1790         }
1791       if (LocaleCompare("clamp",option) == 0)
1792         {
1793           (void) ClampImage(image,exception);
1794           break;
1795         }
1796       if (LocaleCompare("clip",option) == 0)
1797         {
1798           if (plus_alt_op == MagickFalse)
1799             (void) ClipImage(image,exception);
1800           else /* "+clip" remove the write mask */
1801             (void) SetImageMask(image,(Image *) NULL,exception);
1802           break;
1803         }
1804       if (LocaleCompare("clip-mask",option) == 0)
1805         {
1806           CacheView
1807             *mask_view;
1808
1809           Image
1810             *mask_image;
1811
1812           register Quantum
1813             *restrict q;
1814
1815           register ssize_t
1816             x;
1817
1818           ssize_t
1819             y;
1820
1821           if (plus_alt_op != MagickFalse)
1822           { /* "+clip-mask" Remove the write mask */
1823               (void) SetImageMask(image,(Image *) NULL,exception);
1824               break;
1825             }
1826           mask_image=GetImageCache(image_info,arg1,exception);
1827           if (mask_image == (Image *) NULL)
1828             break;
1829           if (SetImageStorageClass(mask_image,DirectClass,exception)
1830                == MagickFalse)
1831             break;
1832           /* Create a write mask from clip-mask image */
1833           /* FUTURE: use Alpha operations instead and create a Grey Image */
1834           mask_view=AcquireCacheView(mask_image);
1835           for (y=0; y < (ssize_t) mask_image->rows; y++)
1836           {
1837             q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1838               exception);
1839             if (q == (Quantum *) NULL)
1840               break;
1841             for (x=0; x < (ssize_t) mask_image->columns; x++)
1842             {
1843               if (mask_image->matte == MagickFalse)
1844                 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
1845               SetPixelRed(mask_image,GetPixelAlpha(mask_image,q),q);
1846               SetPixelGreen(mask_image,GetPixelAlpha(mask_image,q),q);
1847               SetPixelBlue(mask_image,GetPixelAlpha(mask_image,q),q);
1848               q+=GetPixelChannels(mask_image);
1849             }
1850             if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1851               break;
1852           }
1853           /* clean up and set the write mask */
1854           mask_view=DestroyCacheView(mask_view);
1855           mask_image->matte=MagickTrue;
1856           (void) SetImageMask(image,mask_image,exception);
1857           mask_image=DestroyImage(mask_image);
1858           break;
1859         }
1860       if (LocaleCompare("clip-path",option) == 0)
1861         {
1862           (void) ClipImagePath(image,arg1,
1863                (MagickBooleanType)(!(int)plus_alt_op),exception);
1864           break;
1865         }
1866       if (LocaleCompare("colorize",option) == 0)
1867         {
1868           new_image=ColorizeImage(image,arg1,&draw_info->fill,exception);
1869           break;
1870         }
1871       if (LocaleCompare("color-matrix",option) == 0)
1872         {
1873           KernelInfo
1874             *kernel;
1875
1876           kernel=AcquireKernelInfo(arg1);
1877           if (kernel == (KernelInfo *) NULL)
1878             break;
1879           new_image=ColorMatrixImage(image,kernel,exception);
1880           kernel=DestroyKernelInfo(kernel);
1881           break;
1882         }
1883       if (LocaleCompare("colors",option) == 0)
1884         {
1885           /* Reduce the number of colors in the image.
1886              FUTURE: also provide 'plus version with image 'color counts'
1887           */
1888           quantize_info->number_colors=StringToUnsignedLong(arg1);
1889           if (quantize_info->number_colors == 0)
1890             break;
1891           if ((image->storage_class == DirectClass) ||
1892               image->colors > quantize_info->number_colors)
1893             (void) QuantizeImage(quantize_info,image,exception);
1894           else
1895             (void) CompressImageColormap(image,exception);
1896           break;
1897         }
1898       if (LocaleCompare("colorspace",option) == 0)
1899         {
1900           /* WARNING: this is both a image_info setting (already done)
1901                       and a operator to change image colorspace.
1902
1903              FUTURE: default colorspace should be sRGB!
1904              Unless some type of 'linear colorspace' mode is set.
1905
1906              Note that +colorspace sets "undefined" or no effect on
1907              new images, but forces images already in memory back to RGB!
1908              That seems to be a little strange!
1909           */
1910           (void) TransformImageColorspace(image,
1911                     plus_alt_op ? RGBColorspace : image_info->colorspace,
1912                     exception);
1913           break;
1914         }
1915       if (LocaleCompare("contrast",option) == 0)
1916         {
1917           (void) ContrastImage(image,
1918                (MagickBooleanType)(!(int)plus_alt_op),exception);
1919           break;
1920         }
1921       if (LocaleCompare("contrast-stretch",option) == 0)
1922         {
1923           double
1924             black_point,
1925             white_point;
1926
1927           MagickStatusType
1928             flags;
1929
1930           flags=ParseGeometry(arg1,&geometry_info);
1931           black_point=geometry_info.rho;
1932           white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
1933             black_point;
1934           if ((flags & PercentValue) != 0)
1935             {
1936               black_point*=(double) image->columns*image->rows/100.0;
1937               white_point*=(double) image->columns*image->rows/100.0;
1938             }
1939           white_point=(MagickRealType) image->columns*image->rows-
1940             white_point;
1941           (void) ContrastStretchImage(image,black_point,white_point,
1942             exception);
1943           break;
1944         }
1945       if (LocaleCompare("convolve",option) == 0)
1946         {
1947           KernelInfo
1948             *kernel_info;
1949
1950           kernel_info=AcquireKernelInfo(arg1);
1951           if (kernel_info == (KernelInfo *) NULL)
1952             break;
1953           kernel_info->bias=image->bias;
1954           new_image=ConvolveImage(image,kernel_info,exception);
1955           kernel_info=DestroyKernelInfo(kernel_info);
1956           break;
1957         }
1958       if (LocaleCompare("crop",option) == 0)
1959         {
1960           /* WARNING: This can generate multiple images! */
1961           new_image=CropImageToTiles(image,arg1,exception);
1962           break;
1963         }
1964       if (LocaleCompare("cycle",option) == 0)
1965         {
1966           (void) CycleColormapImage(image,(ssize_t) StringToLong(arg1),
1967             exception);
1968           break;
1969         }
1970       break;
1971     }
1972     case 'd':
1973     {
1974       if (LocaleCompare("decipher",option) == 0)
1975         {
1976           StringInfo
1977             *passkey;
1978
1979           passkey=FileToStringInfo(arg1,~0,exception);
1980           if (passkey != (StringInfo *) NULL)
1981             {
1982               (void) PasskeyDecipherImage(image,passkey,exception);
1983               passkey=DestroyStringInfo(passkey);
1984             }
1985           break;
1986         }
1987       if (LocaleCompare("depth",option) == 0)
1988         {
1989           /* The image_info->depth setting has already been set
1990              We just need to apply it to all images in current sequence
1991
1992              WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
1993              That is it really is an operation, not a setting! Arrgghhh
1994
1995              FUTURE: this should not be an operator!!!
1996           */
1997           (void) SetImageDepth(image,image_info->depth,exception);
1998           break;
1999         }
2000       if (LocaleCompare("deskew",option) == 0)
2001         {
2002           double
2003             threshold;
2004
2005           if (plus_alt_op != MagickFalse)
2006             threshold=40.0*QuantumRange/100.0;
2007           else
2008             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2009           new_image=DeskewImage(image,threshold,exception);
2010           break;
2011         }
2012       if (LocaleCompare("despeckle",option) == 0)
2013         {
2014           new_image=DespeckleImage(image,exception);
2015           break;
2016         }
2017       if (LocaleCompare("distort",option) == 0)
2018         {
2019           char
2020             *args,
2021             token[MaxTextExtent];
2022
2023           const char
2024             *p;
2025
2026           DistortImageMethod
2027             method;
2028
2029           double
2030             *arguments;
2031
2032           register ssize_t
2033             x;
2034
2035           size_t
2036             number_arguments;
2037
2038           method=(DistortImageMethod) ParseCommandOption(MagickDistortOptions,
2039             MagickFalse,arg1);
2040           if (method == ResizeDistortion)
2041             {
2042                double
2043                  resize_args[2];
2044                /* Special Case - Argument is actually a resize geometry!
2045                ** Convert that to an appropriate distortion argument array.
2046                ** FUTURE: make a separate special resize operator
2047                */
2048                (void) ParseRegionGeometry(image,arg2,&geometry,
2049                  exception);
2050                resize_args[0]=(double) geometry.width;
2051                resize_args[1]=(double) geometry.height;
2052                new_image=DistortImage(image,method,(size_t)2,
2053                  resize_args,MagickTrue,exception);
2054                break;
2055             }
2056           /* handle percent arguments */
2057           args=InterpretImageProperties(image_info,image,arg2,
2058             exception);
2059           if (args == (char *) NULL)
2060             break;
2061           /* convert arguments into an array of doubles
2062              FUTURE: make this a separate function.
2063              Also make use of new 'sentinal' feature to avoid need for
2064              tokenization.
2065           */
2066           p=(char *) args;
2067           for (x=0; *p != '\0'; x++)
2068           {
2069             GetMagickToken(p,&p,token);
2070             if (*token == ',')
2071               GetMagickToken(p,&p,token);
2072           }
2073           number_arguments=(size_t) x;
2074           arguments=(double *) AcquireQuantumMemory(number_arguments,
2075             sizeof(*arguments));
2076           if (arguments == (double *) NULL)
2077             ThrowWandFatalException(ResourceLimitFatalError,
2078               "MemoryAllocationFailed",image->filename);
2079           (void) ResetMagickMemory(arguments,0,number_arguments*
2080             sizeof(*arguments));
2081           p=(char *) args;
2082           for (x=0; (x < (ssize_t) number_arguments) && (*p != '\0'); x++)
2083           {
2084             GetMagickToken(p,&p,token);
2085             if (*token == ',')
2086               GetMagickToken(p,&p,token);
2087             arguments[x]=StringToDouble(token,(char **) NULL);
2088           }
2089           args=DestroyString(args);
2090           new_image=DistortImage(image,method,number_arguments,arguments,
2091                         plus_alt_op,exception);
2092           arguments=(double *) RelinquishMagickMemory(arguments);
2093           break;
2094         }
2095       if (LocaleCompare("draw",option) == 0)
2096         {
2097           (void) CloneString(&draw_info->primitive,arg1);
2098           (void) DrawImage(image,draw_info,exception);
2099           (void) CloneString(&draw_info->primitive,(char *)NULL);
2100           break;
2101         }
2102       break;
2103     }
2104     case 'e':
2105     {
2106       if (LocaleCompare("edge",option) == 0)
2107         {
2108           flags=ParseGeometry(arg1,&geometry_info);
2109           if ((flags & SigmaValue) == 0)
2110             geometry_info.sigma=1.0;
2111           new_image=EdgeImage(image,geometry_info.rho,
2112             geometry_info.sigma,exception);
2113           break;
2114         }
2115       if (LocaleCompare("emboss",option) == 0)
2116         {
2117           flags=ParseGeometry(arg1,&geometry_info);
2118           if ((flags & SigmaValue) == 0)
2119             geometry_info.sigma=1.0;
2120           new_image=EmbossImage(image,geometry_info.rho,
2121             geometry_info.sigma,exception);
2122           break;
2123         }
2124       if (LocaleCompare("encipher",option) == 0)
2125         {
2126           StringInfo
2127             *passkey;
2128
2129           passkey=FileToStringInfo(arg1,~0,exception);
2130           if (passkey != (StringInfo *) NULL)
2131             {
2132               (void) PasskeyEncipherImage(image,passkey,exception);
2133               passkey=DestroyStringInfo(passkey);
2134             }
2135           break;
2136         }
2137       if (LocaleCompare("enhance",option) == 0)
2138         {
2139           new_image=EnhanceImage(image,exception);
2140           break;
2141         }
2142       if (LocaleCompare("equalize",option) == 0)
2143         {
2144           (void) EqualizeImage(image,exception);
2145           break;
2146         }
2147       if (LocaleCompare("evaluate",option) == 0)
2148         {
2149           double
2150             constant;
2151
2152           MagickEvaluateOperator
2153             op;
2154
2155           op=(MagickEvaluateOperator) ParseCommandOption(
2156             MagickEvaluateOptions,MagickFalse,arg1);
2157           constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2158           (void) EvaluateImage(image,op,constant,exception);
2159           break;
2160         }
2161       if (LocaleCompare("extent",option) == 0)
2162         {
2163           flags=ParseGravityGeometry(image,arg1,&geometry,exception);
2164           if (geometry.width == 0)
2165             geometry.width=image->columns;
2166           if (geometry.height == 0)
2167             geometry.height=image->rows;
2168           new_image=ExtentImage(image,&geometry,exception);
2169           break;
2170         }
2171       break;
2172     }
2173     case 'f':
2174     {
2175       if (LocaleCompare("features",option) == 0)
2176         {
2177           /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
2178           if (plus_alt_op != MagickFalse)
2179             {
2180               (void) DeleteImageArtifact(image,"identify:features");
2181               break;
2182             }
2183           (void) SetImageArtifact(image,"identify:features","true");
2184           (void) SetImageArtifact(image,"verbose","true");
2185           break;
2186         }
2187       if (LocaleCompare("flip",option) == 0)
2188         {
2189           new_image=FlipImage(image,exception);
2190           break;
2191         }
2192       if (LocaleCompare("flop",option) == 0)
2193         {
2194           new_image=FlopImage(image,exception);
2195           break;
2196         }
2197       if (LocaleCompare("floodfill",option) == 0)
2198         {
2199           PixelInfo
2200             target;
2201
2202           (void) ParsePageGeometry(image,arg1,&geometry,exception);
2203           (void) QueryColorCompliance(arg2,AllCompliance,&target,exception);
2204           (void) FloodfillPaintImage(image,draw_info,&target,geometry.x,
2205                     geometry.y,plus_alt_op,exception);
2206           break;
2207         }
2208       if (LocaleCompare("frame",option) == 0)
2209         {
2210           FrameInfo
2211             frame_info;
2212
2213           CompositeOperator
2214             compose;
2215
2216           const char*
2217             value;
2218
2219           value=GetImageOption(image_info,"compose");
2220           if (value != (const char *) NULL)
2221             compose=(CompositeOperator) ParseCommandOption(
2222                  MagickComposeOptions,MagickFalse,value);
2223           else
2224             compose=OverCompositeOp;  /* use Over not image->compose */
2225
2226           flags=ParsePageGeometry(image,arg1,&geometry,exception);
2227           frame_info.width=geometry.width;
2228           frame_info.height=geometry.height;
2229           if ((flags & HeightValue) == 0)
2230             frame_info.height=geometry.width;
2231           frame_info.outer_bevel=geometry.x;
2232           frame_info.inner_bevel=geometry.y;
2233           frame_info.x=(ssize_t) frame_info.width;
2234           frame_info.y=(ssize_t) frame_info.height;
2235           frame_info.width=image->columns+2*frame_info.width;
2236           frame_info.height=image->rows+2*frame_info.height;
2237           new_image=FrameImage(image,&frame_info,compose,exception);
2238           break;
2239         }
2240       if (LocaleCompare("function",option) == 0)
2241         {
2242           char
2243             *arguments,
2244             token[MaxTextExtent];
2245
2246           const char
2247             *p;
2248
2249           double
2250             *parameters;
2251
2252           MagickFunction
2253             function;
2254
2255           register ssize_t
2256             x;
2257
2258           size_t
2259             number_parameters;
2260
2261           /*
2262             Function Modify Image Values
2263             FUTURE: code should be almost a duplicate of that is "distort"
2264           */
2265           function=(MagickFunction) ParseCommandOption(MagickFunctionOptions,
2266             MagickFalse,arg1);
2267           arguments=InterpretImageProperties(image_info,image,arg2,
2268             exception);
2269           if (arguments == (char *) NULL)
2270             break;
2271           p=(char *) arguments;
2272           for (x=0; *p != '\0'; x++)
2273           {
2274             GetMagickToken(p,&p,token);
2275             if (*token == ',')
2276               GetMagickToken(p,&p,token);
2277           }
2278           number_parameters=(size_t) x;
2279           parameters=(double *) AcquireQuantumMemory(number_parameters,
2280             sizeof(*parameters));
2281           if (parameters == (double *) NULL)
2282             ThrowWandFatalException(ResourceLimitFatalError,
2283               "MemoryAllocationFailed",image->filename);
2284           (void) ResetMagickMemory(parameters,0,number_parameters*
2285             sizeof(*parameters));
2286           p=(char *) arguments;
2287           for (x=0; (x < (ssize_t) number_parameters) && (*p != '\0'); x++)
2288           {
2289             GetMagickToken(p,&p,token);
2290             if (*token == ',')
2291               GetMagickToken(p,&p,token);
2292             parameters[x]=StringToDouble(token,(char **) NULL);
2293           }
2294           arguments=DestroyString(arguments);
2295           (void) FunctionImage(image,function,number_parameters,parameters,
2296             exception);
2297           parameters=(double *) RelinquishMagickMemory(parameters);
2298           break;
2299         }
2300       break;
2301     }
2302     case 'g':
2303     {
2304       if (LocaleCompare("gamma",option) == 0)
2305         {
2306           if (plus_alt_op != MagickFalse)
2307             image->gamma=StringToDouble(arg1,(char **) NULL);
2308           else
2309             (void) GammaImage(image,StringToDouble(arg1,(char **) NULL),
2310                  exception);
2311           break;
2312         }
2313       if ((LocaleCompare("gaussian-blur",option) == 0) ||
2314           (LocaleCompare("gaussian",option) == 0))
2315         {
2316           flags=ParseGeometry(arg1,&geometry_info);
2317           if ((flags & SigmaValue) == 0)
2318             geometry_info.sigma=1.0;
2319           new_image=GaussianBlurImage(image,geometry_info.rho,
2320             geometry_info.sigma,exception);
2321           break;
2322         }
2323       if (LocaleCompare("geometry",option) == 0)
2324         {
2325           /*
2326             Record Image offset for composition. (A Setting)
2327             Resize last image. (ListOperator)
2328             FUTURE: Why if no 'offset' does this resize ALL images?
2329             Also why is the setting recorded in the IMAGE non-sense!
2330           */
2331           if (plus_alt_op != MagickFalse)
2332             { /* remove the previous composition geometry offset! */
2333               if (image->geometry != (char *) NULL)
2334                 image->geometry=DestroyString(image->geometry);
2335               break;
2336             }
2337           flags=ParseRegionGeometry(image,arg1,&geometry,exception);
2338           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2339             (void) CloneString(&image->geometry,arg1);
2340           else
2341             new_image=ResizeImage(image,geometry.width,geometry.height,
2342               image->filter,image->blur,exception);
2343           break;
2344         }
2345       break;
2346     }
2347     case 'h':
2348     {
2349       if (LocaleCompare("highlight-color",option) == 0)
2350         {
2351           (void) SetImageArtifact(image,option,arg1);
2352           break;
2353         }
2354       break;
2355     }
2356     case 'i':
2357     {
2358       if (LocaleCompare("identify",option) == 0)
2359         {
2360           const char
2361             *format,
2362             *text;
2363
2364           format=GetImageOption(image_info,"format");
2365           if (format == (char *) NULL)
2366             {
2367               (void) IdentifyImage(image,stdout,image_info->verbose,
2368                 exception);
2369               break;
2370             }
2371           text=InterpretImageProperties(image_info,image,format,exception);
2372           if (text == (char *) NULL)
2373             break;
2374           (void) fputs(text,stdout);
2375           (void) fputc('\n',stdout);
2376           text=DestroyString((char *)text);
2377           break;
2378         }
2379       if (LocaleCompare("implode",option) == 0)
2380         {
2381           (void) ParseGeometry(arg1,&geometry_info);
2382           new_image=ImplodeImage(image,geometry_info.rho,
2383             image->interpolate,exception);
2384           break;
2385         }
2386       if (LocaleCompare("interpolative-resize",option) == 0)
2387         {
2388           (void) ParseRegionGeometry(image,arg1,&geometry,exception);
2389           new_image=InterpolativeResizeImage(image,geometry.width,
2390                geometry.height,image->interpolate,exception);
2391           break;
2392         }
2393       break;
2394     }
2395     case 'l':
2396     {
2397       if (LocaleCompare("lat",option) == 0)
2398         {
2399           flags=ParseGeometry(arg1,&geometry_info);
2400           if ((flags & PercentValue) != 0)
2401             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2402           new_image=AdaptiveThresholdImage(image,(size_t) geometry_info.rho,
2403                (size_t) geometry_info.sigma,(double) geometry_info.xi,
2404                exception);
2405           break;
2406         }
2407       if (LocaleCompare("level",option) == 0)
2408         {
2409           MagickRealType
2410             black_point,
2411             gamma,
2412             white_point;
2413
2414           MagickStatusType
2415             flags;
2416
2417           flags=ParseGeometry(arg1,&geometry_info);
2418           black_point=geometry_info.rho;
2419           white_point=(MagickRealType) QuantumRange;
2420           if ((flags & SigmaValue) != 0)
2421             white_point=geometry_info.sigma;
2422           gamma=1.0;
2423           if ((flags & XiValue) != 0)
2424             gamma=geometry_info.xi;
2425           if ((flags & PercentValue) != 0)
2426             {
2427               black_point*=(MagickRealType) (QuantumRange/100.0);
2428               white_point*=(MagickRealType) (QuantumRange/100.0);
2429             }
2430           if ((flags & SigmaValue) == 0)
2431             white_point=(MagickRealType) QuantumRange-black_point;
2432           if (plus_alt_op || ((flags & AspectValue) != 0))
2433             (void) LevelizeImage(image,black_point,white_point,gamma,
2434               exception);
2435           else
2436             (void) LevelImage(image,black_point,white_point,gamma,
2437               exception);
2438           break;
2439         }
2440       if (LocaleCompare("level-colors",option) == 0)
2441         {
2442           char
2443             token[MaxTextExtent];
2444
2445           const char
2446             *p;
2447
2448           PixelInfo
2449             black_point,
2450             white_point;
2451
2452           p=(const char *) arg1;
2453           GetMagickToken(p,&p,token);  /* get black point color */
2454           if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2455             (void) QueryColorCompliance(token,AllCompliance,
2456                       &black_point,exception);
2457           else
2458             (void) QueryColorCompliance("#000000",AllCompliance,
2459                       &black_point,exception);
2460           if (isalpha((int) token[0]) || (token[0] == '#'))
2461             GetMagickToken(p,&p,token);
2462           if (*token == '\0')
2463             white_point=black_point; /* set everything to that color */
2464           else
2465             {
2466               if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2467                 GetMagickToken(p,&p,token); /* Get white point color. */
2468               if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2469                 (void) QueryColorCompliance(token,AllCompliance,
2470                            &white_point,exception);
2471               else
2472                 (void) QueryColorCompliance("#ffffff",AllCompliance,
2473                            &white_point,exception);
2474             }
2475           (void) LevelImageColors(image,&black_point,&white_point,
2476                      plus_alt_op,exception);
2477           break;
2478         }
2479       if (LocaleCompare("linear-stretch",option) == 0)
2480         {
2481           double
2482             black_point,
2483             white_point;
2484
2485           MagickStatusType
2486             flags;
2487
2488           flags=ParseGeometry(arg1,&geometry_info);
2489           black_point=geometry_info.rho;
2490           white_point=(MagickRealType) image->columns*image->rows;
2491           if ((flags & SigmaValue) != 0)
2492             white_point=geometry_info.sigma;
2493           if ((flags & PercentValue) != 0)
2494             {
2495               black_point*=(double) image->columns*image->rows/100.0;
2496               white_point*=(double) image->columns*image->rows/100.0;
2497             }
2498           if ((flags & SigmaValue) == 0)
2499             white_point=(MagickRealType) image->columns*image->rows-
2500               black_point;
2501           (void) LinearStretchImage(image,black_point,white_point,exception);
2502           break;
2503         }
2504       if (LocaleCompare("liquid-rescale",option) == 0)
2505         {
2506           flags=ParseRegionGeometry(image,arg1,&geometry,exception);
2507           if ((flags & XValue) == 0)
2508             geometry.x=1;
2509           if ((flags & YValue) == 0)
2510             geometry.y=0;
2511           new_image=LiquidRescaleImage(image,geometry.width,
2512             geometry.height,1.0*geometry.x,1.0*geometry.y,exception);
2513           break;
2514         }
2515       if (LocaleCompare("lowlight-color",option) == 0)
2516         {
2517           (void) SetImageArtifact(image,option,arg1);
2518           break;
2519         }
2520       break;
2521     }
2522     case 'm':
2523     {
2524       if (LocaleCompare("map",option) == 0)
2525         {
2526           Image
2527             *remap_image;
2528
2529           /* DEPRECIATED use -remap */
2530           remap_image=GetImageCache(image_info,arg1,exception);
2531           if (remap_image == (Image *) NULL)
2532             break;
2533           (void) RemapImage(quantize_info,image,remap_image,exception);
2534           remap_image=DestroyImage(remap_image);
2535           break;
2536         }
2537       if (LocaleCompare("mask",option) == 0)
2538         {
2539           Image
2540             *mask;
2541
2542           if (plus_alt_op != MagickFalse)
2543             { /* Remove a mask. */
2544               (void) SetImageMask(image,(Image *) NULL,exception);
2545               break;
2546             }
2547           /* Set the image mask. */
2548           mask=GetImageCache(image_info,arg1,exception);
2549           if (mask == (Image *) NULL)
2550             break;
2551           (void) SetImageMask(image,mask,exception);
2552           mask=DestroyImage(mask);
2553           break;
2554         }
2555       if (LocaleCompare("matte",option) == 0)
2556         {
2557           /* DEPRECIATED */
2558           (void) SetImageAlphaChannel(image,plus_alt_op ?
2559             DeactivateAlphaChannel:SetAlphaChannel ,exception);
2560           break;
2561         }
2562       if (LocaleCompare("mode",option) == 0)
2563         {
2564           flags=ParseGeometry(arg1,&geometry_info);
2565           if ((flags & SigmaValue) == 0)
2566             geometry_info.sigma=geometry_info.rho;
2567           new_image=StatisticImage(image,ModeStatistic,(size_t)
2568             geometry_info.rho,(size_t) geometry_info.sigma,exception);
2569           break;
2570         }
2571       if (LocaleCompare("modulate",option) == 0)
2572         {
2573           (void) ModulateImage(image,arg1,exception);
2574           break;
2575         }
2576       if (LocaleCompare("monitor",option) == 0)
2577         {
2578           (void) SetImageProgressMonitor(image, plus_alt_op?
2579                 (MagickProgressMonitor) NULL:MonitorProgress,(void *) NULL);
2580           break;
2581         }
2582       if (LocaleCompare("monochrome",option) == 0)
2583         {
2584           (void) SetImageType(image,BilevelType,exception);
2585           break;
2586         }
2587       if (LocaleCompare("morphology",option) == 0)
2588         {
2589           char
2590             token[MaxTextExtent];
2591
2592           const char
2593             *p;
2594
2595           KernelInfo
2596             *kernel;
2597
2598           MorphologyMethod
2599             method;
2600
2601           ssize_t
2602             iterations;
2603
2604           p=arg1;
2605           GetMagickToken(p,&p,token);
2606           method=(MorphologyMethod) ParseCommandOption(
2607             MagickMorphologyOptions,MagickFalse,token);
2608           iterations=1L;
2609           GetMagickToken(p,&p,token);
2610           if ((*p == ':') || (*p == ','))
2611             GetMagickToken(p,&p,token);
2612           if ((*p != '\0'))
2613             iterations=(ssize_t) StringToLong(p);
2614           kernel=AcquireKernelInfo(arg2);
2615           if (kernel == (KernelInfo *) NULL)
2616             {
2617               (void) ThrowMagickException(exception,GetMagickModule(),
2618                    OptionError,"UnabletoParseKernel","morphology");
2619               break;
2620             }
2621           new_image=MorphologyImage(image,method,iterations,kernel,exception);
2622           kernel=DestroyKernelInfo(kernel);
2623           break;
2624         }
2625       if (LocaleCompare("motion-blur",option) == 0)
2626         {
2627           flags=ParseGeometry(arg1,&geometry_info);
2628           if ((flags & SigmaValue) == 0)
2629             geometry_info.sigma=1.0;
2630           new_image=MotionBlurImage(image,geometry_info.rho,
2631               geometry_info.sigma,geometry_info.xi,geometry_info.psi,
2632               exception);
2633           break;
2634         }
2635       break;
2636     }
2637     case 'n':
2638     {
2639       if (LocaleCompare("negate",option) == 0)
2640         {
2641           (void) NegateImage(image, plus_alt_op, exception);
2642           break;
2643         }
2644       if (LocaleCompare("noise",option) == 0)
2645         {
2646           if (plus_alt_op == MagickFalse)
2647             {
2648               flags=ParseGeometry(arg1,&geometry_info);
2649               if ((flags & SigmaValue) == 0)
2650                 geometry_info.sigma=geometry_info.rho;
2651               new_image=StatisticImage(image,NonpeakStatistic,(size_t)
2652                 geometry_info.rho,(size_t) geometry_info.sigma,exception);
2653             }
2654           else
2655             {
2656               NoiseType
2657                 noise;
2658
2659               double
2660                 attenuate;
2661
2662               const char*
2663                 value;
2664
2665               noise=(NoiseType) ParseCommandOption(MagickNoiseOptions,
2666                           MagickFalse,arg1),
2667
2668               value=GetImageOption(image_info,"attenuate");
2669               if  (value != (const char *) NULL)
2670                 attenuate=StringToDouble(value,(char **) NULL);
2671               else
2672                 attenuate=1.0;
2673
2674               new_image=AddNoiseImage(image,noise,attenuate,exception);
2675             }
2676           break;
2677         }
2678       if (LocaleCompare("normalize",option) == 0)
2679         {
2680           (void) NormalizeImage(image,exception);
2681           break;
2682         }
2683       break;
2684     }
2685     case 'o':
2686     {
2687       if (LocaleCompare("opaque",option) == 0)
2688         {
2689           PixelInfo
2690             target;
2691
2692           (void) QueryColorCompliance(arg1,AllCompliance,&target,exception);
2693           (void) OpaquePaintImage(image,&target,&draw_info->fill,plus_alt_op,
2694                exception);
2695           break;
2696         }
2697       if (LocaleCompare("ordered-dither",option) == 0)
2698         {
2699           (void) OrderedPosterizeImage(image,arg1,exception);
2700           break;
2701         }
2702       break;
2703     }
2704     case 'p':
2705     {
2706       if (LocaleCompare("paint",option) == 0)
2707         {
2708           (void) ParseGeometry(arg1,&geometry_info);
2709           new_image=OilPaintImage(image,geometry_info.rho,geometry_info.sigma,
2710                exception);
2711           break;
2712         }
2713       if (LocaleCompare("polaroid",option) == 0)
2714         {
2715           const char
2716             *caption;
2717
2718           double
2719             angle;
2720
2721           if (plus_alt_op != MagickFalse)
2722             {
2723               RandomInfo
2724               *random_info;
2725
2726               random_info=AcquireRandomInfo();
2727               angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2728               random_info=DestroyRandomInfo(random_info);
2729             }
2730           else
2731             {
2732               SetGeometryInfo(&geometry_info);
2733               flags=ParseGeometry(arg1,&geometry_info);
2734               angle=geometry_info.rho;
2735             }
2736           caption=GetImageProperty(image,"caption",exception);
2737           new_image=PolaroidImage(image,draw_info,caption,angle,
2738             image->interpolate,exception);
2739           break;
2740         }
2741       if (LocaleCompare("posterize",option) == 0)
2742         {
2743           (void) ParseGeometry(arg1,&geometry_info);
2744           (void) PosterizeImage(image,(size_t) geometry_info.rho,
2745                quantize_info->dither,exception);
2746           break;
2747         }
2748       if (LocaleCompare("preview",option) == 0)
2749         {
2750           PreviewType
2751             preview_type;
2752
2753           /* FUTURE: should be a 'Genesis' option?
2754              Option however is also in WandSettingOptionInfo()
2755           */
2756           preview_type=UndefinedPreview;
2757           if (plus_alt_op == MagickFalse)
2758             preview_type=(PreviewType) ParseCommandOption(MagickPreviewOptions,
2759                   MagickFalse,arg1);
2760           new_image=PreviewImage(image,preview_type,exception);
2761           break;
2762         }
2763       if (LocaleCompare("profile",option) == 0)
2764         {
2765           const char
2766             *name;
2767
2768           const StringInfo
2769             *profile;
2770
2771           Image
2772             *profile_image;
2773
2774           ImageInfo
2775             *profile_info;
2776
2777           if (plus_alt_op != MagickFalse)
2778             { /* Remove a profile from the image.  */
2779               (void) ProfileImage(image,arg1,(const unsigned char *)
2780                 NULL,0,exception);
2781               break;
2782             }
2783           /* Associate a profile with the image.  */
2784           profile_info=CloneImageInfo(image_info);
2785           profile=GetImageProfile(image,"iptc");
2786           if (profile != (StringInfo *) NULL)
2787             profile_info->profile=(void *) CloneStringInfo(profile);
2788           profile_image=GetImageCache(profile_info,arg1,exception);
2789           profile_info=DestroyImageInfo(profile_info);
2790           if (profile_image == (Image *) NULL)
2791             {
2792               StringInfo
2793                 *profile;
2794
2795               profile_info=CloneImageInfo(image_info);
2796               (void) CopyMagickString(profile_info->filename,arg1,
2797                 MaxTextExtent);
2798               profile=FileToStringInfo(profile_info->filename,~0UL,exception);
2799               if (profile != (StringInfo *) NULL)
2800                 {
2801                   (void) ProfileImage(image,profile_info->magick,
2802                     GetStringInfoDatum(profile),(size_t)
2803                     GetStringInfoLength(profile),exception);
2804                   profile=DestroyStringInfo(profile);
2805                 }
2806               profile_info=DestroyImageInfo(profile_info);
2807               break;
2808             }
2809           ResetImageProfileIterator(profile_image);
2810           name=GetNextImageProfile(profile_image);
2811           while (name != (const char *) NULL)
2812           {
2813             profile=GetImageProfile(profile_image,name);
2814             if (profile != (StringInfo *) NULL)
2815               (void) ProfileImage(image,name,GetStringInfoDatum(profile),
2816                 (size_t) GetStringInfoLength(profile),exception);
2817             name=GetNextImageProfile(profile_image);
2818           }
2819           profile_image=DestroyImage(profile_image);
2820           break;
2821         }
2822       break;
2823     }
2824     case 'r':
2825     {
2826       if (LocaleCompare("radial-blur",option) == 0)
2827         {
2828           flags=ParseGeometry(arg1,&geometry_info);
2829           new_image=RadialBlurImage(image,geometry_info.rho,
2830             geometry_info.sigma,exception);
2831           break;
2832         }
2833       if (LocaleCompare("raise",option) == 0)
2834         {
2835           flags=ParsePageGeometry(image,arg1,&geometry,exception);
2836           if ((flags & SigmaValue) == 0)
2837             geometry.height=geometry.width;
2838           (void) RaiseImage(image,&geometry,normal_op,exception);
2839           break;
2840         }
2841       if (LocaleCompare("random-threshold",option) == 0)
2842         {
2843           (void) RandomThresholdImage(image,arg1,exception);
2844           break;
2845         }
2846       if (LocaleCompare("remap",option) == 0)
2847         {
2848           Image
2849             *remap_image;
2850
2851           remap_image=GetImageCache(image_info,arg1,exception);
2852           if (remap_image == (Image *) NULL)
2853             break;
2854           (void) RemapImage(quantize_info,image,remap_image,exception);
2855           remap_image=DestroyImage(remap_image);
2856           break;
2857         }
2858       if (LocaleCompare("repage",option) == 0)
2859         {
2860           if (plus_alt_op == MagickFalse)
2861             (void) ResetImagePage(image,arg1);
2862           else
2863             (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
2864           break;
2865         }
2866       if (LocaleCompare("resample",option) == 0)
2867         {
2868           /* FUTURE: remove blur arguemnt - no longer used */
2869           flags=ParseGeometry(arg1,&geometry_info);
2870           if ((flags & SigmaValue) == 0)
2871             geometry_info.sigma=geometry_info.rho;
2872           new_image=ResampleImage(image,geometry_info.rho,
2873             geometry_info.sigma,image->filter,image->blur,exception);
2874           break;
2875         }
2876       if (LocaleCompare("resize",option) == 0)
2877         {
2878           /* FUTURE: remove blur argument - no longer used */
2879           (void) ParseRegionGeometry(image,arg1,&geometry,exception);
2880           new_image=ResizeImage(image,geometry.width,geometry.height,
2881             image->filter,image->blur,exception);
2882           break;
2883         }
2884       if (LocaleCompare("roll",option) == 0)
2885         {
2886           (void) ParsePageGeometry(image,arg1,&geometry,exception);
2887           new_image=RollImage(image,geometry.x,geometry.y,exception);
2888           break;
2889         }
2890       if (LocaleCompare("rotate",option) == 0)
2891         {
2892           if (strchr(arg1,'>') != (char *) NULL)
2893             if (image->columns <= image->rows)
2894               break;
2895           if (strchr(arg1,'<') != (char *) NULL)
2896             if (image->columns >= image->rows)
2897               break;
2898
2899           (void) ParseGeometry(arg1,&geometry_info);
2900           new_image=RotateImage(image,geometry_info.rho,exception);
2901           break;
2902         }
2903       break;
2904     }
2905     case 's':
2906     {
2907       if (LocaleCompare("sample",option) == 0)
2908         {
2909           (void) ParseRegionGeometry(image,arg1,&geometry,exception);
2910           new_image=SampleImage(image,geometry.width,geometry.height,
2911             exception);
2912           break;
2913         }
2914       if (LocaleCompare("scale",option) == 0)
2915         {
2916           (void) ParseRegionGeometry(image,arg1,&geometry,exception);
2917           new_image=ScaleImage(image,geometry.width,geometry.height,
2918             exception);
2919           break;
2920         }
2921       if (LocaleCompare("selective-blur",option) == 0)
2922         {
2923           flags=ParseGeometry(arg1,&geometry_info);
2924           if ((flags & PercentValue) != 0)
2925             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2926           new_image=SelectiveBlurImage(image,geometry_info.rho,
2927             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
2928           break;
2929         }
2930       if (LocaleCompare("separate",option) == 0)
2931         {
2932           /* WARNING: This can generate multiple images! */
2933           new_image=SeparateImages(image,exception);
2934           break;
2935         }
2936       if (LocaleCompare("sepia-tone",option) == 0)
2937         {
2938           double
2939             threshold;
2940
2941           threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2942           new_image=SepiaToneImage(image,threshold,exception);
2943           break;
2944         }
2945       if (LocaleCompare("segment",option) == 0)
2946         {
2947           flags=ParseGeometry(arg1,&geometry_info);
2948           if ((flags & SigmaValue) == 0)
2949             geometry_info.sigma=1.0;
2950           (void) SegmentImage(image,image->colorspace,
2951             image_info->verbose,geometry_info.rho,geometry_info.sigma,
2952             exception);
2953           break;
2954         }
2955       if (LocaleCompare("set",option) == 0)
2956         {
2957           char
2958             *value;
2959
2960           if (plus_alt_op != MagickFalse)
2961             {
2962               if (LocaleNCompare(arg1,"registry:",9) == 0)
2963                 (void) DeleteImageRegistry(arg1+9);
2964               else
2965                 if (LocaleNCompare(arg1,"option:",7) == 0)
2966                   {
2967                     (void) DeleteImageOption(image_info,arg1+7);
2968                     (void) DeleteImageArtifact(image,arg1+7);
2969                   }
2970                 else
2971                   (void) DeleteImageProperty(image,arg1);
2972               break;
2973             }
2974           value=InterpretImageProperties(image_info,image,arg2,
2975             exception);
2976           if (value == (char *) NULL)
2977             break;
2978           if (LocaleNCompare(arg1,"registry:",9) == 0)
2979             (void) SetImageRegistry(StringRegistryType,arg1+9,value,
2980               exception);
2981           else
2982             if (LocaleNCompare(arg1,"option:",7) == 0)
2983               {
2984                 (void) SetImageOption(image_info,arg1+7,value);
2985                 (void) SetImageArtifact(image,arg1+7,value);
2986               }
2987             else
2988               (void) SetImageProperty(image,arg1,value,exception);
2989           value=DestroyString(value);
2990           break;
2991         }
2992       if (LocaleCompare("shade",option) == 0)
2993         {
2994           flags=ParseGeometry(arg1,&geometry_info);
2995           if ((flags & SigmaValue) == 0)
2996             geometry_info.sigma=1.0;
2997           new_image=ShadeImage(image,normal_op,geometry_info.rho,
2998                geometry_info.sigma,exception);
2999           break;
3000         }
3001       if (LocaleCompare("shadow",option) == 0)
3002         {
3003           flags=ParseGeometry(arg1,&geometry_info);
3004           if ((flags & SigmaValue) == 0)
3005             geometry_info.sigma=1.0;
3006           if ((flags & XiValue) == 0)
3007             geometry_info.xi=4.0;
3008           if ((flags & PsiValue) == 0)
3009             geometry_info.psi=4.0;
3010           new_image=ShadowImage(image,geometry_info.rho,
3011             geometry_info.sigma,image->bias,(ssize_t)
3012             ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
3013             exception);
3014           break;
3015         }
3016       if (LocaleCompare("sharpen",option) == 0)
3017         {
3018           flags=ParseGeometry(arg1,&geometry_info);
3019           if ((flags & SigmaValue) == 0)
3020             geometry_info.sigma=1.0;
3021           if ((flags & XiValue) == 0)
3022             geometry_info.xi=0.0;
3023           new_image=SharpenImage(image,geometry_info.rho,
3024             geometry_info.sigma,geometry_info.xi,exception);
3025           break;
3026         }
3027       if (LocaleCompare("shave",option) == 0)
3028         {
3029           flags=ParsePageGeometry(image,arg1,&geometry,exception);
3030           new_image=ShaveImage(image,&geometry,exception);
3031           break;
3032         }
3033       if (LocaleCompare("shear",option) == 0)
3034         {
3035           flags=ParseGeometry(arg1,&geometry_info);
3036           if ((flags & SigmaValue) == 0)
3037             geometry_info.sigma=geometry_info.rho;
3038           new_image=ShearImage(image,geometry_info.rho,
3039             geometry_info.sigma,exception);
3040           break;
3041         }
3042       if (LocaleCompare("sigmoidal-contrast",option) == 0)
3043         {
3044           flags=ParseGeometry(arg1,&geometry_info);
3045           if ((flags & SigmaValue) == 0)
3046             geometry_info.sigma=(double) QuantumRange/2.0;
3047           if ((flags & PercentValue) != 0)
3048             geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3049               100.0;
3050           (void) SigmoidalContrastImage(image,normal_op,geometry_info.rho,
3051                geometry_info.sigma,
3052             exception);
3053           break;
3054         }
3055       if (LocaleCompare("sketch",option) == 0)
3056         {
3057           flags=ParseGeometry(arg1,&geometry_info);
3058           if ((flags & SigmaValue) == 0)
3059             geometry_info.sigma=1.0;
3060           new_image=SketchImage(image,geometry_info.rho,
3061             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3062           break;
3063         }
3064       if (LocaleCompare("solarize",option) == 0)
3065         {
3066           (void) SolarizeImage(image,StringToDoubleInterval(arg1,(double)
3067                  QuantumRange+1.0),exception);
3068           break;
3069         }
3070       if (LocaleCompare("sparse-color",option) == 0)
3071         {
3072           SparseColorMethod
3073             method;
3074
3075           char
3076             *arguments;
3077
3078           method=(SparseColorMethod) ParseCommandOption(
3079             MagickSparseColorOptions,MagickFalse,arg1);
3080           arguments=InterpretImageProperties(image_info,image,arg2,exception);
3081           if (arguments == (char *) NULL)
3082             break;
3083           new_image=SparseColorOption(image,method,arguments,exception);
3084           arguments=DestroyString(arguments);
3085           break;
3086         }
3087       if (LocaleCompare("splice",option) == 0)
3088         {
3089           (void) ParseGravityGeometry(image,arg1,&geometry,exception);
3090           new_image=SpliceImage(image,&geometry,exception);
3091           break;
3092         }
3093       if (LocaleCompare("spread",option) == 0)
3094         {
3095           (void) ParseGeometry(arg1,&geometry_info);
3096           new_image=SpreadImage(image,geometry_info.rho,image->interpolate,
3097                exception);
3098           break;
3099         }
3100       if (LocaleCompare("statistic",option) == 0)
3101         {
3102           StatisticType
3103             type;
3104
3105           type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
3106             MagickFalse,arg1);
3107           (void) ParseGeometry(arg2,&geometry_info);
3108           new_image=StatisticImage(image,type,(size_t) geometry_info.rho,
3109             (size_t) geometry_info.sigma,exception);
3110           break;
3111         }
3112       if (LocaleCompare("strip",option) == 0)
3113         {
3114           (void) StripImage(image,exception);
3115           break;
3116         }
3117       if (LocaleCompare("swirl",option) == 0)
3118         {
3119           (void) ParseGeometry(arg1,&geometry_info);
3120           new_image=SwirlImage(image,geometry_info.rho,
3121             image->interpolate,exception);
3122           break;
3123         }
3124       break;
3125     }
3126     case 't':
3127     {
3128       if (LocaleCompare("threshold",option) == 0)
3129         {
3130           double
3131             threshold;
3132
3133           if (plus_alt_op != MagickFalse)
3134             threshold=(double) QuantumRange/2;
3135           else
3136             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3137           (void) BilevelImage(image,threshold,exception);
3138           break;
3139         }
3140       if (LocaleCompare("thumbnail",option) == 0)
3141         {
3142           (void) ParseRegionGeometry(image,arg1,&geometry,exception);
3143           new_image=ThumbnailImage(image,geometry.width,geometry.height,
3144             exception);
3145           break;
3146         }
3147       if (LocaleCompare("tint",option) == 0)
3148         {
3149           new_image=TintImage(image,arg1,&draw_info->fill,exception);
3150           break;
3151         }
3152       if (LocaleCompare("transform",option) == 0)
3153         {
3154           /* DEPRECIATED */
3155           new_image=AffineTransformImage(image,&draw_info->affine,
3156             exception);
3157           break;
3158         }
3159       if (LocaleCompare("transparent",option) == 0)
3160         {
3161           PixelInfo
3162             target;
3163
3164           (void) QueryColorCompliance(arg1,AllCompliance,&target,exception);
3165           (void) TransparentPaintImage(image,&target,(Quantum)
3166             TransparentAlpha,plus_alt_op,exception);
3167           break;
3168         }
3169       if (LocaleCompare("transpose",option) == 0)
3170         {
3171           new_image=TransposeImage(image,exception);
3172           break;
3173         }
3174       if (LocaleCompare("transverse",option) == 0)
3175         {
3176           new_image=TransverseImage(image,exception);
3177           break;
3178         }
3179       if (LocaleCompare("trim",option) == 0)
3180         {
3181           new_image=TrimImage(image,exception);
3182           break;
3183         }
3184       if (LocaleCompare("type",option) == 0)
3185         {
3186           /* Note that "type" setting should have already been defined */
3187           (void) SetImageType(image,image_info->type,exception);
3188           break;
3189         }
3190       break;
3191     }
3192     case 'u':
3193     {
3194       if (LocaleCompare("unique",option) == 0)
3195         {
3196           /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
3197           if (plus_alt_op != MagickFalse)
3198             {
3199               (void) DeleteImageArtifact(image,"identify:unique-colors");
3200               break;
3201             }
3202           (void) SetImageArtifact(image,"identify:unique-colors","true");
3203           (void) SetImageArtifact(image,"verbose","true");
3204           break;
3205         }
3206       if (LocaleCompare("unique-colors",option) == 0)
3207         {
3208           new_image=UniqueImageColors(image,exception);
3209           break;
3210         }
3211       if (LocaleCompare("unsharp",option) == 0)
3212         {
3213           flags=ParseGeometry(arg1,&geometry_info);
3214           if ((flags & SigmaValue) == 0)
3215             geometry_info.sigma=1.0;
3216           if ((flags & XiValue) == 0)
3217             geometry_info.xi=1.0;
3218           if ((flags & PsiValue) == 0)
3219             geometry_info.psi=0.05;
3220           new_image=UnsharpMaskImage(image,geometry_info.rho,
3221             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3222           break;
3223         }
3224       break;
3225     }
3226     case 'v':
3227     {
3228       if (LocaleCompare("verbose",option) == 0)
3229         {
3230           /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3231              three places!   ImageArtifact   ImageOption  image_info->verbose
3232              Some how new images also get this artifact -- how???
3233           */
3234           (void) SetImageArtifact(image,option,
3235                  (plus_alt_op != MagickFalse) ? "false" : "true" );
3236           break;
3237         }
3238       if (LocaleCompare("vignette",option) == 0)
3239         {
3240           flags=ParseGeometry(arg1,&geometry_info);
3241           if ((flags & SigmaValue) == 0)
3242             geometry_info.sigma=1.0;
3243           if ((flags & XiValue) == 0)
3244             geometry_info.xi=0.1*image->columns;
3245           if ((flags & PsiValue) == 0)
3246             geometry_info.psi=0.1*image->rows;
3247           new_image=VignetteImage(image,geometry_info.rho,geometry_info.sigma,
3248             image->bias,(ssize_t) ceil(geometry_info.xi-0.5),
3249             (ssize_t) ceil(geometry_info.psi-0.5),exception);
3250           break;
3251         }
3252       break;
3253     }
3254     case 'w':
3255     {
3256       if (LocaleCompare("wave",option) == 0)
3257         {
3258           flags=ParseGeometry(arg1,&geometry_info);
3259           if ((flags & SigmaValue) == 0)
3260             geometry_info.sigma=1.0;
3261           new_image=WaveImage(image,geometry_info.rho,geometry_info.sigma,
3262                image->interpolate,exception);
3263           break;
3264         }
3265       if (LocaleCompare("white-threshold",option) == 0)
3266         {
3267           (void) WhiteThresholdImage(image,arg1,exception);
3268           break;
3269         }
3270       break;
3271     }
3272     default:
3273       break;
3274   }
3275   /*
3276      Replace current image with any image that was generated
3277      and set image point to last image (so image->next is correct)
3278   */
3279   if (new_image != (Image *) NULL)
3280     ReplaceImageInListReturnLast(&image,new_image);
3281
3282   return;
3283 #undef image_info
3284 #undef draw_info
3285 #undef quantize_info
3286 #undef image
3287 #undef exception
3288 #undef normal_op
3289 }
3290
3291 WandExport void WandSimpleOperatorImages(MagickWand *wand,
3292   const MagickBooleanType plus_alt_op, const char *option,
3293   const char *arg1, const char *arg2)
3294 {
3295   size_t
3296     n;
3297
3298   register ssize_t
3299     i;
3300
3301   assert(wand->image_info != (const ImageInfo *) NULL);
3302   assert(wand->image_info->signature == MagickSignature);
3303   assert(wand->draw_info != (DrawInfo *) NULL);   /* ensure it is a CLI wand */
3304   assert(wand->images != (Image *) NULL);         /* there is one image */
3305
3306   i=0;
3307   n=GetImageListLength(wand->images);
3308   wand->images=GetFirstImageInList(wand->images);
3309   for ( ; ; )
3310   {
3311     WandSimpleOperatorImage(wand, plus_alt_op, option, arg1, arg2);
3312     if ( wand->images->next == (Image *) NULL )
3313       break;
3314     wand->images=wand->images->next;
3315     i++;
3316   }
3317   wand->images=GetFirstImageInList(wand->images);
3318   return;
3319 }
3320 \f
3321 /*
3322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3323 %                                                                             %
3324 %                                                                             %
3325 %                                                                             %
3326 +     W a n d L i s t O p e r a t o r I m a g e s                             %
3327 %                                                                             %
3328 %                                                                             %
3329 %                                                                             %
3330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3331 %
3332 %  WandListOperatorImages() applies a single operation that is apply to the
3333 %  entire image list as a whole. The result is often a complete replacment
3334 %  of the image list with a completely new list, or just a single image.
3335 %
3336 %  The format of the MogrifyImage method is:
3337 %
3338 %    void WandListOperatorImages(MagickWand *wand,
3339 %        const MagickBooleanType plus_alt_op,const char *option,
3340 %        const char *arg1, const char *arg2)
3341 %
3342 %  A description of each parameter follows:
3343 %
3344 %    o wand: structure holding settings to be applied
3345 %
3346 %    o plus_alt_op:  request the 'plus' or alturnative form of the operation
3347 %
3348 %    o option:  The option string for the operation
3349 %
3350 %    o arg1, arg2: optional argument strings to the operation
3351 %
3352 % NOTE: only "limit" currently uses two arguments.
3353 %
3354 % Example usage...
3355 %
3356 %  WandListOperatorImages(wand,MagickFalse,"duplicate", "3",  NULL);
3357 %  WandListOperatorImages(wand,MagickTrue, "append",    NULL, NULL);
3358 %  if ( wand->exception->severity != UndefinedException ) {
3359 %    CatchException(exception);
3360 %    exit(1);
3361 %  }
3362 %
3363 % Or for handling command line arguments EG: +/-option ["arg"]
3364 %
3365 %    argc,argv
3366 %    i=index in argv
3367 %
3368 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
3369 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
3370 %    if ( (flags & ListOperatorOptionFlag) != 0 )
3371 %      WandListOperatorImages(wand,
3372 %          ((*argv[i])=='+')?MagickTrue:MagickFalse,argv[i]+1,
3373 %          count>=1 ? argv[i+1] : (char *)NULL,
3374 %          count>=2 ? argv[i+2] : (char *)NULL );
3375 %    i += count+1;
3376 %
3377 */
3378 WandExport void WandListOperatorImages(MagickWand *wand,
3379      const MagickBooleanType plus_alt_op,const char *option,
3380      const char *arg1, const char *arg2)
3381 {
3382   Image
3383     *new_images;
3384
3385 #define image_info      (wand->image_info)
3386 #define draw_info       (wand->draw_info)
3387 #define quantize_info   (wand->quantize_info)
3388 #define images          (wand->images)
3389 #define exception       (wand->exception)
3390 #define normal_op       (plus_alt_op?MagickFalse:MagickTrue)
3391
3392   assert(image_info != (const ImageInfo *) NULL);
3393   assert(image_info->signature == MagickSignature);
3394   assert(draw_info != (DrawInfo *) NULL);       /* ensure it is a CLI wand */
3395   assert(images != (Image *) NULL);             /* there is an image */
3396   assert(images->signature == MagickSignature); /* and is a valid image */
3397
3398   if (wand->debug != MagickFalse)
3399     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
3400
3401   (void) SyncImagesSettings(image_info,images,exception);
3402
3403   new_images=NewImageList();
3404
3405   switch (*option)
3406   {
3407     case 'a':
3408     {
3409       if (LocaleCompare("append",option) == 0)
3410         {
3411           new_images=AppendImages(images,normal_op,exception);
3412           break;
3413         }
3414       if (LocaleCompare("average",option) == 0)
3415         {
3416           /* DEPRECIATED - use -evaluate-sequence Mean */
3417           WandListOperatorImages(wand,plus_alt_op,"evaluate-sequence","Mean",
3418                NULL);
3419           break;
3420         }
3421       break;
3422     }
3423     case 'c':
3424     {
3425       if (LocaleCompare("clut",option) == 0)
3426         {
3427           /* FUTURE - make this a compose option (and thus layers compose )
3428              or perhaps compose last image over all other images.
3429           */
3430           Image
3431             *clut_image;
3432
3433           new_images=RemoveFirstImageFromList(&images);
3434           clut_image=RemoveLastImageFromList(&images);
3435           /* FUTURE - produce Exception, rather than silent fail */
3436           if (clut_image == (Image *) NULL)
3437               break;
3438           (void) ClutImage(new_images,clut_image,images->interpolate,exception);
3439           clut_image=DestroyImage(clut_image);
3440           break;
3441         }
3442       if (LocaleCompare("coalesce",option) == 0)
3443         {
3444           new_images=CoalesceImages(images,exception);
3445           break;
3446         }
3447       if (LocaleCompare("combine",option) == 0)
3448         {
3449           new_images=CombineImages(images,exception);
3450           break;
3451         }
3452       if (LocaleCompare("composite",option) == 0)
3453         {
3454           Image
3455             *mask_image,
3456             *source_image;
3457
3458           RectangleInfo
3459             geometry;
3460
3461           CompositeOperator
3462             compose;
3463
3464           const char*
3465             value;
3466
3467           value=GetImageOption(image_info,"compose");
3468           if (value != (const char *) NULL)
3469             compose=(CompositeOperator) ParseCommandOption(
3470                  MagickComposeOptions,MagickFalse,value);
3471           else
3472             compose=OverCompositeOp;  /* use Over not source_image->compose */
3473
3474           new_images=RemoveFirstImageFromList(&images);
3475           source_image=RemoveFirstImageFromList(&images);
3476           /* FUTURE - produce Exception, rather than silent fail */
3477           if (source_image == (Image *) NULL)
3478             break;
3479
3480           /* FUTURE - this should not be here! - should be part of -geometry */
3481           (void) TransformImage(&source_image,(char *) NULL,
3482             source_image->geometry,exception);
3483
3484           SetGeometry(source_image,&geometry);
3485           (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3486           GravityAdjustGeometry(new_images->columns,new_images->rows,
3487                new_images->gravity, &geometry);
3488
3489           mask_image=RemoveFirstImageFromList(&images);
3490           if (mask_image != (Image *) NULL)
3491             { /* handle a third write mask image */
3492               if ((compose == DisplaceCompositeOp) ||
3493                   (compose == DistortCompositeOp))
3494                 { /* Merge Y displacement into X displace/distort map. */
3495                   (void) CompositeImage(source_image,CopyGreenCompositeOp,
3496                     mask_image,0,0,exception);
3497                   mask_image=DestroyImage(mask_image);
3498                 }
3499               else
3500                 {
3501                   /*
3502                     Set a blending mask for the composition.
3503                   */
3504                   (void) NegateImage(mask_image,MagickFalse,exception);
3505                   (void) SetImageMask(new_images,mask_image,exception);
3506                   mask_image=DestroyImage(mask_image);
3507                 }
3508             }
3509           (void) CompositeImage(new_images,compose,source_image,geometry.x,
3510                      geometry.y,exception);
3511           (void) SetImageMask(new_images,(Image *) NULL,exception);
3512           source_image=DestroyImage(source_image);
3513           break;
3514         }
3515       break;
3516     }
3517     case 'd':
3518     {
3519       if (LocaleCompare("deconstruct",option) == 0)
3520         {
3521           /* DEPRECIATED - use -layers CompareAny */
3522           WandListOperatorImages(wand,plus_alt_op,"layer","CompareAny",NULL);
3523           break;
3524         }
3525       if (LocaleCompare("delete",option) == 0)
3526         {
3527           if (plus_alt_op != MagickFalse)
3528             DeleteImages(&images,"-1",exception);
3529           else
3530             DeleteImages(&images,arg1,exception);
3531           break;
3532         }
3533       if (LocaleCompare("duplicate",option) == 0)
3534         {
3535           if (plus_alt_op != MagickFalse)
3536             new_images=DuplicateImages(images,1,"-1",exception);
3537           else
3538             {
3539               const char
3540                 *p;
3541
3542               size_t
3543                 number_duplicates;
3544
3545               number_duplicates=(size_t) StringToLong(arg1);
3546               p=strchr(arg1,',');
3547               if (p == (const char *) NULL)
3548                 new_images=DuplicateImages(images,number_duplicates,
3549                   "-1",exception);
3550               else
3551                 new_images=DuplicateImages(images,number_duplicates,p,
3552                   exception);
3553             }
3554           AppendImageToList(&images, new_images);
3555           new_images=(Image *)NULL;
3556           break;
3557         }
3558       break;
3559     }
3560     case 'e':
3561     {
3562       if (LocaleCompare("evaluate-sequence",option) == 0)
3563         {
3564           MagickEvaluateOperator
3565             method;
3566
3567           method=(MagickEvaluateOperator) ParseCommandOption(
3568             MagickEvaluateOptions,MagickFalse,arg1);
3569           new_images=EvaluateImages(images,method,exception);
3570           break;
3571         }
3572       break;
3573     }
3574     case 'f':
3575     {
3576       if (LocaleCompare("fft",option) == 0)
3577         {
3578           new_images=ForwardFourierTransformImage(images,normal_op,exception);
3579           break;
3580         }
3581       if (LocaleCompare("flatten",option) == 0)
3582         {
3583           /* DEPRECIATED use -layers mosaic instead */
3584           WandListOperatorImages(wand,plus_alt_op,"layer",option,NULL);
3585           break;
3586         }
3587       if (LocaleCompare("fx",option) == 0)
3588         {
3589           new_images=FxImage(images,arg1,exception);
3590           break;
3591         }
3592       break;
3593     }
3594     case 'h':
3595     {
3596       if (LocaleCompare("hald-clut",option) == 0)
3597         {
3598           /* FUTURE - make this a compose option (and thus layers compose )
3599              or perhaps compose last image over all other images.
3600           */
3601           Image
3602             *hald_image;
3603
3604           new_images=RemoveFirstImageFromList(&images);
3605           hald_image=RemoveLastImageFromList(&images);
3606           if (hald_image == (Image *) NULL)
3607             break;
3608           (void) HaldClutImage(new_images,hald_image,exception);
3609           hald_image=DestroyImage(hald_image);
3610           break;
3611         }
3612       break;
3613     }
3614     case 'i':
3615     {
3616       if (LocaleCompare("ift",option) == 0)
3617         {
3618           Image
3619             *magnitude_image,
3620             *phase_image;
3621
3622            magnitude_image=RemoveFirstImageFromList(&images);
3623            phase_image=RemoveFirstImageFromList(&images);
3624           /* FUTURE - produce Exception, rather than silent fail */
3625            if (phase_image == (Image *) NULL)
3626              break;
3627            new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3628                    normal_op,exception);
3629            magnitude_image=DestroyImage(magnitude_image);
3630            phase_image=DestroyImage(phase_image);
3631           break;
3632         }
3633       if (LocaleCompare("insert",option) == 0)
3634         {
3635           Image
3636             *insert_image,
3637             *index_image;
3638
3639           ssize_t
3640             index;
3641
3642           index=0;
3643           insert_image=RemoveLastImageFromList(&images);
3644           if (plus_alt_op == MagickFalse)
3645             index=(ssize_t) StringToLong(arg1);
3646           if (index == 0)
3647             PrependImageToList(&images,insert_image);
3648           else
3649             if (index == (ssize_t) GetImageListLength(images))
3650               AppendImageToList(&images,insert_image);
3651             else
3652               {
3653                  index_image=GetImageFromList(images,index-1);
3654                  if (index_image == (Image *) NULL)
3655                    {
3656                      (void) ThrowMagickException(exception,GetMagickModule(),
3657                        OptionError,"NoSuchImage","`%s'",arg1);
3658                      break;
3659                    }
3660                 InsertImageInList(&index_image,insert_image);
3661               }
3662           images=GetFirstImageInList(index_image);
3663           break;
3664         }
3665       break;
3666     }
3667     case 'l':
3668     {
3669       if (LocaleCompare("layers",option) == 0)
3670         {
3671           ImageLayerMethod
3672             method;
3673
3674           method=(ImageLayerMethod) ParseCommandOption(MagickLayerOptions,
3675             MagickFalse,arg1);
3676           switch (method)
3677           {
3678             case CoalesceLayer:
3679             {
3680               new_images=CoalesceImages(images,exception);
3681               break;
3682             }
3683             case CompareAnyLayer:
3684             case CompareClearLayer:
3685             case CompareOverlayLayer:
3686             default:
3687             {
3688               new_images=CompareImagesLayers(images,method,exception);
3689               break;
3690             }
3691             case MergeLayer:
3692             case FlattenLayer:
3693             case MosaicLayer:
3694             case TrimBoundsLayer:
3695             {
3696               new_images=MergeImageLayers(images,method,exception);
3697               break;
3698             }
3699             case DisposeLayer:
3700             {
3701               new_images=DisposeImages(images,exception);
3702               break;
3703             }
3704             case OptimizeImageLayer:
3705             {
3706               new_images=OptimizeImageLayers(images,exception);
3707               break;
3708             }
3709             case OptimizePlusLayer:
3710             {
3711               new_images=OptimizePlusImageLayers(images,exception);
3712               break;
3713             }
3714             case OptimizeTransLayer:
3715             {
3716               OptimizeImageTransparency(images,exception);
3717               break;
3718             }
3719             case RemoveDupsLayer:
3720             {
3721               RemoveDuplicateLayers(&images,exception);
3722               break;
3723             }
3724             case RemoveZeroLayer:
3725             {
3726               RemoveZeroDelayLayers(&images,exception);
3727               break;
3728             }
3729             case OptimizeLayer:
3730             { /* General Purpose, GIF Animation Optimizer.  */
3731               new_images=CoalesceImages(images,exception);
3732               if (new_images == (Image *) NULL)
3733                 break;
3734               images=DestroyImageList(images);
3735               images=OptimizeImageLayers(new_images,exception);
3736               if (images == (Image *) NULL)
3737                 break;
3738               new_images=DestroyImageList(new_images);
3739               OptimizeImageTransparency(images,exception);
3740               (void) RemapImages(quantize_info,images,(Image *) NULL,
3741                 exception);
3742               break;
3743             }
3744             case CompositeLayer:
3745             {
3746               Image
3747                 *source;
3748
3749               RectangleInfo
3750                 geometry;
3751
3752               CompositeOperator
3753                 compose;
3754
3755               const char*
3756                 value;
3757
3758               value=GetImageOption(image_info,"compose");
3759               compose=OverCompositeOp;  /* Default to Over */
3760               if (value != (const char *) NULL)
3761                 compose=(CompositeOperator) ParseCommandOption(
3762                       MagickComposeOptions,MagickFalse,value);
3763
3764               /* Split image sequence at the first 'NULL:' image. */
3765               source=images;
3766               while (source != (Image *) NULL)
3767               {
3768                 source=GetNextImageInList(source);
3769                 if ((source != (Image *) NULL) &&
3770                     (LocaleCompare(source->magick,"NULL") == 0))
3771                   break;
3772               }
3773               if (source != (Image *) NULL)
3774                 {
3775                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
3776                       (GetNextImageInList(source) == (Image *) NULL))
3777                     source=(Image *) NULL;
3778                   else
3779                     { /* Separate the two lists, junk the null: image.  */
3780                       source=SplitImageList(source->previous);
3781                       DeleteImageFromList(&source);
3782                     }
3783                 }
3784               if (source == (Image *) NULL)
3785                 {
3786                   (void) ThrowMagickException(exception,GetMagickModule(),
3787                     OptionError,"MissingNullSeparator","layers Composite");
3788                   break;
3789                 }
3790               /* Adjust offset with gravity and virtual canvas.  */
3791               SetGeometry(images,&geometry);
3792               (void) ParseAbsoluteGeometry(images->geometry,&geometry);
3793               geometry.width=source->page.width != 0 ?
3794                 source->page.width : source->columns;
3795               geometry.height=source->page.height != 0 ?
3796                source->page.height : source->rows;
3797               GravityAdjustGeometry(images->page.width != 0 ?
3798                 images->page.width : images->columns,
3799                 images->page.height != 0 ? images->page.height :
3800                 images->rows,images->gravity,&geometry);
3801
3802               /* Compose the two image sequences together */
3803               CompositeLayers(images,compose,source,geometry.x,geometry.y,
3804                 exception);
3805               source=DestroyImageList(source);
3806               break;
3807             }
3808           }
3809           break;
3810         }
3811       if (LocaleCompare("limit",option) == 0)
3812         {
3813           MagickSizeType
3814             limit;
3815
3816           ResourceType
3817             type;
3818
3819           type=(ResourceType) ParseCommandOption(MagickResourceOptions,
3820             MagickFalse,arg1);
3821           limit=MagickResourceInfinity;
3822           if (LocaleCompare("unlimited",arg2) != 0)
3823             limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
3824           (void) SetMagickResourceLimit(type,limit);
3825           break;
3826         }
3827       break;
3828     }
3829     case 'm':
3830     {
3831       if (LocaleCompare("map",option) == 0)
3832         {
3833           /* DEPRECIATED use +remap */
3834           (void) RemapImages(quantize_info,images,(Image *) NULL,exception);
3835           break;
3836         }
3837       if (LocaleCompare("morph",option) == 0)
3838         {
3839           Image
3840             *morph_image;
3841
3842           morph_image=MorphImages(images,StringToUnsignedLong(arg1),
3843             exception);
3844           if (morph_image == (Image *) NULL)
3845             break;
3846           images=DestroyImageList(images);
3847           images=morph_image;
3848           break;
3849         }
3850       if (LocaleCompare("mosaic",option) == 0)
3851         {
3852           /* DEPRECIATED use -layers mosaic instead */
3853           WandListOperatorImages(wand,plus_alt_op,"layer",option,NULL);
3854           break;
3855         }
3856       break;
3857     }
3858     case 'p':
3859     {
3860       if (LocaleCompare("print",option) == 0)
3861         {
3862           char
3863             *string;
3864
3865           string=InterpretImageProperties(image_info,images,arg1,
3866             exception);
3867           if (string == (char *) NULL)
3868             break;
3869           (void) FormatLocaleFile(stdout,"%s",string);
3870           string=DestroyString(string);
3871         }
3872       if (LocaleCompare("process",option) == 0)
3873         {
3874           char
3875             **arguments;
3876
3877           int
3878             j,
3879             number_arguments;
3880
3881           arguments=StringToArgv(arg1,&number_arguments);
3882           if (arguments == (char **) NULL)
3883             break;
3884           if (strchr(arguments[1],'=') != (char *) NULL)
3885             {
3886               char
3887                 breaker,
3888                 quote,
3889                 *token;
3890
3891               const char
3892                 *arguments;
3893
3894               int
3895                 next,
3896                 status;
3897
3898               size_t
3899                 length;
3900
3901               TokenInfo
3902                 *token_info;
3903
3904               /*
3905                 Support old style syntax, filter="-option arg".
3906               */
3907               length=strlen(arg1);
3908               token=(char *) NULL;
3909               if (~length >= (MaxTextExtent-1))
3910                 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3911                   sizeof(*token));
3912               if (token == (char *) NULL)
3913                 break;
3914               next=0;
3915               arguments=arg1;
3916               token_info=AcquireTokenInfo();
3917               status=Tokenizer(token_info,0,token,length,arguments,"","=",
3918                 "\"",'\0',&breaker,&next,&quote);
3919               token_info=DestroyTokenInfo(token_info);
3920               if (status == 0)
3921                 {
3922                   const char
3923                     *argv;
3924
3925                   argv=(&(arguments[next]));
3926                   (void) InvokeDynamicImageFilter(token,&images,1,&argv,
3927                     exception);
3928                 }
3929               token=DestroyString(token);
3930               break;
3931             }
3932           (void) SubstituteString(&arguments[1],"-","");
3933           (void) InvokeDynamicImageFilter(arguments[1],&images,
3934             number_arguments-2,(const char **) arguments+2,exception);
3935           for (j=0; j < number_arguments; j++)
3936             arguments[j]=DestroyString(arguments[j]);
3937           arguments=(char **) RelinquishMagickMemory(arguments);
3938           break;
3939         }
3940       break;
3941     }
3942     case 'r':
3943     {
3944       if (LocaleCompare("remap",option) == 0)
3945         {
3946               (void) RemapImages(quantize_info,images,(Image *) NULL,exception);
3947           (void) RemapImages(quantize_info,images,(Image *) NULL,exception);
3948           break;
3949         }
3950       if (LocaleCompare("reverse",option) == 0)
3951         {
3952           ReverseImageList(&images);
3953           break;
3954         }
3955       break;
3956     }
3957     case 's':
3958     {
3959       if (LocaleCompare("smush",option) == 0)
3960         {
3961           Image
3962             *smush_image;
3963
3964           ssize_t
3965             offset;
3966
3967           offset=(ssize_t) StringToLong(arg1);
3968           smush_image=SmushImages(images,normal_op,offset,exception);
3969           if (smush_image == (Image *) NULL)
3970             break;
3971           images=DestroyImageList(images);
3972           images=smush_image;
3973           break;
3974         }
3975       if (LocaleCompare("swap",option) == 0)
3976         {
3977           Image
3978             *p,
3979             *q,
3980             *swap;
3981
3982           ssize_t
3983             index,
3984             swap_index;
3985
3986           index=-1;
3987           swap_index=-2;
3988           if (plus_alt_op == MagickFalse)
3989             {
3990               GeometryInfo
3991                 geometry_info;
3992
3993               MagickStatusType
3994                 flags;
3995
3996               swap_index=(-1);
3997               flags=ParseGeometry(arg1,&geometry_info);
3998               index=(ssize_t) geometry_info.rho;
3999               if ((flags & SigmaValue) != 0)
4000                 swap_index=(ssize_t) geometry_info.sigma;
4001             }
4002           p=GetImageFromList(images,index);
4003           q=GetImageFromList(images,swap_index);
4004           if ((p == (Image *) NULL) || (q == (Image *) NULL))
4005             {
4006               (void) ThrowMagickException(exception,GetMagickModule(),
4007                 OptionError,"NoSuchImage","`%s'",images->filename);
4008               break;
4009             }
4010           if (p == q)
4011             break;
4012           swap=CloneImage(p,0,0,MagickTrue,exception);
4013           ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,exception));
4014           ReplaceImageInList(&q,swap);
4015           images=GetFirstImageInList(q);
4016           break;
4017         }
4018       break;
4019     }
4020     case 'w':
4021     {
4022       if (LocaleCompare("write",option) == 0)
4023         {
4024           char
4025             key[MaxTextExtent];
4026
4027           Image
4028             *write_images;
4029
4030           ImageInfo
4031             *write_info;
4032
4033           (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4034           (void) DeleteImageRegistry(key);
4035           write_images=images;
4036           if (plus_alt_op != MagickFalse)
4037             write_images=CloneImageList(images,exception);
4038           write_info=CloneImageInfo(image_info);
4039           (void) WriteImages(write_info,write_images,arg1,exception);
4040           write_info=DestroyImageInfo(write_info);
4041           if (plus_alt_op != MagickFalse)
4042             write_images=DestroyImageList(write_images);
4043           break;
4044         }
4045       break;
4046     }
4047     default:
4048       break;
4049   }
4050   if (new_images == (Image *) NULL)
4051     return;
4052
4053   if (images != (Image *) NULL)
4054     images=DestroyImageList(images);
4055   images=new_images;
4056   return;
4057
4058 #undef image_info
4059 #undef draw_info
4060 #undef quantize_info
4061 #undef images
4062 #undef exception
4063 #undef normal_op
4064 }