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