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