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