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