2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % CLI Magick Option Methods %
20 % Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
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
44 % Anthony Thyssen, September 2011
50 #include "MagickWand/studio.h"
51 #include "MagickWand/MagickWand.h"
52 #include "MagickWand/magick-wand-private.h"
53 #include "MagickWand/mogrify.h"
54 #include "MagickWand/wand.h"
55 #include "MagickWand/wandcli.h"
56 #include "MagickWand/wandcli-private.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/monitor-private.h"
59 #include "MagickWand/operation.h"
60 #include "MagickCore/thread-private.h"
61 #include "MagickCore/string-private.h"
62 #include "MagickCore/pixel-private.h"
68 MogrifyBackgroundColor[] = "#fff", /* white */
69 MogrifyBorderColor[] = "#dfdfdf", /* sRGB gray */
70 MogrifyMatteColor[] = "#bdbdbd"; /* slightly darker gray */
75 #define USE_WAND_METHODS 1
76 #define MAX_STACK_DEPTH 32
77 #define UNDEFINED_COMPRESSION_QUALITY 0UL
79 /* FUTURE: why is this default so specific? */
80 #define DEFAULT_DISSIMILARITY_THRESHOLD "0.31830988618379067154"
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 )
88 ** Function to report on the progress of image operations
90 static MagickBooleanType MonitorProgress(const char *text,
91 const MagickOffsetType offset,const MagickSizeType extent,
92 void *wand_unused(cli_wandent_data))
95 message[MagickPathExtent],
96 tag[MagickPathExtent];
106 (void) CopyMagickMemory(tag,text,MagickPathExtent);
108 if (p != (char *) NULL)
110 (void) FormatLocaleString(message,MagickPathExtent,"Monitor/%s",tag);
111 locale_message=GetLocaleMessage(message);
112 if (locale_message == message)
114 if (p == (char *) NULL)
115 (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
116 locale_message,(long) offset,(unsigned long) extent,(long)
117 (100L*offset/(extent-1)));
119 (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
120 locale_message,p+1,(long) offset,(unsigned long) extent,(long)
121 (100L*offset/(extent-1)));
122 if (offset == (MagickOffsetType) (extent-1))
123 (void) FormatLocaleFile(stderr,"\n");
124 (void) fflush(stderr);
129 ** GetImageCache() will read an image into a image cache if not already
130 ** present then return the image that is in the cache under that filename.
132 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
133 ExceptionInfo *exception)
136 key[MagickPathExtent];
147 (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",path);
148 sans_exception=AcquireExceptionInfo();
149 image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
150 sans_exception=DestroyExceptionInfo(sans_exception);
151 if (image != (Image *) NULL)
153 read_info=CloneImageInfo(image_info);
154 if (path != (const char *) NULL)
155 (void) CopyMagickString(read_info->filename,path,MagickPathExtent);
156 image=ReadImage(read_info,exception);
157 read_info=DestroyImageInfo(read_info);
158 if (image != (Image *) NULL)
159 (void) SetImageRegistry(ImageRegistryType,key,image,exception);
164 SparseColorOption() parse the complex -sparse-color argument into an
165 an array of floating point values than call SparseColorImage().
166 Argument is a complex mix of floating-point pixel coodinates, and color
167 specifications (or direct floating point numbers). The number of floats
168 needed to represent a color varies depending on the current channel
171 This really should be in MagickCore, so that other API's can make use of it.
173 static Image *SparseColorOption(const Image *image,
174 const SparseColorMethod method,const char *arguments,ExceptionInfo *exception)
177 token[MagickPathExtent];
201 assert(image != (Image *) NULL);
202 assert(image->signature == MagickCoreSignature);
203 if (IfMagickTrue(image->debug))
204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
205 assert(exception != (ExceptionInfo *) NULL);
206 assert(exception->signature == MagickCoreSignature);
208 Limit channels according to image
209 add up number of values needed per color.
212 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
214 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
216 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
218 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
219 (image->colorspace == CMYKColorspace))
221 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
222 image->alpha_trait != UndefinedPixelTrait)
226 Read string, to determine number of arguments needed,
232 GetMagickToken(p,&p,token);
233 if ( token[0] == ',' ) continue;
234 if ( isalpha((int) token[0]) || token[0] == '#' )
235 x += number_colors; /* color argument found */
237 x++; /* floating point argument */
239 /* control points and color values */
240 error = IsMagickTrue( x % (2+number_colors) );
242 if ( IfMagickTrue(error) ) {
243 (void) ThrowMagickException(exception,GetMagickModule(),
244 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
245 "Invalid number of Arguments");
246 return( (Image *) NULL);
249 /* Allocate and fill in the floating point arguments */
250 sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
251 sizeof(*sparse_arguments));
252 if (sparse_arguments == (double *) NULL) {
253 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
254 "MemoryAllocationFailed","%s","SparseColorOption");
255 return( (Image *) NULL);
257 (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
258 sizeof(*sparse_arguments));
261 while( *p != '\0' && x < number_arguments ) {
263 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
264 if ( token[0] == '\0' ) break;
265 if ( isalpha((int) token[0]) || token[0] == '#' ) {
266 (void) ThrowMagickException(exception,GetMagickModule(),
267 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
268 "Color found, instead of X-coord");
272 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
274 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
275 if ( token[0] == '\0' ) break;
276 if ( isalpha((int) token[0]) || token[0] == '#' ) {
277 (void) ThrowMagickException(exception,GetMagickModule(),
278 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
279 "Color found, instead of Y-coord");
283 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
284 /* color name or function given in string argument */
285 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
286 if ( token[0] == '\0' ) break;
287 if ( isalpha((int) token[0]) || token[0] == '#' ) {
288 /* Color string given */
289 (void) QueryColorCompliance(token,AllCompliance,&color,
291 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
292 sparse_arguments[x++] = QuantumScale*color.red;
293 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
294 sparse_arguments[x++] = QuantumScale*color.green;
295 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
296 sparse_arguments[x++] = QuantumScale*color.blue;
297 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
298 (image->colorspace == CMYKColorspace))
299 sparse_arguments[x++] = QuantumScale*color.black;
300 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
301 image->alpha_trait != UndefinedPixelTrait)
302 sparse_arguments[x++] = QuantumScale*color.alpha;
305 /* Colors given as a set of floating point values - experimental */
306 /* NB: token contains the first floating point value to use! */
307 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
309 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
310 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
312 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
313 token[0] = ','; /* used this token - get another */
315 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
317 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
318 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
320 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
321 token[0] = ','; /* used this token - get another */
323 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
325 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
326 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
328 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
329 token[0] = ','; /* used this token - get another */
331 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
332 (image->colorspace == CMYKColorspace))
334 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
335 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
337 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
338 token[0] = ','; /* used this token - get another */
340 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
341 image->alpha_trait != UndefinedPixelTrait)
343 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
344 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
346 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
347 token[0] = ','; /* used this token - get another */
351 if ( number_arguments != x && !error ) {
352 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
353 "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
354 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
355 return( (Image *) NULL);
358 return( (Image *) NULL);
360 /* Call the Sparse Color Interpolation function with the parsed arguments */
361 sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
363 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
364 return( sparse_image );
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372 % C L I S e t t i n g O p t i o n I n f o %
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 % CLISettingOptionInfo() applies a single settings option into a CLI wand
379 % holding the image_info, draw_info, quantize_info structures that will be
380 % used when processing the images.
382 % These options do no require images to be present in the CLI wand for them
383 % to be able to be set, in which case they will generally be applied to image
384 % that are read in later
386 % Options handled by this function are listed in CommandOptions[] of
387 % "option.c" that is one of "SettingOptionFlags" option flags.
389 % The format of the CLISettingOptionInfo method is:
391 % void CLISettingOptionInfo(MagickCLI *cli_wand,
392 % const char *option, const char *arg1, const char *arg2)
394 % A description of each parameter follows:
396 % o cli_wand: structure holding settings to be applied
398 % o option: The option string to be set
400 % o arg1, arg2: optional argument strings to the operation
401 % arg2 is currently only used by "-limit"
404 WandPrivate void CLISettingOptionInfo(MagickCLI *cli_wand,
405 const char *option,const char *arg1n, const char *arg2n)
408 parse; /* option argument parsing (string to value table lookup) */
410 const char /* percent escaped versions of the args */
414 #define _image_info (cli_wand->wand.image_info)
415 #define _image (cli_wand->wand.images)
416 #define _exception (cli_wand->wand.exception)
417 #define _draw_info (cli_wand->draw_info)
418 #define _quantize_info (cli_wand->quantize_info)
419 #define IfSetOption (*option=='-')
420 #define ArgBoolean IsMagickTrue(IfSetOption)
421 #define ArgBooleanNot IsMagickFalse(IfSetOption)
422 #define ArgBooleanString (IfSetOption?"true":"false")
423 #define ArgOption(def) (IfSetOption?arg1:(const char *)(def))
425 assert(cli_wand != (MagickCLI *) NULL);
426 assert(cli_wand->signature == MagickWandSignature);
427 assert(cli_wand->wand.signature == MagickWandSignature);
429 if (IfMagickTrue(cli_wand->wand.debug))
430 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
431 "- Setting Option: %s \"%s\" \"%s\"", option,arg1n,arg2n);
437 #define _process_flags (cli_wand->process_flags)
438 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
439 /* Interpret Percent Escapes in Arguments - using first image */
440 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
441 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
442 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
443 /* Interpret Percent escapes in argument 1 */
444 if (arg1n != (char *) NULL) {
445 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
446 if (arg1 == (char *) NULL) {
447 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
448 arg1=arg1n; /* use the given argument as is */
451 if (arg2n != (char *) NULL) {
452 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
453 if (arg2 == (char *) NULL) {
454 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
455 arg2=arg2n; /* use the given argument as is */
459 #undef _process_flags
467 if (LocaleCompare("adjoin",option+1) == 0)
469 _image_info->adjoin = ArgBoolean;
472 if (LocaleCompare("affine",option+1) == 0)
474 CLIWandWarnReplaced("-draw 'affine ...'");
476 (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception);
478 GetAffineMatrix(&_draw_info->affine);
481 if (LocaleCompare("antialias",option+1) == 0)
483 _image_info->antialias =
484 _draw_info->stroke_antialias =
485 _draw_info->text_antialias = ArgBoolean;
488 if (LocaleCompare("attenuate",option+1) == 0)
490 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
491 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
492 (void) SetImageOption(_image_info,option+1,ArgOption("1.0"));
495 if (LocaleCompare("authenticate",option+1) == 0)
497 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
500 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
504 if (LocaleCompare("background",option+1) == 0)
506 /* FUTURE: both _image_info attribute & ImageOption in use!
507 _image_info only used directly for generating new images.
508 SyncImageSettings() used to set per-image attribute.
510 FUTURE: if _image_info->background_color is not set then
511 we should fall back to per-image background_color
513 At this time -background will 'wipe out' the per-image
516 Better error handling of QueryColorCompliance() needed.
518 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
519 (void) QueryColorCompliance(ArgOption(MogrifyBackgroundColor),AllCompliance,
520 &_image_info->background_color,_exception);
523 if (LocaleCompare("bias",option+1) == 0)
525 /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias"
526 as it is actually rarely used except in direct convolve operations
527 Usage outside a direct convolve operation is actally non-sensible!
529 SyncImageSettings() used to set per-image attribute.
531 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
532 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
533 (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL));
536 if (LocaleCompare("black-point-compensation",option+1) == 0)
538 /* Used as a image chromaticity setting
539 SyncImageSettings() used to set per-image attribute.
541 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
544 if (LocaleCompare("blue-primary",option+1) == 0)
546 /* Image chromaticity X,Y NB: Y=X if Y not defined
547 Used by many coders including PNG
548 SyncImageSettings() used to set per-image attribute.
550 arg1=ArgOption("0.0");
551 if (IfMagickFalse(IsGeometry(arg1)))
552 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
553 (void) SetImageOption(_image_info,option+1,arg1);
556 if (LocaleCompare("bordercolor",option+1) == 0)
558 /* FUTURE: both _image_info attribute & ImageOption in use!
559 SyncImageSettings() used to set per-image attribute.
560 Better error checking of QueryColorCompliance().
564 (void) SetImageOption(_image_info,option+1,arg1);
565 (void) QueryColorCompliance(arg1,AllCompliance,
566 &_image_info->border_color,_exception);
567 (void) QueryColorCompliance(arg1,AllCompliance,
568 &_draw_info->border_color,_exception);
571 (void) DeleteImageOption(_image_info,option+1);
572 (void) QueryColorCompliance(MogrifyBorderColor,AllCompliance,
573 &_image_info->border_color,_exception);
574 (void) QueryColorCompliance(MogrifyBorderColor,AllCompliance,
575 &_draw_info->border_color,_exception);
578 if (LocaleCompare("box",option+1) == 0)
580 CLIWandWarnReplaced("-undercolor");
581 CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2);
584 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
588 if (LocaleCompare("cache",option+1) == 0)
593 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
594 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
595 limit=MagickResourceInfinity;
596 if (LocaleCompare("unlimited",arg1) != 0)
597 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0);
598 (void) SetMagickResourceLimit(MemoryResource,limit);
599 (void) SetMagickResourceLimit(MapResource,2*limit);
602 if (LocaleCompare("caption",option+1) == 0)
604 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
607 if (LocaleCompare("colorspace",option+1) == 0)
609 /* Setting used for new images via AquireImage()
610 But also used as a SimpleImageOperator
611 Undefined colorspace means don't modify images on
612 read or as a operation */
613 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
614 ArgOption("undefined"));
616 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
618 _image_info->colorspace=(ColorspaceType) parse;
621 if (LocaleCompare("comment",option+1) == 0)
623 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
626 if (LocaleCompare("compose",option+1) == 0)
628 /* FUTURE: _image_info should be used,
629 SyncImageSettings() used to set per-image attribute. - REMOVE
631 This setting should NOT be used to set image 'compose'
632 "-layer" operators shoud use _image_info if defined otherwise
633 they should use a per-image compose setting.
635 parse = ParseCommandOption(MagickComposeOptions,MagickFalse,
636 ArgOption("undefined"));
638 CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator",
640 _image_info->compose=(CompositeOperator) parse;
641 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
644 if (LocaleCompare("compress",option+1) == 0)
646 /* FUTURE: What should be used? _image_info or ImageOption ???
647 The former is more efficent, but Crisy prefers the latter!
648 SyncImageSettings() used to set per-image attribute.
650 The coders appears to use _image_info, not Image_Option
651 however the image attribute (for save) is set from the
654 Note that "undefined" is a different setting to "none".
656 parse = ParseCommandOption(MagickCompressOptions,MagickFalse,
657 ArgOption("undefined"));
659 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression",
661 _image_info->compression=(CompressionType) parse;
662 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
665 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
669 if (LocaleCompare("debug",option+1) == 0)
671 /* SyncImageSettings() used to set per-image attribute. */
672 arg1=ArgOption("none");
673 parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1);
675 CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType",
677 (void) SetLogEventMask(arg1);
678 _image_info->debug=IsEventLogging(); /* extract logging*/
679 cli_wand->wand.debug=IsEventLogging();
682 if (LocaleCompare("define",option+1) == 0)
684 if (LocaleNCompare(arg1,"registry:",9) == 0)
687 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception);
689 (void) DeleteImageRegistry(arg1+9);
692 /* DefineImageOption() equals SetImageOption() but with '=' */
694 (void) DefineImageOption(_image_info,arg1);
695 else if (IsMagickFalse(DeleteImageOption(_image_info,arg1)))
696 CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1);
699 if (LocaleCompare("delay",option+1) == 0)
701 /* Only used for new images via AcquireImage()
702 FUTURE: Option should also be used for "-morph" (color morphing)
705 if (IfMagickFalse(IsGeometry(arg1)))
706 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
707 (void) SetImageOption(_image_info,option+1,arg1);
710 if (LocaleCompare("density",option+1) == 0)
712 /* FUTURE: strings used in _image_info attr and _draw_info!
713 Basically as density can be in a XxY form!
715 SyncImageSettings() used to set per-image attribute.
717 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
718 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
719 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
720 (void) CloneString(&_image_info->density,ArgOption(NULL));
721 (void) CloneString(&_draw_info->density,_image_info->density);
724 if (LocaleCompare("depth",option+1) == 0)
726 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
727 SyncImageSettings() used to set per-image attribute.
729 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
730 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
731 _image_info->depth=IfSetOption?StringToUnsignedLong(arg1)
732 :MAGICKCORE_QUANTUM_DEPTH;
735 if (LocaleCompare("direction",option+1) == 0)
737 /* Image Option is only used to set _draw_info */
738 arg1=ArgOption("undefined");
739 parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1);
741 CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType",
743 _draw_info->direction=(DirectionType) parse;
744 (void) SetImageOption(_image_info,option+1,arg1);
747 if (LocaleCompare("display",option+1) == 0)
749 (void) CloneString(&_image_info->server_name,ArgOption(NULL));
750 (void) CloneString(&_draw_info->server_name,_image_info->server_name);
753 if (LocaleCompare("dispose",option+1) == 0)
755 /* only used in setting new images */
756 arg1=ArgOption("undefined");
757 parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1);
759 CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod",
761 (void) SetImageOption(_image_info,option+1,ArgOption("undefined"));
764 if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
766 /* FUTURE: this is only used by CompareImages() which is used
767 only by the "compare" CLI program at this time. */
768 arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD);
769 if (IfMagickFalse(IsGeometry(arg1)))
770 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
771 (void) SetImageOption(_image_info,option+1,arg1);
774 if (LocaleCompare("dither",option+1) == 0)
776 /* _image_info attr (on/off), _quantize_info attr (on/off)
777 but also ImageInfo and _quantize_info method!
778 FUTURE: merge the duality of the dithering options
780 _image_info->dither = ArgBoolean;
781 (void) SetImageOption(_image_info,option+1,ArgOption("none"));
782 _quantize_info->dither_method=(DitherMethod) ParseCommandOption(
783 MagickDitherOptions,MagickFalse,ArgOption("none"));
784 if (_quantize_info->dither_method == NoDitherMethod)
785 _image_info->dither = MagickFalse;
788 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
792 if (LocaleCompare("encoding",option+1) == 0)
794 (void) CloneString(&_draw_info->encoding,ArgOption("undefined"));
795 (void) SetImageOption(_image_info,option+1,_draw_info->encoding);
798 if (LocaleCompare("endian",option+1) == 0)
800 /* Both _image_info attr and ImageInfo */
801 arg1 = ArgOption("undefined");
802 parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1);
804 CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType",
806 /* FUTURE: check alloc/free of endian string! - remove? */
807 _image_info->endian=(EndianType) (*arg1);
808 (void) SetImageOption(_image_info,option+1,arg1);
811 if (LocaleCompare("extract",option+1) == 0)
813 (void) CloneString(&_image_info->extract,ArgOption(NULL));
816 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
820 if (LocaleCompare("family",option+1) == 0)
822 (void) CloneString(&_draw_info->family,ArgOption(NULL));
825 if (LocaleCompare("features",option+1) == 0)
827 (void) SetImageOption(_image_info,"identify:features",
830 (void) SetImageArtifact(_image,"verbose","true");
833 if (LocaleCompare("fill",option+1) == 0)
835 /* Set "fill" OR "fill-pattern" in _draw_info
836 The original fill color is preserved if a fill-pattern is given.
837 That way it does not effect other operations that directly using
838 the fill color and, can be retored using "+tile".
849 arg1 = ArgOption("none"); /* +fill turns it off! */
850 (void) SetImageOption(_image_info,option+1,arg1);
851 if (_draw_info->fill_pattern != (Image *) NULL)
852 _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern);
854 /* is it a color or a image? -- ignore exceptions */
855 sans=AcquireExceptionInfo();
856 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
857 sans=DestroyExceptionInfo(sans);
859 if (IfMagickFalse(status))
860 _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception);
862 _draw_info->fill=color;
865 if (LocaleCompare("filter",option+1) == 0)
867 /* SyncImageSettings() used to set per-image attribute. */
868 arg1 = ArgOption("undefined");
869 parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1);
871 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter",
873 (void) SetImageOption(_image_info,option+1,arg1);
876 if (LocaleCompare("font",option+1) == 0)
878 (void) CloneString(&_draw_info->font,ArgOption(NULL));
879 (void) CloneString(&_image_info->font,_draw_info->font);
882 if (LocaleCompare("format",option+1) == 0)
884 /* FUTURE: why the ping test, you could set ping after this! */
889 for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
890 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
891 _image_info->ping=MagickFalse;
893 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
896 if (LocaleCompare("fuzz",option+1) == 0)
898 /* Option used to set image fuzz! unless blank canvas (from color)
899 Image attribute used for color compare operations
900 SyncImageSettings() used to set per-image attribute.
902 FUTURE: Can't find anything else using _image_info->fuzz directly!
903 convert structure attribute to 'option' string
906 if (IfMagickFalse(IsGeometry(arg1)))
907 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
908 _image_info->fuzz=StringToDoubleInterval(arg1,(double)
910 (void) SetImageOption(_image_info,option+1,arg1);
913 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
917 if (LocaleCompare("gravity",option+1) == 0)
919 /* SyncImageSettings() used to set per-image attribute. */
920 arg1 = ArgOption("none");
921 parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1);
923 CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType",
925 _draw_info->gravity=(GravityType) parse;
926 (void) SetImageOption(_image_info,option+1,arg1);
929 if (LocaleCompare("green-primary",option+1) == 0)
931 /* Image chromaticity X,Y NB: Y=X if Y not defined
932 SyncImageSettings() used to set per-image attribute.
933 Used directly by many coders
935 arg1=ArgOption("0.0");
936 if (IfMagickFalse(IsGeometry(arg1)))
937 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
938 (void) SetImageOption(_image_info,option+1,arg1);
941 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
945 if (LocaleCompare("highlight-color",option+1) == 0)
947 /* FUTURE: this is only used by CompareImages() which is used
948 only by the "compare" CLI program at this time. */
949 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
952 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
956 if (LocaleCompare("intensity",option+1) == 0)
958 arg1 = ArgOption("undefined");
959 parse = ParseCommandOption(MagickPixelIntensityOptions,MagickFalse,
962 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityType",
964 (void) SetImageOption(_image_info,option+1,arg1);
967 if (LocaleCompare("intent",option+1) == 0)
969 /* Only used by coders: MIFF, MPC, BMP, PNG
970 and for image profile call to AcquireTransformThreadSet()
971 SyncImageSettings() used to set per-image attribute.
973 arg1 = ArgOption("undefined");
974 parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1);
976 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType",
978 (void) SetImageOption(_image_info,option+1,arg1);
981 if (LocaleCompare("interlace",option+1) == 0)
983 /* _image_info is directly used by coders (so why an image setting?)
984 SyncImageSettings() used to set per-image attribute.
986 arg1 = ArgOption("undefined");
987 parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1);
989 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType",
991 _image_info->interlace=(InterlaceType) parse;
992 (void) SetImageOption(_image_info,option+1,arg1);
995 if (LocaleCompare("interline-spacing",option+1) == 0)
997 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
998 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
999 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1000 _draw_info->interline_spacing=StringToDouble(ArgOption("0"),
1004 if (LocaleCompare("interpolate",option+1) == 0)
1006 /* SyncImageSettings() used to set per-image attribute. */
1007 arg1 = ArgOption("undefined");
1008 parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1);
1010 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod",
1012 (void) SetImageOption(_image_info,option+1,arg1);
1015 if (LocaleCompare("interword-spacing",option+1) == 0)
1017 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1018 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1019 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1020 _draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
1023 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1027 if (LocaleCompare("kerning",option+1) == 0)
1029 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1030 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1031 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1032 _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
1035 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1039 if (LocaleCompare("label",option+1) == 0)
1041 /* only used for new images - not in SyncImageOptions() */
1042 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1045 if (LocaleCompare("limit",option+1) == 0)
1050 limit=MagickResourceInfinity;
1051 parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1);
1053 CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType",
1055 if (LocaleCompare("unlimited",arg2) != 0)
1056 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
1057 (void) SetMagickResourceLimit((ResourceType)parse,limit);
1060 if (LocaleCompare("log",option+1) == 0)
1063 if ((strchr(arg1,'%') == (char *) NULL))
1064 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1065 (void) SetLogFormat(arg1);
1069 if (LocaleCompare("lowlight-color",option+1) == 0)
1071 /* FUTURE: this is only used by CompareImages() which is used
1072 only by the "compare" CLI program at this time. */
1073 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1076 if (LocaleCompare("loop",option+1) == 0)
1078 /* SyncImageSettings() used to set per-image attribute. */
1079 arg1=ArgOption("0");
1080 if (IfMagickFalse(IsGeometry(arg1)))
1081 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1082 (void) SetImageOption(_image_info,option+1,arg1);
1085 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1089 if (LocaleCompare("mattecolor",option+1) == 0)
1091 /* SyncImageSettings() used to set per-image attribute. */
1092 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1093 (void) QueryColorCompliance(ArgOption(MogrifyMatteColor),AllCompliance,
1094 &_image_info->matte_color,_exception);
1097 if (LocaleCompare("metric",option+1) == 0)
1099 /* FUTURE: this is only used by CompareImages() which is used
1100 only by the "compare" CLI program at this time. */
1101 parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1);
1103 CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType",
1105 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1108 if (LocaleCompare("moments",option+1) == 0)
1110 (void) SetImageOption(_image_info,"identify:moments",
1113 (void) SetImageArtifact(_image,"verbose","true");
1116 if (LocaleCompare("monitor",option+1) == 0)
1118 (void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
1119 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1122 if (LocaleCompare("monochrome",option+1) == 0)
1124 /* Setting (used by some input coders!) -- why?
1125 Warning: This is also Special '-type' SimpleOperator
1127 _image_info->monochrome= ArgBoolean;
1130 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1134 if (LocaleCompare("orient",option+1) == 0)
1136 /* Is not used when defining for new images.
1137 This makes it more of a 'operation' than a setting
1138 FUTURE: make set meta-data operator instead.
1139 SyncImageSettings() used to set per-image attribute.
1141 parse=ParseCommandOption(MagickOrientationOptions,MagickFalse,
1142 ArgOption("undefined"));
1144 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation",
1146 _image_info->orientation=(OrientationType)parse;
1147 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1150 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1154 if (LocaleCompare("page",option+1) == 0)
1156 /* Only used for new images and image generators.
1157 SyncImageSettings() used to set per-image attribute. ?????
1158 That last is WRONG!!!!
1159 FUTURE: adjust named 'page' sizes according density
1163 page[MagickPathExtent];
1176 (void) DeleteImageOption(_image_info,option+1);
1177 (void) CloneString(&_image_info->page,(char *) NULL);
1180 (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1181 image_option=GetImageOption(_image_info,"page");
1182 if (image_option != (const char *) NULL)
1183 flags=ParseAbsoluteGeometry(image_option,&geometry);
1184 canonical_page=GetPageGeometry(arg1);
1185 flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1186 canonical_page=DestroyString(canonical_page);
1187 (void) FormatLocaleString(page,MagickPathExtent,"%lux%lu",
1188 (unsigned long) geometry.width,(unsigned long) geometry.height);
1189 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1190 (void) FormatLocaleString(page,MagickPathExtent,"%lux%lu%+ld%+ld",
1191 (unsigned long) geometry.width,(unsigned long) geometry.height,
1192 (long) geometry.x,(long) geometry.y);
1193 (void) SetImageOption(_image_info,option+1,page);
1194 (void) CloneString(&_image_info->page,page);
1197 if (LocaleCompare("ping",option+1) == 0)
1199 _image_info->ping = ArgBoolean;
1202 if (LocaleCompare("pointsize",option+1) == 0)
1205 if (IfMagickFalse(IsGeometry(arg1)))
1206 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1207 _image_info->pointsize =
1208 _draw_info->pointsize =
1209 StringToDouble(arg1,(char **) NULL);
1212 _image_info->pointsize=0.0; /* unset pointsize */
1213 _draw_info->pointsize=12.0;
1217 if (LocaleCompare("precision",option+1) == 0)
1219 arg1=ArgOption("-1");
1220 if (IfMagickFalse(IsGeometry(arg1)))
1221 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1222 (void) SetMagickPrecision(StringToInteger(arg1));
1225 /* FUTURE: Only the 'preview' coder appears to use this
1226 * DEPRECIATE the coder? Leaving only the 'preview' operator.
1227 if (LocaleCompare("preview",option+1) == 0)
1229 _image_info->preview_type=UndefinedPreview;
1231 _image_info->preview_type=(PreviewType) ParseCommandOption(
1232 MagickPreviewOptions,MagickFalse,arg1);
1236 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1240 if (LocaleCompare("quality",option+1) == 0)
1242 if (IfMagickFalse(IsGeometry(arg1)))
1243 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1244 _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1)
1245 : UNDEFINED_COMPRESSION_QUALITY;
1246 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1249 if (LocaleCompare("quantize",option+1) == 0)
1251 /* Just a set direct in _quantize_info */
1252 arg1=ArgOption("undefined");
1253 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
1255 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
1257 _quantize_info->colorspace=(ColorspaceType)parse;
1260 if (LocaleCompare("quiet",option+1) == 0)
1262 /* FUTURE: if two -quiet is performed you can not do +quiet!
1263 This needs to be checked over thoughly.
1265 static WarningHandler
1266 warning_handler = (WarningHandler) NULL;
1269 tmp = SetWarningHandler((WarningHandler) NULL);
1271 if ( tmp != (WarningHandler) NULL)
1272 warning_handler = tmp; /* remember the old handler */
1273 if (!IfSetOption) /* set the old handler */
1274 warning_handler=SetWarningHandler(warning_handler);
1277 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1281 if (LocaleCompare("red-primary",option+1) == 0)
1283 /* Image chromaticity X,Y NB: Y=X if Y not defined
1285 SyncImageSettings() used to set per-image attribute.
1287 arg1=ArgOption("0.0");
1288 if (IfMagickFalse(IsGeometry(arg1)))
1289 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1290 (void) SetImageOption(_image_info,option+1,arg1);
1293 if (LocaleCompare("regard-warnings",option+1) == 0)
1294 /* FUTURE: to be replaced by a 'fatal-level' type setting */
1296 if (LocaleCompare("render",option+1) == 0)
1298 /* _draw_info only setting */
1299 _draw_info->render= ArgBooleanNot;
1302 if (LocaleCompare("respect-parenthesis",option+1) == 0)
1304 /* link image and setting stacks - option is itself saved on stack! */
1305 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1308 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1312 if (LocaleCompare("sampling-factor",option+1) == 0)
1314 /* FUTURE: should be converted to jpeg:sampling_factor */
1315 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1316 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1317 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1320 if (LocaleCompare("scene",option+1) == 0)
1322 /* SyncImageSettings() used to set this as a per-image attribute.
1325 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1326 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1327 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1328 _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1331 if (LocaleCompare("seed",option+1) == 0)
1333 if (IfMagickFalse(IsGeometry(arg1)))
1334 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1336 IfSetOption ? (unsigned long) StringToUnsignedLong(arg1)
1337 : (unsigned long) time((time_t *) NULL) );
1340 if (LocaleCompare("size",option+1) == 0)
1342 /* FUTURE: string in _image_info -- convert to Option ???
1343 Look at the special handling for "size" in SetImageOption()
1345 (void) CloneString(&_image_info->size,ArgOption(NULL));
1348 if (LocaleCompare("stretch",option+1) == 0)
1350 arg1=ArgOption("undefined");
1351 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1353 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1355 _draw_info->stretch=(StretchType) parse;
1358 if (LocaleCompare("stroke",option+1) == 0)
1360 /* set stroke color OR stroke-pattern
1361 UPDATE: ensure stroke color is not destroyed is a pattern
1362 is given. Just in case the color is also used for other purposes.
1373 arg1 = ArgOption("none"); /* +fill turns it off! */
1374 (void) SetImageOption(_image_info,option+1,arg1);
1375 if (_draw_info->stroke_pattern != (Image *) NULL)
1376 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1378 /* is it a color or a image? -- ignore exceptions */
1379 sans=AcquireExceptionInfo();
1380 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1381 sans=DestroyExceptionInfo(sans);
1383 if (IfMagickFalse(status))
1384 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1386 _draw_info->stroke=color;
1389 if (LocaleCompare("strokewidth",option+1) == 0)
1391 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1392 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1393 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1394 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1398 if (LocaleCompare("style",option+1) == 0)
1400 arg1=ArgOption("undefined");
1401 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1403 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1405 _draw_info->style=(StyleType) parse;
1409 if (LocaleCompare("subimage-search",option+1) == 0)
1411 /* FUTURE: this is only used by CompareImages() which is used
1412 only by the "compare" CLI program at this time. */
1413 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1417 if (LocaleCompare("synchronize",option+1) == 0)
1419 /* FUTURE: syncronize to storage - but what does that mean? */
1420 _image_info->synchronize = ArgBoolean;
1423 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1427 if (LocaleCompare("taint",option+1) == 0)
1429 /* SyncImageSettings() used to set per-image attribute. */
1430 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1433 if (LocaleCompare("texture",option+1) == 0)
1435 /* Note: arguments do not have percent escapes expanded */
1436 /* FUTURE: move _image_info string to option splay-tree
1437 Other than "montage" what uses "texture" ????
1439 (void) CloneString(&_image_info->texture,ArgOption(NULL));
1442 if (LocaleCompare("tile",option+1) == 0)
1444 /* Note: arguments do not have percent escapes expanded */
1445 _draw_info->fill_pattern=IfSetOption
1446 ?GetImageCache(_image_info,arg1,_exception)
1447 :DestroyImage(_draw_info->fill_pattern);
1450 if (LocaleCompare("tile-offset",option+1) == 0)
1452 /* SyncImageSettings() used to set per-image attribute. ??? */
1453 arg1=ArgOption("0");
1454 if (IfMagickFalse(IsGeometry(arg1)))
1455 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1456 (void) SetImageOption(_image_info,option+1,arg1);
1459 if (LocaleCompare("transparent-color",option+1) == 0)
1461 /* FUTURE: both _image_info attribute & ImageOption in use!
1462 _image_info only used for generating new images.
1463 SyncImageSettings() used to set per-image attribute.
1465 Note that +transparent-color, means fall-back to image
1466 attribute so ImageOption is deleted, not set to a default.
1468 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1469 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1470 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1471 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1472 &_image_info->transparent_color,_exception);
1475 if (LocaleCompare("treedepth",option+1) == 0)
1477 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1478 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1481 if (LocaleCompare("type",option+1) == 0)
1483 /* SyncImageSettings() used to set per-image attribute. */
1484 parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1485 ArgOption("undefined"));
1487 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1489 _image_info->type=(ImageType) parse;
1490 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1493 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1497 if (LocaleCompare("undercolor",option+1) == 0)
1499 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1500 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1501 &_draw_info->undercolor,_exception);
1504 if (LocaleCompare("units",option+1) == 0)
1506 /* SyncImageSettings() used to set per-image attribute.
1507 Should this effect _draw_info X and Y resolution?
1508 FUTURE: this probably should be part of the density setting
1510 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1511 ArgOption("undefined"));
1513 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1515 _image_info->units=(ResolutionType) parse;
1516 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1519 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1523 if (LocaleCompare("verbose",option+1) == 0)
1525 /* FUTURE: Remember all options become image artifacts
1526 _image_info->verbose is only used by coders.
1528 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1529 _image_info->verbose= ArgBoolean;
1530 _image_info->ping=MagickFalse; /* verbose can't be a ping */
1533 if (LocaleCompare("view",option+1) == 0)
1535 /* FUTURE: Convert from _image_info to ImageOption
1536 Only used by coder FPX
1537 And it only tests existance, not its content!
1539 (void) CloneString(&_image_info->view,ArgOption(NULL));
1542 if (LocaleCompare("virtual-pixel",option+1) == 0)
1544 /* SyncImageSettings() used to set per-image attribute.
1545 This is VERY deep in the image caching structure.
1547 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1548 ArgOption("undefined"));
1550 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1552 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1555 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1559 if (LocaleCompare("weight",option+1) == 0)
1561 /* Just what does using a font 'weight' do ???
1562 There is no "-list weight" output (reference manual says there is)
1564 arg1=ArgOption("all");
1565 _draw_info->weight=StringToUnsignedLong(arg1);
1566 if (LocaleCompare(arg1,"all") == 0)
1567 _draw_info->weight=0;
1568 if (LocaleCompare(arg1,"bold") == 0)
1569 _draw_info->weight=700;
1570 if (LocaleCompare(arg1,"bolder") == 0)
1571 if (_draw_info->weight <= 800)
1572 _draw_info->weight+=100;
1573 if (LocaleCompare(arg1,"lighter") == 0)
1574 if (_draw_info->weight >= 100)
1575 _draw_info->weight-=100;
1576 if (LocaleCompare(arg1,"normal") == 0)
1577 _draw_info->weight=400;
1580 if (LocaleCompare("white-point",option+1) == 0)
1582 /* Used as a image chromaticity setting
1583 SyncImageSettings() used to set per-image attribute.
1585 arg1=ArgOption("0.0");
1586 if (IfMagickFalse(IsGeometry(arg1)))
1587 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1588 (void) SetImageOption(_image_info,option+1,arg1);
1591 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1594 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1597 /* clean up percent escape interpreted strings */
1598 if ((arg1 && arg1n) && (arg1 != arg1n ))
1599 arg1=DestroyString((char *) arg1);
1600 if ((arg2 && arg2n) && (arg2 != arg2n ))
1601 arg2=DestroyString((char *) arg2);
1606 #undef _quantize_info
1609 #undef ArgBooleanNot
1610 #undef ArgBooleanString
1617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 + C L I S i m p l e O p e r a t o r I m a g e s %
1625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 % CLISimpleOperatorImages() applys one simple image operation given to all
1628 % the images in the CLI wand, using any per-image or global settings that was
1629 % previously saved in the CLI wand.
1631 % It is assumed that any such settings are up-to-date.
1633 % The format of the WandSimpleOperatorImages method is:
1635 % MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,const char *option,
1636 % const char *arg1, const char *arg2,ExceptionInfo *exception)
1638 % A description of each parameter follows:
1640 % o cli_wand: structure holding settings and images to be operated on
1642 % o option: The option string for the operation
1644 % o arg1, arg2: optional argument strings to the operation
1649 CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1650 image operation to the current image pointed to by the CLI wand.
1652 The image in the list may be modified in three different ways...
1653 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1654 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1655 * one image replace by a list of images (-separate and -crop only!)
1657 In each case the result replaces the single original image in the list, as
1658 well as the pointer to the modified image (last image added if replaced by a
1659 list of images) is returned.
1661 As the image pointed to may be replaced, the first image in the list may
1662 also change. GetFirstImageInList() should be used by caller if they wish
1663 return the Image pointer to the first image in list.
1665 static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand,
1666 const char *option, const char *arg1n, const char *arg2n,
1667 ExceptionInfo *exception)
1684 const char /* percent escaped versions of the args */
1688 #define _image_info (cli_wand->wand.image_info)
1689 #define _image (cli_wand->wand.images)
1690 #define _exception (cli_wand->wand.exception)
1691 #define _draw_info (cli_wand->draw_info)
1692 #define _quantize_info (cli_wand->quantize_info)
1693 #define _process_flags (cli_wand->process_flags)
1694 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
1695 #define IfNormalOp (*option=='-')
1696 #define IfPlusOp (*option!='-')
1697 #define IsNormalOp IsMagickTrue(IfNormalOp)
1698 #define IsPlusOp IsMagickFalse(IfNormalOp)
1700 assert(cli_wand != (MagickCLI *) NULL);
1701 assert(cli_wand->signature == MagickWandSignature);
1702 assert(cli_wand->wand.signature == MagickWandSignature);
1703 assert(_image != (Image *) NULL); /* an image must be present */
1704 if (IfMagickTrue(cli_wand->wand.debug))
1705 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1710 /* Interpret Percent Escapes in Arguments - using first image */
1711 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
1712 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1713 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1714 /* Interpret Percent escapes in argument 1 */
1715 if (arg1n != (char *) NULL) {
1716 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1717 if (arg1 == (char *) NULL) {
1718 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1719 arg1=arg1n; /* use the given argument as is */
1722 if (arg2n != (char *) NULL) {
1723 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1724 if (arg2 == (char *) NULL) {
1725 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1726 arg2=arg2n; /* use the given argument as is */
1730 #undef _process_flags
1734 (void) FormatLocaleFile(stderr,
1735 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1738 new_image = (Image *) NULL; /* the replacement image, if not null at end */
1739 SetGeometryInfo(&geometry_info);
1741 switch (*(option+1))
1745 if (LocaleCompare("adaptive-blur",option+1) == 0)
1747 flags=ParseGeometry(arg1,&geometry_info);
1748 if ((flags & (RhoValue|SigmaValue)) == 0)
1749 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1750 if ((flags & SigmaValue) == 0)
1751 geometry_info.sigma=1.0;
1752 new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1753 geometry_info.sigma,_exception);
1756 if (LocaleCompare("adaptive-resize",option+1) == 0)
1758 /* FUTURE: Roll into a resize special operator */
1759 if (IfMagickFalse(IsGeometry(arg1)))
1760 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1761 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1762 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1766 if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1768 flags=ParseGeometry(arg1,&geometry_info);
1769 if ((flags & (RhoValue|SigmaValue)) == 0)
1770 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1771 if ((flags & SigmaValue) == 0)
1772 geometry_info.sigma=1.0;
1773 new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1774 geometry_info.sigma,_exception);
1777 if (LocaleCompare("alpha",option+1) == 0)
1779 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1781 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1783 (void) SetImageAlphaChannel(_image,(AlphaChannelOption) parse,
1787 if (LocaleCompare("annotate",option+1) == 0)
1790 geometry[MagickPathExtent];
1792 SetGeometryInfo(&geometry_info);
1793 flags=ParseGeometry(arg1,&geometry_info);
1795 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1796 if ((flags & SigmaValue) == 0)
1797 geometry_info.sigma=geometry_info.rho;
1798 (void) CloneString(&_draw_info->text,arg2);
1799 (void) FormatLocaleString(geometry,MagickPathExtent,"%+f%+f",
1800 geometry_info.xi,geometry_info.psi);
1801 (void) CloneString(&_draw_info->geometry,geometry);
1802 _draw_info->affine.sx=cos(DegreesToRadians(
1803 fmod(geometry_info.rho,360.0)));
1804 _draw_info->affine.rx=sin(DegreesToRadians(
1805 fmod(geometry_info.rho,360.0)));
1806 _draw_info->affine.ry=(-sin(DegreesToRadians(
1807 fmod(geometry_info.sigma,360.0))));
1808 _draw_info->affine.sy=cos(DegreesToRadians(
1809 fmod(geometry_info.sigma,360.0)));
1810 (void) AnnotateImage(_image,_draw_info,_exception);
1811 GetAffineMatrix(&_draw_info->affine);
1814 if (LocaleCompare("auto-gamma",option+1) == 0)
1816 (void) AutoGammaImage(_image,_exception);
1819 if (LocaleCompare("auto-level",option+1) == 0)
1821 (void) AutoLevelImage(_image,_exception);
1824 if (LocaleCompare("auto-orient",option+1) == 0)
1826 new_image=AutoOrientImage(_image,_image->orientation,_exception);
1829 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1833 if (LocaleCompare("black-threshold",option+1) == 0)
1835 if (IfMagickFalse(IsGeometry(arg1)))
1836 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1837 (void) BlackThresholdImage(_image,arg1,_exception);
1840 if (LocaleCompare("blue-shift",option+1) == 0)
1842 geometry_info.rho=1.5;
1844 flags=ParseGeometry(arg1,&geometry_info);
1845 if ((flags & RhoValue) == 0)
1846 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1848 new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1851 if (LocaleCompare("blur",option+1) == 0)
1853 flags=ParseGeometry(arg1,&geometry_info);
1854 if ((flags & (RhoValue|SigmaValue)) == 0)
1855 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1856 if ((flags & SigmaValue) == 0)
1857 geometry_info.sigma=1.0;
1858 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1862 if (LocaleCompare("border",option+1) == 0)
1870 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1871 if ((flags & (WidthValue | HeightValue)) == 0)
1872 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1873 compose=OverCompositeOp;
1874 value=GetImageOption(_image_info,"compose");
1875 if (value != (const char *) NULL)
1876 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1878 new_image=BorderImage(_image,&geometry,compose,_exception);
1881 if (LocaleCompare("brightness-contrast",option+1) == 0)
1893 flags=ParseGeometry(arg1,&geometry_info);
1894 if ((flags & RhoValue) == 0)
1895 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1896 brightness=geometry_info.rho;
1898 if ((flags & SigmaValue) != 0)
1899 contrast=geometry_info.sigma;
1900 (void) BrightnessContrastImage(_image,brightness,contrast,
1904 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1908 if (LocaleCompare("canny",option+1) == 0)
1910 flags=ParseGeometry(arg1,&geometry_info);
1911 if ((flags & (RhoValue|SigmaValue)) == 0)
1912 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1913 if ((flags & SigmaValue) == 0)
1914 geometry_info.sigma=1.0;
1915 if ((flags & XiValue) == 0)
1916 geometry_info.xi=10;
1917 if ((flags & PsiValue) == 0)
1918 geometry_info.psi=30;
1919 if ((flags & PercentValue) != 0)
1921 geometry_info.xi/=100.0;
1922 geometry_info.psi/=100.0;
1924 new_image=CannyEdgeImage(_image,geometry_info.rho,geometry_info.sigma,
1925 geometry_info.xi,geometry_info.psi,_exception);
1928 if (LocaleCompare("cdl",option+1) == 0)
1930 /* Note: arguments do not have percent escapes expanded */
1932 *color_correction_collection;
1935 Color correct with a color decision list.
1937 color_correction_collection=FileToString(arg1,~0UL,_exception);
1938 if (color_correction_collection == (char *) NULL)
1940 (void) ColorDecisionListImage(_image,color_correction_collection,
1944 if (LocaleCompare("channel",option+1) == 0)
1948 (void) SetPixelChannelMask(_image,DefaultChannels);
1951 parse=ParseChannelOption(arg1);
1953 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
1955 (void) SetPixelChannelMask(_image,(ChannelType) parse);
1958 if (LocaleCompare("charcoal",option+1) == 0)
1960 flags=ParseGeometry(arg1,&geometry_info);
1961 if ((flags & (RhoValue|SigmaValue)) == 0)
1962 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1963 if ((flags & SigmaValue) == 0)
1964 geometry_info.sigma=1.0;
1965 if ((flags & XiValue) == 0)
1966 geometry_info.xi=1.0;
1967 new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1971 if (LocaleCompare("chop",option+1) == 0)
1973 if (IfMagickFalse(IsGeometry(arg1)))
1974 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1975 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
1976 new_image=ChopImage(_image,&geometry,_exception);
1979 if (LocaleCompare("clamp",option+1) == 0)
1981 (void) ClampImage(_image,_exception);
1984 if (LocaleCompare("clip",option+1) == 0)
1987 (void) ClipImage(_image,_exception);
1988 else /* "+mask" remove the write mask */
1989 (void) SetImageMask(_image,ReadPixelMask,(Image *) NULL,_exception);
1992 if (LocaleCompare("clip-mask",option+1) == 0)
1994 /* Note: arguments do not have percent escapes expanded */
2011 /* use "+clip-mask" Remove the write mask for -clip-path */
2012 (void) SetImageMask(_image,ReadPixelMask,(Image *) NULL,_exception);
2015 mask_image=GetImageCache(_image_info,arg1,_exception);
2016 if (mask_image == (Image *) NULL)
2018 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
2020 /* Create a write mask from cli_wand mask image */
2021 /* FUTURE: use Alpha operations instead and create a Grey Image */
2022 mask_view=AcquireAuthenticCacheView(mask_image,_exception);
2023 for (y=0; y < (ssize_t) mask_image->rows; y++)
2025 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
2027 if (q == (Quantum *) NULL)
2029 for (x=0; x < (ssize_t) mask_image->columns; x++)
2031 if (mask_image->alpha_trait == UndefinedPixelTrait)
2032 SetPixelAlpha(mask_image,(Quantum)
2033 GetPixelIntensity(mask_image,q),q);
2034 SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
2035 q+=GetPixelChannels(mask_image);
2037 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2040 /* clean up and set the write mask */
2041 mask_view=DestroyCacheView(mask_view);
2042 mask_image->alpha_trait=BlendPixelTrait;
2043 (void) SetImageColorspace(_image,GRAYColorspace,_exception);
2044 (void) SetImageMask(_image,ReadPixelMask,mask_image,_exception);
2045 mask_image=DestroyImage(mask_image);
2048 if (LocaleCompare("clip-path",option+1) == 0)
2050 (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2051 /* Note: Use "+clip-mask" remove the write mask added */
2054 if (LocaleCompare("colorize",option+1) == 0)
2056 if (IfMagickFalse(IsGeometry(arg1)))
2057 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2058 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2061 if (LocaleCompare("color-matrix",option+1) == 0)
2066 kernel=AcquireKernelInfo(arg1,exception);
2067 if (kernel == (KernelInfo *) NULL)
2068 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2069 new_image=ColorMatrixImage(_image,kernel,_exception);
2070 kernel=DestroyKernelInfo(kernel);
2073 if (LocaleCompare("colors",option+1) == 0)
2075 /* Reduce the number of colors in the image.
2076 FUTURE: also provide 'plus version with image 'color counts'
2078 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2079 if (_quantize_info->number_colors == 0)
2080 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2081 if ((_image->storage_class == DirectClass) ||
2082 _image->colors > _quantize_info->number_colors)
2083 (void) QuantizeImage(_quantize_info,_image,_exception);
2085 (void) CompressImageColormap(_image,_exception);
2088 if (LocaleCompare("colorspace",option+1) == 0)
2090 /* WARNING: this is both a image_info setting (already done)
2091 and a operator to change image colorspace.
2093 FUTURE: default colorspace should be sRGB!
2094 Unless some type of 'linear colorspace' mode is set.
2096 Note that +colorspace sets "undefined" or no effect on
2097 new images, but forces images already in memory back to RGB!
2098 That seems to be a little strange!
2100 (void) TransformImageColorspace(_image,
2101 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2105 if (LocaleCompare("connected-components",option+1) == 0)
2107 if (IfMagickFalse(IsGeometry(arg1)))
2108 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2109 new_image=ConnectedComponentsImage(_image,(size_t)
2110 StringToInteger(arg1),_exception);
2113 if (LocaleCompare("contrast",option+1) == 0)
2115 CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2116 (void) ContrastImage(_image,IsNormalOp,_exception);
2119 if (LocaleCompare("contrast-stretch",option+1) == 0)
2128 flags=ParseGeometry(arg1,&geometry_info);
2129 if ((flags & RhoValue) == 0)
2130 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2131 black_point=geometry_info.rho;
2132 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2134 if ((flags & PercentValue) != 0) {
2135 black_point*=(double) _image->columns*_image->rows/100.0;
2136 white_point*=(double) _image->columns*_image->rows/100.0;
2138 white_point=(double) _image->columns*_image->rows-white_point;
2139 (void) ContrastStretchImage(_image,black_point,white_point,
2143 if (LocaleCompare("convolve",option+1) == 0)
2154 kernel_info=AcquireKernelInfo(arg1,exception);
2155 if (kernel_info == (KernelInfo *) NULL)
2156 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2158 for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2159 gamma+=kernel_info->values[j];
2160 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2161 for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2162 kernel_info->values[j]*=gamma;
2163 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2165 kernel_info=DestroyKernelInfo(kernel_info);
2168 if (LocaleCompare("crop",option+1) == 0)
2170 /* WARNING: This can generate multiple images! */
2171 if (IfMagickFalse(IsGeometry(arg1)))
2172 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2173 new_image=CropImageToTiles(_image,arg1,_exception);
2176 if (LocaleCompare("cycle",option+1) == 0)
2178 if (IfMagickFalse(IsGeometry(arg1)))
2179 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2180 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2184 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2188 if (LocaleCompare("decipher",option+1) == 0)
2190 /* Note: arguments do not have percent escapes expanded */
2194 passkey=FileToStringInfo(arg1,~0UL,_exception);
2195 if (passkey == (StringInfo *) NULL)
2196 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2198 (void) PasskeyDecipherImage(_image,passkey,_exception);
2199 passkey=DestroyStringInfo(passkey);
2202 if (LocaleCompare("depth",option+1) == 0)
2204 /* The _image_info->depth setting has already been set
2205 We just need to apply it to all images in current sequence
2207 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2208 That is it really is an operation, not a setting! Arrgghhh
2210 FUTURE: this should not be an operator!!!
2212 (void) SetImageDepth(_image,_image_info->depth,_exception);
2215 if (LocaleCompare("deskew",option+1) == 0)
2221 if (IfMagickFalse(IsGeometry(arg1)))
2222 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2223 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2226 threshold=40.0*QuantumRange/100.0;
2227 new_image=DeskewImage(_image,threshold,_exception);
2230 if (LocaleCompare("despeckle",option+1) == 0)
2232 new_image=DespeckleImage(_image,_exception);
2235 if (LocaleCompare("distort",option+1) == 0)
2243 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2245 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2247 if ((DistortImageMethod) parse == ResizeDistortion)
2251 /* Special Case - Argument is actually a resize geometry!
2252 ** Convert that to an appropriate distortion argument array.
2253 ** FUTURE: make a separate special resize operator
2254 Roll into a resize special operator */
2255 if (IfMagickFalse(IsGeometry(arg2)))
2256 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2258 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2259 resize_args[0]=(double) geometry.width;
2260 resize_args[1]=(double) geometry.height;
2261 new_image=DistortImage(_image,(DistortImageMethod) parse,
2262 (size_t)2,resize_args,MagickTrue,_exception);
2265 /* convert argument string into an array of doubles */
2266 args = StringToArrayOfDoubles(arg2,&count,_exception);
2267 if (args == (double *) NULL )
2268 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2270 new_image=DistortImage(_image,(DistortImageMethod) parse,(size_t)
2271 count,args,IsPlusOp,_exception);
2272 args=(double *) RelinquishMagickMemory(args);
2275 if (LocaleCompare("draw",option+1) == 0)
2277 (void) CloneString(&_draw_info->primitive,arg1);
2278 (void) DrawImage(_image,_draw_info,_exception);
2279 (void) CloneString(&_draw_info->primitive,(char *) NULL);
2282 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2286 if (LocaleCompare("edge",option+1) == 0)
2288 flags=ParseGeometry(arg1,&geometry_info);
2289 if ((flags & (RhoValue|SigmaValue)) == 0)
2290 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2291 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2294 if (LocaleCompare("emboss",option+1) == 0)
2296 flags=ParseGeometry(arg1,&geometry_info);
2297 if ((flags & (RhoValue|SigmaValue)) == 0)
2298 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2299 if ((flags & SigmaValue) == 0)
2300 geometry_info.sigma=1.0;
2301 new_image=EmbossImage(_image,geometry_info.rho,
2302 geometry_info.sigma,_exception);
2305 if (LocaleCompare("encipher",option+1) == 0)
2307 /* Note: arguments do not have percent escapes expanded */
2311 passkey=FileToStringInfo(arg1,~0UL,_exception);
2312 if (passkey != (StringInfo *) NULL)
2314 (void) PasskeyEncipherImage(_image,passkey,_exception);
2315 passkey=DestroyStringInfo(passkey);
2319 if (LocaleCompare("enhance",option+1) == 0)
2321 new_image=EnhanceImage(_image,_exception);
2324 if (LocaleCompare("equalize",option+1) == 0)
2326 (void) EqualizeImage(_image,_exception);
2329 if (LocaleCompare("evaluate",option+1) == 0)
2334 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2336 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2338 if (IfMagickFalse(IsGeometry(arg2)))
2339 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2340 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2341 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2345 if (LocaleCompare("extent",option+1) == 0)
2347 if (IfMagickFalse(IsGeometry(arg1)))
2348 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2349 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2350 if (geometry.width == 0)
2351 geometry.width=_image->columns;
2352 if (geometry.height == 0)
2353 geometry.height=_image->rows;
2354 new_image=ExtentImage(_image,&geometry,_exception);
2357 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2361 if (LocaleCompare("flip",option+1) == 0)
2363 new_image=FlipImage(_image,_exception);
2366 if (LocaleCompare("flop",option+1) == 0)
2368 new_image=FlopImage(_image,_exception);
2371 if (LocaleCompare("floodfill",option+1) == 0)
2376 if (IfMagickFalse(IsGeometry(arg1)))
2377 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2378 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2379 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2380 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2381 geometry.y,IsPlusOp,_exception);
2384 if (LocaleCompare("frame",option+1) == 0)
2395 value=GetImageOption(_image_info,"compose");
2396 compose=OverCompositeOp; /* use Over not _image->compose */
2397 if (value != (const char *) NULL)
2398 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2400 if (IfMagickFalse(IsGeometry(arg1)))
2401 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2402 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2403 frame_info.width=geometry.width;
2404 frame_info.height=geometry.height;
2405 frame_info.outer_bevel=geometry.x;
2406 frame_info.inner_bevel=geometry.y;
2407 frame_info.x=(ssize_t) frame_info.width;
2408 frame_info.y=(ssize_t) frame_info.height;
2409 frame_info.width=_image->columns+2*frame_info.width;
2410 frame_info.height=_image->rows+2*frame_info.height;
2411 new_image=FrameImage(_image,&frame_info,compose,_exception);
2414 if (LocaleCompare("function",option+1) == 0)
2422 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2424 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2426 /* convert argument string into an array of doubles */
2427 args = StringToArrayOfDoubles(arg2,&count,_exception);
2428 if (args == (double *) NULL )
2429 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2431 (void) FunctionImage(_image,(MagickFunction)parse,(size_t) count,args,
2433 args=(double *) RelinquishMagickMemory(args);
2436 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2440 if (LocaleCompare("gamma",option+1) == 0)
2445 if (IfMagickFalse(IsGeometry(arg1)))
2446 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2447 constant=StringToDouble(arg1,(char **) NULL);
2449 /* Using Gamma, via a cache */
2451 constant=PerceptibleReciprocal(constant);
2452 (void) GammaImage(_image,constant,_exception);
2454 /* Using Evaluate POW, direct update of values - more accurite */
2456 constant=PerceptibleReciprocal(constant);
2457 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2458 _image->gamma*=StringToDouble(arg1,(char **) NULL);
2460 /* Set gamma setting -- Old meaning of "+gamma"
2461 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2465 if (LocaleCompare("gaussian-blur",option+1) == 0)
2467 flags=ParseGeometry(arg1,&geometry_info);
2468 if ((flags & (RhoValue|SigmaValue)) == 0)
2469 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2470 if ((flags & SigmaValue) == 0)
2471 geometry_info.sigma=1.0;
2472 new_image=GaussianBlurImage(_image,geometry_info.rho,
2473 geometry_info.sigma,_exception);
2476 if (LocaleCompare("gaussian",option+1) == 0)
2478 CLIWandWarnReplaced("-gaussian-blur");
2479 (void) CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2481 if (LocaleCompare("geometry",option+1) == 0)
2484 Record Image offset for composition. (A Setting)
2485 Resize last _image. (ListOperator) -- DEPRECIATE
2486 FUTURE: Why if no 'offset' does this resize ALL images?
2487 Also why is the setting recorded in the IMAGE non-sense!
2490 { /* remove the previous composition geometry offset! */
2491 if (_image->geometry != (char *) NULL)
2492 _image->geometry=DestroyString(_image->geometry);
2495 if (IfMagickFalse(IsGeometry(arg1)))
2496 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2497 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2498 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2499 (void) CloneString(&_image->geometry,arg1);
2501 new_image=ResizeImage(_image,geometry.width,geometry.height,
2502 _image->filter,_exception);
2505 if (LocaleCompare("grayscale",option+1) == 0)
2507 parse=ParseCommandOption(MagickPixelIntensityOptions,
2510 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2512 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2515 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2519 if (LocaleCompare("hough-lines",option+1) == 0)
2521 flags=ParseGeometry(arg1,&geometry_info);
2522 if ((flags & (RhoValue|SigmaValue)) == 0)
2523 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2524 if ((flags & SigmaValue) == 0)
2525 geometry_info.sigma=geometry_info.rho;
2526 if ((flags & XiValue) == 0)
2527 geometry_info.xi=40;
2528 new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2529 (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2532 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2536 if (LocaleCompare("identify",option+1) == 0)
2542 format=GetImageOption(_image_info,"format");
2543 if (format == (char *) NULL)
2545 (void) IdentifyImage(_image,stdout,_image_info->verbose,
2549 text=InterpretImageProperties(_image_info,_image,format,_exception);
2550 if (text == (char *) NULL)
2551 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2553 (void) fputs(text,stdout);
2554 text=DestroyString((char *)text);
2557 if (LocaleCompare("implode",option+1) == 0)
2559 flags=ParseGeometry(arg1,&geometry_info);
2560 if ((flags & RhoValue) == 0)
2561 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2562 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2566 if (LocaleCompare("interpolative-resize",option+1) == 0)
2568 /* FUTURE: New to IMv7
2569 Roll into a resize special operator */
2570 if (IfMagickFalse(IsGeometry(arg1)))
2571 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2572 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2573 new_image=InterpolativeResizeImage(_image,geometry.width,
2574 geometry.height,_image->interpolate,_exception);
2577 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2581 if (LocaleCompare("kuwahara",option+1) == 0)
2584 Edge preserving blur.
2586 flags=ParseGeometry(arg1,&geometry_info);
2587 if ((flags & (RhoValue|SigmaValue)) == 0)
2588 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2589 if ((flags & SigmaValue) == 0)
2590 geometry_info.sigma=geometry_info.rho-0.5;
2591 new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2595 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2599 if (LocaleCompare("lat",option+1) == 0)
2601 flags=ParseGeometry(arg1,&geometry_info);
2602 if ((flags & (RhoValue|SigmaValue)) == 0)
2603 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2604 if ((flags & SigmaValue) == 0)
2605 geometry_info.sigma=1.0;
2606 if ((flags & PercentValue) != 0)
2607 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2608 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2609 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2613 if (LocaleCompare("level",option+1) == 0)
2623 flags=ParseGeometry(arg1,&geometry_info);
2624 if ((flags & RhoValue) == 0)
2625 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2626 black_point=geometry_info.rho;
2627 white_point=(double) QuantumRange;
2628 if ((flags & SigmaValue) != 0)
2629 white_point=geometry_info.sigma;
2631 if ((flags & XiValue) != 0)
2632 gamma=geometry_info.xi;
2633 if ((flags & PercentValue) != 0)
2635 black_point*=(double) (QuantumRange/100.0);
2636 white_point*=(double) (QuantumRange/100.0);
2638 if ((flags & SigmaValue) == 0)
2639 white_point=(double) QuantumRange-black_point;
2640 if (IfPlusOp || ((flags & AspectValue) != 0))
2641 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2643 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2646 if (LocaleCompare("level-colors",option+1) == 0)
2649 token[MagickPathExtent];
2658 p=(const char *) arg1;
2659 GetMagickToken(p,&p,token); /* get black point color */
2660 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2661 (void) QueryColorCompliance(token,AllCompliance,
2662 &black_point,_exception);
2664 (void) QueryColorCompliance("#000000",AllCompliance,
2665 &black_point,_exception);
2666 if (isalpha((int) token[0]) || (token[0] == '#'))
2667 GetMagickToken(p,&p,token);
2669 white_point=black_point; /* set everything to that color */
2672 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2673 GetMagickToken(p,&p,token); /* Get white point color. */
2674 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2675 (void) QueryColorCompliance(token,AllCompliance,
2676 &white_point,_exception);
2678 (void) QueryColorCompliance("#ffffff",AllCompliance,
2679 &white_point,_exception);
2681 (void) LevelImageColors(_image,&black_point,&white_point,
2682 IsPlusOp,_exception);
2685 if (LocaleCompare("linear-stretch",option+1) == 0)
2694 flags=ParseGeometry(arg1,&geometry_info);
2695 if ((flags & RhoValue) == 0)
2696 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2697 black_point=geometry_info.rho;
2698 white_point=(double) _image->columns*_image->rows;
2699 if ((flags & SigmaValue) != 0)
2700 white_point=geometry_info.sigma;
2701 if ((flags & PercentValue) != 0)
2703 black_point*=(double) _image->columns*_image->rows/100.0;
2704 white_point*=(double) _image->columns*_image->rows/100.0;
2706 if ((flags & SigmaValue) == 0)
2707 white_point=(double) _image->columns*_image->rows-
2709 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2712 if (LocaleCompare("liquid-rescale",option+1) == 0)
2714 /* FUTURE: Roll into a resize special operator */
2715 if (IfMagickFalse(IsGeometry(arg1)))
2716 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2717 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2718 if ((flags & XValue) == 0)
2720 if ((flags & YValue) == 0)
2722 new_image=LiquidRescaleImage(_image,geometry.width,
2723 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2726 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2730 if (LocaleCompare("magnify",option+1) == 0)
2732 new_image=MagnifyImage(_image,_exception);
2735 if (LocaleCompare("map",option+1) == 0)
2737 CLIWandWarnReplaced("-remap");
2738 (void) CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL,exception);
2741 if (LocaleCompare("mask",option+1) == 0)
2743 /* Note: arguments do not have percent escapes expanded */
2748 { /* Remove a mask. */
2749 (void) SetImageMask(_image,ReadPixelMask,(Image *) NULL,
2753 /* Set the image mask. */
2754 mask=GetImageCache(_image_info,arg1,_exception);
2755 if (mask == (Image *) NULL)
2757 (void) SetImageMask(_image,ReadPixelMask,mask,_exception);
2758 mask=DestroyImage(mask);
2761 if (LocaleCompare("matte",option+1) == 0)
2763 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2764 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2765 DeactivateAlphaChannel, _exception);
2768 if (LocaleCompare("mean-shift",option+1) == 0)
2770 flags=ParseGeometry(arg1,&geometry_info);
2771 if ((flags & (RhoValue|SigmaValue)) == 0)
2772 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2773 if ((flags & SigmaValue) == 0)
2774 geometry_info.sigma=1.0;
2775 if ((flags & XiValue) == 0)
2776 geometry_info.xi=0.10*QuantumRange;
2777 if ((flags & PercentValue) != 0)
2778 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2779 new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2780 (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2783 if (LocaleCompare("median",option+1) == 0)
2785 CLIWandWarnReplaced("-statistic Median");
2786 (void) CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2789 if (LocaleCompare("mode",option+1) == 0)
2791 /* FUTURE: note this is also a special "montage" option */
2792 CLIWandWarnReplaced("-statistic Mode");
2793 (void) CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,exception);
2796 if (LocaleCompare("modulate",option+1) == 0)
2798 if (IfMagickFalse(IsGeometry(arg1)))
2799 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2800 (void) ModulateImage(_image,arg1,_exception);
2803 if (LocaleCompare("monitor",option+1) == 0)
2805 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2806 (MagickProgressMonitor) NULL,(void *) NULL);
2809 if (LocaleCompare("monochrome",option+1) == 0)
2811 (void) SetImageType(_image,BilevelType,_exception);
2814 if (LocaleCompare("morphology",option+1) == 0)
2817 token[MagickPathExtent];
2829 GetMagickToken(p,&p,token);
2830 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2832 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2835 GetMagickToken(p,&p,token);
2836 if ((*p == ':') || (*p == ','))
2837 GetMagickToken(p,&p,token);
2839 iterations=(ssize_t) StringToLong(p);
2840 kernel=AcquireKernelInfo(arg2,exception);
2841 if (kernel == (KernelInfo *) NULL)
2842 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2843 new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2845 kernel=DestroyKernelInfo(kernel);
2848 if (LocaleCompare("motion-blur",option+1) == 0)
2850 flags=ParseGeometry(arg1,&geometry_info);
2851 if ((flags & (RhoValue|SigmaValue)) == 0)
2852 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2853 if ((flags & SigmaValue) == 0)
2854 geometry_info.sigma=1.0;
2855 new_image=MotionBlurImage(_image,geometry_info.rho,geometry_info.sigma,
2856 geometry_info.xi,_exception);
2859 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2863 if (LocaleCompare("negate",option+1) == 0)
2865 (void) NegateImage(_image, IsPlusOp, _exception);
2868 if (LocaleCompare("noise",option+1) == 0)
2878 CLIWandWarnReplaced("-statistic NonPeak");
2879 (void) CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2882 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2884 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2887 value=GetImageOption(_image_info,"attenuate");
2888 if (value != (const char *) NULL)
2889 attenuate=StringToDouble(value,(char **) NULL);
2890 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2894 if (LocaleCompare("normalize",option+1) == 0)
2896 (void) NormalizeImage(_image,_exception);
2899 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2903 if (LocaleCompare("opaque",option+1) == 0)
2908 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2909 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2913 if (LocaleCompare("ordered-dither",option+1) == 0)
2915 (void) OrderedPosterizeImage(_image,arg1,_exception);
2918 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2922 if (LocaleCompare("paint",option+1) == 0)
2924 flags=ParseGeometry(arg1,&geometry_info);
2925 if ((flags & (RhoValue|SigmaValue)) == 0)
2926 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2927 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2931 if (LocaleCompare("perceptible",option+1) == 0)
2933 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2937 if (LocaleCompare("polaroid",option+1) == 0)
2949 random_info=AcquireRandomInfo();
2950 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2951 random_info=DestroyRandomInfo(random_info);
2954 flags=ParseGeometry(arg1,&geometry_info);
2955 if ((flags & RhoValue) == 0)
2956 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2957 angle=geometry_info.rho;
2959 caption=GetImageProperty(_image,"caption",_exception);
2960 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2961 _image->interpolate,_exception);
2964 if (LocaleCompare("posterize",option+1) == 0)
2966 flags=ParseGeometry(arg1,&geometry_info);
2967 if ((flags & RhoValue) == 0)
2968 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2969 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2970 _quantize_info->dither_method,_exception);
2973 if (LocaleCompare("preview",option+1) == 0)
2975 /* FUTURE: should be a 'Genesis' option?
2976 Option however is also in WandSettingOptionInfo()
2979 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2981 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2983 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2986 if (LocaleCompare("profile",option+1) == 0)
2988 /* Note: arguments do not have percent escapes expanded */
3002 { /* Remove a profile from the _image. */
3003 (void) ProfileImage(_image,arg1,(const unsigned char *)
3007 /* Associate a profile with the _image. */
3008 profile_info=CloneImageInfo(_image_info);
3009 profile=GetImageProfile(_image,"iptc");
3010 if (profile != (StringInfo *) NULL)
3011 profile_info->profile=(void *) CloneStringInfo(profile);
3012 profile_image=GetImageCache(profile_info,arg1,_exception);
3013 profile_info=DestroyImageInfo(profile_info);
3014 if (profile_image == (Image *) NULL)
3019 profile_info=CloneImageInfo(_image_info);
3020 (void) CopyMagickString(profile_info->filename,arg1,
3022 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
3023 if (profile != (StringInfo *) NULL)
3025 (void) ProfileImage(_image,profile_info->magick,
3026 GetStringInfoDatum(profile),(size_t)
3027 GetStringInfoLength(profile),_exception);
3028 profile=DestroyStringInfo(profile);
3030 profile_info=DestroyImageInfo(profile_info);
3033 ResetImageProfileIterator(profile_image);
3034 name=GetNextImageProfile(profile_image);
3035 while (name != (const char *) NULL)
3037 profile=GetImageProfile(profile_image,name);
3038 if (profile != (StringInfo *) NULL)
3039 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3040 (size_t) GetStringInfoLength(profile),_exception);
3041 name=GetNextImageProfile(profile_image);
3043 profile_image=DestroyImage(profile_image);
3046 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3050 if (LocaleCompare("rotational-blur",option+1) == 0)
3052 flags=ParseGeometry(arg1,&geometry_info);
3053 if ((flags & RhoValue) == 0)
3054 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3055 new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3058 if (LocaleCompare("raise",option+1) == 0)
3060 if (IfMagickFalse(IsGeometry(arg1)))
3061 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3062 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3063 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3066 if (LocaleCompare("random-threshold",option+1) == 0)
3068 if (IfMagickFalse(IsGeometry(arg1)))
3069 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3070 (void) RandomThresholdImage(_image,arg1,_exception);
3073 if (LocaleCompare("recolor",option+1) == 0)
3075 CLIWandWarnReplaced("-color-matrix");
3076 (void) CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,exception);
3078 if (LocaleCompare("remap",option+1) == 0)
3080 /* Note: arguments do not have percent escapes expanded */
3084 remap_image=GetImageCache(_image_info,arg1,_exception);
3085 if (remap_image == (Image *) NULL)
3087 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3088 remap_image=DestroyImage(remap_image);
3091 if (LocaleCompare("repage",option+1) == 0)
3095 if (IfMagickFalse(IsGeometry(arg1)))
3096 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3098 (void) ResetImagePage(_image,arg1);
3101 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3104 if (LocaleCompare("resample",option+1) == 0)
3106 /* FUTURE: Roll into a resize special operation */
3107 flags=ParseGeometry(arg1,&geometry_info);
3108 if ((flags & (RhoValue|SigmaValue)) == 0)
3109 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3110 if ((flags & SigmaValue) == 0)
3111 geometry_info.sigma=geometry_info.rho;
3112 new_image=ResampleImage(_image,geometry_info.rho,
3113 geometry_info.sigma,_image->filter,_exception);
3116 if (LocaleCompare("resize",option+1) == 0)
3118 if (IfMagickFalse(IsGeometry(arg1)))
3119 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3120 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3121 new_image=ResizeImage(_image,geometry.width,geometry.height,
3122 _image->filter,_exception);
3125 if (LocaleCompare("roll",option+1) == 0)
3127 if (IfMagickFalse(IsGeometry(arg1)))
3128 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3129 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3130 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3133 if (LocaleCompare("rotate",option+1) == 0)
3135 flags=ParseGeometry(arg1,&geometry_info);
3136 if ((flags & RhoValue) == 0)
3137 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3138 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3140 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3142 new_image=RotateImage(_image,geometry_info.rho,_exception);
3145 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3149 if (LocaleCompare("sample",option+1) == 0)
3151 /* FUTURE: Roll into a resize special operator */
3152 if (IfMagickFalse(IsGeometry(arg1)))
3153 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3154 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3155 new_image=SampleImage(_image,geometry.width,geometry.height,
3159 if (LocaleCompare("scale",option+1) == 0)
3161 /* FUTURE: Roll into a resize special operator */
3162 if (IfMagickFalse(IsGeometry(arg1)))
3163 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3164 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3165 new_image=ScaleImage(_image,geometry.width,geometry.height,
3169 if (LocaleCompare("segment",option+1) == 0)
3171 flags=ParseGeometry(arg1,&geometry_info);
3172 if ((flags & (RhoValue|SigmaValue)) == 0)
3173 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3174 if ((flags & SigmaValue) == 0)
3175 geometry_info.sigma=1.0;
3176 (void) SegmentImage(_image,_image->colorspace,
3177 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3181 if (LocaleCompare("selective-blur",option+1) == 0)
3183 flags=ParseGeometry(arg1,&geometry_info);
3184 if ((flags & (RhoValue|SigmaValue)) == 0)
3185 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3186 if ((flags & SigmaValue) == 0)
3187 geometry_info.sigma=1.0;
3188 if ((flags & PercentValue) != 0)
3189 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3190 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3191 geometry_info.sigma,geometry_info.xi,_exception);
3194 if (LocaleCompare("separate",option+1) == 0)
3196 /* WARNING: This can generate multiple images! */
3197 /* FUTURE - this may be replaced by a "-channel" method */
3198 new_image=SeparateImages(_image,_exception);
3201 if (LocaleCompare("sepia-tone",option+1) == 0)
3203 if (IfMagickFalse(IsGeometry(arg1)))
3204 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3205 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3206 (double) QuantumRange+1.0),_exception);
3209 if (LocaleCompare("shade",option+1) == 0)
3211 flags=ParseGeometry(arg1,&geometry_info);
3212 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3213 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3214 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3215 geometry_info.sigma,_exception);
3218 if (LocaleCompare("shadow",option+1) == 0)
3220 flags=ParseGeometry(arg1,&geometry_info);
3221 if ((flags & (RhoValue|SigmaValue)) == 0)
3222 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3223 if ((flags & SigmaValue) == 0)
3224 geometry_info.sigma=1.0;
3225 if ((flags & XiValue) == 0)
3226 geometry_info.xi=4.0;
3227 if ((flags & PsiValue) == 0)
3228 geometry_info.psi=4.0;
3229 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3230 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3231 ceil(geometry_info.psi-0.5),_exception);
3234 if (LocaleCompare("sharpen",option+1) == 0)
3236 flags=ParseGeometry(arg1,&geometry_info);
3237 if ((flags & (RhoValue|SigmaValue)) == 0)
3238 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3239 if ((flags & SigmaValue) == 0)
3240 geometry_info.sigma=1.0;
3241 if ((flags & XiValue) == 0)
3242 geometry_info.xi=0.0;
3243 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3247 if (LocaleCompare("shave",option+1) == 0)
3249 if (IfMagickFalse(IsGeometry(arg1)))
3250 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3251 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3252 new_image=ShaveImage(_image,&geometry,_exception);
3255 if (LocaleCompare("shear",option+1) == 0)
3257 flags=ParseGeometry(arg1,&geometry_info);
3258 if ((flags & RhoValue) == 0)
3259 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3260 if ((flags & SigmaValue) == 0)
3261 geometry_info.sigma=geometry_info.rho;
3262 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3266 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3268 flags=ParseGeometry(arg1,&geometry_info);
3269 if ((flags & RhoValue) == 0)
3270 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3271 if ((flags & SigmaValue) == 0)
3272 geometry_info.sigma=(double) QuantumRange/2.0;
3273 if ((flags & PercentValue) != 0)
3274 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3276 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3277 geometry_info.sigma,_exception);
3280 if (LocaleCompare("sketch",option+1) == 0)
3282 flags=ParseGeometry(arg1,&geometry_info);
3283 if ((flags & (RhoValue|SigmaValue)) == 0)
3284 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3285 if ((flags & SigmaValue) == 0)
3286 geometry_info.sigma=1.0;
3287 new_image=SketchImage(_image,geometry_info.rho,
3288 geometry_info.sigma,geometry_info.xi,_exception);
3291 if (LocaleCompare("solarize",option+1) == 0)
3293 if (IfMagickFalse(IsGeometry(arg1)))
3294 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3295 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3296 QuantumRange+1.0),_exception);
3299 if (LocaleCompare("sparse-color",option+1) == 0)
3301 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3303 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3305 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3309 if (LocaleCompare("splice",option+1) == 0)
3311 if (IfMagickFalse(IsGeometry(arg1)))
3312 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3313 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3314 new_image=SpliceImage(_image,&geometry,_exception);
3317 if (LocaleCompare("spread",option+1) == 0)
3319 flags=ParseGeometry(arg1,&geometry_info);
3320 if ((flags & RhoValue) == 0)
3321 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3322 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3326 if (LocaleCompare("statistic",option+1) == 0)
3328 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3330 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3332 flags=ParseGeometry(arg2,&geometry_info);
3333 if ((flags & RhoValue) == 0)
3334 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3335 if ((flags & SigmaValue) == 0)
3336 geometry_info.sigma=geometry_info.rho;
3337 new_image=StatisticImage(_image,(StatisticType)parse,
3338 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3342 if (LocaleCompare("strip",option+1) == 0)
3344 (void) StripImage(_image,_exception);
3347 if (LocaleCompare("swirl",option+1) == 0)
3349 flags=ParseGeometry(arg1,&geometry_info);
3350 if ((flags & RhoValue) == 0)
3351 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3352 new_image=SwirlImage(_image,geometry_info.rho,
3353 _image->interpolate,_exception);
3356 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3360 if (LocaleCompare("threshold",option+1) == 0)
3365 threshold=(double) QuantumRange/2;
3367 if (IfMagickFalse(IsGeometry(arg1)))
3368 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3369 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3371 (void) BilevelImage(_image,threshold,_exception);
3374 if (LocaleCompare("thumbnail",option+1) == 0)
3376 if (IfMagickFalse(IsGeometry(arg1)))
3377 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3378 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3379 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3383 if (LocaleCompare("tint",option+1) == 0)
3385 if (IfMagickFalse(IsGeometry(arg1)))
3386 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3387 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3390 if (LocaleCompare("transform",option+1) == 0)
3392 CLIWandWarnReplaced("+distort AffineProjection");
3393 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3396 if (LocaleCompare("transparent",option+1) == 0)
3401 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3402 (void) TransparentPaintImage(_image,&target,(Quantum)
3403 TransparentAlpha,IsPlusOp,_exception);
3406 if (LocaleCompare("transpose",option+1) == 0)
3408 new_image=TransposeImage(_image,_exception);
3411 if (LocaleCompare("transverse",option+1) == 0)
3413 new_image=TransverseImage(_image,_exception);
3416 if (LocaleCompare("trim",option+1) == 0)
3418 new_image=TrimImage(_image,_exception);
3421 if (LocaleCompare("type",option+1) == 0)
3423 /* Note that "type" setting should have already been defined */
3424 (void) SetImageType(_image,_image_info->type,_exception);
3427 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3431 if (LocaleCompare("unique",option+1) == 0)
3433 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3434 Option is not documented, bt appears to be for "identify".
3435 We may need a identify specific verbose!
3438 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3441 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3442 (void) SetImageArtifact(_image,"verbose","true");
3445 if (LocaleCompare("unique-colors",option+1) == 0)
3447 new_image=UniqueImageColors(_image,_exception);
3450 if (LocaleCompare("unsharp",option+1) == 0)
3452 flags=ParseGeometry(arg1,&geometry_info);
3453 if ((flags & (RhoValue|SigmaValue)) == 0)
3454 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3455 if ((flags & SigmaValue) == 0)
3456 geometry_info.sigma=1.0;
3457 if ((flags & XiValue) == 0)
3458 geometry_info.xi=1.0;
3459 if ((flags & PsiValue) == 0)
3460 geometry_info.psi=0.05;
3461 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3462 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3465 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3469 if (LocaleCompare("verbose",option+1) == 0)
3471 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3472 three places! ImageArtifact ImageOption _image_info->verbose
3473 Some how new images also get this artifact!
3475 (void) SetImageArtifact(_image,option+1,
3476 IfNormalOp ? "true" : "false" );
3479 if (LocaleCompare("vignette",option+1) == 0)
3481 flags=ParseGeometry(arg1,&geometry_info);
3482 if ((flags & (RhoValue|SigmaValue)) == 0)
3483 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3484 if ((flags & SigmaValue) == 0)
3485 geometry_info.sigma=1.0;
3486 if ((flags & XiValue) == 0)
3487 geometry_info.xi=0.1*_image->columns;
3488 if ((flags & PsiValue) == 0)
3489 geometry_info.psi=0.1*_image->rows;
3490 if ((flags & PercentValue) != 0)
3492 geometry_info.xi*=(double) _image->columns/100.0;
3493 geometry_info.psi*=(double) _image->rows/100.0;
3495 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3496 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3497 ceil(geometry_info.psi-0.5),_exception);
3500 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3504 if (LocaleCompare("wave",option+1) == 0)
3506 flags=ParseGeometry(arg1,&geometry_info);
3507 if ((flags & (RhoValue|SigmaValue)) == 0)
3508 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3509 if ((flags & SigmaValue) == 0)
3510 geometry_info.sigma=1.0;
3511 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3512 _image->interpolate,_exception);
3515 if (LocaleCompare("white-threshold",option+1) == 0)
3517 if (IfMagickFalse(IsGeometry(arg1)))
3518 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3519 (void) WhiteThresholdImage(_image,arg1,_exception);
3522 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3525 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3527 /* clean up percent escape interpreted strings */
3529 arg1=DestroyString((char *)arg1);
3531 arg2=DestroyString((char *)arg2);
3533 /* Replace current image with any image that was generated
3534 and set image point to last image (so image->next is correct) */
3535 if (new_image != (Image *) NULL)
3536 ReplaceImageInListReturnLast(&_image,new_image);
3541 #undef _quantize_info
3550 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3551 const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3553 #if !USE_WAND_METHODS
3559 assert(cli_wand != (MagickCLI *) NULL);
3560 assert(cli_wand->signature == MagickWandSignature);
3561 assert(cli_wand->wand.signature == MagickWandSignature);
3562 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3564 if (IfMagickTrue(cli_wand->wand.debug))
3565 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3566 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3568 #if !USE_WAND_METHODS
3569 /* FUTURE add appropriate tracing */
3571 n=GetImageListLength(cli_wand->wand.images);
3572 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3575 CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3576 if ( cli_wand->wand.images->next == (Image *) NULL )
3578 cli_wand->wand.images=cli_wand->wand.images->next;
3581 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3583 MagickResetIterator(&cli_wand->wand);
3584 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3585 (void) CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3586 MagickResetIterator(&cli_wand->wand);
3592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596 + C L I L i s t O p e r a t o r I m a g e s %
3600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602 % CLIListOperatorImages() applies a single operation that is apply to the
3603 % entire image list as a whole. The result is often a complete replacment
3604 % of the image list with a completely new list, or with just a single image
3607 % The format of the MogrifyImage method is:
3609 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3610 % const char *option,const char *arg1,const char *arg2)
3612 % A description of each parameter follows:
3614 % o cli_wand: structure holding settings to be applied
3616 % o option: The option string for the operation
3618 % o arg1, arg2: optional argument strings to the operation
3619 % arg2 is currently not used
3622 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3623 const char *option,const char *arg1n,const char *arg2n)
3625 const char /* percent escaped versions of the args */
3638 #define _image_info (cli_wand->wand.image_info)
3639 #define _images (cli_wand->wand.images)
3640 #define _exception (cli_wand->wand.exception)
3641 #define _draw_info (cli_wand->draw_info)
3642 #define _quantize_info (cli_wand->quantize_info)
3643 #define _process_flags (cli_wand->process_flags)
3644 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3645 #define IfNormalOp (*option=='-')
3646 #define IfPlusOp (*option!='-')
3647 #define IsNormalOp IsMagickTrue(IfNormalOp)
3649 assert(cli_wand != (MagickCLI *) NULL);
3650 assert(cli_wand->signature == MagickWandSignature);
3651 assert(cli_wand->wand.signature == MagickWandSignature);
3652 assert(_images != (Image *) NULL); /* _images must be present */
3654 if (IfMagickTrue(cli_wand->wand.debug))
3655 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3656 "- List Operator: %s \"%s\" \"%s\"", option,
3657 arg1n == (const char *) NULL ? "null" : arg1n,
3658 arg2n == (const char *) NULL ? "null" : arg2n);
3663 /* Interpret Percent Escapes in Arguments - using first image */
3664 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3665 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3666 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3667 /* Interpret Percent escapes in argument 1 */
3668 if (arg1n != (char *) NULL) {
3669 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3670 if (arg1 == (char *) NULL) {
3671 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3672 arg1=arg1n; /* use the given argument as is */
3675 if (arg2n != (char *) NULL) {
3676 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3677 if (arg2 == (char *) NULL) {
3678 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3679 arg2=arg2n; /* use the given argument as is */
3683 #undef _process_flags
3687 new_images=NewImageList();
3689 switch (*(option+1))
3693 if (LocaleCompare("append",option+1) == 0)
3695 new_images=AppendImages(_images,IsNormalOp,_exception);
3698 if (LocaleCompare("average",option+1) == 0)
3700 CLIWandWarnReplaced("-evaluate-sequence Mean");
3701 (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3704 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3708 if (LocaleCompare("channel-fx",option+1) == 0)
3710 new_images=ChannelFxImage(_images,arg1,_exception);
3713 if (LocaleCompare("clut",option+1) == 0)
3718 /* FUTURE - make this a compose option, and thus can be used
3719 with layers compose or even compose last image over all other
3722 new_images=RemoveFirstImageFromList(&_images);
3723 clut_image=RemoveLastImageFromList(&_images);
3724 /* FUTURE - produce Exception, rather than silent fail */
3725 if (clut_image == (Image *) NULL)
3727 (void) ClutImage(new_images,clut_image,new_images->interpolate,
3729 clut_image=DestroyImage(clut_image);
3732 if (LocaleCompare("coalesce",option+1) == 0)
3734 new_images=CoalesceImages(_images,_exception);
3737 if (LocaleCompare("combine",option+1) == 0)
3739 parse=(ssize_t) _images->colorspace;
3741 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3743 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3745 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3748 if (LocaleCompare("compare",option+1) == 0)
3761 Mathematically and visually annotate the difference between an
3762 image and its reconstruction.
3764 image=RemoveFirstImageFromList(&_images);
3765 reconstruct_image=RemoveFirstImageFromList(&_images);
3766 /* FUTURE - produce Exception, rather than silent fail */
3767 if (reconstruct_image == (Image *) NULL)
3769 metric=UndefinedErrorMetric;
3770 option=GetImageOption(_image_info,"metric");
3771 if (option != (const char *) NULL)
3772 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3773 MagickFalse,option);
3774 new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3777 reconstruct_image=DestroyImage(reconstruct_image);
3778 image=DestroyImage(image);
3781 if (LocaleCompare("complex",option+1) == 0)
3783 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3785 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3787 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3790 if (LocaleCompare("composite",option+1) == 0)
3808 /* Compose value from "-compose" option only */
3809 value=GetImageOption(_image_info,"compose");
3810 if (value == (const char *) NULL)
3811 compose=OverCompositeOp; /* use Over not source_image->compose */
3813 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3816 /* Get "clip-to-self" expert setting (false is normal) */
3817 value=GetImageOption(_image_info,"compose:clip-to-self");
3818 if (value == (const char *) NULL)
3819 clip_to_self=MagickTrue;
3821 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3822 "compose:clip-to-self")); /* if this is true */
3823 value=GetImageOption(_image_info,"compose:outside-overlay");
3824 if (value != (const char *) NULL) { /* or this false */
3825 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3826 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3829 new_images=RemoveFirstImageFromList(&_images);
3830 source_image=RemoveFirstImageFromList(&_images);
3831 if (source_image == (Image *) NULL)
3832 break; /* FUTURE - produce Exception, rather than silent fail */
3834 /* FUTURE - this should not be here! - should be part of -geometry */
3835 (void) TransformImage(&source_image,(char *) NULL,
3836 source_image->geometry,_exception);
3837 SetGeometry(source_image,&geometry);
3838 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3839 GravityAdjustGeometry(new_images->columns,new_images->rows,
3840 new_images->gravity, &geometry);
3841 mask_image=RemoveFirstImageFromList(&_images);
3842 if (mask_image == (Image *) NULL)
3843 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3844 geometry.x,geometry.y,_exception);
3847 if ((compose == DisplaceCompositeOp) ||
3848 (compose == DistortCompositeOp))
3850 status&=CompositeImage(source_image,mask_image,
3851 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3852 status&=CompositeImage(new_images,source_image,compose,
3853 clip_to_self,geometry.x,geometry.y,_exception);
3860 clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
3861 if (clone_image == (Image *) NULL)
3863 status&=CompositeImage(new_images,source_image,compose,
3864 clip_to_self,geometry.x,geometry.y,_exception);
3865 status&=CompositeImage(new_images,mask_image,
3866 CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
3867 status&=CompositeImage(clone_image,new_images,OverCompositeOp,
3868 clip_to_self,geometry.x,geometry.y,_exception);
3869 new_images=DestroyImage(new_images);
3870 new_images=clone_image;
3872 mask_image=DestroyImage(mask_image);
3874 source_image=DestroyImage(source_image);
3877 if (LocaleCompare("copy",option+1) == 0)
3891 if (IfMagickFalse(IsGeometry(arg1)))
3892 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3893 if (IfMagickFalse(IsGeometry(arg2)))
3894 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3895 (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
3896 offset.x=geometry.x;
3897 offset.y=geometry.y;
3898 source_image=_images;
3899 if (source_image->next != (Image *) NULL)
3900 source_image=source_image->next;
3901 (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
3902 (void) CopyImagePixels(_images,source_image,&geometry,&offset,
3906 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3910 if (LocaleCompare("deconstruct",option+1) == 0)
3912 CLIWandWarnReplaced("-layer CompareAny");
3913 (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3916 if (LocaleCompare("delete",option+1) == 0)
3919 DeleteImages(&_images,arg1,_exception);
3921 DeleteImages(&_images,"-1",_exception);
3924 if (LocaleCompare("duplicate",option+1) == 0)
3934 if (IfMagickFalse(IsGeometry(arg1)))
3935 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3937 number_duplicates=(size_t) StringToLong(arg1);
3939 if (p == (const char *) NULL)
3940 new_images=DuplicateImages(_images,number_duplicates,"-1",
3943 new_images=DuplicateImages(_images,number_duplicates,p,
3947 new_images=DuplicateImages(_images,1,"-1",_exception);
3948 AppendImageToList(&_images, new_images);
3949 new_images=(Image *) NULL;
3952 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3956 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3958 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3960 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3962 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3966 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3970 if (LocaleCompare("fft",option+1) == 0)
3972 new_images=ForwardFourierTransformImage(_images,IsNormalOp,
3976 if (LocaleCompare("flatten",option+1) == 0)
3978 /* REDIRECTED to use -layers flatten instead */
3979 (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3982 if (LocaleCompare("fx",option+1) == 0)
3984 new_images=FxImage(_images,arg1,_exception);
3987 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3991 if (LocaleCompare("hald-clut",option+1) == 0)
3993 /* FUTURE - make this a compose option (and thus layers compose )
3994 or perhaps compose last image over all other _images.
3999 new_images=RemoveFirstImageFromList(&_images);
4000 hald_image=RemoveLastImageFromList(&_images);
4001 if (hald_image == (Image *) NULL)
4003 (void) HaldClutImage(new_images,hald_image,_exception);
4004 hald_image=DestroyImage(hald_image);
4007 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4011 if (LocaleCompare("ift",option+1) == 0)
4017 magnitude_image=RemoveFirstImageFromList(&_images);
4018 phase_image=RemoveFirstImageFromList(&_images);
4019 /* FUTURE - produce Exception, rather than silent fail */
4020 if (phase_image == (Image *) NULL)
4022 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4023 IsNormalOp,_exception);
4024 magnitude_image=DestroyImage(magnitude_image);
4025 phase_image=DestroyImage(phase_image);
4028 if (LocaleCompare("insert",option+1) == 0)
4037 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
4038 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4040 insert_image=RemoveLastImageFromList(&_images);
4042 index=(ssize_t) StringToLong(arg1);
4043 index_image=insert_image;
4045 PrependImageToList(&_images,insert_image);
4046 else if (index == (ssize_t) GetImageListLength(_images))
4047 AppendImageToList(&_images,insert_image);
4050 index_image=GetImageFromList(_images,index-1);
4051 if (index_image == (Image *) NULL)
4052 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4053 InsertImageInList(&index_image,insert_image);
4055 _images=GetFirstImageInList(index_image);
4058 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4062 if (LocaleCompare("layers",option+1) == 0)
4064 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4066 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4068 switch ((LayerMethod) parse)
4072 new_images=CoalesceImages(_images,_exception);
4075 case CompareAnyLayer:
4076 case CompareClearLayer:
4077 case CompareOverlayLayer:
4080 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4087 case TrimBoundsLayer:
4089 new_images=MergeImageLayers(_images,(LayerMethod) parse,
4095 new_images=DisposeImages(_images,_exception);
4098 case OptimizeImageLayer:
4100 new_images=OptimizeImageLayers(_images,_exception);
4103 case OptimizePlusLayer:
4105 new_images=OptimizePlusImageLayers(_images,_exception);
4108 case OptimizeTransLayer:
4110 OptimizeImageTransparency(_images,_exception);
4113 case RemoveDupsLayer:
4115 RemoveDuplicateLayers(&_images,_exception);
4118 case RemoveZeroLayer:
4120 RemoveZeroDelayLayers(&_images,_exception);
4124 { /* General Purpose, GIF Animation Optimizer. */
4125 new_images=CoalesceImages(_images,_exception);
4126 if (new_images == (Image *) NULL)
4128 _images=DestroyImageList(_images);
4129 _images=OptimizeImageLayers(new_images,_exception);
4130 if (_images == (Image *) NULL)
4132 new_images=DestroyImageList(new_images);
4133 OptimizeImageTransparency(_images,_exception);
4134 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4138 case CompositeLayer:
4152 value=GetImageOption(_image_info,"compose");
4153 compose=OverCompositeOp; /* Default to Over */
4154 if (value != (const char *) NULL)
4155 compose=(CompositeOperator) ParseCommandOption(
4156 MagickComposeOptions,MagickFalse,value);
4158 /* Split image sequence at the first 'NULL:' image. */
4160 while (source != (Image *) NULL)
4162 source=GetNextImageInList(source);
4163 if ((source != (Image *) NULL) &&
4164 (LocaleCompare(source->magick,"NULL") == 0))
4167 if (source != (Image *) NULL)
4169 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4170 (GetNextImageInList(source) == (Image *) NULL))
4171 source=(Image *) NULL;
4173 { /* Separate the two lists, junk the null: image. */
4174 source=SplitImageList(source->previous);
4175 DeleteImageFromList(&source);
4178 if (source == (Image *) NULL)
4180 (void) ThrowMagickException(_exception,GetMagickModule(),
4181 OptionError,"MissingNullSeparator","layers Composite");
4184 /* Adjust offset with gravity and virtual canvas. */
4185 SetGeometry(_images,&geometry);
4186 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4187 geometry.width=source->page.width != 0 ?
4188 source->page.width : source->columns;
4189 geometry.height=source->page.height != 0 ?
4190 source->page.height : source->rows;
4191 GravityAdjustGeometry(_images->page.width != 0 ?
4192 _images->page.width : _images->columns,
4193 _images->page.height != 0 ? _images->page.height :
4194 _images->rows,_images->gravity,&geometry);
4196 /* Compose the two image sequences together */
4197 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4199 source=DestroyImageList(source);
4205 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4209 if (LocaleCompare("map",option+1) == 0)
4211 CLIWandWarnReplaced("+remap");
4212 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4215 if (LocaleCompare("metric",option+1) == 0)
4217 if (LocaleCompare("morph",option+1) == 0)
4222 if (IfMagickFalse(IsGeometry(arg1)))
4223 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4224 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4226 if (morph_image == (Image *) NULL)
4228 _images=DestroyImageList(_images);
4229 _images=morph_image;
4232 if (LocaleCompare("mosaic",option+1) == 0)
4234 /* REDIRECTED to use -layers mosaic instead */
4235 (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4238 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4242 if (LocaleCompare("poly",option+1) == 0)
4250 /* convert argument string into an array of doubles */
4251 args = StringToArrayOfDoubles(arg1,&count,_exception);
4252 if (args == (double *) NULL )
4253 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4254 new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4256 args=(double *) RelinquishMagickMemory(args);
4259 if (LocaleCompare("process",option+1) == 0)
4261 /* FUTURE: better parsing using ScriptToken() from string ??? */
4269 arguments=StringToArgv(arg1,&number_arguments);
4270 if (arguments == (char **) NULL)
4272 if (strchr(arguments[1],'=') != (char *) NULL)
4293 Support old style syntax, filter="-option arg1".
4295 assert(arg1 != (const char *) NULL);
4296 length=strlen(arg1);
4297 token=(char *) NULL;
4298 if (~length >= (MagickPathExtent-1))
4299 token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4301 if (token == (char *) NULL)
4305 token_info=AcquireTokenInfo();
4306 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4307 "\"",'\0',&breaker,&next,"e);
4308 token_info=DestroyTokenInfo(token_info);
4314 argv=(&(arguments[next]));
4315 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4318 token=DestroyString(token);
4321 (void) SubstituteString(&arguments[1],"-","");
4322 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4323 number_arguments-2,(const char **) arguments+2,_exception);
4324 for (j=0; j < number_arguments; j++)
4325 arguments[j]=DestroyString(arguments[j]);
4326 arguments=(char **) RelinquishMagickMemory(arguments);
4329 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4333 if (LocaleCompare("remap",option+1) == 0)
4335 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4338 if (LocaleCompare("reverse",option+1) == 0)
4340 ReverseImageList(&_images);
4343 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4347 if (LocaleCompare("smush",option+1) == 0)
4349 /* FUTURE: this option needs more work to make better */
4353 if (IfMagickFalse(IsGeometry(arg1)))
4354 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4355 offset=(ssize_t) StringToLong(arg1);
4356 new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4359 if (LocaleCompare("subimage",option+1) == 0)
4377 base_image=GetImageFromList(_images,0);
4378 compare_image=GetImageFromList(_images,1);
4380 /* Comparision Metric */
4381 metric=UndefinedErrorMetric;
4382 value=GetImageOption(_image_info,"metric");
4383 if (value != (const char *) NULL)
4384 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4387 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4388 &offset,&similarity,_exception);
4390 if (new_images != (Image *) NULL)
4393 result[MagickPathExtent];
4395 (void) FormatLocaleString(result,MagickPathExtent,"%lf",
4397 (void) SetImageProperty(new_images,"subimage:similarity",result,
4399 (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4401 (void) SetImageProperty(new_images,"subimage:x",result,
4403 (void) FormatLocaleString(result,MagickPathExtent,"%+ld",(long)
4405 (void) SetImageProperty(new_images,"subimage:y",result,
4407 (void) FormatLocaleString(result,MagickPathExtent,
4408 "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4409 offset.height,(long) offset.x,(long) offset.y);
4410 (void) SetImageProperty(new_images,"subimage:offset",result,
4415 if (LocaleCompare("swap",option+1) == 0)
4436 flags=ParseGeometry(arg1,&geometry_info);
4437 if ((flags & RhoValue) == 0)
4438 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4439 index=(ssize_t) geometry_info.rho;
4440 if ((flags & SigmaValue) != 0)
4441 swap_index=(ssize_t) geometry_info.sigma;
4443 p=GetImageFromList(_images,index);
4444 q=GetImageFromList(_images,swap_index);
4445 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4447 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4449 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4452 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4453 swap=CloneImage(p,0,0,MagickTrue,_exception);
4454 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4455 ReplaceImageInList(&q,swap);
4456 _images=GetFirstImageInList(q);
4459 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4462 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4465 /* clean up percent escape interpreted strings */
4467 arg1=DestroyString((char *)arg1);
4469 arg2=DestroyString((char *)arg2);
4471 /* if new image list generated, replace existing image list */
4472 if (new_images == (Image *) NULL)
4473 return(status == 0 ? MagickFalse : MagickTrue);
4474 _images=DestroyImageList(_images);
4475 _images=GetFirstImageInList(new_images);
4476 return(status == 0 ? MagickFalse : MagickTrue);
4482 #undef _quantize_info
4489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493 + C L I N o I m a g e O p e r a t i o n s %
4497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4499 % CLINoImageOperator() Applies operations that may not actually need images
4502 % The classic operators of this type is "-read", which actually creates
4503 % images even when no images are present. Or image stack operators, which
4504 % can be applied (push or pop) to an empty image list.
4506 % Note that these operators may involve other special 'option' prefix
4507 % characters other than '-' or '+', namely parenthesis and braces.
4509 % The format of the CLINoImageOption method is:
4511 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4512 % const char *arg1, const char *arg2)
4514 % A description of each parameter follows:
4516 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4518 % o option: The special option (with any switch char) to process
4520 % o arg1 & arg2: Argument for option, if required
4521 % Currently arg2 is not used.
4524 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4525 const char *option,const char *arg1n,const char *arg2n)
4527 const char /* percent escaped versions of the args */
4531 #define _image_info (cli_wand->wand.image_info)
4532 #define _images (cli_wand->wand.images)
4533 #define _exception (cli_wand->wand.exception)
4534 #define _process_flags (cli_wand->process_flags)
4535 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4536 #define IfNormalOp (*option=='-')
4537 #define IfPlusOp (*option!='-')
4539 assert(cli_wand != (MagickCLI *) NULL);
4540 assert(cli_wand->signature == MagickWandSignature);
4541 assert(cli_wand->wand.signature == MagickWandSignature);
4543 if (IfMagickTrue(cli_wand->wand.debug))
4544 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4545 "- NoImage Operator: %s \"%s\" \"%s\"", option,
4546 arg1n != (char *) NULL ? arg1n : "",
4547 arg2n != (char *) NULL ? arg2n : "");
4552 /* Interpret Percent Escapes in Arguments - using first image */
4553 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4554 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4555 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4556 /* Interpret Percent escapes in argument 1 */
4557 if (arg1n != (char *) NULL) {
4558 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4559 if (arg1 == (char *) NULL) {
4560 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4561 arg1=arg1n; /* use the given argument as is */
4564 if (arg2n != (char *) NULL) {
4565 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4566 if (arg2 == (char *) NULL) {
4567 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4568 arg2=arg2n; /* use the given argument as is */
4572 #undef _process_flags
4575 do { /* break to exit code */
4577 No-op options (ignore these)
4579 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4581 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4583 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4585 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4587 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4592 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4593 ( LocaleCompare("--",option) == 0 ) ) {
4594 /* Do Glob filename Expansion for 'arg1' then read all images.
4596 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4597 * (but attaching to the filenames in the generated argument list) any
4598 * [...] read modifiers that may be present.
4600 * For example: It will expand '*.gif[20x20]' into a list such as
4601 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4603 * NOTE: In IMv6 this was done globally across all images. This
4604 * meant you could include IM options in '@filename' lists, but you
4605 * could not include comments. Doing it only for image read makes
4606 * it far more secure.
4608 * Note: arguments do not have percent escapes expanded for security
4616 argv = (char **) &arg1;
4618 /* Expand 'glob' expressions in the given filename.
4619 Expansion handles any 'coder:' prefix, or read modifiers attached
4620 to the filename, including them in the resulting expanded list.
4622 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4623 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4624 option,GetExceptionMessage(errno));
4626 /* loop over expanded filename list, and read then all in */
4627 for (i=0; i < (ssize_t) argc; i++) {
4630 if (IfMagickTrue(_image_info->ping))
4631 new_images=PingImages(_image_info,argv[i],_exception);
4633 new_images=ReadImages(_image_info,argv[i],_exception);
4634 AppendImageToList(&_images, new_images);
4636 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4641 Note: Writing a empty image list is valid in specific cases
4643 if (LocaleCompare("write",option+1) == 0) {
4644 /* Note: arguments do not have percent escapes expanded */
4646 key[MagickPathExtent];
4654 /* Need images, unless a "null:" output coder is used */
4655 if ( _images == (Image *) NULL ) {
4656 if ( LocaleCompare(arg1,"null:") == 0 )
4658 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4661 (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4662 (void) DeleteImageRegistry(key);
4663 write_images=_images;
4665 write_images=CloneImageList(_images,_exception);
4666 write_info=CloneImageInfo(_image_info);
4667 (void) WriteImages(write_info,write_images,arg1,_exception);
4668 write_info=DestroyImageInfo(write_info);
4670 write_images=DestroyImageList(write_images);
4674 Parenthesis and Brace operations
4676 if (LocaleCompare("(",option) == 0) {
4677 /* stack 'push' images */
4685 node=cli_wand->image_list_stack;
4686 for ( ; node != (Stack *) NULL; node=node->next)
4688 if ( size >= MAX_STACK_DEPTH )
4689 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4690 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4691 if (node == (Stack *) NULL)
4692 CLIWandExceptionBreak(ResourceLimitFatalError,
4693 "MemoryAllocationFailed",option);
4694 node->data = (void *)cli_wand->wand.images;
4695 node->next = cli_wand->image_list_stack;
4696 cli_wand->image_list_stack = node;
4697 cli_wand->wand.images = NewImageList();
4699 /* handle respect-parenthesis */
4700 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4701 "respect-parenthesis"))))
4702 option="{"; /* fall-thru so as to push image settings too */
4705 /* fall thru to operation */
4707 if (LocaleCompare("{",option) == 0) {
4708 /* stack 'push' of image_info settings */
4716 node=cli_wand->image_info_stack;
4717 for ( ; node != (Stack *) NULL; node=node->next)
4719 if ( size >= MAX_STACK_DEPTH )
4720 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4721 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4722 if (node == (Stack *) NULL)
4723 CLIWandExceptionBreak(ResourceLimitFatalError,
4724 "MemoryAllocationFailed",option);
4726 node->data = (void *)cli_wand->wand.image_info;
4727 node->next = cli_wand->image_info_stack;
4729 cli_wand->image_info_stack = node;
4730 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4731 if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4732 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4734 cli_wand->wand.image_info = (ImageInfo *)node->data;
4735 node = (Stack *)RelinquishMagickMemory(node);
4741 if (LocaleCompare(")",option) == 0) {
4742 /* pop images from stack */
4746 node = (Stack *)cli_wand->image_list_stack;
4747 if ( node == (Stack *) NULL)
4748 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4749 cli_wand->image_list_stack = node->next;
4751 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4752 cli_wand->wand.images= (Image *)node->data;
4753 node = (Stack *)RelinquishMagickMemory(node);
4755 /* handle respect-parenthesis - of the previous 'pushed' settings */
4756 node = cli_wand->image_info_stack;
4757 if ( node != (Stack *) NULL)
4759 if (IfMagickTrue(IsStringTrue(GetImageOption(
4760 cli_wand->wand.image_info,"respect-parenthesis"))))
4761 option="}"; /* fall-thru so as to pop image settings too */
4767 /* fall thru to next if */
4769 if (LocaleCompare("}",option) == 0) {
4770 /* pop image_info settings from stack */
4774 node = (Stack *)cli_wand->image_info_stack;
4775 if ( node == (Stack *) NULL)
4776 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4777 cli_wand->image_info_stack = node->next;
4779 (void) DestroyImageInfo(cli_wand->wand.image_info);
4780 cli_wand->wand.image_info = (ImageInfo *)node->data;
4781 node = (Stack *)RelinquishMagickMemory(node);
4783 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4784 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4785 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4789 if (LocaleCompare("print",option+1) == 0)
4791 (void) FormatLocaleFile(stdout,"%s",arg1);
4794 if (LocaleCompare("set",option+1) == 0)
4796 /* Settings are applied to each image in memory in turn (if any).
4797 While a option: only need to be applied once globally.
4799 NOTE: rguments have not been automatically percent expaneded
4802 /* escape the 'key' once only, using first image. */
4803 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4804 if (arg1 == (char *) NULL)
4805 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4808 if (LocaleNCompare(arg1,"registry:",9) == 0)
4812 (void) DeleteImageRegistry(arg1+9);
4813 arg1=DestroyString((char *)arg1);
4816 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4817 if (arg2 == (char *) NULL) {
4818 arg1=DestroyString((char *)arg1);
4819 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4822 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4823 arg1=DestroyString((char *)arg1);
4824 arg2=DestroyString((char *)arg2);
4827 if (LocaleNCompare(arg1,"option:",7) == 0)
4829 /* delete equivelent artifact from all images (if any) */
4830 if (_images != (Image *) NULL)
4832 MagickResetIterator(&cli_wand->wand);
4833 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4834 (void) DeleteImageArtifact(_images,arg1+7);
4835 MagickResetIterator(&cli_wand->wand);
4837 /* now set/delete the global option as needed */
4838 /* FUTURE: make escapes in a global 'option:' delayed */
4842 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4843 if (arg2 == (char *) NULL)
4844 CLIWandExceptionBreak(OptionWarning,
4845 "InterpretPropertyFailure",option);
4847 (void) SetImageOption(_image_info,arg1+7,arg2);
4848 arg1=DestroyString((char *)arg1);
4849 arg2=DestroyString((char *)arg2);
4852 /* Set Artifacts/Properties/Attributes all images (required) */
4853 if ( _images == (Image *) NULL )
4854 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4856 MagickResetIterator(&cli_wand->wand);
4857 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4862 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4863 if (arg2 == (char *) NULL)
4864 CLIWandExceptionBreak(OptionWarning,
4865 "InterpretPropertyFailure",option);
4867 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4868 (void) SetImageArtifact(_images,arg1+9,arg2);
4869 else if (LocaleNCompare(arg1,"property:",9) == 0)
4870 (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4872 (void) SetImageProperty(_images,arg1,arg2,_exception);
4873 arg2=DestroyString((char *)arg2);
4875 MagickResetIterator(&cli_wand->wand);
4876 arg1=DestroyString((char *)arg1);
4879 if (LocaleCompare("clone",option+1) == 0) {
4884 arg1=AcquireString("-1");
4885 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4886 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4887 if ( cli_wand->image_list_stack == (Stack *) NULL)
4888 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4889 new_images = (Image *)cli_wand->image_list_stack->data;
4890 if (new_images == (Image *) NULL)
4891 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4892 new_images=CloneImages(new_images,arg1,_exception);
4893 if (new_images == (Image *) NULL)
4894 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4895 AppendImageToList(&_images,new_images);
4899 Informational Operations.
4901 Note that these do not require either a cli-wand or images!
4902 Though currently a cli-wand much be provided regardless.
4904 if (LocaleCompare("version",option+1) == 0)
4906 ListMagickVersion(stdout);
4909 if (LocaleCompare("list",option+1) == 0) {
4911 FUTURE: This 'switch' should really be part of MagickCore
4916 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4918 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4923 case MagickCoderOptions:
4925 (void) ListCoderInfo((FILE *) NULL,_exception);
4928 case MagickColorOptions:
4930 (void) ListColorInfo((FILE *) NULL,_exception);
4933 case MagickConfigureOptions:
4935 (void) ListConfigureInfo((FILE *) NULL,_exception);
4938 case MagickDelegateOptions:
4940 (void) ListDelegateInfo((FILE *) NULL,_exception);
4943 case MagickFontOptions:
4945 (void) ListTypeInfo((FILE *) NULL,_exception);
4948 case MagickFormatOptions:
4949 (void) ListMagickInfo((FILE *) NULL,_exception);
4951 case MagickLocaleOptions:
4952 (void) ListLocaleInfo((FILE *) NULL,_exception);
4954 case MagickLogOptions:
4955 (void) ListLogInfo((FILE *) NULL,_exception);
4957 case MagickMagicOptions:
4958 (void) ListMagicInfo((FILE *) NULL,_exception);
4960 case MagickMimeOptions:
4961 (void) ListMimeInfo((FILE *) NULL,_exception);
4963 case MagickModuleOptions:
4964 (void) ListModuleInfo((FILE *) NULL,_exception);
4966 case MagickPolicyOptions:
4967 (void) ListPolicyInfo((FILE *) NULL,_exception);
4969 case MagickResourceOptions:
4970 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4972 case MagickThresholdOptions:
4973 (void) ListThresholdMaps((FILE *) NULL,_exception);
4976 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4983 CLIWandException(OptionError,"UnrecognizedOption",option);
4985 DisableMSCWarning(4127)
4986 } while (0); /* break to exit code. */
4989 /* clean up percent escape interpreted strings */
4991 arg1=DestroyString((char *)arg1);
4993 arg2=DestroyString((char *)arg2);
5003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5007 + C L I O p t i o n %
5011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5013 % CLIOption() Processes the given option using the given CLI Magick Wand.
5014 % The option arguments can be variable in number, though at this time no more
5015 % that two is actually used by any option (this may change). Excess options
5016 % are simply ignored.
5018 % If the cli_wand->command pointer is non-null, then it is assumed that the
5019 % option has already been search for up from the CommandOptions[] table in
5020 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
5021 % routine will do the lookup instead. The pointer is reset afterward.
5023 % This action allows the caller to lookup and pre-handle any 'special'
5024 % options, (such as implicit reads) before calling this general option
5025 % handler to deal with 'standard' command line options.
5027 % The format of the CLIOption method is:
5029 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5031 % A description of each parameter follows:
5033 % o cli_wand: the main CLI Wand to use.
5035 % o option: The special option (with any switch char) to process
5037 % o args: any required arguments for an option (variable number)
5041 % CLIoption(cli_wand,"-read","rose:");
5042 % CLIoption(cli_wand,"-virtual-pixel","transparent");
5043 % CLIoption(cli_wand,"-distort","SRT:","30");
5044 % CLIoption(cli_wand,"-write","rotated_rose.png");
5047 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5049 const char /* extracted option args from args */
5056 assert(cli_wand != (MagickCLI *) NULL);
5057 assert(cli_wand->signature == MagickWandSignature);
5058 assert(cli_wand->wand.signature == MagickWandSignature);
5060 do { /* Break Code Block for error handling */
5062 /* get information about option */
5063 if ( cli_wand->command == (const OptionInfo *) NULL )
5064 cli_wand->command = GetCommandOptionInfo(option);
5066 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5067 option, cli_wand->command->mnemonic );
5069 option_type=(CommandOptionFlags) cli_wand->command->flags;
5071 if ( option_type == UndefinedOptionFlag )
5072 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5074 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5076 /* deprecated options */
5077 if ( (option_type & DeprecateOptionFlag) != 0 )
5078 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5080 /* options that this module does not handle */
5081 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5082 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5084 /* Get argument strings from VarArgs
5085 How can you determine if enough arguments was supplied?
5086 What happens if not enough arguments were supplied?
5089 count = (size_t) cli_wand->command->type;
5094 va_start(operands,option);
5098 arg1=(const char *) va_arg(operands, const char *);
5100 arg2=(const char *) va_arg(operands, const char *);
5104 (void) FormatLocaleFile(stderr,
5105 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5106 option,(long) count,option_type,arg1,arg2);
5111 Call the appropriate option handler
5114 /* FUTURE: this is temporary - get 'settings' to handle distribution of
5115 settings to images attributes,proprieties,artifacts */
5116 if ( cli_wand->wand.images != (Image *) NULL )
5117 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5118 cli_wand->wand.exception);
5120 if ( (option_type & SettingOptionFlags) != 0 ) {
5121 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5122 // FUTURE: Sync Specific Settings into Image Properities (not global)
5125 /* Operators that do not need images - read, write, stack, clone */
5126 if ((option_type & NoImageOperatorFlag) != 0)
5127 CLINoImageOperator(cli_wand, option, arg1, arg2);
5129 /* FUTURE: The not a setting part below is a temporary hack due to
5130 * some options being both a Setting and a Simple operator.
5131 * Specifically -monitor, -depth, and -colorspace */
5132 if ( cli_wand->wand.images == (Image *) NULL )
5133 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5134 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5135 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5137 /* Operators which loop of individual images, simply */
5138 if ( (option_type & SimpleOperatorFlag) != 0 &&
5139 cli_wand->wand.images != (Image *) NULL) /* temp hack */
5141 ExceptionInfo *exception=AcquireExceptionInfo();
5142 (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5143 exception=DestroyExceptionInfo(exception);
5146 /* Operators that work on the image list as a whole */
5147 if ( (option_type & ListOperatorFlag) != 0 )
5148 (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5150 DisableMSCWarning(4127)
5151 } while (0); /* end Break code block */
5154 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */