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