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