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