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