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