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