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