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