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