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