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