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