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