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