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