]> 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,(ComplexOperator) parse,_exception);
3674           break;
3675         }
3676       if (LocaleCompare("composite",option+1) == 0)
3677         {
3678           CompositeOperator
3679             compose;
3680
3681           const char*
3682             value;
3683
3684           MagickBooleanType
3685             clip_to_self;
3686
3687           Image
3688             *mask_image,
3689             *source_image;
3690
3691           RectangleInfo
3692             geometry;
3693
3694           /* Compose value from "-compose" option only */
3695           value=GetImageOption(_image_info,"compose");
3696           if (value == (const char *) NULL)
3697             compose=OverCompositeOp;  /* use Over not source_image->compose */
3698           else
3699             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3700               MagickFalse,value);
3701
3702           /* Get "clip-to-self" expert setting (false is normal) */
3703           value=GetImageOption(_image_info,"compose:clip-to-self");
3704           if (value == (const char *) NULL)
3705             clip_to_self=MagickTrue;
3706           else
3707             clip_to_self=IsStringTrue(GetImageOption(_image_info,
3708               "compose:clip-to-self")); /* if this is true */
3709           value=GetImageOption(_image_info,"compose:outside-overlay");
3710           if (value != (const char *) NULL) {   /* or this false */
3711             /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3712             clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3713           }
3714
3715           new_images=RemoveFirstImageFromList(&_images);
3716           source_image=RemoveFirstImageFromList(&_images);
3717           if (source_image == (Image *) NULL)
3718             break; /* FUTURE - produce Exception, rather than silent fail */
3719
3720           /* FUTURE - this should not be here! - should be part of -geometry */
3721           (void) TransformImage(&source_image,(char *) NULL,
3722             source_image->geometry,_exception);
3723           SetGeometry(source_image,&geometry);
3724           (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3725           GravityAdjustGeometry(new_images->columns,new_images->rows,
3726             new_images->gravity, &geometry);
3727           mask_image=RemoveFirstImageFromList(&_images);
3728           if (mask_image != (Image *) NULL)
3729             {
3730               if ((compose == DisplaceCompositeOp) ||
3731                   (compose == DistortCompositeOp))
3732                 status&=CompositeImage(source_image,mask_image,
3733                   CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3734               else
3735                 {
3736                   Image
3737                     *image;
3738
3739                   RectangleInfo
3740                     source_geometry;
3741
3742                   source_geometry.width=mask_image->columns;
3743                   source_geometry.height=mask_image->rows;
3744                   source_geometry.x=(-geometry.x);
3745                   source_geometry.y=(-geometry.y);
3746                   geometry.x=0;
3747                   geometry.y=0;
3748                   image=ExtentImage(source_image,&source_geometry,_exception);
3749                   if (image != (Image *) NULL)
3750                     {
3751                       source_image=DestroyImage(source_image);
3752                       source_image=image;
3753                     }
3754                   status&=CompositeImage(source_image,mask_image,
3755                     IntensityCompositeOp,MagickTrue,0,0,_exception);
3756                 }
3757               mask_image=DestroyImage(mask_image);
3758             }
3759           status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3760             geometry.x,geometry.y,_exception);
3761           source_image=DestroyImage(source_image);
3762           break;
3763         }
3764       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3765     }
3766     case 'd':
3767     {
3768       if (LocaleCompare("deconstruct",option+1) == 0)
3769         {
3770           CLIWandWarnReplaced("-layer CompareAny");
3771           CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3772           break;
3773         }
3774       if (LocaleCompare("delete",option+1) == 0)
3775         {
3776           if (IfNormalOp)
3777             DeleteImages(&_images,arg1,_exception);
3778           else
3779             DeleteImages(&_images,"-1",_exception);
3780           break;
3781         }
3782       if (LocaleCompare("duplicate",option+1) == 0)
3783         {
3784           if (IfNormalOp)
3785             {
3786               const char
3787                 *p;
3788
3789               size_t
3790                 number_duplicates;
3791
3792               if (IfMagickFalse(IsGeometry(arg1)))
3793                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3794                       arg1);
3795               number_duplicates=(size_t) StringToLong(arg1);
3796               p=strchr(arg1,',');
3797               if (p == (const char *) NULL)
3798                 new_images=DuplicateImages(_images,number_duplicates,"-1",
3799                   _exception);
3800               else
3801                 new_images=DuplicateImages(_images,number_duplicates,p,
3802                   _exception);
3803             }
3804           else
3805             new_images=DuplicateImages(_images,1,"-1",_exception);
3806           AppendImageToList(&_images, new_images);
3807           new_images=(Image *)NULL;
3808           break;
3809         }
3810       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3811     }
3812     case 'e':
3813     {
3814       if (LocaleCompare("evaluate-sequence",option+1) == 0)
3815         {
3816           parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3817           if (parse < 0)
3818             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3819               option,arg1);
3820           new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3821             _exception);
3822           break;
3823         }
3824       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3825     }
3826     case 'f':
3827     {
3828       if (LocaleCompare("fft",option+1) == 0)
3829         {
3830           new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception);
3831           break;
3832         }
3833       if (LocaleCompare("flatten",option+1) == 0)
3834         {
3835           /* REDIRECTED to use -layers flatten instead */
3836           CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3837           break;
3838         }
3839       if (LocaleCompare("fx",option+1) == 0)
3840         {
3841           new_images=FxImage(_images,arg1,_exception);
3842           break;
3843         }
3844       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3845     }
3846     case 'h':
3847     {
3848       if (LocaleCompare("hald-clut",option+1) == 0)
3849         {
3850           /* FUTURE - make this a compose option (and thus layers compose )
3851              or perhaps compose last image over all other _images.
3852           */
3853           Image
3854             *hald_image;
3855
3856           new_images=RemoveFirstImageFromList(&_images);
3857           hald_image=RemoveLastImageFromList(&_images);
3858           if (hald_image == (Image *) NULL)
3859             break;
3860           (void) HaldClutImage(new_images,hald_image,_exception);
3861           hald_image=DestroyImage(hald_image);
3862           break;
3863         }
3864       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3865     }
3866     case 'i':
3867     {
3868       if (LocaleCompare("ift",option+1) == 0)
3869         {
3870           Image
3871             *magnitude_image,
3872             *phase_image;
3873
3874            magnitude_image=RemoveFirstImageFromList(&_images);
3875            phase_image=RemoveFirstImageFromList(&_images);
3876           /* FUTURE - produce Exception, rather than silent fail */
3877            if (phase_image == (Image *) NULL)
3878              break;
3879            new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3880                    IsNormalOp,_exception);
3881            magnitude_image=DestroyImage(magnitude_image);
3882            phase_image=DestroyImage(phase_image);
3883           break;
3884         }
3885       if (LocaleCompare("insert",option+1) == 0)
3886         {
3887           Image
3888             *insert_image,
3889             *index_image;
3890
3891           ssize_t
3892             index;
3893
3894           if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3895             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3896           index=0;
3897           insert_image=RemoveLastImageFromList(&_images);
3898           if (IfNormalOp)
3899             index=(ssize_t) StringToLong(arg1);
3900           index_image=insert_image;
3901           if (index == 0)
3902             PrependImageToList(&_images,insert_image);
3903           else if (index == (ssize_t) GetImageListLength(_images))
3904             AppendImageToList(&_images,insert_image);
3905           else
3906             {
3907                index_image=GetImageFromList(_images,index-1);
3908                if (index_image == (Image *) NULL)
3909                  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3910               InsertImageInList(&index_image,insert_image);
3911             }
3912           _images=GetFirstImageInList(index_image);
3913           break;
3914         }
3915       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3916     }
3917     case 'l':
3918     {
3919       if (LocaleCompare("layers",option+1) == 0)
3920         {
3921           parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3922           if ( parse < 0 )
3923             CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3924                  option,arg1);
3925           switch ((LayerMethod) parse)
3926           {
3927             case CoalesceLayer:
3928             {
3929               new_images=CoalesceImages(_images,_exception);
3930               break;
3931             }
3932             case CompareAnyLayer:
3933             case CompareClearLayer:
3934             case CompareOverlayLayer:
3935             default:
3936             {
3937               new_images=CompareImagesLayers(_images,(LayerMethod) parse,
3938                    _exception);
3939               break;
3940             }
3941             case MergeLayer:
3942             case FlattenLayer:
3943             case MosaicLayer:
3944             case TrimBoundsLayer:
3945             {
3946               new_images=MergeImageLayers(_images,(LayerMethod) parse,
3947                    _exception);
3948               break;
3949             }
3950             case DisposeLayer:
3951             {
3952               new_images=DisposeImages(_images,_exception);
3953               break;
3954             }
3955             case OptimizeImageLayer:
3956             {
3957               new_images=OptimizeImageLayers(_images,_exception);
3958               break;
3959             }
3960             case OptimizePlusLayer:
3961             {
3962               new_images=OptimizePlusImageLayers(_images,_exception);
3963               break;
3964             }
3965             case OptimizeTransLayer:
3966             {
3967               OptimizeImageTransparency(_images,_exception);
3968               break;
3969             }
3970             case RemoveDupsLayer:
3971             {
3972               RemoveDuplicateLayers(&_images,_exception);
3973               break;
3974             }
3975             case RemoveZeroLayer:
3976             {
3977               RemoveZeroDelayLayers(&_images,_exception);
3978               break;
3979             }
3980             case OptimizeLayer:
3981             { /* General Purpose, GIF Animation Optimizer.  */
3982               new_images=CoalesceImages(_images,_exception);
3983               if (new_images == (Image *) NULL)
3984                 break;
3985               _images=DestroyImageList(_images);
3986               _images=OptimizeImageLayers(new_images,_exception);
3987               if (_images == (Image *) NULL)
3988                 break;
3989               new_images=DestroyImageList(new_images);
3990               OptimizeImageTransparency(_images,_exception);
3991               (void) RemapImages(_quantize_info,_images,(Image *) NULL,
3992                 _exception);
3993               break;
3994             }
3995             case CompositeLayer:
3996             {
3997               Image
3998                 *source;
3999
4000               RectangleInfo
4001                 geometry;
4002
4003               CompositeOperator
4004                 compose;
4005
4006               const char*
4007                 value;
4008
4009               value=GetImageOption(_image_info,"compose");
4010               compose=OverCompositeOp;  /* Default to Over */
4011               if (value != (const char *) NULL)
4012                 compose=(CompositeOperator) ParseCommandOption(
4013                       MagickComposeOptions,MagickFalse,value);
4014
4015               /* Split image sequence at the first 'NULL:' image. */
4016               source=_images;
4017               while (source != (Image *) NULL)
4018               {
4019                 source=GetNextImageInList(source);
4020                 if ((source != (Image *) NULL) &&
4021                     (LocaleCompare(source->magick,"NULL") == 0))
4022                   break;
4023               }
4024               if (source != (Image *) NULL)
4025                 {
4026                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4027                       (GetNextImageInList(source) == (Image *) NULL))
4028                     source=(Image *) NULL;
4029                   else
4030                     { /* Separate the two lists, junk the null: image.  */
4031                       source=SplitImageList(source->previous);
4032                       DeleteImageFromList(&source);
4033                     }
4034                 }
4035               if (source == (Image *) NULL)
4036                 {
4037                   (void) ThrowMagickException(_exception,GetMagickModule(),
4038                     OptionError,"MissingNullSeparator","layers Composite");
4039                   break;
4040                 }
4041               /* Adjust offset with gravity and virtual canvas.  */
4042               SetGeometry(_images,&geometry);
4043               (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4044               geometry.width=source->page.width != 0 ?
4045                 source->page.width : source->columns;
4046               geometry.height=source->page.height != 0 ?
4047                source->page.height : source->rows;
4048               GravityAdjustGeometry(_images->page.width != 0 ?
4049                 _images->page.width : _images->columns,
4050                 _images->page.height != 0 ? _images->page.height :
4051                 _images->rows,_images->gravity,&geometry);
4052
4053               /* Compose the two image sequences together */
4054               CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4055                 _exception);
4056               source=DestroyImageList(source);
4057               break;
4058             }
4059           }
4060           break;
4061         }
4062       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4063     }
4064     case 'm':
4065     {
4066       if (LocaleCompare("map",option+1) == 0)
4067         {
4068           CLIWandWarnReplaced("+remap");
4069           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4070           break;
4071         }
4072       if (LocaleCompare("metric",option+1) == 0)
4073         break;
4074       if (LocaleCompare("morph",option+1) == 0)
4075         {
4076           Image
4077             *morph_image;
4078
4079           if (IfMagickFalse(IsGeometry(arg1)))
4080             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4081           morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4082             _exception);
4083           if (morph_image == (Image *) NULL)
4084             break;
4085           _images=DestroyImageList(_images);
4086           _images=morph_image;
4087           break;
4088         }
4089       if (LocaleCompare("mosaic",option+1) == 0)
4090         {
4091           /* REDIRECTED to use -layers mosaic instead */
4092           CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4093           break;
4094         }
4095       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4096     }
4097     case 'p':
4098     {
4099       if (LocaleCompare("poly",option+1) == 0)
4100         {
4101           double
4102             *args;
4103
4104           ssize_t
4105             count;
4106
4107           /* convert argument string into an array of doubles */
4108           args = StringToArrayOfDoubles(arg2,&count,_exception);
4109           if (args == (double *)NULL )
4110             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4111           new_images=PolynomialImage(_images,count >> 1,args,_exception);
4112           args=(double *) RelinquishMagickMemory(args);
4113           break;
4114         }
4115       if (LocaleCompare("process",option+1) == 0)
4116         {
4117           /* FUTURE: better parsing using ScriptToken() from string ??? */
4118           char
4119             **arguments;
4120
4121           int
4122             j,
4123             number_arguments;
4124
4125           arguments=StringToArgv(arg1,&number_arguments);
4126           if (arguments == (char **) NULL)
4127             break;
4128           if (strchr(arguments[1],'=') != (char *) NULL)
4129             {
4130               char
4131                 breaker,
4132                 quote,
4133                 *token;
4134
4135               const char
4136                 *arguments;
4137
4138               int
4139                 next,
4140                 status;
4141
4142               size_t
4143                 length;
4144
4145               TokenInfo
4146                 *token_info;
4147
4148               /*
4149                 Support old style syntax, filter="-option arg1".
4150               */
4151               length=strlen(arg1);
4152               token=(char *) NULL;
4153               if (~length >= (MaxTextExtent-1))
4154                 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4155                   sizeof(*token));
4156               if (token == (char *) NULL)
4157                 break;
4158               next=0;
4159               arguments=arg1;
4160               token_info=AcquireTokenInfo();
4161               status=Tokenizer(token_info,0,token,length,arguments,"","=",
4162                 "\"",'\0',&breaker,&next,&quote);
4163               token_info=DestroyTokenInfo(token_info);
4164               if (status == 0)
4165                 {
4166                   const char
4167                     *argv;
4168
4169                   argv=(&(arguments[next]));
4170                   (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4171                     _exception);
4172                 }
4173               token=DestroyString(token);
4174               break;
4175             }
4176           (void) SubstituteString(&arguments[1],"-","");
4177           (void) InvokeDynamicImageFilter(arguments[1],&_images,
4178             number_arguments-2,(const char **) arguments+2,_exception);
4179           for (j=0; j < number_arguments; j++)
4180             arguments[j]=DestroyString(arguments[j]);
4181           arguments=(char **) RelinquishMagickMemory(arguments);
4182           break;
4183         }
4184       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4185     }
4186     case 'r':
4187     {
4188       if (LocaleCompare("remap",option+1) == 0)
4189         {
4190           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4191           break;
4192         }
4193       if (LocaleCompare("reverse",option+1) == 0)
4194         {
4195           ReverseImageList(&_images);
4196           break;
4197         }
4198       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4199     }
4200     case 's':
4201     {
4202       if (LocaleCompare("smush",option+1) == 0)
4203         {
4204           /* FUTURE: this option needs more work to make better */
4205           ssize_t
4206             offset;
4207
4208           if (IfMagickFalse(IsGeometry(arg1)))
4209             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4210           offset=(ssize_t) StringToLong(arg1);
4211           new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4212           break;
4213         }
4214       if (LocaleCompare("subimage",option+1) == 0)
4215         {
4216           Image
4217             *base_image,
4218             *compare_image;
4219
4220           const char *
4221             value;
4222
4223           MetricType
4224             metric;
4225
4226           double
4227             similarity;
4228
4229           RectangleInfo
4230             offset;
4231
4232           base_image=GetImageFromList(_images,0);
4233           compare_image=GetImageFromList(_images,1);
4234
4235           /* Comparision Metric */
4236           metric=UndefinedErrorMetric;
4237           value=GetImageOption(_image_info,"metric");
4238           if (value != (const char *) NULL)
4239             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4240               MagickFalse,value);
4241
4242           new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4243                &offset,&similarity,_exception);
4244
4245           if ( new_images != (Image *)NULL ) {
4246             char
4247               result[MaxTextExtent];
4248
4249             (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4250             (void) SetImageProperty(new_images,"subimage:similarity",result,
4251                  _exception);
4252             (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4253                 (long) offset.x);
4254             (void) SetImageProperty(new_images,"subimage:x",result,
4255                  _exception);
4256             (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4257                 (long) offset.y);
4258             (void) SetImageProperty(new_images,"subimage:y",result,
4259                  _exception);
4260             (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4261                 (unsigned long) offset.width,(unsigned long) offset.height,
4262                 (long) offset.x,(long) offset.y);
4263             (void) SetImageProperty(new_images,"subimage:offset",result,
4264                  _exception);
4265           }
4266           break;
4267         }
4268       if (LocaleCompare("swap",option+1) == 0) {
4269         Image
4270           *p,
4271           *q,
4272           *swap;
4273
4274         ssize_t
4275           index,
4276           swap_index;
4277
4278         index=(-1);
4279         swap_index=(-2);
4280         if (IfNormalOp) {
4281           GeometryInfo
4282             geometry_info;
4283
4284           MagickStatusType
4285             flags;
4286
4287           swap_index=(-1);
4288           flags=ParseGeometry(arg1,&geometry_info);
4289           if ((flags & RhoValue) == 0)
4290             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4291           index=(ssize_t) geometry_info.rho;
4292           if ((flags & SigmaValue) != 0)
4293             swap_index=(ssize_t) geometry_info.sigma;
4294         }
4295         p=GetImageFromList(_images,index);
4296         q=GetImageFromList(_images,swap_index);
4297         if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4298           if (IfNormalOp)
4299             CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4300           else
4301             CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4302         }
4303         if (p == q)
4304           CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4305         swap=CloneImage(p,0,0,MagickTrue,_exception);
4306         ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4307         ReplaceImageInList(&q,swap);
4308         _images=GetFirstImageInList(q);
4309         break;
4310       }
4311       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4312     }
4313     default:
4314       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4315   }
4316
4317   /* clean up percent escape interpreted strings */
4318   if (arg1 != arg1n )
4319     arg1=DestroyString((char *)arg1);
4320   if (arg2 != arg2n )
4321     arg2=DestroyString((char *)arg2);
4322
4323   /* if new image list generated, replace existing image list */
4324   if (new_images == (Image *) NULL)
4325     return(status == MagickFalse ? 0 : 1);
4326   _images=DestroyImageList(_images);
4327   _images=GetFirstImageInList(new_images);
4328   return(status == MagickFalse ? 0 : 1);
4329
4330 #undef _image_info
4331 #undef _images
4332 #undef _exception
4333 #undef _draw_info
4334 #undef _quantize_info
4335 #undef IfNormalOp
4336 #undef IfPlusOp
4337 #undef IsNormalOp
4338 }
4339 \f
4340 /*
4341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4342 %                                                                             %
4343 %                                                                             %
4344 %                                                                             %
4345 +   C L I N o I m a g e O p e r a t i o n s                                   %
4346 %                                                                             %
4347 %                                                                             %
4348 %                                                                             %
4349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4350 %
4351 %  CLINoImageOperator() Applies operations that may not actually need images
4352 %  in an image list.
4353 %
4354 %  The classic operators of this type is "-read", which actually creates
4355 %  images even when no images are present.  Or image stack operators, which
4356 %  can be applied (push or pop) to an empty image list.
4357 %
4358 %  Note that these operators may involve other special 'option' prefix
4359 %  characters other  than '-' or '+', namely parenthesis and braces.
4360 %
4361 %  The format of the CLINoImageOption method is:
4362 %
4363 %      void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4364 %           const char *arg1, const char *arg2)
4365 %
4366 %  A description of each parameter follows:
4367 %
4368 %    o cli_wand: the main CLI Wand to use. (sometimes not required)
4369 %
4370 %    o option: The special option (with any switch char) to process
4371 %
4372 %    o arg1 & arg2: Argument for option, if required
4373 %                   Currently arg2 is not used.
4374 %
4375 */
4376 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4377   const char *option,const char *arg1n,const char *arg2n)
4378 {
4379   const char    /* percent escaped versions of the args */
4380     *arg1,
4381     *arg2;
4382
4383 #define _image_info     (cli_wand->wand.image_info)
4384 #define _images         (cli_wand->wand.images)
4385 #define _exception      (cli_wand->wand.exception)
4386 #define _process_flags  (cli_wand->process_flags)
4387 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
4388 #define IfNormalOp      (*option=='-')
4389 #define IfPlusOp        (*option!='-')
4390
4391   assert(cli_wand != (MagickCLI *) NULL);
4392   assert(cli_wand->signature == WandSignature);
4393   assert(cli_wand->wand.signature == WandSignature);
4394
4395   if (IfMagickTrue(cli_wand->wand.debug))
4396     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4397          "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
4398
4399   arg1 = arg1n;
4400   arg2 = arg2n;
4401
4402   /* Interpret Percent Escapes in Arguments - using first image */
4403   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4404         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4405        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4406     /* Interpret Percent escapes in argument 1 */
4407     if (arg1n != (char *) NULL) {
4408       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4409       if (arg1 == (char *) NULL) {
4410         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4411         arg1=arg1n;  /* use the given argument as is */
4412       }
4413     }
4414     if (arg2n != (char *) NULL) {
4415       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4416       if (arg2 == (char *) NULL) {
4417         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4418         arg2=arg2n;  /* use the given argument as is */
4419       }
4420     }
4421   }
4422 #undef _process_flags
4423 #undef _option_type
4424
4425   do {  /* break to exit code */
4426     /*
4427       No-op options  (ignore these)
4428     */
4429     if (LocaleCompare("noop",option+1) == 0)   /* zero argument */
4430       break;
4431     if (LocaleCompare("sans",option+1) == 0)   /* one argument */
4432       break;
4433     if (LocaleCompare("sans0",option+1) == 0)  /* zero argument */
4434       break;
4435     if (LocaleCompare("sans1",option+1) == 0)  /* one argument */
4436       break;
4437     if (LocaleCompare("sans2",option+1) == 0)  /* two arguments */
4438       break;
4439     /*
4440       Image Reading
4441     */
4442     if ( ( LocaleCompare("read",option+1) == 0 ) ||
4443       ( LocaleCompare("--",option) == 0 ) ) {
4444       /* Do Glob filename Expansion for 'arg1' then read all images.
4445       *
4446       * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4447       * (but attaching to the filenames in the generated argument list) any
4448       * [...] read modifiers that may be present.
4449       *
4450       * For example: It will expand '*.gif[20x20]' into a list such as
4451       * 'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
4452       *
4453       * NOTE: In IMv6 this was done globally across all images. This
4454       * meant you could include IM options in '@filename' lists, but you
4455       * could not include comments.   Doing it only for image read makes
4456       * it far more secure.
4457       *
4458       * Note: arguments do not have percent escapes expanded for security
4459       * reasons.
4460       */
4461       int      argc;
4462       char     **argv;
4463       ssize_t  i;
4464
4465       argc = 1;
4466       argv = (char **) &arg1;
4467
4468       /* Expand 'glob' expressions in the given filename.
4469         Expansion handles any 'coder:' prefix, or read modifiers attached
4470         to the filename, including them in the resulting expanded list.
4471       */
4472       if (IfMagickFalse(  ExpandFilenames(&argc,&argv)  ))
4473         CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4474             option,GetExceptionMessage(errno));
4475
4476       /* loop over expanded filename list, and read then all in */
4477       for (i=0; i<argc; i++) {
4478         Image *
4479           new_images;
4480         if (IfMagickTrue(_image_info->ping))
4481           new_images=PingImages(_image_info,argv[i],_exception);
4482         else
4483           new_images=ReadImages(_image_info,argv[i],_exception);
4484         AppendImageToList(&_images, new_images);
4485       }
4486       argv=DestroyStringList(argv);  /* Destroy the Expanded Filename list */
4487       break;
4488     }
4489     /*
4490       Image Writing
4491       Note: Writing a empty image list is valid in specific cases
4492     */
4493     if (LocaleCompare("write",option+1) == 0) {
4494       /* Note: arguments do not have percent escapes expanded */
4495       char
4496         key[MaxTextExtent];
4497
4498       Image
4499         *write_images;
4500
4501       ImageInfo
4502         *write_info;
4503
4504       /* Need images, unless a "null:" output coder is used */
4505       if ( _images == (Image *) NULL ) {
4506         if ( LocaleCompare(arg1,"null:") == 0 )
4507           break;
4508         CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4509       }
4510
4511       (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4512       (void) DeleteImageRegistry(key);
4513       write_images=_images;
4514       if (IfPlusOp)
4515         write_images=CloneImageList(_images,_exception);
4516       write_info=CloneImageInfo(_image_info);
4517       (void) WriteImages(write_info,write_images,arg1,_exception);
4518       write_info=DestroyImageInfo(write_info);
4519       if (IfPlusOp)
4520         write_images=DestroyImageList(write_images);
4521       break;
4522     }
4523     /*
4524       Parenthesis and Brace operations
4525     */
4526     if (LocaleCompare("(",option) == 0) {
4527       /* stack 'push' images */
4528       Stack
4529         *node;
4530
4531       size_t
4532         size;
4533
4534       size=0;
4535       node=cli_wand->image_list_stack;
4536       for ( ; node != (Stack *)NULL; node=node->next)
4537         size++;
4538       if ( size >= MAX_STACK_DEPTH )
4539         CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4540       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4541       if (node == (Stack *) NULL)
4542         CLIWandExceptionBreak(ResourceLimitFatalError,
4543             "MemoryAllocationFailed",option);
4544       node->data = (void *)cli_wand->wand.images;
4545       node->next = cli_wand->image_list_stack;
4546       cli_wand->image_list_stack = node;
4547       cli_wand->wand.images = NewImageList();
4548
4549       /* handle respect-parenthesis */
4550       if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4551                     "respect-parenthesis"))))
4552         option="{"; /* fall-thru so as to push image settings too */
4553       else
4554         break;
4555       /* fall thru to operation */
4556     }
4557     if (LocaleCompare("{",option) == 0) {
4558       /* stack 'push' of image_info settings */
4559       Stack
4560         *node;
4561
4562       size_t
4563         size;
4564
4565       size=0;
4566       node=cli_wand->image_info_stack;
4567       for ( ; node != (Stack *)NULL; node=node->next)
4568         size++;
4569       if ( size >= MAX_STACK_DEPTH )
4570         CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4571       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4572       if (node == (Stack *) NULL)
4573         CLIWandExceptionBreak(ResourceLimitFatalError,
4574             "MemoryAllocationFailed",option);
4575
4576       node->data = (void *)cli_wand->wand.image_info;
4577       node->next = cli_wand->image_info_stack;
4578
4579       cli_wand->image_info_stack = node;
4580       cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4581       if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4582         CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4583             option);
4584         cli_wand->wand.image_info = (ImageInfo *)node->data;
4585         node = (Stack *)RelinquishMagickMemory(node);
4586         break;
4587       }
4588
4589       break;
4590     }
4591     if (LocaleCompare(")",option) == 0) {
4592       /* pop images from stack */
4593       Stack
4594         *node;
4595
4596       node = (Stack *)cli_wand->image_list_stack;
4597       if ( node == (Stack *)NULL)
4598         CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4599       cli_wand->image_list_stack = node->next;
4600
4601       AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4602       cli_wand->wand.images= (Image *)node->data;
4603       node = (Stack *)RelinquishMagickMemory(node);
4604
4605       /* handle respect-parenthesis - of the previous 'pushed' settings */
4606       node = cli_wand->image_info_stack;
4607       if ( node != (Stack *)NULL)
4608         {
4609           if (IfMagickTrue(IsStringTrue(GetImageOption(
4610                 cli_wand->wand.image_info,"respect-parenthesis"))))
4611             option="}"; /* fall-thru so as to pop image settings too */
4612           else
4613             break;
4614         }
4615       else
4616         break;
4617       /* fall thru to next if */
4618     }
4619     if (LocaleCompare("}",option) == 0) {
4620       /* pop image_info settings from stack */
4621       Stack
4622         *node;
4623
4624       node = (Stack *)cli_wand->image_info_stack;
4625       if ( node == (Stack *)NULL)
4626         CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4627       cli_wand->image_info_stack = node->next;
4628
4629       (void) DestroyImageInfo(cli_wand->wand.image_info);
4630       cli_wand->wand.image_info = (ImageInfo *)node->data;
4631       node = (Stack *)RelinquishMagickMemory(node);
4632
4633       GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4634       cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4635       cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4636
4637       break;
4638     }
4639       if (LocaleCompare("print",option+1) == 0)
4640         {
4641           (void) FormatLocaleFile(stdout,"%s",arg1);
4642           break;
4643         }
4644     if (LocaleCompare("set",option+1) == 0)
4645       {
4646         /* Settings are applied to each image in memory in turn (if any).
4647            While a option: only need to be applied once globally.
4648
4649            NOTE: rguments have not been automatically percent expaneded
4650         */
4651
4652         /* escape the 'key' once only, using first image. */
4653         arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4654         if (arg1 == (char *) NULL)
4655           CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4656                 option);
4657
4658         if (LocaleNCompare(arg1,"registry:",9) == 0)
4659           {
4660             if (IfPlusOp)
4661               {
4662                 (void) DeleteImageRegistry(arg1+9);
4663                 arg1=DestroyString((char *)arg1);
4664                 break;
4665               }
4666             arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4667             if (arg2 == (char *) NULL) {
4668               arg1=DestroyString((char *)arg1);
4669               CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4670                     option);
4671             }
4672             (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4673             arg1=DestroyString((char *)arg1);
4674             arg2=DestroyString((char *)arg2);
4675             break;
4676           }
4677         if (LocaleNCompare(arg1,"option:",7) == 0)
4678           {
4679             /* delete equivelent artifact from all images (if any) */
4680             if (_images != (Image *)NULL)
4681               {
4682                 MagickResetIterator(&cli_wand->wand);
4683                 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4684                   (void) DeleteImageArtifact(_images,arg1+7);
4685                 MagickResetIterator(&cli_wand->wand);
4686               }
4687             /* now set/delete the global option as needed */
4688             /* FUTURE: make escapes in a global 'option:' delayed */
4689             arg2=(char *)NULL;
4690             if (IfNormalOp)
4691               {
4692                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4693                 if (arg2 == (char *) NULL)
4694                   CLIWandExceptionBreak(OptionWarning,
4695                        "InterpretPropertyFailure",option);
4696               }
4697             (void) SetImageOption(_image_info,arg1+7,arg2);
4698             arg1=DestroyString((char *)arg1);
4699             arg2=DestroyString((char *)arg2);
4700             break;
4701           }
4702         /* Set Artifacts/Properties/Attributes all images (required) */
4703         if ( _images == (Image *) NULL )
4704           CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4705
4706         MagickResetIterator(&cli_wand->wand);
4707         while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4708           {
4709             arg2=(char *)NULL;
4710             if (IfNormalOp)
4711               {
4712                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4713                 if (arg2 == (char *) NULL)
4714                   CLIWandExceptionBreak(OptionWarning,
4715                        "InterpretPropertyFailure",option);
4716               }
4717             if (LocaleNCompare(arg1,"artifact:",9) == 0)
4718               (void) SetImageArtifact(_images,arg1+9,arg2);
4719             else if (LocaleNCompare(arg1,"property:",9) == 0)
4720               (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4721             else
4722               (void) SetImageProperty(_images,arg1,arg2,_exception);
4723             arg2=DestroyString((char *)arg2);
4724           }
4725         MagickResetIterator(&cli_wand->wand);
4726         arg1=DestroyString((char *)arg1);
4727         break;
4728      }
4729     if (LocaleCompare("clone",option+1) == 0) {
4730         Image
4731           *new_images;
4732
4733         if (*option == '+')
4734           arg1="-1";
4735         if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4736           CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4737         if ( cli_wand->image_list_stack == (Stack *)NULL)
4738           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4739         new_images = (Image *)cli_wand->image_list_stack->data;
4740         if (new_images == (Image *) NULL)
4741           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4742         new_images=CloneImages(new_images,arg1,_exception);
4743         if (new_images == (Image *) NULL)
4744           CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4745         AppendImageToList(&_images,new_images);
4746         break;
4747       }
4748     /*
4749        Informational Operations.
4750
4751        Note that these do not require either a cli-wand or images!
4752        Though currently a cli-wand much be provided regardless.
4753     */
4754     if (LocaleCompare("version",option+1) == 0)
4755       {
4756         ListMagickVersion(stdout);
4757         break;
4758       }
4759     if (LocaleCompare("list",option+1) == 0) {
4760       /*
4761          FUTURE: This 'switch' should really be part of MagickCore
4762       */
4763       ssize_t
4764         list;
4765
4766       list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4767       if ( list < 0 ) {
4768         CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4769         break;
4770       }
4771       switch (list)
4772       {
4773         case MagickCoderOptions:
4774         {
4775           (void) ListCoderInfo((FILE *) NULL,_exception);
4776           break;
4777         }
4778         case MagickColorOptions:
4779         {
4780           (void) ListColorInfo((FILE *) NULL,_exception);
4781           break;
4782         }
4783         case MagickConfigureOptions:
4784         {
4785           (void) ListConfigureInfo((FILE *) NULL,_exception);
4786           break;
4787         }
4788         case MagickDelegateOptions:
4789         {
4790           (void) ListDelegateInfo((FILE *) NULL,_exception);
4791           break;
4792         }
4793         case MagickFontOptions:
4794         {
4795           (void) ListTypeInfo((FILE *) NULL,_exception);
4796           break;
4797         }
4798         case MagickFormatOptions:
4799           (void) ListMagickInfo((FILE *) NULL,_exception);
4800           break;
4801         case MagickLocaleOptions:
4802           (void) ListLocaleInfo((FILE *) NULL,_exception);
4803           break;
4804         case MagickLogOptions:
4805           (void) ListLogInfo((FILE *) NULL,_exception);
4806           break;
4807         case MagickMagicOptions:
4808           (void) ListMagicInfo((FILE *) NULL,_exception);
4809           break;
4810         case MagickMimeOptions:
4811           (void) ListMimeInfo((FILE *) NULL,_exception);
4812           break;
4813         case MagickModuleOptions:
4814           (void) ListModuleInfo((FILE *) NULL,_exception);
4815           break;
4816         case MagickPolicyOptions:
4817           (void) ListPolicyInfo((FILE *) NULL,_exception);
4818           break;
4819         case MagickResourceOptions:
4820           (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4821           break;
4822         case MagickThresholdOptions:
4823           (void) ListThresholdMaps((FILE *) NULL,_exception);
4824           break;
4825         default:
4826           (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4827             _exception);
4828           break;
4829       }
4830       break;
4831     }
4832
4833     CLIWandException(OptionError,"UnrecognizedOption",option);
4834
4835   } while (0);  /* break to exit code. */
4836
4837   /* clean up percent escape interpreted strings */
4838   if (arg1 != arg1n )
4839     arg1=DestroyString((char *)arg1);
4840   if (arg2 != arg2n )
4841     arg2=DestroyString((char *)arg2);
4842
4843 #undef _image_info
4844 #undef _images
4845 #undef _exception
4846 #undef IfNormalOp
4847 #undef IfPlusOp
4848 }
4849 \f
4850 /*
4851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4852 %                                                                             %
4853 %                                                                             %
4854 %                                                                             %
4855 +   C L I O p t i o n                                                         %
4856 %                                                                             %
4857 %                                                                             %
4858 %                                                                             %
4859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4860 %
4861 %  CLIOption() Processes the given option using the given CLI Magick Wand.
4862 %  The option arguments can be variable in number, though at this time no more
4863 %  that two is actually used by any option (this may change). Excess options
4864 %  are simply ignored.
4865 %
4866 %  If the cli_wand->command pointer is non-null, then it is assumed that the
4867 %  option has already been search for up from the CommandOptions[] table in
4868 %  "MagickCore/options.c" using  GetCommandOptionInfo().  If not set this
4869 %  routine will do the lookup instead. The pointer is reset afterward.
4870 %
4871 %  This action allows the caller to lookup and pre-handle any 'special'
4872 %  options, (such as implicit reads) before calling this general option
4873 %  handler to deal with 'standard' command line options.
4874 %
4875 %  The format of the CLIOption method is:
4876 %
4877 %       void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4878 %
4879 %  A description of each parameter follows:
4880 %
4881 %     o cli_wand: the main CLI Wand to use.
4882 %
4883 %     o option: The special option (with any switch char) to process
4884 %
4885 %     o args: any required arguments for an option (variable number)
4886 %
4887 %  Example Usage...
4888 %
4889 %    CLIoption(cli_wand,"-read","rose:");
4890 %    CLIoption(cli_wand,"-virtual-pixel","transparent");
4891 %    CLIoption(cli_wand,"-distort","SRT:","30");
4892 %    CLIoption(cli_wand,"-write","rotated_rose.png");
4893 %
4894 */
4895 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4896 {
4897   const char    /* extracted option args from args */
4898     *arg1,
4899     *arg2;
4900
4901   CommandOptionFlags
4902     option_type;
4903
4904   assert(cli_wand != (MagickCLI *) NULL);
4905   assert(cli_wand->signature == WandSignature);
4906   assert(cli_wand->wand.signature == WandSignature);
4907
4908   do { /* Break Code Block for error handling */
4909
4910     /* get information about option */
4911     if ( cli_wand->command == (const OptionInfo *) NULL )
4912       cli_wand->command = GetCommandOptionInfo(option);
4913 #if 0
4914       (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4915             option, cli_wand->command->mnemonic );
4916 #endif
4917     option_type=(CommandOptionFlags) cli_wand->command->flags;
4918
4919     if ( option_type == UndefinedOptionFlag )
4920       CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4921
4922     assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4923
4924     /* depreciated options */
4925     if ( (option_type & DeprecateOptionFlag) != 0 )
4926       CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4927
4928     /* options that this module does not handle */
4929     if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
4930       CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
4931
4932     /* Get argument strings from VarArgs
4933       How can you determine if enough arguments was supplied?
4934       What happens if not enough arguments were supplied?
4935     */
4936     { size_t
4937         count = cli_wand->command->type;
4938
4939       va_list
4940         operands;
4941
4942       va_start(operands,option);
4943
4944       arg1=arg2=NULL;
4945       if ( count >= 1 )
4946         arg1=(const char *) va_arg(operands, const char *);
4947       if ( count >= 2 )
4948         arg2=(const char *) va_arg(operands, const char *);
4949
4950       va_end(operands);
4951 #if 0
4952       (void) FormatLocaleFile(stderr,
4953         "CLIOption: \"%s\"  Count: %ld  Flags: %04x  Args: \"%s\" \"%s\"\n",
4954             option,(long) count,option_type,arg1,arg2);
4955 #endif
4956     }
4957
4958     /*
4959       Call the appropriate option handler
4960     */
4961
4962     /* FUTURE: this is temporary - get 'settings' to handle distribution of
4963       settings to images attributes,proprieties,artifacts */
4964     if ( cli_wand->wand.images != (Image *)NULL )
4965       SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
4966           cli_wand->wand.exception);
4967
4968     if ( (option_type & SettingOptionFlags) != 0 ) {
4969       CLISettingOptionInfo(cli_wand, option, arg1, arg2);
4970       // FUTURE: Sync Specific Settings into Image Properities (not global)
4971     }
4972
4973     /* Operators that do not need images - read, write, stack, clone */
4974     if ( (option_type & NoImageOperatorFlag) != 0)
4975       CLINoImageOperator(cli_wand, option, arg1, arg2);
4976
4977     /* FUTURE: The not a setting part below is a temporary hack due to
4978     * some options being both a Setting and a Simple operator.
4979     * Specifically -monitor, -depth, and  -colorspace */
4980     if ( cli_wand->wand.images == (Image *)NULL )
4981       if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
4982           ((option_type & SettingOptionFlags) == 0 ))  /* temp hack */
4983         CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
4984
4985     /* Operators which loop of individual images, simply */
4986     if ( (option_type & SimpleOperatorFlag) != 0 &&
4987          cli_wand->wand.images != (Image *)NULL) /* temp hack */
4988       CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
4989
4990     /* Operators that work on the image list as a whole */
4991     if ( (option_type & ListOperatorFlag) != 0 )
4992       CLIListOperatorImages(cli_wand, option, arg1, arg2);
4993
4994   } while (0);  /* end Break code block */
4995
4996   cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
4997 }