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=RemoveLastImageFromList(&_images);
3825  /* FUTURE - produce Exception, rather than silent fail */
3826  if (clut_image == (Image *) NULL)
3827  break;
3828  (void) ClutImage(new_images,clut_image,new_images->interpolate,
3829  _exception);
3830  clut_image=DestroyImage(clut_image);
3831  break;
3832  }
3833  if (LocaleCompare("coalesce",option+1) == 0)
3834  {
3835  new_images=CoalesceImages(_images,_exception);
3836  break;
3837  }
3838  if (LocaleCompare("combine",option+1) == 0)
3839  {
3840  parse=(ssize_t) _images->colorspace;
3841  if (_images->number_channels < GetImageListLength(_images))
3842  parse=sRGBColorspace;
3843  if ( IfPlusOp )
3844  parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3845  if (parse < 0)
3846  CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3847  arg1);
3848  new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3849  break;
3850  }
3851  if (LocaleCompare("compare",option+1) == 0)
3852  {
3853  double
3854  distortion;
3855 
3856  Image
3857  *image,
3858  *reconstruct_image;
3859 
3860  MetricType
3861  metric;
3862 
3863  /*
3864  Mathematically and visually annotate the difference between an
3865  image and its reconstruction.
3866  */
3867  image=RemoveFirstImageFromList(&_images);
3868  reconstruct_image=RemoveFirstImageFromList(&_images);
3869  /* FUTURE - produce Exception, rather than silent fail */
3870  if (reconstruct_image == (Image *) NULL)
3871  break;
3872  metric=UndefinedErrorMetric;
3873  option=GetImageOption(_image_info,"metric");
3874  if (option != (const char *) NULL)
3875  metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3876  MagickFalse,option);
3877  new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3878  _exception);
3879  (void) distortion;
3880  reconstruct_image=DestroyImage(reconstruct_image);
3881  image=DestroyImage(image);
3882  break;
3883  }
3884  if (LocaleCompare("complex",option+1) == 0)
3885  {
3886  parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3887  if (parse < 0)
3888  CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3889  option,arg1);
3890  new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3891  break;
3892  }
3893  if (LocaleCompare("composite",option+1) == 0)
3894  {
3895  CompositeOperator
3896  compose;
3897 
3898  const char*
3899  value;
3900 
3901  MagickBooleanType
3902  clip_to_self;
3903 
3904  Image
3905  *mask_image,
3906  *source_image;
3907 
3908  RectangleInfo
3909  geometry;
3910 
3911  /* Compose value from "-compose" option only */
3912  value=GetImageOption(_image_info,"compose");
3913  if (value == (const char *) NULL)
3914  compose=OverCompositeOp; /* use Over not source_image->compose */
3915  else
3916  compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3917  MagickFalse,value);
3918 
3919  /* Get "clip-to-self" expert setting (false is normal) */
3920  clip_to_self=GetCompositeClipToSelf(compose);
3921  value=GetImageOption(_image_info,"compose:clip-to-self");
3922  if (value != (const char *) NULL)
3923  clip_to_self=IsStringTrue(value);
3924  value=GetImageOption(_image_info,"compose:outside-overlay");
3925  if (value != (const char *) NULL)
3926  clip_to_self=IsStringFalse(value); /* deprecated */
3927 
3928  new_images=RemoveFirstImageFromList(&_images);
3929  source_image=RemoveFirstImageFromList(&_images);
3930  if (source_image == (Image *) NULL)
3931  break; /* FUTURE - produce Exception, rather than silent fail */
3932 
3933  /* FUTURE - this should not be here! - should be part of -geometry */
3934  if (source_image->geometry != (char *) NULL)
3935  {
3936  RectangleInfo
3937  resize_geometry;
3938 
3939  (void) ParseRegionGeometry(source_image,source_image->geometry,
3940  &resize_geometry,_exception);
3941  if ((source_image->columns != resize_geometry.width) ||
3942  (source_image->rows != resize_geometry.height))
3943  {
3944  Image
3945  *resize_image;
3946 
3947  resize_image=ResizeImage(source_image,resize_geometry.width,
3948  resize_geometry.height,source_image->filter,_exception);
3949  if (resize_image != (Image *) NULL)
3950  {
3951  source_image=DestroyImage(source_image);
3952  source_image=resize_image;
3953  }
3954  }
3955  }
3956  SetGeometry(source_image,&geometry);
3957  (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3958  GravityAdjustGeometry(new_images->columns,new_images->rows,
3959  new_images->gravity, &geometry);
3960  mask_image=RemoveFirstImageFromList(&_images);
3961  if (mask_image == (Image *) NULL)
3962  status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3963  geometry.x,geometry.y,_exception);
3964  else
3965  {
3966  if ((compose == DisplaceCompositeOp) ||
3967  (compose == DistortCompositeOp))
3968  {
3969  status&=CompositeImage(source_image,mask_image,
3970  CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3971  status&=CompositeImage(new_images,source_image,compose,
3972  clip_to_self,geometry.x,geometry.y,_exception);
3973  }
3974  else
3975  {
3976  Image
3977  *clone_image;
3978 
3979  clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
3980  if (clone_image == (Image *) NULL)
3981  break;
3982  status&=CompositeImage(new_images,source_image,compose,
3983  clip_to_self,geometry.x,geometry.y,_exception);
3984  status&=CompositeImage(new_images,mask_image,
3985  CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
3986  status&=CompositeImage(clone_image,new_images,OverCompositeOp,
3987  clip_to_self,0,0,_exception);
3988  new_images=DestroyImage(new_images);
3989  new_images=clone_image;
3990  }
3991  mask_image=DestroyImage(mask_image);
3992  }
3993  source_image=DestroyImage(source_image);
3994  break;
3995  }
3996  if (LocaleCompare("copy",option+1) == 0)
3997  {
3998  Image
3999  *source_image;
4000 
4001  OffsetInfo
4002  offset;
4003 
4004  RectangleInfo
4005  geometry;
4006 
4007  /*
4008  Copy image pixels.
4009  */
4010  if (IsGeometry(arg1) == MagickFalse)
4011  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4012  if (IsGeometry(arg2) == MagickFalse)
4013  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4014  (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
4015  offset.x=geometry.x;
4016  offset.y=geometry.y;
4017  source_image=_images;
4018  if (source_image->next != (Image *) NULL)
4019  source_image=source_image->next;
4020  (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
4021  (void) CopyImagePixels(_images,source_image,&geometry,&offset,
4022  _exception);
4023  break;
4024  }
4025  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4026  }
4027  case 'd':
4028  {
4029  if (LocaleCompare("deconstruct",option+1) == 0)
4030  {
4031  CLIWandWarnReplaced("-layer CompareAny");
4032  (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
4033  break;
4034  }
4035  if (LocaleCompare("delete",option+1) == 0)
4036  {
4037  if (IfNormalOp)
4038  DeleteImages(&_images,arg1,_exception);
4039  else
4040  DeleteImages(&_images,"-1",_exception);
4041  break;
4042  }
4043  if (LocaleCompare("duplicate",option+1) == 0)
4044  {
4045  if (IfNormalOp)
4046  {
4047  const char
4048  *p;
4049 
4050  size_t
4051  number_duplicates;
4052 
4053  if (IsGeometry(arg1) == MagickFalse)
4054  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
4055  arg1);
4056  number_duplicates=(size_t) StringToLong(arg1);
4057  p=strchr(arg1,',');
4058  if (p == (const char *) NULL)
4059  new_images=DuplicateImages(_images,number_duplicates,"-1",
4060  _exception);
4061  else
4062  new_images=DuplicateImages(_images,number_duplicates,p,
4063  _exception);
4064  }
4065  else
4066  new_images=DuplicateImages(_images,1,"-1",_exception);
4067  AppendImageToList(&_images, new_images);
4068  new_images=(Image *) NULL;
4069  break;
4070  }
4071  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4072  }
4073  case 'e':
4074  {
4075  if (LocaleCompare("evaluate-sequence",option+1) == 0)
4076  {
4077  parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
4078  if (parse < 0)
4079  CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
4080  option,arg1);
4081  new_images=EvaluateImages(_images,(MagickEvaluateOperator) parse,
4082  _exception);
4083  break;
4084  }
4085  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4086  }
4087  case 'f':
4088  {
4089  if (LocaleCompare("fft",option+1) == 0)
4090  {
4091  new_images=ForwardFourierTransformImage(_images,IsNormalOp,
4092  _exception);
4093  break;
4094  }
4095  if (LocaleCompare("flatten",option+1) == 0)
4096  {
4097  /* REDIRECTED to use -layers flatten instead */
4098  (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4099  break;
4100  }
4101  if (LocaleCompare("fx",option+1) == 0)
4102  {
4103  new_images=FxImage(_images,arg1,_exception);
4104  break;
4105  }
4106  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4107  }
4108  case 'h':
4109  {
4110  if (LocaleCompare("hald-clut",option+1) == 0)
4111  {
4112  /* FUTURE - make this a compose option (and thus layers compose )
4113  or perhaps compose last image over all other _images.
4114  */
4115  Image
4116  *hald_image;
4117 
4118  new_images=RemoveFirstImageFromList(&_images);
4119  hald_image=RemoveLastImageFromList(&_images);
4120  if (hald_image == (Image *) NULL)
4121  break;
4122  (void) HaldClutImage(new_images,hald_image,_exception);
4123  hald_image=DestroyImage(hald_image);
4124  break;
4125  }
4126  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4127  }
4128  case 'i':
4129  {
4130  if (LocaleCompare("ift",option+1) == 0)
4131  {
4132  Image
4133  *magnitude_image,
4134  *phase_image;
4135 
4136  magnitude_image=RemoveFirstImageFromList(&_images);
4137  phase_image=RemoveFirstImageFromList(&_images);
4138  /* FUTURE - produce Exception, rather than silent fail */
4139  if (phase_image == (Image *) NULL)
4140  break;
4141  new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4143  magnitude_image=DestroyImage(magnitude_image);
4144  phase_image=DestroyImage(phase_image);
4145  break;
4146  }
4147  if (LocaleCompare("insert",option+1) == 0)
4148  {
4149  Image
4150  *insert_image,
4151  *index_image;
4152 
4153  ssize_t
4154  index;
4155 
4156  if (IfNormalOp && (IsGeometry(arg1) == MagickFalse))
4157  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4158  index=0;
4159  insert_image=RemoveLastImageFromList(&_images);
4160  if (IfNormalOp)
4161  index=(ssize_t) StringToLong(arg1);
4162  index_image=insert_image;
4163  if (index == 0)
4164  PrependImageToList(&_images,insert_image);
4165  else if (index == (ssize_t) GetImageListLength(_images))
4166  AppendImageToList(&_images,insert_image);
4167  else
4168  {
4169  index_image=GetImageFromList(_images,index-1);
4170  if (index_image == (Image *) NULL)
4171  CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4172  InsertImageInList(&index_image,insert_image);
4173  }
4174  _images=GetFirstImageInList(index_image);
4175  break;
4176  }
4177  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4178  }
4179  case 'l':
4180  {
4181  if (LocaleCompare("layers",option+1) == 0)
4182  {
4183  parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4184  if ( parse < 0 )
4185  CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4186  option,arg1);
4187  switch ((LayerMethod) parse)
4188  {
4189  case CoalesceLayer:
4190  {
4191  new_images=CoalesceImages(_images,_exception);
4192  break;
4193  }
4194  case CompareAnyLayer:
4195  case CompareClearLayer:
4196  case CompareOverlayLayer:
4197  default:
4198  {
4199  new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4200  _exception);
4201  break;
4202  }
4203  case MergeLayer:
4204  case FlattenLayer:
4205  case MosaicLayer:
4206  case TrimBoundsLayer:
4207  {
4208  new_images=MergeImageLayers(_images,(LayerMethod) parse,
4209  _exception);
4210  break;
4211  }
4212  case DisposeLayer:
4213  {
4214  new_images=DisposeImages(_images,_exception);
4215  break;
4216  }
4217  case OptimizeImageLayer:
4218  {
4219  new_images=OptimizeImageLayers(_images,_exception);
4220  break;
4221  }
4222  case OptimizePlusLayer:
4223  {
4224  new_images=OptimizePlusImageLayers(_images,_exception);
4225  break;
4226  }
4227  case OptimizeTransLayer:
4228  {
4229  OptimizeImageTransparency(_images,_exception);
4230  break;
4231  }
4232  case RemoveDupsLayer:
4233  {
4234  RemoveDuplicateLayers(&_images,_exception);
4235  break;
4236  }
4237  case RemoveZeroLayer:
4238  {
4239  RemoveZeroDelayLayers(&_images,_exception);
4240  break;
4241  }
4242  case OptimizeLayer:
4243  { /* General Purpose, GIF Animation Optimizer. */
4244  new_images=CoalesceImages(_images,_exception);
4245  if (new_images == (Image *) NULL)
4246  break;
4247  _images=DestroyImageList(_images);
4248  _images=OptimizeImageLayers(new_images,_exception);
4249  if (_images == (Image *) NULL)
4250  break;
4251  new_images=DestroyImageList(new_images);
4252  OptimizeImageTransparency(_images,_exception);
4253  (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4254  _exception);
4255  break;
4256  }
4257  case CompositeLayer:
4258  {
4259  Image
4260  *source;
4261 
4262  RectangleInfo
4263  geometry;
4264 
4265  CompositeOperator
4266  compose;
4267 
4268  const char*
4269  value;
4270 
4271  value=GetImageOption(_image_info,"compose");
4272  compose=OverCompositeOp; /* Default to Over */
4273  if (value != (const char *) NULL)
4274  compose=(CompositeOperator) ParseCommandOption(
4275  MagickComposeOptions,MagickFalse,value);
4276 
4277  /* Split image sequence at the first 'NULL:' image. */
4278  source=_images;
4279  while (source != (Image *) NULL)
4280  {
4281  source=GetNextImageInList(source);
4282  if ((source != (Image *) NULL) &&
4283  (LocaleCompare(source->magick,"NULL") == 0))
4284  break;
4285  }
4286  if (source != (Image *) NULL)
4287  {
4288  if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4289  (GetNextImageInList(source) == (Image *) NULL))
4290  source=(Image *) NULL;
4291  else
4292  { /* Separate the two lists, junk the null: image. */
4293  source=SplitImageList(source->previous);
4294  DeleteImageFromList(&source);
4295  }
4296  }
4297  if (source == (Image *) NULL)
4298  {
4299  (void) ThrowMagickException(_exception,GetMagickModule(),
4300  OptionError,"MissingNullSeparator","layers Composite");
4301  break;
4302  }
4303  /* Adjust offset with gravity and virtual canvas. */
4304  SetGeometry(_images,&geometry);
4305  (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4306  geometry.width=source->page.width != 0 ?
4307  source->page.width : source->columns;
4308  geometry.height=source->page.height != 0 ?
4309  source->page.height : source->rows;
4310  GravityAdjustGeometry(_images->page.width != 0 ?
4311  _images->page.width : _images->columns,
4312  _images->page.height != 0 ? _images->page.height :
4313  _images->rows,_images->gravity,&geometry);
4314 
4315  /* Compose the two image sequences together */
4316  CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4317  _exception);
4318  source=DestroyImageList(source);
4319  break;
4320  }
4321  }
4322  break;
4323  }
4324  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4325  }
4326  case 'm':
4327  {
4328  if (LocaleCompare("map",option+1) == 0)
4329  {
4330  CLIWandWarnReplaced("+remap");
4331  (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4332  break;
4333  }
4334  if (LocaleCompare("metric",option+1) == 0)
4335  {
4336  (void) SetImageOption(_image_info,option+1,arg1);
4337  break;
4338  }
4339  if (LocaleCompare("morph",option+1) == 0)
4340  {
4341  Image
4342  *morph_image;
4343 
4344  if (IsGeometry(arg1) == MagickFalse)
4345  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4346  morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4347  _exception);
4348  if (morph_image == (Image *) NULL)
4349  break;
4350  _images=DestroyImageList(_images);
4351  _images=morph_image;
4352  break;
4353  }
4354  if (LocaleCompare("mosaic",option+1) == 0)
4355  {
4356  /* REDIRECTED to use -layers mosaic instead */
4357  (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4358  break;
4359  }
4360  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4361  }
4362  case 'p':
4363  {
4364  if (LocaleCompare("poly",option+1) == 0)
4365  {
4366  double
4367  *args;
4368 
4369  ssize_t
4370  count;
4371 
4372  /* convert argument string into an array of doubles */
4373  args = StringToArrayOfDoubles(arg1,&count,_exception);
4374  if (args == (double *) NULL )
4375  CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4376  new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4377  _exception);
4378  args=(double *) RelinquishMagickMemory(args);
4379  break;
4380  }
4381  if (LocaleCompare("process",option+1) == 0)
4382  {
4383  /* FUTURE: better parsing using ScriptToken() from string ??? */
4384  char
4385  **arguments;
4386 
4387  int
4388  j,
4389  number_arguments;
4390 
4391  arguments=StringToArgv(arg1,&number_arguments);
4392  if (arguments == (char **) NULL)
4393  break;
4394  if (strchr(arguments[1],'=') != (char *) NULL)
4395  {
4396  char
4397  breaker,
4398  quote,
4399  *token;
4400 
4401  const char
4402  *arguments;
4403 
4404  int
4405  next,
4406  status;
4407 
4408  size_t
4409  length;
4410 
4411  TokenInfo
4412  *token_info;
4413 
4414  /*
4415  Support old style syntax, filter="-option arg1".
4416  */
4417  assert(arg1 != (const char *) NULL);
4418  length=strlen(arg1);
4419  token=(char *) NULL;
4420  if (~length >= (MagickPathExtent-1))
4421  token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4422  sizeof(*token));
4423  if (token == (char *) NULL)
4424  break;
4425  next=0;
4426  arguments=arg1;
4427  token_info=AcquireTokenInfo();
4428  status=Tokenizer(token_info,0,token,length,arguments,"","=",
4429  "\"",'\0',&breaker,&next,&quote);
4430  token_info=DestroyTokenInfo(token_info);
4431  if (status == 0)
4432  {
4433  const char
4434  *argv;
4435 
4436  argv=(&(arguments[next]));
4437  (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4438  _exception);
4439  }
4440  token=DestroyString(token);
4441  break;
4442  }
4443  (void) SubstituteString(&arguments[1],"-","");
4444  (void) InvokeDynamicImageFilter(arguments[1],&_images,
4445  number_arguments-2,(const char **) arguments+2,_exception);
4446  for (j=0; j < number_arguments; j++)
4447  arguments[j]=DestroyString(arguments[j]);
4448  arguments=(char **) RelinquishMagickMemory(arguments);
4449  break;
4450  }
4451  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4452  }
4453  case 'r':
4454  {
4455  if (LocaleCompare("remap",option+1) == 0)
4456  {
4457  (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4458  break;
4459  }
4460  if (LocaleCompare("reverse",option+1) == 0)
4461  {
4462  ReverseImageList(&_images);
4463  break;
4464  }
4465  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4466  }
4467  case 's':
4468  {
4469  if (LocaleCompare("smush",option+1) == 0)
4470  {
4471  /* FUTURE: this option needs more work to make better */
4472  ssize_t
4473  offset;
4474 
4475  if (IsGeometry(arg1) == MagickFalse)
4476  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4477  offset=(ssize_t) StringToLong(arg1);
4478  new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4479  break;
4480  }
4481  if (LocaleCompare("subimage",option+1) == 0)
4482  {
4483  Image
4484  *base_image,
4485  *compare_image;
4486 
4487  const char
4488  *value;
4489 
4490  MetricType
4491  metric;
4492 
4493  double
4494  similarity;
4495 
4496  RectangleInfo
4497  offset;
4498 
4499  base_image=GetImageFromList(_images,0);
4500  compare_image=GetImageFromList(_images,1);
4501 
4502  /* Comparision Metric */
4503  metric=UndefinedErrorMetric;
4504  value=GetImageOption(_image_info,"metric");
4505  if (value != (const char *) NULL)
4506  metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4507  MagickFalse,value);
4508 
4509  new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4510  &offset,&similarity,_exception);
4511 
4512  if (new_images != (Image *) NULL)
4513  {
4514  char
4515  result[MagickPathExtent];
4516 
4517  (void) FormatLocaleString(result,MagickPathExtent,"%lf",
4518  similarity);
4519  (void) SetImageProperty(new_images,"subimage:similarity",result,
4520  _exception);
4521  (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4522  offset.x);
4523  (void) SetImageProperty(new_images,"subimage:x",result,
4524  _exception);
4525  (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4526  offset.y);
4527  (void) SetImageProperty(new_images,"subimage:y",result,
4528  _exception);
4529  (void) FormatLocaleString(result,MagickPathExtent,
4530  "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4531  offset.height,(long) offset.x,(long) offset.y);
4532  (void) SetImageProperty(new_images,"subimage:offset",result,
4533  _exception);
4534  }
4535  break;
4536  }
4537  if (LocaleCompare("swap",option+1) == 0)
4538  {
4539  Image
4540  *p,
4541  *q,
4542  *swap;
4543 
4544  ssize_t
4545  index,
4546  swap_index;
4547 
4548  index=(-1);
4549  swap_index=(-2);
4550  if (IfNormalOp) {
4551  GeometryInfo
4552  geometry_info;
4553 
4554  MagickStatusType
4555  flags;
4556 
4557  swap_index=(-1);
4558  flags=ParseGeometry(arg1,&geometry_info);
4559  if ((flags & RhoValue) == 0)
4560  CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4561  index=(ssize_t) geometry_info.rho;
4562  if ((flags & SigmaValue) != 0)
4563  swap_index=(ssize_t) geometry_info.sigma;
4564  }
4565  p=GetImageFromList(_images,index);
4566  q=GetImageFromList(_images,swap_index);
4567  if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4568  if (IfNormalOp)
4569  CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4570  else
4571  CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4572  }
4573  if (p == q)
4574  CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4575  swap=CloneImage(p,0,0,MagickTrue,_exception);
4576  if (swap == (Image *) NULL)
4577  CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4578  option,GetExceptionMessage(errno));
4579  ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4580  ReplaceImageInList(&q,swap);
4581  _images=GetFirstImageInList(q);
4582  break;
4583  }
4584  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4585  }
4586  default:
4587  CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4588  }
4589 
4590  /* clean up percent escape interpreted strings */
4591  if (arg1 != arg1n )
4592  arg1=DestroyString((char *)arg1);
4593  if (arg2 != arg2n )
4594  arg2=DestroyString((char *)arg2);
4595 
4596  /* if new image list generated, replace existing image list */
4597  if (new_images == (Image *) NULL)
4598  return(status == 0 ? MagickFalse : MagickTrue);
4599  _images=DestroyImageList(_images);
4600  _images=GetFirstImageInList(new_images);
4601  return(status == 0 ? MagickFalse : MagickTrue);
4602 
4603 #undef _image_info
4604 #undef _images
4605 #undef _exception
4606 #undef _draw_info
4607 #undef _quantize_info
4608 #undef IfNormalOp
4609 #undef IfPlusOp
4610 #undef IsNormalOp
4611 }
4612 
4613 /*
4614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4615 % %
4616 % %
4617 % %
4618 + C L I N o I m a g e O p e r a t i o n s %
4619 % %
4620 % %
4621 % %
4622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4623 %
4624 % CLINoImageOperator() Applies operations that may not actually need images
4625 % in an image list.
4626 %
4627 % The classic operators of this type is "-read", which actually creates
4628 % images even when no images are present. Or image stack operators, which
4629 % can be applied (push or pop) to an empty image list.
4630 %
4631 % Note that these operators may involve other special 'option' prefix
4632 % characters other than '-' or '+', namely parenthesis and braces.
4633 %
4634 % The format of the CLINoImageOption method is:
4635 %
4636 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4637 % const char *arg1, const char *arg2)
4638 %
4639 % A description of each parameter follows:
4640 %
4641 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4642 %
4643 % o option: The special option (with any switch char) to process
4644 %
4645 % o arg1 & arg2: Argument for option, if required
4646 % Currently arg2 is not used.
4647 %
4648 */
4650  const char *option,const char *arg1n,const char *arg2n)
4651 {
4652  const char /* percent escaped versions of the args */
4653  *arg1,
4654  *arg2;
4655 
4656 #define _image_info (cli_wand->wand.image_info)
4657 #define _images (cli_wand->wand.images)
4658 #define _exception (cli_wand->wand.exception)
4659 #define _process_flags (cli_wand->process_flags)
4660 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4661 #define IfNormalOp (*option=='-')
4662 #define IfPlusOp (*option!='-')
4663 
4664  assert(cli_wand != (MagickCLI *) NULL);
4665  assert(cli_wand->signature == MagickWandSignature);
4666  assert(cli_wand->wand.signature == MagickWandSignature);
4667 
4668  if (cli_wand->wand.debug != MagickFalse)
4669  (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4670  "- NoImage Operator: %s \"%s\" \"%s\"", option,
4671  arg1n != (char *) NULL ? arg1n : "",
4672  arg2n != (char *) NULL ? arg2n : "");
4673 
4674  arg1 = arg1n;
4675  arg2 = arg2n;
4676 
4677  /* Interpret Percent Escapes in Arguments - using first image */
4679  || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4680  ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4681  /* Interpret Percent escapes in argument 1 */
4682  if (arg1n != (char *) NULL) {
4683  arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4684  if (arg1 == (char *) NULL) {
4685  CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4686  arg1=arg1n; /* use the given argument as is */
4687  }
4688  }
4689  if (arg2n != (char *) NULL) {
4690  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4691  if (arg2 == (char *) NULL) {
4692  CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4693  arg2=arg2n; /* use the given argument as is */
4694  }
4695  }
4696  }
4697 #undef _process_flags
4698 #undef _option_type
4699 
4700  do { /* break to exit code */
4701  /*
4702  No-op options (ignore these)
4703  */
4704  if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4705  break;
4706  if (LocaleCompare("sans",option+1) == 0) /* one argument */
4707  break;
4708  if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4709  break;
4710  if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4711  break;
4712  if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4713  break;
4714  /*
4715  Image Reading
4716  */
4717  if ( ( LocaleCompare("read",option+1) == 0 ) ||
4718  ( LocaleCompare("--",option) == 0 ) ) {
4719  /* Do Glob filename Expansion for 'arg1' then read all images.
4720  *
4721  * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4722  * (but attaching to the filenames in the generated argument list) any
4723  * [...] read modifiers that may be present.
4724  *
4725  * For example: It will expand '*.gif[20x20]' into a list such as
4726  * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4727  *
4728  * NOTE: In IMv6 this was done globally across all images. This
4729  * meant you could include IM options in '@filename' lists, but you
4730  * could not include comments. Doing it only for image read makes
4731  * it far more secure.
4732  *
4733  * Note: arguments do not have percent escapes expanded for security
4734  * reasons.
4735  */
4736  int argc;
4737  char **argv;
4738  ssize_t i;
4739 
4740  argc = 1;
4741  argv = (char **) &arg1;
4742 
4743  /* Expand 'glob' expressions in the given filename.
4744  Expansion handles any 'coder:' prefix, or read modifiers attached
4745  to the filename, including them in the resulting expanded list.
4746  */
4747  if (ExpandFilenames(&argc,&argv) == MagickFalse)
4748  CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4749  option,GetExceptionMessage(errno));
4750 
4751  /* loop over expanded filename list, and read then all in */
4752  for (i=0; i < (ssize_t) argc; i++) {
4753  Image *
4754  new_images;
4755  if (_image_info->ping != MagickFalse)
4756  new_images=PingImages(_image_info,argv[i],_exception);
4757  else
4758  new_images=ReadImages(_image_info,argv[i],_exception);
4759  AppendImageToList(&_images, new_images);
4760  argv[i]=DestroyString(argv[i]);
4761  }
4762  argv=(char **) RelinquishMagickMemory(argv);
4763  break;
4764  }
4765  /*
4766  Image Writing
4767  Note: Writing a empty image list is valid in specific cases
4768  */
4769  if (LocaleCompare("write",option+1) == 0) {
4770  /* Note: arguments do not have percent escapes expanded */
4771  char
4772  key[MagickPathExtent];
4773 
4774  Image
4775  *write_images;
4776 
4777  ImageInfo
4778  *write_info;
4779 
4780  /* Need images, unless a "null:" output coder is used */
4781  if ( _images == (Image *) NULL ) {
4782  if ( LocaleCompare(arg1,"null:") == 0 )
4783  break;
4784  CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4785  }
4786 
4787  (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4788  (void) DeleteImageRegistry(key);
4789  write_images=_images;
4790  if (IfPlusOp)
4791  write_images=CloneImageList(_images,_exception);
4792  write_info=CloneImageInfo(_image_info);
4793  (void) WriteImages(write_info,write_images,arg1,_exception);
4794  write_info=DestroyImageInfo(write_info);
4795  if (IfPlusOp)
4796  write_images=DestroyImageList(write_images);
4797  break;
4798  }
4799  /*
4800  Parenthesis and Brace operations
4801  */
4802  if (LocaleCompare("(",option) == 0) {
4803  /* stack 'push' images */
4804  Stack
4805  *node;
4806 
4807  size_t
4808  size;
4809 
4810  size=0;
4811  node=cli_wand->image_list_stack;
4812  for ( ; node != (Stack *) NULL; node=node->next)
4813  size++;
4814  if ( size >= MAX_STACK_DEPTH )
4815  CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4816  node=(Stack *) AcquireMagickMemory(sizeof(*node));
4817  if (node == (Stack *) NULL)
4818  CLIWandExceptionBreak(ResourceLimitFatalError,
4819  "MemoryAllocationFailed",option);
4820  node->data = (void *)cli_wand->wand.images;
4821  node->next = cli_wand->image_list_stack;
4822  cli_wand->image_list_stack = node;
4823  cli_wand->wand.images = NewImageList();
4824 
4825  /* handle respect-parenthesis */
4826  if (IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4827  "respect-parenthesis")) != MagickFalse)
4828  option="{"; /* fall-thru so as to push image settings too */
4829  else
4830  break;
4831  /* fall thru to operation */
4832  }
4833  if (LocaleCompare("{",option) == 0) {
4834  /* stack 'push' of image_info settings */
4835  Stack
4836  *node;
4837 
4838  size_t
4839  size;
4840 
4841  size=0;
4842  node=cli_wand->image_info_stack;
4843  for ( ; node != (Stack *) NULL; node=node->next)
4844  size++;
4845  if ( size >= MAX_STACK_DEPTH )
4846  CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4847  node=(Stack *) AcquireMagickMemory(sizeof(*node));
4848  if (node == (Stack *) NULL)
4849  CLIWandExceptionBreak(ResourceLimitFatalError,
4850  "MemoryAllocationFailed",option);
4851 
4852  node->data = (void *)cli_wand->wand.image_info;
4853  node->next = cli_wand->image_info_stack;
4854 
4855  cli_wand->image_info_stack = node;
4856  cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4857  if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4858  CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4859  option);
4860  cli_wand->wand.image_info = (ImageInfo *)node->data;
4861  node = (Stack *)RelinquishMagickMemory(node);
4862  break;
4863  }
4864 
4865  break;
4866  }
4867  if (LocaleCompare(")",option) == 0) {
4868  /* pop images from stack */
4869  Stack
4870  *node;
4871 
4872  node = (Stack *)cli_wand->image_list_stack;
4873  if ( node == (Stack *) NULL)
4874  CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4875  cli_wand->image_list_stack = node->next;
4876 
4877  AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4878  cli_wand->wand.images= (Image *)node->data;
4879  node = (Stack *)RelinquishMagickMemory(node);
4880 
4881  /* handle respect-parenthesis - of the previous 'pushed' settings */
4882  node = cli_wand->image_info_stack;
4883  if ( node != (Stack *) NULL)
4884  {
4885  if (IsStringTrue(GetImageOption(
4886  cli_wand->wand.image_info,"respect-parenthesis")) != MagickFalse)
4887  option="}"; /* fall-thru so as to pop image settings too */
4888  else
4889  break;
4890  }
4891  else
4892  break;
4893  /* fall thru to next if */
4894  }
4895  if (LocaleCompare("}",option) == 0) {
4896  /* pop image_info settings from stack */
4897  Stack
4898  *node;
4899 
4900  node = (Stack *)cli_wand->image_info_stack;
4901  if ( node == (Stack *) NULL)
4902  CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4903  cli_wand->image_info_stack = node->next;
4904 
4905  (void) DestroyImageInfo(cli_wand->wand.image_info);
4906  cli_wand->wand.image_info = (ImageInfo *)node->data;
4907  node = (Stack *)RelinquishMagickMemory(node);
4908 
4909  GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4910  cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4911  cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4912 
4913  break;
4914  }
4915  if (LocaleCompare("print",option+1) == 0)
4916  {
4917  (void) FormatLocaleFile(stdout,"%s",arg1);
4918  break;
4919  }
4920  if (LocaleCompare("set",option+1) == 0)
4921  {
4922  /* Settings are applied to each image in memory in turn (if any).
4923  While a option: only need to be applied once globally.
4924 
4925  NOTE: rguments have not been automatically percent expaneded
4926  */
4927 
4928  /* escape the 'key' once only, using first image. */
4929  arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4930  if (arg1 == (char *) NULL)
4931  CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4932  option);
4933 
4934  if (LocaleNCompare(arg1,"registry:",9) == 0)
4935  {
4936  if (IfPlusOp)
4937  {
4938  (void) DeleteImageRegistry(arg1+9);
4939  arg1=DestroyString((char *)arg1);
4940  break;
4941  }
4942  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4943  if (arg2 == (char *) NULL) {
4944  arg1=DestroyString((char *)arg1);
4945  CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4946  option);
4947  }
4948  (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4949  arg1=DestroyString((char *)arg1);
4950  arg2=DestroyString((char *)arg2);
4951  break;
4952  }
4953  if (LocaleNCompare(arg1,"option:",7) == 0)
4954  {
4955  /* delete equivelent artifact from all images (if any) */
4956  if (_images != (Image *) NULL)
4957  {
4958  MagickResetIterator(&cli_wand->wand);
4959  while (MagickNextImage(&cli_wand->wand) != MagickFalse)
4960  (void) DeleteImageArtifact(_images,arg1+7);
4961  MagickResetIterator(&cli_wand->wand);
4962  }
4963  /* now set/delete the global option as needed */
4964  /* FUTURE: make escapes in a global 'option:' delayed */
4965  arg2=(char *) NULL;
4966  if (IfNormalOp)
4967  {
4968  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4969  if (arg2 == (char *) NULL)
4970  CLIWandExceptionBreak(OptionWarning,
4971  "InterpretPropertyFailure",option);
4972  }
4973  (void) SetImageOption(_image_info,arg1+7,arg2);
4974  arg1=DestroyString((char *)arg1);
4975  arg2=DestroyString((char *)arg2);
4976  break;
4977  }
4978  /* Set Artifacts/Properties/Attributes all images (required) */
4979  if ( _images == (Image *) NULL )
4980  CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4981 
4982  MagickResetIterator(&cli_wand->wand);
4983  while (MagickNextImage(&cli_wand->wand) != MagickFalse)
4984  {
4985  arg2=(char *) NULL;
4986  if (IfNormalOp)
4987  {
4988  arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4989  if (arg2 == (char *) NULL)
4990  CLIWandExceptionBreak(OptionWarning,
4991  "InterpretPropertyFailure",option);
4992  }
4993  if (LocaleNCompare(arg1,"artifact:",9) == 0)
4994  (void) SetImageArtifact(_images,arg1+9,arg2);
4995  else if (LocaleNCompare(arg1,"property:",9) == 0)
4996  (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4997  else
4998  (void) SetImageProperty(_images,arg1,arg2,_exception);
4999  arg2=DestroyString((char *)arg2);
5000  }
5001  MagickResetIterator(&cli_wand->wand);
5002  arg1=DestroyString((char *)arg1);
5003  break;
5004  }
5005  if (LocaleCompare("clone",option+1) == 0) {
5006  Image
5007  *new_images;
5008 
5009  if (*option == '+')
5010  arg1=AcquireString("-1");
5011  if (IsSceneGeometry(arg1,MagickFalse) == MagickFalse)
5012  CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
5013  if ( cli_wand->image_list_stack == (Stack *) NULL)
5014  CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5015  new_images = (Image *)cli_wand->image_list_stack->data;
5016  if (new_images == (Image *) NULL)
5017  CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5018  new_images=CloneImages(new_images,arg1,_exception);
5019  if (new_images == (Image *) NULL)
5020  CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
5021  AppendImageToList(&_images,new_images);
5022  break;
5023  }
5024  /*
5025  Informational Operations.
5026 
5027  Note that these do not require either a cli-wand or images!
5028  Though currently a cli-wand much be provided regardless.
5029  */
5030  if (LocaleCompare("version",option+1) == 0)
5031  {
5032  ListMagickVersion(stdout);
5033  break;
5034  }
5035  if (LocaleCompare("list",option+1) == 0) {
5036  /*
5037  FUTURE: This 'switch' should really be part of MagickCore
5038  */
5039  ssize_t
5040  list;
5041 
5042  list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
5043  if ( list < 0 ) {
5044  CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
5045  break;
5046  }
5047  switch (list)
5048  {
5049  case MagickCoderOptions:
5050  {
5051  (void) ListCoderInfo((FILE *) NULL,_exception);
5052  break;
5053  }
5054  case MagickColorOptions:
5055  {
5056  (void) ListColorInfo((FILE *) NULL,_exception);
5057  break;
5058  }
5059  case MagickConfigureOptions:
5060  {
5061  (void) ListConfigureInfo((FILE *) NULL,_exception);
5062  break;
5063  }
5064  case MagickDelegateOptions:
5065  {
5066  (void) ListDelegateInfo((FILE *) NULL,_exception);
5067  break;
5068  }
5069  case MagickFontOptions:
5070  {
5071  (void) ListTypeInfo((FILE *) NULL,_exception);
5072  break;
5073  }
5074  case MagickFormatOptions:
5075  (void) ListMagickInfo((FILE *) NULL,_exception);
5076  break;
5077  case MagickLocaleOptions:
5078  (void) ListLocaleInfo((FILE *) NULL,_exception);
5079  break;
5080  case MagickLogOptions:
5081  (void) ListLogInfo((FILE *) NULL,_exception);
5082  break;
5083  case MagickMagicOptions:
5084  (void) ListMagicInfo((FILE *) NULL,_exception);
5085  break;
5086  case MagickMimeOptions:
5087  (void) ListMimeInfo((FILE *) NULL,_exception);
5088  break;
5089  case MagickModuleOptions:
5090  (void) ListModuleInfo((FILE *) NULL,_exception);
5091  break;
5092  case MagickPolicyOptions:
5093  (void) ListPolicyInfo((FILE *) NULL,_exception);
5094  break;
5095  case MagickResourceOptions:
5096  (void) ListMagickResourceInfo((FILE *) NULL,_exception);
5097  break;
5098  case MagickThresholdOptions:
5099  (void) ListThresholdMaps((FILE *) NULL,_exception);
5100  break;
5101  default:
5102  (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
5103  _exception);
5104  break;
5105  }
5106  break;
5107  }
5108 
5109  CLIWandException(OptionError,"UnrecognizedOption",option);
5110 
5111 DisableMSCWarning(4127)
5112  } while (0); /* break to exit code. */
5114 
5115  /* clean up percent escape interpreted strings */
5116  if (arg1 != arg1n )
5117  arg1=DestroyString((char *)arg1);
5118  if (arg2 != arg2n )
5119  arg2=DestroyString((char *)arg2);
5120 
5121 #undef _image_info
5122 #undef _images
5123 #undef _exception
5124 #undef IfNormalOp
5125 #undef IfPlusOp
5126 }
5127 
5128 /*
5129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5130 % %
5131 % %
5132 % %
5133 + C L I O p t i o n %
5134 % %
5135 % %
5136 % %
5137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5138 %
5139 % CLIOption() Processes the given option using the given CLI Magick Wand.
5140 % The option arguments can be variable in number, though at this time no more
5141 % that two is actually used by any option (this may change). Excess options
5142 % are simply ignored.
5143 %
5144 % If the cli_wand->command pointer is non-null, then it is assumed that the
5145 % option has already been search for up from the CommandOptions[] table in
5146 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
5147 % routine will do the lookup instead. The pointer is reset afterward.
5148 %
5149 % This action allows the caller to lookup and pre-handle any 'special'
5150 % options, (such as implicit reads) before calling this general option
5151 % handler to deal with 'standard' command line options.
5152 %
5153 % The format of the CLIOption method is:
5154 %
5155 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5156 %
5157 % A description of each parameter follows:
5158 %
5159 % o cli_wand: the main CLI Wand to use.
5160 %
5161 % o option: The special option (with any switch char) to process
5162 %
5163 % o args: any required arguments for an option (variable number)
5164 %
5165 % Example Usage...
5166 %
5167 % CLIoption(cli_wand,"-read","rose:");
5168 % CLIoption(cli_wand,"-virtual-pixel","transparent");
5169 % CLIoption(cli_wand,"-distort","SRT:","30");
5170 % CLIoption(cli_wand,"-write","rotated_rose.png");
5171 %
5172 */
5173 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5174 {
5175  const char /* extracted option args from args */
5176  *arg1,
5177  *arg2;
5178 
5179  CommandOptionFlags
5180  option_type;
5181 
5182  assert(cli_wand != (MagickCLI *) NULL);
5183  assert(cli_wand->signature == MagickWandSignature);
5184  assert(cli_wand->wand.signature == MagickWandSignature);
5185 
5186  do { /* Break Code Block for error handling */
5187 
5188  /* get information about option */
5189  if ( cli_wand->command == (const OptionInfo *) NULL )
5190  cli_wand->command = GetCommandOptionInfo(option);
5191 #if 0
5192  (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5193  option, cli_wand->command->mnemonic );
5194 #endif
5195  option_type=(CommandOptionFlags) cli_wand->command->flags;
5196 
5197  if ( option_type == UndefinedOptionFlag )
5198  CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5199 
5200  assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5201 
5202  /* deprecated options */
5203  if ( (option_type & DeprecateOptionFlag) != 0 )
5204  CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5205 
5206  /* options that this module does not handle */
5207  if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5208  CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5209 
5210  /* Get argument strings from VarArgs
5211  How can you determine if enough arguments was supplied?
5212  What happens if not enough arguments were supplied?
5213  */
5214  { size_t
5215  count = (size_t) cli_wand->command->type;
5216 
5217  va_list
5218  operands;
5219 
5220  va_start(operands,option);
5221 
5222  arg1=arg2=NULL;
5223  if ( count >= 1 )
5224  arg1=(const char *) va_arg(operands, const char *);
5225  if ( count >= 2 )
5226  arg2=(const char *) va_arg(operands, const char *);
5227 
5228  va_end(operands);
5229 #if 0
5230  (void) FormatLocaleFile(stderr,
5231  "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5232  option,(long) count,option_type,arg1,arg2);
5233 #endif
5234  }
5235 
5236  /*
5237  Call the appropriate option handler
5238  */
5239 
5240  /* FUTURE: this is temporary - get 'settings' to handle distribution of
5241  settings to images attributes,proprieties,artifacts */
5242  if ( cli_wand->wand.images != (Image *) NULL )
5243  (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5244  cli_wand->wand.exception);
5245 
5246  if ( (option_type & SettingOptionFlags) != 0 ) {
5247  CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5248  /*
5249  FUTURE: Sync Specific Settings into Image Properities (not global)
5250  */
5251  }
5252 
5253  /* Operators that do not need images - read, write, stack, clone */
5254  if ((option_type & NoImageOperatorFlag) != 0)
5255  CLINoImageOperator(cli_wand, option, arg1, arg2);
5256 
5257  /* FUTURE: The not a setting part below is a temporary hack due to
5258  * some options being both a Setting and a Simple operator.
5259  * Specifically -monitor, -depth, and -colorspace */
5260  if ( cli_wand->wand.images == (Image *) NULL )
5261  if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5262  ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5263  CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5264 
5265  /* Operators which loop of individual images, simply */
5266  if ( (option_type & SimpleOperatorFlag) != 0 &&
5267  cli_wand->wand.images != (Image *) NULL) /* temp hack */
5268  {
5269  ExceptionInfo *exception=AcquireExceptionInfo();
5270  (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5271  exception=DestroyExceptionInfo(exception);
5272  }
5273 
5274  /* Operators that work on the image list as a whole */
5275  if ( (option_type & ListOperatorFlag) != 0 )
5276  (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5277 
5278 DisableMSCWarning(4127)
5279  } while (0); /* end Break code block */
5281 
5282  cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
5283 }
#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:5173
#define WandPrivate
char name[MagickPathExtent]
#define ArgBooleanString
WandPrivate void CLINoImageOperator(MagickCLI *, const char *, const char *, const char *)
Definition: operation.c:4649
#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