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