]> 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-2019 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % Apply the given options (settings, and simple, or sequence operations) to
37 % the given image(s) according to the current "image_info", "draw_info", and
38 % "quantize_info" settings, stored in a special CLI Image Wand.
39 %
40 % The final goal is to allow the execution in a strict one option at a time
41 % manner that is needed for 'pipelining and file scripting' of options in
42 % IMv7.
43 %
44 % 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 (IfSetOption && (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("0"));
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("clahe",option+1) == 0)
1970         {
1971           if (IsGeometry(arg1) == MagickFalse)
1972             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1973           flags=ParseGeometry(arg1,&geometry_info);
1974           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
1975           (void) CLAHEImage(_image,geometry.width,geometry.height,
1976             (size_t) geometry.x,geometry_info.psi,_exception);
1977           break;
1978         }
1979       if (LocaleCompare("clamp",option+1) == 0)
1980         {
1981           (void) ClampImage(_image,_exception);
1982           break;
1983         }
1984       if (LocaleCompare("clip",option+1) == 0)
1985         {
1986           if (IfNormalOp)
1987             (void) ClipImage(_image,_exception);
1988           else /* "+mask" remove the write mask */
1989             (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,
1990               _exception);
1991           break;
1992         }
1993       if (LocaleCompare("clip-mask",option+1) == 0)
1994         {
1995           Image
1996             *clip_mask;
1997
1998           if (IfPlusOp) {
1999             /* use "+clip-mask" Remove the write mask for -clip-path */
2000             (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,_exception);
2001             break;
2002           }
2003           clip_mask=GetImageCache(_image_info,arg1,_exception);
2004           if (clip_mask == (Image *) NULL)
2005             break;
2006           (void) SetImageMask(_image,WritePixelMask,clip_mask,_exception);
2007           clip_mask=DestroyImage(clip_mask);
2008           break;
2009         }
2010       if (LocaleCompare("clip-path",option+1) == 0)
2011         {
2012           (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2013           /* Note: Use "+clip-mask" remove the write mask added */
2014           break;
2015         }
2016       if (LocaleCompare("colorize",option+1) == 0)
2017         {
2018           if (IsGeometry(arg1) == MagickFalse)
2019             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2020           new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2021           break;
2022         }
2023       if (LocaleCompare("color-matrix",option+1) == 0)
2024         {
2025           KernelInfo
2026             *kernel;
2027
2028           kernel=AcquireKernelInfo(arg1,exception);
2029           if (kernel == (KernelInfo *) NULL)
2030             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2031           new_image=ColorMatrixImage(_image,kernel,_exception);
2032           kernel=DestroyKernelInfo(kernel);
2033           break;
2034         }
2035       if (LocaleCompare("colors",option+1) == 0)
2036         {
2037           /* Reduce the number of colors in the image.
2038              FUTURE: also provide 'plus version with image 'color counts'
2039           */
2040           _quantize_info->number_colors=StringToUnsignedLong(arg1);
2041           if (_quantize_info->number_colors == 0)
2042             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2043           if ((_image->storage_class == DirectClass) ||
2044               _image->colors > _quantize_info->number_colors)
2045             (void) QuantizeImage(_quantize_info,_image,_exception);
2046           else
2047             (void) CompressImageColormap(_image,_exception);
2048           break;
2049         }
2050       if (LocaleCompare("colorspace",option+1) == 0)
2051         {
2052           /* WARNING: this is both a image_info setting (already done)
2053                       and a operator to change image colorspace.
2054
2055              FUTURE: default colorspace should be sRGB!
2056              Unless some type of 'linear colorspace' mode is set.
2057
2058              Note that +colorspace sets "undefined" or no effect on
2059              new images, but forces images already in memory back to RGB!
2060              That seems to be a little strange!
2061           */
2062           (void) TransformImageColorspace(_image,
2063                     IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2064                     _exception);
2065           break;
2066         }
2067       if (LocaleCompare("connected-components",option+1) == 0)
2068         {
2069           if (IsGeometry(arg1) == MagickFalse)
2070             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2071           new_image=ConnectedComponentsImage(_image,(size_t)
2072             StringToInteger(arg1),(CCObjectInfo **) NULL,_exception);
2073           break;
2074         }
2075       if (LocaleCompare("contrast",option+1) == 0)
2076         {
2077           CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2078           (void) ContrastImage(_image,IsNormalOp,_exception);
2079           break;
2080         }
2081       if (LocaleCompare("contrast-stretch",option+1) == 0)
2082         {
2083           double
2084             black_point,
2085             white_point;
2086
2087           MagickStatusType
2088             flags;
2089
2090           flags=ParseGeometry(arg1,&geometry_info);
2091           if ((flags & RhoValue) == 0)
2092             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2093           black_point=geometry_info.rho;
2094           white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2095             black_point;
2096           if ((flags & PercentValue) != 0) {
2097               black_point*=(double) _image->columns*_image->rows/100.0;
2098               white_point*=(double) _image->columns*_image->rows/100.0;
2099             }
2100           white_point=(double) _image->columns*_image->rows-white_point;
2101           (void) ContrastStretchImage(_image,black_point,white_point,
2102             _exception);
2103           break;
2104         }
2105       if (LocaleCompare("convolve",option+1) == 0)
2106         {
2107           double
2108             gamma;
2109
2110           KernelInfo
2111             *kernel_info;
2112
2113           register ssize_t
2114             j;
2115
2116           kernel_info=AcquireKernelInfo(arg1,exception);
2117           if (kernel_info == (KernelInfo *) NULL)
2118             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2119           gamma=0.0;
2120           for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2121             gamma+=kernel_info->values[j];
2122           gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2123           for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2124             kernel_info->values[j]*=gamma;
2125           new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2126             _exception);
2127           kernel_info=DestroyKernelInfo(kernel_info);
2128           break;
2129         }
2130       if (LocaleCompare("crop",option+1) == 0)
2131         {
2132           /* WARNING: This can generate multiple images! */
2133           if (IsGeometry(arg1) == MagickFalse)
2134             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2135           new_image=CropImageToTiles(_image,arg1,_exception);
2136           break;
2137         }
2138       if (LocaleCompare("cycle",option+1) == 0)
2139         {
2140           if (IsGeometry(arg1) == MagickFalse)
2141             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2142           (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2143             _exception);
2144           break;
2145         }
2146       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2147     }
2148     case 'd':
2149     {
2150       if (LocaleCompare("decipher",option+1) == 0)
2151         {
2152           /* Note: arguments do not have percent escapes expanded */
2153           StringInfo
2154             *passkey;
2155
2156           passkey=FileToStringInfo(arg1,~0UL,_exception);
2157           if (passkey == (StringInfo *) NULL)
2158             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2159
2160           (void) PasskeyDecipherImage(_image,passkey,_exception);
2161           passkey=DestroyStringInfo(passkey);
2162           break;
2163         }
2164       if (LocaleCompare("depth",option+1) == 0)
2165         {
2166           /* The _image_info->depth setting has already been set
2167              We just need to apply it to all images in current sequence
2168
2169              WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2170              That is it really is an operation, not a setting! Arrgghhh
2171
2172              FUTURE: this should not be an operator!!!
2173           */
2174           (void) SetImageDepth(_image,_image_info->depth,_exception);
2175           break;
2176         }
2177       if (LocaleCompare("deskew",option+1) == 0)
2178         {
2179           double
2180             threshold;
2181
2182           if (IfNormalOp) {
2183             if (IsGeometry(arg1) == MagickFalse)
2184               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2185             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2186           }
2187           else
2188             threshold=40.0*QuantumRange/100.0;
2189           new_image=DeskewImage(_image,threshold,_exception);
2190           break;
2191         }
2192       if (LocaleCompare("despeckle",option+1) == 0)
2193         {
2194           new_image=DespeckleImage(_image,_exception);
2195           break;
2196         }
2197       if (LocaleCompare("distort",option+1) == 0)
2198         {
2199           double
2200             *args;
2201
2202           ssize_t
2203             count;
2204
2205           parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2206           if ( parse < 0 )
2207              CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2208                                       option,arg1);
2209           if ((DistortMethod) parse == ResizeDistortion)
2210             {
2211                double
2212                  resize_args[2];
2213                /* Special Case - Argument is actually a resize geometry!
2214                ** Convert that to an appropriate distortion argument array.
2215                ** FUTURE: make a separate special resize operator
2216                     Roll into a resize special operator */
2217                if (IsGeometry(arg2) == MagickFalse)
2218                  CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2219                                            option,arg2);
2220                (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2221                resize_args[0]=(double) geometry.width;
2222                resize_args[1]=(double) geometry.height;
2223                new_image=DistortImage(_image,(DistortMethod) parse,
2224                     (size_t)2,resize_args,MagickTrue,_exception);
2225                break;
2226             }
2227           /* convert argument string into an array of doubles */
2228           args = StringToArrayOfDoubles(arg2,&count,_exception);
2229           if (args == (double *) NULL )
2230             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2231
2232           new_image=DistortImage(_image,(DistortMethod) parse,(size_t)
2233              count,args,IsPlusOp,_exception);
2234           args=(double *) RelinquishMagickMemory(args);
2235           break;
2236         }
2237       if (LocaleCompare("draw",option+1) == 0)
2238         {
2239           (void) CloneString(&_draw_info->primitive,arg1);
2240           (void) DrawImage(_image,_draw_info,_exception);
2241           (void) CloneString(&_draw_info->primitive,(char *) NULL);
2242           break;
2243         }
2244       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2245     }
2246     case 'e':
2247     {
2248       if (LocaleCompare("edge",option+1) == 0)
2249         {
2250           flags=ParseGeometry(arg1,&geometry_info);
2251           if ((flags & (RhoValue|SigmaValue)) == 0)
2252             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2253           new_image=EdgeImage(_image,geometry_info.rho,_exception);
2254           break;
2255         }
2256       if (LocaleCompare("emboss",option+1) == 0)
2257         {
2258           flags=ParseGeometry(arg1,&geometry_info);
2259           if ((flags & (RhoValue|SigmaValue)) == 0)
2260             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2261           if ((flags & SigmaValue) == 0)
2262             geometry_info.sigma=1.0;
2263           new_image=EmbossImage(_image,geometry_info.rho,
2264             geometry_info.sigma,_exception);
2265           break;
2266         }
2267       if (LocaleCompare("encipher",option+1) == 0)
2268         {
2269           /* Note: arguments do not have percent escapes expanded */
2270           StringInfo
2271             *passkey;
2272
2273           passkey=FileToStringInfo(arg1,~0UL,_exception);
2274           if (passkey != (StringInfo *) NULL)
2275             {
2276               (void) PasskeyEncipherImage(_image,passkey,_exception);
2277               passkey=DestroyStringInfo(passkey);
2278             }
2279           break;
2280         }
2281       if (LocaleCompare("enhance",option+1) == 0)
2282         {
2283           new_image=EnhanceImage(_image,_exception);
2284           break;
2285         }
2286       if (LocaleCompare("equalize",option+1) == 0)
2287         {
2288           (void) EqualizeImage(_image,_exception);
2289           break;
2290         }
2291       if (LocaleCompare("evaluate",option+1) == 0)
2292         {
2293           double
2294             constant;
2295
2296           parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2297           if ( parse < 0 )
2298             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2299                  option,arg1);
2300           if (IsGeometry(arg2) == MagickFalse)
2301             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2302           constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2303           (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2304                _exception);
2305           break;
2306         }
2307       if (LocaleCompare("extent",option+1) == 0)
2308         {
2309           if (IsGeometry(arg1) == MagickFalse)
2310             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2311           flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2312           if (geometry.width == 0)
2313             geometry.width=_image->columns;
2314           if (geometry.height == 0)
2315             geometry.height=_image->rows;
2316           new_image=ExtentImage(_image,&geometry,_exception);
2317           break;
2318         }
2319       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2320     }
2321     case 'f':
2322     {
2323       if (LocaleCompare("flip",option+1) == 0)
2324         {
2325           new_image=FlipImage(_image,_exception);
2326           break;
2327         }
2328       if (LocaleCompare("flop",option+1) == 0)
2329         {
2330           new_image=FlopImage(_image,_exception);
2331           break;
2332         }
2333       if (LocaleCompare("floodfill",option+1) == 0)
2334         {
2335           PixelInfo
2336             target;
2337
2338           if (IsGeometry(arg1) == MagickFalse)
2339             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2340           (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2341           (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2342           (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2343             geometry.y,IsPlusOp,_exception);
2344           break;
2345         }
2346       if (LocaleCompare("frame",option+1) == 0)
2347         {
2348           FrameInfo
2349             frame_info;
2350
2351           CompositeOperator
2352             compose;
2353
2354           const char*
2355             value;
2356
2357           value=GetImageOption(_image_info,"compose");
2358             compose=OverCompositeOp;  /* use Over not _image->compose */
2359           if (value != (const char *) NULL)
2360             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2361               MagickFalse,value);
2362           if (IsGeometry(arg1) == MagickFalse)
2363             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2364           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2365           frame_info.width=geometry.width;
2366           frame_info.height=geometry.height;
2367           frame_info.outer_bevel=geometry.x;
2368           frame_info.inner_bevel=geometry.y;
2369           frame_info.x=(ssize_t) frame_info.width;
2370           frame_info.y=(ssize_t) frame_info.height;
2371           frame_info.width=_image->columns+2*frame_info.width;
2372           frame_info.height=_image->rows+2*frame_info.height;
2373           new_image=FrameImage(_image,&frame_info,compose,_exception);
2374           break;
2375         }
2376       if (LocaleCompare("function",option+1) == 0)
2377         {
2378           double
2379             *args;
2380
2381           ssize_t
2382             count;
2383
2384           parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2385           if ( parse < 0 )
2386             CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2387                  option,arg1);
2388           /* convert argument string into an array of doubles */
2389           args = StringToArrayOfDoubles(arg2,&count,_exception);
2390           if (args == (double *) NULL )
2391             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2392
2393           (void) FunctionImage(_image,(MagickFunction)parse,(size_t) count,args,
2394                _exception);
2395           args=(double *) RelinquishMagickMemory(args);
2396           break;
2397         }
2398       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2399     }
2400     case 'g':
2401     {
2402       if (LocaleCompare("gamma",option+1) == 0)
2403         {
2404           double
2405             constant;
2406
2407           if (IsGeometry(arg1) == MagickFalse)
2408             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2409           constant=StringToDouble(arg1,(char **) NULL);
2410 #if 0
2411           /* Using Gamma, via a cache */
2412           if (IfPlusOp)
2413             constant=PerceptibleReciprocal(constant);
2414           (void) GammaImage(_image,constant,_exception);
2415 #else
2416           /* Using Evaluate POW, direct update of values - more accurite */
2417           if (IfNormalOp)
2418             constant=PerceptibleReciprocal(constant);
2419           (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2420           _image->gamma*=StringToDouble(arg1,(char **) NULL);
2421 #endif
2422           /* Set gamma setting -- Old meaning of "+gamma"
2423            * _image->gamma=StringToDouble(arg1,(char **) NULL);
2424            */
2425           break;
2426         }
2427       if (LocaleCompare("gaussian-blur",option+1) == 0)
2428         {
2429           flags=ParseGeometry(arg1,&geometry_info);
2430           if ((flags & (RhoValue|SigmaValue)) == 0)
2431             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2432           if ((flags & SigmaValue) == 0)
2433             geometry_info.sigma=1.0;
2434           new_image=GaussianBlurImage(_image,geometry_info.rho,
2435             geometry_info.sigma,_exception);
2436           break;
2437         }
2438       if (LocaleCompare("gaussian",option+1) == 0)
2439         {
2440           CLIWandWarnReplaced("-gaussian-blur");
2441           (void) CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2442         }
2443       if (LocaleCompare("geometry",option+1) == 0)
2444         {
2445           /*
2446             Record Image offset for composition. (A Setting)
2447             Resize last _image. (ListOperator)  -- DEPRECIATE
2448             FUTURE: Why if no 'offset' does this resize ALL images?
2449             Also why is the setting recorded in the IMAGE non-sense!
2450           */
2451           if (IfPlusOp)
2452             { /* remove the previous composition geometry offset! */
2453               if (_image->geometry != (char *) NULL)
2454                 _image->geometry=DestroyString(_image->geometry);
2455               break;
2456             }
2457           if (IsGeometry(arg1) == MagickFalse)
2458             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2459           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2460           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2461             (void) CloneString(&_image->geometry,arg1);
2462           else
2463             new_image=ResizeImage(_image,geometry.width,geometry.height,
2464               _image->filter,_exception);
2465           break;
2466         }
2467       if (LocaleCompare("grayscale",option+1) == 0)
2468         {
2469           parse=ParseCommandOption(MagickPixelIntensityOptions,
2470             MagickFalse,arg1);
2471           if (parse < 0)
2472             CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2473               option,arg1);
2474           (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2475           break;
2476         }
2477       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2478     }
2479     case 'h':
2480     {
2481       if (LocaleCompare("hough-lines",option+1) == 0)
2482         {
2483           flags=ParseGeometry(arg1,&geometry_info);
2484           if ((flags & (RhoValue|SigmaValue)) == 0)
2485             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2486           if ((flags & SigmaValue) == 0)
2487             geometry_info.sigma=geometry_info.rho;
2488           if ((flags & XiValue) == 0)
2489             geometry_info.xi=40;
2490           new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2491             (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2492           break;
2493         }
2494       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2495     }
2496     case 'i':
2497     {
2498       if (LocaleCompare("identify",option+1) == 0)
2499         {
2500           const char
2501             *format,
2502             *text;
2503
2504           format=GetImageOption(_image_info,"format");
2505           if (format == (char *) NULL)
2506             {
2507               (void) IdentifyImage(_image,stdout,_image_info->verbose,
2508                 _exception);
2509               break;
2510             }
2511           text=InterpretImageProperties(_image_info,_image,format,_exception);
2512           if (text == (char *) NULL)
2513             CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2514               option);
2515           (void) fputs(text,stdout);
2516           text=DestroyString((char *)text);
2517           break;
2518         }
2519       if (LocaleCompare("implode",option+1) == 0)
2520         {
2521           flags=ParseGeometry(arg1,&geometry_info);
2522           if ((flags & RhoValue) == 0)
2523             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2524           new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2525                _exception);
2526           break;
2527         }
2528       if (LocaleCompare("interpolative-resize",option+1) == 0)
2529         {
2530           /* FUTURE: New to IMv7
2531                Roll into a resize special operator */
2532           if (IsGeometry(arg1) == MagickFalse)
2533             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2534           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2535           new_image=InterpolativeResizeImage(_image,geometry.width,
2536                geometry.height,_image->interpolate,_exception);
2537           break;
2538         }
2539       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2540     }
2541     case 'k':
2542     {
2543       if (LocaleCompare("kuwahara",option+1) == 0)
2544         {
2545           /*
2546             Edge preserving blur.
2547           */
2548           flags=ParseGeometry(arg1,&geometry_info);
2549           if ((flags & (RhoValue|SigmaValue)) == 0)
2550             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2551           if ((flags & SigmaValue) == 0)
2552             geometry_info.sigma=geometry_info.rho-0.5;
2553           new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2554            _exception);
2555           break;
2556         }
2557       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2558     }
2559     case 'l':
2560     {
2561       if (LocaleCompare("lat",option+1) == 0)
2562         {
2563           flags=ParseGeometry(arg1,&geometry_info);
2564           if ((flags & (RhoValue|SigmaValue)) == 0)
2565             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2566           if ((flags & SigmaValue) == 0)
2567             geometry_info.sigma=1.0;
2568           if ((flags & PercentValue) != 0)
2569             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2570           new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2571                (size_t) geometry_info.sigma,(double) geometry_info.xi,
2572                _exception);
2573           break;
2574         }
2575       if (LocaleCompare("level",option+1) == 0)
2576         {
2577           double
2578             black_point,
2579             gamma,
2580             white_point;
2581
2582           MagickStatusType
2583             flags;
2584
2585           flags=ParseGeometry(arg1,&geometry_info);
2586           if ((flags & RhoValue) == 0)
2587             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2588           black_point=geometry_info.rho;
2589           white_point=(double) QuantumRange;
2590           if ((flags & SigmaValue) != 0)
2591             white_point=geometry_info.sigma;
2592           gamma=1.0;
2593           if ((flags & XiValue) != 0)
2594             gamma=geometry_info.xi;
2595           if ((flags & PercentValue) != 0)
2596             {
2597               black_point*=(double) (QuantumRange/100.0);
2598               white_point*=(double) (QuantumRange/100.0);
2599             }
2600           if ((flags & SigmaValue) == 0)
2601             white_point=(double) QuantumRange-black_point;
2602           if (IfPlusOp || ((flags & AspectValue) != 0))
2603             (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2604           else
2605             (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2606           break;
2607         }
2608       if (LocaleCompare("level-colors",option+1) == 0)
2609         {
2610           char
2611             token[MagickPathExtent];
2612
2613           const char
2614             *p;
2615
2616           PixelInfo
2617             black_point,
2618             white_point;
2619
2620           p=(const char *) arg1;
2621           GetNextToken(p,&p,MagickPathExtent,token);  /* get black point color */
2622           if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2623             (void) QueryColorCompliance(token,AllCompliance,
2624                       &black_point,_exception);
2625           else
2626             (void) QueryColorCompliance("#000000",AllCompliance,
2627                       &black_point,_exception);
2628           if (isalpha((int) token[0]) || (token[0] == '#'))
2629             GetNextToken(p,&p,MagickPathExtent,token);
2630           if (*token == '\0')
2631             white_point=black_point; /* set everything to that color */
2632           else
2633             {
2634               if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2635                 GetNextToken(p,&p,MagickPathExtent,token); /* Get white point color. */
2636               if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2637                 (void) QueryColorCompliance(token,AllCompliance,
2638                            &white_point,_exception);
2639               else
2640                 (void) QueryColorCompliance("#ffffff",AllCompliance,
2641                            &white_point,_exception);
2642             }
2643           (void) LevelImageColors(_image,&black_point,&white_point,
2644                      IsPlusOp,_exception);
2645           break;
2646         }
2647       if (LocaleCompare("linear-stretch",option+1) == 0)
2648         {
2649           double
2650             black_point,
2651             white_point;
2652
2653           MagickStatusType
2654             flags;
2655
2656           flags=ParseGeometry(arg1,&geometry_info);
2657           if ((flags & RhoValue) == 0)
2658             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2659           black_point=geometry_info.rho;
2660           white_point=(double) _image->columns*_image->rows;
2661           if ((flags & SigmaValue) != 0)
2662             white_point=geometry_info.sigma;
2663           if ((flags & PercentValue) != 0)
2664             {
2665               black_point*=(double) _image->columns*_image->rows/100.0;
2666               white_point*=(double) _image->columns*_image->rows/100.0;
2667             }
2668           if ((flags & SigmaValue) == 0)
2669             white_point=(double) _image->columns*_image->rows-
2670               black_point;
2671           (void) LinearStretchImage(_image,black_point,white_point,_exception);
2672           break;
2673         }
2674       if (LocaleCompare("liquid-rescale",option+1) == 0)
2675         {
2676           /* FUTURE: Roll into a resize special operator */
2677           if (IsGeometry(arg1) == MagickFalse)
2678             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2679           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2680           if ((flags & XValue) == 0)
2681             geometry.x=1;
2682           if ((flags & YValue) == 0)
2683             geometry.y=0;
2684           new_image=LiquidRescaleImage(_image,geometry.width,
2685             geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2686           break;
2687         }
2688       if (LocaleCompare("local-contrast",option+1) == 0)
2689         {
2690           MagickStatusType
2691             flags;
2692
2693           flags=ParseGeometry(arg1,&geometry_info);
2694           if ((flags & RhoValue) == 0)
2695             geometry_info.rho=10;
2696           if ((flags & SigmaValue) == 0)
2697             geometry_info.sigma=12.5;
2698           new_image=LocalContrastImage(_image,geometry_info.rho,
2699             geometry_info.sigma,exception);
2700           break;
2701         }
2702       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2703     }
2704     case 'm':
2705     {
2706       if (LocaleCompare("magnify",option+1) == 0)
2707         {
2708           new_image=MagnifyImage(_image,_exception);
2709           break;
2710         }
2711       if (LocaleCompare("map",option+1) == 0)
2712         {
2713           CLIWandWarnReplaced("-remap");
2714           (void) CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL,exception);
2715           break;
2716         }
2717       if (LocaleCompare("mask",option+1) == 0)
2718         {
2719           Image
2720             *mask;
2721
2722           if (IfPlusOp)
2723             {
2724               /*
2725                 Remove a mask.
2726               */
2727               (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,
2728                 _exception);
2729               break;
2730             }
2731           /*
2732             Set the image mask.
2733           */
2734           mask=GetImageCache(_image_info,arg1,_exception);
2735           if (mask == (Image *) NULL)
2736             break;
2737           (void) SetImageMask(_image,WritePixelMask,mask,_exception);
2738           mask=DestroyImage(mask);
2739           break;
2740         }
2741       if (LocaleCompare("matte",option+1) == 0)
2742         {
2743           CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2744           (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2745             DeactivateAlphaChannel, _exception);
2746           break;
2747         }
2748       if (LocaleCompare("mean-shift",option+1) == 0)
2749         {
2750           flags=ParseGeometry(arg1,&geometry_info);
2751           if ((flags & (RhoValue|SigmaValue)) == 0)
2752             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2753           if ((flags & SigmaValue) == 0)
2754             geometry_info.sigma=1.0;
2755           if ((flags & XiValue) == 0)
2756             geometry_info.xi=0.10*QuantumRange;
2757           if ((flags & PercentValue) != 0)
2758             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2759           new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2760             (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2761           break;
2762         }
2763       if (LocaleCompare("median",option+1) == 0)
2764         {
2765           CLIWandWarnReplaced("-statistic Median");
2766           (void) CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2767           break;
2768         }
2769       if (LocaleCompare("mode",option+1) == 0)
2770         {
2771           /* FUTURE: note this is also a special "montage" option */
2772           CLIWandWarnReplaced("-statistic Mode");
2773           (void) CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,exception);
2774           break;
2775         }
2776       if (LocaleCompare("modulate",option+1) == 0)
2777         {
2778           if (IsGeometry(arg1) == MagickFalse)
2779             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2780           (void) ModulateImage(_image,arg1,_exception);
2781           break;
2782         }
2783       if (LocaleCompare("monitor",option+1) == 0)
2784         {
2785           (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2786                 (MagickProgressMonitor) NULL,(void *) NULL);
2787           break;
2788         }
2789       if (LocaleCompare("monochrome",option+1) == 0)
2790         {
2791           (void) SetImageType(_image,BilevelType,_exception);
2792           break;
2793         }
2794       if (LocaleCompare("morphology",option+1) == 0)
2795         {
2796           char
2797             token[MagickPathExtent];
2798
2799           const char
2800             *p;
2801
2802           KernelInfo
2803             *kernel;
2804
2805           ssize_t
2806             iterations;
2807
2808           p=arg1;
2809           GetNextToken(p,&p,MagickPathExtent,token);
2810           parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2811           if ( parse < 0 )
2812             CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2813               arg1);
2814           iterations=1L;
2815           GetNextToken(p,&p,MagickPathExtent,token);
2816           if ((*p == ':') || (*p == ','))
2817             GetNextToken(p,&p,MagickPathExtent,token);
2818           if ((*p != '\0'))
2819             iterations=(ssize_t) StringToLong(p);
2820           kernel=AcquireKernelInfo(arg2,exception);
2821           if (kernel == (KernelInfo *) NULL)
2822             CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2823           new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2824             kernel,_exception);
2825           kernel=DestroyKernelInfo(kernel);
2826           break;
2827         }
2828       if (LocaleCompare("motion-blur",option+1) == 0)
2829         {
2830           flags=ParseGeometry(arg1,&geometry_info);
2831           if ((flags & (RhoValue|SigmaValue)) == 0)
2832             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2833           if ((flags & SigmaValue) == 0)
2834             geometry_info.sigma=1.0;
2835           new_image=MotionBlurImage(_image,geometry_info.rho,geometry_info.sigma,
2836             geometry_info.xi,_exception);
2837           break;
2838         }
2839       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2840     }
2841     case 'n':
2842     {
2843       if (LocaleCompare("negate",option+1) == 0)
2844         {
2845           (void) NegateImage(_image, IsPlusOp, _exception);
2846           break;
2847         }
2848       if (LocaleCompare("noise",option+1) == 0)
2849         {
2850           double
2851             attenuate;
2852
2853           const char*
2854             value;
2855
2856           if (IfNormalOp)
2857             {
2858               CLIWandWarnReplaced("-statistic NonPeak");
2859               (void) CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2860               break;
2861             }
2862           parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2863           if ( parse < 0 )
2864             CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2865                 option,arg1);
2866           attenuate=1.0;
2867           value=GetImageOption(_image_info,"attenuate");
2868           if  (value != (const char *) NULL)
2869             attenuate=StringToDouble(value,(char **) NULL);
2870           new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2871                _exception);
2872           break;
2873         }
2874       if (LocaleCompare("normalize",option+1) == 0)
2875         {
2876           (void) NormalizeImage(_image,_exception);
2877           break;
2878         }
2879       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2880     }
2881     case 'o':
2882     {
2883       if (LocaleCompare("opaque",option+1) == 0)
2884         {
2885           PixelInfo
2886             target;
2887
2888           (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2889           (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2890                _exception);
2891           break;
2892         }
2893       if (LocaleCompare("ordered-dither",option+1) == 0)
2894         {
2895           (void) OrderedDitherImage(_image,arg1,_exception);
2896           break;
2897         }
2898       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2899     }
2900     case 'p':
2901     {
2902       if (LocaleCompare("paint",option+1) == 0)
2903         {
2904           flags=ParseGeometry(arg1,&geometry_info);
2905           if ((flags & (RhoValue|SigmaValue)) == 0)
2906             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2907           new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2908                _exception);
2909           break;
2910         }
2911       if (LocaleCompare("perceptible",option+1) == 0)
2912         {
2913           (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2914             _exception);
2915           break;
2916         }
2917       if (LocaleCompare("polaroid",option+1) == 0)
2918         {
2919           const char
2920             *caption;
2921
2922           double
2923             angle;
2924
2925           if (IfPlusOp) {
2926             RandomInfo
2927               *random_info;
2928
2929             random_info=AcquireRandomInfo();
2930             angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2931             random_info=DestroyRandomInfo(random_info);
2932           }
2933           else {
2934             flags=ParseGeometry(arg1,&geometry_info);
2935             if ((flags & RhoValue) == 0)
2936               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2937             angle=geometry_info.rho;
2938           }
2939           caption=GetImageProperty(_image,"caption",_exception);
2940           new_image=PolaroidImage(_image,_draw_info,caption,angle,
2941             _image->interpolate,_exception);
2942           break;
2943         }
2944       if (LocaleCompare("posterize",option+1) == 0)
2945         {
2946           flags=ParseGeometry(arg1,&geometry_info);
2947           if ((flags & RhoValue) == 0)
2948             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2949           (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2950             _quantize_info->dither_method,_exception);
2951           break;
2952         }
2953       if (LocaleCompare("preview",option+1) == 0)
2954         {
2955           /* FUTURE: should be a 'Genesis' option?
2956              Option however is also in WandSettingOptionInfo()
2957              Why???
2958           */
2959           parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2960           if ( parse < 0 )
2961             CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2962                 option,arg1);
2963           new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2964           break;
2965         }
2966       if (LocaleCompare("profile",option+1) == 0)
2967         {
2968           const char
2969             *name;
2970
2971           const StringInfo
2972             *profile;
2973
2974           Image
2975             *profile_image;
2976
2977           ImageInfo
2978             *profile_info;
2979
2980           /* Note: arguments do not have percent escapes expanded */
2981           if (IfPlusOp)
2982             { /* Remove a profile from the _image.  */
2983               (void) ProfileImage(_image,arg1,(const unsigned char *)
2984                 NULL,0,_exception);
2985               break;
2986             }
2987           /* Associate a profile with the _image.  */
2988           profile_info=CloneImageInfo(_image_info);
2989           profile=GetImageProfile(_image,"iptc");
2990           if (profile != (StringInfo *) NULL)
2991             profile_info->profile=(void *) CloneStringInfo(profile);
2992           profile_image=GetImageCache(profile_info,arg1,_exception);
2993           profile_info=DestroyImageInfo(profile_info);
2994           if (profile_image == (Image *) NULL)
2995             {
2996               StringInfo
2997                 *profile;
2998
2999               profile_info=CloneImageInfo(_image_info);
3000               (void) CopyMagickString(profile_info->filename,arg1,
3001                 MagickPathExtent);
3002               profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
3003               if (profile != (StringInfo *) NULL)
3004                 {
3005                   (void) SetImageInfo(profile_info,0,_exception);
3006                   (void) ProfileImage(_image,profile_info->magick,
3007                     GetStringInfoDatum(profile),(size_t)
3008                     GetStringInfoLength(profile),_exception);
3009                   profile=DestroyStringInfo(profile);
3010                 }
3011               profile_info=DestroyImageInfo(profile_info);
3012               break;
3013             }
3014           ResetImageProfileIterator(profile_image);
3015           name=GetNextImageProfile(profile_image);
3016           while (name != (const char *) NULL)
3017           {
3018             profile=GetImageProfile(profile_image,name);
3019             if (profile != (StringInfo *) NULL)
3020               (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3021                 (size_t) GetStringInfoLength(profile),_exception);
3022             name=GetNextImageProfile(profile_image);
3023           }
3024           profile_image=DestroyImage(profile_image);
3025           break;
3026         }
3027       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3028     }
3029     case 'r':
3030     {
3031       if (LocaleCompare("raise",option+1) == 0)
3032         {
3033           if (IsGeometry(arg1) == MagickFalse)
3034             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3035           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3036           (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3037           break;
3038         }
3039       if (LocaleCompare("random-threshold",option+1) == 0)
3040         {
3041           double
3042             min_threshold,
3043             max_threshold;
3044
3045           if (IsGeometry(arg1) == MagickFalse)
3046             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3047           min_threshold=0.0;
3048           max_threshold=(double) QuantumRange;
3049           flags=ParseGeometry(arg1,&geometry_info);
3050           min_threshold=geometry_info.rho;
3051           max_threshold=geometry_info.sigma;
3052           if ((flags & SigmaValue) == 0)
3053             max_threshold=min_threshold;
3054           if (strchr(arg1,'%') != (char *) NULL)
3055             {
3056               max_threshold*=(double) (0.01*QuantumRange);
3057               min_threshold*=(double) (0.01*QuantumRange);
3058             }
3059           (void) RandomThresholdImage(_image,min_threshold,max_threshold,
3060             _exception);
3061           break;
3062         }
3063       if (LocaleCompare("range-threshold",option+1) == 0)
3064         {
3065           /*
3066             Range threshold image.
3067           */
3068           if (IsGeometry(arg1) == MagickFalse)
3069             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3070           flags=ParseGeometry(arg1,&geometry_info);
3071           if ((flags & SigmaValue) == 0)
3072             geometry_info.sigma=geometry_info.rho;
3073           if ((flags & XiValue) == 0)
3074             geometry_info.xi=geometry_info.sigma;
3075           if ((flags & PsiValue) == 0)
3076             geometry_info.psi=geometry_info.xi;
3077           if (strchr(arg1,'%') != (char *) NULL)
3078             {
3079               geometry_info.rho*=(double) (0.01*QuantumRange);
3080               geometry_info.sigma*=(double) (0.01*QuantumRange);
3081               geometry_info.xi*=(double) (0.01*QuantumRange);
3082               geometry_info.psi*=(double) (0.01*QuantumRange);
3083             }
3084           (void) RangeThresholdImage(_image,geometry_info.rho,
3085             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3086           break;
3087         }
3088       if (LocaleCompare("read-mask",option+1) == 0)
3089         {
3090           /* Note: arguments do not have percent escapes expanded */
3091           Image
3092             *mask;
3093
3094           if (IfPlusOp)
3095             { /* Remove a mask. */
3096               (void) SetImageMask(_image,ReadPixelMask,(Image *) NULL,
3097                 _exception);
3098               break;
3099             }
3100           /* Set the image mask. */
3101           mask=GetImageCache(_image_info,arg1,_exception);
3102           if (mask == (Image *) NULL)
3103             break;
3104           (void) SetImageMask(_image,ReadPixelMask,mask,_exception);
3105           mask=DestroyImage(mask);
3106           break;
3107         }
3108       if (LocaleCompare("recolor",option+1) == 0)
3109         {
3110           CLIWandWarnReplaced("-color-matrix");
3111           (void) CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,
3112             exception);
3113         }
3114       if (LocaleCompare("region",option+1) == 0)
3115         {
3116           if (*option == '+')
3117             {
3118               (void) SetImageRegionMask(_image,WritePixelMask,
3119                 (const RectangleInfo *) NULL,_exception);
3120               break;
3121             }
3122           if (IsGeometry(arg1) == MagickFalse)
3123             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3124           (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
3125           (void) SetImageRegionMask(_image,WritePixelMask,&geometry,_exception);
3126           break;
3127         }
3128       if (LocaleCompare("remap",option+1) == 0)
3129         {
3130           /* Note: arguments do not have percent escapes expanded */
3131           Image
3132             *remap_image;
3133
3134           remap_image=GetImageCache(_image_info,arg1,_exception);
3135           if (remap_image == (Image *) NULL)
3136             break;
3137           (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3138           remap_image=DestroyImage(remap_image);
3139           break;
3140         }
3141       if (LocaleCompare("repage",option+1) == 0)
3142         {
3143           if (IfNormalOp)
3144             {
3145               if (IsGeometry(arg1) == MagickFalse)
3146                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3147                   arg1);
3148               (void) ResetImagePage(_image,arg1);
3149             }
3150           else
3151             (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3152           break;
3153         }
3154       if (LocaleCompare("resample",option+1) == 0)
3155         {
3156           /* FUTURE: Roll into a resize special operation */
3157           flags=ParseGeometry(arg1,&geometry_info);
3158           if ((flags & (RhoValue|SigmaValue)) == 0)
3159             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3160           if ((flags & SigmaValue) == 0)
3161             geometry_info.sigma=geometry_info.rho;
3162           new_image=ResampleImage(_image,geometry_info.rho,
3163             geometry_info.sigma,_image->filter,_exception);
3164           break;
3165         }
3166       if (LocaleCompare("resize",option+1) == 0)
3167         {
3168           if (IsGeometry(arg1) == MagickFalse)
3169             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3170           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3171           new_image=ResizeImage(_image,geometry.width,geometry.height,
3172             _image->filter,_exception);
3173           break;
3174         }
3175       if (LocaleCompare("roll",option+1) == 0)
3176         {
3177           if (IsGeometry(arg1) == MagickFalse)
3178             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3179           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3180           if ((flags & PercentValue) != 0)
3181             {
3182               geometry.x*=(double) _image->columns/100.0;
3183               geometry.y*=(double) _image->rows/100.0;
3184             }
3185           new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3186           break;
3187         }
3188       if (LocaleCompare("rotate",option+1) == 0)
3189         {
3190           flags=ParseGeometry(arg1,&geometry_info);
3191           if ((flags & RhoValue) == 0)
3192             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3193           if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3194             break;
3195           if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3196             break;
3197           new_image=RotateImage(_image,geometry_info.rho,_exception);
3198           break;
3199         }
3200       if (LocaleCompare("rotational-blur",option+1) == 0)
3201         {
3202           flags=ParseGeometry(arg1,&geometry_info);
3203           if ((flags & RhoValue) == 0)
3204             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3205           new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3206           break;
3207         }
3208       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3209     }
3210     case 's':
3211     {
3212       if (LocaleCompare("sample",option+1) == 0)
3213         {
3214           /* FUTURE: Roll into a resize special operator */
3215           if (IsGeometry(arg1) == MagickFalse)
3216             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3217           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3218           new_image=SampleImage(_image,geometry.width,geometry.height,
3219             _exception);
3220           break;
3221         }
3222       if (LocaleCompare("scale",option+1) == 0)
3223         {
3224           /* FUTURE: Roll into a resize special operator */
3225           if (IsGeometry(arg1) == MagickFalse)
3226             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3227           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3228           new_image=ScaleImage(_image,geometry.width,geometry.height,
3229             _exception);
3230           break;
3231         }
3232       if (LocaleCompare("segment",option+1) == 0)
3233         {
3234           flags=ParseGeometry(arg1,&geometry_info);
3235           if ((flags & (RhoValue|SigmaValue)) == 0)
3236             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3237           if ((flags & SigmaValue) == 0)
3238             geometry_info.sigma=1.0;
3239           (void) SegmentImage(_image,_image->colorspace,
3240             _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3241             _exception);
3242           break;
3243         }
3244       if (LocaleCompare("selective-blur",option+1) == 0)
3245         {
3246           flags=ParseGeometry(arg1,&geometry_info);
3247           if ((flags & (RhoValue|SigmaValue)) == 0)
3248             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3249           if ((flags & SigmaValue) == 0)
3250             geometry_info.sigma=1.0;
3251           if ((flags & PercentValue) != 0)
3252             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3253           new_image=SelectiveBlurImage(_image,geometry_info.rho,
3254             geometry_info.sigma,geometry_info.xi,_exception);
3255           break;
3256         }
3257       if (LocaleCompare("separate",option+1) == 0)
3258         {
3259           /* WARNING: This can generate multiple images! */
3260           /* FUTURE - this may be replaced by a "-channel" method */
3261           new_image=SeparateImages(_image,_exception);
3262           break;
3263         }
3264       if (LocaleCompare("sepia-tone",option+1) == 0)
3265         {
3266           if (IsGeometry(arg1) == MagickFalse)
3267             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3268           new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3269                  (double) QuantumRange+1.0),_exception);
3270           break;
3271         }
3272       if (LocaleCompare("shade",option+1) == 0)
3273         {
3274           flags=ParseGeometry(arg1,&geometry_info);
3275           if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3276             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3277           new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3278                geometry_info.sigma,_exception);
3279           break;
3280         }
3281       if (LocaleCompare("shadow",option+1) == 0)
3282         {
3283           flags=ParseGeometry(arg1,&geometry_info);
3284           if ((flags & (RhoValue|SigmaValue)) == 0)
3285             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3286           if ((flags & SigmaValue) == 0)
3287             geometry_info.sigma=1.0;
3288           if ((flags & XiValue) == 0)
3289             geometry_info.xi=4.0;
3290           if ((flags & PsiValue) == 0)
3291             geometry_info.psi=4.0;
3292           new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3293             (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3294             ceil(geometry_info.psi-0.5),_exception);
3295           break;
3296         }
3297       if (LocaleCompare("sharpen",option+1) == 0)
3298         {
3299           flags=ParseGeometry(arg1,&geometry_info);
3300           if ((flags & (RhoValue|SigmaValue)) == 0)
3301             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3302           if ((flags & SigmaValue) == 0)
3303             geometry_info.sigma=1.0;
3304           if ((flags & XiValue) == 0)
3305             geometry_info.xi=0.0;
3306           new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3307            _exception);
3308           break;
3309         }
3310       if (LocaleCompare("shave",option+1) == 0)
3311         {
3312           if (IsGeometry(arg1) == MagickFalse)
3313             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3314           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3315           new_image=ShaveImage(_image,&geometry,_exception);
3316           break;
3317         }
3318       if (LocaleCompare("shear",option+1) == 0)
3319         {
3320           flags=ParseGeometry(arg1,&geometry_info);
3321           if ((flags & RhoValue) == 0)
3322             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3323           if ((flags & SigmaValue) == 0)
3324             geometry_info.sigma=geometry_info.rho;
3325           new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3326             _exception);
3327           break;
3328         }
3329       if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3330         {
3331           flags=ParseGeometry(arg1,&geometry_info);
3332           if ((flags & RhoValue) == 0)
3333             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3334           if ((flags & SigmaValue) == 0)
3335             geometry_info.sigma=(double) QuantumRange/2.0;
3336           if ((flags & PercentValue) != 0)
3337             geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3338               100.0;
3339           (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3340                geometry_info.sigma,_exception);
3341           break;
3342         }
3343       if (LocaleCompare("sketch",option+1) == 0)
3344         {
3345           flags=ParseGeometry(arg1,&geometry_info);
3346           if ((flags & (RhoValue|SigmaValue)) == 0)
3347             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3348           if ((flags & SigmaValue) == 0)
3349             geometry_info.sigma=1.0;
3350           new_image=SketchImage(_image,geometry_info.rho,
3351             geometry_info.sigma,geometry_info.xi,_exception);
3352           break;
3353         }
3354       if (LocaleCompare("solarize",option+1) == 0)
3355         {
3356           if (IsGeometry(arg1) == MagickFalse)
3357             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3358           (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3359                  QuantumRange+1.0),_exception);
3360           break;
3361         }
3362       if (LocaleCompare("sparse-color",option+1) == 0)
3363         {
3364           parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3365           if ( parse < 0 )
3366             CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3367                 option,arg1);
3368           new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3369                _exception);
3370           break;
3371         }
3372       if (LocaleCompare("splice",option+1) == 0)
3373         {
3374           if (IsGeometry(arg1) == MagickFalse)
3375             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3376           flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3377           new_image=SpliceImage(_image,&geometry,_exception);
3378           break;
3379         }
3380       if (LocaleCompare("spread",option+1) == 0)
3381         {
3382           flags=ParseGeometry(arg1,&geometry_info);
3383           if ((flags & RhoValue) == 0)
3384             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3385           new_image=SpreadImage(_image,_image->interpolate,geometry_info.rho,
3386            _exception);
3387           break;
3388         }
3389       if (LocaleCompare("statistic",option+1) == 0)
3390         {
3391           parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3392           if ( parse < 0 )
3393             CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3394                  option,arg1);
3395           flags=ParseGeometry(arg2,&geometry_info);
3396           if ((flags & RhoValue) == 0)
3397             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3398           if ((flags & SigmaValue) == 0)
3399             geometry_info.sigma=geometry_info.rho;
3400           new_image=StatisticImage(_image,(StatisticType)parse,
3401                (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3402                _exception);
3403           break;
3404         }
3405       if (LocaleCompare("strip",option+1) == 0)
3406         {
3407           (void) StripImage(_image,_exception);
3408           break;
3409         }
3410       if (LocaleCompare("swirl",option+1) == 0)
3411         {
3412           flags=ParseGeometry(arg1,&geometry_info);
3413           if ((flags & RhoValue) == 0)
3414             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3415           new_image=SwirlImage(_image,geometry_info.rho,
3416             _image->interpolate,_exception);
3417           break;
3418         }
3419       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3420     }
3421     case 't':
3422     {
3423       if (LocaleCompare("threshold",option+1) == 0)
3424         {
3425           double
3426             threshold;
3427
3428           threshold=(double) QuantumRange/2;
3429           if (IfNormalOp) {
3430             if (IsGeometry(arg1) == MagickFalse)
3431               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3432             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3433           }
3434           (void) BilevelImage(_image,threshold,_exception);
3435           break;
3436         }
3437       if (LocaleCompare("thumbnail",option+1) == 0)
3438         {
3439           if (IsGeometry(arg1) == MagickFalse)
3440             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3441           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3442           new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3443             _exception);
3444           break;
3445         }
3446       if (LocaleCompare("tint",option+1) == 0)
3447         {
3448           if (IsGeometry(arg1) == MagickFalse)
3449             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3450           new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3451           break;
3452         }
3453       if (LocaleCompare("transform",option+1) == 0)
3454         {
3455           CLIWandWarnReplaced("+distort AffineProjection");
3456           new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3457           break;
3458         }
3459       if (LocaleCompare("transparent",option+1) == 0)
3460         {
3461           PixelInfo
3462             target;
3463
3464           (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3465           (void) TransparentPaintImage(_image,&target,(Quantum)
3466             TransparentAlpha,IsPlusOp,_exception);
3467           break;
3468         }
3469       if (LocaleCompare("transpose",option+1) == 0)
3470         {
3471           new_image=TransposeImage(_image,_exception);
3472           break;
3473         }
3474       if (LocaleCompare("transverse",option+1) == 0)
3475         {
3476           new_image=TransverseImage(_image,_exception);
3477           break;
3478         }
3479       if (LocaleCompare("trim",option+1) == 0)
3480         {
3481           new_image=TrimImage(_image,_exception);
3482           break;
3483         }
3484       if (LocaleCompare("type",option+1) == 0)
3485         {
3486           /* Note that "type" setting should have already been defined */
3487           (void) SetImageType(_image,_image_info->type,_exception);
3488           break;
3489         }
3490       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3491     }
3492     case 'u':
3493     {
3494       if (LocaleCompare("unique",option+1) == 0)
3495         {
3496           /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3497              Option is not documented, bt appears to be for "identify".
3498              We may need a identify specific verbose!
3499           */
3500           if (IsPlusOp) {
3501               (void) DeleteImageArtifact(_image,"identify:unique-colors");
3502               break;
3503             }
3504           (void) SetImageArtifact(_image,"identify:unique-colors","true");
3505           (void) SetImageArtifact(_image,"verbose","true");
3506           break;
3507         }
3508       if (LocaleCompare("unique-colors",option+1) == 0)
3509         {
3510           new_image=UniqueImageColors(_image,_exception);
3511           break;
3512         }
3513       if (LocaleCompare("unsharp",option+1) == 0)
3514         {
3515           flags=ParseGeometry(arg1,&geometry_info);
3516           if ((flags & (RhoValue|SigmaValue)) == 0)
3517             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3518           if ((flags & SigmaValue) == 0)
3519             geometry_info.sigma=1.0;
3520           if ((flags & XiValue) == 0)
3521             geometry_info.xi=1.0;
3522           if ((flags & PsiValue) == 0)
3523             geometry_info.psi=0.05;
3524           new_image=UnsharpMaskImage(_image,geometry_info.rho,
3525             geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3526           break;
3527         }
3528       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3529     }
3530     case 'v':
3531     {
3532       if (LocaleCompare("verbose",option+1) == 0)
3533         {
3534           /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3535              three places!   ImageArtifact   ImageOption  _image_info->verbose
3536              Some how new images also get this artifact!
3537           */
3538           (void) SetImageArtifact(_image,option+1,
3539                            IfNormalOp ? "true" : "false" );
3540           break;
3541         }
3542       if (LocaleCompare("vignette",option+1) == 0)
3543         {
3544           flags=ParseGeometry(arg1,&geometry_info);
3545           if ((flags & (RhoValue|SigmaValue)) == 0)
3546             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3547           if ((flags & SigmaValue) == 0)
3548             geometry_info.sigma=1.0;
3549           if ((flags & XiValue) == 0)
3550             geometry_info.xi=0.1*_image->columns;
3551           if ((flags & PsiValue) == 0)
3552             geometry_info.psi=0.1*_image->rows;
3553           if ((flags & PercentValue) != 0)
3554             {
3555               geometry_info.xi*=(double) _image->columns/100.0;
3556               geometry_info.psi*=(double) _image->rows/100.0;
3557             }
3558           new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3559             (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3560             ceil(geometry_info.psi-0.5),_exception);
3561           break;
3562         }
3563       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3564     }
3565     case 'w':
3566     {
3567       if (LocaleCompare("wave",option+1) == 0)
3568         {
3569           flags=ParseGeometry(arg1,&geometry_info);
3570           if ((flags & (RhoValue|SigmaValue)) == 0)
3571             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3572           if ((flags & SigmaValue) == 0)
3573             geometry_info.sigma=1.0;
3574           new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3575             _image->interpolate,_exception);
3576           break;
3577         }
3578       if (LocaleCompare("wavelet-denoise",option+1) == 0)
3579         {
3580           flags=ParseGeometry(arg1,&geometry_info);
3581           if ((flags & RhoValue) == 0)
3582             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3583           if ((flags & PercentValue) != 0)
3584             {
3585               geometry_info.rho=QuantumRange*geometry_info.rho/100.0;
3586               geometry_info.sigma=QuantumRange*geometry_info.sigma/100.0;
3587             }
3588           if ((flags & SigmaValue) == 0)
3589             geometry_info.sigma=0.0;
3590           new_image=WaveletDenoiseImage(_image,geometry_info.rho,
3591             geometry_info.sigma,_exception);
3592           break;
3593         }
3594       if (LocaleCompare("white-threshold",option+1) == 0)
3595         {
3596           if (IsGeometry(arg1) == MagickFalse)
3597             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3598           (void) WhiteThresholdImage(_image,arg1,_exception);
3599           break;
3600         }
3601       if (LocaleCompare("write-mask",option+1) == 0)
3602         {
3603           /* Note: arguments do not have percent escapes expanded */
3604           Image
3605             *mask;
3606
3607           if (IfPlusOp)
3608             { /* Remove a mask. */
3609               (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,
3610                 _exception);
3611               break;
3612             }
3613           /* Set the image mask. */
3614           mask=GetImageCache(_image_info,arg1,_exception);
3615           if (mask == (Image *) NULL)
3616             break;
3617           (void) SetImageMask(_image,WritePixelMask,mask,_exception);
3618           mask=DestroyImage(mask);
3619           break;
3620         }
3621       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3622     }
3623     default:
3624       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3625   }
3626   /* clean up percent escape interpreted strings */
3627   if (arg1 != arg1n )
3628     arg1=DestroyString((char *)arg1);
3629   if (arg2 != arg2n )
3630     arg2=DestroyString((char *)arg2);
3631
3632   /* Replace current image with any image that was generated
3633      and set image point to last image (so image->next is correct) */
3634   if (new_image != (Image *) NULL)
3635     ReplaceImageInListReturnLast(&_image,new_image);
3636
3637   return(MagickTrue);
3638 #undef _image_info
3639 #undef _draw_info
3640 #undef _quantize_info
3641 #undef _image
3642 #undef _exception
3643 #undef IfNormalOp
3644 #undef IfPlusOp
3645 #undef IsNormalOp
3646 #undef IsPlusOp
3647 }
3648
3649 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3650   const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3651 {
3652 #if !USE_WAND_METHODS
3653   size_t
3654     n,
3655     i;
3656 #endif
3657
3658   assert(cli_wand != (MagickCLI *) NULL);
3659   assert(cli_wand->signature == MagickWandSignature);
3660   assert(cli_wand->wand.signature == MagickWandSignature);
3661   assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3662
3663   if (cli_wand->wand.debug != MagickFalse)
3664     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3665          "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3666
3667 #if !USE_WAND_METHODS
3668   /* FUTURE add appropriate tracing */
3669   i=0;
3670   n=GetImageListLength(cli_wand->wand.images);
3671   cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3672   while (1) {
3673     i++;
3674     CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3675     if ( cli_wand->wand.images->next == (Image *) NULL )
3676       break;
3677     cli_wand->wand.images=cli_wand->wand.images->next;
3678   }
3679   assert( i == n );
3680   cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3681 #else
3682   MagickResetIterator(&cli_wand->wand);
3683   while (MagickNextImage(&cli_wand->wand) != MagickFalse)
3684     (void) CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3685   MagickResetIterator(&cli_wand->wand);
3686 #endif
3687   return(MagickTrue);
3688 }
3689 \f
3690 /*
3691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3692 %                                                                             %
3693 %                                                                             %
3694 %                                                                             %
3695 +     C L I L i s t O p e r a t o r I m a g e s                               %
3696 %                                                                             %
3697 %                                                                             %
3698 %                                                                             %
3699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3700 %
3701 %  CLIListOperatorImages() applies a single operation that is apply to the
3702 %  entire image list as a whole. The result is often a complete replacment
3703 %  of the image list with a completely new list, or with just a single image
3704 %  result.
3705 %
3706 %  The format of the MogrifyImage method is:
3707 %
3708 %    MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3709 %      const char *option,const char *arg1,const char *arg2)
3710 %
3711 %  A description of each parameter follows:
3712 %
3713 %    o cli_wand: structure holding settings to be applied
3714 %
3715 %    o option:  The option string for the operation
3716 %
3717 %    o arg1, arg2: optional argument strings to the operation
3718 %        arg2 is currently not used
3719 %
3720 */
3721 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3722   const char *option,const char *arg1n,const char *arg2n)
3723 {
3724   const char    /* percent escaped versions of the args */
3725     *arg1,
3726     *arg2;
3727
3728   Image
3729     *new_images;
3730
3731   MagickStatusType
3732     status;
3733
3734   ssize_t
3735     parse;
3736
3737 #define _image_info     (cli_wand->wand.image_info)
3738 #define _images         (cli_wand->wand.images)
3739 #define _exception      (cli_wand->wand.exception)
3740 #define _draw_info      (cli_wand->draw_info)
3741 #define _quantize_info  (cli_wand->quantize_info)
3742 #define _process_flags  (cli_wand->process_flags)
3743 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
3744 #define IfNormalOp      (*option=='-')
3745 #define IfPlusOp        (*option!='-')
3746 #define IsNormalOp      IfNormalOp ? MagickTrue : MagickFalse
3747
3748   assert(cli_wand != (MagickCLI *) NULL);
3749   assert(cli_wand->signature == MagickWandSignature);
3750   assert(cli_wand->wand.signature == MagickWandSignature);
3751   assert(_images != (Image *) NULL);             /* _images must be present */
3752
3753   if (cli_wand->wand.debug != MagickFalse)
3754     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3755        "- List Operator: %s \"%s\" \"%s\"", option,
3756        arg1n == (const char *) NULL ? "null" : arg1n,
3757        arg2n == (const char *) NULL ? "null" : arg2n);
3758
3759   arg1 = arg1n;
3760   arg2 = arg2n;
3761
3762   /* Interpret Percent Escapes in Arguments - using first image */
3763   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3764         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3765        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3766     /* Interpret Percent escapes in argument 1 */
3767     if (arg1n != (char *) NULL) {
3768       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3769       if (arg1 == (char *) NULL) {
3770         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3771         arg1=arg1n;  /* use the given argument as is */
3772       }
3773     }
3774     if (arg2n != (char *) NULL) {
3775       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3776       if (arg2 == (char *) NULL) {
3777         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3778         arg2=arg2n;  /* use the given argument as is */
3779       }
3780     }
3781   }
3782 #undef _process_flags
3783 #undef _option_type
3784
3785   status=MagickTrue;
3786   new_images=NewImageList();
3787
3788   switch (*(option+1))
3789   {
3790     case 'a':
3791     {
3792       if (LocaleCompare("append",option+1) == 0)
3793         {
3794           new_images=AppendImages(_images,IsNormalOp,_exception);
3795           break;
3796         }
3797       if (LocaleCompare("average",option+1) == 0)
3798         {
3799           CLIWandWarnReplaced("-evaluate-sequence Mean");
3800           (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",
3801             NULL);
3802           break;
3803         }
3804       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3805     }
3806     case 'c':
3807     {
3808       if (LocaleCompare("channel-fx",option+1) == 0)
3809         {
3810           new_images=ChannelFxImage(_images,arg1,_exception);
3811           break;
3812         }
3813       if (LocaleCompare("clut",option+1) == 0)
3814         {
3815           Image
3816             *clut_image;
3817
3818           /* FUTURE - make this a compose option, and thus can be used
3819              with layers compose or even compose last image over all other
3820              _images.
3821           */
3822           new_images=RemoveFirstImageFromList(&_images);
3823           clut_image=RemoveLastImageFromList(&_images);
3824           /* FUTURE - produce Exception, rather than silent fail */
3825           if (clut_image == (Image *) NULL)
3826             break;
3827           (void) ClutImage(new_images,clut_image,new_images->interpolate,
3828             _exception);
3829           clut_image=DestroyImage(clut_image);
3830           break;
3831         }
3832       if (LocaleCompare("coalesce",option+1) == 0)
3833         {
3834           new_images=CoalesceImages(_images,_exception);
3835           break;
3836         }
3837       if (LocaleCompare("combine",option+1) == 0)
3838         {
3839           parse=(ssize_t) _images->colorspace;
3840           if (_images->number_channels < GetImageListLength(_images))
3841             parse=sRGBColorspace;
3842           if ( IfPlusOp )
3843             parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3844           if (parse < 0)
3845             CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3846               arg1);
3847           new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3848           break;
3849         }
3850       if (LocaleCompare("compare",option+1) == 0)
3851         {
3852           double
3853             distortion;
3854
3855           Image
3856             *image,
3857             *reconstruct_image;
3858
3859           MetricType
3860             metric;
3861
3862           /*
3863             Mathematically and visually annotate the difference between an
3864             image and its reconstruction.
3865           */
3866           image=RemoveFirstImageFromList(&_images);
3867           reconstruct_image=RemoveFirstImageFromList(&_images);
3868           /* FUTURE - produce Exception, rather than silent fail */
3869           if (reconstruct_image == (Image *) NULL)
3870             break;
3871           metric=UndefinedErrorMetric;
3872           option=GetImageOption(_image_info,"metric");
3873           if (option != (const char *) NULL)
3874             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3875               MagickFalse,option);
3876           new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3877             _exception);
3878           (void) distortion;
3879           reconstruct_image=DestroyImage(reconstruct_image);
3880           image=DestroyImage(image);
3881           break;
3882         }
3883       if (LocaleCompare("complex",option+1) == 0)
3884         {
3885           parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3886           if (parse < 0)
3887             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3888               option,arg1);
3889           new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3890           break;
3891         }
3892       if (LocaleCompare("composite",option+1) == 0)
3893         {
3894           CompositeOperator
3895             compose;
3896
3897           const char*
3898             value;
3899
3900           MagickBooleanType
3901             clip_to_self;
3902
3903           Image
3904             *mask_image,
3905             *source_image;
3906
3907           RectangleInfo
3908             geometry;
3909
3910           /* Compose value from "-compose" option only */
3911           value=GetImageOption(_image_info,"compose");
3912           if (value == (const char *) NULL)
3913             compose=OverCompositeOp;  /* use Over not source_image->compose */
3914           else
3915             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3916               MagickFalse,value);
3917
3918           /* Get "clip-to-self" expert setting (false is normal) */
3919           clip_to_self=GetCompositeClipToSelf(compose);
3920           value=GetImageOption(_image_info,"compose:clip-to-self");
3921           if (value != (const char *) NULL)
3922             clip_to_self=IsStringTrue(value);
3923           value=GetImageOption(_image_info,"compose:outside-overlay");
3924           if (value != (const char *) NULL)
3925             clip_to_self=IsStringFalse(value);  /* deprecated */
3926
3927           new_images=RemoveFirstImageFromList(&_images);
3928           source_image=RemoveFirstImageFromList(&_images);
3929           if (source_image == (Image *) NULL)
3930             break; /* FUTURE - produce Exception, rather than silent fail */
3931
3932           /* FUTURE - this should not be here! - should be part of -geometry */
3933           if (source_image->geometry != (char *) NULL)
3934             {
3935               RectangleInfo
3936                 resize_geometry;
3937
3938               (void) ParseRegionGeometry(source_image,source_image->geometry,
3939                 &resize_geometry,_exception);
3940               if ((source_image->columns != resize_geometry.width) ||
3941                   (source_image->rows != resize_geometry.height))
3942                 {
3943                   Image
3944                     *resize_image;
3945
3946                   resize_image=ResizeImage(source_image,resize_geometry.width,
3947                     resize_geometry.height,source_image->filter,_exception);
3948                   if (resize_image != (Image *) NULL)
3949                     {
3950                       source_image=DestroyImage(source_image);
3951                       source_image=resize_image;
3952                     }
3953                 }
3954             }
3955           SetGeometry(source_image,&geometry);
3956           (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3957           GravityAdjustGeometry(new_images->columns,new_images->rows,
3958             new_images->gravity, &geometry);
3959           mask_image=RemoveFirstImageFromList(&_images);
3960           if (mask_image == (Image *) NULL)
3961             status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3962               geometry.x,geometry.y,_exception);
3963           else
3964             {
3965               if ((compose == DisplaceCompositeOp) ||
3966                   (compose == DistortCompositeOp))
3967                 {
3968                   status&=CompositeImage(source_image,mask_image,
3969                     CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3970                   status&=CompositeImage(new_images,source_image,compose,
3971                     clip_to_self,geometry.x,geometry.y,_exception);
3972                 }
3973               else
3974                 {
3975                   Image
3976                     *clone_image;
3977
3978                   clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
3979                   if (clone_image == (Image *) NULL)
3980                     break;
3981                   status&=CompositeImage(new_images,source_image,compose,
3982                     clip_to_self,geometry.x,geometry.y,_exception);
3983                   status&=CompositeImage(new_images,mask_image,
3984                     CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
3985                   status&=CompositeImage(clone_image,new_images,OverCompositeOp,
3986                     clip_to_self,0,0,_exception);
3987                   new_images=DestroyImage(new_images);
3988                   new_images=clone_image;
3989                 }
3990               mask_image=DestroyImage(mask_image);
3991             }
3992           source_image=DestroyImage(source_image);
3993           break;
3994         }
3995         if (LocaleCompare("copy",option+1) == 0)
3996           {
3997             Image
3998               *source_image;
3999
4000             OffsetInfo
4001               offset;
4002
4003             RectangleInfo
4004               geometry;
4005
4006             /*
4007               Copy image pixels.
4008             */
4009             if (IsGeometry(arg1) == MagickFalse)
4010               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4011             if (IsGeometry(arg2) == MagickFalse)
4012               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4013             (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
4014             offset.x=geometry.x;
4015             offset.y=geometry.y;
4016             source_image=_images;
4017             if (source_image->next != (Image *) NULL)
4018               source_image=source_image->next;
4019             (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
4020             (void) CopyImagePixels(_images,source_image,&geometry,&offset,
4021               _exception);
4022             break;
4023           }
4024       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4025     }
4026     case 'd':
4027     {
4028       if (LocaleCompare("deconstruct",option+1) == 0)
4029         {
4030           CLIWandWarnReplaced("-layer CompareAny");
4031           (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
4032           break;
4033         }
4034       if (LocaleCompare("delete",option+1) == 0)
4035         {
4036           if (IfNormalOp)
4037             DeleteImages(&_images,arg1,_exception);
4038           else
4039             DeleteImages(&_images,"-1",_exception);
4040           break;
4041         }
4042       if (LocaleCompare("duplicate",option+1) == 0)
4043         {
4044           if (IfNormalOp)
4045             {
4046               const char
4047                 *p;
4048
4049               size_t
4050                 number_duplicates;
4051
4052               if (IsGeometry(arg1) == MagickFalse)
4053                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
4054                       arg1);
4055               number_duplicates=(size_t) StringToLong(arg1);
4056               p=strchr(arg1,',');
4057               if (p == (const char *) NULL)
4058                 new_images=DuplicateImages(_images,number_duplicates,"-1",
4059                   _exception);
4060               else
4061                 new_images=DuplicateImages(_images,number_duplicates,p,
4062                   _exception);
4063             }
4064           else
4065             new_images=DuplicateImages(_images,1,"-1",_exception);
4066           AppendImageToList(&_images, new_images);
4067           new_images=(Image *) NULL;
4068           break;
4069         }
4070       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4071     }
4072     case 'e':
4073     {
4074       if (LocaleCompare("evaluate-sequence",option+1) == 0)
4075         {
4076           parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
4077           if (parse < 0)
4078             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
4079               option,arg1);
4080           new_images=EvaluateImages(_images,(MagickEvaluateOperator) parse,
4081             _exception);
4082           break;
4083         }
4084       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4085     }
4086     case 'f':
4087     {
4088       if (LocaleCompare("fft",option+1) == 0)
4089         {
4090           new_images=ForwardFourierTransformImage(_images,IsNormalOp,
4091            _exception);
4092           break;
4093         }
4094       if (LocaleCompare("flatten",option+1) == 0)
4095         {
4096           /* REDIRECTED to use -layers flatten instead */
4097           (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4098           break;
4099         }
4100       if (LocaleCompare("fx",option+1) == 0)
4101         {
4102           new_images=FxImage(_images,arg1,_exception);
4103           break;
4104         }
4105       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4106     }
4107     case 'h':
4108     {
4109       if (LocaleCompare("hald-clut",option+1) == 0)
4110         {
4111           /* FUTURE - make this a compose option (and thus layers compose )
4112              or perhaps compose last image over all other _images.
4113           */
4114           Image
4115             *hald_image;
4116
4117           new_images=RemoveFirstImageFromList(&_images);
4118           hald_image=RemoveLastImageFromList(&_images);
4119           if (hald_image == (Image *) NULL)
4120             break;
4121           (void) HaldClutImage(new_images,hald_image,_exception);
4122           hald_image=DestroyImage(hald_image);
4123           break;
4124         }
4125       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4126     }
4127     case 'i':
4128     {
4129       if (LocaleCompare("ift",option+1) == 0)
4130         {
4131           Image
4132             *magnitude_image,
4133             *phase_image;
4134
4135            magnitude_image=RemoveFirstImageFromList(&_images);
4136            phase_image=RemoveFirstImageFromList(&_images);
4137           /* FUTURE - produce Exception, rather than silent fail */
4138            if (phase_image == (Image *) NULL)
4139              break;
4140            new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4141              IsNormalOp,_exception);
4142            magnitude_image=DestroyImage(magnitude_image);
4143            phase_image=DestroyImage(phase_image);
4144           break;
4145         }
4146       if (LocaleCompare("insert",option+1) == 0)
4147         {
4148           Image
4149             *insert_image,
4150             *index_image;
4151
4152           ssize_t
4153             index;
4154
4155           if (IfNormalOp && (IsGeometry(arg1) == MagickFalse))
4156             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4157           index=0;
4158           insert_image=RemoveLastImageFromList(&_images);
4159           if (IfNormalOp)
4160             index=(ssize_t) StringToLong(arg1);
4161           index_image=insert_image;
4162           if (index == 0)
4163             PrependImageToList(&_images,insert_image);
4164           else if (index == (ssize_t) GetImageListLength(_images))
4165             AppendImageToList(&_images,insert_image);
4166           else
4167             {
4168                index_image=GetImageFromList(_images,index-1);
4169                if (index_image == (Image *) NULL)
4170                  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4171               InsertImageInList(&index_image,insert_image);
4172             }
4173           _images=GetFirstImageInList(index_image);
4174           break;
4175         }
4176       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4177     }
4178     case 'l':
4179     {
4180       if (LocaleCompare("layers",option+1) == 0)
4181         {
4182           parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4183           if ( parse < 0 )
4184             CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4185                  option,arg1);
4186           switch ((LayerMethod) parse)
4187           {
4188             case CoalesceLayer:
4189             {
4190               new_images=CoalesceImages(_images,_exception);
4191               break;
4192             }
4193             case CompareAnyLayer:
4194             case CompareClearLayer:
4195             case CompareOverlayLayer:
4196             default:
4197             {
4198               new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4199                    _exception);
4200               break;
4201             }
4202             case MergeLayer:
4203             case FlattenLayer:
4204             case MosaicLayer:
4205             case TrimBoundsLayer:
4206             {
4207               new_images=MergeImageLayers(_images,(LayerMethod) parse,
4208                 _exception);
4209               break;
4210             }
4211             case DisposeLayer:
4212             {
4213               new_images=DisposeImages(_images,_exception);
4214               break;
4215             }
4216             case OptimizeImageLayer:
4217             {
4218               new_images=OptimizeImageLayers(_images,_exception);
4219               break;
4220             }
4221             case OptimizePlusLayer:
4222             {
4223               new_images=OptimizePlusImageLayers(_images,_exception);
4224               break;
4225             }
4226             case OptimizeTransLayer:
4227             {
4228               OptimizeImageTransparency(_images,_exception);
4229               break;
4230             }
4231             case RemoveDupsLayer:
4232             {
4233               RemoveDuplicateLayers(&_images,_exception);
4234               break;
4235             }
4236             case RemoveZeroLayer:
4237             {
4238               RemoveZeroDelayLayers(&_images,_exception);
4239               break;
4240             }
4241             case OptimizeLayer:
4242             { /* General Purpose, GIF Animation Optimizer.  */
4243               new_images=CoalesceImages(_images,_exception);
4244               if (new_images == (Image *) NULL)
4245                 break;
4246               _images=DestroyImageList(_images);
4247               _images=OptimizeImageLayers(new_images,_exception);
4248               if (_images == (Image *) NULL)
4249                 break;
4250               new_images=DestroyImageList(new_images);
4251               OptimizeImageTransparency(_images,_exception);
4252               (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4253                 _exception);
4254               break;
4255             }
4256             case CompositeLayer:
4257             {
4258               Image
4259                 *source;
4260
4261               RectangleInfo
4262                 geometry;
4263
4264               CompositeOperator
4265                 compose;
4266
4267               const char*
4268                 value;
4269
4270               value=GetImageOption(_image_info,"compose");
4271               compose=OverCompositeOp;  /* Default to Over */
4272               if (value != (const char *) NULL)
4273                 compose=(CompositeOperator) ParseCommandOption(
4274                       MagickComposeOptions,MagickFalse,value);
4275
4276               /* Split image sequence at the first 'NULL:' image. */
4277               source=_images;
4278               while (source != (Image *) NULL)
4279               {
4280                 source=GetNextImageInList(source);
4281                 if ((source != (Image *) NULL) &&
4282                     (LocaleCompare(source->magick,"NULL") == 0))
4283                   break;
4284               }
4285               if (source != (Image *) NULL)
4286                 {
4287                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4288                       (GetNextImageInList(source) == (Image *) NULL))
4289                     source=(Image *) NULL;
4290                   else
4291                     { /* Separate the two lists, junk the null: image.  */
4292                       source=SplitImageList(source->previous);
4293                       DeleteImageFromList(&source);
4294                     }
4295                 }
4296               if (source == (Image *) NULL)
4297                 {
4298                   (void) ThrowMagickException(_exception,GetMagickModule(),
4299                     OptionError,"MissingNullSeparator","layers Composite");
4300                   break;
4301                 }
4302               /* Adjust offset with gravity and virtual canvas.  */
4303               SetGeometry(_images,&geometry);
4304               (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4305               geometry.width=source->page.width != 0 ?
4306                 source->page.width : source->columns;
4307               geometry.height=source->page.height != 0 ?
4308                source->page.height : source->rows;
4309               GravityAdjustGeometry(_images->page.width != 0 ?
4310                 _images->page.width : _images->columns,
4311                 _images->page.height != 0 ? _images->page.height :
4312                 _images->rows,_images->gravity,&geometry);
4313
4314               /* Compose the two image sequences together */
4315               CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4316                 _exception);
4317               source=DestroyImageList(source);
4318               break;
4319             }
4320           }
4321           break;
4322         }
4323       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4324     }
4325     case 'm':
4326     {
4327       if (LocaleCompare("map",option+1) == 0)
4328         {
4329           CLIWandWarnReplaced("+remap");
4330           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4331           break;
4332         }
4333       if (LocaleCompare("metric",option+1) == 0)
4334         {
4335           (void) SetImageOption(_image_info,option+1,arg1);
4336           break;
4337         }
4338       if (LocaleCompare("morph",option+1) == 0)
4339         {
4340           Image
4341             *morph_image;
4342
4343           if (IsGeometry(arg1) == MagickFalse)
4344             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4345           morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4346             _exception);
4347           if (morph_image == (Image *) NULL)
4348             break;
4349           _images=DestroyImageList(_images);
4350           _images=morph_image;
4351           break;
4352         }
4353       if (LocaleCompare("mosaic",option+1) == 0)
4354         {
4355           /* REDIRECTED to use -layers mosaic instead */
4356           (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4357           break;
4358         }
4359       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4360     }
4361     case 'p':
4362     {
4363       if (LocaleCompare("poly",option+1) == 0)
4364         {
4365           double
4366             *args;
4367
4368           ssize_t
4369             count;
4370
4371           /* convert argument string into an array of doubles */
4372           args = StringToArrayOfDoubles(arg1,&count,_exception);
4373           if (args == (double *) NULL )
4374             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4375           new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4376            _exception);
4377           args=(double *) RelinquishMagickMemory(args);
4378           break;
4379         }
4380       if (LocaleCompare("process",option+1) == 0)
4381         {
4382           /* FUTURE: better parsing using ScriptToken() from string ??? */
4383           char
4384             **arguments;
4385
4386           int
4387             j,
4388             number_arguments;
4389
4390           arguments=StringToArgv(arg1,&number_arguments);
4391           if (arguments == (char **) NULL)
4392             break;
4393           if (strchr(arguments[1],'=') != (char *) NULL)
4394             {
4395               char
4396                 breaker,
4397                 quote,
4398                 *token;
4399
4400               const char
4401                 *arguments;
4402
4403               int
4404                 next,
4405                 status;
4406
4407               size_t
4408                 length;
4409
4410               TokenInfo
4411                 *token_info;
4412
4413               /*
4414                 Support old style syntax, filter="-option arg1".
4415               */
4416               assert(arg1 != (const char *) NULL);
4417               length=strlen(arg1);
4418               token=(char *) NULL;
4419               if (~length >= (MagickPathExtent-1))
4420                 token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4421                   sizeof(*token));
4422               if (token == (char *) NULL)
4423                 break;
4424               next=0;
4425               arguments=arg1;
4426               token_info=AcquireTokenInfo();
4427               status=Tokenizer(token_info,0,token,length,arguments,"","=",
4428                 "\"",'\0',&breaker,&next,&quote);
4429               token_info=DestroyTokenInfo(token_info);
4430               if (status == 0)
4431                 {
4432                   const char
4433                     *argv;
4434
4435                   argv=(&(arguments[next]));
4436                   (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4437                     _exception);
4438                 }
4439               token=DestroyString(token);
4440               break;
4441             }
4442           (void) SubstituteString(&arguments[1],"-","");
4443           (void) InvokeDynamicImageFilter(arguments[1],&_images,
4444             number_arguments-2,(const char **) arguments+2,_exception);
4445           for (j=0; j < number_arguments; j++)
4446             arguments[j]=DestroyString(arguments[j]);
4447           arguments=(char **) RelinquishMagickMemory(arguments);
4448           break;
4449         }
4450       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4451     }
4452     case 'r':
4453     {
4454       if (LocaleCompare("remap",option+1) == 0)
4455         {
4456           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4457           break;
4458         }
4459       if (LocaleCompare("reverse",option+1) == 0)
4460         {
4461           ReverseImageList(&_images);
4462           break;
4463         }
4464       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4465     }
4466     case 's':
4467     {
4468       if (LocaleCompare("smush",option+1) == 0)
4469         {
4470           /* FUTURE: this option needs more work to make better */
4471           ssize_t
4472             offset;
4473
4474           if (IsGeometry(arg1) == MagickFalse)
4475             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4476           offset=(ssize_t) StringToLong(arg1);
4477           new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4478           break;
4479         }
4480       if (LocaleCompare("subimage",option+1) == 0)
4481         {
4482           Image
4483             *base_image,
4484             *compare_image;
4485
4486           const char
4487             *value;
4488
4489           MetricType
4490             metric;
4491
4492           double
4493             similarity;
4494
4495           RectangleInfo
4496             offset;
4497
4498           base_image=GetImageFromList(_images,0);
4499           compare_image=GetImageFromList(_images,1);
4500
4501           /* Comparision Metric */
4502           metric=UndefinedErrorMetric;
4503           value=GetImageOption(_image_info,"metric");
4504           if (value != (const char *) NULL)
4505             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4506               MagickFalse,value);
4507
4508           new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4509             &offset,&similarity,_exception);
4510
4511           if (new_images != (Image *) NULL)
4512             {
4513               char
4514                 result[MagickPathExtent];
4515
4516               (void) FormatLocaleString(result,MagickPathExtent,"%lf",
4517                 similarity);
4518               (void) SetImageProperty(new_images,"subimage:similarity",result,
4519                 _exception);
4520               (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4521                 offset.x);
4522               (void) SetImageProperty(new_images,"subimage:x",result,
4523                 _exception);
4524               (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4525                 offset.y);
4526               (void) SetImageProperty(new_images,"subimage:y",result,
4527                 _exception);
4528               (void) FormatLocaleString(result,MagickPathExtent,
4529                 "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4530                 offset.height,(long) offset.x,(long) offset.y);
4531               (void) SetImageProperty(new_images,"subimage:offset",result,
4532                 _exception);
4533             }
4534           break;
4535         }
4536       if (LocaleCompare("swap",option+1) == 0)
4537         {
4538         Image
4539           *p,
4540           *q,
4541           *swap;
4542
4543         ssize_t
4544           index,
4545           swap_index;
4546
4547         index=(-1);
4548         swap_index=(-2);
4549         if (IfNormalOp) {
4550           GeometryInfo
4551             geometry_info;
4552
4553           MagickStatusType
4554             flags;
4555
4556           swap_index=(-1);
4557           flags=ParseGeometry(arg1,&geometry_info);
4558           if ((flags & RhoValue) == 0)
4559             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4560           index=(ssize_t) geometry_info.rho;
4561           if ((flags & SigmaValue) != 0)
4562             swap_index=(ssize_t) geometry_info.sigma;
4563         }
4564         p=GetImageFromList(_images,index);
4565         q=GetImageFromList(_images,swap_index);
4566         if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4567           if (IfNormalOp)
4568             CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4569           else
4570             CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4571         }
4572         if (p == q)
4573           CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4574         swap=CloneImage(p,0,0,MagickTrue,_exception);
4575         if (swap == (Image *) NULL)
4576           CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4577             option,GetExceptionMessage(errno));
4578         ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4579         ReplaceImageInList(&q,swap);
4580         _images=GetFirstImageInList(q);
4581         break;
4582       }
4583       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4584     }
4585     default:
4586       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4587   }
4588
4589   /* clean up percent escape interpreted strings */
4590   if (arg1 != arg1n )
4591     arg1=DestroyString((char *)arg1);
4592   if (arg2 != arg2n )
4593     arg2=DestroyString((char *)arg2);
4594
4595   /* if new image list generated, replace existing image list */
4596   if (new_images == (Image *) NULL)
4597     return(status == 0 ? MagickFalse : MagickTrue);
4598   _images=DestroyImageList(_images);
4599   _images=GetFirstImageInList(new_images);
4600   return(status == 0 ? MagickFalse : MagickTrue);
4601
4602 #undef _image_info
4603 #undef _images
4604 #undef _exception
4605 #undef _draw_info
4606 #undef _quantize_info
4607 #undef IfNormalOp
4608 #undef IfPlusOp
4609 #undef IsNormalOp
4610 }
4611 \f
4612 /*
4613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4614 %                                                                             %
4615 %                                                                             %
4616 %                                                                             %
4617 +   C L I N o I m a g e O p e r a t i o n s                                   %
4618 %                                                                             %
4619 %                                                                             %
4620 %                                                                             %
4621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4622 %
4623 %  CLINoImageOperator() Applies operations that may not actually need images
4624 %  in an image list.
4625 %
4626 %  The classic operators of this type is "-read", which actually creates
4627 %  images even when no images are present.  Or image stack operators, which
4628 %  can be applied (push or pop) to an empty image list.
4629 %
4630 %  Note that these operators may involve other special 'option' prefix
4631 %  characters other  than '-' or '+', namely parenthesis and braces.
4632 %
4633 %  The format of the CLINoImageOption method is:
4634 %
4635 %      void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4636 %           const char *arg1, const char *arg2)
4637 %
4638 %  A description of each parameter follows:
4639 %
4640 %    o cli_wand: the main CLI Wand to use. (sometimes not required)
4641 %
4642 %    o option: The special option (with any switch char) to process
4643 %
4644 %    o arg1 & arg2: Argument for option, if required
4645 %                   Currently arg2 is not used.
4646 %
4647 */
4648 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4649   const char *option,const char *arg1n,const char *arg2n)
4650 {
4651   const char    /* percent escaped versions of the args */
4652     *arg1,
4653     *arg2;
4654
4655 #define _image_info     (cli_wand->wand.image_info)
4656 #define _images         (cli_wand->wand.images)
4657 #define _exception      (cli_wand->wand.exception)
4658 #define _process_flags  (cli_wand->process_flags)
4659 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
4660 #define IfNormalOp      (*option=='-')
4661 #define IfPlusOp        (*option!='-')
4662
4663   assert(cli_wand != (MagickCLI *) NULL);
4664   assert(cli_wand->signature == MagickWandSignature);
4665   assert(cli_wand->wand.signature == MagickWandSignature);
4666
4667   if (cli_wand->wand.debug != MagickFalse)
4668     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4669       "- NoImage Operator: %s \"%s\" \"%s\"", option,
4670       arg1n != (char *) NULL ? arg1n : "",
4671       arg2n != (char *) NULL ? arg2n : "");
4672
4673   arg1 = arg1n;
4674   arg2 = arg2n;
4675
4676   /* Interpret Percent Escapes in Arguments - using first image */
4677   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4678         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4679        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4680     /* Interpret Percent escapes in argument 1 */
4681     if (arg1n != (char *) NULL) {
4682       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4683       if (arg1 == (char *) NULL) {
4684         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4685         arg1=arg1n;  /* use the given argument as is */
4686       }
4687     }
4688     if (arg2n != (char *) NULL) {
4689       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4690       if (arg2 == (char *) NULL) {
4691         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4692         arg2=arg2n;  /* use the given argument as is */
4693       }
4694     }
4695   }
4696 #undef _process_flags
4697 #undef _option_type
4698
4699   do {  /* break to exit code */
4700     /*
4701       No-op options  (ignore these)
4702     */
4703     if (LocaleCompare("noop",option+1) == 0)   /* zero argument */
4704       break;
4705     if (LocaleCompare("sans",option+1) == 0)   /* one argument */
4706       break;
4707     if (LocaleCompare("sans0",option+1) == 0)  /* zero argument */
4708       break;
4709     if (LocaleCompare("sans1",option+1) == 0)  /* one argument */
4710       break;
4711     if (LocaleCompare("sans2",option+1) == 0)  /* two arguments */
4712       break;
4713     /*
4714       Image Reading
4715     */
4716     if ( ( LocaleCompare("read",option+1) == 0 ) ||
4717       ( LocaleCompare("--",option) == 0 ) ) {
4718       /* Do Glob filename Expansion for 'arg1' then read all images.
4719       *
4720       * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4721       * (but attaching to the filenames in the generated argument list) any
4722       * [...] read modifiers that may be present.
4723       *
4724       * For example: It will expand '*.gif[20x20]' into a list such as
4725       * 'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
4726       *
4727       * NOTE: In IMv6 this was done globally across all images. This
4728       * meant you could include IM options in '@filename' lists, but you
4729       * could not include comments.   Doing it only for image read makes
4730       * it far more secure.
4731       *
4732       * Note: arguments do not have percent escapes expanded for security
4733       * reasons.
4734       */
4735       int      argc;
4736       char     **argv;
4737       ssize_t  i;
4738
4739       argc = 1;
4740       argv = (char **) &arg1;
4741
4742       /* Expand 'glob' expressions in the given filename.
4743         Expansion handles any 'coder:' prefix, or read modifiers attached
4744         to the filename, including them in the resulting expanded list.
4745       */
4746       if (ExpandFilenames(&argc,&argv) == MagickFalse)
4747         CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4748             option,GetExceptionMessage(errno));
4749
4750       /* loop over expanded filename list, and read then all in */
4751       for (i=0; i < (ssize_t) argc; i++) {
4752         Image *
4753           new_images;
4754         if (_image_info->ping != MagickFalse)
4755           new_images=PingImages(_image_info,argv[i],_exception);
4756         else
4757           new_images=ReadImages(_image_info,argv[i],_exception);
4758         AppendImageToList(&_images, new_images);
4759         argv[i]=DestroyString(argv[i]);
4760       }
4761       argv=(char **) RelinquishMagickMemory(argv);
4762       break;
4763     }
4764     /*
4765       Image Writing
4766       Note: Writing a empty image list is valid in specific cases
4767     */
4768     if (LocaleCompare("write",option+1) == 0) {
4769       /* Note: arguments do not have percent escapes expanded */
4770       char
4771         key[MagickPathExtent];
4772
4773       Image
4774         *write_images;
4775
4776       ImageInfo
4777         *write_info;
4778
4779       /* Need images, unless a "null:" output coder is used */
4780       if ( _images == (Image *) NULL ) {
4781         if ( LocaleCompare(arg1,"null:") == 0 )
4782           break;
4783         CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4784       }
4785
4786       (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4787       (void) DeleteImageRegistry(key);
4788       write_images=_images;
4789       if (IfPlusOp)
4790         write_images=CloneImageList(_images,_exception);
4791       write_info=CloneImageInfo(_image_info);
4792       (void) WriteImages(write_info,write_images,arg1,_exception);
4793       write_info=DestroyImageInfo(write_info);
4794       if (IfPlusOp)
4795         write_images=DestroyImageList(write_images);
4796       break;
4797     }
4798     /*
4799       Parenthesis and Brace operations
4800     */
4801     if (LocaleCompare("(",option) == 0) {
4802       /* stack 'push' images */
4803       Stack
4804         *node;
4805
4806       size_t
4807         size;
4808
4809       size=0;
4810       node=cli_wand->image_list_stack;
4811       for ( ; node != (Stack *) NULL; node=node->next)
4812         size++;
4813       if ( size >= MAX_STACK_DEPTH )
4814         CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4815       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4816       if (node == (Stack *) NULL)
4817         CLIWandExceptionBreak(ResourceLimitFatalError,
4818             "MemoryAllocationFailed",option);
4819       node->data = (void *)cli_wand->wand.images;
4820       node->next = cli_wand->image_list_stack;
4821       cli_wand->image_list_stack = node;
4822       cli_wand->wand.images = NewImageList();
4823
4824       /* handle respect-parenthesis */
4825       if (IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4826                     "respect-parenthesis")) != MagickFalse)
4827         option="{"; /* fall-thru so as to push image settings too */
4828       else
4829         break;
4830       /* fall thru to operation */
4831     }
4832     if (LocaleCompare("{",option) == 0) {
4833       /* stack 'push' of image_info settings */
4834       Stack
4835         *node;
4836
4837       size_t
4838         size;
4839
4840       size=0;
4841       node=cli_wand->image_info_stack;
4842       for ( ; node != (Stack *) NULL; node=node->next)
4843         size++;
4844       if ( size >= MAX_STACK_DEPTH )
4845         CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4846       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4847       if (node == (Stack *) NULL)
4848         CLIWandExceptionBreak(ResourceLimitFatalError,
4849             "MemoryAllocationFailed",option);
4850
4851       node->data = (void *)cli_wand->wand.image_info;
4852       node->next = cli_wand->image_info_stack;
4853
4854       cli_wand->image_info_stack = node;
4855       cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4856       if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4857         CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4858             option);
4859         cli_wand->wand.image_info = (ImageInfo *)node->data;
4860         node = (Stack *)RelinquishMagickMemory(node);
4861         break;
4862       }
4863
4864       break;
4865     }
4866     if (LocaleCompare(")",option) == 0) {
4867       /* pop images from stack */
4868       Stack
4869         *node;
4870
4871       node = (Stack *)cli_wand->image_list_stack;
4872       if ( node == (Stack *) NULL)
4873         CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4874       cli_wand->image_list_stack = node->next;
4875
4876       AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4877       cli_wand->wand.images= (Image *)node->data;
4878       node = (Stack *)RelinquishMagickMemory(node);
4879
4880       /* handle respect-parenthesis - of the previous 'pushed' settings */
4881       node = cli_wand->image_info_stack;
4882       if ( node != (Stack *) NULL)
4883         {
4884           if (IsStringTrue(GetImageOption(
4885                 cli_wand->wand.image_info,"respect-parenthesis")) != MagickFalse)
4886             option="}"; /* fall-thru so as to pop image settings too */
4887           else
4888             break;
4889         }
4890       else
4891         break;
4892       /* fall thru to next if */
4893     }
4894     if (LocaleCompare("}",option) == 0) {
4895       /* pop image_info settings from stack */
4896       Stack
4897         *node;
4898
4899       node = (Stack *)cli_wand->image_info_stack;
4900       if ( node == (Stack *) NULL)
4901         CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4902       cli_wand->image_info_stack = node->next;
4903
4904       (void) DestroyImageInfo(cli_wand->wand.image_info);
4905       cli_wand->wand.image_info = (ImageInfo *)node->data;
4906       node = (Stack *)RelinquishMagickMemory(node);
4907
4908       GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4909       cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4910       cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4911
4912       break;
4913     }
4914       if (LocaleCompare("print",option+1) == 0)
4915         {
4916           (void) FormatLocaleFile(stdout,"%s",arg1);
4917           break;
4918         }
4919     if (LocaleCompare("set",option+1) == 0)
4920       {
4921         /* Settings are applied to each image in memory in turn (if any).
4922            While a option: only need to be applied once globally.
4923
4924            NOTE: rguments have not been automatically percent expaneded
4925         */
4926
4927         /* escape the 'key' once only, using first image. */
4928         arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4929         if (arg1 == (char *) NULL)
4930           CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4931                 option);
4932
4933         if (LocaleNCompare(arg1,"registry:",9) == 0)
4934           {
4935             if (IfPlusOp)
4936               {
4937                 (void) DeleteImageRegistry(arg1+9);
4938                 arg1=DestroyString((char *)arg1);
4939                 break;
4940               }
4941             arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4942             if (arg2 == (char *) NULL) {
4943               arg1=DestroyString((char *)arg1);
4944               CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4945                     option);
4946             }
4947             (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4948             arg1=DestroyString((char *)arg1);
4949             arg2=DestroyString((char *)arg2);
4950             break;
4951           }
4952         if (LocaleNCompare(arg1,"option:",7) == 0)
4953           {
4954             /* delete equivelent artifact from all images (if any) */
4955             if (_images != (Image *) NULL)
4956               {
4957                 MagickResetIterator(&cli_wand->wand);
4958                 while (MagickNextImage(&cli_wand->wand) != MagickFalse)
4959                   (void) DeleteImageArtifact(_images,arg1+7);
4960                 MagickResetIterator(&cli_wand->wand);
4961               }
4962             /* now set/delete the global option as needed */
4963             /* FUTURE: make escapes in a global 'option:' delayed */
4964             arg2=(char *) NULL;
4965             if (IfNormalOp)
4966               {
4967                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4968                 if (arg2 == (char *) NULL)
4969                   CLIWandExceptionBreak(OptionWarning,
4970                        "InterpretPropertyFailure",option);
4971               }
4972             (void) SetImageOption(_image_info,arg1+7,arg2);
4973             arg1=DestroyString((char *)arg1);
4974             arg2=DestroyString((char *)arg2);
4975             break;
4976           }
4977         /* Set Artifacts/Properties/Attributes all images (required) */
4978         if ( _images == (Image *) NULL )
4979           CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4980
4981         MagickResetIterator(&cli_wand->wand);
4982         while (MagickNextImage(&cli_wand->wand) != MagickFalse)
4983           {
4984             arg2=(char *) NULL;
4985             if (IfNormalOp)
4986               {
4987                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4988                 if (arg2 == (char *) NULL)
4989                   CLIWandExceptionBreak(OptionWarning,
4990                        "InterpretPropertyFailure",option);
4991               }
4992             if (LocaleNCompare(arg1,"artifact:",9) == 0)
4993               (void) SetImageArtifact(_images,arg1+9,arg2);
4994             else if (LocaleNCompare(arg1,"property:",9) == 0)
4995               (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4996             else
4997               (void) SetImageProperty(_images,arg1,arg2,_exception);
4998             arg2=DestroyString((char *)arg2);
4999           }
5000         MagickResetIterator(&cli_wand->wand);
5001         arg1=DestroyString((char *)arg1);
5002         break;
5003      }
5004     if (LocaleCompare("clone",option+1) == 0) {
5005         Image
5006           *new_images;
5007
5008         if (*option == '+')
5009           arg1=AcquireString("-1");
5010         if (IsSceneGeometry(arg1,MagickFalse) == MagickFalse)
5011           CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
5012         if ( cli_wand->image_list_stack == (Stack *) NULL)
5013           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5014         new_images = (Image *)cli_wand->image_list_stack->data;
5015         if (new_images == (Image *) NULL)
5016           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5017         new_images=CloneImages(new_images,arg1,_exception);
5018         if (new_images == (Image *) NULL)
5019           CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
5020         AppendImageToList(&_images,new_images);
5021         break;
5022       }
5023     /*
5024        Informational Operations.
5025
5026        Note that these do not require either a cli-wand or images!
5027        Though currently a cli-wand much be provided regardless.
5028     */
5029     if (LocaleCompare("version",option+1) == 0)
5030       {
5031         ListMagickVersion(stdout);
5032         break;
5033       }
5034     if (LocaleCompare("list",option+1) == 0) {
5035       /*
5036          FUTURE: This 'switch' should really be part of MagickCore
5037       */
5038       ssize_t
5039         list;
5040
5041       list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
5042       if ( list < 0 ) {
5043         CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
5044         break;
5045       }
5046       switch (list)
5047       {
5048         case MagickCoderOptions:
5049         {
5050           (void) ListCoderInfo((FILE *) NULL,_exception);
5051           break;
5052         }
5053         case MagickColorOptions:
5054         {
5055           (void) ListColorInfo((FILE *) NULL,_exception);
5056           break;
5057         }
5058         case MagickConfigureOptions:
5059         {
5060           (void) ListConfigureInfo((FILE *) NULL,_exception);
5061           break;
5062         }
5063         case MagickDelegateOptions:
5064         {
5065           (void) ListDelegateInfo((FILE *) NULL,_exception);
5066           break;
5067         }
5068         case MagickFontOptions:
5069         {
5070           (void) ListTypeInfo((FILE *) NULL,_exception);
5071           break;
5072         }
5073         case MagickFormatOptions:
5074           (void) ListMagickInfo((FILE *) NULL,_exception);
5075           break;
5076         case MagickLocaleOptions:
5077           (void) ListLocaleInfo((FILE *) NULL,_exception);
5078           break;
5079         case MagickLogOptions:
5080           (void) ListLogInfo((FILE *) NULL,_exception);
5081           break;
5082         case MagickMagicOptions:
5083           (void) ListMagicInfo((FILE *) NULL,_exception);
5084           break;
5085         case MagickMimeOptions:
5086           (void) ListMimeInfo((FILE *) NULL,_exception);
5087           break;
5088         case MagickModuleOptions:
5089           (void) ListModuleInfo((FILE *) NULL,_exception);
5090           break;
5091         case MagickPolicyOptions:
5092           (void) ListPolicyInfo((FILE *) NULL,_exception);
5093           break;
5094         case MagickResourceOptions:
5095           (void) ListMagickResourceInfo((FILE *) NULL,_exception);
5096           break;
5097         case MagickThresholdOptions:
5098           (void) ListThresholdMaps((FILE *) NULL,_exception);
5099           break;
5100         default:
5101           (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
5102             _exception);
5103           break;
5104       }
5105       break;
5106     }
5107
5108     CLIWandException(OptionError,"UnrecognizedOption",option);
5109
5110 DisableMSCWarning(4127)
5111   } while (0);  /* break to exit code. */
5112 RestoreMSCWarning
5113
5114   /* clean up percent escape interpreted strings */
5115   if (arg1 != arg1n )
5116     arg1=DestroyString((char *)arg1);
5117   if (arg2 != arg2n )
5118     arg2=DestroyString((char *)arg2);
5119
5120 #undef _image_info
5121 #undef _images
5122 #undef _exception
5123 #undef IfNormalOp
5124 #undef IfPlusOp
5125 }
5126 \f
5127 /*
5128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129 %                                                                             %
5130 %                                                                             %
5131 %                                                                             %
5132 +   C L I O p t i o n                                                         %
5133 %                                                                             %
5134 %                                                                             %
5135 %                                                                             %
5136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137 %
5138 %  CLIOption() Processes the given option using the given CLI Magick Wand.
5139 %  The option arguments can be variable in number, though at this time no more
5140 %  that two is actually used by any option (this may change). Excess options
5141 %  are simply ignored.
5142 %
5143 %  If the cli_wand->command pointer is non-null, then it is assumed that the
5144 %  option has already been search for up from the CommandOptions[] table in
5145 %  "MagickCore/options.c" using  GetCommandOptionInfo().  If not set this
5146 %  routine will do the lookup instead. The pointer is reset afterward.
5147 %
5148 %  This action allows the caller to lookup and pre-handle any 'special'
5149 %  options, (such as implicit reads) before calling this general option
5150 %  handler to deal with 'standard' command line options.
5151 %
5152 %  The format of the CLIOption method is:
5153 %
5154 %       void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5155 %
5156 %  A description of each parameter follows:
5157 %
5158 %     o cli_wand: the main CLI Wand to use.
5159 %
5160 %     o option: The special option (with any switch char) to process
5161 %
5162 %     o args: any required arguments for an option (variable number)
5163 %
5164 %  Example Usage...
5165 %
5166 %    CLIoption(cli_wand,"-read","rose:");
5167 %    CLIoption(cli_wand,"-virtual-pixel","transparent");
5168 %    CLIoption(cli_wand,"-distort","SRT:","30");
5169 %    CLIoption(cli_wand,"-write","rotated_rose.png");
5170 %
5171 */
5172 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5173 {
5174   const char    /* extracted option args from args */
5175     *arg1,
5176     *arg2;
5177
5178   CommandOptionFlags
5179     option_type;
5180
5181   assert(cli_wand != (MagickCLI *) NULL);
5182   assert(cli_wand->signature == MagickWandSignature);
5183   assert(cli_wand->wand.signature == MagickWandSignature);
5184
5185   do { /* Break Code Block for error handling */
5186
5187     /* get information about option */
5188     if ( cli_wand->command == (const OptionInfo *) NULL )
5189       cli_wand->command = GetCommandOptionInfo(option);
5190 #if 0
5191       (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5192             option, cli_wand->command->mnemonic );
5193 #endif
5194     option_type=(CommandOptionFlags) cli_wand->command->flags;
5195
5196     if ( option_type == UndefinedOptionFlag )
5197       CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5198
5199     assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5200
5201     /* deprecated options */
5202     if ( (option_type & DeprecateOptionFlag) != 0 )
5203       CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5204
5205     /* options that this module does not handle */
5206     if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5207       CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5208
5209     /* Get argument strings from VarArgs
5210       How can you determine if enough arguments was supplied?
5211       What happens if not enough arguments were supplied?
5212     */
5213     { size_t
5214         count = (size_t) cli_wand->command->type;
5215
5216       va_list
5217         operands;
5218
5219       va_start(operands,option);
5220
5221       arg1=arg2=NULL;
5222       if ( count >= 1 )
5223         arg1=(const char *) va_arg(operands, const char *);
5224       if ( count >= 2 )
5225         arg2=(const char *) va_arg(operands, const char *);
5226
5227       va_end(operands);
5228 #if 0
5229       (void) FormatLocaleFile(stderr,
5230         "CLIOption: \"%s\"  Count: %ld  Flags: %04x  Args: \"%s\" \"%s\"\n",
5231             option,(long) count,option_type,arg1,arg2);
5232 #endif
5233     }
5234
5235     /*
5236       Call the appropriate option handler
5237     */
5238
5239     /* FUTURE: this is temporary - get 'settings' to handle distribution of
5240       settings to images attributes,proprieties,artifacts */
5241     if ( cli_wand->wand.images != (Image *) NULL )
5242       (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5243         cli_wand->wand.exception);
5244
5245     if ( (option_type & SettingOptionFlags) != 0 ) {
5246       CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5247       /*
5248         FUTURE: Sync Specific Settings into Image Properities (not global)
5249       */
5250     }
5251
5252     /* Operators that do not need images - read, write, stack, clone */
5253     if ((option_type & NoImageOperatorFlag) != 0)
5254       CLINoImageOperator(cli_wand, option, arg1, arg2);
5255
5256     /* FUTURE: The not a setting part below is a temporary hack due to
5257     * some options being both a Setting and a Simple operator.
5258     * Specifically -monitor, -depth, and  -colorspace */
5259     if ( cli_wand->wand.images == (Image *) NULL )
5260       if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5261           ((option_type & SettingOptionFlags) == 0 ))  /* temp hack */
5262         CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5263
5264     /* Operators which loop of individual images, simply */
5265     if ( (option_type & SimpleOperatorFlag) != 0 &&
5266          cli_wand->wand.images != (Image *) NULL) /* temp hack */
5267       {
5268         ExceptionInfo *exception=AcquireExceptionInfo();
5269         (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5270         exception=DestroyExceptionInfo(exception);
5271       }
5272
5273     /* Operators that work on the image list as a whole */
5274     if ( (option_type & ListOperatorFlag) != 0 )
5275       (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5276
5277 DisableMSCWarning(4127)
5278   } while (0);  /* end Break code block */
5279 RestoreMSCWarning
5280
5281   cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
5282 }