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