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[MaxTextExtent],
106 (void) CopyMagickMemory(tag,text,MaxTextExtent);
108 if (p != (char *) NULL)
110 (void) FormatLocaleString(message,MaxTextExtent,"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)
147 (void) FormatLocaleString(key,MaxTextExtent,"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,MaxTextExtent);
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[MaxTextExtent];
201 assert(image != (Image *) NULL);
202 assert(image->signature == MagickSignature);
203 if (IfMagickTrue(image->debug))
204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
205 assert(exception != (ExceptionInfo *) NULL);
206 assert(exception->signature == MagickSignature);
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 == WandSignature);
427 assert(cli_wand->wand.signature == WandSignature);
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[MaxTextExtent];
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,MaxTextExtent,"%lux%lu",
1188 (unsigned long) geometry.width,(unsigned long) geometry.height);
1189 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1190 (void) FormatLocaleString(page,MaxTextExtent,"%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 */
1599 arg1=DestroyString((char *)arg1);
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 == WandSignature);
1702 assert(cli_wand->wand.signature == WandSignature);
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[MaxTextExtent];
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,MaxTextExtent,"%+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 SetPixelChannelMask(_image,DefaultChannels);
1951 parse=ParseChannelOption(arg1);
1953 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
1955 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,(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,(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,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)
2148 kernel_info=AcquireKernelInfo(arg1,exception);
2149 if (kernel_info == (KernelInfo *) NULL)
2150 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2151 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2153 kernel_info=DestroyKernelInfo(kernel_info);
2156 if (LocaleCompare("crop",option+1) == 0)
2158 /* WARNING: This can generate multiple images! */
2159 if (IfMagickFalse(IsGeometry(arg1)))
2160 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2161 new_image=CropImageToTiles(_image,arg1,_exception);
2164 if (LocaleCompare("cycle",option+1) == 0)
2166 if (IfMagickFalse(IsGeometry(arg1)))
2167 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2168 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2172 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2176 if (LocaleCompare("decipher",option+1) == 0)
2178 /* Note: arguments do not have percent escapes expanded */
2182 passkey=FileToStringInfo(arg1,~0UL,_exception);
2183 if (passkey == (StringInfo *) NULL)
2184 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2186 (void) PasskeyDecipherImage(_image,passkey,_exception);
2187 passkey=DestroyStringInfo(passkey);
2190 if (LocaleCompare("depth",option+1) == 0)
2192 /* The _image_info->depth setting has already been set
2193 We just need to apply it to all images in current sequence
2195 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2196 That is it really is an operation, not a setting! Arrgghhh
2198 FUTURE: this should not be an operator!!!
2200 (void) SetImageDepth(_image,_image_info->depth,_exception);
2203 if (LocaleCompare("deskew",option+1) == 0)
2209 if (IfMagickFalse(IsGeometry(arg1)))
2210 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2211 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2214 threshold=40.0*QuantumRange/100.0;
2215 new_image=DeskewImage(_image,threshold,_exception);
2218 if (LocaleCompare("despeckle",option+1) == 0)
2220 new_image=DespeckleImage(_image,_exception);
2223 if (LocaleCompare("distort",option+1) == 0)
2231 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2233 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2235 if ((DistortImageMethod) parse == ResizeDistortion)
2239 /* Special Case - Argument is actually a resize geometry!
2240 ** Convert that to an appropriate distortion argument array.
2241 ** FUTURE: make a separate special resize operator
2242 Roll into a resize special operator */
2243 if (IfMagickFalse(IsGeometry(arg2)))
2244 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2246 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2247 resize_args[0]=(double) geometry.width;
2248 resize_args[1]=(double) geometry.height;
2249 new_image=DistortImage(_image,(DistortImageMethod) parse,
2250 (size_t)2,resize_args,MagickTrue,_exception);
2253 /* convert argument string into an array of doubles */
2254 args = StringToArrayOfDoubles(arg2,&count,_exception);
2255 if (args == (double *) NULL )
2256 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2258 new_image=DistortImage(_image,(DistortImageMethod) parse,(size_t)
2259 count,args,IsPlusOp,_exception);
2260 args=(double *) RelinquishMagickMemory(args);
2263 if (LocaleCompare("draw",option+1) == 0)
2265 (void) CloneString(&_draw_info->primitive,arg1);
2266 (void) DrawImage(_image,_draw_info,_exception);
2267 (void) CloneString(&_draw_info->primitive,(char *) NULL);
2270 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2274 if (LocaleCompare("edge",option+1) == 0)
2276 flags=ParseGeometry(arg1,&geometry_info);
2277 if ((flags & (RhoValue|SigmaValue)) == 0)
2278 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2279 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2282 if (LocaleCompare("emboss",option+1) == 0)
2284 flags=ParseGeometry(arg1,&geometry_info);
2285 if ((flags & (RhoValue|SigmaValue)) == 0)
2286 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2287 if ((flags & SigmaValue) == 0)
2288 geometry_info.sigma=1.0;
2289 new_image=EmbossImage(_image,geometry_info.rho,
2290 geometry_info.sigma,_exception);
2293 if (LocaleCompare("encipher",option+1) == 0)
2295 /* Note: arguments do not have percent escapes expanded */
2299 passkey=FileToStringInfo(arg1,~0UL,_exception);
2300 if (passkey != (StringInfo *) NULL)
2302 (void) PasskeyEncipherImage(_image,passkey,_exception);
2303 passkey=DestroyStringInfo(passkey);
2307 if (LocaleCompare("enhance",option+1) == 0)
2309 new_image=EnhanceImage(_image,_exception);
2312 if (LocaleCompare("equalize",option+1) == 0)
2314 (void) EqualizeImage(_image,_exception);
2317 if (LocaleCompare("evaluate",option+1) == 0)
2322 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2324 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2326 if (IfMagickFalse(IsGeometry(arg2)))
2327 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2328 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2329 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2333 if (LocaleCompare("extent",option+1) == 0)
2335 if (IfMagickFalse(IsGeometry(arg1)))
2336 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2337 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2338 if (geometry.width == 0)
2339 geometry.width=_image->columns;
2340 if (geometry.height == 0)
2341 geometry.height=_image->rows;
2342 new_image=ExtentImage(_image,&geometry,_exception);
2345 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2349 if (LocaleCompare("flip",option+1) == 0)
2351 new_image=FlipImage(_image,_exception);
2354 if (LocaleCompare("flop",option+1) == 0)
2356 new_image=FlopImage(_image,_exception);
2359 if (LocaleCompare("floodfill",option+1) == 0)
2364 if (IfMagickFalse(IsGeometry(arg1)))
2365 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2366 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2367 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2368 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2369 geometry.y,IsPlusOp,_exception);
2372 if (LocaleCompare("frame",option+1) == 0)
2383 value=GetImageOption(_image_info,"compose");
2384 compose=OverCompositeOp; /* use Over not _image->compose */
2385 if (value != (const char *) NULL)
2386 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2388 if (IfMagickFalse(IsGeometry(arg1)))
2389 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2390 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2391 frame_info.width=geometry.width;
2392 frame_info.height=geometry.height;
2393 frame_info.outer_bevel=geometry.x;
2394 frame_info.inner_bevel=geometry.y;
2395 frame_info.x=(ssize_t) frame_info.width;
2396 frame_info.y=(ssize_t) frame_info.height;
2397 frame_info.width=_image->columns+2*frame_info.width;
2398 frame_info.height=_image->rows+2*frame_info.height;
2399 new_image=FrameImage(_image,&frame_info,compose,_exception);
2402 if (LocaleCompare("function",option+1) == 0)
2410 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2412 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2414 /* convert argument string into an array of doubles */
2415 args = StringToArrayOfDoubles(arg2,&count,_exception);
2416 if (args == (double *) NULL )
2417 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2419 (void) FunctionImage(_image,(MagickFunction)parse,(size_t) count,args,
2421 args=(double *) RelinquishMagickMemory(args);
2424 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2428 if (LocaleCompare("gamma",option+1) == 0)
2433 if (IfMagickFalse(IsGeometry(arg1)))
2434 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2435 constant=StringToDouble(arg1,(char **) NULL);
2437 /* Using Gamma, via a cache */
2439 constant=PerceptibleReciprocal(constant);
2440 (void) GammaImage(_image,constant,_exception);
2442 /* Using Evaluate POW, direct update of values - more accurite */
2444 constant=PerceptibleReciprocal(constant);
2445 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2446 if (_image->gamma != 0.0)
2447 _image->gamma*=constant;
2449 /* Set gamma setting -- Old meaning of "+gamma"
2450 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2454 if (LocaleCompare("gaussian-blur",option+1) == 0)
2456 flags=ParseGeometry(arg1,&geometry_info);
2457 if ((flags & (RhoValue|SigmaValue)) == 0)
2458 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2459 if ((flags & SigmaValue) == 0)
2460 geometry_info.sigma=1.0;
2461 new_image=GaussianBlurImage(_image,geometry_info.rho,
2462 geometry_info.sigma,_exception);
2465 if (LocaleCompare("gaussian",option+1) == 0)
2467 CLIWandWarnReplaced("-gaussian-blur");
2468 (void) CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2470 if (LocaleCompare("geometry",option+1) == 0)
2473 Record Image offset for composition. (A Setting)
2474 Resize last _image. (ListOperator) -- DEPRECIATE
2475 FUTURE: Why if no 'offset' does this resize ALL images?
2476 Also why is the setting recorded in the IMAGE non-sense!
2479 { /* remove the previous composition geometry offset! */
2480 if (_image->geometry != (char *) NULL)
2481 _image->geometry=DestroyString(_image->geometry);
2484 if (IfMagickFalse(IsGeometry(arg1)))
2485 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2486 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2487 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2488 (void) CloneString(&_image->geometry,arg1);
2490 new_image=ResizeImage(_image,geometry.width,geometry.height,
2491 _image->filter,_exception);
2494 if (LocaleCompare("grayscale",option+1) == 0)
2496 parse=ParseCommandOption(MagickPixelIntensityOptions,
2499 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2501 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2504 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2508 if (LocaleCompare("hough-lines",option+1) == 0)
2510 flags=ParseGeometry(arg1,&geometry_info);
2511 if ((flags & (RhoValue|SigmaValue)) == 0)
2512 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2513 if ((flags & SigmaValue) == 0)
2514 geometry_info.sigma=geometry_info.rho;
2515 if ((flags & XiValue) == 0)
2516 geometry_info.xi=40;
2517 new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2518 (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2521 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2525 if (LocaleCompare("identify",option+1) == 0)
2531 format=GetImageOption(_image_info,"format");
2532 if (format == (char *) NULL)
2534 (void) IdentifyImage(_image,stdout,_image_info->verbose,
2538 text=InterpretImageProperties(_image_info,_image,format,_exception);
2539 if (text == (char *) NULL)
2540 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2542 (void) fputs(text,stdout);
2543 text=DestroyString((char *)text);
2546 if (LocaleCompare("implode",option+1) == 0)
2548 flags=ParseGeometry(arg1,&geometry_info);
2549 if ((flags & RhoValue) == 0)
2550 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2551 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2555 if (LocaleCompare("interpolative-resize",option+1) == 0)
2557 /* FUTURE: New to IMv7
2558 Roll into a resize special operator */
2559 if (IfMagickFalse(IsGeometry(arg1)))
2560 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2561 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2562 new_image=InterpolativeResizeImage(_image,geometry.width,
2563 geometry.height,_image->interpolate,_exception);
2566 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2570 if (LocaleCompare("kuwahara",option+1) == 0)
2573 Edge preserving blur.
2575 flags=ParseGeometry(arg1,&geometry_info);
2576 if ((flags & (RhoValue|SigmaValue)) == 0)
2577 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2578 if ((flags & SigmaValue) == 0)
2579 geometry_info.sigma=geometry_info.rho-0.5;
2580 new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2584 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2588 if (LocaleCompare("lat",option+1) == 0)
2590 flags=ParseGeometry(arg1,&geometry_info);
2591 if ((flags & (RhoValue|SigmaValue)) == 0)
2592 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2593 if ((flags & SigmaValue) == 0)
2594 geometry_info.sigma=1.0;
2595 if ((flags & PercentValue) != 0)
2596 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2597 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2598 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2602 if (LocaleCompare("level",option+1) == 0)
2612 flags=ParseGeometry(arg1,&geometry_info);
2613 if ((flags & RhoValue) == 0)
2614 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2615 black_point=geometry_info.rho;
2616 white_point=(double) QuantumRange;
2617 if ((flags & SigmaValue) != 0)
2618 white_point=geometry_info.sigma;
2620 if ((flags & XiValue) != 0)
2621 gamma=geometry_info.xi;
2622 if ((flags & PercentValue) != 0)
2624 black_point*=(double) (QuantumRange/100.0);
2625 white_point*=(double) (QuantumRange/100.0);
2627 if ((flags & SigmaValue) == 0)
2628 white_point=(double) QuantumRange-black_point;
2629 if (IfPlusOp || ((flags & AspectValue) != 0))
2630 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2632 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2635 if (LocaleCompare("level-colors",option+1) == 0)
2638 token[MaxTextExtent];
2647 p=(const char *) arg1;
2648 GetMagickToken(p,&p,token); /* get black point color */
2649 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2650 (void) QueryColorCompliance(token,AllCompliance,
2651 &black_point,_exception);
2653 (void) QueryColorCompliance("#000000",AllCompliance,
2654 &black_point,_exception);
2655 if (isalpha((int) token[0]) || (token[0] == '#'))
2656 GetMagickToken(p,&p,token);
2658 white_point=black_point; /* set everything to that color */
2661 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2662 GetMagickToken(p,&p,token); /* Get white point color. */
2663 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2664 (void) QueryColorCompliance(token,AllCompliance,
2665 &white_point,_exception);
2667 (void) QueryColorCompliance("#ffffff",AllCompliance,
2668 &white_point,_exception);
2670 (void) LevelImageColors(_image,&black_point,&white_point,
2671 IsPlusOp,_exception);
2674 if (LocaleCompare("linear-stretch",option+1) == 0)
2683 flags=ParseGeometry(arg1,&geometry_info);
2684 if ((flags & RhoValue) == 0)
2685 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2686 black_point=geometry_info.rho;
2687 white_point=(double) _image->columns*_image->rows;
2688 if ((flags & SigmaValue) != 0)
2689 white_point=geometry_info.sigma;
2690 if ((flags & PercentValue) != 0)
2692 black_point*=(double) _image->columns*_image->rows/100.0;
2693 white_point*=(double) _image->columns*_image->rows/100.0;
2695 if ((flags & SigmaValue) == 0)
2696 white_point=(double) _image->columns*_image->rows-
2698 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2701 if (LocaleCompare("liquid-rescale",option+1) == 0)
2703 /* FUTURE: Roll into a resize special operator */
2704 if (IfMagickFalse(IsGeometry(arg1)))
2705 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2706 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2707 if ((flags & XValue) == 0)
2709 if ((flags & YValue) == 0)
2711 new_image=LiquidRescaleImage(_image,geometry.width,
2712 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2715 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2719 if (LocaleCompare("magnify",option+1) == 0)
2721 new_image=MagnifyImage(_image,_exception);
2724 if (LocaleCompare("map",option+1) == 0)
2726 CLIWandWarnReplaced("-remap");
2727 (void) CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL,exception);
2730 if (LocaleCompare("mask",option+1) == 0)
2732 /* Note: arguments do not have percent escapes expanded */
2737 { /* Remove a mask. */
2738 (void) SetImageMask(_image,(Image *) NULL,_exception);
2741 /* Set the image mask. */
2742 mask=GetImageCache(_image_info,arg1,_exception);
2743 if (mask == (Image *) NULL)
2745 (void) SetImageMask(_image,mask,_exception);
2746 mask=DestroyImage(mask);
2749 if (LocaleCompare("matte",option+1) == 0)
2751 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2752 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2753 DeactivateAlphaChannel, _exception);
2756 if (LocaleCompare("mean-shift",option+1) == 0)
2758 flags=ParseGeometry(arg1,&geometry_info);
2759 if ((flags & (RhoValue|SigmaValue)) == 0)
2760 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2761 if ((flags & SigmaValue) == 0)
2762 geometry_info.sigma=1.0;
2763 if ((flags & XiValue) == 0)
2764 geometry_info.xi=0.10*QuantumRange;
2765 if ((flags & PercentValue) != 0)
2766 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2767 new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2768 (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2771 if (LocaleCompare("median",option+1) == 0)
2773 CLIWandWarnReplaced("-statistic Median");
2774 (void) CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2777 if (LocaleCompare("mode",option+1) == 0)
2779 /* FUTURE: note this is also a special "montage" option */
2780 CLIWandWarnReplaced("-statistic Mode");
2781 (void) CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,exception);
2784 if (LocaleCompare("modulate",option+1) == 0)
2786 if (IfMagickFalse(IsGeometry(arg1)))
2787 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2788 (void) ModulateImage(_image,arg1,_exception);
2791 if (LocaleCompare("monitor",option+1) == 0)
2793 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2794 (MagickProgressMonitor) NULL,(void *) NULL);
2797 if (LocaleCompare("monochrome",option+1) == 0)
2799 (void) SetImageType(_image,BilevelType,_exception);
2802 if (LocaleCompare("morphology",option+1) == 0)
2805 token[MaxTextExtent];
2817 GetMagickToken(p,&p,token);
2818 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2820 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2823 GetMagickToken(p,&p,token);
2824 if ((*p == ':') || (*p == ','))
2825 GetMagickToken(p,&p,token);
2827 iterations=(ssize_t) StringToLong(p);
2828 kernel=AcquireKernelInfo(arg2,exception);
2829 if (kernel == (KernelInfo *) NULL)
2830 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2831 new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2833 kernel=DestroyKernelInfo(kernel);
2836 if (LocaleCompare("motion-blur",option+1) == 0)
2838 flags=ParseGeometry(arg1,&geometry_info);
2839 if ((flags & (RhoValue|SigmaValue)) == 0)
2840 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2841 if ((flags & SigmaValue) == 0)
2842 geometry_info.sigma=1.0;
2843 new_image=MotionBlurImage(_image,geometry_info.rho,geometry_info.sigma,
2844 geometry_info.xi,_exception);
2847 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2851 if (LocaleCompare("negate",option+1) == 0)
2853 (void) NegateImage(_image, IsPlusOp, _exception);
2856 if (LocaleCompare("noise",option+1) == 0)
2866 CLIWandWarnReplaced("-statistic NonPeak");
2867 (void) CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2870 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2872 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2875 value=GetImageOption(_image_info,"attenuate");
2876 if (value != (const char *) NULL)
2877 attenuate=StringToDouble(value,(char **) NULL);
2878 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2882 if (LocaleCompare("normalize",option+1) == 0)
2884 (void) NormalizeImage(_image,_exception);
2887 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2891 if (LocaleCompare("opaque",option+1) == 0)
2896 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2897 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2901 if (LocaleCompare("ordered-dither",option+1) == 0)
2903 (void) OrderedPosterizeImage(_image,arg1,_exception);
2906 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2910 if (LocaleCompare("paint",option+1) == 0)
2912 flags=ParseGeometry(arg1,&geometry_info);
2913 if ((flags & (RhoValue|SigmaValue)) == 0)
2914 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2915 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2919 if (LocaleCompare("perceptible",option+1) == 0)
2921 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2925 if (LocaleCompare("polaroid",option+1) == 0)
2937 random_info=AcquireRandomInfo();
2938 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2939 random_info=DestroyRandomInfo(random_info);
2942 flags=ParseGeometry(arg1,&geometry_info);
2943 if ((flags & RhoValue) == 0)
2944 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2945 angle=geometry_info.rho;
2947 caption=GetImageProperty(_image,"caption",_exception);
2948 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2949 _image->interpolate,_exception);
2952 if (LocaleCompare("posterize",option+1) == 0)
2954 flags=ParseGeometry(arg1,&geometry_info);
2955 if ((flags & RhoValue) == 0)
2956 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2957 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2958 _quantize_info->dither_method,_exception);
2961 if (LocaleCompare("preview",option+1) == 0)
2963 /* FUTURE: should be a 'Genesis' option?
2964 Option however is also in WandSettingOptionInfo()
2967 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2969 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2971 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2974 if (LocaleCompare("profile",option+1) == 0)
2976 /* Note: arguments do not have percent escapes expanded */
2990 { /* Remove a profile from the _image. */
2991 (void) ProfileImage(_image,arg1,(const unsigned char *)
2995 /* Associate a profile with the _image. */
2996 profile_info=CloneImageInfo(_image_info);
2997 profile=GetImageProfile(_image,"iptc");
2998 if (profile != (StringInfo *) NULL)
2999 profile_info->profile=(void *) CloneStringInfo(profile);
3000 profile_image=GetImageCache(profile_info,arg1,_exception);
3001 profile_info=DestroyImageInfo(profile_info);
3002 if (profile_image == (Image *) NULL)
3007 profile_info=CloneImageInfo(_image_info);
3008 (void) CopyMagickString(profile_info->filename,arg1,
3010 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
3011 if (profile != (StringInfo *) NULL)
3013 (void) ProfileImage(_image,profile_info->magick,
3014 GetStringInfoDatum(profile),(size_t)
3015 GetStringInfoLength(profile),_exception);
3016 profile=DestroyStringInfo(profile);
3018 profile_info=DestroyImageInfo(profile_info);
3021 ResetImageProfileIterator(profile_image);
3022 name=GetNextImageProfile(profile_image);
3023 while (name != (const char *) NULL)
3025 profile=GetImageProfile(profile_image,name);
3026 if (profile != (StringInfo *) NULL)
3027 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3028 (size_t) GetStringInfoLength(profile),_exception);
3029 name=GetNextImageProfile(profile_image);
3031 profile_image=DestroyImage(profile_image);
3034 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3038 if (LocaleCompare("rotational-blur",option+1) == 0)
3040 flags=ParseGeometry(arg1,&geometry_info);
3041 if ((flags & RhoValue) == 0)
3042 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3043 new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3046 if (LocaleCompare("raise",option+1) == 0)
3048 if (IfMagickFalse(IsGeometry(arg1)))
3049 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3050 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3051 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3054 if (LocaleCompare("random-threshold",option+1) == 0)
3056 if (IfMagickFalse(IsGeometry(arg1)))
3057 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3058 (void) RandomThresholdImage(_image,arg1,_exception);
3061 if (LocaleCompare("recolor",option+1) == 0)
3063 CLIWandWarnReplaced("-color-matrix");
3064 (void) CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,exception);
3066 if (LocaleCompare("remap",option+1) == 0)
3068 /* Note: arguments do not have percent escapes expanded */
3072 remap_image=GetImageCache(_image_info,arg1,_exception);
3073 if (remap_image == (Image *) NULL)
3075 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3076 remap_image=DestroyImage(remap_image);
3079 if (LocaleCompare("repage",option+1) == 0)
3083 if (IfMagickFalse(IsGeometry(arg1)))
3084 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3086 (void) ResetImagePage(_image,arg1);
3089 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3092 if (LocaleCompare("resample",option+1) == 0)
3094 /* FUTURE: Roll into a resize special operation */
3095 flags=ParseGeometry(arg1,&geometry_info);
3096 if ((flags & (RhoValue|SigmaValue)) == 0)
3097 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3098 if ((flags & SigmaValue) == 0)
3099 geometry_info.sigma=geometry_info.rho;
3100 new_image=ResampleImage(_image,geometry_info.rho,
3101 geometry_info.sigma,_image->filter,_exception);
3104 if (LocaleCompare("resize",option+1) == 0)
3106 if (IfMagickFalse(IsGeometry(arg1)))
3107 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3108 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3109 new_image=ResizeImage(_image,geometry.width,geometry.height,
3110 _image->filter,_exception);
3113 if (LocaleCompare("roll",option+1) == 0)
3115 if (IfMagickFalse(IsGeometry(arg1)))
3116 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3117 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3118 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3121 if (LocaleCompare("rotate",option+1) == 0)
3123 flags=ParseGeometry(arg1,&geometry_info);
3124 if ((flags & RhoValue) == 0)
3125 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3126 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3128 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3130 new_image=RotateImage(_image,geometry_info.rho,_exception);
3133 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3137 if (LocaleCompare("sample",option+1) == 0)
3139 /* FUTURE: Roll into a resize special operator */
3140 if (IfMagickFalse(IsGeometry(arg1)))
3141 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3142 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3143 new_image=SampleImage(_image,geometry.width,geometry.height,
3147 if (LocaleCompare("scale",option+1) == 0)
3149 /* FUTURE: Roll into a resize special operator */
3150 if (IfMagickFalse(IsGeometry(arg1)))
3151 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3152 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3153 new_image=ScaleImage(_image,geometry.width,geometry.height,
3157 if (LocaleCompare("segment",option+1) == 0)
3159 flags=ParseGeometry(arg1,&geometry_info);
3160 if ((flags & (RhoValue|SigmaValue)) == 0)
3161 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3162 if ((flags & SigmaValue) == 0)
3163 geometry_info.sigma=1.0;
3164 (void) SegmentImage(_image,_image->colorspace,
3165 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3169 if (LocaleCompare("selective-blur",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 if ((flags & PercentValue) != 0)
3177 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3178 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3179 geometry_info.sigma,geometry_info.xi,_exception);
3182 if (LocaleCompare("separate",option+1) == 0)
3184 /* WARNING: This can generate multiple images! */
3185 /* FUTURE - this may be replaced by a "-channel" method */
3186 new_image=SeparateImages(_image,_exception);
3189 if (LocaleCompare("sepia-tone",option+1) == 0)
3191 if (IfMagickFalse(IsGeometry(arg1)))
3192 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3193 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3194 (double) QuantumRange+1.0),_exception);
3197 if (LocaleCompare("shade",option+1) == 0)
3199 flags=ParseGeometry(arg1,&geometry_info);
3200 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3201 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3202 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3203 geometry_info.sigma,_exception);
3206 if (LocaleCompare("shadow",option+1) == 0)
3208 flags=ParseGeometry(arg1,&geometry_info);
3209 if ((flags & (RhoValue|SigmaValue)) == 0)
3210 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3211 if ((flags & SigmaValue) == 0)
3212 geometry_info.sigma=1.0;
3213 if ((flags & XiValue) == 0)
3214 geometry_info.xi=4.0;
3215 if ((flags & PsiValue) == 0)
3216 geometry_info.psi=4.0;
3217 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3218 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3219 ceil(geometry_info.psi-0.5),_exception);
3222 if (LocaleCompare("sharpen",option+1) == 0)
3224 flags=ParseGeometry(arg1,&geometry_info);
3225 if ((flags & (RhoValue|SigmaValue)) == 0)
3226 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3227 if ((flags & SigmaValue) == 0)
3228 geometry_info.sigma=1.0;
3229 if ((flags & XiValue) == 0)
3230 geometry_info.xi=0.0;
3231 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3235 if (LocaleCompare("shave",option+1) == 0)
3237 if (IfMagickFalse(IsGeometry(arg1)))
3238 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3239 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3240 new_image=ShaveImage(_image,&geometry,_exception);
3243 if (LocaleCompare("shear",option+1) == 0)
3245 flags=ParseGeometry(arg1,&geometry_info);
3246 if ((flags & RhoValue) == 0)
3247 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3248 if ((flags & SigmaValue) == 0)
3249 geometry_info.sigma=geometry_info.rho;
3250 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3254 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3256 flags=ParseGeometry(arg1,&geometry_info);
3257 if ((flags & RhoValue) == 0)
3258 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3259 if ((flags & SigmaValue) == 0)
3260 geometry_info.sigma=(double) QuantumRange/2.0;
3261 if ((flags & PercentValue) != 0)
3262 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3264 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3265 geometry_info.sigma,_exception);
3268 if (LocaleCompare("sketch",option+1) == 0)
3270 flags=ParseGeometry(arg1,&geometry_info);
3271 if ((flags & (RhoValue|SigmaValue)) == 0)
3272 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3273 if ((flags & SigmaValue) == 0)
3274 geometry_info.sigma=1.0;
3275 new_image=SketchImage(_image,geometry_info.rho,
3276 geometry_info.sigma,geometry_info.xi,_exception);
3279 if (LocaleCompare("solarize",option+1) == 0)
3281 if (IfMagickFalse(IsGeometry(arg1)))
3282 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3283 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3284 QuantumRange+1.0),_exception);
3287 if (LocaleCompare("sparse-color",option+1) == 0)
3289 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3291 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3293 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3297 if (LocaleCompare("splice",option+1) == 0)
3299 if (IfMagickFalse(IsGeometry(arg1)))
3300 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3301 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3302 new_image=SpliceImage(_image,&geometry,_exception);
3305 if (LocaleCompare("spread",option+1) == 0)
3307 flags=ParseGeometry(arg1,&geometry_info);
3308 if ((flags & RhoValue) == 0)
3309 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3310 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3314 if (LocaleCompare("statistic",option+1) == 0)
3316 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3318 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3320 flags=ParseGeometry(arg2,&geometry_info);
3321 if ((flags & RhoValue) == 0)
3322 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3323 if ((flags & SigmaValue) == 0)
3324 geometry_info.sigma=geometry_info.rho;
3325 new_image=StatisticImage(_image,(StatisticType)parse,
3326 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3330 if (LocaleCompare("strip",option+1) == 0)
3332 (void) StripImage(_image,_exception);
3335 if (LocaleCompare("swirl",option+1) == 0)
3337 flags=ParseGeometry(arg1,&geometry_info);
3338 if ((flags & RhoValue) == 0)
3339 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3340 new_image=SwirlImage(_image,geometry_info.rho,
3341 _image->interpolate,_exception);
3344 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3348 if (LocaleCompare("threshold",option+1) == 0)
3353 threshold=(double) QuantumRange/2;
3355 if (IfMagickFalse(IsGeometry(arg1)))
3356 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3357 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3359 (void) BilevelImage(_image,threshold,_exception);
3362 if (LocaleCompare("thumbnail",option+1) == 0)
3364 if (IfMagickFalse(IsGeometry(arg1)))
3365 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3366 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3367 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3371 if (LocaleCompare("tint",option+1) == 0)
3373 if (IfMagickFalse(IsGeometry(arg1)))
3374 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3375 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3378 if (LocaleCompare("transform",option+1) == 0)
3380 CLIWandWarnReplaced("+distort AffineProjection");
3381 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3384 if (LocaleCompare("transparent",option+1) == 0)
3389 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3390 (void) TransparentPaintImage(_image,&target,(Quantum)
3391 TransparentAlpha,IsPlusOp,_exception);
3394 if (LocaleCompare("transpose",option+1) == 0)
3396 new_image=TransposeImage(_image,_exception);
3399 if (LocaleCompare("transverse",option+1) == 0)
3401 new_image=TransverseImage(_image,_exception);
3404 if (LocaleCompare("trim",option+1) == 0)
3406 new_image=TrimImage(_image,_exception);
3409 if (LocaleCompare("type",option+1) == 0)
3411 /* Note that "type" setting should have already been defined */
3412 (void) SetImageType(_image,_image_info->type,_exception);
3415 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3419 if (LocaleCompare("unique",option+1) == 0)
3421 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3422 Option is not documented, bt appears to be for "identify".
3423 We may need a identify specific verbose!
3426 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3429 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3430 (void) SetImageArtifact(_image,"verbose","true");
3433 if (LocaleCompare("unique-colors",option+1) == 0)
3435 new_image=UniqueImageColors(_image,_exception);
3438 if (LocaleCompare("unsharp",option+1) == 0)
3440 flags=ParseGeometry(arg1,&geometry_info);
3441 if ((flags & (RhoValue|SigmaValue)) == 0)
3442 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3443 if ((flags & SigmaValue) == 0)
3444 geometry_info.sigma=1.0;
3445 if ((flags & XiValue) == 0)
3446 geometry_info.xi=1.0;
3447 if ((flags & PsiValue) == 0)
3448 geometry_info.psi=0.05;
3449 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3450 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3453 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3457 if (LocaleCompare("verbose",option+1) == 0)
3459 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3460 three places! ImageArtifact ImageOption _image_info->verbose
3461 Some how new images also get this artifact!
3463 (void) SetImageArtifact(_image,option+1,
3464 IfNormalOp ? "true" : "false" );
3467 if (LocaleCompare("vignette",option+1) == 0)
3469 flags=ParseGeometry(arg1,&geometry_info);
3470 if ((flags & (RhoValue|SigmaValue)) == 0)
3471 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3472 if ((flags & SigmaValue) == 0)
3473 geometry_info.sigma=1.0;
3474 if ((flags & XiValue) == 0)
3475 geometry_info.xi=0.1*_image->columns;
3476 if ((flags & PsiValue) == 0)
3477 geometry_info.psi=0.1*_image->rows;
3478 if ((flags & PercentValue) != 0)
3480 geometry_info.xi*=(double) _image->columns/100.0;
3481 geometry_info.psi*=(double) _image->rows/100.0;
3483 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3484 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3485 ceil(geometry_info.psi-0.5),_exception);
3488 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3492 if (LocaleCompare("wave",option+1) == 0)
3494 flags=ParseGeometry(arg1,&geometry_info);
3495 if ((flags & (RhoValue|SigmaValue)) == 0)
3496 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3497 if ((flags & SigmaValue) == 0)
3498 geometry_info.sigma=1.0;
3499 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3500 _image->interpolate,_exception);
3503 if (LocaleCompare("white-threshold",option+1) == 0)
3505 if (IfMagickFalse(IsGeometry(arg1)))
3506 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3507 (void) WhiteThresholdImage(_image,arg1,_exception);
3510 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3513 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3515 /* clean up percent escape interpreted strings */
3517 arg1=DestroyString((char *)arg1);
3519 arg2=DestroyString((char *)arg2);
3521 /* Replace current image with any image that was generated
3522 and set image point to last image (so image->next is correct) */
3523 if (new_image != (Image *) NULL)
3524 ReplaceImageInListReturnLast(&_image,new_image);
3529 #undef _quantize_info
3538 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3539 const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3541 #if !USE_WAND_METHODS
3547 assert(cli_wand != (MagickCLI *) NULL);
3548 assert(cli_wand->signature == WandSignature);
3549 assert(cli_wand->wand.signature == WandSignature);
3550 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3552 if (IfMagickTrue(cli_wand->wand.debug))
3553 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3554 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3556 #if !USE_WAND_METHODS
3557 /* FUTURE add appropriate tracing */
3559 n=GetImageListLength(cli_wand->wand.images);
3560 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3563 CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3564 if ( cli_wand->wand.images->next == (Image *) NULL )
3566 cli_wand->wand.images=cli_wand->wand.images->next;
3569 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3571 MagickResetIterator(&cli_wand->wand);
3572 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3573 (void) CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3574 MagickResetIterator(&cli_wand->wand);
3580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3584 + C L I L i s t O p e r a t o r I m a g e s %
3588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590 % CLIListOperatorImages() applies a single operation that is apply to the
3591 % entire image list as a whole. The result is often a complete replacment
3592 % of the image list with a completely new list, or with just a single image
3595 % The format of the MogrifyImage method is:
3597 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3598 % const char *option,const char *arg1,const char *arg2)
3600 % A description of each parameter follows:
3602 % o cli_wand: structure holding settings to be applied
3604 % o option: The option string for the operation
3606 % o arg1, arg2: optional argument strings to the operation
3607 % arg2 is currently not used
3610 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3611 const char *option,const char *arg1n,const char *arg2n)
3613 const char /* percent escaped versions of the args */
3626 #define _image_info (cli_wand->wand.image_info)
3627 #define _images (cli_wand->wand.images)
3628 #define _exception (cli_wand->wand.exception)
3629 #define _draw_info (cli_wand->draw_info)
3630 #define _quantize_info (cli_wand->quantize_info)
3631 #define _process_flags (cli_wand->process_flags)
3632 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3633 #define IfNormalOp (*option=='-')
3634 #define IfPlusOp (*option!='-')
3635 #define IsNormalOp IsMagickTrue(IfNormalOp)
3637 assert(cli_wand != (MagickCLI *) NULL);
3638 assert(cli_wand->signature == WandSignature);
3639 assert(cli_wand->wand.signature == WandSignature);
3640 assert(_images != (Image *) NULL); /* _images must be present */
3642 if (IfMagickTrue(cli_wand->wand.debug))
3643 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3644 "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
3649 /* Interpret Percent Escapes in Arguments - using first image */
3650 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3651 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3652 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3653 /* Interpret Percent escapes in argument 1 */
3654 if (arg1n != (char *) NULL) {
3655 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3656 if (arg1 == (char *) NULL) {
3657 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3658 arg1=arg1n; /* use the given argument as is */
3661 if (arg2n != (char *) NULL) {
3662 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3663 if (arg2 == (char *) NULL) {
3664 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3665 arg2=arg2n; /* use the given argument as is */
3669 #undef _process_flags
3673 new_images=NewImageList();
3675 switch (*(option+1))
3679 if (LocaleCompare("append",option+1) == 0)
3681 new_images=AppendImages(_images,IsNormalOp,_exception);
3684 if (LocaleCompare("average",option+1) == 0)
3686 CLIWandWarnReplaced("-evaluate-sequence Mean");
3687 (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3690 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3694 if (LocaleCompare("channel-fx",option+1) == 0)
3696 new_images=ChannelFxImage(_images,arg1,_exception);
3699 if (LocaleCompare("clut",option+1) == 0)
3704 /* FUTURE - make this a compose option, and thus can be used
3705 with layers compose or even compose last image over all other
3708 new_images=RemoveFirstImageFromList(&_images);
3709 clut_image=RemoveLastImageFromList(&_images);
3710 /* FUTURE - produce Exception, rather than silent fail */
3711 if (clut_image == (Image *) NULL)
3713 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3714 clut_image=DestroyImage(clut_image);
3717 if (LocaleCompare("coalesce",option+1) == 0)
3719 new_images=CoalesceImages(_images,_exception);
3722 if (LocaleCompare("combine",option+1) == 0)
3724 parse = (ssize_t) sRGBColorspace; /* default (backward compatible) */
3726 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
3729 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3731 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3734 if (LocaleCompare("compare",option+1) == 0)
3747 Mathematically and visually annotate the difference between an
3748 image and its reconstruction.
3750 image=RemoveFirstImageFromList(&_images);
3751 reconstruct_image=RemoveFirstImageFromList(&_images);
3752 /* FUTURE - produce Exception, rather than silent fail */
3753 if (reconstruct_image == (Image *) NULL)
3755 metric=UndefinedErrorMetric;
3756 option=GetImageOption(_image_info,"metric");
3757 if (option != (const char *) NULL)
3758 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3759 MagickFalse,option);
3760 new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3763 reconstruct_image=DestroyImage(reconstruct_image);
3764 image=DestroyImage(image);
3767 if (LocaleCompare("complex",option+1) == 0)
3769 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3771 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3773 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3776 if (LocaleCompare("composite",option+1) == 0)
3794 /* Compose value from "-compose" option only */
3795 value=GetImageOption(_image_info,"compose");
3796 if (value == (const char *) NULL)
3797 compose=OverCompositeOp; /* use Over not source_image->compose */
3799 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3802 /* Get "clip-to-self" expert setting (false is normal) */
3803 value=GetImageOption(_image_info,"compose:clip-to-self");
3804 if (value == (const char *) NULL)
3805 clip_to_self=MagickTrue;
3807 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3808 "compose:clip-to-self")); /* if this is true */
3809 value=GetImageOption(_image_info,"compose:outside-overlay");
3810 if (value != (const char *) NULL) { /* or this false */
3811 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3812 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3815 new_images=RemoveFirstImageFromList(&_images);
3816 source_image=RemoveFirstImageFromList(&_images);
3817 if (source_image == (Image *) NULL)
3818 break; /* FUTURE - produce Exception, rather than silent fail */
3820 /* FUTURE - this should not be here! - should be part of -geometry */
3821 (void) TransformImage(&source_image,(char *) NULL,
3822 source_image->geometry,_exception);
3823 SetGeometry(source_image,&geometry);
3824 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3825 GravityAdjustGeometry(new_images->columns,new_images->rows,
3826 new_images->gravity, &geometry);
3827 mask_image=RemoveFirstImageFromList(&_images);
3828 if (mask_image == (Image *) NULL)
3829 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3830 geometry.x,geometry.y,_exception);
3833 if ((compose == DisplaceCompositeOp) ||
3834 (compose == DistortCompositeOp))
3836 status&=CompositeImage(source_image,mask_image,
3837 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3838 status&=CompositeImage(new_images,source_image,compose,
3839 clip_to_self,geometry.x,geometry.y,_exception);
3846 clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
3847 if (clone_image == (Image *) NULL)
3849 status&=CompositeImage(new_images,source_image,compose,
3850 clip_to_self,geometry.x,geometry.y,_exception);
3851 status&=CompositeImage(new_images,mask_image,
3852 CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
3853 status&=CompositeImage(clone_image,new_images,OverCompositeOp,
3854 clip_to_self,geometry.x,geometry.y,_exception);
3855 new_images=DestroyImage(new_images);
3856 new_images=clone_image;
3858 mask_image=DestroyImage(mask_image);
3860 source_image=DestroyImage(source_image);
3863 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3867 if (LocaleCompare("deconstruct",option+1) == 0)
3869 CLIWandWarnReplaced("-layer CompareAny");
3870 (void) CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3873 if (LocaleCompare("delete",option+1) == 0)
3876 DeleteImages(&_images,arg1,_exception);
3878 DeleteImages(&_images,"-1",_exception);
3881 if (LocaleCompare("duplicate",option+1) == 0)
3891 if (IfMagickFalse(IsGeometry(arg1)))
3892 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3894 number_duplicates=(size_t) StringToLong(arg1);
3896 if (p == (const char *) NULL)
3897 new_images=DuplicateImages(_images,number_duplicates,"-1",
3900 new_images=DuplicateImages(_images,number_duplicates,p,
3904 new_images=DuplicateImages(_images,1,"-1",_exception);
3905 AppendImageToList(&_images, new_images);
3906 new_images=(Image *) NULL;
3909 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3913 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3915 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3917 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3919 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3923 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3927 if (LocaleCompare("fft",option+1) == 0)
3929 new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception);
3932 if (LocaleCompare("flatten",option+1) == 0)
3934 /* REDIRECTED to use -layers flatten instead */
3935 (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3938 if (LocaleCompare("fx",option+1) == 0)
3940 new_images=FxImage(_images,arg1,_exception);
3943 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3947 if (LocaleCompare("hald-clut",option+1) == 0)
3949 /* FUTURE - make this a compose option (and thus layers compose )
3950 or perhaps compose last image over all other _images.
3955 new_images=RemoveFirstImageFromList(&_images);
3956 hald_image=RemoveLastImageFromList(&_images);
3957 if (hald_image == (Image *) NULL)
3959 (void) HaldClutImage(new_images,hald_image,_exception);
3960 hald_image=DestroyImage(hald_image);
3963 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3967 if (LocaleCompare("ift",option+1) == 0)
3973 magnitude_image=RemoveFirstImageFromList(&_images);
3974 phase_image=RemoveFirstImageFromList(&_images);
3975 /* FUTURE - produce Exception, rather than silent fail */
3976 if (phase_image == (Image *) NULL)
3978 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3979 IsNormalOp,_exception);
3980 magnitude_image=DestroyImage(magnitude_image);
3981 phase_image=DestroyImage(phase_image);
3984 if (LocaleCompare("insert",option+1) == 0)
3993 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3994 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3996 insert_image=RemoveLastImageFromList(&_images);
3998 index=(ssize_t) StringToLong(arg1);
3999 index_image=insert_image;
4001 PrependImageToList(&_images,insert_image);
4002 else if (index == (ssize_t) GetImageListLength(_images))
4003 AppendImageToList(&_images,insert_image);
4006 index_image=GetImageFromList(_images,index-1);
4007 if (index_image == (Image *) NULL)
4008 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4009 InsertImageInList(&index_image,insert_image);
4011 _images=GetFirstImageInList(index_image);
4014 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4018 if (LocaleCompare("layers",option+1) == 0)
4020 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4022 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4024 switch ((LayerMethod) parse)
4028 new_images=CoalesceImages(_images,_exception);
4031 case CompareAnyLayer:
4032 case CompareClearLayer:
4033 case CompareOverlayLayer:
4036 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4043 case TrimBoundsLayer:
4045 new_images=MergeImageLayers(_images,(LayerMethod) parse,
4051 new_images=DisposeImages(_images,_exception);
4054 case OptimizeImageLayer:
4056 new_images=OptimizeImageLayers(_images,_exception);
4059 case OptimizePlusLayer:
4061 new_images=OptimizePlusImageLayers(_images,_exception);
4064 case OptimizeTransLayer:
4066 OptimizeImageTransparency(_images,_exception);
4069 case RemoveDupsLayer:
4071 RemoveDuplicateLayers(&_images,_exception);
4074 case RemoveZeroLayer:
4076 RemoveZeroDelayLayers(&_images,_exception);
4080 { /* General Purpose, GIF Animation Optimizer. */
4081 new_images=CoalesceImages(_images,_exception);
4082 if (new_images == (Image *) NULL)
4084 _images=DestroyImageList(_images);
4085 _images=OptimizeImageLayers(new_images,_exception);
4086 if (_images == (Image *) NULL)
4088 new_images=DestroyImageList(new_images);
4089 OptimizeImageTransparency(_images,_exception);
4090 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4094 case CompositeLayer:
4108 value=GetImageOption(_image_info,"compose");
4109 compose=OverCompositeOp; /* Default to Over */
4110 if (value != (const char *) NULL)
4111 compose=(CompositeOperator) ParseCommandOption(
4112 MagickComposeOptions,MagickFalse,value);
4114 /* Split image sequence at the first 'NULL:' image. */
4116 while (source != (Image *) NULL)
4118 source=GetNextImageInList(source);
4119 if ((source != (Image *) NULL) &&
4120 (LocaleCompare(source->magick,"NULL") == 0))
4123 if (source != (Image *) NULL)
4125 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4126 (GetNextImageInList(source) == (Image *) NULL))
4127 source=(Image *) NULL;
4129 { /* Separate the two lists, junk the null: image. */
4130 source=SplitImageList(source->previous);
4131 DeleteImageFromList(&source);
4134 if (source == (Image *) NULL)
4136 (void) ThrowMagickException(_exception,GetMagickModule(),
4137 OptionError,"MissingNullSeparator","layers Composite");
4140 /* Adjust offset with gravity and virtual canvas. */
4141 SetGeometry(_images,&geometry);
4142 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4143 geometry.width=source->page.width != 0 ?
4144 source->page.width : source->columns;
4145 geometry.height=source->page.height != 0 ?
4146 source->page.height : source->rows;
4147 GravityAdjustGeometry(_images->page.width != 0 ?
4148 _images->page.width : _images->columns,
4149 _images->page.height != 0 ? _images->page.height :
4150 _images->rows,_images->gravity,&geometry);
4152 /* Compose the two image sequences together */
4153 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4155 source=DestroyImageList(source);
4161 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4165 if (LocaleCompare("map",option+1) == 0)
4167 CLIWandWarnReplaced("+remap");
4168 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4171 if (LocaleCompare("metric",option+1) == 0)
4173 if (LocaleCompare("morph",option+1) == 0)
4178 if (IfMagickFalse(IsGeometry(arg1)))
4179 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4180 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4182 if (morph_image == (Image *) NULL)
4184 _images=DestroyImageList(_images);
4185 _images=morph_image;
4188 if (LocaleCompare("mosaic",option+1) == 0)
4190 /* REDIRECTED to use -layers mosaic instead */
4191 (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4194 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4198 if (LocaleCompare("poly",option+1) == 0)
4206 /* convert argument string into an array of doubles */
4207 args = StringToArrayOfDoubles(arg1,&count,_exception);
4208 if (args == (double *) NULL )
4209 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4210 new_images=PolynomialImage(_images,(size_t) (count >> 1),args,_exception);
4211 args=(double *) RelinquishMagickMemory(args);
4214 if (LocaleCompare("process",option+1) == 0)
4216 /* FUTURE: better parsing using ScriptToken() from string ??? */
4224 arguments=StringToArgv(arg1,&number_arguments);
4225 if (arguments == (char **) NULL)
4227 if (strchr(arguments[1],'=') != (char *) NULL)
4248 Support old style syntax, filter="-option arg1".
4250 assert(arg1 != (const char *) NULL);
4251 length=strlen(arg1);
4252 token=(char *) NULL;
4253 if (~length >= (MaxTextExtent-1))
4254 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4256 if (token == (char *) NULL)
4260 token_info=AcquireTokenInfo();
4261 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4262 "\"",'\0',&breaker,&next,"e);
4263 token_info=DestroyTokenInfo(token_info);
4269 argv=(&(arguments[next]));
4270 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4273 token=DestroyString(token);
4276 (void) SubstituteString(&arguments[1],"-","");
4277 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4278 number_arguments-2,(const char **) arguments+2,_exception);
4279 for (j=0; j < number_arguments; j++)
4280 arguments[j]=DestroyString(arguments[j]);
4281 arguments=(char **) RelinquishMagickMemory(arguments);
4284 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4288 if (LocaleCompare("remap",option+1) == 0)
4290 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4293 if (LocaleCompare("reverse",option+1) == 0)
4295 ReverseImageList(&_images);
4298 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4302 if (LocaleCompare("smush",option+1) == 0)
4304 /* FUTURE: this option needs more work to make better */
4308 if (IfMagickFalse(IsGeometry(arg1)))
4309 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4310 offset=(ssize_t) StringToLong(arg1);
4311 new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4314 if (LocaleCompare("subimage",option+1) == 0)
4332 base_image=GetImageFromList(_images,0);
4333 compare_image=GetImageFromList(_images,1);
4335 /* Comparision Metric */
4336 metric=UndefinedErrorMetric;
4337 value=GetImageOption(_image_info,"metric");
4338 if (value != (const char *) NULL)
4339 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4342 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4343 &offset,&similarity,_exception);
4345 if ( new_images != (Image *) NULL ) {
4347 result[MaxTextExtent];
4349 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4350 (void) SetImageProperty(new_images,"subimage:similarity",result,
4352 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4354 (void) SetImageProperty(new_images,"subimage:x",result,
4356 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4358 (void) SetImageProperty(new_images,"subimage:y",result,
4360 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4361 (unsigned long) offset.width,(unsigned long) offset.height,
4362 (long) offset.x,(long) offset.y);
4363 (void) SetImageProperty(new_images,"subimage:offset",result,
4368 if (LocaleCompare("swap",option+1) == 0) {
4388 flags=ParseGeometry(arg1,&geometry_info);
4389 if ((flags & RhoValue) == 0)
4390 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4391 index=(ssize_t) geometry_info.rho;
4392 if ((flags & SigmaValue) != 0)
4393 swap_index=(ssize_t) geometry_info.sigma;
4395 p=GetImageFromList(_images,index);
4396 q=GetImageFromList(_images,swap_index);
4397 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4399 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4401 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4404 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4405 swap=CloneImage(p,0,0,MagickTrue,_exception);
4406 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4407 ReplaceImageInList(&q,swap);
4408 _images=GetFirstImageInList(q);
4411 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4414 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4417 /* clean up percent escape interpreted strings */
4419 arg1=DestroyString((char *)arg1);
4421 arg2=DestroyString((char *)arg2);
4423 /* if new image list generated, replace existing image list */
4424 if (new_images == (Image *) NULL)
4425 return(status == 0 ? MagickFalse : MagickTrue);
4426 _images=DestroyImageList(_images);
4427 _images=GetFirstImageInList(new_images);
4428 return(status == 0 ? MagickFalse : MagickTrue);
4434 #undef _quantize_info
4441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4445 + C L I N o I m a g e O p e r a t i o n s %
4449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451 % CLINoImageOperator() Applies operations that may not actually need images
4454 % The classic operators of this type is "-read", which actually creates
4455 % images even when no images are present. Or image stack operators, which
4456 % can be applied (push or pop) to an empty image list.
4458 % Note that these operators may involve other special 'option' prefix
4459 % characters other than '-' or '+', namely parenthesis and braces.
4461 % The format of the CLINoImageOption method is:
4463 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4464 % const char *arg1, const char *arg2)
4466 % A description of each parameter follows:
4468 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4470 % o option: The special option (with any switch char) to process
4472 % o arg1 & arg2: Argument for option, if required
4473 % Currently arg2 is not used.
4476 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4477 const char *option,const char *arg1n,const char *arg2n)
4479 const char /* percent escaped versions of the args */
4483 #define _image_info (cli_wand->wand.image_info)
4484 #define _images (cli_wand->wand.images)
4485 #define _exception (cli_wand->wand.exception)
4486 #define _process_flags (cli_wand->process_flags)
4487 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4488 #define IfNormalOp (*option=='-')
4489 #define IfPlusOp (*option!='-')
4491 assert(cli_wand != (MagickCLI *) NULL);
4492 assert(cli_wand->signature == WandSignature);
4493 assert(cli_wand->wand.signature == WandSignature);
4495 if (IfMagickTrue(cli_wand->wand.debug))
4496 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4497 "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
4502 /* Interpret Percent Escapes in Arguments - using first image */
4503 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4504 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4505 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4506 /* Interpret Percent escapes in argument 1 */
4507 if (arg1n != (char *) NULL) {
4508 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4509 if (arg1 == (char *) NULL) {
4510 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4511 arg1=arg1n; /* use the given argument as is */
4514 if (arg2n != (char *) NULL) {
4515 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4516 if (arg2 == (char *) NULL) {
4517 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4518 arg2=arg2n; /* use the given argument as is */
4522 #undef _process_flags
4525 do { /* break to exit code */
4527 No-op options (ignore these)
4529 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4531 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4533 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4535 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4537 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4542 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4543 ( LocaleCompare("--",option) == 0 ) ) {
4544 /* Do Glob filename Expansion for 'arg1' then read all images.
4546 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4547 * (but attaching to the filenames in the generated argument list) any
4548 * [...] read modifiers that may be present.
4550 * For example: It will expand '*.gif[20x20]' into a list such as
4551 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4553 * NOTE: In IMv6 this was done globally across all images. This
4554 * meant you could include IM options in '@filename' lists, but you
4555 * could not include comments. Doing it only for image read makes
4556 * it far more secure.
4558 * Note: arguments do not have percent escapes expanded for security
4566 argv = (char **) &arg1;
4568 /* Expand 'glob' expressions in the given filename.
4569 Expansion handles any 'coder:' prefix, or read modifiers attached
4570 to the filename, including them in the resulting expanded list.
4572 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4573 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4574 option,GetExceptionMessage(errno));
4576 /* loop over expanded filename list, and read then all in */
4577 for (i=0; i < (ssize_t) argc; i++) {
4580 if (IfMagickTrue(_image_info->ping))
4581 new_images=PingImages(_image_info,argv[i],_exception);
4583 new_images=ReadImages(_image_info,argv[i],_exception);
4584 AppendImageToList(&_images, new_images);
4586 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4591 Note: Writing a empty image list is valid in specific cases
4593 if (LocaleCompare("write",option+1) == 0) {
4594 /* Note: arguments do not have percent escapes expanded */
4604 /* Need images, unless a "null:" output coder is used */
4605 if ( _images == (Image *) NULL ) {
4606 if ( LocaleCompare(arg1,"null:") == 0 )
4608 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4611 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4612 (void) DeleteImageRegistry(key);
4613 write_images=_images;
4615 write_images=CloneImageList(_images,_exception);
4616 write_info=CloneImageInfo(_image_info);
4617 (void) WriteImages(write_info,write_images,arg1,_exception);
4618 write_info=DestroyImageInfo(write_info);
4620 write_images=DestroyImageList(write_images);
4624 Parenthesis and Brace operations
4626 if (LocaleCompare("(",option) == 0) {
4627 /* stack 'push' images */
4635 node=cli_wand->image_list_stack;
4636 for ( ; node != (Stack *) NULL; node=node->next)
4638 if ( size >= MAX_STACK_DEPTH )
4639 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4640 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4641 if (node == (Stack *) NULL)
4642 CLIWandExceptionBreak(ResourceLimitFatalError,
4643 "MemoryAllocationFailed",option);
4644 node->data = (void *)cli_wand->wand.images;
4645 node->next = cli_wand->image_list_stack;
4646 cli_wand->image_list_stack = node;
4647 cli_wand->wand.images = NewImageList();
4649 /* handle respect-parenthesis */
4650 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4651 "respect-parenthesis"))))
4652 option="{"; /* fall-thru so as to push image settings too */
4655 /* fall thru to operation */
4657 if (LocaleCompare("{",option) == 0) {
4658 /* stack 'push' of image_info settings */
4666 node=cli_wand->image_info_stack;
4667 for ( ; node != (Stack *) NULL; node=node->next)
4669 if ( size >= MAX_STACK_DEPTH )
4670 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4671 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4672 if (node == (Stack *) NULL)
4673 CLIWandExceptionBreak(ResourceLimitFatalError,
4674 "MemoryAllocationFailed",option);
4676 node->data = (void *)cli_wand->wand.image_info;
4677 node->next = cli_wand->image_info_stack;
4679 cli_wand->image_info_stack = node;
4680 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4681 if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
4682 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4684 cli_wand->wand.image_info = (ImageInfo *)node->data;
4685 node = (Stack *)RelinquishMagickMemory(node);
4691 if (LocaleCompare(")",option) == 0) {
4692 /* pop images from stack */
4696 node = (Stack *)cli_wand->image_list_stack;
4697 if ( node == (Stack *) NULL)
4698 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4699 cli_wand->image_list_stack = node->next;
4701 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4702 cli_wand->wand.images= (Image *)node->data;
4703 node = (Stack *)RelinquishMagickMemory(node);
4705 /* handle respect-parenthesis - of the previous 'pushed' settings */
4706 node = cli_wand->image_info_stack;
4707 if ( node != (Stack *) NULL)
4709 if (IfMagickTrue(IsStringTrue(GetImageOption(
4710 cli_wand->wand.image_info,"respect-parenthesis"))))
4711 option="}"; /* fall-thru so as to pop image settings too */
4717 /* fall thru to next if */
4719 if (LocaleCompare("}",option) == 0) {
4720 /* pop image_info settings from stack */
4724 node = (Stack *)cli_wand->image_info_stack;
4725 if ( node == (Stack *) NULL)
4726 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4727 cli_wand->image_info_stack = node->next;
4729 (void) DestroyImageInfo(cli_wand->wand.image_info);
4730 cli_wand->wand.image_info = (ImageInfo *)node->data;
4731 node = (Stack *)RelinquishMagickMemory(node);
4733 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4734 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4735 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4739 if (LocaleCompare("print",option+1) == 0)
4741 (void) FormatLocaleFile(stdout,"%s",arg1);
4744 if (LocaleCompare("set",option+1) == 0)
4746 /* Settings are applied to each image in memory in turn (if any).
4747 While a option: only need to be applied once globally.
4749 NOTE: rguments have not been automatically percent expaneded
4752 /* escape the 'key' once only, using first image. */
4753 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4754 if (arg1 == (char *) NULL)
4755 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4758 if (LocaleNCompare(arg1,"registry:",9) == 0)
4762 (void) DeleteImageRegistry(arg1+9);
4763 arg1=DestroyString((char *)arg1);
4766 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4767 if (arg2 == (char *) NULL) {
4768 arg1=DestroyString((char *)arg1);
4769 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4772 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4773 arg1=DestroyString((char *)arg1);
4774 arg2=DestroyString((char *)arg2);
4777 if (LocaleNCompare(arg1,"option:",7) == 0)
4779 /* delete equivelent artifact from all images (if any) */
4780 if (_images != (Image *) NULL)
4782 MagickResetIterator(&cli_wand->wand);
4783 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4784 (void) DeleteImageArtifact(_images,arg1+7);
4785 MagickResetIterator(&cli_wand->wand);
4787 /* now set/delete the global option as needed */
4788 /* FUTURE: make escapes in a global 'option:' delayed */
4792 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4793 if (arg2 == (char *) NULL)
4794 CLIWandExceptionBreak(OptionWarning,
4795 "InterpretPropertyFailure",option);
4797 (void) SetImageOption(_image_info,arg1+7,arg2);
4798 arg1=DestroyString((char *)arg1);
4799 arg2=DestroyString((char *)arg2);
4802 /* Set Artifacts/Properties/Attributes all images (required) */
4803 if ( _images == (Image *) NULL )
4804 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4806 MagickResetIterator(&cli_wand->wand);
4807 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4812 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4813 if (arg2 == (char *) NULL)
4814 CLIWandExceptionBreak(OptionWarning,
4815 "InterpretPropertyFailure",option);
4817 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4818 (void) SetImageArtifact(_images,arg1+9,arg2);
4819 else if (LocaleNCompare(arg1,"property:",9) == 0)
4820 (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4822 (void) SetImageProperty(_images,arg1,arg2,_exception);
4823 arg2=DestroyString((char *)arg2);
4825 MagickResetIterator(&cli_wand->wand);
4826 arg1=DestroyString((char *)arg1);
4829 if (LocaleCompare("clone",option+1) == 0) {
4834 arg1=AcquireString("-1");
4835 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4836 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4837 if ( cli_wand->image_list_stack == (Stack *) NULL)
4838 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4839 new_images = (Image *)cli_wand->image_list_stack->data;
4840 if (new_images == (Image *) NULL)
4841 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4842 new_images=CloneImages(new_images,arg1,_exception);
4843 if (new_images == (Image *) NULL)
4844 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4845 AppendImageToList(&_images,new_images);
4849 Informational Operations.
4851 Note that these do not require either a cli-wand or images!
4852 Though currently a cli-wand much be provided regardless.
4854 if (LocaleCompare("version",option+1) == 0)
4856 ListMagickVersion(stdout);
4859 if (LocaleCompare("list",option+1) == 0) {
4861 FUTURE: This 'switch' should really be part of MagickCore
4866 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4868 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4873 case MagickCoderOptions:
4875 (void) ListCoderInfo((FILE *) NULL,_exception);
4878 case MagickColorOptions:
4880 (void) ListColorInfo((FILE *) NULL,_exception);
4883 case MagickConfigureOptions:
4885 (void) ListConfigureInfo((FILE *) NULL,_exception);
4888 case MagickDelegateOptions:
4890 (void) ListDelegateInfo((FILE *) NULL,_exception);
4893 case MagickFontOptions:
4895 (void) ListTypeInfo((FILE *) NULL,_exception);
4898 case MagickFormatOptions:
4899 (void) ListMagickInfo((FILE *) NULL,_exception);
4901 case MagickLocaleOptions:
4902 (void) ListLocaleInfo((FILE *) NULL,_exception);
4904 case MagickLogOptions:
4905 (void) ListLogInfo((FILE *) NULL,_exception);
4907 case MagickMagicOptions:
4908 (void) ListMagicInfo((FILE *) NULL,_exception);
4910 case MagickMimeOptions:
4911 (void) ListMimeInfo((FILE *) NULL,_exception);
4913 case MagickModuleOptions:
4914 (void) ListModuleInfo((FILE *) NULL,_exception);
4916 case MagickPolicyOptions:
4917 (void) ListPolicyInfo((FILE *) NULL,_exception);
4919 case MagickResourceOptions:
4920 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4922 case MagickThresholdOptions:
4923 (void) ListThresholdMaps((FILE *) NULL,_exception);
4926 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4933 CLIWandException(OptionError,"UnrecognizedOption",option);
4935 DisableMSCWarning(4127)
4936 } while (0); /* break to exit code. */
4939 /* clean up percent escape interpreted strings */
4941 arg1=DestroyString((char *)arg1);
4943 arg2=DestroyString((char *)arg2);
4953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4957 + C L I O p t i o n %
4961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4963 % CLIOption() Processes the given option using the given CLI Magick Wand.
4964 % The option arguments can be variable in number, though at this time no more
4965 % that two is actually used by any option (this may change). Excess options
4966 % are simply ignored.
4968 % If the cli_wand->command pointer is non-null, then it is assumed that the
4969 % option has already been search for up from the CommandOptions[] table in
4970 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4971 % routine will do the lookup instead. The pointer is reset afterward.
4973 % This action allows the caller to lookup and pre-handle any 'special'
4974 % options, (such as implicit reads) before calling this general option
4975 % handler to deal with 'standard' command line options.
4977 % The format of the CLIOption method is:
4979 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4981 % A description of each parameter follows:
4983 % o cli_wand: the main CLI Wand to use.
4985 % o option: The special option (with any switch char) to process
4987 % o args: any required arguments for an option (variable number)
4991 % CLIoption(cli_wand,"-read","rose:");
4992 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4993 % CLIoption(cli_wand,"-distort","SRT:","30");
4994 % CLIoption(cli_wand,"-write","rotated_rose.png");
4997 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4999 const char /* extracted option args from args */
5006 assert(cli_wand != (MagickCLI *) NULL);
5007 assert(cli_wand->signature == WandSignature);
5008 assert(cli_wand->wand.signature == WandSignature);
5010 do { /* Break Code Block for error handling */
5012 /* get information about option */
5013 if ( cli_wand->command == (const OptionInfo *) NULL )
5014 cli_wand->command = GetCommandOptionInfo(option);
5016 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5017 option, cli_wand->command->mnemonic );
5019 option_type=(CommandOptionFlags) cli_wand->command->flags;
5021 if ( option_type == UndefinedOptionFlag )
5022 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5024 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5026 /* deprecated options */
5027 if ( (option_type & DeprecateOptionFlag) != 0 )
5028 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5030 /* options that this module does not handle */
5031 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5032 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5034 /* Get argument strings from VarArgs
5035 How can you determine if enough arguments was supplied?
5036 What happens if not enough arguments were supplied?
5039 count = (size_t) cli_wand->command->type;
5044 va_start(operands,option);
5048 arg1=(const char *) va_arg(operands, const char *);
5050 arg2=(const char *) va_arg(operands, const char *);
5054 (void) FormatLocaleFile(stderr,
5055 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5056 option,(long) count,option_type,arg1,arg2);
5061 Call the appropriate option handler
5064 /* FUTURE: this is temporary - get 'settings' to handle distribution of
5065 settings to images attributes,proprieties,artifacts */
5066 if ( cli_wand->wand.images != (Image *) NULL )
5067 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5068 cli_wand->wand.exception);
5070 if ( (option_type & SettingOptionFlags) != 0 ) {
5071 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5072 // FUTURE: Sync Specific Settings into Image Properities (not global)
5075 /* Operators that do not need images - read, write, stack, clone */
5076 if ( (option_type & NoImageOperatorFlag) != 0)
5077 CLINoImageOperator(cli_wand, option, arg1, arg2);
5079 /* FUTURE: The not a setting part below is a temporary hack due to
5080 * some options being both a Setting and a Simple operator.
5081 * Specifically -monitor, -depth, and -colorspace */
5082 if ( cli_wand->wand.images == (Image *) NULL )
5083 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5084 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5085 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5087 /* Operators which loop of individual images, simply */
5088 if ( (option_type & SimpleOperatorFlag) != 0 &&
5089 cli_wand->wand.images != (Image *) NULL) /* temp hack */
5091 ExceptionInfo *exception=AcquireExceptionInfo();
5092 (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5093 exception=DestroyExceptionInfo(exception);
5096 /* Operators that work on the image list as a whole */
5097 if ( (option_type & ListOperatorFlag) != 0 )
5098 (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5100 DisableMSCWarning(4127)
5101 } while (0); /* end Break code block */
5104 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */