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