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