]> granicus.if.org Git - imagemagick/blob - MagickWand/operation.c
f2bfd74eb9282115f4e1a416606fab677128926a
[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 == MagickCoreSignature);
203   if (IfMagickTrue(image->debug))
204     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
205   assert(exception != (ExceptionInfo *) NULL);
206   assert(exception->signature == MagickCoreSignature);
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 == MagickWandSignature);
427   assert(cli_wand->wand.signature == MagickWandSignature);
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 == MagickWandSignature);
1702   assert(cli_wand->wand.signature == MagickWandSignature);
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 == MagickWandSignature);
3560   assert(cli_wand->wand.signature == MagickWandSignature);
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 == MagickWandSignature);
3650   assert(cli_wand->wand.signature == MagickWandSignature);
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,
3656        arg1n == (const char *) NULL ? "null" : arg1n,
3657        arg2n == (const char *) NULL ? "null" : arg2n);
3658
3659   arg1 = arg1n;
3660   arg2 = arg2n;
3661
3662   /* Interpret Percent Escapes in Arguments - using first image */
3663   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3664         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3665        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3666     /* Interpret Percent escapes in argument 1 */
3667     if (arg1n != (char *) NULL) {
3668       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3669       if (arg1 == (char *) NULL) {
3670         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3671         arg1=arg1n;  /* use the given argument as is */
3672       }
3673     }
3674     if (arg2n != (char *) NULL) {
3675       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3676       if (arg2 == (char *) NULL) {
3677         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3678         arg2=arg2n;  /* use the given argument as is */
3679       }
3680     }
3681   }
3682 #undef _process_flags
3683 #undef _option_type
3684
3685   status=MagickTrue;
3686   new_images=NewImageList();
3687
3688   switch (*(option+1))
3689   {
3690     case 'a':
3691     {
3692       if (LocaleCompare("append",option+1) == 0)
3693         {
3694           new_images=AppendImages(_images,IsNormalOp,_exception);
3695           break;
3696         }
3697       if (LocaleCompare("average",option+1) == 0)
3698         {
3699           CLIWandWarnReplaced("-evaluate-sequence Mean");
3700           (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3701           break;
3702         }
3703       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3704     }
3705     case 'c':
3706     {
3707       if (LocaleCompare("channel-fx",option+1) == 0)
3708         {
3709           new_images=ChannelFxImage(_images,arg1,_exception);
3710           break;
3711         }
3712       if (LocaleCompare("clut",option+1) == 0)
3713         {
3714           Image
3715             *clut_image;
3716
3717           /* FUTURE - make this a compose option, and thus can be used
3718              with layers compose or even compose last image over all other
3719              _images.
3720           */
3721           new_images=RemoveFirstImageFromList(&_images);
3722           clut_image=RemoveLastImageFromList(&_images);
3723           /* FUTURE - produce Exception, rather than silent fail */
3724           if (clut_image == (Image *) NULL)
3725             break;
3726           (void) ClutImage(new_images,clut_image,new_images->interpolate,
3727             _exception);
3728           clut_image=DestroyImage(clut_image);
3729           break;
3730         }
3731       if (LocaleCompare("coalesce",option+1) == 0)
3732         {
3733           new_images=CoalesceImages(_images,_exception);
3734           break;
3735         }
3736       if (LocaleCompare("combine",option+1) == 0)
3737         {
3738           parse=(ssize_t) _images->colorspace;
3739           if ( IfPlusOp )
3740             parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3741           if (parse < 0)
3742             CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3743               arg1);
3744           new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3745           break;
3746         }
3747       if (LocaleCompare("compare",option+1) == 0)
3748         {
3749           double
3750             distortion;
3751
3752           Image
3753             *image,
3754             *reconstruct_image;
3755
3756           MetricType
3757             metric;
3758
3759           /*
3760             Mathematically and visually annotate the difference between an
3761             image and its reconstruction.
3762           */
3763           image=RemoveFirstImageFromList(&_images);
3764           reconstruct_image=RemoveFirstImageFromList(&_images);
3765           /* FUTURE - produce Exception, rather than silent fail */
3766           if (reconstruct_image == (Image *) NULL)
3767             break;
3768           metric=UndefinedErrorMetric;
3769           option=GetImageOption(_image_info,"metric");
3770           if (option != (const char *) NULL)
3771             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3772               MagickFalse,option);
3773           new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3774             _exception);
3775           (void) distortion;
3776           reconstruct_image=DestroyImage(reconstruct_image);
3777           image=DestroyImage(image);
3778           break;
3779         }
3780       if (LocaleCompare("complex",option+1) == 0)
3781         {
3782           parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3783           if (parse < 0)
3784             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3785               option,arg1);
3786           new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3787           break;
3788         }
3789       if (LocaleCompare("composite",option+1) == 0)
3790         {
3791           CompositeOperator
3792             compose;
3793
3794           const char*
3795             value;
3796
3797           MagickBooleanType
3798             clip_to_self;
3799
3800           Image
3801             *mask_image,
3802             *source_image;
3803
3804           RectangleInfo
3805             geometry;
3806
3807           /* Compose value from "-compose" option only */
3808           value=GetImageOption(_image_info,"compose");
3809           if (value == (const char *) NULL)
3810             compose=OverCompositeOp;  /* use Over not source_image->compose */
3811           else
3812             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3813               MagickFalse,value);
3814
3815           /* Get "clip-to-self" expert setting (false is normal) */
3816           value=GetImageOption(_image_info,"compose:clip-to-self");
3817           if (value == (const char *) NULL)
3818             clip_to_self=MagickTrue;
3819           else
3820             clip_to_self=IsStringTrue(GetImageOption(_image_info,
3821               "compose:clip-to-self")); /* if this is true */
3822           value=GetImageOption(_image_info,"compose:outside-overlay");
3823           if (value != (const char *) NULL) {   /* or this false */
3824             /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3825             clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3826           }
3827
3828           new_images=RemoveFirstImageFromList(&_images);
3829           source_image=RemoveFirstImageFromList(&_images);
3830           if (source_image == (Image *) NULL)
3831             break; /* FUTURE - produce Exception, rather than silent fail */
3832
3833           /* FUTURE - this should not be here! - should be part of -geometry */
3834           (void) TransformImage(&source_image,(char *) NULL,
3835             source_image->geometry,_exception);
3836           SetGeometry(source_image,&geometry);
3837           (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3838           GravityAdjustGeometry(new_images->columns,new_images->rows,
3839             new_images->gravity, &geometry);
3840           mask_image=RemoveFirstImageFromList(&_images);
3841           if (mask_image == (Image *) NULL)
3842             status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3843               geometry.x,geometry.y,_exception);
3844           else
3845             {
3846               if ((compose == DisplaceCompositeOp) ||
3847                   (compose == DistortCompositeOp))
3848                 {
3849                   status&=CompositeImage(source_image,mask_image,
3850                     CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3851                   status&=CompositeImage(new_images,source_image,compose,
3852                     clip_to_self,geometry.x,geometry.y,_exception);
3853                 }
3854               else
3855                 {
3856                   Image
3857                     *clone_image;
3858
3859                   clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
3860                   if (clone_image == (Image *) NULL)
3861                     break;
3862                   status&=CompositeImage(new_images,source_image,compose,
3863                     clip_to_self,geometry.x,geometry.y,_exception);
3864                   status&=CompositeImage(new_images,mask_image,
3865                     CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
3866                   status&=CompositeImage(clone_image,new_images,OverCompositeOp,
3867                     clip_to_self,geometry.x,geometry.y,_exception);
3868                   new_images=DestroyImage(new_images);
3869                   new_images=clone_image;
3870                 }
3871               mask_image=DestroyImage(mask_image);
3872             }
3873           source_image=DestroyImage(source_image);
3874           break;
3875         }
3876         if (LocaleCompare("copy",option+1) == 0)
3877           {
3878             Image
3879               *source_image;
3880
3881             OffsetInfo
3882               offset;
3883
3884             RectangleInfo
3885               geometry;
3886
3887             /*
3888               Copy image pixels.
3889             */
3890             if (IfMagickFalse(IsGeometry(arg1)))
3891               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3892             if (IfMagickFalse(IsGeometry(arg2)))
3893               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3894             (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
3895             offset.x=geometry.x;
3896             offset.y=geometry.y;
3897             source_image=_images;
3898             if (source_image->next != (Image *) NULL)
3899               source_image=source_image->next;
3900             (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
3901             (void) CopyImagePixels(_images,source_image,&geometry,&offset,
3902               _exception);
3903             break;
3904           }
3905       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3906     }
3907     case 'd':
3908     {
3909       if (LocaleCompare("deconstruct",option+1) == 0)
3910         {
3911           CLIWandWarnReplaced("-layer CompareAny");
3912           (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3913           break;
3914         }
3915       if (LocaleCompare("delete",option+1) == 0)
3916         {
3917           if (IfNormalOp)
3918             DeleteImages(&_images,arg1,_exception);
3919           else
3920             DeleteImages(&_images,"-1",_exception);
3921           break;
3922         }
3923       if (LocaleCompare("duplicate",option+1) == 0)
3924         {
3925           if (IfNormalOp)
3926             {
3927               const char
3928                 *p;
3929
3930               size_t
3931                 number_duplicates;
3932
3933               if (IfMagickFalse(IsGeometry(arg1)))
3934                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3935                       arg1);
3936               number_duplicates=(size_t) StringToLong(arg1);
3937               p=strchr(arg1,',');
3938               if (p == (const char *) NULL)
3939                 new_images=DuplicateImages(_images,number_duplicates,"-1",
3940                   _exception);
3941               else
3942                 new_images=DuplicateImages(_images,number_duplicates,p,
3943                   _exception);
3944             }
3945           else
3946             new_images=DuplicateImages(_images,1,"-1",_exception);
3947           AppendImageToList(&_images, new_images);
3948           new_images=(Image *) NULL;
3949           break;
3950         }
3951       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3952     }
3953     case 'e':
3954     {
3955       if (LocaleCompare("evaluate-sequence",option+1) == 0)
3956         {
3957           parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3958           if (parse < 0)
3959             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3960               option,arg1);
3961           new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3962             _exception);
3963           break;
3964         }
3965       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3966     }
3967     case 'f':
3968     {
3969       if (LocaleCompare("fft",option+1) == 0)
3970         {
3971           new_images=ForwardFourierTransformImage(_images,IsNormalOp,
3972            _exception);
3973           break;
3974         }
3975       if (LocaleCompare("flatten",option+1) == 0)
3976         {
3977           /* REDIRECTED to use -layers flatten instead */
3978           (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3979           break;
3980         }
3981       if (LocaleCompare("fx",option+1) == 0)
3982         {
3983           new_images=FxImage(_images,arg1,_exception);
3984           break;
3985         }
3986       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3987     }
3988     case 'h':
3989     {
3990       if (LocaleCompare("hald-clut",option+1) == 0)
3991         {
3992           /* FUTURE - make this a compose option (and thus layers compose )
3993              or perhaps compose last image over all other _images.
3994           */
3995           Image
3996             *hald_image;
3997
3998           new_images=RemoveFirstImageFromList(&_images);
3999           hald_image=RemoveLastImageFromList(&_images);
4000           if (hald_image == (Image *) NULL)
4001             break;
4002           (void) HaldClutImage(new_images,hald_image,_exception);
4003           hald_image=DestroyImage(hald_image);
4004           break;
4005         }
4006       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4007     }
4008     case 'i':
4009     {
4010       if (LocaleCompare("ift",option+1) == 0)
4011         {
4012           Image
4013             *magnitude_image,
4014             *phase_image;
4015
4016            magnitude_image=RemoveFirstImageFromList(&_images);
4017            phase_image=RemoveFirstImageFromList(&_images);
4018           /* FUTURE - produce Exception, rather than silent fail */
4019            if (phase_image == (Image *) NULL)
4020              break;
4021            new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4022              IsNormalOp,_exception);
4023            magnitude_image=DestroyImage(magnitude_image);
4024            phase_image=DestroyImage(phase_image);
4025           break;
4026         }
4027       if (LocaleCompare("insert",option+1) == 0)
4028         {
4029           Image
4030             *insert_image,
4031             *index_image;
4032
4033           ssize_t
4034             index;
4035
4036           if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
4037             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4038           index=0;
4039           insert_image=RemoveLastImageFromList(&_images);
4040           if (IfNormalOp)
4041             index=(ssize_t) StringToLong(arg1);
4042           index_image=insert_image;
4043           if (index == 0)
4044             PrependImageToList(&_images,insert_image);
4045           else if (index == (ssize_t) GetImageListLength(_images))
4046             AppendImageToList(&_images,insert_image);
4047           else
4048             {
4049                index_image=GetImageFromList(_images,index-1);
4050                if (index_image == (Image *) NULL)
4051                  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4052               InsertImageInList(&index_image,insert_image);
4053             }
4054           _images=GetFirstImageInList(index_image);
4055           break;
4056         }
4057       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4058     }
4059     case 'l':
4060     {
4061       if (LocaleCompare("layers",option+1) == 0)
4062         {
4063           parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4064           if ( parse < 0 )
4065             CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4066                  option,arg1);
4067           switch ((LayerMethod) parse)
4068           {
4069             case CoalesceLayer:
4070             {
4071               new_images=CoalesceImages(_images,_exception);
4072               break;
4073             }
4074             case CompareAnyLayer:
4075             case CompareClearLayer:
4076             case CompareOverlayLayer:
4077             default:
4078             {
4079               new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4080                    _exception);
4081               break;
4082             }
4083             case MergeLayer:
4084             case FlattenLayer:
4085             case MosaicLayer:
4086             case TrimBoundsLayer:
4087             {
4088               new_images=MergeImageLayers(_images,(LayerMethod) parse,
4089                 _exception);
4090               break;
4091             }
4092             case DisposeLayer:
4093             {
4094               new_images=DisposeImages(_images,_exception);
4095               break;
4096             }
4097             case OptimizeImageLayer:
4098             {
4099               new_images=OptimizeImageLayers(_images,_exception);
4100               break;
4101             }
4102             case OptimizePlusLayer:
4103             {
4104               new_images=OptimizePlusImageLayers(_images,_exception);
4105               break;
4106             }
4107             case OptimizeTransLayer:
4108             {
4109               OptimizeImageTransparency(_images,_exception);
4110               break;
4111             }
4112             case RemoveDupsLayer:
4113             {
4114               RemoveDuplicateLayers(&_images,_exception);
4115               break;
4116             }
4117             case RemoveZeroLayer:
4118             {
4119               RemoveZeroDelayLayers(&_images,_exception);
4120               break;
4121             }
4122             case OptimizeLayer:
4123             { /* General Purpose, GIF Animation Optimizer.  */
4124               new_images=CoalesceImages(_images,_exception);
4125               if (new_images == (Image *) NULL)
4126                 break;
4127               _images=DestroyImageList(_images);
4128               _images=OptimizeImageLayers(new_images,_exception);
4129               if (_images == (Image *) NULL)
4130                 break;
4131               new_images=DestroyImageList(new_images);
4132               OptimizeImageTransparency(_images,_exception);
4133               (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4134                 _exception);
4135               break;
4136             }
4137             case CompositeLayer:
4138             {
4139               Image
4140                 *source;
4141
4142               RectangleInfo
4143                 geometry;
4144
4145               CompositeOperator
4146                 compose;
4147
4148               const char*
4149                 value;
4150
4151               value=GetImageOption(_image_info,"compose");
4152               compose=OverCompositeOp;  /* Default to Over */
4153               if (value != (const char *) NULL)
4154                 compose=(CompositeOperator) ParseCommandOption(
4155                       MagickComposeOptions,MagickFalse,value);
4156
4157               /* Split image sequence at the first 'NULL:' image. */
4158               source=_images;
4159               while (source != (Image *) NULL)
4160               {
4161                 source=GetNextImageInList(source);
4162                 if ((source != (Image *) NULL) &&
4163                     (LocaleCompare(source->magick,"NULL") == 0))
4164                   break;
4165               }
4166               if (source != (Image *) NULL)
4167                 {
4168                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4169                       (GetNextImageInList(source) == (Image *) NULL))
4170                     source=(Image *) NULL;
4171                   else
4172                     { /* Separate the two lists, junk the null: image.  */
4173                       source=SplitImageList(source->previous);
4174                       DeleteImageFromList(&source);
4175                     }
4176                 }
4177               if (source == (Image *) NULL)
4178                 {
4179                   (void) ThrowMagickException(_exception,GetMagickModule(),
4180                     OptionError,"MissingNullSeparator","layers Composite");
4181                   break;
4182                 }
4183               /* Adjust offset with gravity and virtual canvas.  */
4184               SetGeometry(_images,&geometry);
4185               (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4186               geometry.width=source->page.width != 0 ?
4187                 source->page.width : source->columns;
4188               geometry.height=source->page.height != 0 ?
4189                source->page.height : source->rows;
4190               GravityAdjustGeometry(_images->page.width != 0 ?
4191                 _images->page.width : _images->columns,
4192                 _images->page.height != 0 ? _images->page.height :
4193                 _images->rows,_images->gravity,&geometry);
4194
4195               /* Compose the two image sequences together */
4196               CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4197                 _exception);
4198               source=DestroyImageList(source);
4199               break;
4200             }
4201           }
4202           break;
4203         }
4204       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4205     }
4206     case 'm':
4207     {
4208       if (LocaleCompare("map",option+1) == 0)
4209         {
4210           CLIWandWarnReplaced("+remap");
4211           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4212           break;
4213         }
4214       if (LocaleCompare("metric",option+1) == 0)
4215         break;
4216       if (LocaleCompare("morph",option+1) == 0)
4217         {
4218           Image
4219             *morph_image;
4220
4221           if (IfMagickFalse(IsGeometry(arg1)))
4222             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4223           morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4224             _exception);
4225           if (morph_image == (Image *) NULL)
4226             break;
4227           _images=DestroyImageList(_images);
4228           _images=morph_image;
4229           break;
4230         }
4231       if (LocaleCompare("mosaic",option+1) == 0)
4232         {
4233           /* REDIRECTED to use -layers mosaic instead */
4234           (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4235           break;
4236         }
4237       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4238     }
4239     case 'p':
4240     {
4241       if (LocaleCompare("poly",option+1) == 0)
4242         {
4243           double
4244             *args;
4245
4246           ssize_t
4247             count;
4248
4249           /* convert argument string into an array of doubles */
4250           args = StringToArrayOfDoubles(arg1,&count,_exception);
4251           if (args == (double *) NULL )
4252             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4253           new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4254            _exception);
4255           args=(double *) RelinquishMagickMemory(args);
4256           break;
4257         }
4258       if (LocaleCompare("process",option+1) == 0)
4259         {
4260           /* FUTURE: better parsing using ScriptToken() from string ??? */
4261           char
4262             **arguments;
4263
4264           int
4265             j,
4266             number_arguments;
4267
4268           arguments=StringToArgv(arg1,&number_arguments);
4269           if (arguments == (char **) NULL)
4270             break;
4271           if (strchr(arguments[1],'=') != (char *) NULL)
4272             {
4273               char
4274                 breaker,
4275                 quote,
4276                 *token;
4277
4278               const char
4279                 *arguments;
4280
4281               int
4282                 next,
4283                 status;
4284
4285               size_t
4286                 length;
4287
4288               TokenInfo
4289                 *token_info;
4290
4291               /*
4292                 Support old style syntax, filter="-option arg1".
4293               */
4294               assert(arg1 != (const char *) NULL);
4295               length=strlen(arg1);
4296               token=(char *) NULL;
4297               if (~length >= (MagickPathExtent-1))
4298                 token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4299                   sizeof(*token));
4300               if (token == (char *) NULL)
4301                 break;
4302               next=0;
4303               arguments=arg1;
4304               token_info=AcquireTokenInfo();
4305               status=Tokenizer(token_info,0,token,length,arguments,"","=",
4306                 "\"",'\0',&breaker,&next,&quote);
4307               token_info=DestroyTokenInfo(token_info);
4308               if (status == 0)
4309                 {
4310                   const char
4311                     *argv;
4312
4313                   argv=(&(arguments[next]));
4314                   (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4315                     _exception);
4316                 }
4317               token=DestroyString(token);
4318               break;
4319             }
4320           (void) SubstituteString(&arguments[1],"-","");
4321           (void) InvokeDynamicImageFilter(arguments[1],&_images,
4322             number_arguments-2,(const char **) arguments+2,_exception);
4323           for (j=0; j < number_arguments; j++)
4324             arguments[j]=DestroyString(arguments[j]);
4325           arguments=(char **) RelinquishMagickMemory(arguments);
4326           break;
4327         }
4328       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4329     }
4330     case 'r':
4331     {
4332       if (LocaleCompare("remap",option+1) == 0)
4333         {
4334           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4335           break;
4336         }
4337       if (LocaleCompare("reverse",option+1) == 0)
4338         {
4339           ReverseImageList(&_images);
4340           break;
4341         }
4342       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4343     }
4344     case 's':
4345     {
4346       if (LocaleCompare("smush",option+1) == 0)
4347         {
4348           /* FUTURE: this option needs more work to make better */
4349           ssize_t
4350             offset;
4351
4352           if (IfMagickFalse(IsGeometry(arg1)))
4353             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4354           offset=(ssize_t) StringToLong(arg1);
4355           new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4356           break;
4357         }
4358       if (LocaleCompare("subimage",option+1) == 0)
4359         {
4360           Image
4361             *base_image,
4362             *compare_image;
4363
4364           const char
4365             *value;
4366
4367           MetricType
4368             metric;
4369
4370           double
4371             similarity;
4372
4373           RectangleInfo
4374             offset;
4375
4376           base_image=GetImageFromList(_images,0);
4377           compare_image=GetImageFromList(_images,1);
4378
4379           /* Comparision Metric */
4380           metric=UndefinedErrorMetric;
4381           value=GetImageOption(_image_info,"metric");
4382           if (value != (const char *) NULL)
4383             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4384               MagickFalse,value);
4385
4386           new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4387             &offset,&similarity,_exception);
4388
4389           if (new_images != (Image *) NULL)
4390             {
4391               char
4392                 result[MagickPathExtent];
4393
4394               (void) FormatLocaleString(result,MagickPathExtent,"%lf",
4395                 similarity);
4396               (void) SetImageProperty(new_images,"subimage:similarity",result,
4397                 _exception);
4398               (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4399                 offset.x);
4400               (void) SetImageProperty(new_images,"subimage:x",result,
4401                 _exception);
4402               (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4403                 offset.y);
4404               (void) SetImageProperty(new_images,"subimage:y",result,
4405                 _exception);
4406               (void) FormatLocaleString(result,MagickPathExtent,
4407                 "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4408                 offset.height,(long) offset.x,(long) offset.y);
4409               (void) SetImageProperty(new_images,"subimage:offset",result,
4410                 _exception);
4411             }
4412           break;
4413         }
4414       if (LocaleCompare("swap",option+1) == 0)
4415         {
4416         Image
4417           *p,
4418           *q,
4419           *swap;
4420
4421         ssize_t
4422           index,
4423           swap_index;
4424
4425         index=(-1);
4426         swap_index=(-2);
4427         if (IfNormalOp) {
4428           GeometryInfo
4429             geometry_info;
4430
4431           MagickStatusType
4432             flags;
4433
4434           swap_index=(-1);
4435           flags=ParseGeometry(arg1,&geometry_info);
4436           if ((flags & RhoValue) == 0)
4437             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4438           index=(ssize_t) geometry_info.rho;
4439           if ((flags & SigmaValue) != 0)
4440             swap_index=(ssize_t) geometry_info.sigma;
4441         }
4442         p=GetImageFromList(_images,index);
4443         q=GetImageFromList(_images,swap_index);
4444         if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4445           if (IfNormalOp)
4446             CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4447           else
4448             CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4449         }
4450         if (p == q)
4451           CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4452         swap=CloneImage(p,0,0,MagickTrue,_exception);
4453         ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4454         ReplaceImageInList(&q,swap);
4455         _images=GetFirstImageInList(q);
4456         break;
4457       }
4458       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4459     }
4460     default:
4461       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4462   }
4463
4464   /* clean up percent escape interpreted strings */
4465   if (arg1 != arg1n )
4466     arg1=DestroyString((char *)arg1);
4467   if (arg2 != arg2n )
4468     arg2=DestroyString((char *)arg2);
4469
4470   /* if new image list generated, replace existing image list */
4471   if (new_images == (Image *) NULL)
4472     return(status == 0 ? MagickFalse : MagickTrue);
4473   _images=DestroyImageList(_images);
4474   _images=GetFirstImageInList(new_images);
4475   return(status == 0 ? MagickFalse : MagickTrue);
4476
4477 #undef _image_info
4478 #undef _images
4479 #undef _exception
4480 #undef _draw_info
4481 #undef _quantize_info
4482 #undef IfNormalOp
4483 #undef IfPlusOp
4484 #undef IsNormalOp
4485 }
4486 \f
4487 /*
4488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4489 %                                                                             %
4490 %                                                                             %
4491 %                                                                             %
4492 +   C L I N o I m a g e O p e r a t i o n s                                   %
4493 %                                                                             %
4494 %                                                                             %
4495 %                                                                             %
4496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4497 %
4498 %  CLINoImageOperator() Applies operations that may not actually need images
4499 %  in an image list.
4500 %
4501 %  The classic operators of this type is "-read", which actually creates
4502 %  images even when no images are present.  Or image stack operators, which
4503 %  can be applied (push or pop) to an empty image list.
4504 %
4505 %  Note that these operators may involve other special 'option' prefix
4506 %  characters other  than '-' or '+', namely parenthesis and braces.
4507 %
4508 %  The format of the CLINoImageOption method is:
4509 %
4510 %      void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4511 %           const char *arg1, const char *arg2)
4512 %
4513 %  A description of each parameter follows:
4514 %
4515 %    o cli_wand: the main CLI Wand to use. (sometimes not required)
4516 %
4517 %    o option: The special option (with any switch char) to process
4518 %
4519 %    o arg1 & arg2: Argument for option, if required
4520 %                   Currently arg2 is not used.
4521 %
4522 */
4523 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4524   const char *option,const char *arg1n,const char *arg2n)
4525 {
4526   const char    /* percent escaped versions of the args */
4527     *arg1,
4528     *arg2;
4529
4530 #define _image_info     (cli_wand->wand.image_info)
4531 #define _images         (cli_wand->wand.images)
4532 #define _exception      (cli_wand->wand.exception)
4533 #define _process_flags  (cli_wand->process_flags)
4534 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
4535 #define IfNormalOp      (*option=='-')
4536 #define IfPlusOp        (*option!='-')
4537
4538   assert(cli_wand != (MagickCLI *) NULL);
4539   assert(cli_wand->signature == MagickWandSignature);
4540   assert(cli_wand->wand.signature == MagickWandSignature);
4541
4542   if (IfMagickTrue(cli_wand->wand.debug))
4543     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4544       "- NoImage Operator: %s \"%s\" \"%s\"", option,
4545       arg1n != (char *) NULL ? arg1n : "",
4546       arg2n != (char *) NULL ? arg2n : "");
4547
4548   arg1 = arg1n;
4549   arg2 = arg2n;
4550
4551   /* Interpret Percent Escapes in Arguments - using first image */
4552   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4553         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4554        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4555     /* Interpret Percent escapes in argument 1 */
4556     if (arg1n != (char *) NULL) {
4557       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4558       if (arg1 == (char *) NULL) {
4559         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4560         arg1=arg1n;  /* use the given argument as is */
4561       }
4562     }
4563     if (arg2n != (char *) NULL) {
4564       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4565       if (arg2 == (char *) NULL) {
4566         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4567         arg2=arg2n;  /* use the given argument as is */
4568       }
4569     }
4570   }
4571 #undef _process_flags
4572 #undef _option_type
4573
4574   do {  /* break to exit code */
4575     /*
4576       No-op options  (ignore these)
4577     */
4578     if (LocaleCompare("noop",option+1) == 0)   /* zero argument */
4579       break;
4580     if (LocaleCompare("sans",option+1) == 0)   /* one argument */
4581       break;
4582     if (LocaleCompare("sans0",option+1) == 0)  /* zero argument */
4583       break;
4584     if (LocaleCompare("sans1",option+1) == 0)  /* one argument */
4585       break;
4586     if (LocaleCompare("sans2",option+1) == 0)  /* two arguments */
4587       break;
4588     /*
4589       Image Reading
4590     */
4591     if ( ( LocaleCompare("read",option+1) == 0 ) ||
4592       ( LocaleCompare("--",option) == 0 ) ) {
4593       /* Do Glob filename Expansion for 'arg1' then read all images.
4594       *
4595       * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4596       * (but attaching to the filenames in the generated argument list) any
4597       * [...] read modifiers that may be present.
4598       *
4599       * For example: It will expand '*.gif[20x20]' into a list such as
4600       * 'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
4601       *
4602       * NOTE: In IMv6 this was done globally across all images. This
4603       * meant you could include IM options in '@filename' lists, but you
4604       * could not include comments.   Doing it only for image read makes
4605       * it far more secure.
4606       *
4607       * Note: arguments do not have percent escapes expanded for security
4608       * reasons.
4609       */
4610       int      argc;
4611       char     **argv;
4612       ssize_t  i;
4613
4614       argc = 1;
4615       argv = (char **) &arg1;
4616
4617       /* Expand 'glob' expressions in the given filename.
4618         Expansion handles any 'coder:' prefix, or read modifiers attached
4619         to the filename, including them in the resulting expanded list.
4620       */
4621       if (IfMagickFalse(  ExpandFilenames(&argc,&argv)  ))
4622         CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4623             option,GetExceptionMessage(errno));
4624
4625       /* loop over expanded filename list, and read then all in */
4626       for (i=0; i < (ssize_t) argc; i++) {
4627         Image *
4628           new_images;
4629         if (IfMagickTrue(_image_info->ping))
4630           new_images=PingImages(_image_info,argv[i],_exception);
4631         else
4632           new_images=ReadImages(_image_info,argv[i],_exception);
4633         AppendImageToList(&_images, new_images);
4634       }
4635       argv=DestroyStringList(argv);  /* Destroy the Expanded Filename list */
4636       break;
4637     }
4638     /*
4639       Image Writing
4640       Note: Writing a empty image list is valid in specific cases
4641     */
4642     if (LocaleCompare("write",option+1) == 0) {
4643       /* Note: arguments do not have percent escapes expanded */
4644       char
4645         key[MagickPathExtent];
4646
4647       Image
4648         *write_images;
4649
4650       ImageInfo
4651         *write_info;
4652
4653       /* Need images, unless a "null:" output coder is used */
4654       if ( _images == (Image *) NULL ) {
4655         if ( LocaleCompare(arg1,"null:") == 0 )
4656           break;
4657         CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4658       }
4659
4660       (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4661       (void) DeleteImageRegistry(key);
4662       write_images=_images;
4663       if (IfPlusOp)
4664         write_images=CloneImageList(_images,_exception);
4665       write_info=CloneImageInfo(_image_info);
4666       (void) WriteImages(write_info,write_images,arg1,_exception);
4667       write_info=DestroyImageInfo(write_info);
4668       if (IfPlusOp)
4669         write_images=DestroyImageList(write_images);
4670       break;
4671     }
4672     /*
4673       Parenthesis and Brace operations
4674     */
4675     if (LocaleCompare("(",option) == 0) {
4676       /* stack 'push' images */
4677       Stack
4678         *node;
4679
4680       size_t
4681         size;
4682
4683       size=0;
4684       node=cli_wand->image_list_stack;
4685       for ( ; node != (Stack *) NULL; node=node->next)
4686         size++;
4687       if ( size >= MAX_STACK_DEPTH )
4688         CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4689       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4690       if (node == (Stack *) NULL)
4691         CLIWandExceptionBreak(ResourceLimitFatalError,
4692             "MemoryAllocationFailed",option);
4693       node->data = (void *)cli_wand->wand.images;
4694       node->next = cli_wand->image_list_stack;
4695       cli_wand->image_list_stack = node;
4696       cli_wand->wand.images = NewImageList();
4697
4698       /* handle respect-parenthesis */
4699       if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4700                     "respect-parenthesis"))))
4701         option="{"; /* fall-thru so as to push image settings too */
4702       else
4703         break;
4704       /* fall thru to operation */
4705     }
4706     if (LocaleCompare("{",option) == 0) {
4707       /* stack 'push' of image_info settings */
4708       Stack
4709         *node;
4710
4711       size_t
4712         size;
4713
4714       size=0;
4715       node=cli_wand->image_info_stack;
4716       for ( ; node != (Stack *) NULL; node=node->next)
4717         size++;
4718       if ( size >= MAX_STACK_DEPTH )
4719         CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4720       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4721       if (node == (Stack *) NULL)
4722         CLIWandExceptionBreak(ResourceLimitFatalError,
4723             "MemoryAllocationFailed",option);
4724
4725       node->data = (void *)cli_wand->wand.image_info;
4726       node->next = cli_wand->image_info_stack;
4727
4728       cli_wand->image_info_stack = node;
4729       cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4730       if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4731         CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4732             option);
4733         cli_wand->wand.image_info = (ImageInfo *)node->data;
4734         node = (Stack *)RelinquishMagickMemory(node);
4735         break;
4736       }
4737
4738       break;
4739     }
4740     if (LocaleCompare(")",option) == 0) {
4741       /* pop images from stack */
4742       Stack
4743         *node;
4744
4745       node = (Stack *)cli_wand->image_list_stack;
4746       if ( node == (Stack *) NULL)
4747         CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4748       cli_wand->image_list_stack = node->next;
4749
4750       AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4751       cli_wand->wand.images= (Image *)node->data;
4752       node = (Stack *)RelinquishMagickMemory(node);
4753
4754       /* handle respect-parenthesis - of the previous 'pushed' settings */
4755       node = cli_wand->image_info_stack;
4756       if ( node != (Stack *) NULL)
4757         {
4758           if (IfMagickTrue(IsStringTrue(GetImageOption(
4759                 cli_wand->wand.image_info,"respect-parenthesis"))))
4760             option="}"; /* fall-thru so as to pop image settings too */
4761           else
4762             break;
4763         }
4764       else
4765         break;
4766       /* fall thru to next if */
4767     }
4768     if (LocaleCompare("}",option) == 0) {
4769       /* pop image_info settings from stack */
4770       Stack
4771         *node;
4772
4773       node = (Stack *)cli_wand->image_info_stack;
4774       if ( node == (Stack *) NULL)
4775         CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4776       cli_wand->image_info_stack = node->next;
4777
4778       (void) DestroyImageInfo(cli_wand->wand.image_info);
4779       cli_wand->wand.image_info = (ImageInfo *)node->data;
4780       node = (Stack *)RelinquishMagickMemory(node);
4781
4782       GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4783       cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4784       cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4785
4786       break;
4787     }
4788       if (LocaleCompare("print",option+1) == 0)
4789         {
4790           (void) FormatLocaleFile(stdout,"%s",arg1);
4791           break;
4792         }
4793     if (LocaleCompare("set",option+1) == 0)
4794       {
4795         /* Settings are applied to each image in memory in turn (if any).
4796            While a option: only need to be applied once globally.
4797
4798            NOTE: rguments have not been automatically percent expaneded
4799         */
4800
4801         /* escape the 'key' once only, using first image. */
4802         arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4803         if (arg1 == (char *) NULL)
4804           CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4805                 option);
4806
4807         if (LocaleNCompare(arg1,"registry:",9) == 0)
4808           {
4809             if (IfPlusOp)
4810               {
4811                 (void) DeleteImageRegistry(arg1+9);
4812                 arg1=DestroyString((char *)arg1);
4813                 break;
4814               }
4815             arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4816             if (arg2 == (char *) NULL) {
4817               arg1=DestroyString((char *)arg1);
4818               CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4819                     option);
4820             }
4821             (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4822             arg1=DestroyString((char *)arg1);
4823             arg2=DestroyString((char *)arg2);
4824             break;
4825           }
4826         if (LocaleNCompare(arg1,"option:",7) == 0)
4827           {
4828             /* delete equivelent artifact from all images (if any) */
4829             if (_images != (Image *) NULL)
4830               {
4831                 MagickResetIterator(&cli_wand->wand);
4832                 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4833                   (void) DeleteImageArtifact(_images,arg1+7);
4834                 MagickResetIterator(&cli_wand->wand);
4835               }
4836             /* now set/delete the global option as needed */
4837             /* FUTURE: make escapes in a global 'option:' delayed */
4838             arg2=(char *) NULL;
4839             if (IfNormalOp)
4840               {
4841                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4842                 if (arg2 == (char *) NULL)
4843                   CLIWandExceptionBreak(OptionWarning,
4844                        "InterpretPropertyFailure",option);
4845               }
4846             (void) SetImageOption(_image_info,arg1+7,arg2);
4847             arg1=DestroyString((char *)arg1);
4848             arg2=DestroyString((char *)arg2);
4849             break;
4850           }
4851         /* Set Artifacts/Properties/Attributes all images (required) */
4852         if ( _images == (Image *) NULL )
4853           CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4854
4855         MagickResetIterator(&cli_wand->wand);
4856         while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4857           {
4858             arg2=(char *) NULL;
4859             if (IfNormalOp)
4860               {
4861                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4862                 if (arg2 == (char *) NULL)
4863                   CLIWandExceptionBreak(OptionWarning,
4864                        "InterpretPropertyFailure",option);
4865               }
4866             if (LocaleNCompare(arg1,"artifact:",9) == 0)
4867               (void) SetImageArtifact(_images,arg1+9,arg2);
4868             else if (LocaleNCompare(arg1,"property:",9) == 0)
4869               (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4870             else
4871               (void) SetImageProperty(_images,arg1,arg2,_exception);
4872             arg2=DestroyString((char *)arg2);
4873           }
4874         MagickResetIterator(&cli_wand->wand);
4875         arg1=DestroyString((char *)arg1);
4876         break;
4877      }
4878     if (LocaleCompare("clone",option+1) == 0) {
4879         Image
4880           *new_images;
4881
4882         if (*option == '+')
4883           arg1=AcquireString("-1");
4884         if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4885           CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4886         if ( cli_wand->image_list_stack == (Stack *) NULL)
4887           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4888         new_images = (Image *)cli_wand->image_list_stack->data;
4889         if (new_images == (Image *) NULL)
4890           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4891         new_images=CloneImages(new_images,arg1,_exception);
4892         if (new_images == (Image *) NULL)
4893           CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4894         AppendImageToList(&_images,new_images);
4895         break;
4896       }
4897     /*
4898        Informational Operations.
4899
4900        Note that these do not require either a cli-wand or images!
4901        Though currently a cli-wand much be provided regardless.
4902     */
4903     if (LocaleCompare("version",option+1) == 0)
4904       {
4905         ListMagickVersion(stdout);
4906         break;
4907       }
4908     if (LocaleCompare("list",option+1) == 0) {
4909       /*
4910          FUTURE: This 'switch' should really be part of MagickCore
4911       */
4912       ssize_t
4913         list;
4914
4915       list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4916       if ( list < 0 ) {
4917         CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4918         break;
4919       }
4920       switch (list)
4921       {
4922         case MagickCoderOptions:
4923         {
4924           (void) ListCoderInfo((FILE *) NULL,_exception);
4925           break;
4926         }
4927         case MagickColorOptions:
4928         {
4929           (void) ListColorInfo((FILE *) NULL,_exception);
4930           break;
4931         }
4932         case MagickConfigureOptions:
4933         {
4934           (void) ListConfigureInfo((FILE *) NULL,_exception);
4935           break;
4936         }
4937         case MagickDelegateOptions:
4938         {
4939           (void) ListDelegateInfo((FILE *) NULL,_exception);
4940           break;
4941         }
4942         case MagickFontOptions:
4943         {
4944           (void) ListTypeInfo((FILE *) NULL,_exception);
4945           break;
4946         }
4947         case MagickFormatOptions:
4948           (void) ListMagickInfo((FILE *) NULL,_exception);
4949           break;
4950         case MagickLocaleOptions:
4951           (void) ListLocaleInfo((FILE *) NULL,_exception);
4952           break;
4953         case MagickLogOptions:
4954           (void) ListLogInfo((FILE *) NULL,_exception);
4955           break;
4956         case MagickMagicOptions:
4957           (void) ListMagicInfo((FILE *) NULL,_exception);
4958           break;
4959         case MagickMimeOptions:
4960           (void) ListMimeInfo((FILE *) NULL,_exception);
4961           break;
4962         case MagickModuleOptions:
4963           (void) ListModuleInfo((FILE *) NULL,_exception);
4964           break;
4965         case MagickPolicyOptions:
4966           (void) ListPolicyInfo((FILE *) NULL,_exception);
4967           break;
4968         case MagickResourceOptions:
4969           (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4970           break;
4971         case MagickThresholdOptions:
4972           (void) ListThresholdMaps((FILE *) NULL,_exception);
4973           break;
4974         default:
4975           (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4976             _exception);
4977           break;
4978       }
4979       break;
4980     }
4981
4982     CLIWandException(OptionError,"UnrecognizedOption",option);
4983
4984 DisableMSCWarning(4127)
4985   } while (0);  /* break to exit code. */
4986 RestoreMSCWarning
4987
4988   /* clean up percent escape interpreted strings */
4989   if (arg1 != arg1n )
4990     arg1=DestroyString((char *)arg1);
4991   if (arg2 != arg2n )
4992     arg2=DestroyString((char *)arg2);
4993
4994 #undef _image_info
4995 #undef _images
4996 #undef _exception
4997 #undef IfNormalOp
4998 #undef IfPlusOp
4999 }
5000 \f
5001 /*
5002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5003 %                                                                             %
5004 %                                                                             %
5005 %                                                                             %
5006 +   C L I O p t i o n                                                         %
5007 %                                                                             %
5008 %                                                                             %
5009 %                                                                             %
5010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5011 %
5012 %  CLIOption() Processes the given option using the given CLI Magick Wand.
5013 %  The option arguments can be variable in number, though at this time no more
5014 %  that two is actually used by any option (this may change). Excess options
5015 %  are simply ignored.
5016 %
5017 %  If the cli_wand->command pointer is non-null, then it is assumed that the
5018 %  option has already been search for up from the CommandOptions[] table in
5019 %  "MagickCore/options.c" using  GetCommandOptionInfo().  If not set this
5020 %  routine will do the lookup instead. The pointer is reset afterward.
5021 %
5022 %  This action allows the caller to lookup and pre-handle any 'special'
5023 %  options, (such as implicit reads) before calling this general option
5024 %  handler to deal with 'standard' command line options.
5025 %
5026 %  The format of the CLIOption method is:
5027 %
5028 %       void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5029 %
5030 %  A description of each parameter follows:
5031 %
5032 %     o cli_wand: the main CLI Wand to use.
5033 %
5034 %     o option: The special option (with any switch char) to process
5035 %
5036 %     o args: any required arguments for an option (variable number)
5037 %
5038 %  Example Usage...
5039 %
5040 %    CLIoption(cli_wand,"-read","rose:");
5041 %    CLIoption(cli_wand,"-virtual-pixel","transparent");
5042 %    CLIoption(cli_wand,"-distort","SRT:","30");
5043 %    CLIoption(cli_wand,"-write","rotated_rose.png");
5044 %
5045 */
5046 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5047 {
5048   const char    /* extracted option args from args */
5049     *arg1,
5050     *arg2;
5051
5052   CommandOptionFlags
5053     option_type;
5054
5055   assert(cli_wand != (MagickCLI *) NULL);
5056   assert(cli_wand->signature == MagickWandSignature);
5057   assert(cli_wand->wand.signature == MagickWandSignature);
5058
5059   do { /* Break Code Block for error handling */
5060
5061     /* get information about option */
5062     if ( cli_wand->command == (const OptionInfo *) NULL )
5063       cli_wand->command = GetCommandOptionInfo(option);
5064 #if 0
5065       (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5066             option, cli_wand->command->mnemonic );
5067 #endif
5068     option_type=(CommandOptionFlags) cli_wand->command->flags;
5069
5070     if ( option_type == UndefinedOptionFlag )
5071       CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5072
5073     assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5074
5075     /* deprecated options */
5076     if ( (option_type & DeprecateOptionFlag) != 0 )
5077       CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5078
5079     /* options that this module does not handle */
5080     if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5081       CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5082
5083     /* Get argument strings from VarArgs
5084       How can you determine if enough arguments was supplied?
5085       What happens if not enough arguments were supplied?
5086     */
5087     { size_t
5088         count = (size_t) cli_wand->command->type;
5089
5090       va_list
5091         operands;
5092
5093       va_start(operands,option);
5094
5095       arg1=arg2=NULL;
5096       if ( count >= 1 )
5097         arg1=(const char *) va_arg(operands, const char *);
5098       if ( count >= 2 )
5099         arg2=(const char *) va_arg(operands, const char *);
5100
5101       va_end(operands);
5102 #if 0
5103       (void) FormatLocaleFile(stderr,
5104         "CLIOption: \"%s\"  Count: %ld  Flags: %04x  Args: \"%s\" \"%s\"\n",
5105             option,(long) count,option_type,arg1,arg2);
5106 #endif
5107     }
5108
5109     /*
5110       Call the appropriate option handler
5111     */
5112
5113     /* FUTURE: this is temporary - get 'settings' to handle distribution of
5114       settings to images attributes,proprieties,artifacts */
5115     if ( cli_wand->wand.images != (Image *) NULL )
5116       (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5117         cli_wand->wand.exception);
5118
5119     if ( (option_type & SettingOptionFlags) != 0 ) {
5120       CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5121       // FUTURE: Sync Specific Settings into Image Properities (not global)
5122     }
5123
5124     /* Operators that do not need images - read, write, stack, clone */
5125     if ((option_type & NoImageOperatorFlag) != 0)
5126       CLINoImageOperator(cli_wand, option, arg1, arg2);
5127
5128     /* FUTURE: The not a setting part below is a temporary hack due to
5129     * some options being both a Setting and a Simple operator.
5130     * Specifically -monitor, -depth, and  -colorspace */
5131     if ( cli_wand->wand.images == (Image *) NULL )
5132       if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5133           ((option_type & SettingOptionFlags) == 0 ))  /* temp hack */
5134         CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5135
5136     /* Operators which loop of individual images, simply */
5137     if ( (option_type & SimpleOperatorFlag) != 0 &&
5138          cli_wand->wand.images != (Image *) NULL) /* temp hack */
5139       {
5140         ExceptionInfo *exception=AcquireExceptionInfo();
5141         (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5142         exception=DestroyExceptionInfo(exception);
5143       }
5144
5145     /* Operators that work on the image list as a whole */
5146     if ( (option_type & ListOperatorFlag) != 0 )
5147       (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5148
5149 DisableMSCWarning(4127)
5150   } while (0);  /* end Break code block */
5151 RestoreMSCWarning
5152
5153   cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
5154 }