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