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