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