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