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