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