MagickWand  7.0.11
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  geometry[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(geometry,MagickPathExtent,"%+f%+f",
1797  geometry_info.xi,geometry_info.psi);
1798  (void) CloneString(&_draw_info->geometry,geometry);
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  GeometryInfo
1913  geometry_info;
1914 
1915  MagickStatusType
1916  flags;
1917 
1918  flags=ParseGeometry(arg1,&geometry_info);
1919  if ((flags & RhoValue) == 0)
1920  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1921  brightness=geometry_info.rho;
1922  contrast=0.0;
1923  if ((flags & SigmaValue) != 0)
1924  contrast=geometry_info.sigma;
1925  (void) BrightnessContrastImage(_image,brightness,contrast,
1926  _exception);
1927  break;
1928  }
1929  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1930  }
1931  case 'c':
1932  {
1933  if (LocaleCompare("canny",option+1) == 0)
1934  {
1935  flags=ParseGeometry(arg1,&geometry_info);
1936  if ((flags & (RhoValue|SigmaValue)) == 0)
1937  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1938  if ((flags & SigmaValue) == 0)
1939  geometry_info.sigma=1.0;
1940  if ((flags & XiValue) == 0)
1941  geometry_info.xi=10;
1942  if ((flags & PsiValue) == 0)
1943  geometry_info.psi=30;
1944  if ((flags & PercentValue) != 0)
1945  {
1946  geometry_info.xi/=100.0;
1947  geometry_info.psi/=100.0;
1948  }
1949  new_image=CannyEdgeImage(_image,geometry_info.rho,geometry_info.sigma,
1950  geometry_info.xi,geometry_info.psi,_exception);
1951  break;
1952  }
1953  if (LocaleCompare("cdl",option+1) == 0)
1954  {
1955  char
1956  *color_correction_collection; /* Note: arguments do not have percent escapes expanded */
1957 
1958  /*
1959  Color correct with a color decision list.
1960  */
1961  color_correction_collection=FileToString(arg1,~0UL,_exception);
1962  if (color_correction_collection == (char *) NULL)
1963  break;
1964  (void) ColorDecisionListImage(_image,color_correction_collection,
1965  _exception);
1966  break;
1967  }
1968  if (LocaleCompare("channel",option+1) == 0)
1969  {
1970  if (IfPlusOp)
1971  {
1972  (void) SetPixelChannelMask(_image,DefaultChannels);
1973  break;
1974  }
1975  parse=ParseChannelOption(arg1);
1976  if (parse < 0)
1977  CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",option,
1978  arg1);
1979  (void) SetPixelChannelMask(_image,(ChannelType) parse);
1980  break;
1981  }
1982  if (LocaleCompare("charcoal",option+1) == 0)
1983  {
1984  flags=ParseGeometry(arg1,&geometry_info);
1985  if ((flags & (RhoValue|SigmaValue)) == 0)
1986  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1987  if ((flags & SigmaValue) == 0)
1988  geometry_info.sigma=1.0;
1989  if ((flags & XiValue) == 0)
1990  geometry_info.xi=1.0;
1991  new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1992  _exception);
1993  break;
1994  }
1995  if (LocaleCompare("chop",option+1) == 0)
1996  {
1997  if (IsGeometry(arg1) == MagickFalse)
1998  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1999  (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
2000  new_image=ChopImage(_image,&geometry,_exception);
2001  break;
2002  }
2003  if (LocaleCompare("clahe",option+1) == 0)
2004  {
2005  if (IsGeometry(arg1) == MagickFalse)
2006  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2007  flags=ParseGeometry(arg1,&geometry_info);
2008  flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2009  (void) CLAHEImage(_image,geometry.width,geometry.height,
2010  (size_t) geometry.x,geometry_info.psi,_exception);
2011  break;
2012  }
2013  if (LocaleCompare("clamp",option+1) == 0)
2014  {
2015  (void) ClampImage(_image,_exception);
2016  break;
2017  }
2018  if (LocaleCompare("clip",option+1) == 0)
2019  {
2020  if (IfNormalOp)
2021  (void) ClipImage(_image,_exception);
2022  else /* "+mask" remove the write mask */
2023  (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,
2024  _exception);
2025  break;
2026  }
2027  if (LocaleCompare("clip-mask",option+1) == 0)
2028  {
2029  Image
2030  *clip_mask;
2031 
2032  if (IfPlusOp) {
2033  /* use "+clip-mask" Remove the write mask for -clip-path */
2034  (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,_exception);
2035  break;
2036  }
2037  clip_mask=GetImageCache(_image_info,arg1,_exception);
2038  if (clip_mask == (Image *) NULL)
2039  break;
2040  (void) SetImageMask(_image,WritePixelMask,clip_mask,_exception);
2041  clip_mask=DestroyImage(clip_mask);
2042  break;
2043  }
2044  if (LocaleCompare("clip-path",option+1) == 0)
2045  {
2046  (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2047  /* Note: Use "+clip-mask" remove the write mask added */
2048  break;
2049  }
2050  if (LocaleCompare("colorize",option+1) == 0)
2051  {
2052  if (IsGeometry(arg1) == MagickFalse)
2053  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2054  new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2055  break;
2056  }
2057  if (LocaleCompare("color-matrix",option+1) == 0)
2058  {
2059  KernelInfo
2060  *kernel;
2061 
2062  kernel=AcquireKernelInfo(arg1,exception);
2063  if (kernel == (KernelInfo *) NULL)
2064  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2065  new_image=ColorMatrixImage(_image,kernel,_exception);
2066  kernel=DestroyKernelInfo(kernel);
2067  break;
2068  }
2069  if (LocaleCompare("colors",option+1) == 0)
2070  {
2071  /* Reduce the number of colors in the image.
2072  FUTURE: also provide 'plus version with image 'color counts'
2073  */
2074  _quantize_info->number_colors=StringToUnsignedLong(arg1);
2075  if (_quantize_info->number_colors == 0)
2076  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2077  if ((_image->storage_class == DirectClass) ||
2078  _image->colors > _quantize_info->number_colors)
2079  (void) QuantizeImage(_quantize_info,_image,_exception);
2080  else
2081  (void) CompressImageColormap(_image,_exception);
2082  break;
2083  }
2084  if (LocaleCompare("colorspace",option+1) == 0)
2085  {
2086  /* WARNING: this is both a image_info setting (already done)
2087  and a operator to change image colorspace.
2088 
2089  FUTURE: default colorspace should be sRGB!
2090  Unless some type of 'linear colorspace' mode is set.
2091 
2092  Note that +colorspace sets "undefined" or no effect on
2093  new images, but forces images already in memory back to RGB!
2094  That seems to be a little strange!
2095  */
2096  (void) TransformImageColorspace(_image,
2097  IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2098  _exception);
2099  break;
2100  }
2101  if (LocaleCompare("color-threshold",option+1) == 0)
2102  {
2103  PixelInfo
2104  start,
2105  stop;
2106 
2107  /*
2108  Color threshold image.
2109  */
2110  if (*option == '+')
2111  (void) GetColorRange("white-black",&start,&stop,_exception);
2112  else
2113  (void) GetColorRange(arg1,&start,&stop,_exception);
2114  (void) ColorThresholdImage(_image,&start,&stop,_exception);
2115  break;
2116  }
2117  if (LocaleCompare("connected-components",option+1) == 0)
2118  {
2119  if (IsGeometry(arg1) == MagickFalse)
2120  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2121  new_image=ConnectedComponentsImage(_image,(size_t)
2122  StringToInteger(arg1),(CCObjectInfo **) NULL,_exception);
2123  break;
2124  }
2125  if (LocaleCompare("contrast",option+1) == 0)
2126  {
2127  CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2128  (void) ContrastImage(_image,IsNormalOp,_exception);
2129  break;
2130  }
2131  if (LocaleCompare("contrast-stretch",option+1) == 0)
2132  {
2133  double
2134  black_point,
2135  white_point;
2136 
2137  MagickStatusType
2138  flags;
2139 
2140  flags=ParseGeometry(arg1,&geometry_info);
2141  if ((flags & RhoValue) == 0)
2142  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2143  black_point=geometry_info.rho;
2144  white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2145  black_point;
2146  if ((flags & PercentValue) != 0)
2147  {
2148  black_point*=(double) _image->columns*_image->rows/100.0;
2149  white_point*=(double) _image->columns*_image->rows/100.0;
2150  }
2151  white_point=(double) _image->columns*_image->rows-white_point;
2152  (void) ContrastStretchImage(_image,black_point,white_point,
2153  _exception);
2154  break;
2155  }
2156  if (LocaleCompare("convolve",option+1) == 0)
2157  {
2158  double
2159  gamma;
2160 
2161  KernelInfo
2162  *kernel_info;
2163 
2164  ssize_t
2165  j;
2166 
2167  kernel_info=AcquireKernelInfo(arg1,exception);
2168  if (kernel_info == (KernelInfo *) NULL)
2169  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2170  gamma=0.0;
2171  for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2172  gamma+=kernel_info->values[j];
2173  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2174  for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2175  kernel_info->values[j]*=gamma;
2176  new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2177  _exception);
2178  kernel_info=DestroyKernelInfo(kernel_info);
2179  break;
2180  }
2181  if (LocaleCompare("crop",option+1) == 0)
2182  {
2183  /* WARNING: This can generate multiple images! */
2184  if (IsGeometry(arg1) == MagickFalse)
2185  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2186  new_image=CropImageToTiles(_image,arg1,_exception);
2187  break;
2188  }
2189  if (LocaleCompare("cycle",option+1) == 0)
2190  {
2191  if (IsGeometry(arg1) == MagickFalse)
2192  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2193  (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2194  _exception);
2195  break;
2196  }
2197  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2198  }
2199  case 'd':
2200  {
2201  if (LocaleCompare("decipher",option+1) == 0)
2202  {
2203  /* Note: arguments do not have percent escapes expanded */
2204  StringInfo
2205  *passkey;
2206 
2207  passkey=FileToStringInfo(arg1,~0UL,_exception);
2208  if (passkey == (StringInfo *) NULL)
2209  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2210 
2211  (void) PasskeyDecipherImage(_image,passkey,_exception);
2212  passkey=DestroyStringInfo(passkey);
2213  break;
2214  }
2215  if (LocaleCompare("depth",option+1) == 0)
2216  {
2217  /* The _image_info->depth setting has already been set
2218  We just need to apply it to all images in current sequence
2219 
2220  WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2221  That is it really is an operation, not a setting! Arrgghhh
2222 
2223  FUTURE: this should not be an operator!!!
2224  */
2225  (void) SetImageDepth(_image,_image_info->depth,_exception);
2226  break;
2227  }
2228  if (LocaleCompare("deskew",option+1) == 0)
2229  {
2230  double
2231  threshold;
2232 
2233  if (IfNormalOp) {
2234  if (IsGeometry(arg1) == MagickFalse)
2235  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2236  threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2237  }
2238  else
2239  threshold=40.0*QuantumRange/100.0;
2240  new_image=DeskewImage(_image,threshold,_exception);
2241  break;
2242  }
2243  if (LocaleCompare("despeckle",option+1) == 0)
2244  {
2245  new_image=DespeckleImage(_image,_exception);
2246  break;
2247  }
2248  if (LocaleCompare("distort",option+1) == 0)
2249  {
2250  double
2251  *args;
2252 
2253  ssize_t
2254  count;
2255 
2256  parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2257  if ( parse < 0 )
2258  CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2259  option,arg1);
2260  if ((DistortMethod) parse == ResizeDistortion)
2261  {
2262  double
2263  resize_args[2];
2264  /* Special Case - Argument is actually a resize geometry!
2265  ** Convert that to an appropriate distortion argument array.
2266  ** FUTURE: make a separate special resize operator
2267  Roll into a resize special operator */
2268  if (IsGeometry(arg2) == MagickFalse)
2269  CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2270  option,arg2);
2271  (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2272  resize_args[0]=(double) geometry.width;
2273  resize_args[1]=(double) geometry.height;
2274  new_image=DistortImage(_image,(DistortMethod) parse,
2275  (size_t)2,resize_args,MagickTrue,_exception);
2276  break;
2277  }
2278  /* convert argument string into an array of doubles */
2279  args = StringToArrayOfDoubles(arg2,&count,_exception);
2280  if (args == (double *) NULL )
2281  CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2282 
2283  new_image=DistortImage(_image,(DistortMethod) parse,(size_t)
2284  count,args,IsPlusOp,_exception);
2285  args=(double *) RelinquishMagickMemory(args);
2286  break;
2287  }
2288  if (LocaleCompare("draw",option+1) == 0)
2289  {
2290  (void) CloneString(&_draw_info->primitive,arg1);
2291  (void) DrawImage(_image,_draw_info,_exception);
2292  (void) CloneString(&_draw_info->primitive,(char *) NULL);
2293  break;
2294  }
2295  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2296  }
2297  case 'e':
2298  {
2299  if (LocaleCompare("edge",option+1) == 0)
2300  {
2301  flags=ParseGeometry(arg1,&geometry_info);
2302  if ((flags & (RhoValue|SigmaValue)) == 0)
2303  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2304  new_image=EdgeImage(_image,geometry_info.rho,_exception);
2305  break;
2306  }
2307  if (LocaleCompare("emboss",option+1) == 0)
2308  {
2309  flags=ParseGeometry(arg1,&geometry_info);
2310  if ((flags & (RhoValue|SigmaValue)) == 0)
2311  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2312  if ((flags & SigmaValue) == 0)
2313  geometry_info.sigma=1.0;
2314  new_image=EmbossImage(_image,geometry_info.rho,
2315  geometry_info.sigma,_exception);
2316  break;
2317  }
2318  if (LocaleCompare("encipher",option+1) == 0)
2319  {
2320  /* Note: arguments do not have percent escapes expanded */
2321  StringInfo
2322  *passkey;
2323 
2324  passkey=FileToStringInfo(arg1,~0UL,_exception);
2325  if (passkey != (StringInfo *) NULL)
2326  {
2327  (void) PasskeyEncipherImage(_image,passkey,_exception);
2328  passkey=DestroyStringInfo(passkey);
2329  }
2330  break;
2331  }
2332  if (LocaleCompare("enhance",option+1) == 0)
2333  {
2334  new_image=EnhanceImage(_image,_exception);
2335  break;
2336  }
2337  if (LocaleCompare("equalize",option+1) == 0)
2338  {
2339  (void) EqualizeImage(_image,_exception);
2340  break;
2341  }
2342  if (LocaleCompare("evaluate",option+1) == 0)
2343  {
2344  double
2345  constant;
2346 
2347  parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2348  if ( parse < 0 )
2349  CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2350  option,arg1);
2351  if (IsGeometry(arg2) == MagickFalse)
2352  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2353  constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2354  (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2355  _exception);
2356  break;
2357  }
2358  if (LocaleCompare("extent",option+1) == 0)
2359  {
2360  if (IsGeometry(arg1) == MagickFalse)
2361  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2362  flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2363  if (geometry.width == 0)
2364  geometry.width=_image->columns;
2365  if (geometry.height == 0)
2366  geometry.height=_image->rows;
2367  new_image=ExtentImage(_image,&geometry,_exception);
2368  break;
2369  }
2370  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2371  }
2372  case 'f':
2373  {
2374  if (LocaleCompare("features",option+1) == 0)
2375  {
2376  CLIWandWarnReplaced("-version -define identify:features=");
2377  if (*option == '+')
2378  {
2379  (void) DeleteImageArtifact(_image,"identify:features");
2380  break;
2381  }
2382  (void) SetImageArtifact(_image,"identify:features",arg1);
2383  (void) SetImageArtifact(_image,"verbose","true");
2384  break;
2385  }
2386  if (LocaleCompare("flip",option+1) == 0)
2387  {
2388  new_image=FlipImage(_image,_exception);
2389  break;
2390  }
2391  if (LocaleCompare("flop",option+1) == 0)
2392  {
2393  new_image=FlopImage(_image,_exception);
2394  break;
2395  }
2396  if (LocaleCompare("floodfill",option+1) == 0)
2397  {
2398  PixelInfo
2399  target;
2400 
2401  if (IsGeometry(arg1) == MagickFalse)
2402  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2403  (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2404  (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2405  (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2406  geometry.y,IsPlusOp,_exception);
2407  break;
2408  }
2409  if (LocaleCompare("frame",option+1) == 0)
2410  {
2411  FrameInfo
2412  frame_info;
2413 
2414  CompositeOperator
2415  compose;
2416 
2417  const char*
2418  value;
2419 
2420  value=GetImageOption(_image_info,"compose");
2421  compose=OverCompositeOp; /* use Over not _image->compose */
2422  if (value != (const char *) NULL)
2423  compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2424  MagickFalse,value);
2425  if (IsGeometry(arg1) == MagickFalse)
2426  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2427  flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2428  frame_info.width=geometry.width;
2429  frame_info.height=geometry.height;
2430  frame_info.outer_bevel=geometry.x;
2431  frame_info.inner_bevel=geometry.y;
2432  frame_info.x=(ssize_t) frame_info.width;
2433  frame_info.y=(ssize_t) frame_info.height;
2434  frame_info.width=_image->columns+2*frame_info.width;
2435  frame_info.height=_image->rows+2*frame_info.height;
2436  new_image=FrameImage(_image,&frame_info,compose,_exception);
2437  break;
2438  }
2439  if (LocaleCompare("function",option+1) == 0)
2440  {
2441  double
2442  *args;
2443 
2444  ssize_t
2445  count;
2446 
2447  parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2448  if ( parse < 0 )
2449  CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2450  option,arg1);
2451  /* convert argument string into an array of doubles */
2452  args = StringToArrayOfDoubles(arg2,&count,_exception);
2453  if (args == (double *) NULL )
2454  CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2455 
2456  (void) FunctionImage(_image,(MagickFunction)parse,(size_t) count,args,
2457  _exception);
2458  args=(double *) RelinquishMagickMemory(args);
2459  break;
2460  }
2461  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2462  }
2463  case 'g':
2464  {
2465  if (LocaleCompare("gamma",option+1) == 0)
2466  {
2467  double
2468  constant;
2469 
2470  if (IsGeometry(arg1) == MagickFalse)
2471  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2472  constant=StringToDouble(arg1,(char **) NULL);
2473 #if 0
2474  /* Using Gamma, via a cache */
2475  if (IfPlusOp)
2476  constant=PerceptibleReciprocal(constant);
2477  (void) GammaImage(_image,constant,_exception);
2478 #else
2479  /* Using Evaluate POW, direct update of values - more accurite */
2480  if (IfNormalOp)
2481  constant=PerceptibleReciprocal(constant);
2482  (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2483  _image->gamma*=StringToDouble(arg1,(char **) NULL);
2484 #endif
2485  /* Set gamma setting -- Old meaning of "+gamma"
2486  * _image->gamma=StringToDouble(arg1,(char **) NULL);
2487  */
2488  break;
2489  }
2490  if (LocaleCompare("gaussian-blur",option+1) == 0)
2491  {
2492  flags=ParseGeometry(arg1,&geometry_info);
2493  if ((flags & (RhoValue|SigmaValue)) == 0)
2494  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2495  if ((flags & SigmaValue) == 0)
2496  geometry_info.sigma=1.0;
2497  new_image=GaussianBlurImage(_image,geometry_info.rho,
2498  geometry_info.sigma,_exception);
2499  break;
2500  }
2501  if (LocaleCompare("gaussian",option+1) == 0)
2502  {
2503  CLIWandWarnReplaced("-gaussian-blur");
2504  (void) CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2505  }
2506  if (LocaleCompare("geometry",option+1) == 0)
2507  {
2508  /*
2509  Record Image offset for composition. (A Setting)
2510  Resize last _image. (ListOperator) -- DEPRECIATE
2511  FUTURE: Why if no 'offset' does this resize ALL images?
2512  Also why is the setting recorded in the IMAGE non-sense!
2513  */
2514  if (IfPlusOp)
2515  { /* remove the previous composition geometry offset! */
2516  if (_image->geometry != (char *) NULL)
2517  _image->geometry=DestroyString(_image->geometry);
2518  break;
2519  }
2520  if (IsGeometry(arg1) == MagickFalse)
2521  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2522  flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2523  if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2524  (void) CloneString(&_image->geometry,arg1);
2525  else
2526  new_image=ResizeImage(_image,geometry.width,geometry.height,
2527  _image->filter,_exception);
2528  break;
2529  }
2530  if (LocaleCompare("grayscale",option+1) == 0)
2531  {
2532  parse=ParseCommandOption(MagickPixelIntensityOptions,
2533  MagickFalse,arg1);
2534  if (parse < 0)
2535  CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2536  option,arg1);
2537  (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2538  break;
2539  }
2540  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2541  }
2542  case 'h':
2543  {
2544  if (LocaleCompare("hough-lines",option+1) == 0)
2545  {
2546  flags=ParseGeometry(arg1,&geometry_info);
2547  if ((flags & (RhoValue|SigmaValue)) == 0)
2548  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2549  if ((flags & SigmaValue) == 0)
2550  geometry_info.sigma=geometry_info.rho;
2551  if ((flags & XiValue) == 0)
2552  geometry_info.xi=40;
2553  new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2554  (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2555  break;
2556  }
2557  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2558  }
2559  case 'i':
2560  {
2561  if (LocaleCompare("identify",option+1) == 0)
2562  {
2563  const char
2564  *format,
2565  *text;
2566 
2567  format=GetImageOption(_image_info,"format");
2568  if (format == (char *) NULL)
2569  {
2570  (void) IdentifyImage(_image,stdout,_image_info->verbose,
2571  _exception);
2572  break;
2573  }
2574  text=InterpretImageProperties(_image_info,_image,format,_exception);
2575  if (text == (char *) NULL)
2576  CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2577  option);
2578  (void) fputs(text,stdout);
2579  text=DestroyString((char *)text);
2580  break;
2581  }
2582  if (LocaleCompare("implode",option+1) == 0)
2583  {
2584  flags=ParseGeometry(arg1,&geometry_info);
2585  if ((flags & RhoValue) == 0)
2586  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2587  new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2588  _exception);
2589  break;
2590  }
2591  if (LocaleCompare("interpolative-resize",option+1) == 0)
2592  {
2593  /* FUTURE: New to IMv7
2594  Roll into a resize special operator */
2595  if (IsGeometry(arg1) == MagickFalse)
2596  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2597  (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2598  new_image=InterpolativeResizeImage(_image,geometry.width,
2599  geometry.height,_image->interpolate,_exception);
2600  break;
2601  }
2602  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2603  }
2604  case 'k':
2605  {
2606  if (LocaleCompare("kmeans",option+1) == 0)
2607  {
2608  /*
2609  K-means clustering.
2610  */
2611  flags=ParseGeometry(arg1,&geometry_info);
2612  if ((flags & (RhoValue|SigmaValue)) == 0)
2613  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2614  if ((flags & SigmaValue) == 0)
2615  geometry_info.sigma=100.0;
2616  if ((flags & XiValue) == 0)
2617  geometry_info.xi=0.01;
2618  (void) KmeansImage(_image,(size_t) geometry_info.rho,(size_t)
2619  geometry_info.sigma,geometry_info.xi,_exception);
2620  break;
2621  }
2622  if (LocaleCompare("kuwahara",option+1) == 0)
2623  {
2624  /*
2625  Edge preserving blur.
2626  */
2627  flags=ParseGeometry(arg1,&geometry_info);
2628  if ((flags & (RhoValue|SigmaValue)) == 0)
2629  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2630  if ((flags & SigmaValue) == 0)
2631  geometry_info.sigma=geometry_info.rho-0.5;
2632  new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2633  _exception);
2634  break;
2635  }
2636  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2637  }
2638  case 'l':
2639  {
2640  if (LocaleCompare("lat",option+1) == 0)
2641  {
2642  flags=ParseGeometry(arg1,&geometry_info);
2643  if ((flags & (RhoValue|SigmaValue)) == 0)
2644  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2645  if ((flags & SigmaValue) == 0)
2646  geometry_info.sigma=1.0;
2647  if ((flags & PercentValue) != 0)
2648  geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2649  new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2650  (size_t) geometry_info.sigma,(double) geometry_info.xi,
2651  _exception);
2652  break;
2653  }
2654  if (LocaleCompare("level",option+1) == 0)
2655  {
2656  double
2657  black_point,
2658  gamma,
2659  white_point;
2660 
2661  MagickStatusType
2662  flags;
2663 
2664  flags=ParseGeometry(arg1,&geometry_info);
2665  if ((flags & RhoValue) == 0)
2666  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2667  black_point=geometry_info.rho;
2668  white_point=(double) QuantumRange;
2669  if ((flags & SigmaValue) != 0)
2670  white_point=geometry_info.sigma;
2671  gamma=1.0;
2672  if ((flags & XiValue) != 0)
2673  gamma=geometry_info.xi;
2674  if ((flags & PercentValue) != 0)
2675  {
2676  black_point*=(double) (QuantumRange/100.0);
2677  white_point*=(double) (QuantumRange/100.0);
2678  }
2679  if ((flags & SigmaValue) == 0)
2680  white_point=(double) QuantumRange-black_point;
2681  if (IfPlusOp || ((flags & AspectValue) != 0))
2682  (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2683  else
2684  (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2685  break;
2686  }
2687  if (LocaleCompare("level-colors",option+1) == 0)
2688  {
2689  char
2690  token[MagickPathExtent];
2691 
2692  const char
2693  *p;
2694 
2695  PixelInfo
2696  black_point,
2697  white_point;
2698 
2699  p=(const char *) arg1;
2700  (void) GetNextToken(p,&p,MagickPathExtent,token); /* get black point color */
2701  if ((isalpha((int) ((unsigned char) *token)) != 0) || ((*token == '#') != 0))
2702  (void) QueryColorCompliance(token,AllCompliance,
2703  &black_point,_exception);
2704  else
2705  (void) QueryColorCompliance("#000000",AllCompliance,
2706  &black_point,_exception);
2707  if (isalpha((int) ((unsigned char) *token)) || (*token == '#'))
2708  (void) GetNextToken(p,&p,MagickPathExtent,token);
2709  if (*token == '\0')
2710  white_point=black_point; /* set everything to that color */
2711  else
2712  {
2713  if ((isalpha((int) ((unsigned char) *token)) == 0) && ((*token == '#') == 0))
2714  (void) GetNextToken(p,&p,MagickPathExtent,token); /* Get white point color. */
2715  if ((isalpha((int) ((unsigned char) *token)) != 0) || ((*token == '#') != 0))
2716  (void) QueryColorCompliance(token,AllCompliance,
2717  &white_point,_exception);
2718  else
2719  (void) QueryColorCompliance("#ffffff",AllCompliance,
2720  &white_point,_exception);
2721  }
2722  (void) LevelImageColors(_image,&black_point,&white_point,
2724  break;
2725  }
2726  if (LocaleCompare("linear-stretch",option+1) == 0)
2727  {
2728  double
2729  black_point,
2730  white_point;
2731 
2732  MagickStatusType
2733  flags;
2734 
2735  flags=ParseGeometry(arg1,&geometry_info);
2736  if ((flags & RhoValue) == 0)
2737  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2738  black_point=geometry_info.rho;
2739  white_point=(double) _image->columns*_image->rows;
2740  if ((flags & SigmaValue) != 0)
2741  white_point=geometry_info.sigma;
2742  if ((flags & PercentValue) != 0)
2743  {
2744  black_point*=(double) _image->columns*_image->rows/100.0;
2745  white_point*=(double) _image->columns*_image->rows/100.0;
2746  }
2747  if ((flags & SigmaValue) == 0)
2748  white_point=(double) _image->columns*_image->rows-
2749  black_point;
2750  (void) LinearStretchImage(_image,black_point,white_point,_exception);
2751  break;
2752  }
2753  if (LocaleCompare("liquid-rescale",option+1) == 0)
2754  {
2755  /* FUTURE: Roll into a resize special operator */
2756  if (IsGeometry(arg1) == MagickFalse)
2757  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2758  flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2759  if ((flags & XValue) == 0)
2760  geometry.x=1;
2761  if ((flags & YValue) == 0)
2762  geometry.y=0;
2763  new_image=LiquidRescaleImage(_image,geometry.width,
2764  geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2765  break;
2766  }
2767  if (LocaleCompare("local-contrast",option+1) == 0)
2768  {
2769  MagickStatusType
2770  flags;
2771 
2772  flags=ParseGeometry(arg1,&geometry_info);
2773  if ((flags & RhoValue) == 0)
2774  geometry_info.rho=10;
2775  if ((flags & SigmaValue) == 0)
2776  geometry_info.sigma=12.5;
2777  new_image=LocalContrastImage(_image,geometry_info.rho,
2778  geometry_info.sigma,exception);
2779  break;
2780  }
2781  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2782  }
2783  case 'm':
2784  {
2785  if (LocaleCompare("magnify",option+1) == 0)
2786  {
2787  new_image=MagnifyImage(_image,_exception);
2788  break;
2789  }
2790  if (LocaleCompare("map",option+1) == 0)
2791  {
2792  CLIWandWarnReplaced("-remap");
2793  (void) CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL,exception);
2794  break;
2795  }
2796  if (LocaleCompare("mask",option+1) == 0)
2797  {
2798  Image
2799  *mask;
2800 
2801  if (IfPlusOp)
2802  {
2803  /*
2804  Remove a mask.
2805  */
2806  (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,
2807  _exception);
2808  break;
2809  }
2810  /*
2811  Set the image mask.
2812  */
2814  if (mask == (Image *) NULL)
2815  break;
2816  (void) SetImageMask(_image,WritePixelMask,mask,_exception);
2817  mask=DestroyImage(mask);
2818  break;
2819  }
2820  if (LocaleCompare("matte",option+1) == 0)
2821  {
2822  CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2823  (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2824  DeactivateAlphaChannel, _exception);
2825  break;
2826  }
2827  if (LocaleCompare("mean-shift",option+1) == 0)
2828  {
2829  flags=ParseGeometry(arg1,&geometry_info);
2830  if ((flags & (RhoValue|SigmaValue)) == 0)
2831  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2832  if ((flags & SigmaValue) == 0)
2833  geometry_info.sigma=1.0;
2834  if ((flags & XiValue) == 0)
2835  geometry_info.xi=0.10*QuantumRange;
2836  if ((flags & PercentValue) != 0)
2837  geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2838  new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2839  (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2840  break;
2841  }
2842  if (LocaleCompare("median",option+1) == 0)
2843  {
2844  CLIWandWarnReplaced("-statistic Median");
2845  (void) CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2846  break;
2847  }
2848  if (LocaleCompare("mode",option+1) == 0)
2849  {
2850  /* FUTURE: note this is also a special "montage" option */
2851  CLIWandWarnReplaced("-statistic Mode");
2852  (void) CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,exception);
2853  break;
2854  }
2855  if (LocaleCompare("modulate",option+1) == 0)
2856  {
2857  if (IsGeometry(arg1) == MagickFalse)
2858  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2859  (void) ModulateImage(_image,arg1,_exception);
2860  break;
2861  }
2862  if (LocaleCompare("monitor",option+1) == 0)
2863  {
2864  (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2865  (MagickProgressMonitor) NULL,(void *) NULL);
2866  break;
2867  }
2868  if (LocaleCompare("monochrome",option+1) == 0)
2869  {
2870  (void) SetImageType(_image,BilevelType,_exception);
2871  break;
2872  }
2873  if (LocaleCompare("morphology",option+1) == 0)
2874  {
2875  char
2876  token[MagickPathExtent];
2877 
2878  const char
2879  *p;
2880 
2881  KernelInfo
2882  *kernel;
2883 
2884  ssize_t
2885  iterations;
2886 
2887  p=arg1;
2888  (void) GetNextToken(p,&p,MagickPathExtent,token);
2889  parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2890  if ( parse < 0 )
2891  CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2892  arg1);
2893  iterations=1L;
2894  (void) GetNextToken(p,&p,MagickPathExtent,token);
2895  if ((*p == ':') || (*p == ','))
2896  (void) GetNextToken(p,&p,MagickPathExtent,token);
2897  if ((*p != '\0'))
2898  iterations=(ssize_t) StringToLong(p);
2899  kernel=AcquireKernelInfo(arg2,exception);
2900  if (kernel == (KernelInfo *) NULL)
2901  CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2902  new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2903  kernel,_exception);
2904  kernel=DestroyKernelInfo(kernel);
2905  break;
2906  }
2907  if (LocaleCompare("motion-blur",option+1) == 0)
2908  {
2909  flags=ParseGeometry(arg1,&geometry_info);
2910  if ((flags & (RhoValue|SigmaValue)) == 0)
2911  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2912  if ((flags & SigmaValue) == 0)
2913  geometry_info.sigma=1.0;
2914  new_image=MotionBlurImage(_image,geometry_info.rho,geometry_info.sigma,
2915  geometry_info.xi,_exception);
2916  break;
2917  }
2918  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2919  }
2920  case 'n':
2921  {
2922  if (LocaleCompare("negate",option+1) == 0)
2923  {
2924  (void) NegateImage(_image, IsPlusOp, _exception);
2925  break;
2926  }
2927  if (LocaleCompare("noise",option+1) == 0)
2928  {
2929  double
2930  attenuate;
2931 
2932  const char*
2933  value;
2934 
2935  if (IfNormalOp)
2936  {
2937  CLIWandWarnReplaced("-statistic NonPeak");
2938  (void) CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2939  break;
2940  }
2941  parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2942  if ( parse < 0 )
2943  CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2944  option,arg1);
2945  attenuate=1.0;
2946  value=GetImageOption(_image_info,"attenuate");
2947  if (value != (const char *) NULL)
2948  attenuate=StringToDouble(value,(char **) NULL);
2949  new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2950  _exception);
2951  break;
2952  }
2953  if (LocaleCompare("normalize",option+1) == 0)
2954  {
2955  (void) NormalizeImage(_image,_exception);
2956  break;
2957  }
2958  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2959  }
2960  case 'o':
2961  {
2962  if (LocaleCompare("opaque",option+1) == 0)
2963  {
2964  PixelInfo
2965  target;
2966 
2967  (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2968  (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2969  _exception);
2970  break;
2971  }
2972  if (LocaleCompare("ordered-dither",option+1) == 0)
2973  {
2974  (void) OrderedDitherImage(_image,arg1,_exception);
2975  break;
2976  }
2977  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2978  }
2979  case 'p':
2980  {
2981  if (LocaleCompare("paint",option+1) == 0)
2982  {
2983  flags=ParseGeometry(arg1,&geometry_info);
2984  if ((flags & (RhoValue|SigmaValue)) == 0)
2985  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2986  new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2987  _exception);
2988  break;
2989  }
2990  if (LocaleCompare("perceptible",option+1) == 0)
2991  {
2992  (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2993  _exception);
2994  break;
2995  }
2996  if (LocaleCompare("polaroid",option+1) == 0)
2997  {
2998  const char
2999  *caption;
3000 
3001  double
3002  angle;
3003 
3004  if (IfPlusOp) {
3005  RandomInfo
3006  *random_info;
3007 
3008  random_info=AcquireRandomInfo();
3009  angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
3010  random_info=DestroyRandomInfo(random_info);
3011  }
3012  else {
3013  flags=ParseGeometry(arg1,&geometry_info);
3014  if ((flags & RhoValue) == 0)
3015  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3016  angle=geometry_info.rho;
3017  }
3018  caption=GetImageProperty(_image,"caption",_exception);
3019  new_image=PolaroidImage(_image,_draw_info,caption,angle,
3020  _image->interpolate,_exception);
3021  break;
3022  }
3023  if (LocaleCompare("posterize",option+1) == 0)
3024  {
3025  flags=ParseGeometry(arg1,&geometry_info);
3026  if ((flags & RhoValue) == 0)
3027  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3028  (void) PosterizeImage(_image,(size_t) geometry_info.rho,
3029  _quantize_info->dither_method,_exception);
3030  break;
3031  }
3032  if (LocaleCompare("preview",option+1) == 0)
3033  {
3034  /* FUTURE: should be a 'Genesis' option?
3035  Option however is also in WandSettingOptionInfo()
3036  Why???
3037  */
3038  parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
3039  if ( parse < 0 )
3040  CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
3041  option,arg1);
3042  new_image=PreviewImage(_image,(PreviewType)parse,_exception);
3043  break;
3044  }
3045  if (LocaleCompare("profile",option+1) == 0)
3046  {
3047  const char
3048  *name;
3049 
3050  const StringInfo
3051  *profile;
3052 
3053  Image
3054  *profile_image;
3055 
3056  ImageInfo
3057  *profile_info;
3058 
3059  /* Note: arguments do not have percent escapes expanded */
3060  if (IfPlusOp)
3061  { /* Remove a profile from the _image. */
3062  (void) ProfileImage(_image,arg1,(const unsigned char *)
3063  NULL,0,_exception);
3064  break;
3065  }
3066  /* Associate a profile with the _image. */
3067  profile_info=CloneImageInfo(_image_info);
3068  profile=GetImageProfile(_image,"iptc");
3069  if (profile != (StringInfo *) NULL)
3070  profile_info->profile=(void *) CloneStringInfo(profile);
3071  profile_image=GetImageCache(profile_info,arg1,_exception);
3072  profile_info=DestroyImageInfo(profile_info);
3073  if (profile_image == (Image *) NULL)
3074  {
3075  StringInfo
3076  *profile;
3077 
3078  profile_info=CloneImageInfo(_image_info);
3079  (void) CopyMagickString(profile_info->filename,arg1,
3081  profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
3082  if (profile != (StringInfo *) NULL)
3083  {
3084  (void) SetImageInfo(profile_info,0,_exception);
3085  (void) ProfileImage(_image,profile_info->magick,
3086  GetStringInfoDatum(profile),(size_t)
3087  GetStringInfoLength(profile),_exception);
3088  profile=DestroyStringInfo(profile);
3089  }
3090  profile_info=DestroyImageInfo(profile_info);
3091  break;
3092  }
3093  ResetImageProfileIterator(profile_image);
3094  name=GetNextImageProfile(profile_image);
3095  while (name != (const char *) NULL)
3096  {
3097  profile=GetImageProfile(profile_image,name);
3098  if (profile != (StringInfo *) NULL)
3099  (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3100  (size_t) GetStringInfoLength(profile),_exception);
3101  name=GetNextImageProfile(profile_image);
3102  }
3103  profile_image=DestroyImage(profile_image);
3104  break;
3105  }
3106  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3107  }
3108  case 'r':
3109  {
3110  if (LocaleCompare("raise",option+1) == 0)
3111  {
3112  if (IsGeometry(arg1) == MagickFalse)
3113  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3114  flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3115  (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3116  break;
3117  }
3118  if (LocaleCompare("random-threshold",option+1) == 0)
3119  {
3120  double
3121  min_threshold,
3122  max_threshold;
3123 
3124  if (IsGeometry(arg1) == MagickFalse)
3125  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3126  min_threshold=0.0;
3127  max_threshold=(double) QuantumRange;
3128  flags=ParseGeometry(arg1,&geometry_info);
3129  min_threshold=geometry_info.rho;
3130  max_threshold=geometry_info.sigma;
3131  if ((flags & SigmaValue) == 0)
3132  max_threshold=min_threshold;
3133  if (strchr(arg1,'%') != (char *) NULL)
3134  {
3135  max_threshold*=(double) (0.01*QuantumRange);
3136  min_threshold*=(double) (0.01*QuantumRange);
3137  }
3138  (void) RandomThresholdImage(_image,min_threshold,max_threshold,
3139  _exception);
3140  break;
3141  }
3142  if (LocaleCompare("range-threshold",option+1) == 0)
3143  {
3144  /*
3145  Range threshold image.
3146  */
3147  if (IsGeometry(arg1) == MagickFalse)
3148  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3149  flags=ParseGeometry(arg1,&geometry_info);
3150  if ((flags & SigmaValue) == 0)
3151  geometry_info.sigma=geometry_info.rho;
3152  if ((flags & XiValue) == 0)
3153  geometry_info.xi=geometry_info.sigma;
3154  if ((flags & PsiValue) == 0)
3155  geometry_info.psi=geometry_info.xi;
3156  if (strchr(arg1,'%') != (char *) NULL)
3157  {
3158  geometry_info.rho*=(double) (0.01*QuantumRange);
3159  geometry_info.sigma*=(double) (0.01*QuantumRange);
3160  geometry_info.xi*=(double) (0.01*QuantumRange);
3161  geometry_info.psi*=(double) (0.01*QuantumRange);
3162  }
3163  (void) RangeThresholdImage(_image,geometry_info.rho,
3164  geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3165  break;
3166  }
3167  if (LocaleCompare("read-mask",option+1) == 0)
3168  {
3169  /* Note: arguments do not have percent escapes expanded */
3170  Image
3171  *mask;
3172 
3173  if (IfPlusOp)
3174  { /* Remove a mask. */
3175  (void) SetImageMask(_image,ReadPixelMask,(Image *) NULL,
3176  _exception);
3177  break;
3178  }
3179  /* Set the image mask. */
3181  if (mask == (Image *) NULL)
3182  break;
3183  (void) SetImageMask(_image,ReadPixelMask,mask,_exception);
3184  mask=DestroyImage(mask);
3185  break;
3186  }
3187  if (LocaleCompare("recolor",option+1) == 0)
3188  {
3189  CLIWandWarnReplaced("-color-matrix");
3190  (void) CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,
3191  exception);
3192  }
3193  if (LocaleCompare("region",option+1) == 0)
3194  {
3195  if (*option == '+')
3196  {
3197  (void) SetImageRegionMask(_image,WritePixelMask,
3198  (const RectangleInfo *) NULL,_exception);
3199  break;
3200  }
3201  if (IsGeometry(arg1) == MagickFalse)
3202  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3203  (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
3204  (void) SetImageRegionMask(_image,WritePixelMask,&geometry,_exception);
3205  break;
3206  }
3207  if (LocaleCompare("remap",option+1) == 0)
3208  {
3209  /* Note: arguments do not have percent escapes expanded */
3210  Image
3211  *remap_image;
3212 
3213  remap_image=GetImageCache(_image_info,arg1,_exception);
3214  if (remap_image == (Image *) NULL)
3215  break;
3216  (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3217  remap_image=DestroyImage(remap_image);
3218  break;
3219  }
3220  if (LocaleCompare("repage",option+1) == 0)
3221  {
3222  if (IfNormalOp)
3223  {
3224  if (IsGeometry(arg1) == MagickFalse)
3225  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3226  arg1);
3227  (void) ResetImagePage(_image,arg1);
3228  }
3229  else
3230  (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3231  break;
3232  }
3233  if (LocaleCompare("resample",option+1) == 0)
3234  {
3235  /* FUTURE: Roll into a resize special operation */
3236  flags=ParseGeometry(arg1,&geometry_info);
3237  if ((flags & (RhoValue|SigmaValue)) == 0)
3238  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3239  if ((flags & SigmaValue) == 0)
3240  geometry_info.sigma=geometry_info.rho;
3241  new_image=ResampleImage(_image,geometry_info.rho,
3242  geometry_info.sigma,_image->filter,_exception);
3243  break;
3244  }
3245  if (LocaleCompare("resize",option+1) == 0)
3246  {
3247  if (IsGeometry(arg1) == MagickFalse)
3248  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3249  (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3250  new_image=ResizeImage(_image,geometry.width,geometry.height,
3251  _image->filter,_exception);
3252  break;
3253  }
3254  if (LocaleCompare("roll",option+1) == 0)
3255  {
3256  if (IsGeometry(arg1) == MagickFalse)
3257  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3258  flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3259  if ((flags & PercentValue) != 0)
3260  {
3261  geometry.x*=(double) _image->columns/100.0;
3262  geometry.y*=(double) _image->rows/100.0;
3263  }
3264  new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3265  break;
3266  }
3267  if (LocaleCompare("rotate",option+1) == 0)
3268  {
3269  flags=ParseGeometry(arg1,&geometry_info);
3270  if ((flags & RhoValue) == 0)
3271  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3272  if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3273  break;
3274  if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3275  break;
3276  new_image=RotateImage(_image,geometry_info.rho,_exception);
3277  break;
3278  }
3279  if (LocaleCompare("rotational-blur",option+1) == 0)
3280  {
3281  flags=ParseGeometry(arg1,&geometry_info);
3282  if ((flags & RhoValue) == 0)
3283  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3284  new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3285  break;
3286  }
3287  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3288  }
3289  case 's':
3290  {
3291  if (LocaleCompare("sample",option+1) == 0)
3292  {
3293  /* FUTURE: Roll into a resize special operator */
3294  if (IsGeometry(arg1) == MagickFalse)
3295  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3296  (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3297  new_image=SampleImage(_image,geometry.width,geometry.height,
3298  _exception);
3299  break;
3300  }
3301  if (LocaleCompare("scale",option+1) == 0)
3302  {
3303  /* FUTURE: Roll into a resize special operator */
3304  if (IsGeometry(arg1) == MagickFalse)
3305  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3306  (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3307  new_image=ScaleImage(_image,geometry.width,geometry.height,
3308  _exception);
3309  break;
3310  }
3311  if (LocaleCompare("segment",option+1) == 0)
3312  {
3313  flags=ParseGeometry(arg1,&geometry_info);
3314  if ((flags & (RhoValue|SigmaValue)) == 0)
3315  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3316  if ((flags & SigmaValue) == 0)
3317  geometry_info.sigma=1.0;
3318  (void) SegmentImage(_image,_image->colorspace,
3319  _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3320  _exception);
3321  break;
3322  }
3323  if (LocaleCompare("selective-blur",option+1) == 0)
3324  {
3325  flags=ParseGeometry(arg1,&geometry_info);
3326  if ((flags & (RhoValue|SigmaValue)) == 0)
3327  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3328  if ((flags & SigmaValue) == 0)
3329  geometry_info.sigma=1.0;
3330  if ((flags & PercentValue) != 0)
3331  geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3332  new_image=SelectiveBlurImage(_image,geometry_info.rho,
3333  geometry_info.sigma,geometry_info.xi,_exception);
3334  break;
3335  }
3336  if (LocaleCompare("separate",option+1) == 0)
3337  {
3338  /* WARNING: This can generate multiple images! */
3339  /* FUTURE - this may be replaced by a "-channel" method */
3340  new_image=SeparateImages(_image,_exception);
3341  break;
3342  }
3343  if (LocaleCompare("sepia-tone",option+1) == 0)
3344  {
3345  if (IsGeometry(arg1) == MagickFalse)
3346  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3347  new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3348  (double) QuantumRange+1.0),_exception);
3349  break;
3350  }
3351  if (LocaleCompare("shade",option+1) == 0)
3352  {
3353  flags=ParseGeometry(arg1,&geometry_info);
3354  if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3355  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3356  new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3357  geometry_info.sigma,_exception);
3358  break;
3359  }
3360  if (LocaleCompare("shadow",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=4.0;
3369  if ((flags & PsiValue) == 0)
3370  geometry_info.psi=4.0;
3371  new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3372  (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3373  ceil(geometry_info.psi-0.5),_exception);
3374  break;
3375  }
3376  if (LocaleCompare("sharpen",option+1) == 0)
3377  {
3378  flags=ParseGeometry(arg1,&geometry_info);
3379  if ((flags & (RhoValue|SigmaValue)) == 0)
3380  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3381  if ((flags & SigmaValue) == 0)
3382  geometry_info.sigma=1.0;
3383  if ((flags & XiValue) == 0)
3384  geometry_info.xi=0.0;
3385  new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3386  _exception);
3387  break;
3388  }
3389  if (LocaleCompare("shave",option+1) == 0)
3390  {
3391  if (IsGeometry(arg1) == MagickFalse)
3392  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3393  flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3394  new_image=ShaveImage(_image,&geometry,_exception);
3395  break;
3396  }
3397  if (LocaleCompare("shear",option+1) == 0)
3398  {
3399  flags=ParseGeometry(arg1,&geometry_info);
3400  if ((flags & RhoValue) == 0)
3401  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3402  if ((flags & SigmaValue) == 0)
3403  geometry_info.sigma=geometry_info.rho;
3404  new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3405  _exception);
3406  break;
3407  }
3408  if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3409  {
3410  flags=ParseGeometry(arg1,&geometry_info);
3411  if ((flags & RhoValue) == 0)
3412  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3413  if ((flags & SigmaValue) == 0)
3414  geometry_info.sigma=(double) QuantumRange/2.0;
3415  if ((flags & PercentValue) != 0)
3416  geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3417  100.0;
3418  (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3419  geometry_info.sigma,_exception);
3420  break;
3421  }
3422  if (LocaleCompare("sketch",option+1) == 0)
3423  {
3424  flags=ParseGeometry(arg1,&geometry_info);
3425  if ((flags & (RhoValue|SigmaValue)) == 0)
3426  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3427  if ((flags & SigmaValue) == 0)
3428  geometry_info.sigma=1.0;
3429  new_image=SketchImage(_image,geometry_info.rho,
3430  geometry_info.sigma,geometry_info.xi,_exception);
3431  break;
3432  }
3433  if (LocaleCompare("solarize",option+1) == 0)
3434  {
3435  if (IsGeometry(arg1) == MagickFalse)
3436  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3437  (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3438  QuantumRange+1.0),_exception);
3439  break;
3440  }
3441  if (LocaleCompare("sort-pixels",option+1) == 0)
3442  {
3443  (void) SortImagePixels(_image,_exception);
3444  break;
3445  }
3446  if (LocaleCompare("sparse-color",option+1) == 0)
3447  {
3448  parse=ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3449  if (parse < 0)
3450  CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3451  option,arg1);
3452  new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3453  _exception);
3454  break;
3455  }
3456  if (LocaleCompare("splice",option+1) == 0)
3457  {
3458  if (IsGeometry(arg1) == MagickFalse)
3459  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3460  flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3461  new_image=SpliceImage(_image,&geometry,_exception);
3462  break;
3463  }
3464  if (LocaleCompare("spread",option+1) == 0)
3465  {
3466  flags=ParseGeometry(arg1,&geometry_info);
3467  if ((flags & RhoValue) == 0)
3468  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3469  new_image=SpreadImage(_image,_image->interpolate,geometry_info.rho,
3470  _exception);
3471  break;
3472  }
3473  if (LocaleCompare("statistic",option+1) == 0)
3474  {
3475  parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3476  if ( parse < 0 )
3477  CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3478  option,arg1);
3479  flags=ParseGeometry(arg2,&geometry_info);
3480  if ((flags & RhoValue) == 0)
3481  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3482  if ((flags & SigmaValue) == 0)
3483  geometry_info.sigma=geometry_info.rho;
3484  new_image=StatisticImage(_image,(StatisticType)parse,
3485  (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3486  _exception);
3487  break;
3488  }
3489  if (LocaleCompare("strip",option+1) == 0)
3490  {
3491  (void) StripImage(_image,_exception);
3492  break;
3493  }
3494  if (LocaleCompare("swirl",option+1) == 0)
3495  {
3496  flags=ParseGeometry(arg1,&geometry_info);
3497  if ((flags & RhoValue) == 0)
3498  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3499  new_image=SwirlImage(_image,geometry_info.rho,
3500  _image->interpolate,_exception);
3501  break;
3502  }
3503  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3504  }
3505  case 't':
3506  {
3507  if (LocaleCompare("threshold",option+1) == 0)
3508  {
3509  double
3510  threshold;
3511 
3512  threshold=(double) QuantumRange/2;
3513  if (IfNormalOp) {
3514  if (IsGeometry(arg1) == MagickFalse)
3515  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3516  threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3517  }
3518  (void) BilevelImage(_image,threshold,_exception);
3519  break;
3520  }
3521  if (LocaleCompare("thumbnail",option+1) == 0)
3522  {
3523  if (IsGeometry(arg1) == MagickFalse)
3524  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3525  (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3526  new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3527  _exception);
3528  break;
3529  }
3530  if (LocaleCompare("tint",option+1) == 0)
3531  {
3532  if (IsGeometry(arg1) == MagickFalse)
3533  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3534  new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3535  break;
3536  }
3537  if (LocaleCompare("transform",option+1) == 0)
3538  {
3539  CLIWandWarnReplaced("+distort AffineProjection");
3540  new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3541  break;
3542  }
3543  if (LocaleCompare("transparent",option+1) == 0)
3544  {
3545  PixelInfo
3546  target;
3547 
3548  (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3549  (void) TransparentPaintImage(_image,&target,(Quantum)
3550  TransparentAlpha,IsPlusOp,_exception);
3551  break;
3552  }
3553  if (LocaleCompare("transpose",option+1) == 0)
3554  {
3555  new_image=TransposeImage(_image,_exception);
3556  break;
3557  }
3558  if (LocaleCompare("transverse",option+1) == 0)
3559  {
3560  new_image=TransverseImage(_image,_exception);
3561  break;
3562  }
3563  if (LocaleCompare("trim",option+1) == 0)
3564  {
3565  new_image=TrimImage(_image,_exception);
3566  break;
3567  }
3568  if (LocaleCompare("type",option+1) == 0)
3569  {
3570  /* Note that "type" setting should have already been defined */
3571  (void) SetImageType(_image,_image_info->type,_exception);
3572  break;
3573  }
3574  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3575  }
3576  case 'u':
3577  {
3578  if (LocaleCompare("unique",option+1) == 0)
3579  {
3580  /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3581  Option is not documented, bt appears to be for "identify".
3582  We may need a identify specific verbose!
3583  */
3584  if (IsPlusOp) {
3585  (void) DeleteImageArtifact(_image,"identify:unique-colors");
3586  break;
3587  }
3588  (void) SetImageArtifact(_image,"identify:unique-colors","true");
3589  (void) SetImageArtifact(_image,"verbose","true");
3590  break;
3591  }
3592  if (LocaleCompare("unique-colors",option+1) == 0)
3593  {
3594  new_image=UniqueImageColors(_image,_exception);
3595  break;
3596  }
3597  if (LocaleCompare("unsharp",option+1) == 0)
3598  {
3599  flags=ParseGeometry(arg1,&geometry_info);
3600  if ((flags & (RhoValue|SigmaValue)) == 0)
3601  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3602  if ((flags & SigmaValue) == 0)
3603  geometry_info.sigma=1.0;
3604  if ((flags & XiValue) == 0)
3605  geometry_info.xi=1.0;
3606  if ((flags & PsiValue) == 0)
3607  geometry_info.psi=0.05;
3608  new_image=UnsharpMaskImage(_image,geometry_info.rho,
3609  geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3610  break;
3611  }
3612  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3613  }
3614  case 'v':
3615  {
3616  if (LocaleCompare("verbose",option+1) == 0)
3617  {
3618  /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3619  three places! ImageArtifact ImageOption _image_info->verbose
3620  Some how new images also get this artifact!
3621  */
3622  (void) SetImageArtifact(_image,option+1,IfNormalOp ? "true" :
3623  "false" );
3624  break;
3625  }
3626  if (LocaleCompare("vignette",option+1) == 0)
3627  {
3628  flags=ParseGeometry(arg1,&geometry_info);
3629  if ((flags & (RhoValue|SigmaValue)) == 0)
3630  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3631  if ((flags & SigmaValue) == 0)
3632  geometry_info.sigma=1.0;
3633  if ((flags & XiValue) == 0)
3634  geometry_info.xi=0.1*_image->columns;
3635  if ((flags & PsiValue) == 0)
3636  geometry_info.psi=0.1*_image->rows;
3637  if ((flags & PercentValue) != 0)
3638  {
3639  geometry_info.xi*=(double) _image->columns/100.0;
3640  geometry_info.psi*=(double) _image->rows/100.0;
3641  }
3642  new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3643  (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3644  ceil(geometry_info.psi-0.5),_exception);
3645  break;
3646  }
3647  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3648  }
3649  case 'w':
3650  {
3651  if (LocaleCompare("wave",option+1) == 0)
3652  {
3653  flags=ParseGeometry(arg1,&geometry_info);
3654  if ((flags & (RhoValue|SigmaValue)) == 0)
3655  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3656  if ((flags & SigmaValue) == 0)
3657  geometry_info.sigma=1.0;
3658  new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3659  _image->interpolate,_exception);
3660  break;
3661  }
3662  if (LocaleCompare("wavelet-denoise",option+1) == 0)
3663  {
3664  flags=ParseGeometry(arg1,&geometry_info);
3665  if ((flags & RhoValue) == 0)
3666  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3667  if ((flags & PercentValue) != 0)
3668  {
3669  geometry_info.rho=QuantumRange*geometry_info.rho/100.0;
3670  geometry_info.sigma=QuantumRange*geometry_info.sigma/100.0;
3671  }
3672  if ((flags & SigmaValue) == 0)
3673  geometry_info.sigma=0.0;
3674  new_image=WaveletDenoiseImage(_image,geometry_info.rho,
3675  geometry_info.sigma,_exception);
3676  break;
3677  }
3678  if (LocaleCompare("white-balance",option+1) == 0)
3679  {
3680  (void) WhiteBalanceImage(_image,_exception);
3681  break;
3682  }
3683  if (LocaleCompare("white-threshold",option+1) == 0)
3684  {
3685  if (IsGeometry(arg1) == MagickFalse)
3686  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3687  (void) WhiteThresholdImage(_image,arg1,_exception);
3688  break;
3689  }
3690  if (LocaleCompare("write-mask",option+1) == 0)
3691  {
3692  /* Note: arguments do not have percent escapes expanded */
3693  Image
3694  *mask;
3695 
3696  if (IfPlusOp)
3697  { /* Remove a mask. */
3698  (void) SetImageMask(_image,WritePixelMask,(Image *) NULL,
3699  _exception);
3700  break;
3701  }
3702  /* Set the image mask. */
3704  if (mask == (Image *) NULL)
3705  break;
3706  (void) SetImageMask(_image,WritePixelMask,mask,_exception);
3707  mask=DestroyImage(mask);
3708  break;
3709  }
3710  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3711  }
3712  default:
3713  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3714  }
3715  /* clean up percent escape interpreted strings */
3716  if (arg1 != arg1n )
3717  arg1=DestroyString((char *)arg1);
3718  if (arg2 != arg2n )
3719  arg2=DestroyString((char *)arg2);
3720 
3721  /* Replace current image with any image that was generated
3722  and set image point to last image (so image->next is correct) */
3723  if (new_image != (Image *) NULL)
3724  ReplaceImageInListReturnLast(&_image,new_image);
3725 
3726  return(MagickTrue);
3727 #undef _image_info
3728 #undef _draw_info
3729 #undef _quantize_info
3730 #undef _image
3731 #undef _exception
3732 #undef IfNormalOp
3733 #undef IfPlusOp
3734 #undef IsNormalOp
3735 #undef IsPlusOp
3736 }
3737 
3738 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3739  const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3740 {
3741 #if !USE_WAND_METHODS
3742  size_t
3743  n,
3744  i;
3745 #endif
3746 
3747  assert(cli_wand != (MagickCLI *) NULL);
3748  assert(cli_wand->signature == MagickWandSignature);
3749  assert(cli_wand->wand.signature == MagickWandSignature);
3750  assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3751 
3752  if (cli_wand->wand.debug != MagickFalse)
3753  (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3754  "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3755 
3756 #if !USE_WAND_METHODS
3757  /* FUTURE add appropriate tracing */
3758  i=0;
3759  n=GetImageListLength(cli_wand->wand.images);
3760  cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3761  while (1) {
3762  i++;
3763  CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3764  if ( cli_wand->wand.images->next == (Image *) NULL )
3765  break;
3766  cli_wand->wand.images=cli_wand->wand.images->next;
3767  }
3768  assert( i == n );
3769  cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3770 #else
3771  MagickResetIterator(&cli_wand->wand);
3772  while (MagickNextImage(&cli_wand->wand) != MagickFalse)
3773  (void) CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3774  MagickResetIterator(&cli_wand->wand);
3775 #endif
3776  return(MagickTrue);
3777 }
3778 
3779 /*
3780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3781 % %
3782 % %
3783 % %
3784 + C L I L i s t O p e r a t o r I m a g e s %
3785 % %
3786 % %
3787 % %
3788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3789 %
3790 % CLIListOperatorImages() applies a single operation that is apply to the
3791 % entire image list as a whole. The result is often a complete replacment
3792 % of the image list with a completely new list, or with just a single image
3793 % result.
3794 %
3795 % The format of the MogrifyImage method is:
3796 %
3797 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3798 % const char *option,const char *arg1,const char *arg2)
3799 %
3800 % A description of each parameter follows:
3801 %
3802 % o cli_wand: structure holding settings to be applied
3803 %
3804 % o option: The option string for the operation
3805 %
3806 % o arg1, arg2: optional argument strings to the operation
3807 % arg2 is currently not used
3808 %
3809 */
3810 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3811  const char *option,const char *arg1n,const char *arg2n)
3812 {
3813  const char /* percent escaped versions of the args */
3814  *arg1,
3815  *arg2;
3816 
3817  Image
3818  *new_images;
3819 
3820  MagickStatusType
3821  status;
3822 
3823  ssize_t
3824  parse;
3825 
3826 #define _image_info (cli_wand->wand.image_info)
3827 #define _images (cli_wand->wand.images)
3828 #define _exception (cli_wand->wand.exception)
3829 #define _draw_info (cli_wand->draw_info)
3830 #define _quantize_info (cli_wand->quantize_info)
3831 #define _process_flags (cli_wand->process_flags)
3832 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3833 #define IfNormalOp (*option=='-')
3834 #define IfPlusOp (*option!='-')
3835 #define IsNormalOp IfNormalOp ? MagickTrue : MagickFalse
3836 
3837  assert(cli_wand != (MagickCLI *) NULL);
3838  assert(cli_wand->signature == MagickWandSignature);
3839  assert(cli_wand->wand.signature == MagickWandSignature);
3840  assert(_images != (Image *) NULL); /* _images must be present */
3841 
3842  if (cli_wand->wand.debug != MagickFalse)
3843  (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3844  "- List Operator: %s \"%s\" \"%s\"", option,
3845  arg1n == (const char *) NULL ? "null" : arg1n,
3846  arg2n == (const char *) NULL ? "null" : arg2n);
3847 
3848  arg1 = arg1n;
3849  arg2 = arg2n;
3850 
3851  /* Interpret Percent Escapes in Arguments - using first image */
3853  || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3854  ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3855  /* Interpret Percent escapes in argument 1 */
3856  if (arg1n != (char *) NULL) {
3857  arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3858  if (arg1 == (char *) NULL) {
3859  CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3860  arg1=arg1n; /* use the given argument as is */
3861  }
3862  }
3863  if (arg2n != (char *) NULL) {
3864  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3865  if (arg2 == (char *) NULL) {
3866  CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3867  arg2=arg2n; /* use the given argument as is */
3868  }
3869  }
3870  }
3871 #undef _process_flags
3872 #undef _option_type
3873 
3874  status=MagickTrue;
3875  new_images=NewImageList();
3876 
3877  switch (*(option+1))
3878  {
3879  case 'a':
3880  {
3881  if (LocaleCompare("append",option+1) == 0)
3882  {
3883  new_images=AppendImages(_images,IsNormalOp,_exception);
3884  break;
3885  }
3886  if (LocaleCompare("average",option+1) == 0)
3887  {
3888  CLIWandWarnReplaced("-evaluate-sequence Mean");
3889  (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",
3890  NULL);
3891  break;
3892  }
3893  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3894  }
3895  case 'c':
3896  {
3897  if (LocaleCompare("channel-fx",option+1) == 0)
3898  {
3899  new_images=ChannelFxImage(_images,arg1,_exception);
3900  break;
3901  }
3902  if (LocaleCompare("clut",option+1) == 0)
3903  {
3904  Image
3905  *clut_image;
3906 
3907  /* FUTURE - make this a compose option, and thus can be used
3908  with layers compose or even compose last image over all other
3909  _images.
3910  */
3911  new_images=RemoveFirstImageFromList(&_images);
3912  clut_image=RemoveFirstImageFromList(&_images);
3913  /* FUTURE - produce Exception, rather than silent fail */
3914  if (clut_image == (Image *) NULL)
3915  {
3916  (void) ThrowMagickException(_exception,GetMagickModule(),
3917  OptionError,"ImageSequenceRequired","`%s'",option);
3918  new_images=DestroyImage(new_images);
3919  status=MagickFalse;
3920  break;
3921  }
3922  (void) ClutImage(new_images,clut_image,new_images->interpolate,
3923  _exception);
3924  clut_image=DestroyImage(clut_image);
3925  break;
3926  }
3927  if (LocaleCompare("coalesce",option+1) == 0)
3928  {
3929  new_images=CoalesceImages(_images,_exception);
3930  break;
3931  }
3932  if (LocaleCompare("combine",option+1) == 0)
3933  {
3934  parse=(ssize_t) _images->colorspace;
3935  if (_images->number_channels < GetImageListLength(_images))
3936  parse=sRGBColorspace;
3937  if ( IfPlusOp )
3938  parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3939  if (parse < 0)
3940  CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3941  arg1);
3942  new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3943  break;
3944  }
3945  if (LocaleCompare("compare",option+1) == 0)
3946  {
3947  double
3948  distortion;
3949 
3950  Image
3951  *image,
3952  *reconstruct_image;
3953 
3954  MetricType
3955  metric;
3956 
3957  /*
3958  Mathematically and visually annotate the difference between an
3959  image and its reconstruction.
3960  */
3961  image=RemoveFirstImageFromList(&_images);
3962  reconstruct_image=RemoveFirstImageFromList(&_images);
3963  /* FUTURE - produce Exception, rather than silent fail */
3964  if (reconstruct_image == (Image *) NULL)
3965  {
3966  (void) ThrowMagickException(_exception,GetMagickModule(),
3967  OptionError,"ImageSequenceRequired","`%s'",option);
3968  image=DestroyImage(image);
3969  status=MagickFalse;
3970  break;
3971  }
3972  metric=UndefinedErrorMetric;
3973  option=GetImageOption(_image_info,"metric");
3974  if (option != (const char *) NULL)
3975  metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3976  MagickFalse,option);
3977  new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3978  _exception);
3979  (void) distortion;
3980  reconstruct_image=DestroyImage(reconstruct_image);
3981  image=DestroyImage(image);
3982  break;
3983  }
3984  if (LocaleCompare("complex",option+1) == 0)
3985  {
3986  parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3987  if (parse < 0)
3988  CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3989  option,arg1);
3990  new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3991  break;
3992  }
3993  if (LocaleCompare("composite",option+1) == 0)
3994  {
3995  CompositeOperator
3996  compose;
3997 
3998  const char*
3999  value;
4000 
4001  MagickBooleanType
4002  clip_to_self;
4003 
4004  Image
4005  *mask_image,
4006  *source_image;
4007 
4008  RectangleInfo
4009  geometry;
4010 
4011  /* Compose value from "-compose" option only */
4012  value=GetImageOption(_image_info,"compose");
4013  if (value == (const char *) NULL)
4014  compose=OverCompositeOp; /* use Over not source_image->compose */
4015  else
4016  compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
4017  MagickFalse,value);
4018 
4019  /* Get "clip-to-self" expert setting (false is normal) */
4020  clip_to_self=GetCompositeClipToSelf(compose);
4021  value=GetImageOption(_image_info,"compose:clip-to-self");
4022  if (value != (const char *) NULL)
4023  clip_to_self=IsStringTrue(value);
4024  value=GetImageOption(_image_info,"compose:outside-overlay");
4025  if (value != (const char *) NULL)
4026  clip_to_self=IsStringFalse(value); /* deprecated */
4027 
4028  new_images=RemoveFirstImageFromList(&_images);
4029  source_image=RemoveFirstImageFromList(&_images);
4030  if (source_image == (Image *) NULL)
4031  {
4032  (void) ThrowMagickException(_exception,GetMagickModule(),
4033  OptionError,"ImageSequenceRequired","`%s'",option);
4034  new_images=DestroyImage(new_images);
4035  status=MagickFalse;
4036  break;
4037  }
4038 
4039  /* FUTURE - this should not be here! - should be part of -geometry */
4040  if (source_image->geometry != (char *) NULL)
4041  {
4042  RectangleInfo
4043  resize_geometry;
4044 
4045  (void) ParseRegionGeometry(source_image,source_image->geometry,
4046  &resize_geometry,_exception);
4047  if ((source_image->columns != resize_geometry.width) ||
4048  (source_image->rows != resize_geometry.height))
4049  {
4050  Image
4051  *resize_image;
4052 
4053  resize_image=ResizeImage(source_image,resize_geometry.width,
4054  resize_geometry.height,source_image->filter,_exception);
4055  if (resize_image != (Image *) NULL)
4056  {
4057  source_image=DestroyImage(source_image);
4058  source_image=resize_image;
4059  }
4060  }
4061  }
4062  SetGeometry(source_image,&geometry);
4063  (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
4064  GravityAdjustGeometry(new_images->columns,new_images->rows,
4065  new_images->gravity, &geometry);
4066  mask_image=RemoveFirstImageFromList(&_images);
4067  if (mask_image == (Image *) NULL)
4068  status&=CompositeImage(new_images,source_image,compose,clip_to_self,
4069  geometry.x,geometry.y,_exception);
4070  else
4071  {
4072  if ((compose == DisplaceCompositeOp) ||
4073  (compose == DistortCompositeOp))
4074  {
4075  status&=CompositeImage(source_image,mask_image,
4076  CopyGreenCompositeOp,MagickTrue,0,0,_exception);
4077  status&=CompositeImage(new_images,source_image,compose,
4078  clip_to_self,geometry.x,geometry.y,_exception);
4079  }
4080  else
4081  {
4082  Image
4083  *clone_image;
4084 
4085  clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
4086  if (clone_image == (Image *) NULL)
4087  break;
4088  status&=CompositeImage(new_images,source_image,compose,
4089  clip_to_self,geometry.x,geometry.y,_exception);
4090  status&=CompositeImage(new_images,mask_image,
4091  CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
4092  status&=CompositeImage(clone_image,new_images,OverCompositeOp,
4093  clip_to_self,0,0,_exception);
4094  new_images=DestroyImageList(new_images);
4095  new_images=clone_image;
4096  }
4097  mask_image=DestroyImage(mask_image);
4098  }
4099  source_image=DestroyImage(source_image);
4100  break;
4101  }
4102  if (LocaleCompare("copy",option+1) == 0)
4103  {
4104  Image
4105  *source_image;
4106 
4107  OffsetInfo
4108  offset;
4109 
4110  RectangleInfo
4111  geometry;
4112 
4113  /*
4114  Copy image pixels.
4115  */
4116  if (IsGeometry(arg1) == MagickFalse)
4117  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4118  if (IsGeometry(arg2) == MagickFalse)
4119  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4120  (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
4121  offset.x=geometry.x;
4122  offset.y=geometry.y;
4123  source_image=_images;
4124  if (source_image->next != (Image *) NULL)
4125  source_image=source_image->next;
4126  (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
4127  (void) CopyImagePixels(_images,source_image,&geometry,&offset,
4128  _exception);
4129  break;
4130  }
4131  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4132  }
4133  case 'd':
4134  {
4135  if (LocaleCompare("deconstruct",option+1) == 0)
4136  {
4137  CLIWandWarnReplaced("-layers CompareAny");
4138  (void) CLIListOperatorImages(cli_wand,"-layers","CompareAny",NULL);
4139  break;
4140  }
4141  if (LocaleCompare("delete",option+1) == 0)
4142  {
4143  if (IfNormalOp)
4144  DeleteImages(&_images,arg1,_exception);
4145  else
4146  DeleteImages(&_images,"-1",_exception);
4147  break;
4148  }
4149  if (LocaleCompare("duplicate",option+1) == 0)
4150  {
4151  if (!IfNormalOp)
4152  new_images=DuplicateImages(_images,1,"-1",_exception);
4153  else
4154  {
4155  const char
4156  *p;
4157 
4158  size_t
4159  number_duplicates;
4160 
4161  if (IsGeometry(arg1) == MagickFalse)
4162  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
4163  arg1);
4164  number_duplicates=(size_t) StringToLong(arg1);
4165  p=strchr(arg1,',');
4166  if (p == (const char *) NULL)
4167  new_images=DuplicateImages(_images,number_duplicates,"-1",
4168  _exception);
4169  else
4170  new_images=DuplicateImages(_images,number_duplicates,p+1,
4171  _exception);
4172  }
4173  AppendImageToList(&_images, new_images);
4174  new_images=(Image *) NULL;
4175  break;
4176  }
4177  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4178  }
4179  case 'e':
4180  {
4181  if (LocaleCompare("evaluate-sequence",option+1) == 0)
4182  {
4183  parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
4184  if (parse < 0)
4185  CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
4186  option,arg1);
4187  new_images=EvaluateImages(_images,(MagickEvaluateOperator) parse,
4188  _exception);
4189  break;
4190  }
4191  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4192  }
4193  case 'f':
4194  {
4195  if (LocaleCompare("fft",option+1) == 0)
4196  {
4197  new_images=ForwardFourierTransformImage(_images,IsNormalOp,
4198  _exception);
4199  break;
4200  }
4201  if (LocaleCompare("flatten",option+1) == 0)
4202  {
4203  /* REDIRECTED to use -layers flatten instead */
4204  (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4205  break;
4206  }
4207  if (LocaleCompare("fx",option+1) == 0)
4208  {
4209  new_images=FxImage(_images,arg1,_exception);
4210  break;
4211  }
4212  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4213  }
4214  case 'h':
4215  {
4216  if (LocaleCompare("hald-clut",option+1) == 0)
4217  {
4218  /* FUTURE - make this a compose option (and thus layers compose )
4219  or perhaps compose last image over all other _images.
4220  */
4221  Image
4222  *hald_image;
4223 
4224  new_images=RemoveFirstImageFromList(&_images);
4225  hald_image=RemoveLastImageFromList(&_images);
4226  if (hald_image == (Image *) NULL)
4227  {
4228  (void) ThrowMagickException(_exception,GetMagickModule(),
4229  OptionError,"ImageSequenceRequired","`%s'",option);
4230  new_images=DestroyImage(new_images);
4231  status=MagickFalse;
4232  break;
4233  }
4234  (void) HaldClutImage(new_images,hald_image,_exception);
4235  hald_image=DestroyImage(hald_image);
4236  break;
4237  }
4238  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4239  }
4240  case 'i':
4241  {
4242  if (LocaleCompare("ift",option+1) == 0)
4243  {
4244  Image
4245  *magnitude_image,
4246  *phase_image;
4247 
4248  magnitude_image=RemoveFirstImageFromList(&_images);
4249  phase_image=RemoveFirstImageFromList(&_images);
4250  if (phase_image == (Image *) NULL)
4251  {
4252  (void) ThrowMagickException(_exception,GetMagickModule(),
4253  OptionError,"ImageSequenceRequired","`%s'",option);
4254  magnitude_image=DestroyImage(magnitude_image);
4255  status=MagickFalse;
4256  break;
4257  }
4258  new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4260  magnitude_image=DestroyImage(magnitude_image);
4261  phase_image=DestroyImage(phase_image);
4262  break;
4263  }
4264  if (LocaleCompare("insert",option+1) == 0)
4265  {
4266  Image
4267  *insert_image,
4268  *index_image;
4269 
4270  ssize_t
4271  index;
4272 
4273  if (IfNormalOp && (IsGeometry(arg1) == MagickFalse))
4274  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4275  index=0;
4276  insert_image=RemoveLastImageFromList(&_images);
4277  if (IfNormalOp)
4278  index=(ssize_t) StringToLong(arg1);
4279  index_image=insert_image;
4280  if (index == 0)
4281  PrependImageToList(&_images,insert_image);
4282  else if (index == (ssize_t) GetImageListLength(_images))
4283  AppendImageToList(&_images,insert_image);
4284  else
4285  {
4286  index_image=GetImageFromList(_images,index-1);
4287  if (index_image == (Image *) NULL)
4288  {
4289  insert_image=DestroyImage(insert_image);
4290  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4291  }
4292  InsertImageInList(&index_image,insert_image);
4293  }
4294  _images=GetFirstImageInList(index_image);
4295  break;
4296  }
4297  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4298  }
4299  case 'l':
4300  {
4301  if (LocaleCompare("layers",option+1) == 0)
4302  {
4303  parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4304  if ( parse < 0 )
4305  CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4306  option,arg1);
4307  switch ((LayerMethod) parse)
4308  {
4309  case CoalesceLayer:
4310  {
4311  new_images=CoalesceImages(_images,_exception);
4312  break;
4313  }
4314  case CompareAnyLayer:
4315  case CompareClearLayer:
4316  case CompareOverlayLayer:
4317  default:
4318  {
4319  new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4320  _exception);
4321  break;
4322  }
4323  case MergeLayer:
4324  case FlattenLayer:
4325  case MosaicLayer:
4326  case TrimBoundsLayer:
4327  {
4328  new_images=MergeImageLayers(_images,(LayerMethod) parse,
4329  _exception);
4330  break;
4331  }
4332  case DisposeLayer:
4333  {
4334  new_images=DisposeImages(_images,_exception);
4335  break;
4336  }
4337  case OptimizeImageLayer:
4338  {
4339  new_images=OptimizeImageLayers(_images,_exception);
4340  break;
4341  }
4342  case OptimizePlusLayer:
4343  {
4344  new_images=OptimizePlusImageLayers(_images,_exception);
4345  break;
4346  }
4347  case OptimizeTransLayer:
4348  {
4349  OptimizeImageTransparency(_images,_exception);
4350  break;
4351  }
4352  case RemoveDupsLayer:
4353  {
4354  RemoveDuplicateLayers(&_images,_exception);
4355  break;
4356  }
4357  case RemoveZeroLayer:
4358  {
4359  RemoveZeroDelayLayers(&_images,_exception);
4360  break;
4361  }
4362  case OptimizeLayer:
4363  { /* General Purpose, GIF Animation Optimizer. */
4364  new_images=CoalesceImages(_images,_exception);
4365  if (new_images == (Image *) NULL)
4366  break;
4367  _images=DestroyImageList(_images);
4368  _images=OptimizeImageLayers(new_images,_exception);
4369  if (_images == (Image *) NULL)
4370  break;
4371  new_images=DestroyImageList(new_images);
4372  OptimizeImageTransparency(_images,_exception);
4373  (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4374  _exception);
4375  break;
4376  }
4377  case CompositeLayer:
4378  {
4379  Image
4380  *source;
4381 
4382  RectangleInfo
4383  geometry;
4384 
4385  CompositeOperator
4386  compose;
4387 
4388  const char*
4389  value;
4390 
4391  value=GetImageOption(_image_info,"compose");
4392  compose=OverCompositeOp; /* Default to Over */
4393  if (value != (const char *) NULL)
4394  compose=(CompositeOperator) ParseCommandOption(
4395  MagickComposeOptions,MagickFalse,value);
4396 
4397  /* Split image sequence at the first 'NULL:' image. */
4398  source=_images;
4399  while (source != (Image *) NULL)
4400  {
4401  source=GetNextImageInList(source);
4402  if ((source != (Image *) NULL) &&
4403  (LocaleCompare(source->magick,"NULL") == 0))
4404  break;
4405  }
4406  if (source != (Image *) NULL)
4407  {
4408  if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4409  (GetNextImageInList(source) == (Image *) NULL))
4410  source=(Image *) NULL;
4411  else
4412  { /* Separate the two lists, junk the null: image. */
4413  source=SplitImageList(source->previous);
4414  DeleteImageFromList(&source);
4415  }
4416  }
4417  if (source == (Image *) NULL)
4418  {
4419  (void) ThrowMagickException(_exception,GetMagickModule(),
4420  OptionError,"MissingNullSeparator","layers Composite");
4421  break;
4422  }
4423  /* Adjust offset with gravity and virtual canvas. */
4424  SetGeometry(_images,&geometry);
4425  (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4426  geometry.width=source->page.width != 0 ?
4427  source->page.width : source->columns;
4428  geometry.height=source->page.height != 0 ?
4429  source->page.height : source->rows;
4430  GravityAdjustGeometry(_images->page.width != 0 ?
4431  _images->page.width : _images->columns,
4432  _images->page.height != 0 ? _images->page.height :
4433  _images->rows,_images->gravity,&geometry);
4434 
4435  /* Compose the two image sequences together */
4436  CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4437  _exception);
4438  source=DestroyImageList(source);
4439  break;
4440  }
4441  }
4442  break;
4443  }
4444  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4445  }
4446  case 'm':
4447  {
4448  if (LocaleCompare("map",option+1) == 0)
4449  {
4450  CLIWandWarnReplaced("+remap");
4451  (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4452  break;
4453  }
4454  if (LocaleCompare("metric",option+1) == 0)
4455  {
4456  (void) SetImageOption(_image_info,option+1,arg1);
4457  break;
4458  }
4459  if (LocaleCompare("morph",option+1) == 0)
4460  {
4461  Image
4462  *morph_image;
4463 
4464  if (IsGeometry(arg1) == MagickFalse)
4465  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4466  morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4467  _exception);
4468  if (morph_image == (Image *) NULL)
4469  break;
4470  _images=DestroyImageList(_images);
4471  _images=morph_image;
4472  break;
4473  }
4474  if (LocaleCompare("mosaic",option+1) == 0)
4475  {
4476  /* REDIRECTED to use -layers mosaic instead */
4477  (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4478  break;
4479  }
4480  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4481  }
4482  case 'p':
4483  {
4484  if (LocaleCompare("poly",option+1) == 0)
4485  {
4486  double
4487  *args;
4488 
4489  ssize_t
4490  count;
4491 
4492  /* convert argument string into an array of doubles */
4493  args = StringToArrayOfDoubles(arg1,&count,_exception);
4494  if (args == (double *) NULL )
4495  CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4496  new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4497  _exception);
4498  args=(double *) RelinquishMagickMemory(args);
4499  break;
4500  }
4501  if (LocaleCompare("process",option+1) == 0)
4502  {
4503  /* FUTURE: better parsing using ScriptToken() from string ??? */
4504  char
4505  **arguments;
4506 
4507  int
4508  j,
4509  number_arguments;
4510 
4511  arguments=StringToArgv(arg1,&number_arguments);
4512  if (arguments == (char **) NULL)
4513  break;
4514  if (strchr(arguments[1],'=') != (char *) NULL)
4515  {
4516  char
4517  breaker,
4518  quote,
4519  *token;
4520 
4521  const char
4522  *arguments;
4523 
4524  int
4525  next,
4526  status;
4527 
4528  size_t
4529  length;
4530 
4531  TokenInfo
4532  *token_info;
4533 
4534  /*
4535  Support old style syntax, filter="-option arg1".
4536  */
4537  assert(arg1 != (const char *) NULL);
4538  length=strlen(arg1);
4539  token=(char *) NULL;
4540  if (~length >= (MagickPathExtent-1))
4541  token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4542  sizeof(*token));
4543  if (token == (char *) NULL)
4544  break;
4545  next=0;
4546  arguments=arg1;
4547  token_info=AcquireTokenInfo();
4548  status=Tokenizer(token_info,0,token,length,arguments,"","=",
4549  "\"",'\0',&breaker,&next,&quote);
4550  token_info=DestroyTokenInfo(token_info);
4551  if (status == 0)
4552  {
4553  const char
4554  *argv;
4555 
4556  argv=(&(arguments[next]));
4557  (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4558  _exception);
4559  }
4560  token=DestroyString(token);
4561  break;
4562  }
4563  (void) SubstituteString(&arguments[1],"-","");
4564  (void) InvokeDynamicImageFilter(arguments[1],&_images,
4565  number_arguments-2,(const char **) arguments+2,_exception);
4566  for (j=0; j < number_arguments; j++)
4567  arguments[j]=DestroyString(arguments[j]);
4568  arguments=(char **) RelinquishMagickMemory(arguments);
4569  break;
4570  }
4571  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4572  }
4573  case 'r':
4574  {
4575  if (LocaleCompare("remap",option+1) == 0)
4576  {
4577  (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4578  break;
4579  }
4580  if (LocaleCompare("reverse",option+1) == 0)
4581  {
4582  ReverseImageList(&_images);
4583  break;
4584  }
4585  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4586  }
4587  case 's':
4588  {
4589  if (LocaleCompare("smush",option+1) == 0)
4590  {
4591  /* FUTURE: this option needs more work to make better */
4592  ssize_t
4593  offset;
4594 
4595  if (IsGeometry(arg1) == MagickFalse)
4596  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4597  offset=(ssize_t) StringToLong(arg1);
4598  new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4599  break;
4600  }
4601  if (LocaleCompare("subimage",option+1) == 0)
4602  {
4603  Image
4604  *base_image,
4605  *compare_image;
4606 
4607  const char
4608  *value;
4609 
4610  MetricType
4611  metric;
4612 
4613  double
4614  similarity;
4615 
4616  RectangleInfo
4617  offset;
4618 
4619  base_image=GetImageFromList(_images,0);
4620  compare_image=GetImageFromList(_images,1);
4621 
4622  /* Comparision Metric */
4623  metric=UndefinedErrorMetric;
4624  value=GetImageOption(_image_info,"metric");
4625  if (value != (const char *) NULL)
4626  metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4627  MagickFalse,value);
4628 
4629  new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4630  &offset,&similarity,_exception);
4631 
4632  if (new_images != (Image *) NULL)
4633  {
4634  (void) FormatImageProperty(new_images,"subimage:similarity",
4635  "%.*g",GetMagickPrecision(),similarity);
4636  (void) FormatImageProperty(new_images,"subimage:x","%+ld",(long)
4637  offset.x);
4638  (void) FormatImageProperty(new_images,"subimage:y","%+ld",(long)
4639  offset.y);
4640  (void) FormatImageProperty(new_images,"subimage:offset",
4641  "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4642  offset.height,(long) offset.x,(long) offset.y);
4643  }
4644  break;
4645  }
4646  if (LocaleCompare("swap",option+1) == 0)
4647  {
4648  Image
4649  *p,
4650  *q,
4651  *swap;
4652 
4653  ssize_t
4654  index,
4655  swap_index;
4656 
4657  index=(-1);
4658  swap_index=(-2);
4659  if (IfNormalOp) {
4660  GeometryInfo
4661  geometry_info;
4662 
4663  MagickStatusType
4664  flags;
4665 
4666  swap_index=(-1);
4667  flags=ParseGeometry(arg1,&geometry_info);
4668  if ((flags & RhoValue) == 0)
4669  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4670  index=(ssize_t) geometry_info.rho;
4671  if ((flags & SigmaValue) != 0)
4672  swap_index=(ssize_t) geometry_info.sigma;
4673  }
4674  p=GetImageFromList(_images,index);
4675  q=GetImageFromList(_images,swap_index);
4676  if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4677  if (IfNormalOp)
4678  CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4679  else
4680  CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4681  }
4682  if (p == q)
4683  CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4684  swap=CloneImage(p,0,0,MagickTrue,_exception);
4685  if (swap == (Image *) NULL)
4686  CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4687  option,GetExceptionMessage(errno));
4688  ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4689  ReplaceImageInList(&q,swap);
4690  _images=GetFirstImageInList(q);
4691  break;
4692  }
4693  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4694  }
4695  default:
4696  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4697  }
4698 
4699  /* clean up percent escape interpreted strings */
4700  if (arg1 != arg1n )
4701  arg1=DestroyString((char *)arg1);
4702  if (arg2 != arg2n )
4703  arg2=DestroyString((char *)arg2);
4704 
4705  /* if new image list generated, replace existing image list */
4706  if (new_images == (Image *) NULL)
4707  return(status == 0 ? MagickFalse : MagickTrue);
4708  _images=DestroyImageList(_images);
4709  _images=GetFirstImageInList(new_images);
4710  return(status == 0 ? MagickFalse : MagickTrue);
4711 
4712 #undef _image_info
4713 #undef _images
4714 #undef _exception
4715 #undef _draw_info
4716 #undef _quantize_info
4717 #undef IfNormalOp
4718 #undef IfPlusOp
4719 #undef IsNormalOp
4720 }
4721 
4722 /*
4723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4724 % %
4725 % %
4726 % %
4727 + C L I N o I m a g e O p e r a t i o n s %
4728 % %
4729 % %
4730 % %
4731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4732 %
4733 % CLINoImageOperator() Applies operations that may not actually need images
4734 % in an image list.
4735 %
4736 % The classic operators of this type is "-read", which actually creates
4737 % images even when no images are present. Or image stack operators, which
4738 % can be applied (push or pop) to an empty image list.
4739 %
4740 % Note that these operators may involve other special 'option' prefix
4741 % characters other than '-' or '+', namely parenthesis and braces.
4742 %
4743 % The format of the CLINoImageOption method is:
4744 %
4745 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4746 % const char *arg1, const char *arg2)
4747 %
4748 % A description of each parameter follows:
4749 %
4750 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4751 %
4752 % o option: The special option (with any switch char) to process
4753 %
4754 % o arg1 & arg2: Argument for option, if required
4755 % Currently arg2 is not used.
4756 %
4757 */
4759  const char *option,const char *arg1n,const char *arg2n)
4760 {
4761  const char /* percent escaped versions of the args */
4762  *arg1,
4763  *arg2;
4764 
4765 #define _image_info (cli_wand->wand.image_info)
4766 #define _images (cli_wand->wand.images)
4767 #define _exception (cli_wand->wand.exception)
4768 #define _process_flags (cli_wand->process_flags)
4769 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4770 #define IfNormalOp (*option=='-')
4771 #define IfPlusOp (*option!='-')
4772 
4773  assert(cli_wand != (MagickCLI *) NULL);
4774  assert(cli_wand->signature == MagickWandSignature);
4775  assert(cli_wand->wand.signature == MagickWandSignature);
4776 
4777  if (cli_wand->wand.debug != MagickFalse)
4778  (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4779  "- NoImage Operator: %s \"%s\" \"%s\"", option,
4780  arg1n != (char *) NULL ? arg1n : "",
4781  arg2n != (char *) NULL ? arg2n : "");
4782 
4783  arg1 = arg1n;
4784  arg2 = arg2n;
4785 
4786  /* Interpret Percent Escapes in Arguments - using first image */
4788  || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4789  ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4790  /* Interpret Percent escapes in argument 1 */
4791  if (arg1n != (char *) NULL) {
4792  arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4793  if (arg1 == (char *) NULL) {
4794  CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4795  arg1=arg1n; /* use the given argument as is */
4796  }
4797  }
4798  if (arg2n != (char *) NULL) {
4799  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4800  if (arg2 == (char *) NULL) {
4801  CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4802  arg2=arg2n; /* use the given argument as is */
4803  }
4804  }
4805  }
4806 #undef _process_flags
4807 #undef _option_type
4808 
4809  do { /* break to exit code */
4810  /*
4811  No-op options (ignore these)
4812  */
4813  if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4814  break;
4815  if (LocaleCompare("sans",option+1) == 0) /* one argument */
4816  break;
4817  if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4818  break;
4819  if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4820  break;
4821  if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4822  break;
4823  /*
4824  Image Reading
4825  */
4826  if ( ( LocaleCompare("read",option+1) == 0 ) ||
4827  ( LocaleCompare("--",option) == 0 ) ) {
4828  /* Do Glob filename Expansion for 'arg1' then read all images.
4829  *
4830  * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4831  * (but attaching to the filenames in the generated argument list) any
4832  * [...] read modifiers that may be present.
4833  *
4834  * For example: It will expand '*.gif[20x20]' into a list such as
4835  * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4836  *
4837  * NOTE: In IMv6 this was done globally across all images. This
4838  * meant you could include IM options in '@filename' lists, but you
4839  * could not include comments. Doing it only for image read makes
4840  * it far more secure.
4841  *
4842  * Note: arguments do not have percent escapes expanded for security
4843  * reasons.
4844  */
4845  int argc;
4846  char **argv;
4847  ssize_t i;
4848 
4849  argc = 1;
4850  argv = (char **) &arg1;
4851 
4852  /* Expand 'glob' expressions in the given filename.
4853  Expansion handles any 'coder:' prefix, or read modifiers attached
4854  to the filename, including them in the resulting expanded list.
4855  */
4856  if (ExpandFilenames(&argc,&argv) == MagickFalse)
4857  CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4858  option,GetExceptionMessage(errno));
4859 
4860  /* loop over expanded filename list, and read then all in */
4861  for (i=0; i < (ssize_t) argc; i++) {
4862  Image *
4863  new_images;
4864  if (_image_info->ping != MagickFalse)
4865  new_images=PingImages(_image_info,argv[i],_exception);
4866  else
4867  new_images=ReadImages(_image_info,argv[i],_exception);
4868  AppendImageToList(&_images, new_images);
4869  argv[i]=DestroyString(argv[i]);
4870  }
4871  argv=(char **) RelinquishMagickMemory(argv);
4872  break;
4873  }
4874  /*
4875  Image Writing
4876  Note: Writing a empty image list is valid in specific cases
4877  */
4878  if (LocaleCompare("write",option+1) == 0) {
4879  /* Note: arguments do not have percent escapes expanded */
4880  char
4881  key[MagickPathExtent];
4882 
4883  Image
4884  *write_images;
4885 
4886  ImageInfo
4887  *write_info;
4888 
4889  /* Need images, unless a "null:" output coder is used */
4890  if ( _images == (Image *) NULL ) {
4891  if ( LocaleCompare(arg1,"null:") == 0 )
4892  break;
4893  CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4894  }
4895 
4896  (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4897  (void) DeleteImageRegistry(key);
4898  write_images=_images;
4899  if (IfPlusOp)
4900  write_images=CloneImageList(_images,_exception);
4901  write_info=CloneImageInfo(_image_info);
4902  (void) WriteImages(write_info,write_images,arg1,_exception);
4903  write_info=DestroyImageInfo(write_info);
4904  if (IfPlusOp)
4905  write_images=DestroyImageList(write_images);
4906  break;
4907  }
4908  /*
4909  Parenthesis and Brace operations
4910  */
4911  if (LocaleCompare("(",option) == 0) {
4912  /* stack 'push' images */
4913  Stack
4914  *node;
4915 
4916  size_t
4917  size;
4918 
4919  size=0;
4920  node=cli_wand->image_list_stack;
4921  for ( ; node != (Stack *) NULL; node=node->next)
4922  size++;
4923  if ( size >= MAX_STACK_DEPTH )
4924  CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4925  node=(Stack *) AcquireMagickMemory(sizeof(*node));
4926  if (node == (Stack *) NULL)
4927  CLIWandExceptionBreak(ResourceLimitFatalError,
4928  "MemoryAllocationFailed",option);
4929  node->data = (void *)cli_wand->wand.images;
4930  node->next = cli_wand->image_list_stack;
4931  cli_wand->image_list_stack = node;
4932  cli_wand->wand.images = NewImageList();
4933 
4934  /* handle respect-parenthesis */
4935  if (IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4936  "respect-parenthesis")) != MagickFalse)
4937  option="{"; /* fall-thru so as to push image settings too */
4938  else
4939  break;
4940  /* fall thru to operation */
4941  }
4942  if (LocaleCompare("{",option) == 0) {
4943  /* stack 'push' of image_info settings */
4944  Stack
4945  *node;
4946 
4947  size_t
4948  size;
4949 
4950  size=0;
4951  node=cli_wand->image_info_stack;
4952  for ( ; node != (Stack *) NULL; node=node->next)
4953  size++;
4954  if ( size >= MAX_STACK_DEPTH )
4955  CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4956  node=(Stack *) AcquireMagickMemory(sizeof(*node));
4957  if (node == (Stack *) NULL)
4958  CLIWandExceptionBreak(ResourceLimitFatalError,
4959  "MemoryAllocationFailed",option);
4960 
4961  node->data = (void *)cli_wand->wand.image_info;
4962  node->next = cli_wand->image_info_stack;
4963 
4964  cli_wand->image_info_stack = node;
4965  cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4966  if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4967  CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4968  option);
4969  cli_wand->wand.image_info = (ImageInfo *)node->data;
4970  node = (Stack *)RelinquishMagickMemory(node);
4971  break;
4972  }
4973 
4974  break;
4975  }
4976  if (LocaleCompare(")",option) == 0) {
4977  /* pop images from stack */
4978  Stack
4979  *node;
4980 
4981  node = (Stack *)cli_wand->image_list_stack;
4982  if ( node == (Stack *) NULL)
4983  CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4984  cli_wand->image_list_stack = node->next;
4985 
4986  AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4987  cli_wand->wand.images= (Image *)node->data;
4988  node = (Stack *)RelinquishMagickMemory(node);
4989 
4990  /* handle respect-parenthesis - of the previous 'pushed' settings */
4991  node = cli_wand->image_info_stack;
4992  if ( node != (Stack *) NULL)
4993  {
4994  if (IsStringTrue(GetImageOption(
4995  cli_wand->wand.image_info,"respect-parenthesis")) != MagickFalse)
4996  option="}"; /* fall-thru so as to pop image settings too */
4997  else
4998  break;
4999  }
5000  else
5001  break;
5002  /* fall thru to next if */
5003  }
5004  if (LocaleCompare("}",option) == 0) {
5005  /* pop image_info settings from stack */
5006  Stack
5007  *node;
5008 
5009  node = (Stack *)cli_wand->image_info_stack;
5010  if ( node == (Stack *) NULL)
5011  CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
5012  cli_wand->image_info_stack = node->next;
5013 
5014  (void) DestroyImageInfo(cli_wand->wand.image_info);
5015  cli_wand->wand.image_info = (ImageInfo *)node->data;
5016  node = (Stack *)RelinquishMagickMemory(node);
5017 
5018  GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
5019  cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
5020  cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
5021 
5022  break;
5023  }
5024  if (LocaleCompare("print",option+1) == 0)
5025  {
5026  (void) FormatLocaleFile(stdout,"%s",arg1);
5027  break;
5028  }
5029  if (LocaleCompare("set",option+1) == 0)
5030  {
5031  /* Settings are applied to each image in memory in turn (if any).
5032  While a option: only need to be applied once globally.
5033 
5034  NOTE: rguments have not been automatically percent expaneded
5035  */
5036 
5037  /* escape the 'key' once only, using first image. */
5038  arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
5039  if (arg1 == (char *) NULL)
5040  CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
5041  option);
5042 
5043  if (LocaleNCompare(arg1,"registry:",9) == 0)
5044  {
5045  if (IfPlusOp)
5046  {
5047  (void) DeleteImageRegistry(arg1+9);
5048  arg1=DestroyString((char *)arg1);
5049  break;
5050  }
5051  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
5052  if (arg2 == (char *) NULL) {
5053  arg1=DestroyString((char *)arg1);
5054  CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
5055  option);
5056  }
5057  (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
5058  arg1=DestroyString((char *)arg1);
5059  arg2=DestroyString((char *)arg2);
5060  break;
5061  }
5062  if (LocaleNCompare(arg1,"option:",7) == 0)
5063  {
5064  /* delete equivelent artifact from all images (if any) */
5065  if (_images != (Image *) NULL)
5066  {
5067  MagickResetIterator(&cli_wand->wand);
5068  while (MagickNextImage(&cli_wand->wand) != MagickFalse)
5069  (void) DeleteImageArtifact(_images,arg1+7);
5070  MagickResetIterator(&cli_wand->wand);
5071  }
5072  /* now set/delete the global option as needed */
5073  /* FUTURE: make escapes in a global 'option:' delayed */
5074  arg2=(char *) NULL;
5075  if (IfNormalOp)
5076  {
5077  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
5078  if (arg2 == (char *) NULL)
5079  CLIWandExceptionBreak(OptionWarning,
5080  "InterpretPropertyFailure",option);
5081  }
5082  (void) SetImageOption(_image_info,arg1+7,arg2);
5083  arg1=DestroyString((char *)arg1);
5084  arg2=DestroyString((char *)arg2);
5085  break;
5086  }
5087  /* Set Artifacts/Properties/Attributes all images (required) */
5088  if ( _images == (Image *) NULL )
5089  CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
5090 
5091  MagickResetIterator(&cli_wand->wand);
5092  while (MagickNextImage(&cli_wand->wand) != MagickFalse)
5093  {
5094  arg2=(char *) NULL;
5095  if (IfNormalOp)
5096  {
5097  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
5098  if (arg2 == (char *) NULL)
5099  CLIWandExceptionBreak(OptionWarning,
5100  "InterpretPropertyFailure",option);
5101  }
5102  if (LocaleNCompare(arg1,"artifact:",9) == 0)
5103  (void) SetImageArtifact(_images,arg1+9,arg2);
5104  else if (LocaleNCompare(arg1,"property:",9) == 0)
5105  (void) SetImageProperty(_images,arg1+9,arg2,_exception);
5106  else
5107  (void) SetImageProperty(_images,arg1,arg2,_exception);
5108  arg2=DestroyString((char *)arg2);
5109  }
5110  MagickResetIterator(&cli_wand->wand);
5111  arg1=DestroyString((char *)arg1);
5112  break;
5113  }
5114  if (LocaleCompare("clone",option+1) == 0) {
5115  Image
5116  *new_images;
5117 
5118  if (*option == '+')
5119  arg1=AcquireString("-1");
5120  if (IsSceneGeometry(arg1,MagickFalse) == MagickFalse)
5121  CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
5122  if ( cli_wand->image_list_stack == (Stack *) NULL)
5123  CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5124  new_images = (Image *)cli_wand->image_list_stack->data;
5125  if (new_images == (Image *) NULL)
5126  CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5127  new_images=CloneImages(new_images,arg1,_exception);
5128  if (new_images == (Image *) NULL)
5129  CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
5130  AppendImageToList(&_images,new_images);
5131  break;
5132  }
5133  /*
5134  Informational Operations.
5135 
5136  Note that these do not require either a cli-wand or images!
5137  Though currently a cli-wand much be provided regardless.
5138  */
5139  if (LocaleCompare("version",option+1) == 0)
5140  {
5141  ListMagickVersion(stdout);
5142  break;
5143  }
5144  if (LocaleCompare("list",option+1) == 0) {
5145  /*
5146  FUTURE: This 'switch' should really be part of MagickCore
5147  */
5148  ssize_t
5149  list;
5150 
5151  list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
5152  if ( list < 0 ) {
5153  CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
5154  break;
5155  }
5156  switch (list)
5157  {
5158  case MagickCoderOptions:
5159  {
5160  (void) ListCoderInfo((FILE *) NULL,_exception);
5161  break;
5162  }
5163  case MagickColorOptions:
5164  {
5165  (void) ListColorInfo((FILE *) NULL,_exception);
5166  break;
5167  }
5168  case MagickConfigureOptions:
5169  {
5170  (void) ListConfigureInfo((FILE *) NULL,_exception);
5171  break;
5172  }
5173  case MagickDelegateOptions:
5174  {
5175  (void) ListDelegateInfo((FILE *) NULL,_exception);
5176  break;
5177  }
5178  case MagickFontOptions:
5179  {
5180  (void) ListTypeInfo((FILE *) NULL,_exception);
5181  break;
5182  }
5183  case MagickFormatOptions:
5184  (void) ListMagickInfo((FILE *) NULL,_exception);
5185  break;
5186  case MagickLocaleOptions:
5187  (void) ListLocaleInfo((FILE *) NULL,_exception);
5188  break;
5189  case MagickLogOptions:
5190  (void) ListLogInfo((FILE *) NULL,_exception);
5191  break;
5192  case MagickMagicOptions:
5193  (void) ListMagicInfo((FILE *) NULL,_exception);
5194  break;
5195  case MagickMimeOptions:
5196  (void) ListMimeInfo((FILE *) NULL,_exception);
5197  break;
5198  case MagickModuleOptions:
5199  (void) ListModuleInfo((FILE *) NULL,_exception);
5200  break;
5201  case MagickPolicyOptions:
5202  (void) ListPolicyInfo((FILE *) NULL,_exception);
5203  break;
5204  case MagickResourceOptions:
5205  (void) ListMagickResourceInfo((FILE *) NULL,_exception);
5206  break;
5207  case MagickThresholdOptions:
5208  (void) ListThresholdMaps((FILE *) NULL,_exception);
5209  break;
5210  default:
5211  (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
5212  _exception);
5213  break;
5214  }
5215  break;
5216  }
5217 
5218  CLIWandException(OptionError,"UnrecognizedOption",option);
5219 
5220 DisableMSCWarning(4127)
5221  } while (0); /* break to exit code. */
5223 
5224  /* clean up percent escape interpreted strings */
5225  if (arg1 != arg1n )
5226  arg1=DestroyString((char *)arg1);
5227  if (arg2 != arg2n )
5228  arg2=DestroyString((char *)arg2);
5229 
5230 #undef _image_info
5231 #undef _images
5232 #undef _exception
5233 #undef IfNormalOp
5234 #undef IfPlusOp
5235 }
5236 
5237 /*
5238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5239 % %
5240 % %
5241 % %
5242 + C L I O p t i o n %
5243 % %
5244 % %
5245 % %
5246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5247 %
5248 % CLIOption() Processes the given option using the given CLI Magick Wand.
5249 % The option arguments can be variable in number, though at this time no more
5250 % that two is actually used by any option (this may change). Excess options
5251 % are simply ignored.
5252 %
5253 % If the cli_wand->command pointer is non-null, then it is assumed that the
5254 % option has already been search for up from the CommandOptions[] table in
5255 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
5256 % routine will do the lookup instead. The pointer is reset afterward.
5257 %
5258 % This action allows the caller to lookup and pre-handle any 'special'
5259 % options, (such as implicit reads) before calling this general option
5260 % handler to deal with 'standard' command line options.
5261 %
5262 % The format of the CLIOption method is:
5263 %
5264 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5265 %
5266 % A description of each parameter follows:
5267 %
5268 % o cli_wand: the main CLI Wand to use.
5269 %
5270 % o option: The special option (with any switch char) to process
5271 %
5272 % o args: any required arguments for an option (variable number)
5273 %
5274 % Example Usage...
5275 %
5276 % CLIoption(cli_wand,"-read","rose:");
5277 % CLIoption(cli_wand,"-virtual-pixel","transparent");
5278 % CLIoption(cli_wand,"-distort","SRT:","30");
5279 % CLIoption(cli_wand,"-write","rotated_rose.png");
5280 %
5281 */
5282 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5283 {
5284  const char /* extracted option args from args */
5285  *arg1,
5286  *arg2;
5287 
5288  CommandOptionFlags
5289  option_type;
5290 
5291  assert(cli_wand != (MagickCLI *) NULL);
5292  assert(cli_wand->signature == MagickWandSignature);
5293  assert(cli_wand->wand.signature == MagickWandSignature);
5294 
5295  do { /* Break Code Block for error handling */
5296 
5297  /* get information about option */
5298  if ( cli_wand->command == (const OptionInfo *) NULL )
5299  cli_wand->command = GetCommandOptionInfo(option);
5300 #if 0
5301  (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5302  option, cli_wand->command->mnemonic );
5303 #endif
5304  option_type=(CommandOptionFlags) cli_wand->command->flags;
5305 
5306  if ( option_type == UndefinedOptionFlag )
5307  CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5308 
5309  assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5310 
5311  /* deprecated options */
5312  if ( (option_type & DeprecateOptionFlag) != 0 )
5313  CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5314 
5315  /* options that this module does not handle */
5316  if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5317  CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5318 
5319  /* Get argument strings from VarArgs
5320  How can you determine if enough arguments was supplied?
5321  What happens if not enough arguments were supplied?
5322  */
5323  { size_t
5324  count = (size_t) cli_wand->command->type;
5325 
5326  va_list
5327  operands;
5328 
5329  va_start(operands,option);
5330 
5331  arg1=arg2=NULL;
5332  if ( count >= 1 )
5333  arg1=(const char *) va_arg(operands, const char *);
5334  if ( count >= 2 )
5335  arg2=(const char *) va_arg(operands, const char *);
5336 
5337  va_end(operands);
5338 #if 0
5339  (void) FormatLocaleFile(stderr,
5340  "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5341  option,(long) count,option_type,arg1,arg2);
5342 #endif
5343  }
5344 
5345  /*
5346  Call the appropriate option handler
5347  */
5348 
5349  /* FUTURE: this is temporary - get 'settings' to handle distribution of
5350  settings to images attributes,proprieties,artifacts */
5351  if ( cli_wand->wand.images != (Image *) NULL )
5352  (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5353  cli_wand->wand.exception);
5354 
5355  if ( (option_type & SettingOptionFlags) != 0 ) {
5356  CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5357  /*
5358  FUTURE: Sync Specific Settings into Image Properities (not global)
5359  */
5360  }
5361 
5362  /* Operators that do not need images - read, write, stack, clone */
5363  if ((option_type & NoImageOperatorFlag) != 0)
5364  CLINoImageOperator(cli_wand, option, arg1, arg2);
5365 
5366  /* FUTURE: The not a setting part below is a temporary hack due to
5367  * some options being both a Setting and a Simple operator.
5368  * Specifically -monitor, -depth, and -colorspace */
5369  if ( cli_wand->wand.images == (Image *) NULL )
5370  if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5371  ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5372  CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5373 
5374  /* Operators which loop of individual images, simply */
5375  if ( (option_type & SimpleOperatorFlag) != 0 &&
5376  cli_wand->wand.images != (Image *) NULL) /* temp hack */
5377  {
5378  ExceptionInfo *exception=AcquireExceptionInfo();
5379  (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5380  exception=DestroyExceptionInfo(exception);
5381  }
5382 
5383  /* Operators that work on the image list as a whole */
5384  if ( (option_type & ListOperatorFlag) != 0 )
5385  (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5386 
5387 DisableMSCWarning(4127)
5388  } while (0); /* end Break code block */
5390 
5391  cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
5392 }
#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:315
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:4758
MagickBooleanType debug
struct _MagickWand wand
#define CLIWandExceptionReturn(severity, tag, option)
#define RestoreMSCWarning
Definition: studio.h:316
#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:5282
#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:3810
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:3738
#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