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-2014 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 == BlendPixelTrait)
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 == BlendPixelTrait)
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 == BlendPixelTrait)
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 % void 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 != BlendPixelTrait)
2032 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
2033 SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
2034 q+=GetPixelChannels(mask_image);
2036 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2039 /* clean up and set the write mask */
2040 mask_view=DestroyCacheView(mask_view);
2041 mask_image->alpha_trait=BlendPixelTrait;
2042 (void) SetImageColorspace(_image,GRAYColorspace,_exception);
2043 (void) SetImageMask(_image,mask_image,_exception);
2044 mask_image=DestroyImage(mask_image);
2047 if (LocaleCompare("clip-path",option+1) == 0)
2049 (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2050 /* Note: Use "+clip-mask" remove the write mask added */
2053 if (LocaleCompare("colorize",option+1) == 0)
2055 if (IfMagickFalse(IsGeometry(arg1)))
2056 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2057 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2060 if (LocaleCompare("color-matrix",option+1) == 0)
2065 kernel=AcquireKernelInfo(arg1,exception);
2066 if (kernel == (KernelInfo *) NULL)
2067 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2068 new_image=ColorMatrixImage(_image,kernel,_exception);
2069 kernel=DestroyKernelInfo(kernel);
2072 if (LocaleCompare("colors",option+1) == 0)
2074 /* Reduce the number of colors in the image.
2075 FUTURE: also provide 'plus version with image 'color counts'
2077 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2078 if (_quantize_info->number_colors == 0)
2079 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2080 if ((_image->storage_class == DirectClass) ||
2081 _image->colors > _quantize_info->number_colors)
2082 (void) QuantizeImage(_quantize_info,_image,_exception);
2084 (void) CompressImageColormap(_image,_exception);
2087 if (LocaleCompare("colorspace",option+1) == 0)
2089 /* WARNING: this is both a image_info setting (already done)
2090 and a operator to change image colorspace.
2092 FUTURE: default colorspace should be sRGB!
2093 Unless some type of 'linear colorspace' mode is set.
2095 Note that +colorspace sets "undefined" or no effect on
2096 new images, but forces images already in memory back to RGB!
2097 That seems to be a little strange!
2099 (void) TransformImageColorspace(_image,
2100 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2104 if (LocaleCompare("connected-components",option+1) == 0)
2106 if (IfMagickFalse(IsGeometry(arg1)))
2107 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2108 new_image=ConnectedComponentsImage(_image,StringToInteger(arg1),
2112 if (LocaleCompare("contrast",option+1) == 0)
2114 CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2115 (void) ContrastImage(_image,IsNormalOp,_exception);
2118 if (LocaleCompare("contrast-stretch",option+1) == 0)
2127 flags=ParseGeometry(arg1,&geometry_info);
2128 if ((flags & RhoValue) == 0)
2129 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2130 black_point=geometry_info.rho;
2131 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2133 if ((flags & PercentValue) != 0) {
2134 black_point*=(double) _image->columns*_image->rows/100.0;
2135 white_point*=(double) _image->columns*_image->rows/100.0;
2137 white_point=(double) _image->columns*_image->rows-white_point;
2138 (void) ContrastStretchImage(_image,black_point,white_point,
2142 if (LocaleCompare("convolve",option+1) == 0)
2147 kernel_info=AcquireKernelInfo(arg1,exception);
2148 if (kernel_info == (KernelInfo *) NULL)
2149 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2150 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2152 kernel_info=DestroyKernelInfo(kernel_info);
2155 if (LocaleCompare("crop",option+1) == 0)
2157 /* WARNING: This can generate multiple images! */
2158 if (IfMagickFalse(IsGeometry(arg1)))
2159 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2160 new_image=CropImageToTiles(_image,arg1,_exception);
2163 if (LocaleCompare("cycle",option+1) == 0)
2165 if (IfMagickFalse(IsGeometry(arg1)))
2166 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2167 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2171 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2175 if (LocaleCompare("decipher",option+1) == 0)
2177 /* Note: arguments do not have percent escapes expanded */
2181 passkey=FileToStringInfo(arg1,~0UL,_exception);
2182 if (passkey == (StringInfo *) NULL)
2183 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2185 (void) PasskeyDecipherImage(_image,passkey,_exception);
2186 passkey=DestroyStringInfo(passkey);
2189 if (LocaleCompare("depth",option+1) == 0)
2191 /* The _image_info->depth setting has already been set
2192 We just need to apply it to all images in current sequence
2194 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2195 That is it really is an operation, not a setting! Arrgghhh
2197 FUTURE: this should not be an operator!!!
2199 (void) SetImageDepth(_image,_image_info->depth,_exception);
2202 if (LocaleCompare("deskew",option+1) == 0)
2208 if (IfMagickFalse(IsGeometry(arg1)))
2209 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2210 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2213 threshold=40.0*QuantumRange/100.0;
2214 new_image=DeskewImage(_image,threshold,_exception);
2217 if (LocaleCompare("despeckle",option+1) == 0)
2219 new_image=DespeckleImage(_image,_exception);
2222 if (LocaleCompare("distort",option+1) == 0)
2230 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2232 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2234 if ((DistortImageMethod) parse == ResizeDistortion)
2238 /* Special Case - Argument is actually a resize geometry!
2239 ** Convert that to an appropriate distortion argument array.
2240 ** FUTURE: make a separate special resize operator
2241 Roll into a resize special operator */
2242 if (IfMagickFalse(IsGeometry(arg2)))
2243 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2245 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2246 resize_args[0]=(double) geometry.width;
2247 resize_args[1]=(double) geometry.height;
2248 new_image=DistortImage(_image,(DistortImageMethod) parse,
2249 (size_t)2,resize_args,MagickTrue,_exception);
2252 /* convert argument string into an array of doubles */
2253 args = StringToArrayOfDoubles(arg2,&count,_exception);
2254 if (args == (double *)NULL )
2255 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2257 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2258 IsPlusOp,_exception);
2259 args=(double *) RelinquishMagickMemory(args);
2262 if (LocaleCompare("draw",option+1) == 0)
2264 (void) CloneString(&_draw_info->primitive,arg1);
2265 (void) DrawImage(_image,_draw_info,_exception);
2266 (void) CloneString(&_draw_info->primitive,(char *)NULL);
2269 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2273 if (LocaleCompare("edge",option+1) == 0)
2275 flags=ParseGeometry(arg1,&geometry_info);
2276 if ((flags & (RhoValue|SigmaValue)) == 0)
2277 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2278 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2281 if (LocaleCompare("emboss",option+1) == 0)
2283 flags=ParseGeometry(arg1,&geometry_info);
2284 if ((flags & (RhoValue|SigmaValue)) == 0)
2285 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2286 if ((flags & SigmaValue) == 0)
2287 geometry_info.sigma=1.0;
2288 new_image=EmbossImage(_image,geometry_info.rho,
2289 geometry_info.sigma,_exception);
2292 if (LocaleCompare("encipher",option+1) == 0)
2294 /* Note: arguments do not have percent escapes expanded */
2298 passkey=FileToStringInfo(arg1,~0UL,_exception);
2299 if (passkey != (StringInfo *) NULL)
2301 (void) PasskeyEncipherImage(_image,passkey,_exception);
2302 passkey=DestroyStringInfo(passkey);
2306 if (LocaleCompare("enhance",option+1) == 0)
2308 new_image=EnhanceImage(_image,_exception);
2311 if (LocaleCompare("equalize",option+1) == 0)
2313 (void) EqualizeImage(_image,_exception);
2316 if (LocaleCompare("evaluate",option+1) == 0)
2321 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2323 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2325 if (IfMagickFalse(IsGeometry(arg2)))
2326 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2327 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2328 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2332 if (LocaleCompare("extent",option+1) == 0)
2334 if (IfMagickFalse(IsGeometry(arg1)))
2335 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2336 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2337 if (geometry.width == 0)
2338 geometry.width=_image->columns;
2339 if (geometry.height == 0)
2340 geometry.height=_image->rows;
2341 new_image=ExtentImage(_image,&geometry,_exception);
2344 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2348 if (LocaleCompare("flip",option+1) == 0)
2350 new_image=FlipImage(_image,_exception);
2353 if (LocaleCompare("flop",option+1) == 0)
2355 new_image=FlopImage(_image,_exception);
2358 if (LocaleCompare("floodfill",option+1) == 0)
2363 if (IfMagickFalse(IsGeometry(arg1)))
2364 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2365 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2366 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2367 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2368 geometry.y,IsPlusOp,_exception);
2371 if (LocaleCompare("frame",option+1) == 0)
2382 value=GetImageOption(_image_info,"compose");
2383 compose=OverCompositeOp; /* use Over not _image->compose */
2384 if (value != (const char *) NULL)
2385 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2387 if (IfMagickFalse(IsGeometry(arg1)))
2388 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2389 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2390 frame_info.width=geometry.width;
2391 frame_info.height=geometry.height;
2392 frame_info.outer_bevel=geometry.x;
2393 frame_info.inner_bevel=geometry.y;
2394 frame_info.x=(ssize_t) frame_info.width;
2395 frame_info.y=(ssize_t) frame_info.height;
2396 frame_info.width=_image->columns+2*frame_info.width;
2397 frame_info.height=_image->rows+2*frame_info.height;
2398 new_image=FrameImage(_image,&frame_info,compose,_exception);
2401 if (LocaleCompare("function",option+1) == 0)
2409 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2411 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2413 /* convert argument string into an array of doubles */
2414 args = StringToArrayOfDoubles(arg2,&count,_exception);
2415 if (args == (double *)NULL )
2416 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2418 (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2420 args=(double *) RelinquishMagickMemory(args);
2423 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2427 if (LocaleCompare("gamma",option+1) == 0)
2432 if (IfMagickFalse(IsGeometry(arg1)))
2433 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2434 constant=StringToDouble(arg1,(char **) NULL);
2436 /* Using Gamma, via a cache */
2438 constant=PerceptibleReciprocal(constant);
2439 (void) GammaImage(_image,constant,_exception);
2441 /* Using Evaluate POW, direct update of values - more accurite */
2443 constant=PerceptibleReciprocal(constant);
2444 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2446 /* Set gamma setting -- Old meaning of "+gamma"
2447 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2451 if (LocaleCompare("gaussian-blur",option+1) == 0)
2453 flags=ParseGeometry(arg1,&geometry_info);
2454 if ((flags & (RhoValue|SigmaValue)) == 0)
2455 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2456 if ((flags & SigmaValue) == 0)
2457 geometry_info.sigma=1.0;
2458 new_image=GaussianBlurImage(_image,geometry_info.rho,
2459 geometry_info.sigma,_exception);
2462 if (LocaleCompare("gaussian",option+1) == 0)
2464 CLIWandWarnReplaced("-gaussian-blur");
2465 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2467 if (LocaleCompare("geometry",option+1) == 0)
2470 Record Image offset for composition. (A Setting)
2471 Resize last _image. (ListOperator) -- DEPRECIATE
2472 FUTURE: Why if no 'offset' does this resize ALL images?
2473 Also why is the setting recorded in the IMAGE non-sense!
2476 { /* remove the previous composition geometry offset! */
2477 if (_image->geometry != (char *) NULL)
2478 _image->geometry=DestroyString(_image->geometry);
2481 if (IfMagickFalse(IsGeometry(arg1)))
2482 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2483 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2484 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2485 (void) CloneString(&_image->geometry,arg1);
2487 new_image=ResizeImage(_image,geometry.width,geometry.height,
2488 _image->filter,_exception);
2491 if (LocaleCompare("grayscale",option+1) == 0)
2493 parse=ParseCommandOption(MagickPixelIntensityOptions,
2496 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2498 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2501 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2505 if (LocaleCompare("hough-lines",option+1) == 0)
2507 flags=ParseGeometry(arg1,&geometry_info);
2508 if ((flags & (RhoValue|SigmaValue)) == 0)
2509 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2510 if ((flags & SigmaValue) == 0)
2511 geometry_info.sigma=geometry_info.rho;
2512 if ((flags & XiValue) == 0)
2513 geometry_info.xi=40;
2514 new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2515 (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2518 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2522 if (LocaleCompare("identify",option+1) == 0)
2528 format=GetImageOption(_image_info,"format");
2529 if (format == (char *) NULL)
2531 (void) IdentifyImage(_image,stdout,_image_info->verbose,
2535 text=InterpretImageProperties(_image_info,_image,format,_exception);
2536 if (text == (char *) NULL)
2537 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2539 (void) fputs(text,stdout);
2540 text=DestroyString((char *)text);
2543 if (LocaleCompare("implode",option+1) == 0)
2545 flags=ParseGeometry(arg1,&geometry_info);
2546 if ((flags & RhoValue) == 0)
2547 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2548 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2552 if (LocaleCompare("interpolative-resize",option+1) == 0)
2554 /* FUTURE: New to IMv7
2555 Roll into a resize special operator */
2556 if (IfMagickFalse(IsGeometry(arg1)))
2557 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2558 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2559 new_image=InterpolativeResizeImage(_image,geometry.width,
2560 geometry.height,_image->interpolate,_exception);
2563 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2567 if (LocaleCompare("kuwahara",option+1) == 0)
2570 Edge preserving blur.
2572 flags=ParseGeometry(arg1,&geometry_info);
2573 if ((flags & (RhoValue|SigmaValue)) == 0)
2574 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2575 if ((flags & SigmaValue) == 0)
2576 geometry_info.sigma=geometry_info.rho-0.5;
2577 new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2581 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2585 if (LocaleCompare("lat",option+1) == 0)
2587 flags=ParseGeometry(arg1,&geometry_info);
2588 if ((flags & (RhoValue|SigmaValue)) == 0)
2589 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2590 if ((flags & SigmaValue) == 0)
2591 geometry_info.sigma=1.0;
2592 if ((flags & PercentValue) != 0)
2593 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2594 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2595 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2599 if (LocaleCompare("level",option+1) == 0)
2609 flags=ParseGeometry(arg1,&geometry_info);
2610 if ((flags & RhoValue) == 0)
2611 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2612 black_point=geometry_info.rho;
2613 white_point=(double) QuantumRange;
2614 if ((flags & SigmaValue) != 0)
2615 white_point=geometry_info.sigma;
2617 if ((flags & XiValue) != 0)
2618 gamma=geometry_info.xi;
2619 if ((flags & PercentValue) != 0)
2621 black_point*=(double) (QuantumRange/100.0);
2622 white_point*=(double) (QuantumRange/100.0);
2624 if ((flags & SigmaValue) == 0)
2625 white_point=(double) QuantumRange-black_point;
2626 if (IfPlusOp || ((flags & AspectValue) != 0))
2627 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2629 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2632 if (LocaleCompare("level-colors",option+1) == 0)
2635 token[MaxTextExtent];
2644 p=(const char *) arg1;
2645 GetMagickToken(p,&p,token); /* get black point color */
2646 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2647 (void) QueryColorCompliance(token,AllCompliance,
2648 &black_point,_exception);
2650 (void) QueryColorCompliance("#000000",AllCompliance,
2651 &black_point,_exception);
2652 if (isalpha((int) token[0]) || (token[0] == '#'))
2653 GetMagickToken(p,&p,token);
2655 white_point=black_point; /* set everything to that color */
2658 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2659 GetMagickToken(p,&p,token); /* Get white point color. */
2660 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2661 (void) QueryColorCompliance(token,AllCompliance,
2662 &white_point,_exception);
2664 (void) QueryColorCompliance("#ffffff",AllCompliance,
2665 &white_point,_exception);
2667 (void) LevelImageColors(_image,&black_point,&white_point,
2668 IsPlusOp,_exception);
2671 if (LocaleCompare("linear-stretch",option+1) == 0)
2680 flags=ParseGeometry(arg1,&geometry_info);
2681 if ((flags & RhoValue) == 0)
2682 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2683 black_point=geometry_info.rho;
2684 white_point=(double) _image->columns*_image->rows;
2685 if ((flags & SigmaValue) != 0)
2686 white_point=geometry_info.sigma;
2687 if ((flags & PercentValue) != 0)
2689 black_point*=(double) _image->columns*_image->rows/100.0;
2690 white_point*=(double) _image->columns*_image->rows/100.0;
2692 if ((flags & SigmaValue) == 0)
2693 white_point=(double) _image->columns*_image->rows-
2695 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2698 if (LocaleCompare("liquid-rescale",option+1) == 0)
2700 /* FUTURE: Roll into a resize special operator */
2701 if (IfMagickFalse(IsGeometry(arg1)))
2702 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2703 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2704 if ((flags & XValue) == 0)
2706 if ((flags & YValue) == 0)
2708 new_image=LiquidRescaleImage(_image,geometry.width,
2709 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2712 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2716 if (LocaleCompare("magnify",option+1) == 0)
2718 new_image=MagnifyImage(_image,_exception);
2721 if (LocaleCompare("map",option+1) == 0)
2723 CLIWandWarnReplaced("-remap");
2724 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL,exception);
2727 if (LocaleCompare("mask",option+1) == 0)
2729 /* Note: arguments do not have percent escapes expanded */
2734 { /* Remove a mask. */
2735 (void) SetImageMask(_image,(Image *) NULL,_exception);
2738 /* Set the image mask. */
2739 mask=GetImageCache(_image_info,arg1,_exception);
2740 if (mask == (Image *) NULL)
2742 (void) SetImageMask(_image,mask,_exception);
2743 mask=DestroyImage(mask);
2746 if (LocaleCompare("matte",option+1) == 0)
2748 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2749 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2750 DeactivateAlphaChannel, _exception);
2753 if (LocaleCompare("mean-shift",option+1) == 0)
2755 flags=ParseGeometry(arg1,&geometry_info);
2756 if ((flags & (RhoValue|SigmaValue)) == 0)
2757 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2758 if ((flags & SigmaValue) == 0)
2759 geometry_info.sigma=1.0;
2760 if ((flags & XiValue) == 0)
2761 geometry_info.xi=0.10*QuantumRange;
2762 if ((flags & PercentValue) != 0)
2763 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2764 new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2765 (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2768 if (LocaleCompare("median",option+1) == 0)
2770 CLIWandWarnReplaced("-statistic Median");
2771 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2774 if (LocaleCompare("mode",option+1) == 0)
2776 /* FUTURE: note this is also a special "montage" option */
2777 CLIWandWarnReplaced("-statistic Mode");
2778 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,exception);
2781 if (LocaleCompare("modulate",option+1) == 0)
2783 if (IfMagickFalse(IsGeometry(arg1)))
2784 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2785 (void) ModulateImage(_image,arg1,_exception);
2788 if (LocaleCompare("monitor",option+1) == 0)
2790 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2791 (MagickProgressMonitor) NULL,(void *) NULL);
2794 if (LocaleCompare("monochrome",option+1) == 0)
2796 (void) SetImageType(_image,BilevelType,_exception);
2799 if (LocaleCompare("morphology",option+1) == 0)
2802 token[MaxTextExtent];
2814 GetMagickToken(p,&p,token);
2815 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2817 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2820 GetMagickToken(p,&p,token);
2821 if ((*p == ':') || (*p == ','))
2822 GetMagickToken(p,&p,token);
2824 iterations=(ssize_t) StringToLong(p);
2825 kernel=AcquireKernelInfo(arg2,exception);
2826 if (kernel == (KernelInfo *) NULL)
2827 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2828 new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2830 kernel=DestroyKernelInfo(kernel);
2833 if (LocaleCompare("motion-blur",option+1) == 0)
2835 flags=ParseGeometry(arg1,&geometry_info);
2836 if ((flags & (RhoValue|SigmaValue)) == 0)
2837 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2838 if ((flags & SigmaValue) == 0)
2839 geometry_info.sigma=1.0;
2840 new_image=MotionBlurImage(_image,geometry_info.rho,geometry_info.sigma,
2841 geometry_info.xi,_exception);
2844 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2848 if (LocaleCompare("negate",option+1) == 0)
2850 (void) NegateImage(_image, IsPlusOp, _exception);
2853 if (LocaleCompare("noise",option+1) == 0)
2863 CLIWandWarnReplaced("-statistic NonPeak");
2864 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2867 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2869 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2872 value=GetImageOption(_image_info,"attenuate");
2873 if (value != (const char *) NULL)
2874 attenuate=StringToDouble(value,(char **) NULL);
2875 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2879 if (LocaleCompare("normalize",option+1) == 0)
2881 (void) NormalizeImage(_image,_exception);
2884 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2888 if (LocaleCompare("opaque",option+1) == 0)
2893 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2894 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2898 if (LocaleCompare("ordered-dither",option+1) == 0)
2900 (void) OrderedPosterizeImage(_image,arg1,_exception);
2903 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2907 if (LocaleCompare("paint",option+1) == 0)
2909 flags=ParseGeometry(arg1,&geometry_info);
2910 if ((flags & (RhoValue|SigmaValue)) == 0)
2911 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2912 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2916 if (LocaleCompare("perceptible",option+1) == 0)
2918 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2922 if (LocaleCompare("polaroid",option+1) == 0)
2934 random_info=AcquireRandomInfo();
2935 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2936 random_info=DestroyRandomInfo(random_info);
2939 flags=ParseGeometry(arg1,&geometry_info);
2940 if ((flags & RhoValue) == 0)
2941 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2942 angle=geometry_info.rho;
2944 caption=GetImageProperty(_image,"caption",_exception);
2945 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2946 _image->interpolate,_exception);
2949 if (LocaleCompare("posterize",option+1) == 0)
2951 flags=ParseGeometry(arg1,&geometry_info);
2952 if ((flags & RhoValue) == 0)
2953 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2954 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2955 _quantize_info->dither_method,_exception);
2958 if (LocaleCompare("preview",option+1) == 0)
2960 /* FUTURE: should be a 'Genesis' option?
2961 Option however is also in WandSettingOptionInfo()
2964 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2966 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2968 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2971 if (LocaleCompare("profile",option+1) == 0)
2973 /* Note: arguments do not have percent escapes expanded */
2987 { /* Remove a profile from the _image. */
2988 (void) ProfileImage(_image,arg1,(const unsigned char *)
2992 /* Associate a profile with the _image. */
2993 profile_info=CloneImageInfo(_image_info);
2994 profile=GetImageProfile(_image,"iptc");
2995 if (profile != (StringInfo *) NULL)
2996 profile_info->profile=(void *) CloneStringInfo(profile);
2997 profile_image=GetImageCache(profile_info,arg1,_exception);
2998 profile_info=DestroyImageInfo(profile_info);
2999 if (profile_image == (Image *) NULL)
3004 profile_info=CloneImageInfo(_image_info);
3005 (void) CopyMagickString(profile_info->filename,arg1,
3007 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
3008 if (profile != (StringInfo *) NULL)
3010 (void) ProfileImage(_image,profile_info->magick,
3011 GetStringInfoDatum(profile),(size_t)
3012 GetStringInfoLength(profile),_exception);
3013 profile=DestroyStringInfo(profile);
3015 profile_info=DestroyImageInfo(profile_info);
3018 ResetImageProfileIterator(profile_image);
3019 name=GetNextImageProfile(profile_image);
3020 while (name != (const char *) NULL)
3022 profile=GetImageProfile(profile_image,name);
3023 if (profile != (StringInfo *) NULL)
3024 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3025 (size_t) GetStringInfoLength(profile),_exception);
3026 name=GetNextImageProfile(profile_image);
3028 profile_image=DestroyImage(profile_image);
3031 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3035 if (LocaleCompare("rotational-blur",option+1) == 0)
3037 flags=ParseGeometry(arg1,&geometry_info);
3038 if ((flags & RhoValue) == 0)
3039 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3040 new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3043 if (LocaleCompare("raise",option+1) == 0)
3045 if (IfMagickFalse(IsGeometry(arg1)))
3046 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3047 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3048 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3051 if (LocaleCompare("random-threshold",option+1) == 0)
3053 if (IfMagickFalse(IsGeometry(arg1)))
3054 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3055 (void) RandomThresholdImage(_image,arg1,_exception);
3058 if (LocaleCompare("recolor",option+1) == 0)
3060 CLIWandWarnReplaced("-color-matrix");
3061 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,exception);
3063 if (LocaleCompare("remap",option+1) == 0)
3065 /* Note: arguments do not have percent escapes expanded */
3069 remap_image=GetImageCache(_image_info,arg1,_exception);
3070 if (remap_image == (Image *) NULL)
3072 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3073 remap_image=DestroyImage(remap_image);
3076 if (LocaleCompare("repage",option+1) == 0)
3080 if (IfMagickFalse(IsGeometry(arg1)))
3081 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3083 (void) ResetImagePage(_image,arg1);
3086 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3089 if (LocaleCompare("resample",option+1) == 0)
3091 /* FUTURE: Roll into a resize special operation */
3092 flags=ParseGeometry(arg1,&geometry_info);
3093 if ((flags & (RhoValue|SigmaValue)) == 0)
3094 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3095 if ((flags & SigmaValue) == 0)
3096 geometry_info.sigma=geometry_info.rho;
3097 new_image=ResampleImage(_image,geometry_info.rho,
3098 geometry_info.sigma,_image->filter,_exception);
3101 if (LocaleCompare("resize",option+1) == 0)
3103 if (IfMagickFalse(IsGeometry(arg1)))
3104 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3105 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3106 new_image=ResizeImage(_image,geometry.width,geometry.height,
3107 _image->filter,_exception);
3110 if (LocaleCompare("roll",option+1) == 0)
3112 if (IfMagickFalse(IsGeometry(arg1)))
3113 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3114 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3115 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3118 if (LocaleCompare("rotate",option+1) == 0)
3120 flags=ParseGeometry(arg1,&geometry_info);
3121 if ((flags & RhoValue) == 0)
3122 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3123 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3125 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3127 new_image=RotateImage(_image,geometry_info.rho,_exception);
3130 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3134 if (LocaleCompare("sample",option+1) == 0)
3136 /* FUTURE: Roll into a resize special operator */
3137 if (IfMagickFalse(IsGeometry(arg1)))
3138 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3139 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3140 new_image=SampleImage(_image,geometry.width,geometry.height,
3144 if (LocaleCompare("scale",option+1) == 0)
3146 /* FUTURE: Roll into a resize special operator */
3147 if (IfMagickFalse(IsGeometry(arg1)))
3148 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3149 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3150 new_image=ScaleImage(_image,geometry.width,geometry.height,
3154 if (LocaleCompare("segment",option+1) == 0)
3156 flags=ParseGeometry(arg1,&geometry_info);
3157 if ((flags & (RhoValue|SigmaValue)) == 0)
3158 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3159 if ((flags & SigmaValue) == 0)
3160 geometry_info.sigma=1.0;
3161 (void) SegmentImage(_image,_image->colorspace,
3162 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3166 if (LocaleCompare("selective-blur",option+1) == 0)
3168 flags=ParseGeometry(arg1,&geometry_info);
3169 if ((flags & (RhoValue|SigmaValue)) == 0)
3170 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3171 if ((flags & SigmaValue) == 0)
3172 geometry_info.sigma=1.0;
3173 if ((flags & PercentValue) != 0)
3174 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3175 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3176 geometry_info.sigma,geometry_info.xi,_exception);
3179 if (LocaleCompare("separate",option+1) == 0)
3181 /* WARNING: This can generate multiple images! */
3182 /* FUTURE - this may be replaced by a "-channel" method */
3183 new_image=SeparateImages(_image,_exception);
3186 if (LocaleCompare("sepia-tone",option+1) == 0)
3188 if (IfMagickFalse(IsGeometry(arg1)))
3189 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3190 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3191 (double) QuantumRange+1.0),_exception);
3194 if (LocaleCompare("shade",option+1) == 0)
3196 flags=ParseGeometry(arg1,&geometry_info);
3197 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3198 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3199 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3200 geometry_info.sigma,_exception);
3203 if (LocaleCompare("shadow",option+1) == 0)
3205 flags=ParseGeometry(arg1,&geometry_info);
3206 if ((flags & (RhoValue|SigmaValue)) == 0)
3207 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3208 if ((flags & SigmaValue) == 0)
3209 geometry_info.sigma=1.0;
3210 if ((flags & XiValue) == 0)
3211 geometry_info.xi=4.0;
3212 if ((flags & PsiValue) == 0)
3213 geometry_info.psi=4.0;
3214 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3215 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3216 ceil(geometry_info.psi-0.5),_exception);
3219 if (LocaleCompare("sharpen",option+1) == 0)
3221 flags=ParseGeometry(arg1,&geometry_info);
3222 if ((flags & (RhoValue|SigmaValue)) == 0)
3223 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3224 if ((flags & SigmaValue) == 0)
3225 geometry_info.sigma=1.0;
3226 if ((flags & XiValue) == 0)
3227 geometry_info.xi=0.0;
3228 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3232 if (LocaleCompare("shave",option+1) == 0)
3234 if (IfMagickFalse(IsGeometry(arg1)))
3235 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3236 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3237 new_image=ShaveImage(_image,&geometry,_exception);
3240 if (LocaleCompare("shear",option+1) == 0)
3242 flags=ParseGeometry(arg1,&geometry_info);
3243 if ((flags & RhoValue) == 0)
3244 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3245 if ((flags & SigmaValue) == 0)
3246 geometry_info.sigma=geometry_info.rho;
3247 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3251 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3253 flags=ParseGeometry(arg1,&geometry_info);
3254 if ((flags & RhoValue) == 0)
3255 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3256 if ((flags & SigmaValue) == 0)
3257 geometry_info.sigma=(double) QuantumRange/2.0;
3258 if ((flags & PercentValue) != 0)
3259 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3261 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3262 geometry_info.sigma,_exception);
3265 if (LocaleCompare("sketch",option+1) == 0)
3267 flags=ParseGeometry(arg1,&geometry_info);
3268 if ((flags & (RhoValue|SigmaValue)) == 0)
3269 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3270 if ((flags & SigmaValue) == 0)
3271 geometry_info.sigma=1.0;
3272 new_image=SketchImage(_image,geometry_info.rho,
3273 geometry_info.sigma,geometry_info.xi,_exception);
3276 if (LocaleCompare("solarize",option+1) == 0)
3278 if (IfMagickFalse(IsGeometry(arg1)))
3279 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3280 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3281 QuantumRange+1.0),_exception);
3284 if (LocaleCompare("sparse-color",option+1) == 0)
3286 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3288 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3290 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3294 if (LocaleCompare("splice",option+1) == 0)
3296 if (IfMagickFalse(IsGeometry(arg1)))
3297 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3298 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3299 new_image=SpliceImage(_image,&geometry,_exception);
3302 if (LocaleCompare("spread",option+1) == 0)
3304 flags=ParseGeometry(arg1,&geometry_info);
3305 if ((flags & RhoValue) == 0)
3306 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3307 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3311 if (LocaleCompare("statistic",option+1) == 0)
3313 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3315 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3317 flags=ParseGeometry(arg2,&geometry_info);
3318 if ((flags & RhoValue) == 0)
3319 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3320 if ((flags & SigmaValue) == 0)
3321 geometry_info.sigma=geometry_info.rho;
3322 new_image=StatisticImage(_image,(StatisticType)parse,
3323 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3327 if (LocaleCompare("strip",option+1) == 0)
3329 (void) StripImage(_image,_exception);
3332 if (LocaleCompare("swirl",option+1) == 0)
3334 flags=ParseGeometry(arg1,&geometry_info);
3335 if ((flags & RhoValue) == 0)
3336 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3337 new_image=SwirlImage(_image,geometry_info.rho,
3338 _image->interpolate,_exception);
3341 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3345 if (LocaleCompare("threshold",option+1) == 0)
3350 threshold=(double) QuantumRange/2;
3352 if (IfMagickFalse(IsGeometry(arg1)))
3353 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3354 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3356 (void) BilevelImage(_image,threshold,_exception);
3359 if (LocaleCompare("thumbnail",option+1) == 0)
3361 if (IfMagickFalse(IsGeometry(arg1)))
3362 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3363 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3364 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3368 if (LocaleCompare("tint",option+1) == 0)
3370 if (IfMagickFalse(IsGeometry(arg1)))
3371 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3372 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3375 if (LocaleCompare("transform",option+1) == 0)
3377 CLIWandWarnReplaced("+distort AffineProjection");
3378 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3381 if (LocaleCompare("transparent",option+1) == 0)
3386 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3387 (void) TransparentPaintImage(_image,&target,(Quantum)
3388 TransparentAlpha,IsPlusOp,_exception);
3391 if (LocaleCompare("transpose",option+1) == 0)
3393 new_image=TransposeImage(_image,_exception);
3396 if (LocaleCompare("transverse",option+1) == 0)
3398 new_image=TransverseImage(_image,_exception);
3401 if (LocaleCompare("trim",option+1) == 0)
3403 new_image=TrimImage(_image,_exception);
3406 if (LocaleCompare("type",option+1) == 0)
3408 /* Note that "type" setting should have already been defined */
3409 (void) SetImageType(_image,_image_info->type,_exception);
3412 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3416 if (LocaleCompare("unique",option+1) == 0)
3418 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3419 Option is not documented, bt appears to be for "identify".
3420 We may need a identify specific verbose!
3423 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3426 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3427 (void) SetImageArtifact(_image,"verbose","true");
3430 if (LocaleCompare("unique-colors",option+1) == 0)
3432 new_image=UniqueImageColors(_image,_exception);
3435 if (LocaleCompare("unsharp",option+1) == 0)
3437 flags=ParseGeometry(arg1,&geometry_info);
3438 if ((flags & (RhoValue|SigmaValue)) == 0)
3439 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3440 if ((flags & SigmaValue) == 0)
3441 geometry_info.sigma=1.0;
3442 if ((flags & XiValue) == 0)
3443 geometry_info.xi=1.0;
3444 if ((flags & PsiValue) == 0)
3445 geometry_info.psi=0.05;
3446 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3447 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3450 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3454 if (LocaleCompare("verbose",option+1) == 0)
3456 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3457 three places! ImageArtifact ImageOption _image_info->verbose
3458 Some how new images also get this artifact!
3460 (void) SetImageArtifact(_image,option+1,
3461 IfNormalOp ? "true" : "false" );
3464 if (LocaleCompare("vignette",option+1) == 0)
3466 flags=ParseGeometry(arg1,&geometry_info);
3467 if ((flags & (RhoValue|SigmaValue)) == 0)
3468 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3469 if ((flags & SigmaValue) == 0)
3470 geometry_info.sigma=1.0;
3471 if ((flags & XiValue) == 0)
3472 geometry_info.xi=0.1*_image->columns;
3473 if ((flags & PsiValue) == 0)
3474 geometry_info.psi=0.1*_image->rows;
3475 if ((flags & PercentValue) != 0)
3477 geometry_info.xi*=(double) _image->columns/100.0;
3478 geometry_info.psi*=(double) _image->rows/100.0;
3480 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3481 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3482 ceil(geometry_info.psi-0.5),_exception);
3485 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3489 if (LocaleCompare("wave",option+1) == 0)
3491 flags=ParseGeometry(arg1,&geometry_info);
3492 if ((flags & (RhoValue|SigmaValue)) == 0)
3493 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3494 if ((flags & SigmaValue) == 0)
3495 geometry_info.sigma=1.0;
3496 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3497 _image->interpolate,_exception);
3500 if (LocaleCompare("white-threshold",option+1) == 0)
3502 if (IfMagickFalse(IsGeometry(arg1)))
3503 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3504 (void) WhiteThresholdImage(_image,arg1,_exception);
3507 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3510 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3512 /* clean up percent escape interpreted strings */
3514 arg1=DestroyString((char *)arg1);
3516 arg2=DestroyString((char *)arg2);
3518 /* Replace current image with any image that was generated
3519 and set image point to last image (so image->next is correct) */
3520 if (new_image != (Image *) NULL)
3521 ReplaceImageInListReturnLast(&_image,new_image);
3526 #undef _quantize_info
3535 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3536 const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3538 #if !USE_WAND_METHODS
3544 assert(cli_wand != (MagickCLI *) NULL);
3545 assert(cli_wand->signature == WandSignature);
3546 assert(cli_wand->wand.signature == WandSignature);
3547 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3549 if (IfMagickTrue(cli_wand->wand.debug))
3550 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3551 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3553 #if !USE_WAND_METHODS
3554 /* FUTURE add appropriate tracing */
3556 n=GetImageListLength(cli_wand->wand.images);
3557 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3560 CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3561 if ( cli_wand->wand.images->next == (Image *) NULL )
3563 cli_wand->wand.images=cli_wand->wand.images->next;
3566 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3568 MagickResetIterator(&cli_wand->wand);
3569 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3570 CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3571 MagickResetIterator(&cli_wand->wand);
3577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3581 + C L I L i s t O p e r a t o r I m a g e s %
3585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3587 % CLIListOperatorImages() applies a single operation that is apply to the
3588 % entire image list as a whole. The result is often a complete replacment
3589 % of the image list with a completely new list, or with just a single image
3592 % The format of the MogrifyImage method is:
3594 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3595 % const char *option,const char *arg1,const char *arg2)
3597 % A description of each parameter follows:
3599 % o cli_wand: structure holding settings to be applied
3601 % o option: The option string for the operation
3603 % o arg1, arg2: optional argument strings to the operation
3604 % arg2 is currently not used
3607 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3608 const char *option,const char *arg1n,const char *arg2n)
3610 const char /* percent escaped versions of the args */
3623 #define _image_info (cli_wand->wand.image_info)
3624 #define _images (cli_wand->wand.images)
3625 #define _exception (cli_wand->wand.exception)
3626 #define _draw_info (cli_wand->draw_info)
3627 #define _quantize_info (cli_wand->quantize_info)
3628 #define _process_flags (cli_wand->process_flags)
3629 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3630 #define IfNormalOp (*option=='-')
3631 #define IfPlusOp (*option!='-')
3632 #define IsNormalOp IsMagickTrue(IfNormalOp)
3634 assert(cli_wand != (MagickCLI *) NULL);
3635 assert(cli_wand->signature == WandSignature);
3636 assert(cli_wand->wand.signature == WandSignature);
3637 assert(_images != (Image *) NULL); /* _images must be present */
3639 if (IfMagickTrue(cli_wand->wand.debug))
3640 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3641 "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
3646 /* Interpret Percent Escapes in Arguments - using first image */
3647 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3648 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3649 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3650 /* Interpret Percent escapes in argument 1 */
3651 if (arg1n != (char *) NULL) {
3652 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3653 if (arg1 == (char *) NULL) {
3654 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3655 arg1=arg1n; /* use the given argument as is */
3658 if (arg2n != (char *) NULL) {
3659 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3660 if (arg2 == (char *) NULL) {
3661 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3662 arg2=arg2n; /* use the given argument as is */
3666 #undef _process_flags
3670 new_images=NewImageList();
3672 switch (*(option+1))
3676 if (LocaleCompare("append",option+1) == 0)
3678 new_images=AppendImages(_images,IsNormalOp,_exception);
3681 if (LocaleCompare("average",option+1) == 0)
3683 CLIWandWarnReplaced("-evaluate-sequence Mean");
3684 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3687 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3691 if (LocaleCompare("channel-fx",option+1) == 0)
3693 new_images=ChannelFxImage(_images,arg1,_exception);
3696 if (LocaleCompare("clut",option+1) == 0)
3701 /* FUTURE - make this a compose option, and thus can be used
3702 with layers compose or even compose last image over all other
3705 new_images=RemoveFirstImageFromList(&_images);
3706 clut_image=RemoveLastImageFromList(&_images);
3707 /* FUTURE - produce Exception, rather than silent fail */
3708 if (clut_image == (Image *) NULL)
3710 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3711 clut_image=DestroyImage(clut_image);
3714 if (LocaleCompare("coalesce",option+1) == 0)
3716 new_images=CoalesceImages(_images,_exception);
3719 if (LocaleCompare("combine",option+1) == 0)
3721 parse = (ssize_t) sRGBColorspace; /* default (backward compatible) */
3723 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
3726 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3728 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3731 if (LocaleCompare("compare",option+1) == 0)
3744 Mathematically and visually annotate the difference between an
3745 image and its reconstruction.
3747 image=RemoveFirstImageFromList(&_images);
3748 reconstruct_image=RemoveFirstImageFromList(&_images);
3749 /* FUTURE - produce Exception, rather than silent fail */
3750 if (reconstruct_image == (Image *) NULL)
3752 metric=UndefinedErrorMetric;
3753 option=GetImageOption(_image_info,"metric");
3754 if (option != (const char *) NULL)
3755 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3756 MagickFalse,option);
3757 new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3760 reconstruct_image=DestroyImage(reconstruct_image);
3761 image=DestroyImage(image);
3764 if (LocaleCompare("complex",option+1) == 0)
3766 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3768 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3770 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3773 if (LocaleCompare("composite",option+1) == 0)
3791 /* Compose value from "-compose" option only */
3792 value=GetImageOption(_image_info,"compose");
3793 if (value == (const char *) NULL)
3794 compose=OverCompositeOp; /* use Over not source_image->compose */
3796 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3799 /* Get "clip-to-self" expert setting (false is normal) */
3800 value=GetImageOption(_image_info,"compose:clip-to-self");
3801 if (value == (const char *) NULL)
3802 clip_to_self=MagickTrue;
3804 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3805 "compose:clip-to-self")); /* if this is true */
3806 value=GetImageOption(_image_info,"compose:outside-overlay");
3807 if (value != (const char *) NULL) { /* or this false */
3808 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3809 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3812 new_images=RemoveFirstImageFromList(&_images);
3813 source_image=RemoveFirstImageFromList(&_images);
3814 if (source_image == (Image *) NULL)
3815 break; /* FUTURE - produce Exception, rather than silent fail */
3817 /* FUTURE - this should not be here! - should be part of -geometry */
3818 (void) TransformImage(&source_image,(char *) NULL,
3819 source_image->geometry,_exception);
3820 SetGeometry(source_image,&geometry);
3821 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3822 GravityAdjustGeometry(new_images->columns,new_images->rows,
3823 new_images->gravity, &geometry);
3824 mask_image=RemoveFirstImageFromList(&_images);
3825 if (mask_image != (Image *) NULL)
3827 if ((compose == DisplaceCompositeOp) ||
3828 (compose == DistortCompositeOp))
3829 status&=CompositeImage(source_image,mask_image,
3830 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3839 source_geometry.width=mask_image->columns;
3840 source_geometry.height=mask_image->rows;
3841 source_geometry.x=(-geometry.x);
3842 source_geometry.y=(-geometry.y);
3845 image=ExtentImage(source_image,&source_geometry,_exception);
3846 if (image != (Image *) NULL)
3848 source_image=DestroyImage(source_image);
3851 status&=CompositeImage(source_image,mask_image,
3852 IntensityCompositeOp,MagickTrue,0,0,_exception);
3854 mask_image=DestroyImage(mask_image);
3856 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3857 geometry.x,geometry.y,_exception);
3858 source_image=DestroyImage(source_image);
3861 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3865 if (LocaleCompare("deconstruct",option+1) == 0)
3867 CLIWandWarnReplaced("-layer CompareAny");
3868 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3871 if (LocaleCompare("delete",option+1) == 0)
3874 DeleteImages(&_images,arg1,_exception);
3876 DeleteImages(&_images,"-1",_exception);
3879 if (LocaleCompare("duplicate",option+1) == 0)
3889 if (IfMagickFalse(IsGeometry(arg1)))
3890 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3892 number_duplicates=(size_t) StringToLong(arg1);
3894 if (p == (const char *) NULL)
3895 new_images=DuplicateImages(_images,number_duplicates,"-1",
3898 new_images=DuplicateImages(_images,number_duplicates,p,
3902 new_images=DuplicateImages(_images,1,"-1",_exception);
3903 AppendImageToList(&_images, new_images);
3904 new_images=(Image *)NULL;
3907 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3911 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3913 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3915 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3917 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3921 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3925 if (LocaleCompare("fft",option+1) == 0)
3927 new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception);
3930 if (LocaleCompare("flatten",option+1) == 0)
3932 /* REDIRECTED to use -layers flatten instead */
3933 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3936 if (LocaleCompare("fx",option+1) == 0)
3938 new_images=FxImage(_images,arg1,_exception);
3941 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3945 if (LocaleCompare("hald-clut",option+1) == 0)
3947 /* FUTURE - make this a compose option (and thus layers compose )
3948 or perhaps compose last image over all other _images.
3953 new_images=RemoveFirstImageFromList(&_images);
3954 hald_image=RemoveLastImageFromList(&_images);
3955 if (hald_image == (Image *) NULL)
3957 (void) HaldClutImage(new_images,hald_image,_exception);
3958 hald_image=DestroyImage(hald_image);
3961 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3965 if (LocaleCompare("ift",option+1) == 0)
3971 magnitude_image=RemoveFirstImageFromList(&_images);
3972 phase_image=RemoveFirstImageFromList(&_images);
3973 /* FUTURE - produce Exception, rather than silent fail */
3974 if (phase_image == (Image *) NULL)
3976 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3977 IsNormalOp,_exception);
3978 magnitude_image=DestroyImage(magnitude_image);
3979 phase_image=DestroyImage(phase_image);
3982 if (LocaleCompare("insert",option+1) == 0)
3991 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3992 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3994 insert_image=RemoveLastImageFromList(&_images);
3996 index=(ssize_t) StringToLong(arg1);
3997 index_image=insert_image;
3999 PrependImageToList(&_images,insert_image);
4000 else if (index == (ssize_t) GetImageListLength(_images))
4001 AppendImageToList(&_images,insert_image);
4004 index_image=GetImageFromList(_images,index-1);
4005 if (index_image == (Image *) NULL)
4006 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4007 InsertImageInList(&index_image,insert_image);
4009 _images=GetFirstImageInList(index_image);
4012 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4016 if (LocaleCompare("layers",option+1) == 0)
4018 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4020 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4022 switch ((LayerMethod) parse)
4026 new_images=CoalesceImages(_images,_exception);
4029 case CompareAnyLayer:
4030 case CompareClearLayer:
4031 case CompareOverlayLayer:
4034 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4041 case TrimBoundsLayer:
4043 new_images=MergeImageLayers(_images,(LayerMethod) parse,
4049 new_images=DisposeImages(_images,_exception);
4052 case OptimizeImageLayer:
4054 new_images=OptimizeImageLayers(_images,_exception);
4057 case OptimizePlusLayer:
4059 new_images=OptimizePlusImageLayers(_images,_exception);
4062 case OptimizeTransLayer:
4064 OptimizeImageTransparency(_images,_exception);
4067 case RemoveDupsLayer:
4069 RemoveDuplicateLayers(&_images,_exception);
4072 case RemoveZeroLayer:
4074 RemoveZeroDelayLayers(&_images,_exception);
4078 { /* General Purpose, GIF Animation Optimizer. */
4079 new_images=CoalesceImages(_images,_exception);
4080 if (new_images == (Image *) NULL)
4082 _images=DestroyImageList(_images);
4083 _images=OptimizeImageLayers(new_images,_exception);
4084 if (_images == (Image *) NULL)
4086 new_images=DestroyImageList(new_images);
4087 OptimizeImageTransparency(_images,_exception);
4088 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4092 case CompositeLayer:
4106 value=GetImageOption(_image_info,"compose");
4107 compose=OverCompositeOp; /* Default to Over */
4108 if (value != (const char *) NULL)
4109 compose=(CompositeOperator) ParseCommandOption(
4110 MagickComposeOptions,MagickFalse,value);
4112 /* Split image sequence at the first 'NULL:' image. */
4114 while (source != (Image *) NULL)
4116 source=GetNextImageInList(source);
4117 if ((source != (Image *) NULL) &&
4118 (LocaleCompare(source->magick,"NULL") == 0))
4121 if (source != (Image *) NULL)
4123 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4124 (GetNextImageInList(source) == (Image *) NULL))
4125 source=(Image *) NULL;
4127 { /* Separate the two lists, junk the null: image. */
4128 source=SplitImageList(source->previous);
4129 DeleteImageFromList(&source);
4132 if (source == (Image *) NULL)
4134 (void) ThrowMagickException(_exception,GetMagickModule(),
4135 OptionError,"MissingNullSeparator","layers Composite");
4138 /* Adjust offset with gravity and virtual canvas. */
4139 SetGeometry(_images,&geometry);
4140 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4141 geometry.width=source->page.width != 0 ?
4142 source->page.width : source->columns;
4143 geometry.height=source->page.height != 0 ?
4144 source->page.height : source->rows;
4145 GravityAdjustGeometry(_images->page.width != 0 ?
4146 _images->page.width : _images->columns,
4147 _images->page.height != 0 ? _images->page.height :
4148 _images->rows,_images->gravity,&geometry);
4150 /* Compose the two image sequences together */
4151 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4153 source=DestroyImageList(source);
4159 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4163 if (LocaleCompare("map",option+1) == 0)
4165 CLIWandWarnReplaced("+remap");
4166 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4169 if (LocaleCompare("metric",option+1) == 0)
4171 if (LocaleCompare("morph",option+1) == 0)
4176 if (IfMagickFalse(IsGeometry(arg1)))
4177 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4178 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4180 if (morph_image == (Image *) NULL)
4182 _images=DestroyImageList(_images);
4183 _images=morph_image;
4186 if (LocaleCompare("mosaic",option+1) == 0)
4188 /* REDIRECTED to use -layers mosaic instead */
4189 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4192 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4196 if (LocaleCompare("poly",option+1) == 0)
4204 /* convert argument string into an array of doubles */
4205 args = StringToArrayOfDoubles(arg2,&count,_exception);
4206 if (args == (double *)NULL )
4207 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4208 new_images=PolynomialImage(_images,count >> 1,args,_exception);
4209 args=(double *) RelinquishMagickMemory(args);
4212 if (LocaleCompare("process",option+1) == 0)
4214 /* FUTURE: better parsing using ScriptToken() from string ??? */
4222 arguments=StringToArgv(arg1,&number_arguments);
4223 if (arguments == (char **) NULL)
4225 if (strchr(arguments[1],'=') != (char *) NULL)
4246 Support old style syntax, filter="-option arg1".
4248 assert(arg1 != (const char *) NULL);
4249 length=strlen(arg1);
4250 token=(char *) NULL;
4251 if (~length >= (MaxTextExtent-1))
4252 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4254 if (token == (char *) NULL)
4258 token_info=AcquireTokenInfo();
4259 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4260 "\"",'\0',&breaker,&next,"e);
4261 token_info=DestroyTokenInfo(token_info);
4267 argv=(&(arguments[next]));
4268 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4271 token=DestroyString(token);
4274 (void) SubstituteString(&arguments[1],"-","");
4275 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4276 number_arguments-2,(const char **) arguments+2,_exception);
4277 for (j=0; j < number_arguments; j++)
4278 arguments[j]=DestroyString(arguments[j]);
4279 arguments=(char **) RelinquishMagickMemory(arguments);
4282 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4286 if (LocaleCompare("remap",option+1) == 0)
4288 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4291 if (LocaleCompare("reverse",option+1) == 0)
4293 ReverseImageList(&_images);
4296 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4300 if (LocaleCompare("smush",option+1) == 0)
4302 /* FUTURE: this option needs more work to make better */
4306 if (IfMagickFalse(IsGeometry(arg1)))
4307 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4308 offset=(ssize_t) StringToLong(arg1);
4309 new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4312 if (LocaleCompare("subimage",option+1) == 0)
4330 base_image=GetImageFromList(_images,0);
4331 compare_image=GetImageFromList(_images,1);
4333 /* Comparision Metric */
4334 metric=UndefinedErrorMetric;
4335 value=GetImageOption(_image_info,"metric");
4336 if (value != (const char *) NULL)
4337 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4340 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4341 &offset,&similarity,_exception);
4343 if ( new_images != (Image *)NULL ) {
4345 result[MaxTextExtent];
4347 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4348 (void) SetImageProperty(new_images,"subimage:similarity",result,
4350 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4352 (void) SetImageProperty(new_images,"subimage:x",result,
4354 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4356 (void) SetImageProperty(new_images,"subimage:y",result,
4358 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4359 (unsigned long) offset.width,(unsigned long) offset.height,
4360 (long) offset.x,(long) offset.y);
4361 (void) SetImageProperty(new_images,"subimage:offset",result,
4366 if (LocaleCompare("swap",option+1) == 0) {
4386 flags=ParseGeometry(arg1,&geometry_info);
4387 if ((flags & RhoValue) == 0)
4388 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4389 index=(ssize_t) geometry_info.rho;
4390 if ((flags & SigmaValue) != 0)
4391 swap_index=(ssize_t) geometry_info.sigma;
4393 p=GetImageFromList(_images,index);
4394 q=GetImageFromList(_images,swap_index);
4395 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4397 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4399 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4402 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4403 swap=CloneImage(p,0,0,MagickTrue,_exception);
4404 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4405 ReplaceImageInList(&q,swap);
4406 _images=GetFirstImageInList(q);
4409 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4412 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4415 /* clean up percent escape interpreted strings */
4417 arg1=DestroyString((char *)arg1);
4419 arg2=DestroyString((char *)arg2);
4421 /* if new image list generated, replace existing image list */
4422 if (new_images == (Image *) NULL)
4423 return(status == 0 ? MagickFalse : MagickTrue);
4424 _images=DestroyImageList(_images);
4425 _images=GetFirstImageInList(new_images);
4426 return(status == 0 ? MagickFalse : MagickTrue);
4432 #undef _quantize_info
4439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4443 + C L I N o I m a g e O p e r a t i o n s %
4447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4449 % CLINoImageOperator() Applies operations that may not actually need images
4452 % The classic operators of this type is "-read", which actually creates
4453 % images even when no images are present. Or image stack operators, which
4454 % can be applied (push or pop) to an empty image list.
4456 % Note that these operators may involve other special 'option' prefix
4457 % characters other than '-' or '+', namely parenthesis and braces.
4459 % The format of the CLINoImageOption method is:
4461 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4462 % const char *arg1, const char *arg2)
4464 % A description of each parameter follows:
4466 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4468 % o option: The special option (with any switch char) to process
4470 % o arg1 & arg2: Argument for option, if required
4471 % Currently arg2 is not used.
4474 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4475 const char *option,const char *arg1n,const char *arg2n)
4477 const char /* percent escaped versions of the args */
4481 #define _image_info (cli_wand->wand.image_info)
4482 #define _images (cli_wand->wand.images)
4483 #define _exception (cli_wand->wand.exception)
4484 #define _process_flags (cli_wand->process_flags)
4485 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4486 #define IfNormalOp (*option=='-')
4487 #define IfPlusOp (*option!='-')
4489 assert(cli_wand != (MagickCLI *) NULL);
4490 assert(cli_wand->signature == WandSignature);
4491 assert(cli_wand->wand.signature == WandSignature);
4493 if (IfMagickTrue(cli_wand->wand.debug))
4494 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4495 "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
4500 /* Interpret Percent Escapes in Arguments - using first image */
4501 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4502 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4503 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4504 /* Interpret Percent escapes in argument 1 */
4505 if (arg1n != (char *) NULL) {
4506 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4507 if (arg1 == (char *) NULL) {
4508 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4509 arg1=arg1n; /* use the given argument as is */
4512 if (arg2n != (char *) NULL) {
4513 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4514 if (arg2 == (char *) NULL) {
4515 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4516 arg2=arg2n; /* use the given argument as is */
4520 #undef _process_flags
4523 do { /* break to exit code */
4525 No-op options (ignore these)
4527 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4529 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4531 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4533 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4535 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4540 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4541 ( LocaleCompare("--",option) == 0 ) ) {
4542 /* Do Glob filename Expansion for 'arg1' then read all images.
4544 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4545 * (but attaching to the filenames in the generated argument list) any
4546 * [...] read modifiers that may be present.
4548 * For example: It will expand '*.gif[20x20]' into a list such as
4549 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4551 * NOTE: In IMv6 this was done globally across all images. This
4552 * meant you could include IM options in '@filename' lists, but you
4553 * could not include comments. Doing it only for image read makes
4554 * it far more secure.
4556 * Note: arguments do not have percent escapes expanded for security
4564 argv = (char **) &arg1;
4566 /* Expand 'glob' expressions in the given filename.
4567 Expansion handles any 'coder:' prefix, or read modifiers attached
4568 to the filename, including them in the resulting expanded list.
4570 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4571 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4572 option,GetExceptionMessage(errno));
4574 /* loop over expanded filename list, and read then all in */
4575 for (i=0; i<argc; i++) {
4578 if (IfMagickTrue(_image_info->ping))
4579 new_images=PingImages(_image_info,argv[i],_exception);
4581 new_images=ReadImages(_image_info,argv[i],_exception);
4582 AppendImageToList(&_images, new_images);
4584 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4589 Note: Writing a empty image list is valid in specific cases
4591 if (LocaleCompare("write",option+1) == 0) {
4592 /* Note: arguments do not have percent escapes expanded */
4602 /* Need images, unless a "null:" output coder is used */
4603 if ( _images == (Image *) NULL ) {
4604 if ( LocaleCompare(arg1,"null:") == 0 )
4606 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4609 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4610 (void) DeleteImageRegistry(key);
4611 write_images=_images;
4613 write_images=CloneImageList(_images,_exception);
4614 write_info=CloneImageInfo(_image_info);
4615 (void) WriteImages(write_info,write_images,arg1,_exception);
4616 write_info=DestroyImageInfo(write_info);
4618 write_images=DestroyImageList(write_images);
4622 Parenthesis and Brace operations
4624 if (LocaleCompare("(",option) == 0) {
4625 /* stack 'push' images */
4633 node=cli_wand->image_list_stack;
4634 for ( ; node != (Stack *)NULL; node=node->next)
4636 if ( size >= MAX_STACK_DEPTH )
4637 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4638 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4639 if (node == (Stack *) NULL)
4640 CLIWandExceptionBreak(ResourceLimitFatalError,
4641 "MemoryAllocationFailed",option);
4642 node->data = (void *)cli_wand->wand.images;
4643 node->next = cli_wand->image_list_stack;
4644 cli_wand->image_list_stack = node;
4645 cli_wand->wand.images = NewImageList();
4647 /* handle respect-parenthesis */
4648 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4649 "respect-parenthesis"))))
4650 option="{"; /* fall-thru so as to push image settings too */
4653 /* fall thru to operation */
4655 if (LocaleCompare("{",option) == 0) {
4656 /* stack 'push' of image_info settings */
4664 node=cli_wand->image_info_stack;
4665 for ( ; node != (Stack *)NULL; node=node->next)
4667 if ( size >= MAX_STACK_DEPTH )
4668 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4669 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4670 if (node == (Stack *) NULL)
4671 CLIWandExceptionBreak(ResourceLimitFatalError,
4672 "MemoryAllocationFailed",option);
4674 node->data = (void *)cli_wand->wand.image_info;
4675 node->next = cli_wand->image_info_stack;
4677 cli_wand->image_info_stack = node;
4678 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4679 if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4680 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4682 cli_wand->wand.image_info = (ImageInfo *)node->data;
4683 node = (Stack *)RelinquishMagickMemory(node);
4689 if (LocaleCompare(")",option) == 0) {
4690 /* pop images from stack */
4694 node = (Stack *)cli_wand->image_list_stack;
4695 if ( node == (Stack *)NULL)
4696 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4697 cli_wand->image_list_stack = node->next;
4699 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4700 cli_wand->wand.images= (Image *)node->data;
4701 node = (Stack *)RelinquishMagickMemory(node);
4703 /* handle respect-parenthesis - of the previous 'pushed' settings */
4704 node = cli_wand->image_info_stack;
4705 if ( node != (Stack *)NULL)
4707 if (IfMagickTrue(IsStringTrue(GetImageOption(
4708 cli_wand->wand.image_info,"respect-parenthesis"))))
4709 option="}"; /* fall-thru so as to pop image settings too */
4715 /* fall thru to next if */
4717 if (LocaleCompare("}",option) == 0) {
4718 /* pop image_info settings from stack */
4722 node = (Stack *)cli_wand->image_info_stack;
4723 if ( node == (Stack *)NULL)
4724 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4725 cli_wand->image_info_stack = node->next;
4727 (void) DestroyImageInfo(cli_wand->wand.image_info);
4728 cli_wand->wand.image_info = (ImageInfo *)node->data;
4729 node = (Stack *)RelinquishMagickMemory(node);
4731 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4732 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4733 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4737 if (LocaleCompare("print",option+1) == 0)
4739 (void) FormatLocaleFile(stdout,"%s",arg1);
4742 if (LocaleCompare("set",option+1) == 0)
4744 /* Settings are applied to each image in memory in turn (if any).
4745 While a option: only need to be applied once globally.
4747 NOTE: rguments have not been automatically percent expaneded
4750 /* escape the 'key' once only, using first image. */
4751 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4752 if (arg1 == (char *) NULL)
4753 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4756 if (LocaleNCompare(arg1,"registry:",9) == 0)
4760 (void) DeleteImageRegistry(arg1+9);
4761 arg1=DestroyString((char *)arg1);
4764 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4765 if (arg2 == (char *) NULL) {
4766 arg1=DestroyString((char *)arg1);
4767 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4770 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4771 arg1=DestroyString((char *)arg1);
4772 arg2=DestroyString((char *)arg2);
4775 if (LocaleNCompare(arg1,"option:",7) == 0)
4777 /* delete equivelent artifact from all images (if any) */
4778 if (_images != (Image *)NULL)
4780 MagickResetIterator(&cli_wand->wand);
4781 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4782 (void) DeleteImageArtifact(_images,arg1+7);
4783 MagickResetIterator(&cli_wand->wand);
4785 /* now set/delete the global option as needed */
4786 /* FUTURE: make escapes in a global 'option:' delayed */
4790 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4791 if (arg2 == (char *) NULL)
4792 CLIWandExceptionBreak(OptionWarning,
4793 "InterpretPropertyFailure",option);
4795 (void) SetImageOption(_image_info,arg1+7,arg2);
4796 arg1=DestroyString((char *)arg1);
4797 arg2=DestroyString((char *)arg2);
4800 /* Set Artifacts/Properties/Attributes all images (required) */
4801 if ( _images == (Image *) NULL )
4802 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4804 MagickResetIterator(&cli_wand->wand);
4805 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4810 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4811 if (arg2 == (char *) NULL)
4812 CLIWandExceptionBreak(OptionWarning,
4813 "InterpretPropertyFailure",option);
4815 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4816 (void) SetImageArtifact(_images,arg1+9,arg2);
4817 else if (LocaleNCompare(arg1,"property:",9) == 0)
4818 (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4820 (void) SetImageProperty(_images,arg1,arg2,_exception);
4821 arg2=DestroyString((char *)arg2);
4823 MagickResetIterator(&cli_wand->wand);
4824 arg1=DestroyString((char *)arg1);
4827 if (LocaleCompare("clone",option+1) == 0) {
4833 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4834 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4835 if ( cli_wand->image_list_stack == (Stack *)NULL)
4836 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4837 new_images = (Image *)cli_wand->image_list_stack->data;
4838 if (new_images == (Image *) NULL)
4839 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4840 new_images=CloneImages(new_images,arg1,_exception);
4841 if (new_images == (Image *) NULL)
4842 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4843 AppendImageToList(&_images,new_images);
4847 Informational Operations.
4849 Note that these do not require either a cli-wand or images!
4850 Though currently a cli-wand much be provided regardless.
4852 if (LocaleCompare("version",option+1) == 0)
4854 ListMagickVersion(stdout);
4857 if (LocaleCompare("list",option+1) == 0) {
4859 FUTURE: This 'switch' should really be part of MagickCore
4864 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4866 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4871 case MagickCoderOptions:
4873 (void) ListCoderInfo((FILE *) NULL,_exception);
4876 case MagickColorOptions:
4878 (void) ListColorInfo((FILE *) NULL,_exception);
4881 case MagickConfigureOptions:
4883 (void) ListConfigureInfo((FILE *) NULL,_exception);
4886 case MagickDelegateOptions:
4888 (void) ListDelegateInfo((FILE *) NULL,_exception);
4891 case MagickFontOptions:
4893 (void) ListTypeInfo((FILE *) NULL,_exception);
4896 case MagickFormatOptions:
4897 (void) ListMagickInfo((FILE *) NULL,_exception);
4899 case MagickLocaleOptions:
4900 (void) ListLocaleInfo((FILE *) NULL,_exception);
4902 case MagickLogOptions:
4903 (void) ListLogInfo((FILE *) NULL,_exception);
4905 case MagickMagicOptions:
4906 (void) ListMagicInfo((FILE *) NULL,_exception);
4908 case MagickMimeOptions:
4909 (void) ListMimeInfo((FILE *) NULL,_exception);
4911 case MagickModuleOptions:
4912 (void) ListModuleInfo((FILE *) NULL,_exception);
4914 case MagickPolicyOptions:
4915 (void) ListPolicyInfo((FILE *) NULL,_exception);
4917 case MagickResourceOptions:
4918 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4920 case MagickThresholdOptions:
4921 (void) ListThresholdMaps((FILE *) NULL,_exception);
4924 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4931 CLIWandException(OptionError,"UnrecognizedOption",option);
4933 DisableMSCWarning(4127)
4934 } while (0); /* break to exit code. */
4937 /* clean up percent escape interpreted strings */
4939 arg1=DestroyString((char *)arg1);
4941 arg2=DestroyString((char *)arg2);
4951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4955 + C L I O p t i o n %
4959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4961 % CLIOption() Processes the given option using the given CLI Magick Wand.
4962 % The option arguments can be variable in number, though at this time no more
4963 % that two is actually used by any option (this may change). Excess options
4964 % are simply ignored.
4966 % If the cli_wand->command pointer is non-null, then it is assumed that the
4967 % option has already been search for up from the CommandOptions[] table in
4968 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4969 % routine will do the lookup instead. The pointer is reset afterward.
4971 % This action allows the caller to lookup and pre-handle any 'special'
4972 % options, (such as implicit reads) before calling this general option
4973 % handler to deal with 'standard' command line options.
4975 % The format of the CLIOption method is:
4977 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4979 % A description of each parameter follows:
4981 % o cli_wand: the main CLI Wand to use.
4983 % o option: The special option (with any switch char) to process
4985 % o args: any required arguments for an option (variable number)
4989 % CLIoption(cli_wand,"-read","rose:");
4990 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4991 % CLIoption(cli_wand,"-distort","SRT:","30");
4992 % CLIoption(cli_wand,"-write","rotated_rose.png");
4995 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4997 const char /* extracted option args from args */
5004 assert(cli_wand != (MagickCLI *) NULL);
5005 assert(cli_wand->signature == WandSignature);
5006 assert(cli_wand->wand.signature == WandSignature);
5008 do { /* Break Code Block for error handling */
5010 /* get information about option */
5011 if ( cli_wand->command == (const OptionInfo *) NULL )
5012 cli_wand->command = GetCommandOptionInfo(option);
5014 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5015 option, cli_wand->command->mnemonic );
5017 option_type=(CommandOptionFlags) cli_wand->command->flags;
5019 if ( option_type == UndefinedOptionFlag )
5020 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5022 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5024 /* deprecated options */
5025 if ( (option_type & DeprecateOptionFlag) != 0 )
5026 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5028 /* options that this module does not handle */
5029 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5030 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5032 /* Get argument strings from VarArgs
5033 How can you determine if enough arguments was supplied?
5034 What happens if not enough arguments were supplied?
5037 count = cli_wand->command->type;
5042 va_start(operands,option);
5046 arg1=(const char *) va_arg(operands, const char *);
5048 arg2=(const char *) va_arg(operands, const char *);
5052 (void) FormatLocaleFile(stderr,
5053 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5054 option,(long) count,option_type,arg1,arg2);
5059 Call the appropriate option handler
5062 /* FUTURE: this is temporary - get 'settings' to handle distribution of
5063 settings to images attributes,proprieties,artifacts */
5064 if ( cli_wand->wand.images != (Image *)NULL )
5065 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5066 cli_wand->wand.exception);
5068 if ( (option_type & SettingOptionFlags) != 0 ) {
5069 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5070 // FUTURE: Sync Specific Settings into Image Properities (not global)
5073 /* Operators that do not need images - read, write, stack, clone */
5074 if ( (option_type & NoImageOperatorFlag) != 0)
5075 CLINoImageOperator(cli_wand, option, arg1, arg2);
5077 /* FUTURE: The not a setting part below is a temporary hack due to
5078 * some options being both a Setting and a Simple operator.
5079 * Specifically -monitor, -depth, and -colorspace */
5080 if ( cli_wand->wand.images == (Image *)NULL )
5081 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5082 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5083 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5085 /* Operators which loop of individual images, simply */
5086 if ( (option_type & SimpleOperatorFlag) != 0 &&
5087 cli_wand->wand.images != (Image *)NULL) /* temp hack */
5089 ExceptionInfo *exception=AcquireExceptionInfo();
5090 CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5091 exception=DestroyExceptionInfo(exception);
5094 /* Operators that work on the image list as a whole */
5095 if ( (option_type & ListOperatorFlag) != 0 )
5096 CLIListOperatorImages(cli_wand, option, arg1, arg2);
5098 DisableMSCWarning(4127)
5099 } while (0); /* end Break code block */
5102 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */