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