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