]> granicus.if.org Git - imagemagick/blob - MagickWand/operation.c
(no commit message)
[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-2013 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/wand.h"
54 #include "MagickWand/wandcli.h"
55 #include "MagickWand/wandcli-private.h"
56 #include "MagickWand/operation.h"
57 #include "MagickCore/monitor-private.h"
58 #include "MagickCore/thread-private.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/pixel-private.h"
61 \f
62 /*
63   Define declarations.
64 */
65 #define USE_WAND_METHODS  1
66 #define MAX_STACK_DEPTH  32
67 #define UNDEFINED_COMPRESSION_QUALITY  0UL
68
69 /* FUTURE: why is this default so specific? */
70 #define DEFAULT_DISSIMILARITY_THRESHOLD "0.31830988618379067154"
71
72 /*
73   Constant declaration. (temporary exports)
74 */
75 static const char
76   BackgroundColor[] = "#fff",  /* white */
77   BorderColor[] = "#dfdfdf",  /* sRGB gray */
78   MatteColor[] = "#bdbdbd";  /* slightly darker gray */
79
80 /* For Debugging Geometry Input */
81 #define ReportGeometry(flags,info) \
82   (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", \
83        flags, info.rho, info.sigma, info.xi, info.psi )
84 \f
85 /*
86 ** Function to report on the progress of image operations
87 */
88 static MagickBooleanType MonitorProgress(const char *text,
89   const MagickOffsetType offset,const MagickSizeType extent,
90   void *wand_unused(cli_wandent_data))
91 {
92   char
93     message[MaxTextExtent],
94     tag[MaxTextExtent];
95
96   const char
97     *locale_message;
98
99   register char
100     *p;
101
102   if (extent < 2)
103     return(MagickTrue);
104   (void) CopyMagickMemory(tag,text,MaxTextExtent);
105   p=strrchr(tag,'/');
106   if (p != (char *) NULL)
107     *p='\0';
108   (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
109   locale_message=GetLocaleMessage(message);
110   if (locale_message == message)
111     locale_message=tag;
112   if (p == (char *) NULL)
113     (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
114       locale_message,(long) offset,(unsigned long) extent,(long)
115       (100L*offset/(extent-1)));
116   else
117     (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
118       locale_message,p+1,(long) offset,(unsigned long) extent,(long)
119       (100L*offset/(extent-1)));
120   if (offset == (MagickOffsetType) (extent-1))
121     (void) FormatLocaleFile(stderr,"\n");
122   (void) fflush(stderr);
123   return(MagickTrue);
124 }
125
126 /*
127 ** GetImageCache() will read an image into a image cache if not already
128 ** present then return the image that is in the cache under that filename.
129 */
130 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
131   ExceptionInfo *exception)
132 {
133   char
134     key[MaxTextExtent];
135
136   ExceptionInfo
137     *sans_exception;
138
139   Image
140     *image;
141
142   ImageInfo
143     *read_info;
144
145   (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
146   sans_exception=AcquireExceptionInfo();
147   image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
148   sans_exception=DestroyExceptionInfo(sans_exception);
149   if (image != (Image *) NULL)
150     return(image);
151   read_info=CloneImageInfo(image_info);
152   (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
153   image=ReadImage(read_info,exception);
154   read_info=DestroyImageInfo(read_info);
155   if (image != (Image *) NULL)
156     (void) SetImageRegistry(ImageRegistryType,key,image,exception);
157   return(image);
158 }
159
160 /*
161   SparseColorOption() parse the complex -sparse-color argument into an
162   an array of floating point values than call SparseColorImage().
163   Argument is a complex mix of floating-point pixel coodinates, and color
164   specifications (or direct floating point numbers).  The number of floats
165   needed to represent a color varies depending on the current channel
166   setting.
167
168   This really should be in MagickCore, so that other API's can make use of it.
169 */
170 static Image *SparseColorOption(const Image *image,
171   const SparseColorMethod method,const char *arguments,ExceptionInfo *exception)
172 {
173   char
174     token[MaxTextExtent];
175
176   const char
177     *p;
178
179   double
180     *sparse_arguments;
181
182   Image
183     *sparse_image;
184
185   PixelInfo
186     color;
187
188   MagickBooleanType
189     error;
190
191   register size_t
192     x;
193
194   size_t
195     number_arguments,
196     number_colors;
197
198   assert(image != (Image *) NULL);
199   assert(image->signature == MagickSignature);
200   if (IfMagickTrue(image->debug))
201     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
202   assert(exception != (ExceptionInfo *) NULL);
203   assert(exception->signature == MagickSignature);
204   /*
205     Limit channels according to image
206     add up number of values needed per color.
207   */
208   number_colors=0;
209   if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
210     number_colors++;
211   if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
212     number_colors++;
213   if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
214     number_colors++;
215   if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
216       (image->colorspace == CMYKColorspace))
217     number_colors++;
218   if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
219       image->alpha_trait == BlendPixelTrait)
220     number_colors++;
221
222   /*
223     Read string, to determine number of arguments needed,
224   */
225   p=arguments;
226   x=0;
227   while( *p != '\0' )
228   {
229     GetMagickToken(p,&p,token);
230     if ( token[0] == ',' ) continue;
231     if ( isalpha((int) token[0]) || token[0] == '#' )
232       x += number_colors;  /* color argument found */
233     else
234       x++;   /* floating point argument */
235   }
236   /* control points and color values */
237   error = IsMagickTrue( x % (2+number_colors) );
238   number_arguments=x;
239   if ( IfMagickTrue(error) ) {
240     (void) ThrowMagickException(exception,GetMagickModule(),
241                OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
242                "Invalid number of Arguments");
243     return( (Image *)NULL);
244   }
245
246   /* Allocate and fill in the floating point arguments */
247   sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
248     sizeof(*sparse_arguments));
249   if (sparse_arguments == (double *) NULL) {
250     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
251       "MemoryAllocationFailed","%s","SparseColorOption");
252     return( (Image *)NULL);
253   }
254   (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
255     sizeof(*sparse_arguments));
256   p=arguments;
257   x=0;
258   while( *p != '\0' && x < number_arguments ) {
259     /* X coordinate */
260     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
261     if ( token[0] == '\0' ) break;
262     if ( isalpha((int) token[0]) || token[0] == '#' ) {
263       (void) ThrowMagickException(exception,GetMagickModule(),
264             OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
265             "Color found, instead of X-coord");
266       error = MagickTrue;
267       break;
268     }
269     sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
270     /* Y coordinate */
271     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
272     if ( token[0] == '\0' ) break;
273     if ( isalpha((int) token[0]) || token[0] == '#' ) {
274       (void) ThrowMagickException(exception,GetMagickModule(),
275             OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
276             "Color found, instead of Y-coord");
277       error = MagickTrue;
278       break;
279     }
280     sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
281     /* color name or function given in string argument */
282     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
283     if ( token[0] == '\0' ) break;
284     if ( isalpha((int) token[0]) || token[0] == '#' ) {
285       /* Color string given */
286       (void) QueryColorCompliance(token,AllCompliance,&color,
287                 exception);
288       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
289         sparse_arguments[x++] = QuantumScale*color.red;
290       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
291         sparse_arguments[x++] = QuantumScale*color.green;
292       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
293         sparse_arguments[x++] = QuantumScale*color.blue;
294       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
295           (image->colorspace == CMYKColorspace))
296         sparse_arguments[x++] = QuantumScale*color.black;
297       if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
298           image->alpha_trait == BlendPixelTrait)
299         sparse_arguments[x++] = QuantumScale*color.alpha;
300     }
301     else {
302       /* Colors given as a set of floating point values - experimental */
303       /* NB: token contains the first floating point value to use! */
304       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
305         {
306         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
307         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
308           break;
309         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
310         token[0] = ','; /* used this token - get another */
311       }
312       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
313         {
314         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
315         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
316           break;
317         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
318         token[0] = ','; /* used this token - get another */
319       }
320       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
321         {
322         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
323         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
324           break;
325         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
326         token[0] = ','; /* used this token - get another */
327       }
328       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
329           (image->colorspace == CMYKColorspace))
330         {
331         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
332         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
333           break;
334         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
335         token[0] = ','; /* used this token - get another */
336       }
337       if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
338           image->alpha_trait == BlendPixelTrait)
339         {
340         while ( token[0] == ',' ) GetMagickToken(p,&p,token);
341         if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
342           break;
343         sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
344         token[0] = ','; /* used this token - get another */
345       }
346     }
347   }
348   if ( number_arguments != x && !error ) {
349     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
350       "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
351     sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
352     return( (Image *)NULL);
353   }
354   if ( error )
355     return( (Image *)NULL);
356
357   /* Call the Sparse Color Interpolation function with the parsed arguments */
358   sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
359     exception);
360   sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
361   return( sparse_image );
362 }
363 \f
364 /*
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 %                                                                             %
367 %                                                                             %
368 %                                                                             %
369 %   C L I S e t t i n g O p t i o n I n f o                                   %
370 %                                                                             %
371 %                                                                             %
372 %                                                                             %
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 %
375 %  CLISettingOptionInfo() applies a single settings option into a CLI wand
376 %  holding the image_info, draw_info, quantize_info structures that will be
377 %  used when processing the images.
378 %
379 %  These options do no require images to be present in the CLI wand for them
380 %  to be able to be set, in which case they will generally be applied to image
381 %  that are read in later
382 %
383 %  Options handled by this function are listed in CommandOptions[] of
384 %  "option.c" that is one of "SettingOptionFlags" option flags.
385 %
386 %  The format of the CLISettingOptionInfo method is:
387 %
388 %    void CLISettingOptionInfo(MagickCLI *cli_wand,
389 %               const char *option, const char *arg1, const char *arg2)
390 %
391 %  A description of each parameter follows:
392 %
393 %    o cli_wand: structure holding settings to be applied
394 %
395 %    o option: The option string to be set
396 %
397 %    o arg1, arg2: optional argument strings to the operation
398 %        arg2 is currently only used by "-limit"
399 %
400 */
401 WandPrivate void CLISettingOptionInfo(MagickCLI *cli_wand,
402      const char *option,const char *arg1n, const char *arg2n)
403 {
404   ssize_t
405     parse;     /* option argument parsing (string to value table lookup) */
406
407   const char    /* percent escaped versions of the args */
408     *arg1,
409     *arg2;
410
411 #define _image_info       (cli_wand->wand.image_info)
412 #define _image            (cli_wand->wand.images)
413 #define _exception        (cli_wand->wand.exception)
414 #define _draw_info        (cli_wand->draw_info)
415 #define _quantize_info    (cli_wand->quantize_info)
416 #define IfSetOption       (*option=='-')
417 #define ArgBoolean        IsMagickTrue(IfSetOption)
418 #define ArgBooleanNot     IsMagickFalse(IfSetOption)
419 #define ArgBooleanString  (IfSetOption?"true":"false")
420 #define ArgOption(def)    (IfSetOption?arg1:(const char *)(def))
421
422   assert(cli_wand != (MagickCLI *) NULL);
423   assert(cli_wand->signature == WandSignature);
424   assert(cli_wand->wand.signature == WandSignature);
425
426   if (IfMagickTrue(cli_wand->wand.debug))
427     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
428          "- Setting Option: %s \"%s\" \"%s\"", option,arg1n,arg2n);
429
430   arg1 = arg1n,
431   arg2 = arg2n;
432
433 #if 1
434 #define _process_flags    (cli_wand->process_flags)
435 #define _option_type      ((CommandOptionFlags) cli_wand->command->flags)
436   /* Interpret Percent Escapes in Arguments - using first image */
437   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
438         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
439        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
440     /* Interpret Percent escapes in argument 1 */
441     if (arg1n != (char *) NULL) {
442       arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
443       if (arg1 == (char *) NULL) {
444         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
445         arg1=arg1n;  /* use the given argument as is */
446       }
447     }
448     if (arg2n != (char *) NULL) {
449       arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
450       if (arg2 == (char *) NULL) {
451         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
452         arg2=arg2n;  /* use the given argument as is */
453       }
454     }
455   }
456 #undef _process_flags
457 #undef _option_type
458 #endif
459
460   switch (*(option+1))
461   {
462     case 'a':
463     {
464       if (LocaleCompare("adjoin",option+1) == 0)
465         {
466           _image_info->adjoin = ArgBoolean;
467           break;
468         }
469       if (LocaleCompare("affine",option+1) == 0)
470         {
471           CLIWandWarnReplaced("-draw 'affine ...'");
472           if (IfSetOption)
473             (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception);
474           else
475             GetAffineMatrix(&_draw_info->affine);
476           break;
477         }
478       if (LocaleCompare("antialias",option+1) == 0)
479         {
480           _image_info->antialias =
481             _draw_info->stroke_antialias =
482               _draw_info->text_antialias = ArgBoolean;
483           break;
484         }
485       if (LocaleCompare("attenuate",option+1) == 0)
486         {
487           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
488             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
489           (void) SetImageOption(_image_info,option+1,ArgOption("1.0"));
490           break;
491         }
492       if (LocaleCompare("authenticate",option+1) == 0)
493         {
494           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
495           break;
496         }
497       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
498     }
499     case 'b':
500     {
501       if (LocaleCompare("background",option+1) == 0)
502         {
503           /* FUTURE: both _image_info attribute & ImageOption in use!
504              _image_info only used directly for generating new images.
505              SyncImageSettings() used to set per-image attribute.
506
507              FUTURE: if _image_info->background_color is not set then
508              we should fall back to per-image background_color
509
510              At this time -background will 'wipe out' the per-image
511              background color!
512
513              Better error handling of QueryColorCompliance() needed.
514           */
515           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
516           (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance,
517              &_image_info->background_color,_exception);
518           break;
519         }
520       if (LocaleCompare("bias",option+1) == 0)
521         {
522           /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias"
523              as it is actually rarely used except in direct convolve operations
524              Usage outside a direct convolve operation is actally non-sensible!
525
526              SyncImageSettings() used to set per-image attribute.
527           */
528           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
529             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
530           (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL));
531           break;
532         }
533       if (LocaleCompare("black-point-compensation",option+1) == 0)
534         {
535           /* Used as a image chromaticity setting
536              SyncImageSettings() used to set per-image attribute.
537           */
538           (void) SetImageOption(_image_info,option+1,ArgBooleanString);
539           break;
540         }
541       if (LocaleCompare("blue-primary",option+1) == 0)
542         {
543           /* Image chromaticity X,Y  NB: Y=X if Y not defined
544              Used by many coders including PNG
545              SyncImageSettings() used to set per-image attribute.
546           */
547           arg1=ArgOption("0.0");
548           if (IfMagickFalse(IsGeometry(arg1)))
549             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
550           (void) SetImageOption(_image_info,option+1,arg1);
551           break;
552         }
553       if (LocaleCompare("bordercolor",option+1) == 0)
554         {
555           /* FUTURE: both _image_info attribute & ImageOption in use!
556              SyncImageSettings() used to set per-image attribute.
557              Better error checking of QueryColorCompliance().
558           */
559           if (IfSetOption)
560             {
561               (void) SetImageOption(_image_info,option+1,arg1);
562               (void) QueryColorCompliance(arg1,AllCompliance,
563                   &_image_info->border_color,_exception);
564               (void) QueryColorCompliance(arg1,AllCompliance,
565                   &_draw_info->border_color,_exception);
566               break;
567             }
568           (void) DeleteImageOption(_image_info,option+1);
569           (void) QueryColorCompliance(BorderColor,AllCompliance,
570             &_image_info->border_color,_exception);
571           (void) QueryColorCompliance(BorderColor,AllCompliance,
572             &_draw_info->border_color,_exception);
573           break;
574         }
575       if (LocaleCompare("box",option+1) == 0)
576         {
577           CLIWandWarnReplaced("-undercolor");
578           CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2);
579           break;
580         }
581       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
582     }
583     case 'c':
584     {
585       if (LocaleCompare("cache",option+1) == 0)
586         {
587           MagickSizeType
588             limit;
589
590           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
591             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
592           limit=MagickResourceInfinity;
593           if (LocaleCompare("unlimited",arg1) != 0)
594             limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0);
595           (void) SetMagickResourceLimit(MemoryResource,limit);
596           (void) SetMagickResourceLimit(MapResource,2*limit);
597           break;
598         }
599       if (LocaleCompare("caption",option+1) == 0)
600         {
601           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
602           break;
603         }
604       if (LocaleCompare("channel",option+1) == 0)
605         {
606           parse=ParseChannelOption(ArgOption("Default"));
607           if (parse < 0)
608             CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",
609                  option,arg1);
610           _image_info->channel=(ChannelType) parse;
611           (void) SetImageOption(_image_info,option+1,arg1);
612           break;
613         }
614       if (LocaleCompare("colorspace",option+1) == 0)
615         {
616           /* Setting used for new images via AquireImage()
617              But also used as a SimpleImageOperator
618              Undefined colorspace means don't modify images on
619              read or as a operation */
620           parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
621                         ArgOption("undefined"));
622           if (parse < 0)
623             CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
624                                     option,arg1);
625           _image_info->colorspace=(ColorspaceType) parse;
626           break;
627         }
628       if (LocaleCompare("comment",option+1) == 0)
629         {
630           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
631           break;
632         }
633       if (LocaleCompare("compose",option+1) == 0)
634         {
635           /* FUTURE: _image_info should be used,
636              SyncImageSettings() used to set per-image attribute. - REMOVE
637
638              This setting should NOT be used to set image 'compose'
639              "-layer" operators shoud use _image_info if defined otherwise
640              they should use a per-image compose setting.
641           */
642           parse = ParseCommandOption(MagickComposeOptions,MagickFalse,
643                           ArgOption("undefined"));
644           if (parse < 0)
645             CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator",
646                                       option,arg1);
647           _image_info->compose=(CompositeOperator) parse;
648           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
649           break;
650         }
651       if (LocaleCompare("compress",option+1) == 0)
652         {
653           /* FUTURE: What should be used?  _image_info  or ImageOption ???
654              The former is more efficent, but Crisy prefers the latter!
655              SyncImageSettings() used to set per-image attribute.
656
657              The coders appears to use _image_info, not Image_Option
658              however the image attribute (for save) is set from the
659              ImageOption!
660
661              Note that "undefined" is a different setting to "none".
662           */
663           parse = ParseCommandOption(MagickCompressOptions,MagickFalse,
664                      ArgOption("undefined"));
665           if (parse < 0)
666             CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression",
667                                       option,arg1);
668           _image_info->compression=(CompressionType) parse;
669           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
670           break;
671         }
672       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
673     }
674     case 'd':
675     {
676       if (LocaleCompare("debug",option+1) == 0)
677         {
678           /* SyncImageSettings() used to set per-image attribute. */
679           arg1=ArgOption("none");
680           parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1);
681           if (parse < 0)
682             CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType",
683                                       option,arg1);
684           (void) SetLogEventMask(arg1);
685           _image_info->debug=IsEventLogging();   /* extract logging*/
686           cli_wand->wand.debug=IsEventLogging();
687           break;
688         }
689       if (LocaleCompare("define",option+1) == 0)
690         {
691           if (LocaleNCompare(arg1,"registry:",9) == 0)
692             {
693               if (IfSetOption)
694                 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception);
695               else
696                 (void) DeleteImageRegistry(arg1+9);
697               break;
698             }
699           /* DefineImageOption() equals SetImageOption() but with '=' */
700           if (IfSetOption)
701             (void) DefineImageOption(_image_info,arg1);
702           else if (IsMagickFalse(DeleteImageOption(_image_info,arg1)))
703             CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1);
704           break;
705         }
706       if (LocaleCompare("delay",option+1) == 0)
707         {
708           /* Only used for new images via AcquireImage()
709              FUTURE: Option should also be used for "-morph" (color morphing)
710           */
711           arg1=ArgOption("0");
712           if (IfMagickFalse(IsGeometry(arg1)))
713             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
714           (void) SetImageOption(_image_info,option+1,arg1);
715           break;
716         }
717       if (LocaleCompare("density",option+1) == 0)
718         {
719           /* FUTURE: strings used in _image_info attr and _draw_info!
720              Basically as density can be in a XxY form!
721
722              SyncImageSettings() used to set per-image attribute.
723           */
724           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
725             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
726           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
727           (void) CloneString(&_image_info->density,ArgOption(NULL));
728           (void) CloneString(&_draw_info->density,_image_info->density);
729           break;
730         }
731       if (LocaleCompare("depth",option+1) == 0)
732         {
733           /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
734              SyncImageSettings() used to set per-image attribute.
735           */
736           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
737             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
738           _image_info->depth=IfSetOption?StringToUnsignedLong(arg1)
739                                        :MAGICKCORE_QUANTUM_DEPTH;
740           break;
741         }
742       if (LocaleCompare("direction",option+1) == 0)
743         {
744           /* Image Option is only used to set _draw_info */
745           arg1=ArgOption("undefined");
746           parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1);
747           if (parse < 0)
748             CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType",
749                                       option,arg1);
750           _draw_info->direction=(DirectionType) parse;
751           (void) SetImageOption(_image_info,option+1,arg1);
752           break;
753         }
754       if (LocaleCompare("display",option+1) == 0)
755         {
756           (void) CloneString(&_image_info->server_name,ArgOption(NULL));
757           (void) CloneString(&_draw_info->server_name,_image_info->server_name);
758           break;
759         }
760       if (LocaleCompare("dispose",option+1) == 0)
761         {
762           /* only used in setting new images */
763           arg1=ArgOption("undefined");
764           parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1);
765           if (parse < 0)
766             CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod",
767                                       option,arg1);
768           (void) SetImageOption(_image_info,option+1,ArgOption("undefined"));
769           break;
770         }
771       if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
772         {
773           /* FUTURE: this is only used by CompareImages() which is used
774              only by the "compare" CLI program at this time.  */
775           arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD);
776           if (IfMagickFalse(IsGeometry(arg1)))
777             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
778           (void) SetImageOption(_image_info,option+1,arg1);
779           break;
780         }
781       if (LocaleCompare("dither",option+1) == 0)
782         {
783           /* _image_info attr (on/off), _quantize_info attr (on/off)
784              but also ImageInfo and _quantize_info method!
785              FUTURE: merge the duality of the dithering options
786           */
787           _image_info->dither = ArgBoolean;
788           (void) SetImageOption(_image_info,option+1,ArgOption("none"));
789           _quantize_info->dither_method=(DitherMethod) ParseCommandOption(
790              MagickDitherOptions,MagickFalse,ArgOption("none"));
791           if (_quantize_info->dither_method == NoDitherMethod)
792             _image_info->dither = MagickFalse;
793           break;
794         }
795       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
796     }
797     case 'e':
798     {
799       if (LocaleCompare("encoding",option+1) == 0)
800         {
801           (void) CloneString(&_draw_info->encoding,ArgOption("undefined"));
802           (void) SetImageOption(_image_info,option+1,_draw_info->encoding);
803           break;
804         }
805       if (LocaleCompare("endian",option+1) == 0)
806         {
807           /* Both _image_info attr and ImageInfo */
808           arg1 = ArgOption("undefined");
809           parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1);
810           if (parse < 0)
811             CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType",
812                                       option,arg1);
813           /* FUTURE: check alloc/free of endian string!  - remove? */
814           _image_info->endian=(EndianType) (*arg1);
815           (void) SetImageOption(_image_info,option+1,arg1);
816           break;
817         }
818       if (LocaleCompare("extract",option+1) == 0)
819         {
820           (void) CloneString(&_image_info->extract,ArgOption(NULL));
821           break;
822         }
823       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
824     }
825     case 'f':
826     {
827       if (LocaleCompare("family",option+1) == 0)
828         {
829           (void) CloneString(&_draw_info->family,ArgOption(NULL));
830           break;
831         }
832       if (LocaleCompare("features",option+1) == 0)
833         {
834           (void) SetImageOption(_image_info,"identify:features",
835             ArgBooleanString);
836           if (IfSetOption)
837             (void) SetImageArtifact(_image,"verbose","true");
838           break;
839         }
840       if (LocaleCompare("fill",option+1) == 0)
841         {
842           /* Set "fill" OR "fill-pattern" in _draw_info
843              The original fill color is preserved if a fill-pattern is given.
844              That way it does not effect other operations that directly using
845              the fill color and, can be retored using "+tile".
846           */
847           MagickBooleanType
848             status;
849
850           ExceptionInfo
851             *sans;
852
853           PixelInfo
854             color;
855
856           arg1 = ArgOption("none");  /* +fill turns it off! */
857           (void) SetImageOption(_image_info,option+1,arg1);
858           if (_draw_info->fill_pattern != (Image *) NULL)
859             _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern);
860
861           /* is it a color or a image? -- ignore exceptions */
862           sans=AcquireExceptionInfo();
863           status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
864           sans=DestroyExceptionInfo(sans);
865
866           if (IfMagickFalse(status))
867             _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception);
868           else
869             _draw_info->fill=color;
870           break;
871         }
872       if (LocaleCompare("filter",option+1) == 0)
873         {
874           /* SyncImageSettings() used to set per-image attribute. */
875           arg1 = ArgOption("undefined");
876           parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1);
877           if (parse < 0)
878             CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter",
879                                       option,arg1);
880           (void) SetImageOption(_image_info,option+1,arg1);
881           break;
882         }
883       if (LocaleCompare("font",option+1) == 0)
884         {
885           (void) CloneString(&_draw_info->font,ArgOption(NULL));
886           (void) CloneString(&_image_info->font,_draw_info->font);
887           break;
888         }
889       if (LocaleCompare("format",option+1) == 0)
890         {
891           /* FUTURE: why the ping test, you could set ping after this! */
892           /*
893           register const char
894             *q;
895
896           for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
897             if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
898               _image_info->ping=MagickFalse;
899           */
900           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
901           break;
902         }
903       if (LocaleCompare("fuzz",option+1) == 0)
904         {
905           /* Option used to set image fuzz! unless blank canvas (from color)
906              Image attribute used for color compare operations
907              SyncImageSettings() used to set per-image attribute.
908
909              FUTURE: Can't find anything else using _image_info->fuzz directly!
910                      convert structure attribute to 'option' string
911           */
912           arg1=ArgOption("0");
913           if (IfMagickFalse(IsGeometry(arg1)))
914             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
915           _image_info->fuzz=StringToDoubleInterval(arg1,(double)
916                 QuantumRange+1.0);
917           (void) SetImageOption(_image_info,option+1,arg1);
918           break;
919         }
920       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
921     }
922     case 'g':
923     {
924       if (LocaleCompare("gravity",option+1) == 0)
925         {
926           /* SyncImageSettings() used to set per-image attribute. */
927           arg1 = ArgOption("none");
928           parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1);
929           if (parse < 0)
930             CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType",
931                                       option,arg1);
932           _draw_info->gravity=(GravityType) parse;
933           (void) SetImageOption(_image_info,option+1,arg1);
934           break;
935         }
936       if (LocaleCompare("green-primary",option+1) == 0)
937         {
938           /* Image chromaticity X,Y  NB: Y=X if Y not defined
939              SyncImageSettings() used to set per-image attribute.
940              Used directly by many coders
941           */
942           arg1=ArgOption("0.0");
943           if (IfMagickFalse(IsGeometry(arg1)))
944             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
945           (void) SetImageOption(_image_info,option+1,arg1);
946           break;
947         }
948       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
949     }
950     case 'h':
951     {
952       if (LocaleCompare("highlight-color",option+1) == 0)
953         {
954           /* FUTURE: this is only used by CompareImages() which is used
955              only by the "compare" CLI program at this time.  */
956           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
957           break;
958         }
959       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
960     }
961     case 'i':
962     {
963       if (LocaleCompare("intensity",option+1) == 0)
964         {
965           arg1 = ArgOption("undefined");
966           parse = ParseCommandOption(MagickPixelIntensityOptions,MagickFalse,
967             arg1);
968           if (parse < 0)
969             CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityType",
970               option,arg1);
971           (void) SetImageOption(_image_info,option+1,arg1);
972           break;
973         }
974       if (LocaleCompare("intent",option+1) == 0)
975         {
976           /* Only used by coders: MIFF, MPC, BMP, PNG
977              and for image profile call to AcquireTransformThreadSet()
978              SyncImageSettings() used to set per-image attribute.
979           */
980           arg1 = ArgOption("undefined");
981           parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1);
982           if (parse < 0)
983             CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType",
984                                       option,arg1);
985           (void) SetImageOption(_image_info,option+1,arg1);
986           break;
987         }
988       if (LocaleCompare("interlace",option+1) == 0)
989         {
990           /* _image_info is directly used by coders (so why an image setting?)
991              SyncImageSettings() used to set per-image attribute.
992           */
993           arg1 = ArgOption("undefined");
994           parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1);
995           if (parse < 0)
996             CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType",
997                                       option,arg1);
998           _image_info->interlace=(InterlaceType) parse;
999           (void) SetImageOption(_image_info,option+1,arg1);
1000           break;
1001         }
1002       if (LocaleCompare("interline-spacing",option+1) == 0)
1003         {
1004           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1005             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1006           (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1007           _draw_info->interline_spacing=StringToDouble(ArgOption("0"),
1008                (char **) NULL);
1009           break;
1010         }
1011       if (LocaleCompare("interpolate",option+1) == 0)
1012         {
1013           /* SyncImageSettings() used to set per-image attribute. */
1014           arg1 = ArgOption("undefined");
1015           parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1);
1016           if (parse < 0)
1017             CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod",
1018                                       option,arg1);
1019           (void) SetImageOption(_image_info,option+1,arg1);
1020           break;
1021         }
1022       if (LocaleCompare("interword-spacing",option+1) == 0)
1023         {
1024           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1025             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1026           (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1027           _draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
1028           break;
1029         }
1030       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1031     }
1032     case 'k':
1033     {
1034       if (LocaleCompare("kerning",option+1) == 0)
1035         {
1036           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1037             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1038           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1039           _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
1040           break;
1041         }
1042       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1043     }
1044     case 'l':
1045     {
1046       if (LocaleCompare("label",option+1) == 0)
1047         {
1048           /* only used for new images - not in SyncImageOptions() */
1049           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1050           break;
1051         }
1052       if (LocaleCompare("limit",option+1) == 0)
1053         {
1054           MagickSizeType
1055             limit;
1056
1057           limit=MagickResourceInfinity;
1058           parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1);
1059           if ( parse < 0 )
1060             CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType",
1061                 option,arg1);
1062           if (LocaleCompare("unlimited",arg2) != 0)
1063             limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
1064           (void) SetMagickResourceLimit((ResourceType)parse,limit);
1065           break;
1066         }
1067       if (LocaleCompare("log",option+1) == 0)
1068         {
1069           if (IfSetOption) {
1070             if ((strchr(arg1,'%') == (char *) NULL))
1071               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1072             (void) SetLogFormat(arg1);
1073           }
1074           break;
1075         }
1076       if (LocaleCompare("lowlight-color",option+1) == 0)
1077         {
1078           /* FUTURE: this is only used by CompareImages() which is used
1079              only by the "compare" CLI program at this time.  */
1080           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1081           break;
1082         }
1083       if (LocaleCompare("loop",option+1) == 0)
1084         {
1085           /* SyncImageSettings() used to set per-image attribute. */
1086           arg1=ArgOption("0");
1087           if (IfMagickFalse(IsGeometry(arg1)))
1088             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1089           (void) SetImageOption(_image_info,option+1,arg1);
1090           break;
1091         }
1092       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1093     }
1094     case 'm':
1095     {
1096       if (LocaleCompare("mattecolor",option+1) == 0)
1097         {
1098           /* SyncImageSettings() used to set per-image attribute. */
1099           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1100           (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance,
1101              &_image_info->matte_color,_exception);
1102           break;
1103         }
1104       if (LocaleCompare("metric",option+1) == 0)
1105         {
1106           /* FUTURE: this is only used by CompareImages() which is used
1107              only by the "compare" CLI program at this time.  */
1108           parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1);
1109           if ( parse < 0 )
1110             CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType",
1111                 option,arg1);
1112           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1113           break;
1114         }
1115       if (LocaleCompare("monitor",option+1) == 0)
1116         {
1117           (void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
1118                 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1119           break;
1120         }
1121       if (LocaleCompare("monochrome",option+1) == 0)
1122         {
1123           /* Setting (used by some input coders!) -- why?
1124              Warning: This is also Special '-type' SimpleOperator
1125           */
1126           _image_info->monochrome= ArgBoolean;
1127           break;
1128         }
1129       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1130     }
1131     case 'o':
1132     {
1133       if (LocaleCompare("orient",option+1) == 0)
1134         {
1135           /* Is not used when defining for new images.
1136              This makes it more of a 'operation' than a setting
1137              FUTURE: make set meta-data operator instead.
1138              SyncImageSettings() used to set per-image attribute.
1139           */
1140           parse=ParseCommandOption(MagickOrientationOptions,MagickFalse,
1141                ArgOption("undefined"));
1142           if (parse < 0)
1143             CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation",
1144                                       option,arg1);
1145           _image_info->orientation=(OrientationType)parse;
1146           (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1147           break;
1148         }
1149       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1150     }
1151     case 'p':
1152     {
1153       if (LocaleCompare("page",option+1) == 0)
1154         {
1155           /* Only used for new images and image generators.
1156              SyncImageSettings() used to set per-image attribute. ?????
1157              That last is WRONG!!!!
1158              FUTURE: adjust named 'page' sizes according density
1159           */
1160           char
1161             *canonical_page,
1162             page[MaxTextExtent];
1163
1164           const char
1165             *image_option;
1166
1167           MagickStatusType
1168             flags;
1169
1170           RectangleInfo
1171             geometry;
1172
1173           if (!IfSetOption)
1174             {
1175               (void) DeleteImageOption(_image_info,option+1);
1176               (void) CloneString(&_image_info->page,(char *) NULL);
1177               break;
1178             }
1179           (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1180           image_option=GetImageOption(_image_info,"page");
1181           if (image_option != (const char *) NULL)
1182             flags=ParseAbsoluteGeometry(image_option,&geometry);
1183           canonical_page=GetPageGeometry(arg1);
1184           flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1185           canonical_page=DestroyString(canonical_page);
1186           (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1187             (unsigned long) geometry.width,(unsigned long) geometry.height);
1188           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1189             (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1190               (unsigned long) geometry.width,(unsigned long) geometry.height,
1191               (long) geometry.x,(long) geometry.y);
1192           (void) SetImageOption(_image_info,option+1,page);
1193           (void) CloneString(&_image_info->page,page);
1194           break;
1195         }
1196       if (LocaleCompare("ping",option+1) == 0)
1197         {
1198           _image_info->ping = ArgBoolean;
1199           break;
1200         }
1201       if (LocaleCompare("pointsize",option+1) == 0)
1202         {
1203           if (IfSetOption) {
1204             if (IfMagickFalse(IsGeometry(arg1)))
1205               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1206             _image_info->pointsize =
1207             _draw_info->pointsize =
1208               StringToDouble(arg1,(char **) NULL);
1209           }
1210           else {
1211             _image_info->pointsize=0.0; /* unset pointsize */
1212             _draw_info->pointsize=12.0;
1213           }
1214           break;
1215         }
1216       if (LocaleCompare("precision",option+1) == 0)
1217         {
1218           arg1=ArgOption("-1");
1219           if (IfMagickFalse(IsGeometry(arg1)))
1220             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1221           (void) SetMagickPrecision(StringToInteger(arg1));
1222           break;
1223         }
1224       /* FUTURE: Only the 'preview' coder appears to use this
1225        * DEPRECIATE the coder?  Leaving only the 'preview' operator.
1226       if (LocaleCompare("preview",option+1) == 0)
1227         {
1228           _image_info->preview_type=UndefinedPreview;
1229           if (IfSetOption)
1230             _image_info->preview_type=(PreviewType) ParseCommandOption(
1231                 MagickPreviewOptions,MagickFalse,arg1);
1232           break;
1233         }
1234       */
1235       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1236     }
1237     case 'q':
1238     {
1239       if (LocaleCompare("quality",option+1) == 0)
1240         {
1241           if (IfMagickFalse(IsGeometry(arg1)))
1242             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1243           _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1)
1244                                             : UNDEFINED_COMPRESSION_QUALITY;
1245           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1246           break;
1247         }
1248       if (LocaleCompare("quantize",option+1) == 0)
1249         {
1250           /* Just a set direct in _quantize_info */
1251           arg1=ArgOption("undefined");
1252           parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
1253           if (parse < 0)
1254             CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
1255                  option,arg1);
1256           _quantize_info->colorspace=(ColorspaceType)parse;
1257           break;
1258         }
1259       if (LocaleCompare("quiet",option+1) == 0)
1260         {
1261           /* FUTURE: if two -quiet is performed you can not do +quiet!
1262              This needs to be checked over thoughly.
1263           */
1264           static WarningHandler
1265             warning_handler = (WarningHandler) NULL;
1266
1267           WarningHandler
1268             tmp = SetWarningHandler((WarningHandler) NULL);
1269
1270           if ( tmp != (WarningHandler) NULL)
1271             warning_handler = tmp; /* remember the old handler */
1272           if (!IfSetOption)        /* set the old handler */
1273             warning_handler=SetWarningHandler(warning_handler);
1274           break;
1275         }
1276       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1277     }
1278     case 'r':
1279     {
1280       if (LocaleCompare("red-primary",option+1) == 0)
1281         {
1282           /* Image chromaticity X,Y  NB: Y=X if Y not defined
1283              Used by many coders
1284              SyncImageSettings() used to set per-image attribute.
1285           */
1286           arg1=ArgOption("0.0");
1287           if (IfMagickFalse(IsGeometry(arg1)))
1288             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1289           (void) SetImageOption(_image_info,option+1,arg1);
1290           break;
1291         }
1292       if (LocaleCompare("regard-warnings",option+1) == 0)
1293         /* FUTURE: to be replaced by a 'fatal-level' type setting */
1294         break;
1295       if (LocaleCompare("render",option+1) == 0)
1296         {
1297           /* _draw_info only setting */
1298           _draw_info->render= ArgBooleanNot;
1299           break;
1300         }
1301       if (LocaleCompare("respect-parenthesis",option+1) == 0)
1302         {
1303           /* link image and setting stacks - option is itself saved on stack! */
1304           (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1305           break;
1306         }
1307       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1308     }
1309     case 's':
1310     {
1311       if (LocaleCompare("sampling-factor",option+1) == 0)
1312         {
1313           /* FUTURE: should be converted to jpeg:sampling_factor */
1314           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1315             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1316           (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1317           break;
1318         }
1319       if (LocaleCompare("scene",option+1) == 0)
1320         {
1321           /* SyncImageSettings() used to set this as a per-image attribute.
1322              What ??? Why ????
1323           */
1324           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1325             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1326           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1327           _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1328           break;
1329         }
1330       if (LocaleCompare("seed",option+1) == 0)
1331         {
1332           if (IfMagickFalse(IsGeometry(arg1)))
1333             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1334           SetRandomSecretKey(
1335                IfSetOption ? (unsigned long) StringToUnsignedLong(arg1)
1336                            : (unsigned long) time((time_t *) NULL) );
1337           break;
1338         }
1339       if (LocaleCompare("size",option+1) == 0)
1340         {
1341           /* FUTURE: string in _image_info -- convert to Option ???
1342              Look at the special handling for "size" in SetImageOption()
1343            */
1344           (void) CloneString(&_image_info->size,ArgOption(NULL));
1345           break;
1346         }
1347       if (LocaleCompare("stretch",option+1) == 0)
1348         {
1349           arg1=ArgOption("undefined");
1350           parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1351           if (parse < 0)
1352             CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1353                  option,arg1);
1354           _draw_info->stretch=(StretchType) parse;
1355           break;
1356         }
1357       if (LocaleCompare("stroke",option+1) == 0)
1358         {
1359           /* set stroke color OR stroke-pattern
1360              UPDATE: ensure stroke color is not destroyed is a pattern
1361              is given. Just in case the color is also used for other purposes.
1362            */
1363           MagickBooleanType
1364             status;
1365
1366           ExceptionInfo
1367             *sans;
1368
1369           PixelInfo
1370             color;
1371
1372           arg1 = ArgOption("none");  /* +fill turns it off! */
1373           (void) SetImageOption(_image_info,option+1,arg1);
1374           if (_draw_info->stroke_pattern != (Image *) NULL)
1375             _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1376
1377           /* is it a color or a image? -- ignore exceptions */
1378           sans=AcquireExceptionInfo();
1379           status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1380           sans=DestroyExceptionInfo(sans);
1381
1382           if (IfMagickFalse(status))
1383             _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1384           else
1385             _draw_info->stroke=color;
1386           break;
1387         }
1388       if (LocaleCompare("strokewidth",option+1) == 0)
1389         {
1390           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1391             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1392           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1393           _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1394                (char **) NULL);
1395           break;
1396         }
1397       if (LocaleCompare("style",option+1) == 0)
1398         {
1399           arg1=ArgOption("undefined");
1400           parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1401           if (parse < 0)
1402             CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1403                  option,arg1);
1404           _draw_info->style=(StyleType) parse;
1405           break;
1406         }
1407 #if 0
1408       if (LocaleCompare("subimage-search",option+1) == 0)
1409         {
1410         /* FUTURE: this is only used by CompareImages() which is used
1411             only by the "compare" CLI program at this time.  */
1412           (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1413           break;
1414         }
1415 #endif
1416       if (LocaleCompare("synchronize",option+1) == 0)
1417         {
1418           /* FUTURE: syncronize to storage - but what does that mean? */
1419           _image_info->synchronize = ArgBoolean;
1420           break;
1421         }
1422       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1423     }
1424     case 't':
1425     {
1426       if (LocaleCompare("taint",option+1) == 0)
1427         {
1428           /* SyncImageSettings() used to set per-image attribute. */
1429           (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1430           break;
1431         }
1432       if (LocaleCompare("texture",option+1) == 0)
1433         {
1434           /* Note: arguments do not have percent escapes expanded */
1435           /* FUTURE: move _image_info string to option splay-tree
1436              Other than "montage" what uses "texture" ????
1437           */
1438           (void) CloneString(&_image_info->texture,ArgOption(NULL));
1439           break;
1440         }
1441       if (LocaleCompare("tile",option+1) == 0)
1442         {
1443           /* Note: arguments do not have percent escapes expanded */
1444           _draw_info->fill_pattern=IfSetOption
1445                                  ?GetImageCache(_image_info,arg1,_exception)
1446                                  :DestroyImage(_draw_info->fill_pattern);
1447           break;
1448         }
1449       if (LocaleCompare("tile-offset",option+1) == 0)
1450         {
1451           /* SyncImageSettings() used to set per-image attribute. ??? */
1452           arg1=ArgOption("0");
1453           if (IfMagickFalse(IsGeometry(arg1)))
1454             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1455           (void) SetImageOption(_image_info,option+1,arg1);
1456           break;
1457         }
1458       if (LocaleCompare("transparent-color",option+1) == 0)
1459         {
1460           /* FUTURE: both _image_info attribute & ImageOption in use!
1461              _image_info only used for generating new images.
1462              SyncImageSettings() used to set per-image attribute.
1463
1464              Note that +transparent-color, means fall-back to image
1465              attribute so ImageOption is deleted, not set to a default.
1466           */
1467           if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1468             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1469           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1470           (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1471               &_image_info->transparent_color,_exception);
1472           break;
1473         }
1474       if (LocaleCompare("treedepth",option+1) == 0)
1475         {
1476           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1477           _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1478           break;
1479         }
1480       if (LocaleCompare("type",option+1) == 0)
1481         {
1482           /* SyncImageSettings() used to set per-image attribute. */
1483           parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1484                ArgOption("undefined"));
1485           if (parse < 0)
1486             CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1487                  option,arg1);
1488           _image_info->type=(ImageType) parse;
1489           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1490           break;
1491         }
1492       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1493     }
1494     case 'u':
1495     {
1496       if (LocaleCompare("undercolor",option+1) == 0)
1497         {
1498           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1499           (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1500                &_draw_info->undercolor,_exception);
1501           break;
1502         }
1503       if (LocaleCompare("units",option+1) == 0)
1504         {
1505           /* SyncImageSettings() used to set per-image attribute.
1506              Should this effect _draw_info X and Y resolution?
1507              FUTURE: this probably should be part of the density setting
1508           */
1509           parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1510                ArgOption("undefined"));
1511           if (parse < 0)
1512             CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1513                  option,arg1);
1514           _image_info->units=(ResolutionType) parse;
1515           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1516           break;
1517         }
1518       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1519     }
1520     case 'v':
1521     {
1522       if (LocaleCompare("verbose",option+1) == 0)
1523         {
1524           /* FUTURE: Remember all options become image artifacts
1525              _image_info->verbose is only used by coders.
1526           */
1527           (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1528           _image_info->verbose= ArgBoolean;
1529           _image_info->ping=MagickFalse; /* verbose can't be a ping */
1530           break;
1531         }
1532       if (LocaleCompare("view",option+1) == 0)
1533         {
1534           /* FUTURE: Convert from _image_info to ImageOption
1535              Only used by coder FPX
1536              And it only tests existance, not its content!
1537           */
1538           (void) CloneString(&_image_info->view,ArgOption(NULL));
1539           break;
1540         }
1541       if (LocaleCompare("virtual-pixel",option+1) == 0)
1542         {
1543           /* SyncImageSettings() used to set per-image attribute.
1544              This is VERY deep in the image caching structure.
1545           */
1546           parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1547                ArgOption("undefined"));
1548           if (parse < 0)
1549             CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1550                  option,arg1);
1551           (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1552           break;
1553         }
1554       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1555     }
1556     case 'w':
1557     {
1558       if (LocaleCompare("weight",option+1) == 0)
1559         {
1560           /* Just what does using a font 'weight' do ???
1561              There is no "-list weight" output (reference manual says there is)
1562           */
1563           arg1=ArgOption("all");
1564           _draw_info->weight=StringToUnsignedLong(arg1);
1565           if (LocaleCompare(arg1,"all") == 0)
1566             _draw_info->weight=0;
1567           if (LocaleCompare(arg1,"bold") == 0)
1568             _draw_info->weight=700;
1569           if (LocaleCompare(arg1,"bolder") == 0)
1570             if (_draw_info->weight <= 800)
1571               _draw_info->weight+=100;
1572           if (LocaleCompare(arg1,"lighter") == 0)
1573             if (_draw_info->weight >= 100)
1574               _draw_info->weight-=100;
1575           if (LocaleCompare(arg1,"normal") == 0)
1576             _draw_info->weight=400;
1577           break;
1578         }
1579       if (LocaleCompare("white-point",option+1) == 0)
1580         {
1581           /* Used as a image chromaticity setting
1582              SyncImageSettings() used to set per-image attribute.
1583           */
1584           arg1=ArgOption("0.0");
1585           if (IfMagickFalse(IsGeometry(arg1)))
1586             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1587           (void) SetImageOption(_image_info,option+1,arg1);
1588           break;
1589         }
1590       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1591     }
1592     default:
1593       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1594   }
1595
1596   /* clean up percent escape interpreted strings */
1597   if (arg1 != arg1n )
1598     arg1=DestroyString((char *)arg1);
1599   if (arg2 != arg2n )
1600     arg2=DestroyString((char *)arg2);
1601
1602 #undef _image_info
1603 #undef _exception
1604 #undef _draw_info
1605 #undef _quantize_info
1606 #undef IfSetOption
1607 #undef ArgBoolean
1608 #undef ArgBooleanNot
1609 #undef ArgBooleanString
1610 #undef ArgOption
1611
1612   return;
1613 }
1614 \f
1615 /*
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 %                                                                             %
1618 %                                                                             %
1619 %                                                                             %
1620 +     C L I S i m p l e O p e r a t o r I m a g e s                           %
1621 %                                                                             %
1622 %                                                                             %
1623 %                                                                             %
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 %
1626 %  CLISimpleOperatorImages() applys one simple image operation given to all
1627 %  the images in the CLI wand, using any per-image or global settings that was
1628 %  previously saved in the CLI wand.
1629 %
1630 %  It is assumed that any such settings are up-to-date.
1631 %
1632 %  The format of the WandSimpleOperatorImages method is:
1633 %
1634 %    void CLISimpleOperatorImages(MagickCLI *cli_wand,
1635 %        const char *option, const char *arg1, const char *arg2)
1636 %
1637 %  A description of each parameter follows:
1638 %
1639 %    o cli_wand: structure holding settings and images to be operated on
1640 %
1641 %    o option:  The option string for the operation
1642 %
1643 %    o arg1, arg2: optional argument strings to the operation
1644 %
1645 */
1646
1647 /*
1648   CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1649   image operation to the current image pointed to by the CLI wand.
1650
1651   The image in the list may be modified in three different ways...
1652     * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1653     * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1654     * one image replace by a list of images (-separate and -crop only!)
1655
1656   In each case the result replaces the single original image in the list, as
1657   well as the pointer to the modified image (last image added if replaced by a
1658   list of images) is returned.
1659
1660   As the image pointed to may be replaced, the first image in the list may
1661   also change.  GetFirstImageInList() should be used by caller if they wish
1662   return the Image pointer to the first image in list.
1663 */
1664 static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand,
1665   const char *option, const char *arg1n, const char *arg2n)
1666 {
1667   Image *
1668     new_image;
1669
1670   GeometryInfo
1671     geometry_info;
1672
1673   RectangleInfo
1674     geometry;
1675
1676   MagickStatusType
1677     flags;
1678
1679   ssize_t
1680     parse;
1681
1682   const char    /* percent escaped versions of the args */
1683     *arg1,
1684     *arg2;
1685
1686 #define _image_info       (cli_wand->wand.image_info)
1687 #define _image            (cli_wand->wand.images)
1688 #define _exception        (cli_wand->wand.exception)
1689 #define _draw_info        (cli_wand->draw_info)
1690 #define _quantize_info    (cli_wand->quantize_info)
1691 #define _process_flags    (cli_wand->process_flags)
1692 #define _option_type      ((CommandOptionFlags) cli_wand->command->flags)
1693 #define IfNormalOp        (*option=='-')
1694 #define IfPlusOp          (*option!='-')
1695 #define IsNormalOp        IsMagickTrue(IfNormalOp)
1696 #define IsPlusOp          IsMagickFalse(IfNormalOp)
1697
1698   assert(cli_wand != (MagickCLI *) NULL);
1699   assert(cli_wand->signature == WandSignature);
1700   assert(cli_wand->wand.signature == WandSignature);
1701   assert(_image != (Image *) NULL);             /* an image must be present */
1702   if (IfMagickTrue(cli_wand->wand.debug))
1703     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1704
1705   arg1 = arg1n,
1706   arg2 = arg2n;
1707
1708   /* Interpret Percent Escapes in Arguments - using first image */
1709   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
1710         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1711        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1712     /* Interpret Percent escapes in argument 1 */
1713     if (arg1n != (char *) NULL) {
1714       arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1715       if (arg1 == (char *) NULL) {
1716         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1717         arg1=arg1n;  /* use the given argument as is */
1718       }
1719     }
1720     if (arg2n != (char *) NULL) {
1721       arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1722       if (arg2 == (char *) NULL) {
1723         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1724         arg2=arg2n;  /* use the given argument as is */
1725       }
1726     }
1727   }
1728 #undef _process_flags
1729 #undef _option_type
1730
1731 #if 0
1732   (void) FormatLocaleFile(stderr,
1733     "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1734 #endif
1735
1736   new_image = (Image *)NULL; /* the replacement image, if not null at end */
1737   SetGeometryInfo(&geometry_info);
1738
1739   switch (*(option+1))
1740   {
1741     case 'a':
1742     {
1743       if (LocaleCompare("adaptive-blur",option+1) == 0)
1744         {
1745           flags=ParseGeometry(arg1,&geometry_info);
1746           if ((flags & (RhoValue|SigmaValue)) == 0)
1747             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1748           if ((flags & SigmaValue) == 0)
1749             geometry_info.sigma=1.0;
1750           new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1751             geometry_info.sigma,_exception);
1752           break;
1753         }
1754       if (LocaleCompare("adaptive-resize",option+1) == 0)
1755         {
1756           /* FUTURE: Roll into a resize special operator */
1757           if (IfMagickFalse(IsGeometry(arg1)))
1758             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1759           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1760           new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1761             _exception);
1762           break;
1763         }
1764       if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1765         {
1766           flags=ParseGeometry(arg1,&geometry_info);
1767           if ((flags & (RhoValue|SigmaValue)) == 0)
1768             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1769           if ((flags & SigmaValue) == 0)
1770             geometry_info.sigma=1.0;
1771           new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1772             geometry_info.sigma,_exception);
1773           break;
1774         }
1775       if (LocaleCompare("alpha",option+1) == 0)
1776         {
1777           parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1778           if (parse < 0)
1779             CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1780                  option,arg1);
1781           (void) SetImageAlphaChannel(_image,(AlphaChannelOption)parse,
1782                _exception);
1783           break;
1784         }
1785       if (LocaleCompare("annotate",option+1) == 0)
1786         {
1787           char
1788             geometry[MaxTextExtent];
1789
1790           SetGeometryInfo(&geometry_info);
1791           flags=ParseGeometry(arg1,&geometry_info);
1792           if (flags == 0)
1793             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1794           if ((flags & SigmaValue) == 0)
1795             geometry_info.sigma=geometry_info.rho;
1796           (void) CloneString(&_draw_info->text,arg2);
1797           (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1798             geometry_info.xi,geometry_info.psi);
1799           (void) CloneString(&_draw_info->geometry,geometry);
1800           _draw_info->affine.sx=cos(DegreesToRadians(
1801             fmod(geometry_info.rho,360.0)));
1802           _draw_info->affine.rx=sin(DegreesToRadians(
1803             fmod(geometry_info.rho,360.0)));
1804           _draw_info->affine.ry=(-sin(DegreesToRadians(
1805             fmod(geometry_info.sigma,360.0))));
1806           _draw_info->affine.sy=cos(DegreesToRadians(
1807             fmod(geometry_info.sigma,360.0)));
1808           (void) AnnotateImage(_image,_draw_info,_exception);
1809           GetAffineMatrix(&_draw_info->affine);
1810           break;
1811         }
1812       if (LocaleCompare("auto-gamma",option+1) == 0)
1813         {
1814           (void) AutoGammaImage(_image,_exception);
1815           break;
1816         }
1817       if (LocaleCompare("auto-level",option+1) == 0)
1818         {
1819           (void) AutoLevelImage(_image,_exception);
1820           break;
1821         }
1822       if (LocaleCompare("auto-orient",option+1) == 0)
1823         {
1824           new_image=AutoOrientImage(_image,_image->orientation,_exception);
1825           break;
1826         }
1827       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1828     }
1829     case 'b':
1830     {
1831       if (LocaleCompare("black-threshold",option+1) == 0)
1832         {
1833           if (IfMagickFalse(IsGeometry(arg1)))
1834             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1835           (void) BlackThresholdImage(_image,arg1,_exception);
1836           break;
1837         }
1838       if (LocaleCompare("blue-shift",option+1) == 0)
1839         {
1840           geometry_info.rho=1.5;
1841           if (IfNormalOp) {
1842             flags=ParseGeometry(arg1,&geometry_info);
1843             if ((flags & RhoValue) == 0)
1844               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1845           }
1846           new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1847           break;
1848         }
1849       if (LocaleCompare("blur",option+1) == 0)
1850         {
1851           flags=ParseGeometry(arg1,&geometry_info);
1852           if ((flags & (RhoValue|SigmaValue)) == 0)
1853             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1854           if ((flags & SigmaValue) == 0)
1855             geometry_info.sigma=1.0;
1856           new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1857            _exception);
1858           break;
1859         }
1860       if (LocaleCompare("border",option+1) == 0)
1861         {
1862           CompositeOperator
1863             compose;
1864
1865           const char*
1866             value;
1867
1868           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1869           if ((flags & (WidthValue | HeightValue)) == 0)
1870             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1871           compose=OverCompositeOp;
1872           value=GetImageOption(_image_info,"compose");
1873           if (value != (const char *) NULL)
1874             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1875               MagickFalse,value);
1876           new_image=BorderImage(_image,&geometry,compose,_exception);
1877           break;
1878         }
1879       if (LocaleCompare("brightness-contrast",option+1) == 0)
1880         {
1881           double
1882             brightness,
1883             contrast;
1884
1885           GeometryInfo
1886             geometry_info;
1887
1888           MagickStatusType
1889             flags;
1890
1891           flags=ParseGeometry(arg1,&geometry_info);
1892           if ((flags & RhoValue) == 0)
1893             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1894           brightness=geometry_info.rho;
1895           contrast=0.0;
1896           if ((flags & SigmaValue) != 0)
1897             contrast=geometry_info.sigma;
1898           (void) BrightnessContrastImage(_image,brightness,contrast,
1899             _exception);
1900           break;
1901         }
1902       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1903     }
1904     case 'c':
1905     {
1906       if (LocaleCompare("cdl",option+1) == 0)
1907         {
1908           /* Note: arguments do not have percent escapes expanded */
1909           char
1910             *color_correction_collection;
1911
1912           /*
1913             Color correct with a color decision list.
1914           */
1915           color_correction_collection=FileToString(arg1,~0,_exception);
1916           if (color_correction_collection == (char *) NULL)
1917             break;
1918           (void) ColorDecisionListImage(_image,color_correction_collection,
1919             _exception);
1920           break;
1921         }
1922       if (LocaleCompare("charcoal",option+1) == 0)
1923         {
1924           flags=ParseGeometry(arg1,&geometry_info);
1925           if ((flags & (RhoValue|SigmaValue)) == 0)
1926             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1927           if ((flags & SigmaValue) == 0)
1928             geometry_info.sigma=1.0;
1929           if ((flags & XiValue) == 0)
1930             geometry_info.xi=1.0;
1931           new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1932             _exception);
1933           break;
1934         }
1935       if (LocaleCompare("chop",option+1) == 0)
1936         {
1937           if (IfMagickFalse(IsGeometry(arg1)))
1938             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1939           (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
1940           new_image=ChopImage(_image,&geometry,_exception);
1941           break;
1942         }
1943       if (LocaleCompare("clamp",option+1) == 0)
1944         {
1945           (void) ClampImage(_image,_exception);
1946           break;
1947         }
1948       if (LocaleCompare("clip",option+1) == 0)
1949         {
1950           if (IfNormalOp)
1951             (void) ClipImage(_image,_exception);
1952           else /* "+mask" remove the write mask */
1953             (void) SetImageMask(_image,(Image *) NULL,_exception);
1954           break;
1955         }
1956       if (LocaleCompare("clip-mask",option+1) == 0)
1957         {
1958           /* Note: arguments do not have percent escapes expanded */
1959           CacheView
1960             *mask_view;
1961
1962           Image
1963             *mask_image;
1964
1965           register Quantum
1966             *restrict q;
1967
1968           register ssize_t
1969             x;
1970
1971           ssize_t
1972             y;
1973
1974           if (IfPlusOp) {
1975             /* use "+clip-mask" Remove the write mask for -clip-path */
1976             (void) SetImageMask(_image,(Image *) NULL,_exception);
1977             break;
1978           }
1979           mask_image=GetImageCache(_image_info,arg1,_exception);
1980           if (mask_image == (Image *) NULL)
1981             break;
1982           if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
1983             break;
1984           /* Create a write mask from cli_wand mask image */
1985           /* FUTURE: use Alpha operations instead and create a Grey Image */
1986           mask_view=AcquireAuthenticCacheView(mask_image,_exception);
1987           for (y=0; y < (ssize_t) mask_image->rows; y++)
1988           {
1989             q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1990               _exception);
1991             if (q == (Quantum *) NULL)
1992               break;
1993             for (x=0; x < (ssize_t) mask_image->columns; x++)
1994             {
1995               if (mask_image->alpha_trait != BlendPixelTrait)
1996                 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
1997               SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
1998               q+=GetPixelChannels(mask_image);
1999             }
2000             if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2001               break;
2002           }
2003           /* clean up and set the write mask */
2004           mask_view=DestroyCacheView(mask_view);
2005           mask_image->alpha_trait=BlendPixelTrait;
2006           (void) SetImageColorspace(_image,GRAYColorspace,_exception);
2007           (void) SetImageMask(_image,mask_image,_exception);
2008           mask_image=DestroyImage(mask_image);
2009           break;
2010         }
2011       if (LocaleCompare("clip-path",option+1) == 0)
2012         {
2013           (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2014           /* Note: Use "+clip-mask" remove the write mask added */
2015           break;
2016         }
2017       if (LocaleCompare("colorize",option+1) == 0)
2018         {
2019           if (IfMagickFalse(IsGeometry(arg1)))
2020             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2021           new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2022           break;
2023         }
2024       if (LocaleCompare("color-matrix",option+1) == 0)
2025         {
2026           KernelInfo
2027             *kernel;
2028
2029           kernel=AcquireKernelInfo(arg1);
2030           if (kernel == (KernelInfo *) NULL)
2031             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2032           new_image=ColorMatrixImage(_image,kernel,_exception);
2033           kernel=DestroyKernelInfo(kernel);
2034           break;
2035         }
2036       if (LocaleCompare("colors",option+1) == 0)
2037         {
2038           /* Reduce the number of colors in the image.
2039              FUTURE: also provide 'plus version with image 'color counts'
2040           */
2041           _quantize_info->number_colors=StringToUnsignedLong(arg1);
2042           if (_quantize_info->number_colors == 0)
2043             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2044           if ((_image->storage_class == DirectClass) ||
2045               _image->colors > _quantize_info->number_colors)
2046             (void) QuantizeImage(_quantize_info,_image,_exception);
2047           else
2048             (void) CompressImageColormap(_image,_exception);
2049           break;
2050         }
2051       if (LocaleCompare("colorspace",option+1) == 0)
2052         {
2053           /* WARNING: this is both a image_info setting (already done)
2054                       and a operator to change image colorspace.
2055
2056              FUTURE: default colorspace should be sRGB!
2057              Unless some type of 'linear colorspace' mode is set.
2058
2059              Note that +colorspace sets "undefined" or no effect on
2060              new images, but forces images already in memory back to RGB!
2061              That seems to be a little strange!
2062           */
2063           (void) TransformImageColorspace(_image,
2064                     IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2065                     _exception);
2066           break;
2067         }
2068       if (LocaleCompare("contrast",option+1) == 0)
2069         {
2070           CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2071           (void) ContrastImage(_image,IsNormalOp,_exception);
2072           break;
2073         }
2074       if (LocaleCompare("contrast-stretch",option+1) == 0)
2075         {
2076           double
2077             black_point,
2078             white_point;
2079
2080           MagickStatusType
2081             flags;
2082
2083           flags=ParseGeometry(arg1,&geometry_info);
2084           if ((flags & RhoValue) == 0)
2085             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2086           black_point=geometry_info.rho;
2087           white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2088             black_point;
2089           if ((flags & PercentValue) != 0) {
2090               black_point*=(double) _image->columns*_image->rows/100.0;
2091               white_point*=(double) _image->columns*_image->rows/100.0;
2092             }
2093           white_point=(double) _image->columns*_image->rows-
2094             white_point;
2095           (void) ContrastStretchImage(_image,black_point,white_point,
2096             _exception);
2097           break;
2098         }
2099       if (LocaleCompare("convolve",option+1) == 0)
2100         {
2101           KernelInfo
2102             *kernel_info;
2103
2104           kernel_info=AcquireKernelInfo(arg1);
2105           if (kernel_info == (KernelInfo *) NULL)
2106             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2107           new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2108             _exception);
2109           kernel_info=DestroyKernelInfo(kernel_info);
2110           break;
2111         }
2112       if (LocaleCompare("crop",option+1) == 0)
2113         {
2114           /* WARNING: This can generate multiple images! */
2115           if (IfMagickFalse(IsGeometry(arg1)))
2116             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2117           new_image=CropImageToTiles(_image,arg1,_exception);
2118           break;
2119         }
2120       if (LocaleCompare("cycle",option+1) == 0)
2121         {
2122           if (IfMagickFalse(IsGeometry(arg1)))
2123             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2124           (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2125             _exception);
2126           break;
2127         }
2128       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2129     }
2130     case 'd':
2131     {
2132       if (LocaleCompare("decipher",option+1) == 0)
2133         {
2134           /* Note: arguments do not have percent escapes expanded */
2135           StringInfo
2136             *passkey;
2137
2138           passkey=FileToStringInfo(arg1,~0,_exception);
2139           if (passkey == (StringInfo *) NULL)
2140             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2141
2142           (void) PasskeyDecipherImage(_image,passkey,_exception);
2143           passkey=DestroyStringInfo(passkey);
2144           break;
2145         }
2146       if (LocaleCompare("depth",option+1) == 0)
2147         {
2148           /* The _image_info->depth setting has already been set
2149              We just need to apply it to all images in current sequence
2150
2151              WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2152              That is it really is an operation, not a setting! Arrgghhh
2153
2154              FUTURE: this should not be an operator!!!
2155           */
2156           (void) SetImageDepth(_image,_image_info->depth,_exception);
2157           break;
2158         }
2159       if (LocaleCompare("deskew",option+1) == 0)
2160         {
2161           double
2162             threshold;
2163
2164           if (IfNormalOp) {
2165             if (IfMagickFalse(IsGeometry(arg1)))
2166               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2167             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2168           }
2169           else
2170             threshold=40.0*QuantumRange/100.0;
2171           new_image=DeskewImage(_image,threshold,_exception);
2172           break;
2173         }
2174       if (LocaleCompare("despeckle",option+1) == 0)
2175         {
2176           new_image=DespeckleImage(_image,_exception);
2177           break;
2178         }
2179       if (LocaleCompare("distort",option+1) == 0)
2180         {
2181           double
2182             *args;
2183
2184           ssize_t
2185             count;
2186
2187           parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2188           if ( parse < 0 )
2189              CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2190                                       option,arg1);
2191           if ((DistortImageMethod) parse == ResizeDistortion)
2192             {
2193                double
2194                  resize_args[2];
2195                /* Special Case - Argument is actually a resize geometry!
2196                ** Convert that to an appropriate distortion argument array.
2197                ** FUTURE: make a separate special resize operator
2198                     Roll into a resize special operator */
2199                if (IfMagickFalse(IsGeometry(arg2)))
2200                  CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2201                                            option,arg2);
2202                (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2203                resize_args[0]=(double) geometry.width;
2204                resize_args[1]=(double) geometry.height;
2205                new_image=DistortImage(_image,(DistortImageMethod) parse,
2206                     (size_t)2,resize_args,MagickTrue,_exception);
2207                break;
2208             }
2209           /* convert argument string into an array of doubles */
2210           args = StringToArrayOfDoubles(arg2,&count,_exception);
2211           if (args == (double *)NULL )
2212             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2213
2214           new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2215                IsPlusOp,_exception);
2216           args=(double *) RelinquishMagickMemory(args);
2217           break;
2218         }
2219       if (LocaleCompare("draw",option+1) == 0)
2220         {
2221           (void) CloneString(&_draw_info->primitive,arg1);
2222           (void) DrawImage(_image,_draw_info,_exception);
2223           (void) CloneString(&_draw_info->primitive,(char *)NULL);
2224           break;
2225         }
2226       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2227     }
2228     case 'e':
2229     {
2230       if (LocaleCompare("edge",option+1) == 0)
2231         {
2232           flags=ParseGeometry(arg1,&geometry_info);
2233           if ((flags & (RhoValue|SigmaValue)) == 0)
2234             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2235           new_image=EdgeImage(_image,geometry_info.rho,_exception);
2236           break;
2237         }
2238       if (LocaleCompare("emboss",option+1) == 0)
2239         {
2240           flags=ParseGeometry(arg1,&geometry_info);
2241           if ((flags & (RhoValue|SigmaValue)) == 0)
2242             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2243           if ((flags & SigmaValue) == 0)
2244             geometry_info.sigma=1.0;
2245           new_image=EmbossImage(_image,geometry_info.rho,
2246             geometry_info.sigma,_exception);
2247           break;
2248         }
2249       if (LocaleCompare("encipher",option+1) == 0)
2250         {
2251           /* Note: arguments do not have percent escapes expanded */
2252           StringInfo
2253             *passkey;
2254
2255           passkey=FileToStringInfo(arg1,~0,_exception);
2256           if (passkey != (StringInfo *) NULL)
2257             {
2258               (void) PasskeyEncipherImage(_image,passkey,_exception);
2259               passkey=DestroyStringInfo(passkey);
2260             }
2261           break;
2262         }
2263       if (LocaleCompare("enhance",option+1) == 0)
2264         {
2265           new_image=EnhanceImage(_image,_exception);
2266           break;
2267         }
2268       if (LocaleCompare("equalize",option+1) == 0)
2269         {
2270           (void) EqualizeImage(_image,_exception);
2271           break;
2272         }
2273       if (LocaleCompare("evaluate",option+1) == 0)
2274         {
2275           double
2276             constant;
2277
2278           parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2279           if ( parse < 0 )
2280             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2281                  option,arg1);
2282           if (IfMagickFalse(IsGeometry(arg2)))
2283             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2284           constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2285           (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2286                _exception);
2287           break;
2288         }
2289       if (LocaleCompare("extent",option+1) == 0)
2290         {
2291           if (IfMagickFalse(IsGeometry(arg1)))
2292             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2293           flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2294           if (geometry.width == 0)
2295             geometry.width=_image->columns;
2296           if (geometry.height == 0)
2297             geometry.height=_image->rows;
2298           new_image=ExtentImage(_image,&geometry,_exception);
2299           break;
2300         }
2301       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2302     }
2303     case 'f':
2304     {
2305       if (LocaleCompare("flip",option+1) == 0)
2306         {
2307           new_image=FlipImage(_image,_exception);
2308           break;
2309         }
2310       if (LocaleCompare("flop",option+1) == 0)
2311         {
2312           new_image=FlopImage(_image,_exception);
2313           break;
2314         }
2315       if (LocaleCompare("floodfill",option+1) == 0)
2316         {
2317           PixelInfo
2318             target;
2319
2320           if (IfMagickFalse(IsGeometry(arg1)))
2321             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2322           (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2323           (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2324           (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2325             geometry.y,IsPlusOp,_exception);
2326           break;
2327         }
2328       if (LocaleCompare("frame",option+1) == 0)
2329         {
2330           FrameInfo
2331             frame_info;
2332
2333           CompositeOperator
2334             compose;
2335
2336           const char*
2337             value;
2338
2339           value=GetImageOption(_image_info,"compose");
2340             compose=OverCompositeOp;  /* use Over not _image->compose */
2341           if (value != (const char *) NULL)
2342             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2343               MagickFalse,value);
2344           if (IfMagickFalse(IsGeometry(arg1)))
2345             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2346           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2347           frame_info.width=geometry.width;
2348           frame_info.height=geometry.height;
2349           frame_info.outer_bevel=geometry.x;
2350           frame_info.inner_bevel=geometry.y;
2351           frame_info.x=(ssize_t) frame_info.width;
2352           frame_info.y=(ssize_t) frame_info.height;
2353           frame_info.width=_image->columns+2*frame_info.width;
2354           frame_info.height=_image->rows+2*frame_info.height;
2355           new_image=FrameImage(_image,&frame_info,compose,_exception);
2356           break;
2357         }
2358       if (LocaleCompare("function",option+1) == 0)
2359         {
2360           double
2361             *args;
2362
2363           ssize_t
2364             count;
2365
2366           parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2367           if ( parse < 0 )
2368             CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2369                  option,arg1);
2370           /* convert argument string into an array of doubles */
2371           args = StringToArrayOfDoubles(arg2,&count,_exception);
2372           if (args == (double *)NULL )
2373             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2374
2375           (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2376                _exception);
2377           args=(double *) RelinquishMagickMemory(args);
2378           break;
2379         }
2380       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2381     }
2382     case 'g':
2383     {
2384       if (LocaleCompare("gamma",option+1) == 0)
2385         {
2386           double
2387             constant;
2388
2389           if (IfMagickFalse(IsGeometry(arg1)))
2390             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2391           constant=StringToDouble(arg1,(char **) NULL);
2392 #if 0
2393           /* Using Gamma, via a cache */
2394           if (IfPlusOp)
2395             constant=PerceptibleReciprocal(constant);
2396           (void) GammaImage(_image,constant,_exception);
2397 #else
2398           /* Using Evaluate POW, direct update of values - more accurite */
2399           if (IfNormalOp)
2400             constant=PerceptibleReciprocal(constant);
2401           (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2402 #endif
2403           /* Set gamma setting -- Old meaning of "+gamma"
2404            * _image->gamma=StringToDouble(arg1,(char **) NULL);
2405            */
2406           break;
2407         }
2408       if (LocaleCompare("gaussian-blur",option+1) == 0)
2409         {
2410           flags=ParseGeometry(arg1,&geometry_info);
2411           if ((flags & (RhoValue|SigmaValue)) == 0)
2412             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2413           if ((flags & SigmaValue) == 0)
2414             geometry_info.sigma=1.0;
2415           new_image=GaussianBlurImage(_image,geometry_info.rho,
2416             geometry_info.sigma,_exception);
2417           break;
2418         }
2419       if (LocaleCompare("gaussian",option+1) == 0)
2420         {
2421           CLIWandWarnReplaced("-gaussian-blur");
2422           CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL);
2423         }
2424       if (LocaleCompare("geometry",option+1) == 0)
2425         {
2426           /*
2427             Record Image offset for composition. (A Setting)
2428             Resize last _image. (ListOperator)  -- DEPRECIATE
2429             FUTURE: Why if no 'offset' does this resize ALL images?
2430             Also why is the setting recorded in the IMAGE non-sense!
2431           */
2432           if (IfPlusOp)
2433             { /* remove the previous composition geometry offset! */
2434               if (_image->geometry != (char *) NULL)
2435                 _image->geometry=DestroyString(_image->geometry);
2436               break;
2437             }
2438           if (IfMagickFalse(IsGeometry(arg1)))
2439             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2440           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2441           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2442             (void) CloneString(&_image->geometry,arg1);
2443           else
2444             new_image=ResizeImage(_image,geometry.width,geometry.height,
2445               _image->filter,_exception);
2446           break;
2447         }
2448       if (LocaleCompare("grayscale",option+1) == 0)
2449         {
2450           parse=ParseCommandOption(MagickPixelIntensityOptions,
2451             MagickFalse,arg1);
2452           if (parse < 0)
2453             CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2454               option,arg1);
2455           (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2456           break;
2457         }
2458       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2459     }
2460     case 'i':
2461     {
2462       if (LocaleCompare("identify",option+1) == 0)
2463         {
2464           const char
2465             *format,
2466             *text;
2467
2468           format=GetImageOption(_image_info,"format");
2469           if (format == (char *) NULL)
2470             {
2471               (void) IdentifyImage(_image,stdout,_image_info->verbose,
2472                 _exception);
2473               break;
2474             }
2475           text=InterpretImageProperties(_image_info,_image,format,_exception);
2476           if (text == (char *) NULL)
2477             CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2478               option);
2479           (void) fputs(text,stdout);
2480           text=DestroyString((char *)text);
2481           break;
2482         }
2483       if (LocaleCompare("implode",option+1) == 0)
2484         {
2485           flags=ParseGeometry(arg1,&geometry_info);
2486           if ((flags & RhoValue) == 0)
2487             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2488           new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2489                _exception);
2490           break;
2491         }
2492       if (LocaleCompare("interpolative-resize",option+1) == 0)
2493         {
2494           /* FUTURE: New to IMv7
2495                Roll into a resize special operator */
2496           if (IfMagickFalse(IsGeometry(arg1)))
2497             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2498           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2499           new_image=InterpolativeResizeImage(_image,geometry.width,
2500                geometry.height,_image->interpolate,_exception);
2501           break;
2502         }
2503       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2504     }
2505     case 'l':
2506     {
2507       if (LocaleCompare("lat",option+1) == 0)
2508         {
2509           flags=ParseGeometry(arg1,&geometry_info);
2510           if ((flags & (RhoValue|SigmaValue)) == 0)
2511             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2512           if ((flags & SigmaValue) == 0)
2513             geometry_info.sigma=1.0;
2514           if ((flags & PercentValue) != 0)
2515             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2516           new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2517                (size_t) geometry_info.sigma,(double) geometry_info.xi,
2518                _exception);
2519           break;
2520         }
2521       if (LocaleCompare("level",option+1) == 0)
2522         {
2523           double
2524             black_point,
2525             gamma,
2526             white_point;
2527
2528           MagickStatusType
2529             flags;
2530
2531           flags=ParseGeometry(arg1,&geometry_info);
2532           if ((flags & RhoValue) == 0)
2533             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2534           black_point=geometry_info.rho;
2535           white_point=(double) QuantumRange;
2536           if ((flags & SigmaValue) != 0)
2537             white_point=geometry_info.sigma;
2538           gamma=1.0;
2539           if ((flags & XiValue) != 0)
2540             gamma=geometry_info.xi;
2541           if ((flags & PercentValue) != 0)
2542             {
2543               black_point*=(double) (QuantumRange/100.0);
2544               white_point*=(double) (QuantumRange/100.0);
2545             }
2546           if ((flags & SigmaValue) == 0)
2547             white_point=(double) QuantumRange-black_point;
2548           if (IfPlusOp || ((flags & AspectValue) != 0))
2549             (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2550           else
2551             (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2552           break;
2553         }
2554       if (LocaleCompare("level-colors",option+1) == 0)
2555         {
2556           char
2557             token[MaxTextExtent];
2558
2559           const char
2560             *p;
2561
2562           PixelInfo
2563             black_point,
2564             white_point;
2565
2566           p=(const char *) arg1;
2567           GetMagickToken(p,&p,token);  /* get black point color */
2568           if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2569             (void) QueryColorCompliance(token,AllCompliance,
2570                       &black_point,_exception);
2571           else
2572             (void) QueryColorCompliance("#000000",AllCompliance,
2573                       &black_point,_exception);
2574           if (isalpha((int) token[0]) || (token[0] == '#'))
2575             GetMagickToken(p,&p,token);
2576           if (*token == '\0')
2577             white_point=black_point; /* set everything to that color */
2578           else
2579             {
2580               if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2581                 GetMagickToken(p,&p,token); /* Get white point color. */
2582               if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2583                 (void) QueryColorCompliance(token,AllCompliance,
2584                            &white_point,_exception);
2585               else
2586                 (void) QueryColorCompliance("#ffffff",AllCompliance,
2587                            &white_point,_exception);
2588             }
2589           (void) LevelImageColors(_image,&black_point,&white_point,
2590                      IsPlusOp,_exception);
2591           break;
2592         }
2593       if (LocaleCompare("linear-stretch",option+1) == 0)
2594         {
2595           double
2596             black_point,
2597             white_point;
2598
2599           MagickStatusType
2600             flags;
2601
2602           flags=ParseGeometry(arg1,&geometry_info);
2603           if ((flags & RhoValue) == 0)
2604             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2605           black_point=geometry_info.rho;
2606           white_point=(double) _image->columns*_image->rows;
2607           if ((flags & SigmaValue) != 0)
2608             white_point=geometry_info.sigma;
2609           if ((flags & PercentValue) != 0)
2610             {
2611               black_point*=(double) _image->columns*_image->rows/100.0;
2612               white_point*=(double) _image->columns*_image->rows/100.0;
2613             }
2614           if ((flags & SigmaValue) == 0)
2615             white_point=(double) _image->columns*_image->rows-
2616               black_point;
2617           (void) LinearStretchImage(_image,black_point,white_point,_exception);
2618           break;
2619         }
2620       if (LocaleCompare("liquid-rescale",option+1) == 0)
2621         {
2622           /* FUTURE: Roll into a resize special operator */
2623           if (IfMagickFalse(IsGeometry(arg1)))
2624             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2625           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2626           if ((flags & XValue) == 0)
2627             geometry.x=1;
2628           if ((flags & YValue) == 0)
2629             geometry.y=0;
2630           new_image=LiquidRescaleImage(_image,geometry.width,
2631             geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2632           break;
2633         }
2634       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2635     }
2636     case 'm':
2637     {
2638       if (LocaleCompare("magnify",option+1) == 0)
2639         {
2640           new_image=MagnifyImage(_image,_exception);
2641           break;
2642         }
2643       if (LocaleCompare("map",option+1) == 0)
2644         {
2645           CLIWandWarnReplaced("-remap");
2646           CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL);
2647           break;
2648         }
2649       if (LocaleCompare("mask",option+1) == 0)
2650         {
2651           /* Note: arguments do not have percent escapes expanded */
2652           Image
2653             *mask;
2654
2655           if (IfPlusOp)
2656             { /* Remove a mask. */
2657               (void) SetImageMask(_image,(Image *) NULL,_exception);
2658               break;
2659             }
2660           /* Set the image mask. */
2661           mask=GetImageCache(_image_info,arg1,_exception);
2662           if (mask == (Image *) NULL)
2663             break;
2664           (void) SetImageMask(_image,mask,_exception);
2665           mask=DestroyImage(mask);
2666           break;
2667         }
2668       if (LocaleCompare("matte",option+1) == 0)
2669         {
2670           CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2671           (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2672                          DeactivateAlphaChannel, _exception);
2673           break;
2674         }
2675       if (LocaleCompare("median",option+1) == 0)
2676         {
2677           CLIWandWarnReplaced("-statistic Median");
2678           CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1);
2679           break;
2680         }
2681       if (LocaleCompare("mode",option+1) == 0)
2682         {
2683           /* FUTURE: note this is also a special "montage" option */
2684           CLIWandWarnReplaced("-statistic Mode");
2685           CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1);
2686           break;
2687         }
2688       if (LocaleCompare("modulate",option+1) == 0)
2689         {
2690           if (IfMagickFalse(IsGeometry(arg1)))
2691             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2692           (void) ModulateImage(_image,arg1,_exception);
2693           break;
2694         }
2695       if (LocaleCompare("monitor",option+1) == 0)
2696         {
2697           (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2698                 (MagickProgressMonitor) NULL,(void *) NULL);
2699           break;
2700         }
2701       if (LocaleCompare("monochrome",option+1) == 0)
2702         {
2703           (void) SetImageType(_image,BilevelType,_exception);
2704           break;
2705         }
2706       if (LocaleCompare("morphology",option+1) == 0)
2707         {
2708           char
2709             token[MaxTextExtent];
2710
2711           const char
2712             *p;
2713
2714           KernelInfo
2715             *kernel;
2716
2717           ssize_t
2718             iterations;
2719
2720           p=arg1;
2721           GetMagickToken(p,&p,token);
2722           parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2723           if ( parse < 0 )
2724             CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2725                  option,arg1);
2726           iterations=1L;
2727           GetMagickToken(p,&p,token);
2728           if ((*p == ':') || (*p == ','))
2729             GetMagickToken(p,&p,token);
2730           if ((*p != '\0'))
2731             iterations=(ssize_t) StringToLong(p);
2732           kernel=AcquireKernelInfo(arg2);
2733           if (kernel == (KernelInfo *) NULL)
2734             CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",
2735                  option,arg2);
2736           new_image=MorphologyImage(_image,(MorphologyMethod)parse,
2737                iterations,kernel,_exception);
2738           kernel=DestroyKernelInfo(kernel);
2739           break;
2740         }
2741       if (LocaleCompare("motion-blur",option+1) == 0)
2742         {
2743           flags=ParseGeometry(arg1,&geometry_info);
2744           if ((flags & (RhoValue|SigmaValue)) == 0)
2745             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2746           if ((flags & SigmaValue) == 0)
2747             geometry_info.sigma=1.0;
2748           new_image=MotionBlurImage(_image,geometry_info.rho,
2749             geometry_info.sigma,geometry_info.xi,_exception);
2750           break;
2751         }
2752       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2753     }
2754     case 'n':
2755     {
2756       if (LocaleCompare("negate",option+1) == 0)
2757         {
2758           (void) NegateImage(_image, IsPlusOp, _exception);
2759           break;
2760         }
2761       if (LocaleCompare("noise",option+1) == 0)
2762         {
2763           double
2764             attenuate;
2765
2766           const char*
2767             value;
2768
2769           if (IfNormalOp)
2770             {
2771               CLIWandWarnReplaced("-statistic NonPeak");
2772               CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1);
2773               break;
2774             }
2775           parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2776           if ( parse < 0 )
2777             CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2778                 option,arg1);
2779           attenuate=1.0;
2780           value=GetImageOption(_image_info,"attenuate");
2781           if  (value != (const char *) NULL)
2782             attenuate=StringToDouble(value,(char **) NULL);
2783           new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2784                _exception);
2785           break;
2786         }
2787       if (LocaleCompare("normalize",option+1) == 0)
2788         {
2789           (void) NormalizeImage(_image,_exception);
2790           break;
2791         }
2792       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2793     }
2794     case 'o':
2795     {
2796       if (LocaleCompare("opaque",option+1) == 0)
2797         {
2798           PixelInfo
2799             target;
2800
2801           (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2802           (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2803                _exception);
2804           break;
2805         }
2806       if (LocaleCompare("ordered-dither",option+1) == 0)
2807         {
2808           (void) OrderedPosterizeImage(_image,arg1,_exception);
2809           break;
2810         }
2811       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2812     }
2813     case 'p':
2814     {
2815       if (LocaleCompare("paint",option+1) == 0)
2816         {
2817           flags=ParseGeometry(arg1,&geometry_info);
2818           if ((flags & (RhoValue|SigmaValue)) == 0)
2819             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2820           new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2821                _exception);
2822           break;
2823         }
2824       if (LocaleCompare("perceptible",option+1) == 0)
2825         {
2826           (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2827             _exception);
2828           break;
2829         }
2830       if (LocaleCompare("polaroid",option+1) == 0)
2831         {
2832           const char
2833             *caption;
2834
2835           double
2836             angle;
2837
2838           if (IfPlusOp) {
2839             RandomInfo
2840             *random_info;
2841
2842             random_info=AcquireRandomInfo();
2843             angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2844             random_info=DestroyRandomInfo(random_info);
2845           }
2846           else {
2847             flags=ParseGeometry(arg1,&geometry_info);
2848             if ((flags & RhoValue) == 0)
2849               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2850             angle=geometry_info.rho;
2851           }
2852           caption=GetImageProperty(_image,"caption",_exception);
2853           new_image=PolaroidImage(_image,_draw_info,caption,angle,
2854             _image->interpolate,_exception);
2855           break;
2856         }
2857       if (LocaleCompare("posterize",option+1) == 0)
2858         {
2859           flags=ParseGeometry(arg1,&geometry_info);
2860           if ((flags & RhoValue) == 0)
2861             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2862           (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2863             _quantize_info->dither_method,_exception);
2864           break;
2865         }
2866       if (LocaleCompare("preview",option+1) == 0)
2867         {
2868           /* FUTURE: should be a 'Genesis' option?
2869              Option however is also in WandSettingOptionInfo()
2870              Why???
2871           */
2872           parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2873           if ( parse < 0 )
2874             CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2875                 option,arg1);
2876           new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2877           break;
2878         }
2879       if (LocaleCompare("profile",option+1) == 0)
2880         {
2881           /* Note: arguments do not have percent escapes expanded */
2882           const char
2883             *name;
2884
2885           const StringInfo
2886             *profile;
2887
2888           Image
2889             *profile_image;
2890
2891           ImageInfo
2892             *profile_info;
2893
2894           if (IfPlusOp)
2895             { /* Remove a profile from the _image.  */
2896               (void) ProfileImage(_image,arg1,(const unsigned char *)
2897                 NULL,0,_exception);
2898               break;
2899             }
2900           /* Associate a profile with the _image.  */
2901           profile_info=CloneImageInfo(_image_info);
2902           profile=GetImageProfile(_image,"iptc");
2903           if (profile != (StringInfo *) NULL)
2904             profile_info->profile=(void *) CloneStringInfo(profile);
2905           profile_image=GetImageCache(profile_info,arg1,_exception);
2906           profile_info=DestroyImageInfo(profile_info);
2907           if (profile_image == (Image *) NULL)
2908             {
2909               StringInfo
2910                 *profile;
2911
2912               profile_info=CloneImageInfo(_image_info);
2913               (void) CopyMagickString(profile_info->filename,arg1,
2914                 MaxTextExtent);
2915               profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
2916               if (profile != (StringInfo *) NULL)
2917                 {
2918                   (void) ProfileImage(_image,profile_info->magick,
2919                     GetStringInfoDatum(profile),(size_t)
2920                     GetStringInfoLength(profile),_exception);
2921                   profile=DestroyStringInfo(profile);
2922                 }
2923               profile_info=DestroyImageInfo(profile_info);
2924               break;
2925             }
2926           ResetImageProfileIterator(profile_image);
2927           name=GetNextImageProfile(profile_image);
2928           while (name != (const char *) NULL)
2929           {
2930             profile=GetImageProfile(profile_image,name);
2931             if (profile != (StringInfo *) NULL)
2932               (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
2933                 (size_t) GetStringInfoLength(profile),_exception);
2934             name=GetNextImageProfile(profile_image);
2935           }
2936           profile_image=DestroyImage(profile_image);
2937           break;
2938         }
2939       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2940     }
2941     case 'r':
2942     {
2943       if (LocaleCompare("radial-blur",option+1) == 0)
2944         {
2945           flags=ParseGeometry(arg1,&geometry_info);
2946           if ((flags & RhoValue) == 0)
2947             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2948           new_image=RadialBlurImage(_image,geometry_info.rho,_exception);
2949           break;
2950         }
2951       if (LocaleCompare("raise",option+1) == 0)
2952         {
2953           if (IfMagickFalse(IsGeometry(arg1)))
2954             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2955           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2956           (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
2957           break;
2958         }
2959       if (LocaleCompare("random-threshold",option+1) == 0)
2960         {
2961           if (IfMagickFalse(IsGeometry(arg1)))
2962             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2963           (void) RandomThresholdImage(_image,arg1,_exception);
2964           break;
2965         }
2966       if (LocaleCompare("recolor",option+1) == 0)
2967         {
2968           CLIWandWarnReplaced("-color-matrix");
2969           CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL);
2970         }
2971       if (LocaleCompare("remap",option+1) == 0)
2972         {
2973           /* Note: arguments do not have percent escapes expanded */
2974           Image
2975             *remap_image;
2976
2977           remap_image=GetImageCache(_image_info,arg1,_exception);
2978           if (remap_image == (Image *) NULL)
2979             break;
2980           (void) RemapImage(_quantize_info,_image,remap_image,_exception);
2981           remap_image=DestroyImage(remap_image);
2982           break;
2983         }
2984       if (LocaleCompare("repage",option+1) == 0)
2985         {
2986           if (IfNormalOp)
2987             {
2988               if (IfMagickFalse(IsGeometry(arg1)))
2989                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
2990                   arg1);
2991               (void) ResetImagePage(_image,arg1);
2992             }
2993           else
2994             (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
2995           break;
2996         }
2997       if (LocaleCompare("resample",option+1) == 0)
2998         {
2999           /* FUTURE: Roll into a resize special operation */
3000           flags=ParseGeometry(arg1,&geometry_info);
3001           if ((flags & (RhoValue|SigmaValue)) == 0)
3002             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3003           if ((flags & SigmaValue) == 0)
3004             geometry_info.sigma=geometry_info.rho;
3005           new_image=ResampleImage(_image,geometry_info.rho,
3006             geometry_info.sigma,_image->filter,_exception);
3007           break;
3008         }
3009       if (LocaleCompare("resize",option+1) == 0)
3010         {
3011           if (IfMagickFalse(IsGeometry(arg1)))
3012             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3013           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3014           new_image=ResizeImage(_image,geometry.width,geometry.height,
3015             _image->filter,_exception);
3016           break;
3017         }
3018       if (LocaleCompare("roll",option+1) == 0)
3019         {
3020           if (IfMagickFalse(IsGeometry(arg1)))
3021             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3022           (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3023           new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3024           break;
3025         }
3026       if (LocaleCompare("rotate",option+1) == 0)
3027         {
3028           flags=ParseGeometry(arg1,&geometry_info);
3029           if ((flags & RhoValue) == 0)
3030             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3031           if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3032             break;
3033           if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3034             break;
3035           new_image=RotateImage(_image,geometry_info.rho,_exception);
3036           break;
3037         }
3038       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3039     }
3040     case 's':
3041     {
3042       if (LocaleCompare("sample",option+1) == 0)
3043         {
3044           /* FUTURE: Roll into a resize special operator */
3045           if (IfMagickFalse(IsGeometry(arg1)))
3046             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3047           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3048           new_image=SampleImage(_image,geometry.width,geometry.height,
3049             _exception);
3050           break;
3051         }
3052       if (LocaleCompare("scale",option+1) == 0)
3053         {
3054           /* FUTURE: Roll into a resize special operator */
3055           if (IfMagickFalse(IsGeometry(arg1)))
3056             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3057           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3058           new_image=ScaleImage(_image,geometry.width,geometry.height,
3059             _exception);
3060           break;
3061         }
3062       if (LocaleCompare("segment",option+1) == 0)
3063         {
3064           flags=ParseGeometry(arg1,&geometry_info);
3065           if ((flags & (RhoValue|SigmaValue)) == 0)
3066             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3067           if ((flags & SigmaValue) == 0)
3068             geometry_info.sigma=1.0;
3069           (void) SegmentImage(_image,_image->colorspace,
3070             _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3071             _exception);
3072           break;
3073         }
3074       if (LocaleCompare("selective-blur",option+1) == 0)
3075         {
3076           flags=ParseGeometry(arg1,&geometry_info);
3077           if ((flags & (RhoValue|SigmaValue)) == 0)
3078             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3079           if ((flags & SigmaValue) == 0)
3080             geometry_info.sigma=1.0;
3081           if ((flags & PercentValue) != 0)
3082             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3083           new_image=SelectiveBlurImage(_image,geometry_info.rho,
3084             geometry_info.sigma,geometry_info.xi,_exception);
3085           break;
3086         }
3087       if (LocaleCompare("separate",option+1) == 0)
3088         {
3089           /* WARNING: This can generate multiple images! */
3090           /* FUTURE - this may be replaced by a "-channel" method */
3091           new_image=SeparateImages(_image,_exception);
3092           break;
3093         }
3094       if (LocaleCompare("sepia-tone",option+1) == 0)
3095         {
3096           if (IfMagickFalse(IsGeometry(arg1)))
3097             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3098           new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3099                  (double) QuantumRange+1.0),_exception);
3100           break;
3101         }
3102       if (LocaleCompare("shade",option+1) == 0)
3103         {
3104           flags=ParseGeometry(arg1,&geometry_info);
3105           if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3106             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3107           new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3108                geometry_info.sigma,_exception);
3109           break;
3110         }
3111       if (LocaleCompare("shadow",option+1) == 0)
3112         {
3113           flags=ParseGeometry(arg1,&geometry_info);
3114           if ((flags & (RhoValue|SigmaValue)) == 0)
3115             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3116           if ((flags & SigmaValue) == 0)
3117             geometry_info.sigma=1.0;
3118           if ((flags & XiValue) == 0)
3119             geometry_info.xi=4.0;
3120           if ((flags & PsiValue) == 0)
3121             geometry_info.psi=4.0;
3122           new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3123             (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3124             ceil(geometry_info.psi-0.5),_exception);
3125           break;
3126         }
3127       if (LocaleCompare("sharpen",option+1) == 0)
3128         {
3129           flags=ParseGeometry(arg1,&geometry_info);
3130           if ((flags & (RhoValue|SigmaValue)) == 0)
3131             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3132           if ((flags & SigmaValue) == 0)
3133             geometry_info.sigma=1.0;
3134           if ((flags & XiValue) == 0)
3135             geometry_info.xi=0.0;
3136           new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3137            _exception);
3138           break;
3139         }
3140       if (LocaleCompare("shave",option+1) == 0)
3141         {
3142           if (IfMagickFalse(IsGeometry(arg1)))
3143             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3144           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3145           new_image=ShaveImage(_image,&geometry,_exception);
3146           break;
3147         }
3148       if (LocaleCompare("shear",option+1) == 0)
3149         {
3150           flags=ParseGeometry(arg1,&geometry_info);
3151           if ((flags & RhoValue) == 0)
3152             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3153           if ((flags & SigmaValue) == 0)
3154             geometry_info.sigma=geometry_info.rho;
3155           new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3156             _exception);
3157           break;
3158         }
3159       if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3160         {
3161           flags=ParseGeometry(arg1,&geometry_info);
3162           if ((flags & RhoValue) == 0)
3163             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3164           if ((flags & SigmaValue) == 0)
3165             geometry_info.sigma=(double) QuantumRange/2.0;
3166           if ((flags & PercentValue) != 0)
3167             geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3168               100.0;
3169           (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3170                geometry_info.sigma,_exception);
3171           break;
3172         }
3173       if (LocaleCompare("sketch",option+1) == 0)
3174         {
3175           flags=ParseGeometry(arg1,&geometry_info);
3176           if ((flags & (RhoValue|SigmaValue)) == 0)
3177             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3178           if ((flags & SigmaValue) == 0)
3179             geometry_info.sigma=1.0;
3180           new_image=SketchImage(_image,geometry_info.rho,
3181             geometry_info.sigma,geometry_info.xi,_exception);
3182           break;
3183         }
3184       if (LocaleCompare("solarize",option+1) == 0)
3185         {
3186           if (IfMagickFalse(IsGeometry(arg1)))
3187             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3188           (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3189                  QuantumRange+1.0),_exception);
3190           break;
3191         }
3192       if (LocaleCompare("sparse-color",option+1) == 0)
3193         {
3194           parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3195           if ( parse < 0 )
3196             CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3197                 option,arg1);
3198           new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3199                _exception);
3200           break;
3201         }
3202       if (LocaleCompare("splice",option+1) == 0)
3203         {
3204           if (IfMagickFalse(IsGeometry(arg1)))
3205             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3206           flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3207           new_image=SpliceImage(_image,&geometry,_exception);
3208           break;
3209         }
3210       if (LocaleCompare("spread",option+1) == 0)
3211         {
3212           flags=ParseGeometry(arg1,&geometry_info);
3213           if ((flags & RhoValue) == 0)
3214             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3215           new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3216                _exception);
3217           break;
3218         }
3219       if (LocaleCompare("statistic",option+1) == 0)
3220         {
3221           parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3222           if ( parse < 0 )
3223             CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3224                  option,arg1);
3225           flags=ParseGeometry(arg2,&geometry_info);
3226           if ((flags & RhoValue) == 0)
3227             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3228           if ((flags & SigmaValue) == 0)
3229             geometry_info.sigma=geometry_info.rho;
3230           new_image=StatisticImage(_image,(StatisticType)parse,
3231                (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3232                _exception);
3233           break;
3234         }
3235       if (LocaleCompare("strip",option+1) == 0)
3236         {
3237           (void) StripImage(_image,_exception);
3238           break;
3239         }
3240       if (LocaleCompare("swirl",option+1) == 0)
3241         {
3242           flags=ParseGeometry(arg1,&geometry_info);
3243           if ((flags & RhoValue) == 0)
3244             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3245           new_image=SwirlImage(_image,geometry_info.rho,
3246             _image->interpolate,_exception);
3247           break;
3248         }
3249       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3250     }
3251     case 't':
3252     {
3253       if (LocaleCompare("threshold",option+1) == 0)
3254         {
3255           double
3256             threshold;
3257
3258           threshold=(double) QuantumRange/2;
3259           if (IfNormalOp) {
3260             if (IfMagickFalse(IsGeometry(arg1)))
3261               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3262             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3263           }
3264           (void) BilevelImage(_image,threshold,_exception);
3265           break;
3266         }
3267       if (LocaleCompare("thumbnail",option+1) == 0)
3268         {
3269           if (IfMagickFalse(IsGeometry(arg1)))
3270             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3271           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3272           new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3273             _exception);
3274           break;
3275         }
3276       if (LocaleCompare("tint",option+1) == 0)
3277         {
3278           if (IfMagickFalse(IsGeometry(arg1)))
3279             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3280           new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3281           break;
3282         }
3283       if (LocaleCompare("transform",option+1) == 0)
3284         {
3285           CLIWandWarnReplaced("+distort AffineProjection");
3286           new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3287           break;
3288         }
3289       if (LocaleCompare("transparent",option+1) == 0)
3290         {
3291           PixelInfo
3292             target;
3293
3294           (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3295           (void) TransparentPaintImage(_image,&target,(Quantum)
3296             TransparentAlpha,IsPlusOp,_exception);
3297           break;
3298         }
3299       if (LocaleCompare("transpose",option+1) == 0)
3300         {
3301           new_image=TransposeImage(_image,_exception);
3302           break;
3303         }
3304       if (LocaleCompare("transverse",option+1) == 0)
3305         {
3306           new_image=TransverseImage(_image,_exception);
3307           break;
3308         }
3309       if (LocaleCompare("trim",option+1) == 0)
3310         {
3311           new_image=TrimImage(_image,_exception);
3312           break;
3313         }
3314       if (LocaleCompare("type",option+1) == 0)
3315         {
3316           /* Note that "type" setting should have already been defined */
3317           (void) SetImageType(_image,_image_info->type,_exception);
3318           break;
3319         }
3320       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3321     }
3322     case 'u':
3323     {
3324       if (LocaleCompare("unique",option+1) == 0)
3325         {
3326           /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3327              Option is not documented, bt appears to be for "identify".
3328              We may need a identify specific verbose!
3329           */
3330           if (IsPlusOp) {
3331               (void) DeleteImageArtifact(_image,"identify:unique-colors");
3332               break;
3333             }
3334           (void) SetImageArtifact(_image,"identify:unique-colors","true");
3335           (void) SetImageArtifact(_image,"verbose","true");
3336           break;
3337         }
3338       if (LocaleCompare("unique-colors",option+1) == 0)
3339         {
3340           new_image=UniqueImageColors(_image,_exception);
3341           break;
3342         }
3343       if (LocaleCompare("unsharp",option+1) == 0)
3344         {
3345           flags=ParseGeometry(arg1,&geometry_info);
3346           if ((flags & (RhoValue|SigmaValue)) == 0)
3347             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3348           if ((flags & SigmaValue) == 0)
3349             geometry_info.sigma=1.0;
3350           if ((flags & XiValue) == 0)
3351             geometry_info.xi=1.0;
3352           if ((flags & PsiValue) == 0)
3353             geometry_info.psi=0.05;
3354           new_image=UnsharpMaskImage(_image,geometry_info.rho,
3355             geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3356           break;
3357         }
3358       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3359     }
3360     case 'v':
3361     {
3362       if (LocaleCompare("verbose",option+1) == 0)
3363         {
3364           /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3365              three places!   ImageArtifact   ImageOption  _image_info->verbose
3366              Some how new images also get this artifact!
3367           */
3368           (void) SetImageArtifact(_image,option+1,
3369                            IfNormalOp ? "true" : "false" );
3370           break;
3371         }
3372       if (LocaleCompare("vignette",option+1) == 0)
3373         {
3374           flags=ParseGeometry(arg1,&geometry_info);
3375           if ((flags & (RhoValue|SigmaValue)) == 0)
3376             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3377           if ((flags & SigmaValue) == 0)
3378             geometry_info.sigma=1.0;
3379           if ((flags & XiValue) == 0)
3380             geometry_info.xi=0.1*_image->columns;
3381           if ((flags & PsiValue) == 0)
3382             geometry_info.psi=0.1*_image->rows;
3383           new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3384             (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3385             ceil(geometry_info.psi-0.5),_exception);
3386           break;
3387         }
3388       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3389     }
3390     case 'w':
3391     {
3392       if (LocaleCompare("wave",option+1) == 0)
3393         {
3394           flags=ParseGeometry(arg1,&geometry_info);
3395           if ((flags & (RhoValue|SigmaValue)) == 0)
3396             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3397           if ((flags & SigmaValue) == 0)
3398             geometry_info.sigma=1.0;
3399           new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3400                _image->interpolate,_exception);
3401           break;
3402         }
3403       if (LocaleCompare("white-threshold",option+1) == 0)
3404         {
3405           if (IfMagickFalse(IsGeometry(arg1)))
3406             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3407           (void) WhiteThresholdImage(_image,arg1,_exception);
3408           break;
3409         }
3410       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3411     }
3412     default:
3413       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3414   }
3415   /* clean up percent escape interpreted strings */
3416   if (arg1 != arg1n )
3417     arg1=DestroyString((char *)arg1);
3418   if (arg2 != arg2n )
3419     arg2=DestroyString((char *)arg2);
3420
3421   /* Replace current image with any image that was generated
3422      and set image point to last image (so image->next is correct) */
3423   if (new_image != (Image *) NULL)
3424     ReplaceImageInListReturnLast(&_image,new_image);
3425
3426   return(MagickTrue);
3427 #undef _image_info
3428 #undef _draw_info
3429 #undef _quantize_info
3430 #undef _image
3431 #undef _exception
3432 #undef IfNormalOp
3433 #undef IfPlusOp
3434 #undef IsNormalOp
3435 #undef IsPlusOp
3436 }
3437
3438 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3439   const char *option,const char *arg1,const char *arg2)
3440 {
3441 #if !USE_WAND_METHODS
3442   size_t
3443     n,
3444     i;
3445 #endif
3446
3447   assert(cli_wand != (MagickCLI *) NULL);
3448   assert(cli_wand->signature == WandSignature);
3449   assert(cli_wand->wand.signature == WandSignature);
3450   assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3451
3452   if (IfMagickTrue(cli_wand->wand.debug))
3453     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3454          "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3455
3456 #if !USE_WAND_METHODS
3457   /* FUTURE add appropriate tracing */
3458   i=0;
3459   n=GetImageListLength(cli_wand->wand.images);
3460   cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3461   while (1) {
3462     i++;
3463     CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3464     if ( cli_wand->wand.images->next == (Image *) NULL )
3465       break;
3466     cli_wand->wand.images=cli_wand->wand.images->next;
3467   }
3468   assert( i == n );
3469   cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3470 #else
3471   MagickResetIterator(&cli_wand->wand);
3472   while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3473     CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3474   MagickResetIterator(&cli_wand->wand);
3475 #endif
3476   return(MagickTrue);
3477 }
3478 \f
3479 /*
3480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3481 %                                                                             %
3482 %                                                                             %
3483 %                                                                             %
3484 +     C L I L i s t O p e r a t o r I m a g e s                               %
3485 %                                                                             %
3486 %                                                                             %
3487 %                                                                             %
3488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489 %
3490 %  CLIListOperatorImages() applies a single operation that is apply to the
3491 %  entire image list as a whole. The result is often a complete replacment
3492 %  of the image list with a completely new list, or with just a single image
3493 %  result.
3494 %
3495 %  The format of the MogrifyImage method is:
3496 %
3497 %    MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3498 %      const char *option,const char *arg1,const char *arg2)
3499 %
3500 %  A description of each parameter follows:
3501 %
3502 %    o cli_wand: structure holding settings to be applied
3503 %
3504 %    o option:  The option string for the operation
3505 %
3506 %    o arg1, arg2: optional argument strings to the operation
3507 %        arg2 is currently not used
3508 %
3509 */
3510 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3511   const char *option,const char *arg1n,const char *arg2n)
3512 {
3513   const char    /* percent escaped versions of the args */
3514     *arg1,
3515     *arg2;
3516
3517   Image
3518     *new_images;
3519
3520   MagickStatusType
3521     status;
3522
3523   ssize_t
3524     parse;
3525
3526 #define _image_info     (cli_wand->wand.image_info)
3527 #define _images         (cli_wand->wand.images)
3528 #define _exception      (cli_wand->wand.exception)
3529 #define _draw_info      (cli_wand->draw_info)
3530 #define _quantize_info  (cli_wand->quantize_info)
3531 #define _process_flags  (cli_wand->process_flags)
3532 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
3533 #define IfNormalOp      (*option=='-')
3534 #define IfPlusOp        (*option!='-')
3535 #define IsNormalOp       IsMagickTrue(IfNormalOp)
3536
3537   assert(cli_wand != (MagickCLI *) NULL);
3538   assert(cli_wand->signature == WandSignature);
3539   assert(cli_wand->wand.signature == WandSignature);
3540   assert(_images != (Image *) NULL);             /* _images must be present */
3541
3542   if (IfMagickTrue(cli_wand->wand.debug))
3543     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3544          "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
3545
3546   arg1 = arg1n;
3547   arg2 = arg2n;
3548
3549   /* Interpret Percent Escapes in Arguments - using first image */
3550   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3551         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3552        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3553     /* Interpret Percent escapes in argument 1 */
3554     if (arg1n != (char *) NULL) {
3555       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3556       if (arg1 == (char *) NULL) {
3557         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3558         arg1=arg1n;  /* use the given argument as is */
3559       }
3560     }
3561     if (arg2n != (char *) NULL) {
3562       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3563       if (arg2 == (char *) NULL) {
3564         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3565         arg2=arg2n;  /* use the given argument as is */
3566       }
3567     }
3568   }
3569 #undef _process_flags
3570 #undef _option_type
3571
3572   status=MagickTrue;
3573   new_images=NewImageList();
3574
3575   switch (*(option+1))
3576   {
3577     case 'a':
3578     {
3579       if (LocaleCompare("append",option+1) == 0)
3580         {
3581           new_images=AppendImages(_images,IsNormalOp,_exception);
3582           break;
3583         }
3584       if (LocaleCompare("average",option+1) == 0)
3585         {
3586           CLIWandWarnReplaced("-evaluate-sequence Mean");
3587           CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3588           break;
3589         }
3590       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3591     }
3592     case 'c':
3593     {
3594       if (LocaleCompare("channel-fx",option+1) == 0)
3595         {
3596           new_images=ChannelFxImage(_images,arg1,_exception);
3597           break;
3598         }
3599       if (LocaleCompare("clut",option+1) == 0)
3600         {
3601           Image
3602             *clut_image;
3603
3604           /* FUTURE - make this a compose option, and thus can be used
3605              with layers compose or even compose last image over all other
3606              _images.
3607           */
3608           new_images=RemoveFirstImageFromList(&_images);
3609           clut_image=RemoveLastImageFromList(&_images);
3610           /* FUTURE - produce Exception, rather than silent fail */
3611           if (clut_image == (Image *) NULL)
3612             break;
3613           (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3614           clut_image=DestroyImage(clut_image);
3615           break;
3616         }
3617       if (LocaleCompare("coalesce",option+1) == 0)
3618         {
3619           new_images=CoalesceImages(_images,_exception);
3620           break;
3621         }
3622       if (LocaleCompare("combine",option+1) == 0)
3623         {
3624           parse = (ssize_t) sRGBColorspace; /* default (backward compatible) */
3625           if ( IfPlusOp )
3626             parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
3627                  arg1);
3628           if (parse < 0)
3629             CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3630               arg1);
3631           new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3632           break;
3633         }
3634       if (LocaleCompare("compare",option+1) == 0)
3635         {
3636           double
3637             distortion;
3638
3639           Image
3640             *image,
3641             *reconstruct_image;
3642
3643           MetricType
3644             metric;
3645
3646           /*
3647             Mathematically and visually annotate the difference between an
3648             image and its reconstruction.
3649           */
3650           image=RemoveFirstImageFromList(&_images);
3651           reconstruct_image=RemoveFirstImageFromList(&_images);
3652           /* FUTURE - produce Exception, rather than silent fail */
3653           if (reconstruct_image == (Image *) NULL)
3654             break;
3655           metric=UndefinedErrorMetric;
3656           option=GetImageOption(_image_info,"metric");
3657           if (option != (const char *) NULL)
3658             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3659               MagickFalse,option);
3660           new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3661             _exception);
3662           (void) distortion;
3663           reconstruct_image=DestroyImage(reconstruct_image);
3664           image=DestroyImage(image);
3665           break;
3666         }
3667       if (LocaleCompare("complex",option+1) == 0)
3668         {
3669           parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3670           if (parse < 0)
3671             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3672               option,arg1);
3673           new_images=ComplexImages(_images,(MagickComplexOperator) parse,
3674             _exception);
3675           break;
3676         }
3677       if (LocaleCompare("composite",option+1) == 0)
3678         {
3679           CompositeOperator
3680             compose;
3681
3682           const char*
3683             value;
3684
3685           MagickBooleanType
3686             clip_to_self;
3687
3688           Image
3689             *mask_image,
3690             *source_image;
3691
3692           RectangleInfo
3693             geometry;
3694
3695           /* Compose value from "-compose" option only */
3696           value=GetImageOption(_image_info,"compose");
3697           if (value == (const char *) NULL)
3698             compose=OverCompositeOp;  /* use Over not source_image->compose */
3699           else
3700             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3701               MagickFalse,value);
3702
3703           /* Get "clip-to-self" expert setting (false is normal) */
3704           value=GetImageOption(_image_info,"compose:clip-to-self");
3705           if (value == (const char *) NULL)
3706             clip_to_self=MagickTrue;
3707           else
3708             clip_to_self=IsStringTrue(GetImageOption(_image_info,
3709               "compose:clip-to-self")); /* if this is true */
3710           value=GetImageOption(_image_info,"compose:outside-overlay");
3711           if (value != (const char *) NULL) {   /* or this false */
3712             /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3713             clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3714           }
3715
3716           new_images=RemoveFirstImageFromList(&_images);
3717           source_image=RemoveFirstImageFromList(&_images);
3718           if (source_image == (Image *) NULL)
3719             break; /* FUTURE - produce Exception, rather than silent fail */
3720
3721           /* FUTURE - this should not be here! - should be part of -geometry */
3722           (void) TransformImage(&source_image,(char *) NULL,
3723             source_image->geometry,_exception);
3724           SetGeometry(source_image,&geometry);
3725           (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3726           GravityAdjustGeometry(new_images->columns,new_images->rows,
3727             new_images->gravity, &geometry);
3728           mask_image=RemoveFirstImageFromList(&_images);
3729           if (mask_image != (Image *) NULL)
3730             {
3731               if ((compose == DisplaceCompositeOp) ||
3732                   (compose == DistortCompositeOp))
3733                 status&=CompositeImage(source_image,mask_image,
3734                   CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3735               else
3736                 {
3737                   Image
3738                     *image;
3739
3740                   RectangleInfo
3741                     source_geometry;
3742
3743                   source_geometry.width=mask_image->columns;
3744                   source_geometry.height=mask_image->rows;
3745                   source_geometry.x=(-geometry.x);
3746                   source_geometry.y=(-geometry.y);
3747                   geometry.x=0;
3748                   geometry.y=0;
3749                   image=ExtentImage(source_image,&source_geometry,_exception);
3750                   if (image != (Image *) NULL)
3751                     {
3752                       source_image=DestroyImage(source_image);
3753                       source_image=image;
3754                     }
3755                   status&=CompositeImage(source_image,mask_image,
3756                     IntensityCompositeOp,MagickTrue,0,0,_exception);
3757                 }
3758               mask_image=DestroyImage(mask_image);
3759             }
3760           status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3761             geometry.x,geometry.y,_exception);
3762           source_image=DestroyImage(source_image);
3763           break;
3764         }
3765       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3766     }
3767     case 'd':
3768     {
3769       if (LocaleCompare("deconstruct",option+1) == 0)
3770         {
3771           CLIWandWarnReplaced("-layer CompareAny");
3772           CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3773           break;
3774         }
3775       if (LocaleCompare("delete",option+1) == 0)
3776         {
3777           if (IfNormalOp)
3778             DeleteImages(&_images,arg1,_exception);
3779           else
3780             DeleteImages(&_images,"-1",_exception);
3781           break;
3782         }
3783       if (LocaleCompare("duplicate",option+1) == 0)
3784         {
3785           if (IfNormalOp)
3786             {
3787               const char
3788                 *p;
3789
3790               size_t
3791                 number_duplicates;
3792
3793               if (IfMagickFalse(IsGeometry(arg1)))
3794                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3795                       arg1);
3796               number_duplicates=(size_t) StringToLong(arg1);
3797               p=strchr(arg1,',');
3798               if (p == (const char *) NULL)
3799                 new_images=DuplicateImages(_images,number_duplicates,"-1",
3800                   _exception);
3801               else
3802                 new_images=DuplicateImages(_images,number_duplicates,p,
3803                   _exception);
3804             }
3805           else
3806             new_images=DuplicateImages(_images,1,"-1",_exception);
3807           AppendImageToList(&_images, new_images);
3808           new_images=(Image *)NULL;
3809           break;
3810         }
3811       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3812     }
3813     case 'e':
3814     {
3815       if (LocaleCompare("evaluate-sequence",option+1) == 0)
3816         {
3817           parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3818           if (parse < 0)
3819             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3820               option,arg1);
3821           new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3822             _exception);
3823           break;
3824         }
3825       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3826     }
3827     case 'f':
3828     {
3829       if (LocaleCompare("fft",option+1) == 0)
3830         {
3831           new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception);
3832           break;
3833         }
3834       if (LocaleCompare("flatten",option+1) == 0)
3835         {
3836           /* REDIRECTED to use -layers flatten instead */
3837           CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3838           break;
3839         }
3840       if (LocaleCompare("fx",option+1) == 0)
3841         {
3842           new_images=FxImage(_images,arg1,_exception);
3843           break;
3844         }
3845       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3846     }
3847     case 'h':
3848     {
3849       if (LocaleCompare("hald-clut",option+1) == 0)
3850         {
3851           /* FUTURE - make this a compose option (and thus layers compose )
3852              or perhaps compose last image over all other _images.
3853           */
3854           Image
3855             *hald_image;
3856
3857           new_images=RemoveFirstImageFromList(&_images);
3858           hald_image=RemoveLastImageFromList(&_images);
3859           if (hald_image == (Image *) NULL)
3860             break;
3861           (void) HaldClutImage(new_images,hald_image,_exception);
3862           hald_image=DestroyImage(hald_image);
3863           break;
3864         }
3865       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3866     }
3867     case 'i':
3868     {
3869       if (LocaleCompare("ift",option+1) == 0)
3870         {
3871           Image
3872             *magnitude_image,
3873             *phase_image;
3874
3875            magnitude_image=RemoveFirstImageFromList(&_images);
3876            phase_image=RemoveFirstImageFromList(&_images);
3877           /* FUTURE - produce Exception, rather than silent fail */
3878            if (phase_image == (Image *) NULL)
3879              break;
3880            new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3881                    IsNormalOp,_exception);
3882            magnitude_image=DestroyImage(magnitude_image);
3883            phase_image=DestroyImage(phase_image);
3884           break;
3885         }
3886       if (LocaleCompare("insert",option+1) == 0)
3887         {
3888           Image
3889             *insert_image,
3890             *index_image;
3891
3892           ssize_t
3893             index;
3894
3895           if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3896             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3897           index=0;
3898           insert_image=RemoveLastImageFromList(&_images);
3899           if (IfNormalOp)
3900             index=(ssize_t) StringToLong(arg1);
3901           index_image=insert_image;
3902           if (index == 0)
3903             PrependImageToList(&_images,insert_image);
3904           else if (index == (ssize_t) GetImageListLength(_images))
3905             AppendImageToList(&_images,insert_image);
3906           else
3907             {
3908                index_image=GetImageFromList(_images,index-1);
3909                if (index_image == (Image *) NULL)
3910                  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3911               InsertImageInList(&index_image,insert_image);
3912             }
3913           _images=GetFirstImageInList(index_image);
3914           break;
3915         }
3916       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3917     }
3918     case 'l':
3919     {
3920       if (LocaleCompare("layers",option+1) == 0)
3921         {
3922           parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3923           if ( parse < 0 )
3924             CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3925                  option,arg1);
3926           switch ((LayerMethod) parse)
3927           {
3928             case CoalesceLayer:
3929             {
3930               new_images=CoalesceImages(_images,_exception);
3931               break;
3932             }
3933             case CompareAnyLayer:
3934             case CompareClearLayer:
3935             case CompareOverlayLayer:
3936             default:
3937             {
3938               new_images=CompareImagesLayers(_images,(LayerMethod) parse,
3939                    _exception);
3940               break;
3941             }
3942             case MergeLayer:
3943             case FlattenLayer:
3944             case MosaicLayer:
3945             case TrimBoundsLayer:
3946             {
3947               new_images=MergeImageLayers(_images,(LayerMethod) parse,
3948                    _exception);
3949               break;
3950             }
3951             case DisposeLayer:
3952             {
3953               new_images=DisposeImages(_images,_exception);
3954               break;
3955             }
3956             case OptimizeImageLayer:
3957             {
3958               new_images=OptimizeImageLayers(_images,_exception);
3959               break;
3960             }
3961             case OptimizePlusLayer:
3962             {
3963               new_images=OptimizePlusImageLayers(_images,_exception);
3964               break;
3965             }
3966             case OptimizeTransLayer:
3967             {
3968               OptimizeImageTransparency(_images,_exception);
3969               break;
3970             }
3971             case RemoveDupsLayer:
3972             {
3973               RemoveDuplicateLayers(&_images,_exception);
3974               break;
3975             }
3976             case RemoveZeroLayer:
3977             {
3978               RemoveZeroDelayLayers(&_images,_exception);
3979               break;
3980             }
3981             case OptimizeLayer:
3982             { /* General Purpose, GIF Animation Optimizer.  */
3983               new_images=CoalesceImages(_images,_exception);
3984               if (new_images == (Image *) NULL)
3985                 break;
3986               _images=DestroyImageList(_images);
3987               _images=OptimizeImageLayers(new_images,_exception);
3988               if (_images == (Image *) NULL)
3989                 break;
3990               new_images=DestroyImageList(new_images);
3991               OptimizeImageTransparency(_images,_exception);
3992               (void) RemapImages(_quantize_info,_images,(Image *) NULL,
3993                 _exception);
3994               break;
3995             }
3996             case CompositeLayer:
3997             {
3998               Image
3999                 *source;
4000
4001               RectangleInfo
4002                 geometry;
4003
4004               CompositeOperator
4005                 compose;
4006
4007               const char*
4008                 value;
4009
4010               value=GetImageOption(_image_info,"compose");
4011               compose=OverCompositeOp;  /* Default to Over */
4012               if (value != (const char *) NULL)
4013                 compose=(CompositeOperator) ParseCommandOption(
4014                       MagickComposeOptions,MagickFalse,value);
4015
4016               /* Split image sequence at the first 'NULL:' image. */
4017               source=_images;
4018               while (source != (Image *) NULL)
4019               {
4020                 source=GetNextImageInList(source);
4021                 if ((source != (Image *) NULL) &&
4022                     (LocaleCompare(source->magick,"NULL") == 0))
4023                   break;
4024               }
4025               if (source != (Image *) NULL)
4026                 {
4027                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4028                       (GetNextImageInList(source) == (Image *) NULL))
4029                     source=(Image *) NULL;
4030                   else
4031                     { /* Separate the two lists, junk the null: image.  */
4032                       source=SplitImageList(source->previous);
4033                       DeleteImageFromList(&source);
4034                     }
4035                 }
4036               if (source == (Image *) NULL)
4037                 {
4038                   (void) ThrowMagickException(_exception,GetMagickModule(),
4039                     OptionError,"MissingNullSeparator","layers Composite");
4040                   break;
4041                 }
4042               /* Adjust offset with gravity and virtual canvas.  */
4043               SetGeometry(_images,&geometry);
4044               (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4045               geometry.width=source->page.width != 0 ?
4046                 source->page.width : source->columns;
4047               geometry.height=source->page.height != 0 ?
4048                source->page.height : source->rows;
4049               GravityAdjustGeometry(_images->page.width != 0 ?
4050                 _images->page.width : _images->columns,
4051                 _images->page.height != 0 ? _images->page.height :
4052                 _images->rows,_images->gravity,&geometry);
4053
4054               /* Compose the two image sequences together */
4055               CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4056                 _exception);
4057               source=DestroyImageList(source);
4058               break;
4059             }
4060           }
4061           break;
4062         }
4063       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4064     }
4065     case 'm':
4066     {
4067       if (LocaleCompare("map",option+1) == 0)
4068         {
4069           CLIWandWarnReplaced("+remap");
4070           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4071           break;
4072         }
4073       if (LocaleCompare("metric",option+1) == 0)
4074         break;
4075       if (LocaleCompare("morph",option+1) == 0)
4076         {
4077           Image
4078             *morph_image;
4079
4080           if (IfMagickFalse(IsGeometry(arg1)))
4081             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4082           morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4083             _exception);
4084           if (morph_image == (Image *) NULL)
4085             break;
4086           _images=DestroyImageList(_images);
4087           _images=morph_image;
4088           break;
4089         }
4090       if (LocaleCompare("mosaic",option+1) == 0)
4091         {
4092           /* REDIRECTED to use -layers mosaic instead */
4093           CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4094           break;
4095         }
4096       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4097     }
4098     case 'p':
4099     {
4100       if (LocaleCompare("poly",option+1) == 0)
4101         {
4102           double
4103             *args;
4104
4105           ssize_t
4106             count;
4107
4108           /* convert argument string into an array of doubles */
4109           args = StringToArrayOfDoubles(arg2,&count,_exception);
4110           if (args == (double *)NULL )
4111             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4112           new_images=PolynomialImage(_images,count >> 1,args,_exception);
4113           args=(double *) RelinquishMagickMemory(args);
4114           break;
4115         }
4116       if (LocaleCompare("process",option+1) == 0)
4117         {
4118           /* FUTURE: better parsing using ScriptToken() from string ??? */
4119           char
4120             **arguments;
4121
4122           int
4123             j,
4124             number_arguments;
4125
4126           arguments=StringToArgv(arg1,&number_arguments);
4127           if (arguments == (char **) NULL)
4128             break;
4129           if (strchr(arguments[1],'=') != (char *) NULL)
4130             {
4131               char
4132                 breaker,
4133                 quote,
4134                 *token;
4135
4136               const char
4137                 *arguments;
4138
4139               int
4140                 next,
4141                 status;
4142
4143               size_t
4144                 length;
4145
4146               TokenInfo
4147                 *token_info;
4148
4149               /*
4150                 Support old style syntax, filter="-option arg1".
4151               */
4152               length=strlen(arg1);
4153               token=(char *) NULL;
4154               if (~length >= (MaxTextExtent-1))
4155                 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4156                   sizeof(*token));
4157               if (token == (char *) NULL)
4158                 break;
4159               next=0;
4160               arguments=arg1;
4161               token_info=AcquireTokenInfo();
4162               status=Tokenizer(token_info,0,token,length,arguments,"","=",
4163                 "\"",'\0',&breaker,&next,&quote);
4164               token_info=DestroyTokenInfo(token_info);
4165               if (status == 0)
4166                 {
4167                   const char
4168                     *argv;
4169
4170                   argv=(&(arguments[next]));
4171                   (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4172                     _exception);
4173                 }
4174               token=DestroyString(token);
4175               break;
4176             }
4177           (void) SubstituteString(&arguments[1],"-","");
4178           (void) InvokeDynamicImageFilter(arguments[1],&_images,
4179             number_arguments-2,(const char **) arguments+2,_exception);
4180           for (j=0; j < number_arguments; j++)
4181             arguments[j]=DestroyString(arguments[j]);
4182           arguments=(char **) RelinquishMagickMemory(arguments);
4183           break;
4184         }
4185       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4186     }
4187     case 'r':
4188     {
4189       if (LocaleCompare("remap",option+1) == 0)
4190         {
4191           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4192           break;
4193         }
4194       if (LocaleCompare("reverse",option+1) == 0)
4195         {
4196           ReverseImageList(&_images);
4197           break;
4198         }
4199       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4200     }
4201     case 's':
4202     {
4203       if (LocaleCompare("smush",option+1) == 0)
4204         {
4205           /* FUTURE: this option needs more work to make better */
4206           ssize_t
4207             offset;
4208
4209           if (IfMagickFalse(IsGeometry(arg1)))
4210             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4211           offset=(ssize_t) StringToLong(arg1);
4212           new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4213           break;
4214         }
4215       if (LocaleCompare("subimage",option+1) == 0)
4216         {
4217           Image
4218             *base_image,
4219             *compare_image;
4220
4221           const char *
4222             value;
4223
4224           MetricType
4225             metric;
4226
4227           double
4228             similarity;
4229
4230           RectangleInfo
4231             offset;
4232
4233           base_image=GetImageFromList(_images,0);
4234           compare_image=GetImageFromList(_images,1);
4235
4236           /* Comparision Metric */
4237           metric=UndefinedErrorMetric;
4238           value=GetImageOption(_image_info,"metric");
4239           if (value != (const char *) NULL)
4240             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4241               MagickFalse,value);
4242
4243           new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4244                &offset,&similarity,_exception);
4245
4246           if ( new_images != (Image *)NULL ) {
4247             char
4248               result[MaxTextExtent];
4249
4250             (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4251             (void) SetImageProperty(new_images,"subimage:similarity",result,
4252                  _exception);
4253             (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4254                 (long) offset.x);
4255             (void) SetImageProperty(new_images,"subimage:x",result,
4256                  _exception);
4257             (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4258                 (long) offset.y);
4259             (void) SetImageProperty(new_images,"subimage:y",result,
4260                  _exception);
4261             (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4262                 (unsigned long) offset.width,(unsigned long) offset.height,
4263                 (long) offset.x,(long) offset.y);
4264             (void) SetImageProperty(new_images,"subimage:offset",result,
4265                  _exception);
4266           }
4267           break;
4268         }
4269       if (LocaleCompare("swap",option+1) == 0) {
4270         Image
4271           *p,
4272           *q,
4273           *swap;
4274
4275         ssize_t
4276           index,
4277           swap_index;
4278
4279         index=(-1);
4280         swap_index=(-2);
4281         if (IfNormalOp) {
4282           GeometryInfo
4283             geometry_info;
4284
4285           MagickStatusType
4286             flags;
4287
4288           swap_index=(-1);
4289           flags=ParseGeometry(arg1,&geometry_info);
4290           if ((flags & RhoValue) == 0)
4291             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4292           index=(ssize_t) geometry_info.rho;
4293           if ((flags & SigmaValue) != 0)
4294             swap_index=(ssize_t) geometry_info.sigma;
4295         }
4296         p=GetImageFromList(_images,index);
4297         q=GetImageFromList(_images,swap_index);
4298         if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4299           if (IfNormalOp)
4300             CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4301           else
4302             CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4303         }
4304         if (p == q)
4305           CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4306         swap=CloneImage(p,0,0,MagickTrue,_exception);
4307         ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4308         ReplaceImageInList(&q,swap);
4309         _images=GetFirstImageInList(q);
4310         break;
4311       }
4312       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4313     }
4314     default:
4315       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4316   }
4317
4318   /* clean up percent escape interpreted strings */
4319   if (arg1 != arg1n )
4320     arg1=DestroyString((char *)arg1);
4321   if (arg2 != arg2n )
4322     arg2=DestroyString((char *)arg2);
4323
4324   /* if new image list generated, replace existing image list */
4325   if (new_images == (Image *) NULL)
4326     return(status == MagickFalse ? 0 : 1);
4327   _images=DestroyImageList(_images);
4328   _images=GetFirstImageInList(new_images);
4329   return(status == MagickFalse ? 0 : 1);
4330
4331 #undef _image_info
4332 #undef _images
4333 #undef _exception
4334 #undef _draw_info
4335 #undef _quantize_info
4336 #undef IfNormalOp
4337 #undef IfPlusOp
4338 #undef IsNormalOp
4339 }
4340 \f
4341 /*
4342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4343 %                                                                             %
4344 %                                                                             %
4345 %                                                                             %
4346 +   C L I N o I m a g e O p e r a t i o n s                                   %
4347 %                                                                             %
4348 %                                                                             %
4349 %                                                                             %
4350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4351 %
4352 %  CLINoImageOperator() Applies operations that may not actually need images
4353 %  in an image list.
4354 %
4355 %  The classic operators of this type is "-read", which actually creates
4356 %  images even when no images are present.  Or image stack operators, which
4357 %  can be applied (push or pop) to an empty image list.
4358 %
4359 %  Note that these operators may involve other special 'option' prefix
4360 %  characters other  than '-' or '+', namely parenthesis and braces.
4361 %
4362 %  The format of the CLINoImageOption method is:
4363 %
4364 %      void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4365 %           const char *arg1, const char *arg2)
4366 %
4367 %  A description of each parameter follows:
4368 %
4369 %    o cli_wand: the main CLI Wand to use. (sometimes not required)
4370 %
4371 %    o option: The special option (with any switch char) to process
4372 %
4373 %    o arg1 & arg2: Argument for option, if required
4374 %                   Currently arg2 is not used.
4375 %
4376 */
4377 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4378   const char *option,const char *arg1n,const char *arg2n)
4379 {
4380   const char    /* percent escaped versions of the args */
4381     *arg1,
4382     *arg2;
4383
4384 #define _image_info     (cli_wand->wand.image_info)
4385 #define _images         (cli_wand->wand.images)
4386 #define _exception      (cli_wand->wand.exception)
4387 #define _process_flags  (cli_wand->process_flags)
4388 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
4389 #define IfNormalOp      (*option=='-')
4390 #define IfPlusOp        (*option!='-')
4391
4392   assert(cli_wand != (MagickCLI *) NULL);
4393   assert(cli_wand->signature == WandSignature);
4394   assert(cli_wand->wand.signature == WandSignature);
4395
4396   if (IfMagickTrue(cli_wand->wand.debug))
4397     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4398          "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
4399
4400   arg1 = arg1n;
4401   arg2 = arg2n;
4402
4403   /* Interpret Percent Escapes in Arguments - using first image */
4404   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4405         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4406        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4407     /* Interpret Percent escapes in argument 1 */
4408     if (arg1n != (char *) NULL) {
4409       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4410       if (arg1 == (char *) NULL) {
4411         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4412         arg1=arg1n;  /* use the given argument as is */
4413       }
4414     }
4415     if (arg2n != (char *) NULL) {
4416       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4417       if (arg2 == (char *) NULL) {
4418         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4419         arg2=arg2n;  /* use the given argument as is */
4420       }
4421     }
4422   }
4423 #undef _process_flags
4424 #undef _option_type
4425
4426   do {  /* break to exit code */
4427     /*
4428       No-op options  (ignore these)
4429     */
4430     if (LocaleCompare("noop",option+1) == 0)   /* zero argument */
4431       break;
4432     if (LocaleCompare("sans",option+1) == 0)   /* one argument */
4433       break;
4434     if (LocaleCompare("sans0",option+1) == 0)  /* zero argument */
4435       break;
4436     if (LocaleCompare("sans1",option+1) == 0)  /* one argument */
4437       break;
4438     if (LocaleCompare("sans2",option+1) == 0)  /* two arguments */
4439       break;
4440     /*
4441       Image Reading
4442     */
4443     if ( ( LocaleCompare("read",option+1) == 0 ) ||
4444       ( LocaleCompare("--",option) == 0 ) ) {
4445       /* Do Glob filename Expansion for 'arg1' then read all images.
4446       *
4447       * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4448       * (but attaching to the filenames in the generated argument list) any
4449       * [...] read modifiers that may be present.
4450       *
4451       * For example: It will expand '*.gif[20x20]' into a list such as
4452       * 'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
4453       *
4454       * NOTE: In IMv6 this was done globally across all images. This
4455       * meant you could include IM options in '@filename' lists, but you
4456       * could not include comments.   Doing it only for image read makes
4457       * it far more secure.
4458       *
4459       * Note: arguments do not have percent escapes expanded for security
4460       * reasons.
4461       */
4462       int      argc;
4463       char     **argv;
4464       ssize_t  i;
4465
4466       argc = 1;
4467       argv = (char **) &arg1;
4468
4469       /* Expand 'glob' expressions in the given filename.
4470         Expansion handles any 'coder:' prefix, or read modifiers attached
4471         to the filename, including them in the resulting expanded list.
4472       */
4473       if (IfMagickFalse(  ExpandFilenames(&argc,&argv)  ))
4474         CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4475             option,GetExceptionMessage(errno));
4476
4477       /* loop over expanded filename list, and read then all in */
4478       for (i=0; i<argc; i++) {
4479         Image *
4480           new_images;
4481         if (IfMagickTrue(_image_info->ping))
4482           new_images=PingImages(_image_info,argv[i],_exception);
4483         else
4484           new_images=ReadImages(_image_info,argv[i],_exception);
4485         AppendImageToList(&_images, new_images);
4486       }
4487       argv=DestroyStringList(argv);  /* Destroy the Expanded Filename list */
4488       break;
4489     }
4490     /*
4491       Image Writing
4492       Note: Writing a empty image list is valid in specific cases
4493     */
4494     if (LocaleCompare("write",option+1) == 0) {
4495       /* Note: arguments do not have percent escapes expanded */
4496       char
4497         key[MaxTextExtent];
4498
4499       Image
4500         *write_images;
4501
4502       ImageInfo
4503         *write_info;
4504
4505       /* Need images, unless a "null:" output coder is used */
4506       if ( _images == (Image *) NULL ) {
4507         if ( LocaleCompare(arg1,"null:") == 0 )
4508           break;
4509         CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4510       }
4511
4512       (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4513       (void) DeleteImageRegistry(key);
4514       write_images=_images;
4515       if (IfPlusOp)
4516         write_images=CloneImageList(_images,_exception);
4517       write_info=CloneImageInfo(_image_info);
4518       (void) WriteImages(write_info,write_images,arg1,_exception);
4519       write_info=DestroyImageInfo(write_info);
4520       if (IfPlusOp)
4521         write_images=DestroyImageList(write_images);
4522       break;
4523     }
4524     /*
4525       Parenthesis and Brace operations
4526     */
4527     if (LocaleCompare("(",option) == 0) {
4528       /* stack 'push' images */
4529       Stack
4530         *node;
4531
4532       size_t
4533         size;
4534
4535       size=0;
4536       node=cli_wand->image_list_stack;
4537       for ( ; node != (Stack *)NULL; node=node->next)
4538         size++;
4539       if ( size >= MAX_STACK_DEPTH )
4540         CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4541       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4542       if (node == (Stack *) NULL)
4543         CLIWandExceptionBreak(ResourceLimitFatalError,
4544             "MemoryAllocationFailed",option);
4545       node->data = (void *)cli_wand->wand.images;
4546       node->next = cli_wand->image_list_stack;
4547       cli_wand->image_list_stack = node;
4548       cli_wand->wand.images = NewImageList();
4549
4550       /* handle respect-parenthesis */
4551       if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4552                     "respect-parenthesis"))))
4553         option="{"; /* fall-thru so as to push image settings too */
4554       else
4555         break;
4556       /* fall thru to operation */
4557     }
4558     if (LocaleCompare("{",option) == 0) {
4559       /* stack 'push' of image_info settings */
4560       Stack
4561         *node;
4562
4563       size_t
4564         size;
4565
4566       size=0;
4567       node=cli_wand->image_info_stack;
4568       for ( ; node != (Stack *)NULL; node=node->next)
4569         size++;
4570       if ( size >= MAX_STACK_DEPTH )
4571         CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4572       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4573       if (node == (Stack *) NULL)
4574         CLIWandExceptionBreak(ResourceLimitFatalError,
4575             "MemoryAllocationFailed",option);
4576
4577       node->data = (void *)cli_wand->wand.image_info;
4578       node->next = cli_wand->image_info_stack;
4579
4580       cli_wand->image_info_stack = node;
4581       cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4582       if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4583         CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4584             option);
4585         cli_wand->wand.image_info = (ImageInfo *)node->data;
4586         node = (Stack *)RelinquishMagickMemory(node);
4587         break;
4588       }
4589
4590       break;
4591     }
4592     if (LocaleCompare(")",option) == 0) {
4593       /* pop images from stack */
4594       Stack
4595         *node;
4596
4597       node = (Stack *)cli_wand->image_list_stack;
4598       if ( node == (Stack *)NULL)
4599         CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4600       cli_wand->image_list_stack = node->next;
4601
4602       AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4603       cli_wand->wand.images= (Image *)node->data;
4604       node = (Stack *)RelinquishMagickMemory(node);
4605
4606       /* handle respect-parenthesis - of the previous 'pushed' settings */
4607       node = cli_wand->image_info_stack;
4608       if ( node != (Stack *)NULL)
4609         {
4610           if (IfMagickTrue(IsStringTrue(GetImageOption(
4611                 cli_wand->wand.image_info,"respect-parenthesis"))))
4612             option="}"; /* fall-thru so as to pop image settings too */
4613           else
4614             break;
4615         }
4616       else
4617         break;
4618       /* fall thru to next if */
4619     }
4620     if (LocaleCompare("}",option) == 0) {
4621       /* pop image_info settings from stack */
4622       Stack
4623         *node;
4624
4625       node = (Stack *)cli_wand->image_info_stack;
4626       if ( node == (Stack *)NULL)
4627         CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4628       cli_wand->image_info_stack = node->next;
4629
4630       (void) DestroyImageInfo(cli_wand->wand.image_info);
4631       cli_wand->wand.image_info = (ImageInfo *)node->data;
4632       node = (Stack *)RelinquishMagickMemory(node);
4633
4634       GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4635       cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4636       cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4637
4638       break;
4639     }
4640       if (LocaleCompare("print",option+1) == 0)
4641         {
4642           (void) FormatLocaleFile(stdout,"%s",arg1);
4643           break;
4644         }
4645     if (LocaleCompare("set",option+1) == 0)
4646       {
4647         /* Settings are applied to each image in memory in turn (if any).
4648            While a option: only need to be applied once globally.
4649
4650            NOTE: rguments have not been automatically percent expaneded
4651         */
4652
4653         /* escape the 'key' once only, using first image. */
4654         arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4655         if (arg1 == (char *) NULL)
4656           CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4657                 option);
4658
4659         if (LocaleNCompare(arg1,"registry:",9) == 0)
4660           {
4661             if (IfPlusOp)
4662               {
4663                 (void) DeleteImageRegistry(arg1+9);
4664                 arg1=DestroyString((char *)arg1);
4665                 break;
4666               }
4667             arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4668             if (arg2 == (char *) NULL) {
4669               arg1=DestroyString((char *)arg1);
4670               CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4671                     option);
4672             }
4673             (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4674             arg1=DestroyString((char *)arg1);
4675             arg2=DestroyString((char *)arg2);
4676             break;
4677           }
4678         if (LocaleNCompare(arg1,"option:",7) == 0)
4679           {
4680             /* delete equivelent artifact from all images (if any) */
4681             if (_images != (Image *)NULL)
4682               {
4683                 MagickResetIterator(&cli_wand->wand);
4684                 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4685                   (void) DeleteImageArtifact(_images,arg1+7);
4686                 MagickResetIterator(&cli_wand->wand);
4687               }
4688             /* now set/delete the global option as needed */
4689             /* FUTURE: make escapes in a global 'option:' delayed */
4690             arg2=(char *)NULL;
4691             if (IfNormalOp)
4692               {
4693                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4694                 if (arg2 == (char *) NULL)
4695                   CLIWandExceptionBreak(OptionWarning,
4696                        "InterpretPropertyFailure",option);
4697               }
4698             (void) SetImageOption(_image_info,arg1+7,arg2);
4699             arg1=DestroyString((char *)arg1);
4700             arg2=DestroyString((char *)arg2);
4701             break;
4702           }
4703         /* Set Artifacts/Properties/Attributes all images (required) */
4704         if ( _images == (Image *) NULL )
4705           CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4706
4707         MagickResetIterator(&cli_wand->wand);
4708         while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4709           {
4710             arg2=(char *)NULL;
4711             if (IfNormalOp)
4712               {
4713                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4714                 if (arg2 == (char *) NULL)
4715                   CLIWandExceptionBreak(OptionWarning,
4716                        "InterpretPropertyFailure",option);
4717               }
4718             if (LocaleNCompare(arg1,"artifact:",9) == 0)
4719               (void) SetImageArtifact(_images,arg1+9,arg2);
4720             else if (LocaleNCompare(arg1,"property:",9) == 0)
4721               (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4722             else
4723               (void) SetImageProperty(_images,arg1,arg2,_exception);
4724             arg2=DestroyString((char *)arg2);
4725           }
4726         MagickResetIterator(&cli_wand->wand);
4727         arg1=DestroyString((char *)arg1);
4728         break;
4729      }
4730     if (LocaleCompare("clone",option+1) == 0) {
4731         Image
4732           *new_images;
4733
4734         if (*option == '+')
4735           arg1="-1";
4736         if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4737           CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4738         if ( cli_wand->image_list_stack == (Stack *)NULL)
4739           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4740         new_images = (Image *)cli_wand->image_list_stack->data;
4741         if (new_images == (Image *) NULL)
4742           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4743         new_images=CloneImages(new_images,arg1,_exception);
4744         if (new_images == (Image *) NULL)
4745           CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4746         AppendImageToList(&_images,new_images);
4747         break;
4748       }
4749     /*
4750        Informational Operations.
4751
4752        Note that these do not require either a cli-wand or images!
4753        Though currently a cli-wand much be provided regardless.
4754     */
4755     if (LocaleCompare("version",option+1) == 0)
4756       {
4757         ListMagickVersion(stdout);
4758         break;
4759       }
4760     if (LocaleCompare("list",option+1) == 0) {
4761       /*
4762          FUTURE: This 'switch' should really be part of MagickCore
4763       */
4764       ssize_t
4765         list;
4766
4767       list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4768       if ( list < 0 ) {
4769         CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4770         break;
4771       }
4772       switch (list)
4773       {
4774         case MagickCoderOptions:
4775         {
4776           (void) ListCoderInfo((FILE *) NULL,_exception);
4777           break;
4778         }
4779         case MagickColorOptions:
4780         {
4781           (void) ListColorInfo((FILE *) NULL,_exception);
4782           break;
4783         }
4784         case MagickConfigureOptions:
4785         {
4786           (void) ListConfigureInfo((FILE *) NULL,_exception);
4787           break;
4788         }
4789         case MagickDelegateOptions:
4790         {
4791           (void) ListDelegateInfo((FILE *) NULL,_exception);
4792           break;
4793         }
4794         case MagickFontOptions:
4795         {
4796           (void) ListTypeInfo((FILE *) NULL,_exception);
4797           break;
4798         }
4799         case MagickFormatOptions:
4800           (void) ListMagickInfo((FILE *) NULL,_exception);
4801           break;
4802         case MagickLocaleOptions:
4803           (void) ListLocaleInfo((FILE *) NULL,_exception);
4804           break;
4805         case MagickLogOptions:
4806           (void) ListLogInfo((FILE *) NULL,_exception);
4807           break;
4808         case MagickMagicOptions:
4809           (void) ListMagicInfo((FILE *) NULL,_exception);
4810           break;
4811         case MagickMimeOptions:
4812           (void) ListMimeInfo((FILE *) NULL,_exception);
4813           break;
4814         case MagickModuleOptions:
4815           (void) ListModuleInfo((FILE *) NULL,_exception);
4816           break;
4817         case MagickPolicyOptions:
4818           (void) ListPolicyInfo((FILE *) NULL,_exception);
4819           break;
4820         case MagickResourceOptions:
4821           (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4822           break;
4823         case MagickThresholdOptions:
4824           (void) ListThresholdMaps((FILE *) NULL,_exception);
4825           break;
4826         default:
4827           (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4828             _exception);
4829           break;
4830       }
4831       break;
4832     }
4833
4834     CLIWandException(OptionError,"UnrecognizedOption",option);
4835
4836   } while (0);  /* break to exit code. */
4837
4838   /* clean up percent escape interpreted strings */
4839   if (arg1 != arg1n )
4840     arg1=DestroyString((char *)arg1);
4841   if (arg2 != arg2n )
4842     arg2=DestroyString((char *)arg2);
4843
4844 #undef _image_info
4845 #undef _images
4846 #undef _exception
4847 #undef IfNormalOp
4848 #undef IfPlusOp
4849 }
4850 \f
4851 /*
4852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4853 %                                                                             %
4854 %                                                                             %
4855 %                                                                             %
4856 +   C L I O p t i o n                                                         %
4857 %                                                                             %
4858 %                                                                             %
4859 %                                                                             %
4860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861 %
4862 %  CLIOption() Processes the given option using the given CLI Magick Wand.
4863 %  The option arguments can be variable in number, though at this time no more
4864 %  that two is actually used by any option (this may change). Excess options
4865 %  are simply ignored.
4866 %
4867 %  If the cli_wand->command pointer is non-null, then it is assumed that the
4868 %  option has already been search for up from the CommandOptions[] table in
4869 %  "MagickCore/options.c" using  GetCommandOptionInfo().  If not set this
4870 %  routine will do the lookup instead. The pointer is reset afterward.
4871 %
4872 %  This action allows the caller to lookup and pre-handle any 'special'
4873 %  options, (such as implicit reads) before calling this general option
4874 %  handler to deal with 'standard' command line options.
4875 %
4876 %  The format of the CLIOption method is:
4877 %
4878 %       void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4879 %
4880 %  A description of each parameter follows:
4881 %
4882 %     o cli_wand: the main CLI Wand to use.
4883 %
4884 %     o option: The special option (with any switch char) to process
4885 %
4886 %     o args: any required arguments for an option (variable number)
4887 %
4888 %  Example Usage...
4889 %
4890 %    CLIoption(cli_wand,"-read","rose:");
4891 %    CLIoption(cli_wand,"-virtual-pixel","transparent");
4892 %    CLIoption(cli_wand,"-distort","SRT:","30");
4893 %    CLIoption(cli_wand,"-write","rotated_rose.png");
4894 %
4895 */
4896 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4897 {
4898   const char    /* extracted option args from args */
4899     *arg1,
4900     *arg2;
4901
4902   CommandOptionFlags
4903     option_type;
4904
4905   assert(cli_wand != (MagickCLI *) NULL);
4906   assert(cli_wand->signature == WandSignature);
4907   assert(cli_wand->wand.signature == WandSignature);
4908
4909   do { /* Break Code Block for error handling */
4910
4911     /* get information about option */
4912     if ( cli_wand->command == (const OptionInfo *) NULL )
4913       cli_wand->command = GetCommandOptionInfo(option);
4914 #if 0
4915       (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4916             option, cli_wand->command->mnemonic );
4917 #endif
4918     option_type=(CommandOptionFlags) cli_wand->command->flags;
4919
4920     if ( option_type == UndefinedOptionFlag )
4921       CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4922
4923     assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4924
4925     /* depreciated options */
4926     if ( (option_type & DeprecateOptionFlag) != 0 )
4927       CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4928
4929     /* options that this module does not handle */
4930     if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
4931       CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
4932
4933     /* Get argument strings from VarArgs
4934       How can you determine if enough arguments was supplied?
4935       What happens if not enough arguments were supplied?
4936     */
4937     { size_t
4938         count = cli_wand->command->type;
4939
4940       va_list
4941         operands;
4942
4943       va_start(operands,option);
4944
4945       arg1=arg2=NULL;
4946       if ( count >= 1 )
4947         arg1=(const char *) va_arg(operands, const char *);
4948       if ( count >= 2 )
4949         arg2=(const char *) va_arg(operands, const char *);
4950
4951       va_end(operands);
4952 #if 0
4953       (void) FormatLocaleFile(stderr,
4954         "CLIOption: \"%s\"  Count: %ld  Flags: %04x  Args: \"%s\" \"%s\"\n",
4955             option,(long) count,option_type,arg1,arg2);
4956 #endif
4957     }
4958
4959     /*
4960       Call the appropriate option handler
4961     */
4962
4963     /* FUTURE: this is temporary - get 'settings' to handle distribution of
4964       settings to images attributes,proprieties,artifacts */
4965     if ( cli_wand->wand.images != (Image *)NULL )
4966       SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
4967           cli_wand->wand.exception);
4968
4969     if ( (option_type & SettingOptionFlags) != 0 ) {
4970       CLISettingOptionInfo(cli_wand, option, arg1, arg2);
4971       // FUTURE: Sync Specific Settings into Image Properities (not global)
4972     }
4973
4974     /* Operators that do not need images - read, write, stack, clone */
4975     if ( (option_type & NoImageOperatorFlag) != 0)
4976       CLINoImageOperator(cli_wand, option, arg1, arg2);
4977
4978     /* FUTURE: The not a setting part below is a temporary hack due to
4979     * some options being both a Setting and a Simple operator.
4980     * Specifically -monitor, -depth, and  -colorspace */
4981     if ( cli_wand->wand.images == (Image *)NULL )
4982       if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
4983           ((option_type & SettingOptionFlags) == 0 ))  /* temp hack */
4984         CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
4985
4986     /* Operators which loop of individual images, simply */
4987     if ( (option_type & SimpleOperatorFlag) != 0 &&
4988          cli_wand->wand.images != (Image *)NULL) /* temp hack */
4989       CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
4990
4991     /* Operators that work on the image list as a whole */
4992     if ( (option_type & ListOperatorFlag) != 0 )
4993       CLIListOperatorImages(cli_wand, option, arg1, arg2);
4994
4995   } while (0);  /* end Break code block */
4996
4997   cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
4998 }