]> 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,(Image *) NULL,_exception);
1990           break;
1991         }
1992       if (LocaleCompare("clip-mask",option+1) == 0)
1993         {
1994           /* Note: arguments do not have percent escapes expanded */
1995           CacheView
1996             *mask_view;
1997
1998           Image
1999             *mask_image;
2000
2001           register Quantum
2002             *restrict q;
2003
2004           register ssize_t
2005             x;
2006
2007           ssize_t
2008             y;
2009
2010           if (IfPlusOp) {
2011             /* use "+clip-mask" Remove the write mask for -clip-path */
2012             (void) SetImageMask(_image,(Image *) NULL,_exception);
2013             break;
2014           }
2015           mask_image=GetImageCache(_image_info,arg1,_exception);
2016           if (mask_image == (Image *) NULL)
2017             break;
2018           if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
2019             break;
2020           /* Create a write mask from cli_wand mask image */
2021           /* FUTURE: use Alpha operations instead and create a Grey Image */
2022           mask_view=AcquireAuthenticCacheView(mask_image,_exception);
2023           for (y=0; y < (ssize_t) mask_image->rows; y++)
2024           {
2025             q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
2026               _exception);
2027             if (q == (Quantum *) NULL)
2028               break;
2029             for (x=0; x < (ssize_t) mask_image->columns; x++)
2030             {
2031               if (mask_image->alpha_trait == UndefinedPixelTrait)
2032                 SetPixelAlpha(mask_image,(Quantum)
2033                   GetPixelIntensity(mask_image,q),q);
2034               SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
2035               q+=GetPixelChannels(mask_image);
2036             }
2037             if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2038               break;
2039           }
2040           /* clean up and set the write mask */
2041           mask_view=DestroyCacheView(mask_view);
2042           mask_image->alpha_trait=BlendPixelTrait;
2043           (void) SetImageColorspace(_image,GRAYColorspace,_exception);
2044           (void) SetImageMask(_image,mask_image,_exception);
2045           mask_image=DestroyImage(mask_image);
2046           break;
2047         }
2048       if (LocaleCompare("clip-path",option+1) == 0)
2049         {
2050           (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2051           /* Note: Use "+clip-mask" remove the write mask added */
2052           break;
2053         }
2054       if (LocaleCompare("colorize",option+1) == 0)
2055         {
2056           if (IfMagickFalse(IsGeometry(arg1)))
2057             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2058           new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2059           break;
2060         }
2061       if (LocaleCompare("color-matrix",option+1) == 0)
2062         {
2063           KernelInfo
2064             *kernel;
2065
2066           kernel=AcquireKernelInfo(arg1,exception);
2067           if (kernel == (KernelInfo *) NULL)
2068             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2069           new_image=ColorMatrixImage(_image,kernel,_exception);
2070           kernel=DestroyKernelInfo(kernel);
2071           break;
2072         }
2073       if (LocaleCompare("colors",option+1) == 0)
2074         {
2075           /* Reduce the number of colors in the image.
2076              FUTURE: also provide 'plus version with image 'color counts'
2077           */
2078           _quantize_info->number_colors=StringToUnsignedLong(arg1);
2079           if (_quantize_info->number_colors == 0)
2080             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2081           if ((_image->storage_class == DirectClass) ||
2082               _image->colors > _quantize_info->number_colors)
2083             (void) QuantizeImage(_quantize_info,_image,_exception);
2084           else
2085             (void) CompressImageColormap(_image,_exception);
2086           break;
2087         }
2088       if (LocaleCompare("colorspace",option+1) == 0)
2089         {
2090           /* WARNING: this is both a image_info setting (already done)
2091                       and a operator to change image colorspace.
2092
2093              FUTURE: default colorspace should be sRGB!
2094              Unless some type of 'linear colorspace' mode is set.
2095
2096              Note that +colorspace sets "undefined" or no effect on
2097              new images, but forces images already in memory back to RGB!
2098              That seems to be a little strange!
2099           */
2100           (void) TransformImageColorspace(_image,
2101                     IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2102                     _exception);
2103           break;
2104         }
2105       if (LocaleCompare("connected-components",option+1) == 0)
2106         {
2107           if (IfMagickFalse(IsGeometry(arg1)))
2108             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2109           new_image=ConnectedComponentsImage(_image,(size_t)
2110             StringToInteger(arg1),_exception);
2111           break;
2112         }
2113       if (LocaleCompare("contrast",option+1) == 0)
2114         {
2115           CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2116           (void) ContrastImage(_image,IsNormalOp,_exception);
2117           break;
2118         }
2119       if (LocaleCompare("contrast-stretch",option+1) == 0)
2120         {
2121           double
2122             black_point,
2123             white_point;
2124
2125           MagickStatusType
2126             flags;
2127
2128           flags=ParseGeometry(arg1,&geometry_info);
2129           if ((flags & RhoValue) == 0)
2130             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2131           black_point=geometry_info.rho;
2132           white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2133             black_point;
2134           if ((flags & PercentValue) != 0) {
2135               black_point*=(double) _image->columns*_image->rows/100.0;
2136               white_point*=(double) _image->columns*_image->rows/100.0;
2137             }
2138           white_point=(double) _image->columns*_image->rows-white_point;
2139           (void) ContrastStretchImage(_image,black_point,white_point,
2140             _exception);
2141           break;
2142         }
2143       if (LocaleCompare("convolve",option+1) == 0)
2144         {
2145           double
2146             gamma;
2147             
2148           KernelInfo
2149             *kernel_info;
2150             
2151           register ssize_t
2152             j;
2153
2154           kernel_info=AcquireKernelInfo(arg1,exception);
2155           if (kernel_info == (KernelInfo *) NULL)
2156             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2157           gamma=0.0;
2158           for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2159             gamma+=kernel_info->values[j];
2160           gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2161           for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2162             kernel_info->values[j]*=gamma;
2163           new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2164             _exception);
2165           kernel_info=DestroyKernelInfo(kernel_info);
2166           break;
2167         }
2168       if (LocaleCompare("crop",option+1) == 0)
2169         {
2170           /* WARNING: This can generate multiple images! */
2171           if (IfMagickFalse(IsGeometry(arg1)))
2172             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2173           new_image=CropImageToTiles(_image,arg1,_exception);
2174           break;
2175         }
2176       if (LocaleCompare("cycle",option+1) == 0)
2177         {
2178           if (IfMagickFalse(IsGeometry(arg1)))
2179             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2180           (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2181             _exception);
2182           break;
2183         }
2184       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2185     }
2186     case 'd':
2187     {
2188       if (LocaleCompare("decipher",option+1) == 0)
2189         {
2190           /* Note: arguments do not have percent escapes expanded */
2191           StringInfo
2192             *passkey;
2193
2194           passkey=FileToStringInfo(arg1,~0UL,_exception);
2195           if (passkey == (StringInfo *) NULL)
2196             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2197
2198           (void) PasskeyDecipherImage(_image,passkey,_exception);
2199           passkey=DestroyStringInfo(passkey);
2200           break;
2201         }
2202       if (LocaleCompare("depth",option+1) == 0)
2203         {
2204           /* The _image_info->depth setting has already been set
2205              We just need to apply it to all images in current sequence
2206
2207              WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2208              That is it really is an operation, not a setting! Arrgghhh
2209
2210              FUTURE: this should not be an operator!!!
2211           */
2212           (void) SetImageDepth(_image,_image_info->depth,_exception);
2213           break;
2214         }
2215       if (LocaleCompare("deskew",option+1) == 0)
2216         {
2217           double
2218             threshold;
2219
2220           if (IfNormalOp) {
2221             if (IfMagickFalse(IsGeometry(arg1)))
2222               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2223             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2224           }
2225           else
2226             threshold=40.0*QuantumRange/100.0;
2227           new_image=DeskewImage(_image,threshold,_exception);
2228           break;
2229         }
2230       if (LocaleCompare("despeckle",option+1) == 0)
2231         {
2232           new_image=DespeckleImage(_image,_exception);
2233           break;
2234         }
2235       if (LocaleCompare("distort",option+1) == 0)
2236         {
2237           double
2238             *args;
2239
2240           ssize_t
2241             count;
2242
2243           parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2244           if ( parse < 0 )
2245              CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2246                                       option,arg1);
2247           if ((DistortImageMethod) parse == ResizeDistortion)
2248             {
2249                double
2250                  resize_args[2];
2251                /* Special Case - Argument is actually a resize geometry!
2252                ** Convert that to an appropriate distortion argument array.
2253                ** FUTURE: make a separate special resize operator
2254                     Roll into a resize special operator */
2255                if (IfMagickFalse(IsGeometry(arg2)))
2256                  CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2257                                            option,arg2);
2258                (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2259                resize_args[0]=(double) geometry.width;
2260                resize_args[1]=(double) geometry.height;
2261                new_image=DistortImage(_image,(DistortImageMethod) parse,
2262                     (size_t)2,resize_args,MagickTrue,_exception);
2263                break;
2264             }
2265           /* convert argument string into an array of doubles */
2266           args = StringToArrayOfDoubles(arg2,&count,_exception);
2267           if (args == (double *) NULL )
2268             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2269
2270           new_image=DistortImage(_image,(DistortImageMethod) parse,(size_t)
2271              count,args,IsPlusOp,_exception);
2272           args=(double *) RelinquishMagickMemory(args);
2273           break;
2274         }
2275       if (LocaleCompare("draw",option+1) == 0)
2276         {
2277           (void) CloneString(&_draw_info->primitive,arg1);
2278           (void) DrawImage(_image,_draw_info,_exception);
2279           (void) CloneString(&_draw_info->primitive,(char *) NULL);
2280           break;
2281         }
2282       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2283     }
2284     case 'e':
2285     {
2286       if (LocaleCompare("edge",option+1) == 0)
2287         {
2288           flags=ParseGeometry(arg1,&geometry_info);
2289           if ((flags & (RhoValue|SigmaValue)) == 0)
2290             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2291           new_image=EdgeImage(_image,geometry_info.rho,_exception);
2292           break;
2293         }
2294       if (LocaleCompare("emboss",option+1) == 0)
2295         {
2296           flags=ParseGeometry(arg1,&geometry_info);
2297           if ((flags & (RhoValue|SigmaValue)) == 0)
2298             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2299           if ((flags & SigmaValue) == 0)
2300             geometry_info.sigma=1.0;
2301           new_image=EmbossImage(_image,geometry_info.rho,
2302             geometry_info.sigma,_exception);
2303           break;
2304         }
2305       if (LocaleCompare("encipher",option+1) == 0)
2306         {
2307           /* Note: arguments do not have percent escapes expanded */
2308           StringInfo
2309             *passkey;
2310
2311           passkey=FileToStringInfo(arg1,~0UL,_exception);
2312           if (passkey != (StringInfo *) NULL)
2313             {
2314               (void) PasskeyEncipherImage(_image,passkey,_exception);
2315               passkey=DestroyStringInfo(passkey);
2316             }
2317           break;
2318         }
2319       if (LocaleCompare("enhance",option+1) == 0)
2320         {
2321           new_image=EnhanceImage(_image,_exception);
2322           break;
2323         }
2324       if (LocaleCompare("equalize",option+1) == 0)
2325         {
2326           (void) EqualizeImage(_image,_exception);
2327           break;
2328         }
2329       if (LocaleCompare("evaluate",option+1) == 0)
2330         {
2331           double
2332             constant;
2333
2334           parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2335           if ( parse < 0 )
2336             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2337                  option,arg1);
2338           if (IfMagickFalse(IsGeometry(arg2)))
2339             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2340           constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2341           (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2342                _exception);
2343           break;
2344         }
2345       if (LocaleCompare("extent",option+1) == 0)
2346         {
2347           if (IfMagickFalse(IsGeometry(arg1)))
2348             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2349           flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2350           if (geometry.width == 0)
2351             geometry.width=_image->columns;
2352           if (geometry.height == 0)
2353             geometry.height=_image->rows;
2354           new_image=ExtentImage(_image,&geometry,_exception);
2355           break;
2356         }
2357       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2358     }
2359     case 'f':
2360     {
2361       if (LocaleCompare("flip",option+1) == 0)
2362         {
2363           new_image=FlipImage(_image,_exception);
2364           break;
2365         }
2366       if (LocaleCompare("flop",option+1) == 0)
2367         {
2368           new_image=FlopImage(_image,_exception);
2369           break;
2370         }
2371       if (LocaleCompare("floodfill",option+1) == 0)
2372         {
2373           PixelInfo
2374             target;
2375
2376           if (IfMagickFalse(IsGeometry(arg1)))
2377             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2378           (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2379           (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2380           (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2381             geometry.y,IsPlusOp,_exception);
2382           break;
2383         }
2384       if (LocaleCompare("frame",option+1) == 0)
2385         {
2386           FrameInfo
2387             frame_info;
2388
2389           CompositeOperator
2390             compose;
2391
2392           const char*
2393             value;
2394
2395           value=GetImageOption(_image_info,"compose");
2396             compose=OverCompositeOp;  /* use Over not _image->compose */
2397           if (value != (const char *) NULL)
2398             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2399               MagickFalse,value);
2400           if (IfMagickFalse(IsGeometry(arg1)))
2401             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2402           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2403           frame_info.width=geometry.width;
2404           frame_info.height=geometry.height;
2405           frame_info.outer_bevel=geometry.x;
2406           frame_info.inner_bevel=geometry.y;
2407           frame_info.x=(ssize_t) frame_info.width;
2408           frame_info.y=(ssize_t) frame_info.height;
2409           frame_info.width=_image->columns+2*frame_info.width;
2410           frame_info.height=_image->rows+2*frame_info.height;
2411           new_image=FrameImage(_image,&frame_info,compose,_exception);
2412           break;
2413         }
2414       if (LocaleCompare("function",option+1) == 0)
2415         {
2416           double
2417             *args;
2418
2419           ssize_t
2420             count;
2421
2422           parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2423           if ( parse < 0 )
2424             CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2425                  option,arg1);
2426           /* convert argument string into an array of doubles */
2427           args = StringToArrayOfDoubles(arg2,&count,_exception);
2428           if (args == (double *) NULL )
2429             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2430
2431           (void) FunctionImage(_image,(MagickFunction)parse,(size_t) count,args,
2432                _exception);
2433           args=(double *) RelinquishMagickMemory(args);
2434           break;
2435         }
2436       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2437     }
2438     case 'g':
2439     {
2440       if (LocaleCompare("gamma",option+1) == 0)
2441         {
2442           double
2443             constant;
2444
2445           if (IfMagickFalse(IsGeometry(arg1)))
2446             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2447           constant=StringToDouble(arg1,(char **) NULL);
2448 #if 0
2449           /* Using Gamma, via a cache */
2450           if (IfPlusOp)
2451             constant=PerceptibleReciprocal(constant);
2452           (void) GammaImage(_image,constant,_exception);
2453 #else
2454           /* Using Evaluate POW, direct update of values - more accurite */
2455           if (IfNormalOp)
2456             constant=PerceptibleReciprocal(constant);
2457           (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2458           _image->gamma*=StringToDouble(arg1,(char **) NULL);
2459 #endif
2460           /* Set gamma setting -- Old meaning of "+gamma"
2461            * _image->gamma=StringToDouble(arg1,(char **) NULL);
2462            */
2463           break;
2464         }
2465       if (LocaleCompare("gaussian-blur",option+1) == 0)
2466         {
2467           flags=ParseGeometry(arg1,&geometry_info);
2468           if ((flags & (RhoValue|SigmaValue)) == 0)
2469             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2470           if ((flags & SigmaValue) == 0)
2471             geometry_info.sigma=1.0;
2472           new_image=GaussianBlurImage(_image,geometry_info.rho,
2473             geometry_info.sigma,_exception);
2474           break;
2475         }
2476       if (LocaleCompare("gaussian",option+1) == 0)
2477         {
2478           CLIWandWarnReplaced("-gaussian-blur");
2479           (void) CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2480         }
2481       if (LocaleCompare("geometry",option+1) == 0)
2482         {
2483           /*
2484             Record Image offset for composition. (A Setting)
2485             Resize last _image. (ListOperator)  -- DEPRECIATE
2486             FUTURE: Why if no 'offset' does this resize ALL images?
2487             Also why is the setting recorded in the IMAGE non-sense!
2488           */
2489           if (IfPlusOp)
2490             { /* remove the previous composition geometry offset! */
2491               if (_image->geometry != (char *) NULL)
2492                 _image->geometry=DestroyString(_image->geometry);
2493               break;
2494             }
2495           if (IfMagickFalse(IsGeometry(arg1)))
2496             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2497           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2498           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2499             (void) CloneString(&_image->geometry,arg1);
2500           else
2501             new_image=ResizeImage(_image,geometry.width,geometry.height,
2502               _image->filter,_exception);
2503           break;
2504         }
2505       if (LocaleCompare("grayscale",option+1) == 0)
2506         {
2507           parse=ParseCommandOption(MagickPixelIntensityOptions,
2508             MagickFalse,arg1);
2509           if (parse < 0)
2510             CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2511               option,arg1);
2512           (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2513           break;
2514         }
2515       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2516     }
2517     case 'h':
2518     {
2519       if (LocaleCompare("hough-lines",option+1) == 0)
2520         {
2521           flags=ParseGeometry(arg1,&geometry_info);
2522           if ((flags & (RhoValue|SigmaValue)) == 0)
2523             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2524           if ((flags & SigmaValue) == 0)
2525             geometry_info.sigma=geometry_info.rho;
2526           if ((flags & XiValue) == 0)
2527             geometry_info.xi=40;
2528           new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2529             (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2530           break;
2531         }
2532       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2533     }
2534     case 'i':
2535     {
2536       if (LocaleCompare("identify",option+1) == 0)
2537         {
2538           const char
2539             *format,
2540             *text;
2541
2542           format=GetImageOption(_image_info,"format");
2543           if (format == (char *) NULL)
2544             {
2545               (void) IdentifyImage(_image,stdout,_image_info->verbose,
2546                 _exception);
2547               break;
2548             }
2549           text=InterpretImageProperties(_image_info,_image,format,_exception);
2550           if (text == (char *) NULL)
2551             CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2552               option);
2553           (void) fputs(text,stdout);
2554           text=DestroyString((char *)text);
2555           break;
2556         }
2557       if (LocaleCompare("implode",option+1) == 0)
2558         {
2559           flags=ParseGeometry(arg1,&geometry_info);
2560           if ((flags & RhoValue) == 0)
2561             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2562           new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2563                _exception);
2564           break;
2565         }
2566       if (LocaleCompare("interpolative-resize",option+1) == 0)
2567         {
2568           /* FUTURE: New to IMv7
2569                Roll into a resize special operator */
2570           if (IfMagickFalse(IsGeometry(arg1)))
2571             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2572           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2573           new_image=InterpolativeResizeImage(_image,geometry.width,
2574                geometry.height,_image->interpolate,_exception);
2575           break;
2576         }
2577       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2578     }
2579     case 'k':
2580     {
2581       if (LocaleCompare("kuwahara",option+1) == 0)
2582         {
2583           /*
2584             Edge preserving blur.
2585           */
2586           flags=ParseGeometry(arg1,&geometry_info);
2587           if ((flags & (RhoValue|SigmaValue)) == 0)
2588             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2589           if ((flags & SigmaValue) == 0)
2590             geometry_info.sigma=geometry_info.rho-0.5;
2591           new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2592            _exception);
2593           break;
2594         }
2595       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2596     }
2597     case 'l':
2598     {
2599       if (LocaleCompare("lat",option+1) == 0)
2600         {
2601           flags=ParseGeometry(arg1,&geometry_info);
2602           if ((flags & (RhoValue|SigmaValue)) == 0)
2603             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2604           if ((flags & SigmaValue) == 0)
2605             geometry_info.sigma=1.0;
2606           if ((flags & PercentValue) != 0)
2607             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2608           new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2609                (size_t) geometry_info.sigma,(double) geometry_info.xi,
2610                _exception);
2611           break;
2612         }
2613       if (LocaleCompare("level",option+1) == 0)
2614         {
2615           double
2616             black_point,
2617             gamma,
2618             white_point;
2619
2620           MagickStatusType
2621             flags;
2622
2623           flags=ParseGeometry(arg1,&geometry_info);
2624           if ((flags & RhoValue) == 0)
2625             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2626           black_point=geometry_info.rho;
2627           white_point=(double) QuantumRange;
2628           if ((flags & SigmaValue) != 0)
2629             white_point=geometry_info.sigma;
2630           gamma=1.0;
2631           if ((flags & XiValue) != 0)
2632             gamma=geometry_info.xi;
2633           if ((flags & PercentValue) != 0)
2634             {
2635               black_point*=(double) (QuantumRange/100.0);
2636               white_point*=(double) (QuantumRange/100.0);
2637             }
2638           if ((flags & SigmaValue) == 0)
2639             white_point=(double) QuantumRange-black_point;
2640           if (IfPlusOp || ((flags & AspectValue) != 0))
2641             (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2642           else
2643             (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2644           break;
2645         }
2646       if (LocaleCompare("level-colors",option+1) == 0)
2647         {
2648           char
2649             token[MagickPathExtent];
2650
2651           const char
2652             *p;
2653
2654           PixelInfo
2655             black_point,
2656             white_point;
2657
2658           p=(const char *) arg1;
2659           GetMagickToken(p,&p,token);  /* get black point color */
2660           if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2661             (void) QueryColorCompliance(token,AllCompliance,
2662                       &black_point,_exception);
2663           else
2664             (void) QueryColorCompliance("#000000",AllCompliance,
2665                       &black_point,_exception);
2666           if (isalpha((int) token[0]) || (token[0] == '#'))
2667             GetMagickToken(p,&p,token);
2668           if (*token == '\0')
2669             white_point=black_point; /* set everything to that color */
2670           else
2671             {
2672               if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2673                 GetMagickToken(p,&p,token); /* Get white point color. */
2674               if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2675                 (void) QueryColorCompliance(token,AllCompliance,
2676                            &white_point,_exception);
2677               else
2678                 (void) QueryColorCompliance("#ffffff",AllCompliance,
2679                            &white_point,_exception);
2680             }
2681           (void) LevelImageColors(_image,&black_point,&white_point,
2682                      IsPlusOp,_exception);
2683           break;
2684         }
2685       if (LocaleCompare("linear-stretch",option+1) == 0)
2686         {
2687           double
2688             black_point,
2689             white_point;
2690
2691           MagickStatusType
2692             flags;
2693
2694           flags=ParseGeometry(arg1,&geometry_info);
2695           if ((flags & RhoValue) == 0)
2696             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2697           black_point=geometry_info.rho;
2698           white_point=(double) _image->columns*_image->rows;
2699           if ((flags & SigmaValue) != 0)
2700             white_point=geometry_info.sigma;
2701           if ((flags & PercentValue) != 0)
2702             {
2703               black_point*=(double) _image->columns*_image->rows/100.0;
2704               white_point*=(double) _image->columns*_image->rows/100.0;
2705             }
2706           if ((flags & SigmaValue) == 0)
2707             white_point=(double) _image->columns*_image->rows-
2708               black_point;
2709           (void) LinearStretchImage(_image,black_point,white_point,_exception);
2710           break;
2711         }
2712       if (LocaleCompare("liquid-rescale",option+1) == 0)
2713         {
2714           /* FUTURE: Roll into a resize special operator */
2715           if (IfMagickFalse(IsGeometry(arg1)))
2716             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2717           flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2718           if ((flags & XValue) == 0)
2719             geometry.x=1;
2720           if ((flags & YValue) == 0)
2721             geometry.y=0;
2722           new_image=LiquidRescaleImage(_image,geometry.width,
2723             geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2724           break;
2725         }
2726       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2727     }
2728     case 'm':
2729     {
2730       if (LocaleCompare("magnify",option+1) == 0)
2731         {
2732           new_image=MagnifyImage(_image,_exception);
2733           break;
2734         }
2735       if (LocaleCompare("map",option+1) == 0)
2736         {
2737           CLIWandWarnReplaced("-remap");
2738           (void) CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL,exception);
2739           break;
2740         }
2741       if (LocaleCompare("mask",option+1) == 0)
2742         {
2743           /* Note: arguments do not have percent escapes expanded */
2744           Image
2745             *mask;
2746
2747           if (IfPlusOp)
2748             { /* Remove a mask. */
2749               (void) SetImageMask(_image,(Image *) NULL,_exception);
2750               break;
2751             }
2752           /* Set the image mask. */
2753           mask=GetImageCache(_image_info,arg1,_exception);
2754           if (mask == (Image *) NULL)
2755             break;
2756           (void) SetImageMask(_image,mask,_exception);
2757           mask=DestroyImage(mask);
2758           break;
2759         }
2760       if (LocaleCompare("matte",option+1) == 0)
2761         {
2762           CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2763           (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2764             DeactivateAlphaChannel, _exception);
2765           break;
2766         }
2767       if (LocaleCompare("mean-shift",option+1) == 0)
2768         {
2769           flags=ParseGeometry(arg1,&geometry_info);
2770           if ((flags & (RhoValue|SigmaValue)) == 0)
2771             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2772           if ((flags & SigmaValue) == 0)
2773             geometry_info.sigma=1.0;
2774           if ((flags & XiValue) == 0)
2775             geometry_info.xi=0.10*QuantumRange;
2776           if ((flags & PercentValue) != 0)
2777             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2778           new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2779             (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2780           break;
2781         }
2782       if (LocaleCompare("median",option+1) == 0)
2783         {
2784           CLIWandWarnReplaced("-statistic Median");
2785           (void) CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2786           break;
2787         }
2788       if (LocaleCompare("mode",option+1) == 0)
2789         {
2790           /* FUTURE: note this is also a special "montage" option */
2791           CLIWandWarnReplaced("-statistic Mode");
2792           (void) CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,exception);
2793           break;
2794         }
2795       if (LocaleCompare("modulate",option+1) == 0)
2796         {
2797           if (IfMagickFalse(IsGeometry(arg1)))
2798             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2799           (void) ModulateImage(_image,arg1,_exception);
2800           break;
2801         }
2802       if (LocaleCompare("monitor",option+1) == 0)
2803         {
2804           (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2805                 (MagickProgressMonitor) NULL,(void *) NULL);
2806           break;
2807         }
2808       if (LocaleCompare("monochrome",option+1) == 0)
2809         {
2810           (void) SetImageType(_image,BilevelType,_exception);
2811           break;
2812         }
2813       if (LocaleCompare("morphology",option+1) == 0)
2814         {
2815           char
2816             token[MagickPathExtent];
2817
2818           const char
2819             *p;
2820
2821           KernelInfo
2822             *kernel;
2823
2824           ssize_t
2825             iterations;
2826
2827           p=arg1;
2828           GetMagickToken(p,&p,token);
2829           parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2830           if ( parse < 0 )
2831             CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2832               arg1);
2833           iterations=1L;
2834           GetMagickToken(p,&p,token);
2835           if ((*p == ':') || (*p == ','))
2836             GetMagickToken(p,&p,token);
2837           if ((*p != '\0'))
2838             iterations=(ssize_t) StringToLong(p);
2839           kernel=AcquireKernelInfo(arg2,exception);
2840           if (kernel == (KernelInfo *) NULL)
2841             CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2842           new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2843             kernel,_exception);
2844           kernel=DestroyKernelInfo(kernel);
2845           break;
2846         }
2847       if (LocaleCompare("motion-blur",option+1) == 0)
2848         {
2849           flags=ParseGeometry(arg1,&geometry_info);
2850           if ((flags & (RhoValue|SigmaValue)) == 0)
2851             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2852           if ((flags & SigmaValue) == 0)
2853             geometry_info.sigma=1.0;
2854           new_image=MotionBlurImage(_image,geometry_info.rho,geometry_info.sigma,
2855             geometry_info.xi,_exception);
2856           break;
2857         }
2858       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2859     }
2860     case 'n':
2861     {
2862       if (LocaleCompare("negate",option+1) == 0)
2863         {
2864           (void) NegateImage(_image, IsPlusOp, _exception);
2865           break;
2866         }
2867       if (LocaleCompare("noise",option+1) == 0)
2868         {
2869           double
2870             attenuate;
2871
2872           const char*
2873             value;
2874
2875           if (IfNormalOp)
2876             {
2877               CLIWandWarnReplaced("-statistic NonPeak");
2878               (void) CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2879               break;
2880             }
2881           parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2882           if ( parse < 0 )
2883             CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2884                 option,arg1);
2885           attenuate=1.0;
2886           value=GetImageOption(_image_info,"attenuate");
2887           if  (value != (const char *) NULL)
2888             attenuate=StringToDouble(value,(char **) NULL);
2889           new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2890                _exception);
2891           break;
2892         }
2893       if (LocaleCompare("normalize",option+1) == 0)
2894         {
2895           (void) NormalizeImage(_image,_exception);
2896           break;
2897         }
2898       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2899     }
2900     case 'o':
2901     {
2902       if (LocaleCompare("opaque",option+1) == 0)
2903         {
2904           PixelInfo
2905             target;
2906
2907           (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2908           (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2909                _exception);
2910           break;
2911         }
2912       if (LocaleCompare("ordered-dither",option+1) == 0)
2913         {
2914           (void) OrderedPosterizeImage(_image,arg1,_exception);
2915           break;
2916         }
2917       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2918     }
2919     case 'p':
2920     {
2921       if (LocaleCompare("paint",option+1) == 0)
2922         {
2923           flags=ParseGeometry(arg1,&geometry_info);
2924           if ((flags & (RhoValue|SigmaValue)) == 0)
2925             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2926           new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2927                _exception);
2928           break;
2929         }
2930       if (LocaleCompare("perceptible",option+1) == 0)
2931         {
2932           (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2933             _exception);
2934           break;
2935         }
2936       if (LocaleCompare("polaroid",option+1) == 0)
2937         {
2938           const char
2939             *caption;
2940
2941           double
2942             angle;
2943
2944           if (IfPlusOp) {
2945             RandomInfo
2946               *random_info;
2947
2948             random_info=AcquireRandomInfo();
2949             angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2950             random_info=DestroyRandomInfo(random_info);
2951           }
2952           else {
2953             flags=ParseGeometry(arg1,&geometry_info);
2954             if ((flags & RhoValue) == 0)
2955               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2956             angle=geometry_info.rho;
2957           }
2958           caption=GetImageProperty(_image,"caption",_exception);
2959           new_image=PolaroidImage(_image,_draw_info,caption,angle,
2960             _image->interpolate,_exception);
2961           break;
2962         }
2963       if (LocaleCompare("posterize",option+1) == 0)
2964         {
2965           flags=ParseGeometry(arg1,&geometry_info);
2966           if ((flags & RhoValue) == 0)
2967             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2968           (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2969             _quantize_info->dither_method,_exception);
2970           break;
2971         }
2972       if (LocaleCompare("preview",option+1) == 0)
2973         {
2974           /* FUTURE: should be a 'Genesis' option?
2975              Option however is also in WandSettingOptionInfo()
2976              Why???
2977           */
2978           parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2979           if ( parse < 0 )
2980             CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2981                 option,arg1);
2982           new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2983           break;
2984         }
2985       if (LocaleCompare("profile",option+1) == 0)
2986         {
2987           /* Note: arguments do not have percent escapes expanded */
2988           const char
2989             *name;
2990
2991           const StringInfo
2992             *profile;
2993
2994           Image
2995             *profile_image;
2996
2997           ImageInfo
2998             *profile_info;
2999
3000           if (IfPlusOp)
3001             { /* Remove a profile from the _image.  */
3002               (void) ProfileImage(_image,arg1,(const unsigned char *)
3003                 NULL,0,_exception);
3004               break;
3005             }
3006           /* Associate a profile with the _image.  */
3007           profile_info=CloneImageInfo(_image_info);
3008           profile=GetImageProfile(_image,"iptc");
3009           if (profile != (StringInfo *) NULL)
3010             profile_info->profile=(void *) CloneStringInfo(profile);
3011           profile_image=GetImageCache(profile_info,arg1,_exception);
3012           profile_info=DestroyImageInfo(profile_info);
3013           if (profile_image == (Image *) NULL)
3014             {
3015               StringInfo
3016                 *profile;
3017
3018               profile_info=CloneImageInfo(_image_info);
3019               (void) CopyMagickString(profile_info->filename,arg1,
3020                 MagickPathExtent);
3021               profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
3022               if (profile != (StringInfo *) NULL)
3023                 {
3024                   (void) ProfileImage(_image,profile_info->magick,
3025                     GetStringInfoDatum(profile),(size_t)
3026                     GetStringInfoLength(profile),_exception);
3027                   profile=DestroyStringInfo(profile);
3028                 }
3029               profile_info=DestroyImageInfo(profile_info);
3030               break;
3031             }
3032           ResetImageProfileIterator(profile_image);
3033           name=GetNextImageProfile(profile_image);
3034           while (name != (const char *) NULL)
3035           {
3036             profile=GetImageProfile(profile_image,name);
3037             if (profile != (StringInfo *) NULL)
3038               (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3039                 (size_t) GetStringInfoLength(profile),_exception);
3040             name=GetNextImageProfile(profile_image);
3041           }
3042           profile_image=DestroyImage(profile_image);
3043           break;
3044         }
3045       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3046     }
3047     case 'r':
3048     {
3049       if (LocaleCompare("rotational-blur",option+1) == 0)
3050         {
3051           flags=ParseGeometry(arg1,&geometry_info);
3052           if ((flags & RhoValue) == 0)
3053             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3054           new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3055           break;
3056         }
3057       if (LocaleCompare("raise",option+1) == 0)
3058         {
3059           if (IfMagickFalse(IsGeometry(arg1)))
3060             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3061           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3062           (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3063           break;
3064         }
3065       if (LocaleCompare("random-threshold",option+1) == 0)
3066         {
3067           if (IfMagickFalse(IsGeometry(arg1)))
3068             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3069           (void) RandomThresholdImage(_image,arg1,_exception);
3070           break;
3071         }
3072       if (LocaleCompare("recolor",option+1) == 0)
3073         {
3074           CLIWandWarnReplaced("-color-matrix");
3075           (void) CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,exception);
3076         }
3077       if (LocaleCompare("remap",option+1) == 0)
3078         {
3079           /* Note: arguments do not have percent escapes expanded */
3080           Image
3081             *remap_image;
3082
3083           remap_image=GetImageCache(_image_info,arg1,_exception);
3084           if (remap_image == (Image *) NULL)
3085             break;
3086           (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3087           remap_image=DestroyImage(remap_image);
3088           break;
3089         }
3090       if (LocaleCompare("repage",option+1) == 0)
3091         {
3092           if (IfNormalOp)
3093             {
3094               if (IfMagickFalse(IsGeometry(arg1)))
3095                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3096                   arg1);
3097               (void) ResetImagePage(_image,arg1);
3098             }
3099           else
3100             (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3101           break;
3102         }
3103       if (LocaleCompare("resample",option+1) == 0)
3104         {
3105           /* FUTURE: Roll into a resize special operation */
3106           flags=ParseGeometry(arg1,&geometry_info);
3107           if ((flags & (RhoValue|SigmaValue)) == 0)
3108             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3109           if ((flags & SigmaValue) == 0)
3110             geometry_info.sigma=geometry_info.rho;
3111           new_image=ResampleImage(_image,geometry_info.rho,
3112             geometry_info.sigma,_image->filter,_exception);
3113           break;
3114         }
3115       if (LocaleCompare("resize",option+1) == 0)
3116         {
3117           if (IfMagickFalse(IsGeometry(arg1)))
3118             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3119           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3120           new_image=ResizeImage(_image,geometry.width,geometry.height,
3121             _image->filter,_exception);
3122           break;
3123         }
3124       if (LocaleCompare("roll",option+1) == 0)
3125         {
3126           if (IfMagickFalse(IsGeometry(arg1)))
3127             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3128           (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3129           new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3130           break;
3131         }
3132       if (LocaleCompare("rotate",option+1) == 0)
3133         {
3134           flags=ParseGeometry(arg1,&geometry_info);
3135           if ((flags & RhoValue) == 0)
3136             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3137           if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3138             break;
3139           if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3140             break;
3141           new_image=RotateImage(_image,geometry_info.rho,_exception);
3142           break;
3143         }
3144       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3145     }
3146     case 's':
3147     {
3148       if (LocaleCompare("sample",option+1) == 0)
3149         {
3150           /* FUTURE: Roll into a resize special operator */
3151           if (IfMagickFalse(IsGeometry(arg1)))
3152             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3153           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3154           new_image=SampleImage(_image,geometry.width,geometry.height,
3155             _exception);
3156           break;
3157         }
3158       if (LocaleCompare("scale",option+1) == 0)
3159         {
3160           /* FUTURE: Roll into a resize special operator */
3161           if (IfMagickFalse(IsGeometry(arg1)))
3162             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3163           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3164           new_image=ScaleImage(_image,geometry.width,geometry.height,
3165             _exception);
3166           break;
3167         }
3168       if (LocaleCompare("segment",option+1) == 0)
3169         {
3170           flags=ParseGeometry(arg1,&geometry_info);
3171           if ((flags & (RhoValue|SigmaValue)) == 0)
3172             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3173           if ((flags & SigmaValue) == 0)
3174             geometry_info.sigma=1.0;
3175           (void) SegmentImage(_image,_image->colorspace,
3176             _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3177             _exception);
3178           break;
3179         }
3180       if (LocaleCompare("selective-blur",option+1) == 0)
3181         {
3182           flags=ParseGeometry(arg1,&geometry_info);
3183           if ((flags & (RhoValue|SigmaValue)) == 0)
3184             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3185           if ((flags & SigmaValue) == 0)
3186             geometry_info.sigma=1.0;
3187           if ((flags & PercentValue) != 0)
3188             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3189           new_image=SelectiveBlurImage(_image,geometry_info.rho,
3190             geometry_info.sigma,geometry_info.xi,_exception);
3191           break;
3192         }
3193       if (LocaleCompare("separate",option+1) == 0)
3194         {
3195           /* WARNING: This can generate multiple images! */
3196           /* FUTURE - this may be replaced by a "-channel" method */
3197           new_image=SeparateImages(_image,_exception);
3198           break;
3199         }
3200       if (LocaleCompare("sepia-tone",option+1) == 0)
3201         {
3202           if (IfMagickFalse(IsGeometry(arg1)))
3203             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3204           new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3205                  (double) QuantumRange+1.0),_exception);
3206           break;
3207         }
3208       if (LocaleCompare("shade",option+1) == 0)
3209         {
3210           flags=ParseGeometry(arg1,&geometry_info);
3211           if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3212             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3213           new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3214                geometry_info.sigma,_exception);
3215           break;
3216         }
3217       if (LocaleCompare("shadow",option+1) == 0)
3218         {
3219           flags=ParseGeometry(arg1,&geometry_info);
3220           if ((flags & (RhoValue|SigmaValue)) == 0)
3221             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3222           if ((flags & SigmaValue) == 0)
3223             geometry_info.sigma=1.0;
3224           if ((flags & XiValue) == 0)
3225             geometry_info.xi=4.0;
3226           if ((flags & PsiValue) == 0)
3227             geometry_info.psi=4.0;
3228           new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3229             (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3230             ceil(geometry_info.psi-0.5),_exception);
3231           break;
3232         }
3233       if (LocaleCompare("sharpen",option+1) == 0)
3234         {
3235           flags=ParseGeometry(arg1,&geometry_info);
3236           if ((flags & (RhoValue|SigmaValue)) == 0)
3237             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3238           if ((flags & SigmaValue) == 0)
3239             geometry_info.sigma=1.0;
3240           if ((flags & XiValue) == 0)
3241             geometry_info.xi=0.0;
3242           new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3243            _exception);
3244           break;
3245         }
3246       if (LocaleCompare("shave",option+1) == 0)
3247         {
3248           if (IfMagickFalse(IsGeometry(arg1)))
3249             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3250           flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3251           new_image=ShaveImage(_image,&geometry,_exception);
3252           break;
3253         }
3254       if (LocaleCompare("shear",option+1) == 0)
3255         {
3256           flags=ParseGeometry(arg1,&geometry_info);
3257           if ((flags & RhoValue) == 0)
3258             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3259           if ((flags & SigmaValue) == 0)
3260             geometry_info.sigma=geometry_info.rho;
3261           new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3262             _exception);
3263           break;
3264         }
3265       if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3266         {
3267           flags=ParseGeometry(arg1,&geometry_info);
3268           if ((flags & RhoValue) == 0)
3269             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3270           if ((flags & SigmaValue) == 0)
3271             geometry_info.sigma=(double) QuantumRange/2.0;
3272           if ((flags & PercentValue) != 0)
3273             geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3274               100.0;
3275           (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3276                geometry_info.sigma,_exception);
3277           break;
3278         }
3279       if (LocaleCompare("sketch",option+1) == 0)
3280         {
3281           flags=ParseGeometry(arg1,&geometry_info);
3282           if ((flags & (RhoValue|SigmaValue)) == 0)
3283             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3284           if ((flags & SigmaValue) == 0)
3285             geometry_info.sigma=1.0;
3286           new_image=SketchImage(_image,geometry_info.rho,
3287             geometry_info.sigma,geometry_info.xi,_exception);
3288           break;
3289         }
3290       if (LocaleCompare("solarize",option+1) == 0)
3291         {
3292           if (IfMagickFalse(IsGeometry(arg1)))
3293             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3294           (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3295                  QuantumRange+1.0),_exception);
3296           break;
3297         }
3298       if (LocaleCompare("sparse-color",option+1) == 0)
3299         {
3300           parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3301           if ( parse < 0 )
3302             CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3303                 option,arg1);
3304           new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3305                _exception);
3306           break;
3307         }
3308       if (LocaleCompare("splice",option+1) == 0)
3309         {
3310           if (IfMagickFalse(IsGeometry(arg1)))
3311             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3312           flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3313           new_image=SpliceImage(_image,&geometry,_exception);
3314           break;
3315         }
3316       if (LocaleCompare("spread",option+1) == 0)
3317         {
3318           flags=ParseGeometry(arg1,&geometry_info);
3319           if ((flags & RhoValue) == 0)
3320             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3321           new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3322                _exception);
3323           break;
3324         }
3325       if (LocaleCompare("statistic",option+1) == 0)
3326         {
3327           parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3328           if ( parse < 0 )
3329             CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3330                  option,arg1);
3331           flags=ParseGeometry(arg2,&geometry_info);
3332           if ((flags & RhoValue) == 0)
3333             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3334           if ((flags & SigmaValue) == 0)
3335             geometry_info.sigma=geometry_info.rho;
3336           new_image=StatisticImage(_image,(StatisticType)parse,
3337                (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3338                _exception);
3339           break;
3340         }
3341       if (LocaleCompare("strip",option+1) == 0)
3342         {
3343           (void) StripImage(_image,_exception);
3344           break;
3345         }
3346       if (LocaleCompare("swirl",option+1) == 0)
3347         {
3348           flags=ParseGeometry(arg1,&geometry_info);
3349           if ((flags & RhoValue) == 0)
3350             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3351           new_image=SwirlImage(_image,geometry_info.rho,
3352             _image->interpolate,_exception);
3353           break;
3354         }
3355       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3356     }
3357     case 't':
3358     {
3359       if (LocaleCompare("threshold",option+1) == 0)
3360         {
3361           double
3362             threshold;
3363
3364           threshold=(double) QuantumRange/2;
3365           if (IfNormalOp) {
3366             if (IfMagickFalse(IsGeometry(arg1)))
3367               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3368             threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3369           }
3370           (void) BilevelImage(_image,threshold,_exception);
3371           break;
3372         }
3373       if (LocaleCompare("thumbnail",option+1) == 0)
3374         {
3375           if (IfMagickFalse(IsGeometry(arg1)))
3376             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3377           (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3378           new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3379             _exception);
3380           break;
3381         }
3382       if (LocaleCompare("tint",option+1) == 0)
3383         {
3384           if (IfMagickFalse(IsGeometry(arg1)))
3385             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3386           new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3387           break;
3388         }
3389       if (LocaleCompare("transform",option+1) == 0)
3390         {
3391           CLIWandWarnReplaced("+distort AffineProjection");
3392           new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3393           break;
3394         }
3395       if (LocaleCompare("transparent",option+1) == 0)
3396         {
3397           PixelInfo
3398             target;
3399
3400           (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3401           (void) TransparentPaintImage(_image,&target,(Quantum)
3402             TransparentAlpha,IsPlusOp,_exception);
3403           break;
3404         }
3405       if (LocaleCompare("transpose",option+1) == 0)
3406         {
3407           new_image=TransposeImage(_image,_exception);
3408           break;
3409         }
3410       if (LocaleCompare("transverse",option+1) == 0)
3411         {
3412           new_image=TransverseImage(_image,_exception);
3413           break;
3414         }
3415       if (LocaleCompare("trim",option+1) == 0)
3416         {
3417           new_image=TrimImage(_image,_exception);
3418           break;
3419         }
3420       if (LocaleCompare("type",option+1) == 0)
3421         {
3422           /* Note that "type" setting should have already been defined */
3423           (void) SetImageType(_image,_image_info->type,_exception);
3424           break;
3425         }
3426       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3427     }
3428     case 'u':
3429     {
3430       if (LocaleCompare("unique",option+1) == 0)
3431         {
3432           /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3433              Option is not documented, bt appears to be for "identify".
3434              We may need a identify specific verbose!
3435           */
3436           if (IsPlusOp) {
3437               (void) DeleteImageArtifact(_image,"identify:unique-colors");
3438               break;
3439             }
3440           (void) SetImageArtifact(_image,"identify:unique-colors","true");
3441           (void) SetImageArtifact(_image,"verbose","true");
3442           break;
3443         }
3444       if (LocaleCompare("unique-colors",option+1) == 0)
3445         {
3446           new_image=UniqueImageColors(_image,_exception);
3447           break;
3448         }
3449       if (LocaleCompare("unsharp",option+1) == 0)
3450         {
3451           flags=ParseGeometry(arg1,&geometry_info);
3452           if ((flags & (RhoValue|SigmaValue)) == 0)
3453             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3454           if ((flags & SigmaValue) == 0)
3455             geometry_info.sigma=1.0;
3456           if ((flags & XiValue) == 0)
3457             geometry_info.xi=1.0;
3458           if ((flags & PsiValue) == 0)
3459             geometry_info.psi=0.05;
3460           new_image=UnsharpMaskImage(_image,geometry_info.rho,
3461             geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3462           break;
3463         }
3464       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3465     }
3466     case 'v':
3467     {
3468       if (LocaleCompare("verbose",option+1) == 0)
3469         {
3470           /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3471              three places!   ImageArtifact   ImageOption  _image_info->verbose
3472              Some how new images also get this artifact!
3473           */
3474           (void) SetImageArtifact(_image,option+1,
3475                            IfNormalOp ? "true" : "false" );
3476           break;
3477         }
3478       if (LocaleCompare("vignette",option+1) == 0)
3479         {
3480           flags=ParseGeometry(arg1,&geometry_info);
3481           if ((flags & (RhoValue|SigmaValue)) == 0)
3482             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3483           if ((flags & SigmaValue) == 0)
3484             geometry_info.sigma=1.0;
3485           if ((flags & XiValue) == 0)
3486             geometry_info.xi=0.1*_image->columns;
3487           if ((flags & PsiValue) == 0)
3488             geometry_info.psi=0.1*_image->rows;
3489           if ((flags & PercentValue) != 0)
3490             {
3491               geometry_info.xi*=(double) _image->columns/100.0;
3492               geometry_info.psi*=(double) _image->rows/100.0;
3493             }
3494           new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3495             (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3496             ceil(geometry_info.psi-0.5),_exception);
3497           break;
3498         }
3499       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3500     }
3501     case 'w':
3502     {
3503       if (LocaleCompare("wave",option+1) == 0)
3504         {
3505           flags=ParseGeometry(arg1,&geometry_info);
3506           if ((flags & (RhoValue|SigmaValue)) == 0)
3507             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3508           if ((flags & SigmaValue) == 0)
3509             geometry_info.sigma=1.0;
3510           new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3511                _image->interpolate,_exception);
3512           break;
3513         }
3514       if (LocaleCompare("white-threshold",option+1) == 0)
3515         {
3516           if (IfMagickFalse(IsGeometry(arg1)))
3517             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3518           (void) WhiteThresholdImage(_image,arg1,_exception);
3519           break;
3520         }
3521       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3522     }
3523     default:
3524       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3525   }
3526   /* clean up percent escape interpreted strings */
3527   if (arg1 != arg1n )
3528     arg1=DestroyString((char *)arg1);
3529   if (arg2 != arg2n )
3530     arg2=DestroyString((char *)arg2);
3531
3532   /* Replace current image with any image that was generated
3533      and set image point to last image (so image->next is correct) */
3534   if (new_image != (Image *) NULL)
3535     ReplaceImageInListReturnLast(&_image,new_image);
3536
3537   return(MagickTrue);
3538 #undef _image_info
3539 #undef _draw_info
3540 #undef _quantize_info
3541 #undef _image
3542 #undef _exception
3543 #undef IfNormalOp
3544 #undef IfPlusOp
3545 #undef IsNormalOp
3546 #undef IsPlusOp
3547 }
3548
3549 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3550   const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3551 {
3552 #if !USE_WAND_METHODS
3553   size_t
3554     n,
3555     i;
3556 #endif
3557
3558   assert(cli_wand != (MagickCLI *) NULL);
3559   assert(cli_wand->signature == MagickWandSignature);
3560   assert(cli_wand->wand.signature == MagickWandSignature);
3561   assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3562
3563   if (IfMagickTrue(cli_wand->wand.debug))
3564     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3565          "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3566
3567 #if !USE_WAND_METHODS
3568   /* FUTURE add appropriate tracing */
3569   i=0;
3570   n=GetImageListLength(cli_wand->wand.images);
3571   cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3572   while (1) {
3573     i++;
3574     CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3575     if ( cli_wand->wand.images->next == (Image *) NULL )
3576       break;
3577     cli_wand->wand.images=cli_wand->wand.images->next;
3578   }
3579   assert( i == n );
3580   cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3581 #else
3582   MagickResetIterator(&cli_wand->wand);
3583   while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3584     (void) CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3585   MagickResetIterator(&cli_wand->wand);
3586 #endif
3587   return(MagickTrue);
3588 }
3589 \f
3590 /*
3591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3592 %                                                                             %
3593 %                                                                             %
3594 %                                                                             %
3595 +     C L I L i s t O p e r a t o r I m a g e s                               %
3596 %                                                                             %
3597 %                                                                             %
3598 %                                                                             %
3599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3600 %
3601 %  CLIListOperatorImages() applies a single operation that is apply to the
3602 %  entire image list as a whole. The result is often a complete replacment
3603 %  of the image list with a completely new list, or with just a single image
3604 %  result.
3605 %
3606 %  The format of the MogrifyImage method is:
3607 %
3608 %    MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3609 %      const char *option,const char *arg1,const char *arg2)
3610 %
3611 %  A description of each parameter follows:
3612 %
3613 %    o cli_wand: structure holding settings to be applied
3614 %
3615 %    o option:  The option string for the operation
3616 %
3617 %    o arg1, arg2: optional argument strings to the operation
3618 %        arg2 is currently not used
3619 %
3620 */
3621 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3622   const char *option,const char *arg1n,const char *arg2n)
3623 {
3624   const char    /* percent escaped versions of the args */
3625     *arg1,
3626     *arg2;
3627
3628   Image
3629     *new_images;
3630
3631   MagickStatusType
3632     status;
3633
3634   ssize_t
3635     parse;
3636
3637 #define _image_info     (cli_wand->wand.image_info)
3638 #define _images         (cli_wand->wand.images)
3639 #define _exception      (cli_wand->wand.exception)
3640 #define _draw_info      (cli_wand->draw_info)
3641 #define _quantize_info  (cli_wand->quantize_info)
3642 #define _process_flags  (cli_wand->process_flags)
3643 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
3644 #define IfNormalOp      (*option=='-')
3645 #define IfPlusOp        (*option!='-')
3646 #define IsNormalOp       IsMagickTrue(IfNormalOp)
3647
3648   assert(cli_wand != (MagickCLI *) NULL);
3649   assert(cli_wand->signature == MagickWandSignature);
3650   assert(cli_wand->wand.signature == MagickWandSignature);
3651   assert(_images != (Image *) NULL);             /* _images must be present */
3652
3653   if (IfMagickTrue(cli_wand->wand.debug))
3654     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3655          "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
3656
3657   arg1 = arg1n;
3658   arg2 = arg2n;
3659
3660   /* Interpret Percent Escapes in Arguments - using first image */
3661   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3662         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3663        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3664     /* Interpret Percent escapes in argument 1 */
3665     if (arg1n != (char *) NULL) {
3666       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3667       if (arg1 == (char *) NULL) {
3668         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3669         arg1=arg1n;  /* use the given argument as is */
3670       }
3671     }
3672     if (arg2n != (char *) NULL) {
3673       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3674       if (arg2 == (char *) NULL) {
3675         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3676         arg2=arg2n;  /* use the given argument as is */
3677       }
3678     }
3679   }
3680 #undef _process_flags
3681 #undef _option_type
3682
3683   status=MagickTrue;
3684   new_images=NewImageList();
3685
3686   switch (*(option+1))
3687   {
3688     case 'a':
3689     {
3690       if (LocaleCompare("append",option+1) == 0)
3691         {
3692           new_images=AppendImages(_images,IsNormalOp,_exception);
3693           break;
3694         }
3695       if (LocaleCompare("average",option+1) == 0)
3696         {
3697           CLIWandWarnReplaced("-evaluate-sequence Mean");
3698           (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3699           break;
3700         }
3701       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3702     }
3703     case 'c':
3704     {
3705       if (LocaleCompare("channel-fx",option+1) == 0)
3706         {
3707           new_images=ChannelFxImage(_images,arg1,_exception);
3708           break;
3709         }
3710       if (LocaleCompare("clut",option+1) == 0)
3711         {
3712           Image
3713             *clut_image;
3714
3715           /* FUTURE - make this a compose option, and thus can be used
3716              with layers compose or even compose last image over all other
3717              _images.
3718           */
3719           new_images=RemoveFirstImageFromList(&_images);
3720           clut_image=RemoveLastImageFromList(&_images);
3721           /* FUTURE - produce Exception, rather than silent fail */
3722           if (clut_image == (Image *) NULL)
3723             break;
3724           (void) ClutImage(new_images,clut_image,new_images->interpolate,
3725             _exception);
3726           clut_image=DestroyImage(clut_image);
3727           break;
3728         }
3729       if (LocaleCompare("coalesce",option+1) == 0)
3730         {
3731           new_images=CoalesceImages(_images,_exception);
3732           break;
3733         }
3734       if (LocaleCompare("combine",option+1) == 0)
3735         {
3736           parse=(ssize_t) _images->colorspace;
3737           if ( IfPlusOp )
3738             parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3739           if (parse < 0)
3740             CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3741               arg1);
3742           new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3743           break;
3744         }
3745       if (LocaleCompare("compare",option+1) == 0)
3746         {
3747           double
3748             distortion;
3749
3750           Image
3751             *image,
3752             *reconstruct_image;
3753
3754           MetricType
3755             metric;
3756
3757           /*
3758             Mathematically and visually annotate the difference between an
3759             image and its reconstruction.
3760           */
3761           image=RemoveFirstImageFromList(&_images);
3762           reconstruct_image=RemoveFirstImageFromList(&_images);
3763           /* FUTURE - produce Exception, rather than silent fail */
3764           if (reconstruct_image == (Image *) NULL)
3765             break;
3766           metric=UndefinedErrorMetric;
3767           option=GetImageOption(_image_info,"metric");
3768           if (option != (const char *) NULL)
3769             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3770               MagickFalse,option);
3771           new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3772             _exception);
3773           (void) distortion;
3774           reconstruct_image=DestroyImage(reconstruct_image);
3775           image=DestroyImage(image);
3776           break;
3777         }
3778       if (LocaleCompare("complex",option+1) == 0)
3779         {
3780           parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3781           if (parse < 0)
3782             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3783               option,arg1);
3784           new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3785           break;
3786         }
3787       if (LocaleCompare("composite",option+1) == 0)
3788         {
3789           CompositeOperator
3790             compose;
3791
3792           const char*
3793             value;
3794
3795           MagickBooleanType
3796             clip_to_self;
3797
3798           Image
3799             *mask_image,
3800             *source_image;
3801
3802           RectangleInfo
3803             geometry;
3804
3805           /* Compose value from "-compose" option only */
3806           value=GetImageOption(_image_info,"compose");
3807           if (value == (const char *) NULL)
3808             compose=OverCompositeOp;  /* use Over not source_image->compose */
3809           else
3810             compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3811               MagickFalse,value);
3812
3813           /* Get "clip-to-self" expert setting (false is normal) */
3814           value=GetImageOption(_image_info,"compose:clip-to-self");
3815           if (value == (const char *) NULL)
3816             clip_to_self=MagickTrue;
3817           else
3818             clip_to_self=IsStringTrue(GetImageOption(_image_info,
3819               "compose:clip-to-self")); /* if this is true */
3820           value=GetImageOption(_image_info,"compose:outside-overlay");
3821           if (value != (const char *) NULL) {   /* or this false */
3822             /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3823             clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3824           }
3825
3826           new_images=RemoveFirstImageFromList(&_images);
3827           source_image=RemoveFirstImageFromList(&_images);
3828           if (source_image == (Image *) NULL)
3829             break; /* FUTURE - produce Exception, rather than silent fail */
3830
3831           /* FUTURE - this should not be here! - should be part of -geometry */
3832           (void) TransformImage(&source_image,(char *) NULL,
3833             source_image->geometry,_exception);
3834           SetGeometry(source_image,&geometry);
3835           (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3836           GravityAdjustGeometry(new_images->columns,new_images->rows,
3837             new_images->gravity, &geometry);
3838           mask_image=RemoveFirstImageFromList(&_images);
3839           if (mask_image == (Image *) NULL)
3840             status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3841               geometry.x,geometry.y,_exception);
3842           else
3843             {
3844               if ((compose == DisplaceCompositeOp) ||
3845                   (compose == DistortCompositeOp))
3846                 {
3847                   status&=CompositeImage(source_image,mask_image,
3848                     CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3849                   status&=CompositeImage(new_images,source_image,compose,
3850                     clip_to_self,geometry.x,geometry.y,_exception);
3851                 }
3852               else
3853                 {
3854                   Image
3855                     *clone_image;
3856
3857                   clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
3858                   if (clone_image == (Image *) NULL)
3859                     break;
3860                   status&=CompositeImage(new_images,source_image,compose,
3861                     clip_to_self,geometry.x,geometry.y,_exception);
3862                   status&=CompositeImage(new_images,mask_image,
3863                     CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
3864                   status&=CompositeImage(clone_image,new_images,OverCompositeOp,
3865                     clip_to_self,geometry.x,geometry.y,_exception);
3866                   new_images=DestroyImage(new_images);
3867                   new_images=clone_image;
3868                 }
3869               mask_image=DestroyImage(mask_image);
3870             }
3871           source_image=DestroyImage(source_image);
3872           break;
3873         }
3874         if (LocaleCompare("copy",option+1) == 0)
3875           {
3876             Image
3877               *source_image;
3878
3879             OffsetInfo
3880               offset;
3881
3882             RectangleInfo
3883               geometry;
3884
3885             /*
3886               Copy image pixels.
3887             */
3888             if (IfMagickFalse(IsGeometry(arg1)))
3889               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3890             if (IfMagickFalse(IsGeometry(arg2)))
3891               CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3892             (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
3893             offset.x=geometry.x;
3894             offset.y=geometry.y;
3895             source_image=_images;
3896             if (source_image->next != (Image *) NULL)
3897               source_image=source_image->next;
3898             (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
3899             (void) CopyImagePixels(_images,source_image,&geometry,&offset,
3900               _exception);
3901             break;
3902           }
3903       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3904     }
3905     case 'd':
3906     {
3907       if (LocaleCompare("deconstruct",option+1) == 0)
3908         {
3909           CLIWandWarnReplaced("-layer CompareAny");
3910           (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3911           break;
3912         }
3913       if (LocaleCompare("delete",option+1) == 0)
3914         {
3915           if (IfNormalOp)
3916             DeleteImages(&_images,arg1,_exception);
3917           else
3918             DeleteImages(&_images,"-1",_exception);
3919           break;
3920         }
3921       if (LocaleCompare("duplicate",option+1) == 0)
3922         {
3923           if (IfNormalOp)
3924             {
3925               const char
3926                 *p;
3927
3928               size_t
3929                 number_duplicates;
3930
3931               if (IfMagickFalse(IsGeometry(arg1)))
3932                 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3933                       arg1);
3934               number_duplicates=(size_t) StringToLong(arg1);
3935               p=strchr(arg1,',');
3936               if (p == (const char *) NULL)
3937                 new_images=DuplicateImages(_images,number_duplicates,"-1",
3938                   _exception);
3939               else
3940                 new_images=DuplicateImages(_images,number_duplicates,p,
3941                   _exception);
3942             }
3943           else
3944             new_images=DuplicateImages(_images,1,"-1",_exception);
3945           AppendImageToList(&_images, new_images);
3946           new_images=(Image *) NULL;
3947           break;
3948         }
3949       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3950     }
3951     case 'e':
3952     {
3953       if (LocaleCompare("evaluate-sequence",option+1) == 0)
3954         {
3955           parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3956           if (parse < 0)
3957             CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3958               option,arg1);
3959           new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3960             _exception);
3961           break;
3962         }
3963       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3964     }
3965     case 'f':
3966     {
3967       if (LocaleCompare("fft",option+1) == 0)
3968         {
3969           new_images=ForwardFourierTransformImage(_images,IsNormalOp,
3970            _exception);
3971           break;
3972         }
3973       if (LocaleCompare("flatten",option+1) == 0)
3974         {
3975           /* REDIRECTED to use -layers flatten instead */
3976           (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3977           break;
3978         }
3979       if (LocaleCompare("fx",option+1) == 0)
3980         {
3981           new_images=FxImage(_images,arg1,_exception);
3982           break;
3983         }
3984       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3985     }
3986     case 'h':
3987     {
3988       if (LocaleCompare("hald-clut",option+1) == 0)
3989         {
3990           /* FUTURE - make this a compose option (and thus layers compose )
3991              or perhaps compose last image over all other _images.
3992           */
3993           Image
3994             *hald_image;
3995
3996           new_images=RemoveFirstImageFromList(&_images);
3997           hald_image=RemoveLastImageFromList(&_images);
3998           if (hald_image == (Image *) NULL)
3999             break;
4000           (void) HaldClutImage(new_images,hald_image,_exception);
4001           hald_image=DestroyImage(hald_image);
4002           break;
4003         }
4004       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4005     }
4006     case 'i':
4007     {
4008       if (LocaleCompare("ift",option+1) == 0)
4009         {
4010           Image
4011             *magnitude_image,
4012             *phase_image;
4013
4014            magnitude_image=RemoveFirstImageFromList(&_images);
4015            phase_image=RemoveFirstImageFromList(&_images);
4016           /* FUTURE - produce Exception, rather than silent fail */
4017            if (phase_image == (Image *) NULL)
4018              break;
4019            new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4020              IsNormalOp,_exception);
4021            magnitude_image=DestroyImage(magnitude_image);
4022            phase_image=DestroyImage(phase_image);
4023           break;
4024         }
4025       if (LocaleCompare("insert",option+1) == 0)
4026         {
4027           Image
4028             *insert_image,
4029             *index_image;
4030
4031           ssize_t
4032             index;
4033
4034           if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
4035             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4036           index=0;
4037           insert_image=RemoveLastImageFromList(&_images);
4038           if (IfNormalOp)
4039             index=(ssize_t) StringToLong(arg1);
4040           index_image=insert_image;
4041           if (index == 0)
4042             PrependImageToList(&_images,insert_image);
4043           else if (index == (ssize_t) GetImageListLength(_images))
4044             AppendImageToList(&_images,insert_image);
4045           else
4046             {
4047                index_image=GetImageFromList(_images,index-1);
4048                if (index_image == (Image *) NULL)
4049                  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4050               InsertImageInList(&index_image,insert_image);
4051             }
4052           _images=GetFirstImageInList(index_image);
4053           break;
4054         }
4055       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4056     }
4057     case 'l':
4058     {
4059       if (LocaleCompare("layers",option+1) == 0)
4060         {
4061           parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4062           if ( parse < 0 )
4063             CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4064                  option,arg1);
4065           switch ((LayerMethod) parse)
4066           {
4067             case CoalesceLayer:
4068             {
4069               new_images=CoalesceImages(_images,_exception);
4070               break;
4071             }
4072             case CompareAnyLayer:
4073             case CompareClearLayer:
4074             case CompareOverlayLayer:
4075             default:
4076             {
4077               new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4078                    _exception);
4079               break;
4080             }
4081             case MergeLayer:
4082             case FlattenLayer:
4083             case MosaicLayer:
4084             case TrimBoundsLayer:
4085             {
4086               new_images=MergeImageLayers(_images,(LayerMethod) parse,
4087                 _exception);
4088               break;
4089             }
4090             case DisposeLayer:
4091             {
4092               new_images=DisposeImages(_images,_exception);
4093               break;
4094             }
4095             case OptimizeImageLayer:
4096             {
4097               new_images=OptimizeImageLayers(_images,_exception);
4098               break;
4099             }
4100             case OptimizePlusLayer:
4101             {
4102               new_images=OptimizePlusImageLayers(_images,_exception);
4103               break;
4104             }
4105             case OptimizeTransLayer:
4106             {
4107               OptimizeImageTransparency(_images,_exception);
4108               break;
4109             }
4110             case RemoveDupsLayer:
4111             {
4112               RemoveDuplicateLayers(&_images,_exception);
4113               break;
4114             }
4115             case RemoveZeroLayer:
4116             {
4117               RemoveZeroDelayLayers(&_images,_exception);
4118               break;
4119             }
4120             case OptimizeLayer:
4121             { /* General Purpose, GIF Animation Optimizer.  */
4122               new_images=CoalesceImages(_images,_exception);
4123               if (new_images == (Image *) NULL)
4124                 break;
4125               _images=DestroyImageList(_images);
4126               _images=OptimizeImageLayers(new_images,_exception);
4127               if (_images == (Image *) NULL)
4128                 break;
4129               new_images=DestroyImageList(new_images);
4130               OptimizeImageTransparency(_images,_exception);
4131               (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4132                 _exception);
4133               break;
4134             }
4135             case CompositeLayer:
4136             {
4137               Image
4138                 *source;
4139
4140               RectangleInfo
4141                 geometry;
4142
4143               CompositeOperator
4144                 compose;
4145
4146               const char*
4147                 value;
4148
4149               value=GetImageOption(_image_info,"compose");
4150               compose=OverCompositeOp;  /* Default to Over */
4151               if (value != (const char *) NULL)
4152                 compose=(CompositeOperator) ParseCommandOption(
4153                       MagickComposeOptions,MagickFalse,value);
4154
4155               /* Split image sequence at the first 'NULL:' image. */
4156               source=_images;
4157               while (source != (Image *) NULL)
4158               {
4159                 source=GetNextImageInList(source);
4160                 if ((source != (Image *) NULL) &&
4161                     (LocaleCompare(source->magick,"NULL") == 0))
4162                   break;
4163               }
4164               if (source != (Image *) NULL)
4165                 {
4166                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4167                       (GetNextImageInList(source) == (Image *) NULL))
4168                     source=(Image *) NULL;
4169                   else
4170                     { /* Separate the two lists, junk the null: image.  */
4171                       source=SplitImageList(source->previous);
4172                       DeleteImageFromList(&source);
4173                     }
4174                 }
4175               if (source == (Image *) NULL)
4176                 {
4177                   (void) ThrowMagickException(_exception,GetMagickModule(),
4178                     OptionError,"MissingNullSeparator","layers Composite");
4179                   break;
4180                 }
4181               /* Adjust offset with gravity and virtual canvas.  */
4182               SetGeometry(_images,&geometry);
4183               (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4184               geometry.width=source->page.width != 0 ?
4185                 source->page.width : source->columns;
4186               geometry.height=source->page.height != 0 ?
4187                source->page.height : source->rows;
4188               GravityAdjustGeometry(_images->page.width != 0 ?
4189                 _images->page.width : _images->columns,
4190                 _images->page.height != 0 ? _images->page.height :
4191                 _images->rows,_images->gravity,&geometry);
4192
4193               /* Compose the two image sequences together */
4194               CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4195                 _exception);
4196               source=DestroyImageList(source);
4197               break;
4198             }
4199           }
4200           break;
4201         }
4202       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4203     }
4204     case 'm':
4205     {
4206       if (LocaleCompare("map",option+1) == 0)
4207         {
4208           CLIWandWarnReplaced("+remap");
4209           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4210           break;
4211         }
4212       if (LocaleCompare("metric",option+1) == 0)
4213         break;
4214       if (LocaleCompare("morph",option+1) == 0)
4215         {
4216           Image
4217             *morph_image;
4218
4219           if (IfMagickFalse(IsGeometry(arg1)))
4220             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4221           morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4222             _exception);
4223           if (morph_image == (Image *) NULL)
4224             break;
4225           _images=DestroyImageList(_images);
4226           _images=morph_image;
4227           break;
4228         }
4229       if (LocaleCompare("mosaic",option+1) == 0)
4230         {
4231           /* REDIRECTED to use -layers mosaic instead */
4232           (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4233           break;
4234         }
4235       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4236     }
4237     case 'p':
4238     {
4239       if (LocaleCompare("poly",option+1) == 0)
4240         {
4241           double
4242             *args;
4243
4244           ssize_t
4245             count;
4246
4247           /* convert argument string into an array of doubles */
4248           args = StringToArrayOfDoubles(arg1,&count,_exception);
4249           if (args == (double *) NULL )
4250             CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4251           new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4252            _exception);
4253           args=(double *) RelinquishMagickMemory(args);
4254           break;
4255         }
4256       if (LocaleCompare("process",option+1) == 0)
4257         {
4258           /* FUTURE: better parsing using ScriptToken() from string ??? */
4259           char
4260             **arguments;
4261
4262           int
4263             j,
4264             number_arguments;
4265
4266           arguments=StringToArgv(arg1,&number_arguments);
4267           if (arguments == (char **) NULL)
4268             break;
4269           if (strchr(arguments[1],'=') != (char *) NULL)
4270             {
4271               char
4272                 breaker,
4273                 quote,
4274                 *token;
4275
4276               const char
4277                 *arguments;
4278
4279               int
4280                 next,
4281                 status;
4282
4283               size_t
4284                 length;
4285
4286               TokenInfo
4287                 *token_info;
4288
4289               /*
4290                 Support old style syntax, filter="-option arg1".
4291               */
4292               assert(arg1 != (const char *) NULL);
4293               length=strlen(arg1);
4294               token=(char *) NULL;
4295               if (~length >= (MagickPathExtent-1))
4296                 token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4297                   sizeof(*token));
4298               if (token == (char *) NULL)
4299                 break;
4300               next=0;
4301               arguments=arg1;
4302               token_info=AcquireTokenInfo();
4303               status=Tokenizer(token_info,0,token,length,arguments,"","=",
4304                 "\"",'\0',&breaker,&next,&quote);
4305               token_info=DestroyTokenInfo(token_info);
4306               if (status == 0)
4307                 {
4308                   const char
4309                     *argv;
4310
4311                   argv=(&(arguments[next]));
4312                   (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4313                     _exception);
4314                 }
4315               token=DestroyString(token);
4316               break;
4317             }
4318           (void) SubstituteString(&arguments[1],"-","");
4319           (void) InvokeDynamicImageFilter(arguments[1],&_images,
4320             number_arguments-2,(const char **) arguments+2,_exception);
4321           for (j=0; j < number_arguments; j++)
4322             arguments[j]=DestroyString(arguments[j]);
4323           arguments=(char **) RelinquishMagickMemory(arguments);
4324           break;
4325         }
4326       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4327     }
4328     case 'r':
4329     {
4330       if (LocaleCompare("remap",option+1) == 0)
4331         {
4332           (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4333           break;
4334         }
4335       if (LocaleCompare("reverse",option+1) == 0)
4336         {
4337           ReverseImageList(&_images);
4338           break;
4339         }
4340       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4341     }
4342     case 's':
4343     {
4344       if (LocaleCompare("smush",option+1) == 0)
4345         {
4346           /* FUTURE: this option needs more work to make better */
4347           ssize_t
4348             offset;
4349
4350           if (IfMagickFalse(IsGeometry(arg1)))
4351             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4352           offset=(ssize_t) StringToLong(arg1);
4353           new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4354           break;
4355         }
4356       if (LocaleCompare("subimage",option+1) == 0)
4357         {
4358           Image
4359             *base_image,
4360             *compare_image;
4361
4362           const char
4363             *value;
4364
4365           MetricType
4366             metric;
4367
4368           double
4369             similarity;
4370
4371           RectangleInfo
4372             offset;
4373
4374           base_image=GetImageFromList(_images,0);
4375           compare_image=GetImageFromList(_images,1);
4376
4377           /* Comparision Metric */
4378           metric=UndefinedErrorMetric;
4379           value=GetImageOption(_image_info,"metric");
4380           if (value != (const char *) NULL)
4381             metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4382               MagickFalse,value);
4383
4384           new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4385             &offset,&similarity,_exception);
4386
4387           if (new_images != (Image *) NULL)
4388             {
4389               char
4390                 result[MagickPathExtent];
4391
4392               (void) FormatLocaleString(result,MagickPathExtent,"%lf",
4393                 similarity);
4394               (void) SetImageProperty(new_images,"subimage:similarity",result,
4395                 _exception);
4396               (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4397                 offset.x);
4398               (void) SetImageProperty(new_images,"subimage:x",result,
4399                 _exception);
4400               (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4401                 offset.y);
4402               (void) SetImageProperty(new_images,"subimage:y",result,
4403                 _exception);
4404               (void) FormatLocaleString(result,MagickPathExtent,
4405                 "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4406                 offset.height,(long) offset.x,(long) offset.y);
4407               (void) SetImageProperty(new_images,"subimage:offset",result,
4408                 _exception);
4409             }
4410           break;
4411         }
4412       if (LocaleCompare("swap",option+1) == 0)
4413         {
4414         Image
4415           *p,
4416           *q,
4417           *swap;
4418
4419         ssize_t
4420           index,
4421           swap_index;
4422
4423         index=(-1);
4424         swap_index=(-2);
4425         if (IfNormalOp) {
4426           GeometryInfo
4427             geometry_info;
4428
4429           MagickStatusType
4430             flags;
4431
4432           swap_index=(-1);
4433           flags=ParseGeometry(arg1,&geometry_info);
4434           if ((flags & RhoValue) == 0)
4435             CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4436           index=(ssize_t) geometry_info.rho;
4437           if ((flags & SigmaValue) != 0)
4438             swap_index=(ssize_t) geometry_info.sigma;
4439         }
4440         p=GetImageFromList(_images,index);
4441         q=GetImageFromList(_images,swap_index);
4442         if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4443           if (IfNormalOp)
4444             CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4445           else
4446             CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4447         }
4448         if (p == q)
4449           CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4450         swap=CloneImage(p,0,0,MagickTrue,_exception);
4451         ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4452         ReplaceImageInList(&q,swap);
4453         _images=GetFirstImageInList(q);
4454         break;
4455       }
4456       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4457     }
4458     default:
4459       CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4460   }
4461
4462   /* clean up percent escape interpreted strings */
4463   if (arg1 != arg1n )
4464     arg1=DestroyString((char *)arg1);
4465   if (arg2 != arg2n )
4466     arg2=DestroyString((char *)arg2);
4467
4468   /* if new image list generated, replace existing image list */
4469   if (new_images == (Image *) NULL)
4470     return(status == 0 ? MagickFalse : MagickTrue);
4471   _images=DestroyImageList(_images);
4472   _images=GetFirstImageInList(new_images);
4473   return(status == 0 ? MagickFalse : MagickTrue);
4474
4475 #undef _image_info
4476 #undef _images
4477 #undef _exception
4478 #undef _draw_info
4479 #undef _quantize_info
4480 #undef IfNormalOp
4481 #undef IfPlusOp
4482 #undef IsNormalOp
4483 }
4484 \f
4485 /*
4486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487 %                                                                             %
4488 %                                                                             %
4489 %                                                                             %
4490 +   C L I N o I m a g e O p e r a t i o n s                                   %
4491 %                                                                             %
4492 %                                                                             %
4493 %                                                                             %
4494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4495 %
4496 %  CLINoImageOperator() Applies operations that may not actually need images
4497 %  in an image list.
4498 %
4499 %  The classic operators of this type is "-read", which actually creates
4500 %  images even when no images are present.  Or image stack operators, which
4501 %  can be applied (push or pop) to an empty image list.
4502 %
4503 %  Note that these operators may involve other special 'option' prefix
4504 %  characters other  than '-' or '+', namely parenthesis and braces.
4505 %
4506 %  The format of the CLINoImageOption method is:
4507 %
4508 %      void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4509 %           const char *arg1, const char *arg2)
4510 %
4511 %  A description of each parameter follows:
4512 %
4513 %    o cli_wand: the main CLI Wand to use. (sometimes not required)
4514 %
4515 %    o option: The special option (with any switch char) to process
4516 %
4517 %    o arg1 & arg2: Argument for option, if required
4518 %                   Currently arg2 is not used.
4519 %
4520 */
4521 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4522   const char *option,const char *arg1n,const char *arg2n)
4523 {
4524   const char    /* percent escaped versions of the args */
4525     *arg1,
4526     *arg2;
4527
4528 #define _image_info     (cli_wand->wand.image_info)
4529 #define _images         (cli_wand->wand.images)
4530 #define _exception      (cli_wand->wand.exception)
4531 #define _process_flags  (cli_wand->process_flags)
4532 #define _option_type    ((CommandOptionFlags) cli_wand->command->flags)
4533 #define IfNormalOp      (*option=='-')
4534 #define IfPlusOp        (*option!='-')
4535
4536   assert(cli_wand != (MagickCLI *) NULL);
4537   assert(cli_wand->signature == MagickWandSignature);
4538   assert(cli_wand->wand.signature == MagickWandSignature);
4539
4540   if (IfMagickTrue(cli_wand->wand.debug))
4541     (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4542       "- NoImage Operator: %s \"%s\" \"%s\"", option,
4543       arg1n != (char *) NULL ? arg1n : "",
4544       arg2n != (char *) NULL ? arg2n : "");
4545
4546   arg1 = arg1n;
4547   arg2 = arg2n;
4548
4549   /* Interpret Percent Escapes in Arguments - using first image */
4550   if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4551         || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4552        )  && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4553     /* Interpret Percent escapes in argument 1 */
4554     if (arg1n != (char *) NULL) {
4555       arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4556       if (arg1 == (char *) NULL) {
4557         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4558         arg1=arg1n;  /* use the given argument as is */
4559       }
4560     }
4561     if (arg2n != (char *) NULL) {
4562       arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4563       if (arg2 == (char *) NULL) {
4564         CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4565         arg2=arg2n;  /* use the given argument as is */
4566       }
4567     }
4568   }
4569 #undef _process_flags
4570 #undef _option_type
4571
4572   do {  /* break to exit code */
4573     /*
4574       No-op options  (ignore these)
4575     */
4576     if (LocaleCompare("noop",option+1) == 0)   /* zero argument */
4577       break;
4578     if (LocaleCompare("sans",option+1) == 0)   /* one argument */
4579       break;
4580     if (LocaleCompare("sans0",option+1) == 0)  /* zero argument */
4581       break;
4582     if (LocaleCompare("sans1",option+1) == 0)  /* one argument */
4583       break;
4584     if (LocaleCompare("sans2",option+1) == 0)  /* two arguments */
4585       break;
4586     /*
4587       Image Reading
4588     */
4589     if ( ( LocaleCompare("read",option+1) == 0 ) ||
4590       ( LocaleCompare("--",option) == 0 ) ) {
4591       /* Do Glob filename Expansion for 'arg1' then read all images.
4592       *
4593       * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4594       * (but attaching to the filenames in the generated argument list) any
4595       * [...] read modifiers that may be present.
4596       *
4597       * For example: It will expand '*.gif[20x20]' into a list such as
4598       * 'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
4599       *
4600       * NOTE: In IMv6 this was done globally across all images. This
4601       * meant you could include IM options in '@filename' lists, but you
4602       * could not include comments.   Doing it only for image read makes
4603       * it far more secure.
4604       *
4605       * Note: arguments do not have percent escapes expanded for security
4606       * reasons.
4607       */
4608       int      argc;
4609       char     **argv;
4610       ssize_t  i;
4611
4612       argc = 1;
4613       argv = (char **) &arg1;
4614
4615       /* Expand 'glob' expressions in the given filename.
4616         Expansion handles any 'coder:' prefix, or read modifiers attached
4617         to the filename, including them in the resulting expanded list.
4618       */
4619       if (IfMagickFalse(  ExpandFilenames(&argc,&argv)  ))
4620         CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4621             option,GetExceptionMessage(errno));
4622
4623       /* loop over expanded filename list, and read then all in */
4624       for (i=0; i < (ssize_t) argc; i++) {
4625         Image *
4626           new_images;
4627         if (IfMagickTrue(_image_info->ping))
4628           new_images=PingImages(_image_info,argv[i],_exception);
4629         else
4630           new_images=ReadImages(_image_info,argv[i],_exception);
4631         AppendImageToList(&_images, new_images);
4632       }
4633       argv=DestroyStringList(argv);  /* Destroy the Expanded Filename list */
4634       break;
4635     }
4636     /*
4637       Image Writing
4638       Note: Writing a empty image list is valid in specific cases
4639     */
4640     if (LocaleCompare("write",option+1) == 0) {
4641       /* Note: arguments do not have percent escapes expanded */
4642       char
4643         key[MagickPathExtent];
4644
4645       Image
4646         *write_images;
4647
4648       ImageInfo
4649         *write_info;
4650
4651       /* Need images, unless a "null:" output coder is used */
4652       if ( _images == (Image *) NULL ) {
4653         if ( LocaleCompare(arg1,"null:") == 0 )
4654           break;
4655         CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4656       }
4657
4658       (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4659       (void) DeleteImageRegistry(key);
4660       write_images=_images;
4661       if (IfPlusOp)
4662         write_images=CloneImageList(_images,_exception);
4663       write_info=CloneImageInfo(_image_info);
4664       (void) WriteImages(write_info,write_images,arg1,_exception);
4665       write_info=DestroyImageInfo(write_info);
4666       if (IfPlusOp)
4667         write_images=DestroyImageList(write_images);
4668       break;
4669     }
4670     /*
4671       Parenthesis and Brace operations
4672     */
4673     if (LocaleCompare("(",option) == 0) {
4674       /* stack 'push' images */
4675       Stack
4676         *node;
4677
4678       size_t
4679         size;
4680
4681       size=0;
4682       node=cli_wand->image_list_stack;
4683       for ( ; node != (Stack *) NULL; node=node->next)
4684         size++;
4685       if ( size >= MAX_STACK_DEPTH )
4686         CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4687       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4688       if (node == (Stack *) NULL)
4689         CLIWandExceptionBreak(ResourceLimitFatalError,
4690             "MemoryAllocationFailed",option);
4691       node->data = (void *)cli_wand->wand.images;
4692       node->next = cli_wand->image_list_stack;
4693       cli_wand->image_list_stack = node;
4694       cli_wand->wand.images = NewImageList();
4695
4696       /* handle respect-parenthesis */
4697       if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4698                     "respect-parenthesis"))))
4699         option="{"; /* fall-thru so as to push image settings too */
4700       else
4701         break;
4702       /* fall thru to operation */
4703     }
4704     if (LocaleCompare("{",option) == 0) {
4705       /* stack 'push' of image_info settings */
4706       Stack
4707         *node;
4708
4709       size_t
4710         size;
4711
4712       size=0;
4713       node=cli_wand->image_info_stack;
4714       for ( ; node != (Stack *) NULL; node=node->next)
4715         size++;
4716       if ( size >= MAX_STACK_DEPTH )
4717         CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4718       node=(Stack *) AcquireMagickMemory(sizeof(*node));
4719       if (node == (Stack *) NULL)
4720         CLIWandExceptionBreak(ResourceLimitFatalError,
4721             "MemoryAllocationFailed",option);
4722
4723       node->data = (void *)cli_wand->wand.image_info;
4724       node->next = cli_wand->image_info_stack;
4725
4726       cli_wand->image_info_stack = node;
4727       cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4728       if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4729         CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4730             option);
4731         cli_wand->wand.image_info = (ImageInfo *)node->data;
4732         node = (Stack *)RelinquishMagickMemory(node);
4733         break;
4734       }
4735
4736       break;
4737     }
4738     if (LocaleCompare(")",option) == 0) {
4739       /* pop images from stack */
4740       Stack
4741         *node;
4742
4743       node = (Stack *)cli_wand->image_list_stack;
4744       if ( node == (Stack *) NULL)
4745         CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4746       cli_wand->image_list_stack = node->next;
4747
4748       AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4749       cli_wand->wand.images= (Image *)node->data;
4750       node = (Stack *)RelinquishMagickMemory(node);
4751
4752       /* handle respect-parenthesis - of the previous 'pushed' settings */
4753       node = cli_wand->image_info_stack;
4754       if ( node != (Stack *) NULL)
4755         {
4756           if (IfMagickTrue(IsStringTrue(GetImageOption(
4757                 cli_wand->wand.image_info,"respect-parenthesis"))))
4758             option="}"; /* fall-thru so as to pop image settings too */
4759           else
4760             break;
4761         }
4762       else
4763         break;
4764       /* fall thru to next if */
4765     }
4766     if (LocaleCompare("}",option) == 0) {
4767       /* pop image_info settings from stack */
4768       Stack
4769         *node;
4770
4771       node = (Stack *)cli_wand->image_info_stack;
4772       if ( node == (Stack *) NULL)
4773         CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4774       cli_wand->image_info_stack = node->next;
4775
4776       (void) DestroyImageInfo(cli_wand->wand.image_info);
4777       cli_wand->wand.image_info = (ImageInfo *)node->data;
4778       node = (Stack *)RelinquishMagickMemory(node);
4779
4780       GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4781       cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4782       cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4783
4784       break;
4785     }
4786       if (LocaleCompare("print",option+1) == 0)
4787         {
4788           (void) FormatLocaleFile(stdout,"%s",arg1);
4789           break;
4790         }
4791     if (LocaleCompare("set",option+1) == 0)
4792       {
4793         /* Settings are applied to each image in memory in turn (if any).
4794            While a option: only need to be applied once globally.
4795
4796            NOTE: rguments have not been automatically percent expaneded
4797         */
4798
4799         /* escape the 'key' once only, using first image. */
4800         arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4801         if (arg1 == (char *) NULL)
4802           CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4803                 option);
4804
4805         if (LocaleNCompare(arg1,"registry:",9) == 0)
4806           {
4807             if (IfPlusOp)
4808               {
4809                 (void) DeleteImageRegistry(arg1+9);
4810                 arg1=DestroyString((char *)arg1);
4811                 break;
4812               }
4813             arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4814             if (arg2 == (char *) NULL) {
4815               arg1=DestroyString((char *)arg1);
4816               CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4817                     option);
4818             }
4819             (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4820             arg1=DestroyString((char *)arg1);
4821             arg2=DestroyString((char *)arg2);
4822             break;
4823           }
4824         if (LocaleNCompare(arg1,"option:",7) == 0)
4825           {
4826             /* delete equivelent artifact from all images (if any) */
4827             if (_images != (Image *) NULL)
4828               {
4829                 MagickResetIterator(&cli_wand->wand);
4830                 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4831                   (void) DeleteImageArtifact(_images,arg1+7);
4832                 MagickResetIterator(&cli_wand->wand);
4833               }
4834             /* now set/delete the global option as needed */
4835             /* FUTURE: make escapes in a global 'option:' delayed */
4836             arg2=(char *) NULL;
4837             if (IfNormalOp)
4838               {
4839                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4840                 if (arg2 == (char *) NULL)
4841                   CLIWandExceptionBreak(OptionWarning,
4842                        "InterpretPropertyFailure",option);
4843               }
4844             (void) SetImageOption(_image_info,arg1+7,arg2);
4845             arg1=DestroyString((char *)arg1);
4846             arg2=DestroyString((char *)arg2);
4847             break;
4848           }
4849         /* Set Artifacts/Properties/Attributes all images (required) */
4850         if ( _images == (Image *) NULL )
4851           CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4852
4853         MagickResetIterator(&cli_wand->wand);
4854         while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4855           {
4856             arg2=(char *) NULL;
4857             if (IfNormalOp)
4858               {
4859                 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4860                 if (arg2 == (char *) NULL)
4861                   CLIWandExceptionBreak(OptionWarning,
4862                        "InterpretPropertyFailure",option);
4863               }
4864             if (LocaleNCompare(arg1,"artifact:",9) == 0)
4865               (void) SetImageArtifact(_images,arg1+9,arg2);
4866             else if (LocaleNCompare(arg1,"property:",9) == 0)
4867               (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4868             else
4869               (void) SetImageProperty(_images,arg1,arg2,_exception);
4870             arg2=DestroyString((char *)arg2);
4871           }
4872         MagickResetIterator(&cli_wand->wand);
4873         arg1=DestroyString((char *)arg1);
4874         break;
4875      }
4876     if (LocaleCompare("clone",option+1) == 0) {
4877         Image
4878           *new_images;
4879
4880         if (*option == '+')
4881           arg1=AcquireString("-1");
4882         if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4883           CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4884         if ( cli_wand->image_list_stack == (Stack *) NULL)
4885           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4886         new_images = (Image *)cli_wand->image_list_stack->data;
4887         if (new_images == (Image *) NULL)
4888           CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4889         new_images=CloneImages(new_images,arg1,_exception);
4890         if (new_images == (Image *) NULL)
4891           CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4892         AppendImageToList(&_images,new_images);
4893         break;
4894       }
4895     /*
4896        Informational Operations.
4897
4898        Note that these do not require either a cli-wand or images!
4899        Though currently a cli-wand much be provided regardless.
4900     */
4901     if (LocaleCompare("version",option+1) == 0)
4902       {
4903         ListMagickVersion(stdout);
4904         break;
4905       }
4906     if (LocaleCompare("list",option+1) == 0) {
4907       /*
4908          FUTURE: This 'switch' should really be part of MagickCore
4909       */
4910       ssize_t
4911         list;
4912
4913       list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4914       if ( list < 0 ) {
4915         CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4916         break;
4917       }
4918       switch (list)
4919       {
4920         case MagickCoderOptions:
4921         {
4922           (void) ListCoderInfo((FILE *) NULL,_exception);
4923           break;
4924         }
4925         case MagickColorOptions:
4926         {
4927           (void) ListColorInfo((FILE *) NULL,_exception);
4928           break;
4929         }
4930         case MagickConfigureOptions:
4931         {
4932           (void) ListConfigureInfo((FILE *) NULL,_exception);
4933           break;
4934         }
4935         case MagickDelegateOptions:
4936         {
4937           (void) ListDelegateInfo((FILE *) NULL,_exception);
4938           break;
4939         }
4940         case MagickFontOptions:
4941         {
4942           (void) ListTypeInfo((FILE *) NULL,_exception);
4943           break;
4944         }
4945         case MagickFormatOptions:
4946           (void) ListMagickInfo((FILE *) NULL,_exception);
4947           break;
4948         case MagickLocaleOptions:
4949           (void) ListLocaleInfo((FILE *) NULL,_exception);
4950           break;
4951         case MagickLogOptions:
4952           (void) ListLogInfo((FILE *) NULL,_exception);
4953           break;
4954         case MagickMagicOptions:
4955           (void) ListMagicInfo((FILE *) NULL,_exception);
4956           break;
4957         case MagickMimeOptions:
4958           (void) ListMimeInfo((FILE *) NULL,_exception);
4959           break;
4960         case MagickModuleOptions:
4961           (void) ListModuleInfo((FILE *) NULL,_exception);
4962           break;
4963         case MagickPolicyOptions:
4964           (void) ListPolicyInfo((FILE *) NULL,_exception);
4965           break;
4966         case MagickResourceOptions:
4967           (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4968           break;
4969         case MagickThresholdOptions:
4970           (void) ListThresholdMaps((FILE *) NULL,_exception);
4971           break;
4972         default:
4973           (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4974             _exception);
4975           break;
4976       }
4977       break;
4978     }
4979
4980     CLIWandException(OptionError,"UnrecognizedOption",option);
4981
4982 DisableMSCWarning(4127)
4983   } while (0);  /* break to exit code. */
4984 RestoreMSCWarning
4985
4986   /* clean up percent escape interpreted strings */
4987   if (arg1 != arg1n )
4988     arg1=DestroyString((char *)arg1);
4989   if (arg2 != arg2n )
4990     arg2=DestroyString((char *)arg2);
4991
4992 #undef _image_info
4993 #undef _images
4994 #undef _exception
4995 #undef IfNormalOp
4996 #undef IfPlusOp
4997 }
4998 \f
4999 /*
5000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5001 %                                                                             %
5002 %                                                                             %
5003 %                                                                             %
5004 +   C L I O p t i o n                                                         %
5005 %                                                                             %
5006 %                                                                             %
5007 %                                                                             %
5008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009 %
5010 %  CLIOption() Processes the given option using the given CLI Magick Wand.
5011 %  The option arguments can be variable in number, though at this time no more
5012 %  that two is actually used by any option (this may change). Excess options
5013 %  are simply ignored.
5014 %
5015 %  If the cli_wand->command pointer is non-null, then it is assumed that the
5016 %  option has already been search for up from the CommandOptions[] table in
5017 %  "MagickCore/options.c" using  GetCommandOptionInfo().  If not set this
5018 %  routine will do the lookup instead. The pointer is reset afterward.
5019 %
5020 %  This action allows the caller to lookup and pre-handle any 'special'
5021 %  options, (such as implicit reads) before calling this general option
5022 %  handler to deal with 'standard' command line options.
5023 %
5024 %  The format of the CLIOption method is:
5025 %
5026 %       void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5027 %
5028 %  A description of each parameter follows:
5029 %
5030 %     o cli_wand: the main CLI Wand to use.
5031 %
5032 %     o option: The special option (with any switch char) to process
5033 %
5034 %     o args: any required arguments for an option (variable number)
5035 %
5036 %  Example Usage...
5037 %
5038 %    CLIoption(cli_wand,"-read","rose:");
5039 %    CLIoption(cli_wand,"-virtual-pixel","transparent");
5040 %    CLIoption(cli_wand,"-distort","SRT:","30");
5041 %    CLIoption(cli_wand,"-write","rotated_rose.png");
5042 %
5043 */
5044 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5045 {
5046   const char    /* extracted option args from args */
5047     *arg1,
5048     *arg2;
5049
5050   CommandOptionFlags
5051     option_type;
5052
5053   assert(cli_wand != (MagickCLI *) NULL);
5054   assert(cli_wand->signature == MagickWandSignature);
5055   assert(cli_wand->wand.signature == MagickWandSignature);
5056
5057   do { /* Break Code Block for error handling */
5058
5059     /* get information about option */
5060     if ( cli_wand->command == (const OptionInfo *) NULL )
5061       cli_wand->command = GetCommandOptionInfo(option);
5062 #if 0
5063       (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5064             option, cli_wand->command->mnemonic );
5065 #endif
5066     option_type=(CommandOptionFlags) cli_wand->command->flags;
5067
5068     if ( option_type == UndefinedOptionFlag )
5069       CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5070
5071     assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5072
5073     /* deprecated options */
5074     if ( (option_type & DeprecateOptionFlag) != 0 )
5075       CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5076
5077     /* options that this module does not handle */
5078     if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5079       CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5080
5081     /* Get argument strings from VarArgs
5082       How can you determine if enough arguments was supplied?
5083       What happens if not enough arguments were supplied?
5084     */
5085     { size_t
5086         count = (size_t) cli_wand->command->type;
5087
5088       va_list
5089         operands;
5090
5091       va_start(operands,option);
5092
5093       arg1=arg2=NULL;
5094       if ( count >= 1 )
5095         arg1=(const char *) va_arg(operands, const char *);
5096       if ( count >= 2 )
5097         arg2=(const char *) va_arg(operands, const char *);
5098
5099       va_end(operands);
5100 #if 0
5101       (void) FormatLocaleFile(stderr,
5102         "CLIOption: \"%s\"  Count: %ld  Flags: %04x  Args: \"%s\" \"%s\"\n",
5103             option,(long) count,option_type,arg1,arg2);
5104 #endif
5105     }
5106
5107     /*
5108       Call the appropriate option handler
5109     */
5110
5111     /* FUTURE: this is temporary - get 'settings' to handle distribution of
5112       settings to images attributes,proprieties,artifacts */
5113     if ( cli_wand->wand.images != (Image *) NULL )
5114       (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5115         cli_wand->wand.exception);
5116
5117     if ( (option_type & SettingOptionFlags) != 0 ) {
5118       CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5119       // FUTURE: Sync Specific Settings into Image Properities (not global)
5120     }
5121
5122     /* Operators that do not need images - read, write, stack, clone */
5123     if ((option_type & NoImageOperatorFlag) != 0)
5124       CLINoImageOperator(cli_wand, option, arg1, arg2);
5125
5126     /* FUTURE: The not a setting part below is a temporary hack due to
5127     * some options being both a Setting and a Simple operator.
5128     * Specifically -monitor, -depth, and  -colorspace */
5129     if ( cli_wand->wand.images == (Image *) NULL )
5130       if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5131           ((option_type & SettingOptionFlags) == 0 ))  /* temp hack */
5132         CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5133
5134     /* Operators which loop of individual images, simply */
5135     if ( (option_type & SimpleOperatorFlag) != 0 &&
5136          cli_wand->wand.images != (Image *) NULL) /* temp hack */
5137       {
5138         ExceptionInfo *exception=AcquireExceptionInfo();
5139         (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5140         exception=DestroyExceptionInfo(exception);
5141       }
5142
5143     /* Operators that work on the image list as a whole */
5144     if ( (option_type & ListOperatorFlag) != 0 )
5145       (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5146
5147 DisableMSCWarning(4127)
5148   } while (0);  /* end Break code block */
5149 RestoreMSCWarning
5150
5151   cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
5152 }