source: ImageMagick/trunk/MagickWand/operation.c @ 7454

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