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