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-2013 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/wand.h"
54 #include "MagickWand/wandcli.h"
55 #include "MagickWand/wandcli-private.h"
56 #include "MagickWand/operation.h"
57 #include "MagickCore/monitor-private.h"
58 #include "MagickCore/thread-private.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/pixel-private.h"
65 #define USE_WAND_METHODS 1
66 #define MAX_STACK_DEPTH 32
67 #define UNDEFINED_COMPRESSION_QUALITY 0UL
69 /* FUTURE: why is this default so specific? */
70 #define DEFAULT_DISSIMILARITY_THRESHOLD "0.31830988618379067154"
73 Constant declaration. (temporary exports)
76 BackgroundColor[] = "#fff", /* white */
77 BorderColor[] = "#dfdfdf", /* sRGB gray */
78 MatteColor[] = "#bdbdbd"; /* slightly darker gray */
80 /* For Debugging Geometry Input */
81 #define ReportGeometry(flags,info) \
82 (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", \
83 flags, info.rho, info.sigma, info.xi, info.psi )
86 ** Function to report on the progress of image operations
88 static MagickBooleanType MonitorProgress(const char *text,
89 const MagickOffsetType offset,const MagickSizeType extent,
90 void *wand_unused(cli_wandent_data))
93 message[MaxTextExtent],
104 (void) CopyMagickMemory(tag,text,MaxTextExtent);
106 if (p != (char *) NULL)
108 (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
109 locale_message=GetLocaleMessage(message);
110 if (locale_message == message)
112 if (p == (char *) NULL)
113 (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
114 locale_message,(long) offset,(unsigned long) extent,(long)
115 (100L*offset/(extent-1)));
117 (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
118 locale_message,p+1,(long) offset,(unsigned long) extent,(long)
119 (100L*offset/(extent-1)));
120 if (offset == (MagickOffsetType) (extent-1))
121 (void) FormatLocaleFile(stderr,"\n");
122 (void) fflush(stderr);
127 ** GetImageCache() will read an image into a image cache if not already
128 ** present then return the image that is in the cache under that filename.
130 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
131 ExceptionInfo *exception)
145 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
146 sans_exception=AcquireExceptionInfo();
147 image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
148 sans_exception=DestroyExceptionInfo(sans_exception);
149 if (image != (Image *) NULL)
151 read_info=CloneImageInfo(image_info);
152 (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
153 image=ReadImage(read_info,exception);
154 read_info=DestroyImageInfo(read_info);
155 if (image != (Image *) NULL)
156 (void) SetImageRegistry(ImageRegistryType,key,image,exception);
161 SparseColorOption() parse the complex -sparse-color argument into an
162 an array of floating point values than call SparseColorImage().
163 Argument is a complex mix of floating-point pixel coodinates, and color
164 specifications (or direct floating point numbers). The number of floats
165 needed to represent a color varies depending on teh current channel
168 This really should be in MagickCore, so that other API's can make use of it.
170 static Image *SparseColorOption(const Image *image,
171 const SparseColorMethod method,const char *arguments,ExceptionInfo *exception)
174 token[MaxTextExtent];
198 assert(image != (Image *) NULL);
199 assert(image->signature == MagickSignature);
200 if (IfMagickTrue(image->debug))
201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
202 assert(exception != (ExceptionInfo *) NULL);
203 assert(exception->signature == MagickSignature);
205 Limit channels according to image
206 add up number of values needed per color.
209 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
211 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
213 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
215 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
216 (image->colorspace == CMYKColorspace))
218 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
219 image->alpha_trait == BlendPixelTrait)
223 Read string, to determine number of arguments needed,
229 GetMagickToken(p,&p,token);
230 if ( token[0] == ',' ) continue;
231 if ( isalpha((int) token[0]) || token[0] == '#' )
232 x += number_colors; /* color argument found */
234 x++; /* floating point argument */
236 /* control points and color values */
237 error = IsMagickTrue( x % (2+number_colors) );
239 if ( IfMagickTrue(error) ) {
240 (void) ThrowMagickException(exception,GetMagickModule(),
241 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
242 "Invalid number of Arguments");
243 return( (Image *)NULL);
246 /* Allocate and fill in the floating point arguments */
247 sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
248 sizeof(*sparse_arguments));
249 if (sparse_arguments == (double *) NULL) {
250 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
251 "MemoryAllocationFailed","%s","SparseColorOption");
252 return( (Image *)NULL);
254 (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
255 sizeof(*sparse_arguments));
258 while( *p != '\0' && x < number_arguments ) {
260 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
261 if ( token[0] == '\0' ) break;
262 if ( isalpha((int) token[0]) || token[0] == '#' ) {
263 (void) ThrowMagickException(exception,GetMagickModule(),
264 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
265 "Color found, instead of X-coord");
269 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
271 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
272 if ( token[0] == '\0' ) break;
273 if ( isalpha((int) token[0]) || token[0] == '#' ) {
274 (void) ThrowMagickException(exception,GetMagickModule(),
275 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
276 "Color found, instead of Y-coord");
280 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
281 /* color name or function given in string argument */
282 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
283 if ( token[0] == '\0' ) break;
284 if ( isalpha((int) token[0]) || token[0] == '#' ) {
285 /* Color string given */
286 (void) QueryColorCompliance(token,AllCompliance,&color,
288 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
289 sparse_arguments[x++] = QuantumScale*color.red;
290 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
291 sparse_arguments[x++] = QuantumScale*color.green;
292 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
293 sparse_arguments[x++] = QuantumScale*color.blue;
294 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
295 (image->colorspace == CMYKColorspace))
296 sparse_arguments[x++] = QuantumScale*color.black;
297 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
298 image->alpha_trait == BlendPixelTrait)
299 sparse_arguments[x++] = QuantumScale*color.alpha;
302 /* Colors given as a set of floating point values - experimental */
303 /* NB: token contains the first floating point value to use! */
304 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
306 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
307 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
309 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
310 token[0] = ','; /* used this token - get another */
312 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
314 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
315 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
317 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
318 token[0] = ','; /* used this token - get another */
320 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
322 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
323 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
325 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
326 token[0] = ','; /* used this token - get another */
328 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
329 (image->colorspace == CMYKColorspace))
331 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
332 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
334 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
335 token[0] = ','; /* used this token - get another */
337 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
338 image->alpha_trait == BlendPixelTrait)
340 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
341 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
343 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
344 token[0] = ','; /* used this token - get another */
348 if ( number_arguments != x && !error ) {
349 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
350 "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
351 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
352 return( (Image *)NULL);
355 return( (Image *)NULL);
357 /* Call the Sparse Color Interpolation function with the parsed arguments */
358 sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
360 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
361 return( sparse_image );
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369 % C L I S e t t i n g O p t i o n I n f o %
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 % CLISettingOptionInfo() applies a single settings option into a CLI wand
376 % holding the image_info, draw_info, quantize_info structures that will be
377 % used when processing the images.
379 % These options do no require images to be present in the CLI wand for them
380 % to be able to be set, in which case they will generally be applied to image
381 % that are read in later
383 % Options handled by this function are listed in CommandOptions[] of
384 % "option.c" that is one of "SettingOptionFlags" option flags.
386 % The format of the CLISettingOptionInfo method is:
388 % void CLISettingOptionInfo(MagickCLI *cli_wand,
389 % const char *option, const char *arg1, const char *arg2)
391 % A description of each parameter follows:
393 % o cli_wand: structure holding settings to be applied
395 % o option: The option string to be set
397 % o arg1, arg2: optional argument strings to the operation
398 % arg2 is currently only used by "-limit"
401 WandPrivate void CLISettingOptionInfo(MagickCLI *cli_wand,
402 const char *option,const char *arg1, const char *arg2)
405 parse; /* option argument parsing (string to value table lookup) */
407 assert(cli_wand != (MagickCLI *) NULL);
408 assert(cli_wand->signature == WandSignature);
409 assert(cli_wand->wand.signature == WandSignature);
410 if (IfMagickTrue(cli_wand->wand.debug))
411 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
413 #define _image_info (cli_wand->wand.image_info)
414 #define _exception (cli_wand->wand.exception)
415 #define _draw_info (cli_wand->draw_info)
416 #define _quantize_info (cli_wand->quantize_info)
417 #define IfSetOption (*option=='-')
418 #define ArgBoolean IsMagickTrue(IfSetOption)
419 #define ArgBooleanNot IsMagickFalse(IfSetOption)
420 #define ArgBooleanString (IfSetOption?"true":"false")
421 #define ArgOption(def) (IfSetOption?arg1:(const char *)(def))
424 Setting are not directly involved with images, so can not
425 interpret Percent Escapes in Arguments, At least not yet */
427 #define _process_flags (cli_wand->process_flags)
428 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
429 /* Interpret Percent Escapes in Arguments - using first image */
432 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
433 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
434 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
435 /* Interpret Percent escapes in argument 1 */
436 if (arg1n != (char *) NULL) {
437 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
438 if (arg1 == (char *) NULL) {
439 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
440 arg1=arg1n; /* use the given argument as is */
443 if (arg2n != (char *) NULL) {
444 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
445 if (arg2 == (char *) NULL) {
446 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
447 arg2=arg2n; /* use the given argument as is */
451 #undef _process_flags
459 if (LocaleCompare("adjoin",option+1) == 0)
461 _image_info->adjoin = ArgBoolean;
464 if (LocaleCompare("affine",option+1) == 0)
466 CLIWandWarnReplaced("-draw 'affine ...'");
468 (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception);
470 GetAffineMatrix(&_draw_info->affine);
473 if (LocaleCompare("antialias",option+1) == 0)
475 _image_info->antialias =
476 _draw_info->stroke_antialias =
477 _draw_info->text_antialias = ArgBoolean;
480 if (LocaleCompare("attenuate",option+1) == 0)
482 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
483 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
484 (void) SetImageOption(_image_info,option+1,ArgOption("1.0"));
487 if (LocaleCompare("authenticate",option+1) == 0)
489 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
492 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
496 if (LocaleCompare("background",option+1) == 0)
498 /* FUTURE: both _image_info attribute & ImageOption in use!
499 _image_info only used directly for generating new images.
500 SyncImageSettings() used to set per-image attribute.
502 FUTURE: if _image_info->background_color is not set then
503 we should fall back to per-image background_color
505 At this time -background will 'wipe out' the per-image
508 Better error handling of QueryColorCompliance() needed.
510 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
511 (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance,
512 &_image_info->background_color,_exception);
515 if (LocaleCompare("bias",option+1) == 0)
517 /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias"
518 as it is actually rarely used except in direct convolve operations
519 Usage outside a direct convolve operation is actally non-sensible!
521 SyncImageSettings() used to set per-image attribute.
523 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
524 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
525 (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL));
528 if (LocaleCompare("black-point-compensation",option+1) == 0)
530 /* Used as a image chromaticity setting
531 SyncImageSettings() used to set per-image attribute.
533 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
536 if (LocaleCompare("blue-primary",option+1) == 0)
538 /* Image chromaticity X,Y NB: Y=X if Y not defined
539 Used by many coders including PNG
540 SyncImageSettings() used to set per-image attribute.
542 arg1=ArgOption("0.0");
543 if (IfMagickFalse(IsGeometry(arg1)))
544 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
545 (void) SetImageOption(_image_info,option+1,arg1);
548 if (LocaleCompare("bordercolor",option+1) == 0)
550 /* FUTURE: both _image_info attribute & ImageOption in use!
551 SyncImageSettings() used to set per-image attribute.
552 Better error checking of QueryColorCompliance().
556 (void) SetImageOption(_image_info,option+1,arg1);
557 (void) QueryColorCompliance(arg1,AllCompliance,
558 &_image_info->border_color,_exception);
559 (void) QueryColorCompliance(arg1,AllCompliance,
560 &_draw_info->border_color,_exception);
563 (void) DeleteImageOption(_image_info,option+1);
564 (void) QueryColorCompliance(BorderColor,AllCompliance,
565 &_image_info->border_color,_exception);
566 (void) QueryColorCompliance(BorderColor,AllCompliance,
567 &_draw_info->border_color,_exception);
570 if (LocaleCompare("box",option+1) == 0)
572 CLIWandWarnReplaced("-undercolor");
573 CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2);
576 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
580 if (LocaleCompare("cache",option+1) == 0)
585 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
586 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
587 limit=MagickResourceInfinity;
588 if (LocaleCompare("unlimited",arg1) != 0)
589 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0);
590 (void) SetMagickResourceLimit(MemoryResource,limit);
591 (void) SetMagickResourceLimit(MapResource,2*limit);
594 if (LocaleCompare("caption",option+1) == 0)
596 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
599 if (LocaleCompare("channel",option+1) == 0)
601 arg1=ArgOption("default");
602 parse=ParseChannelOption(arg1);
604 CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",
606 _image_info->channel=(ChannelType) parse;
607 (void) SetImageOption(_image_info,option+1,arg1);
610 if (LocaleCompare("colorspace",option+1) == 0)
612 /* Setting used for new images via AquireImage()
613 But also used as a SimpleImageOperator
614 Undefined colorspace means don't modify images on
615 read or as a operation */
616 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
617 ArgOption("undefined"));
619 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
621 _image_info->colorspace=(ColorspaceType) parse;
624 if (LocaleCompare("comment",option+1) == 0)
626 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
629 if (LocaleCompare("compose",option+1) == 0)
631 /* FUTURE: _image_info should be used,
632 SyncImageSettings() used to set per-image attribute. - REMOVE
634 This setting should NOT be used to set image 'compose'
635 "-layer" operators shoud use _image_info if defined otherwise
636 they should use a per-image compose setting.
638 parse = ParseCommandOption(MagickComposeOptions,MagickFalse,
639 ArgOption("undefined"));
641 CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator",
643 _image_info->compose=(CompositeOperator) parse;
644 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
647 if (LocaleCompare("compress",option+1) == 0)
649 /* FUTURE: What should be used? _image_info or ImageOption ???
650 The former is more efficent, but Crisy prefers the latter!
651 SyncImageSettings() used to set per-image attribute.
653 The coders appears to use _image_info, not Image_Option
654 however the image attribute (for save) is set from the
657 Note that "undefined" is a different setting to "none".
659 parse = ParseCommandOption(MagickCompressOptions,MagickFalse,
660 ArgOption("undefined"));
662 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression",
664 _image_info->compression=(CompressionType) parse;
665 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
668 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
672 if (LocaleCompare("debug",option+1) == 0)
674 /* SyncImageSettings() used to set per-image attribute. */
675 arg1=ArgOption("none");
676 parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1);
678 CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType",
680 (void) SetLogEventMask(arg1);
681 _image_info->debug=IsEventLogging(); /* extract logging*/
682 cli_wand->wand.debug=IsEventLogging();
685 if (LocaleCompare("define",option+1) == 0)
687 if (LocaleNCompare(arg1,"registry:",9) == 0)
690 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception);
692 (void) DeleteImageRegistry(arg1+9);
695 /* DefineImageOption() equals SetImageOption() but with '=' */
697 (void) DefineImageOption(_image_info,arg1);
698 else if (IsMagickFalse(DeleteImageOption(_image_info,arg1)))
699 CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1);
702 if (LocaleCompare("delay",option+1) == 0)
704 /* Only used for new images via AcquireImage()
705 FUTURE: Option should also be used for "-morph" (color morphing)
708 if (IfMagickFalse(IsGeometry(arg1)))
709 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
710 (void) SetImageOption(_image_info,option+1,arg1);
713 if (LocaleCompare("density",option+1) == 0)
715 /* FUTURE: strings used in _image_info attr and _draw_info!
716 Basically as density can be in a XxY form!
718 SyncImageSettings() used to set per-image attribute.
720 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
721 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
722 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
723 (void) CloneString(&_image_info->density,ArgOption(NULL));
724 (void) CloneString(&_draw_info->density,_image_info->density);
727 if (LocaleCompare("depth",option+1) == 0)
729 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
730 SyncImageSettings() used to set per-image attribute.
732 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
733 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
734 _image_info->depth=IfSetOption?StringToUnsignedLong(arg1)
735 :MAGICKCORE_QUANTUM_DEPTH;
738 if (LocaleCompare("direction",option+1) == 0)
740 /* Image Option is only used to set _draw_info */
741 arg1=ArgOption("undefined");
742 parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1);
744 CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType",
746 _draw_info->direction=(DirectionType) parse;
747 (void) SetImageOption(_image_info,option+1,arg1);
750 if (LocaleCompare("display",option+1) == 0)
752 (void) CloneString(&_image_info->server_name,ArgOption(NULL));
753 (void) CloneString(&_draw_info->server_name,_image_info->server_name);
756 if (LocaleCompare("dispose",option+1) == 0)
758 /* only used in setting new images */
759 arg1=ArgOption("undefined");
760 parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1);
762 CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod",
764 (void) SetImageOption(_image_info,option+1,ArgOption("undefined"));
767 if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
769 /* FUTURE: this is only used by CompareImages() which is used
770 only by the "compare" CLI program at this time. */
771 arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD);
772 if (IfMagickFalse(IsGeometry(arg1)))
773 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
774 (void) SetImageOption(_image_info,option+1,arg1);
777 if (LocaleCompare("dither",option+1) == 0)
779 /* _image_info attr (on/off), _quantize_info attr (on/off)
780 but also ImageInfo and _quantize_info method!
781 FUTURE: merge the duality of the dithering options
783 _image_info->dither = ArgBoolean;
784 (void) SetImageOption(_image_info,option+1,ArgOption("none"));
785 _quantize_info->dither_method=(DitherMethod) ParseCommandOption(
786 MagickDitherOptions,MagickFalse,ArgOption("none"));
787 if (_quantize_info->dither_method == NoDitherMethod)
788 _image_info->dither = MagickFalse;
791 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
795 if (LocaleCompare("encoding",option+1) == 0)
797 (void) CloneString(&_draw_info->encoding,ArgOption("undefined"));
798 (void) SetImageOption(_image_info,option+1,_draw_info->encoding);
801 if (LocaleCompare("endian",option+1) == 0)
803 /* Both _image_info attr and ImageInfo */
804 arg1 = ArgOption("undefined");
805 parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1);
807 CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType",
809 /* FUTURE: check alloc/free of endian string! - remove? */
810 _image_info->endian=(EndianType) (*arg1);
811 (void) SetImageOption(_image_info,option+1,arg1);
814 if (LocaleCompare("extract",option+1) == 0)
816 (void) CloneString(&_image_info->extract,ArgOption(NULL));
819 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
823 if (LocaleCompare("family",option+1) == 0)
825 (void) CloneString(&_draw_info->family,ArgOption(NULL));
828 if (LocaleCompare("fill",option+1) == 0)
830 /* Set "fill" OR "fill-pattern" in _draw_info
831 The original fill color is preserved if a fill-pattern is given.
832 That way it does not effect other operations that directly using
833 the fill color and, can be retored using "+tile".
844 arg1 = ArgOption("none"); /* +fill turns it off! */
845 (void) SetImageOption(_image_info,option+1,arg1);
846 if (_draw_info->fill_pattern != (Image *) NULL)
847 _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern);
849 /* is it a color or a image? -- ignore exceptions */
850 sans=AcquireExceptionInfo();
851 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
852 sans=DestroyExceptionInfo(sans);
854 if (IfMagickFalse(status))
855 _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception);
857 _draw_info->fill=color;
860 if (LocaleCompare("filter",option+1) == 0)
862 /* SyncImageSettings() used to set per-image attribute. */
863 arg1 = ArgOption("undefined");
864 parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1);
866 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter",
868 (void) SetImageOption(_image_info,option+1,arg1);
871 if (LocaleCompare("font",option+1) == 0)
873 (void) CloneString(&_draw_info->font,ArgOption(NULL));
874 (void) CloneString(&_image_info->font,_draw_info->font);
877 if (LocaleCompare("format",option+1) == 0)
879 /* FUTURE: why the ping test, you could set ping after this! */
884 for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
885 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
886 _image_info->ping=MagickFalse;
888 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
891 if (LocaleCompare("fuzz",option+1) == 0)
893 /* Option used to set image fuzz! unless blank canvas (from color)
894 Image attribute used for color compare operations
895 SyncImageSettings() used to set per-image attribute.
897 FUTURE: Can't find anything else using _image_info->fuzz directly!
898 remove direct sttribute from image_info
901 if (IfMagickFalse(IsGeometry(arg1)))
902 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
903 _image_info->fuzz=StringToDoubleInterval(arg1,(double)
905 (void) SetImageOption(_image_info,option+1,arg1);
908 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
912 if (LocaleCompare("gravity",option+1) == 0)
914 /* SyncImageSettings() used to set per-image attribute. */
915 arg1 = ArgOption("none");
916 parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1);
918 CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType",
920 _draw_info->gravity=(GravityType) parse;
921 (void) SetImageOption(_image_info,option+1,arg1);
924 if (LocaleCompare("green-primary",option+1) == 0)
926 /* Image chromaticity X,Y NB: Y=X if Y not defined
927 SyncImageSettings() used to set per-image attribute.
928 Used directly by many coders
930 arg1=ArgOption("0.0");
931 if (IfMagickFalse(IsGeometry(arg1)))
932 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
933 (void) SetImageOption(_image_info,option+1,arg1);
936 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
940 if (LocaleCompare("highlight-color",option+1) == 0)
942 /* FUTURE: this is only used by CompareImages() which is used
943 only by the "compare" CLI program at this time. */
944 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
947 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
951 if (LocaleCompare("intensity",option+1) == 0)
953 arg1 = ArgOption("undefined");
954 parse = ParseCommandOption(MagickPixelIntensityOptions,MagickFalse,
957 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityType",
959 (void) SetImageOption(_image_info,option+1,arg1);
962 if (LocaleCompare("intent",option+1) == 0)
964 /* Only used by coders: MIFF, MPC, BMP, PNG
965 and for image profile call to AcquireTransformThreadSet()
966 SyncImageSettings() used to set per-image attribute.
968 arg1 = ArgOption("undefined");
969 parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1);
971 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType",
973 (void) SetImageOption(_image_info,option+1,arg1);
976 if (LocaleCompare("interlace",option+1) == 0)
978 /* _image_info is directly used by coders (so why an image setting?)
979 SyncImageSettings() used to set per-image attribute.
981 arg1 = ArgOption("undefined");
982 parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1);
984 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType",
986 _image_info->interlace=(InterlaceType) parse;
987 (void) SetImageOption(_image_info,option+1,arg1);
990 if (LocaleCompare("interline-spacing",option+1) == 0)
992 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
993 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
994 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
995 _draw_info->interline_spacing=StringToDouble(ArgOption("0"),
999 if (LocaleCompare("interpolate",option+1) == 0)
1001 /* SyncImageSettings() used to set per-image attribute. */
1002 arg1 = ArgOption("undefined");
1003 parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1);
1005 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod",
1007 (void) SetImageOption(_image_info,option+1,arg1);
1010 if (LocaleCompare("interword-spacing",option+1) == 0)
1012 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1013 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1014 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1015 _draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
1018 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1022 if (LocaleCompare("kerning",option+1) == 0)
1024 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1025 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1026 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1027 _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
1030 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1034 if (LocaleCompare("label",option+1) == 0)
1036 /* only used for new images - not in SyncImageOptions() */
1037 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1040 if (LocaleCompare("limit",option+1) == 0)
1045 limit=MagickResourceInfinity;
1046 parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1);
1048 CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType",
1050 if (LocaleCompare("unlimited",arg2) != 0)
1051 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
1052 (void) SetMagickResourceLimit((ResourceType)parse,limit);
1055 if (LocaleCompare("log",option+1) == 0)
1058 if ((strchr(arg1,'%') == (char *) NULL))
1059 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1060 (void) SetLogFormat(arg1);
1064 if (LocaleCompare("lowlight-color",option+1) == 0)
1066 /* FUTURE: this is only used by CompareImages() which is used
1067 only by the "compare" CLI program at this time. */
1068 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1071 if (LocaleCompare("loop",option+1) == 0)
1073 /* SyncImageSettings() used to set per-image attribute. */
1074 arg1=ArgOption("0");
1075 if (IfMagickFalse(IsGeometry(arg1)))
1076 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1077 (void) SetImageOption(_image_info,option+1,arg1);
1080 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1084 if (LocaleCompare("mattecolor",option+1) == 0)
1086 /* SyncImageSettings() used to set per-image attribute. */
1087 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1088 (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance,
1089 &_image_info->matte_color,_exception);
1092 if (LocaleCompare("metric",option+1) == 0)
1094 /* FUTURE: this is only used by CompareImages() which is used
1095 only by the "compare" CLI program at this time. */
1096 parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1);
1098 CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType",
1100 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1103 if (LocaleCompare("monitor",option+1) == 0)
1105 (void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
1106 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1109 if (LocaleCompare("monochrome",option+1) == 0)
1111 /* Setting (used by some input coders!) -- why?
1112 Warning: This is also Special '-type' SimpleOperator
1114 _image_info->monochrome= ArgBoolean;
1117 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1121 if (LocaleCompare("orient",option+1) == 0)
1123 /* Is not used when defining for new images.
1124 This makes it more of a 'operation' than a setting
1125 FUTURE: make set meta-data operator instead.
1126 SyncImageSettings() used to set per-image attribute.
1128 parse=ParseCommandOption(MagickOrientationOptions,MagickFalse,
1129 ArgOption("undefined"));
1131 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation",
1133 _image_info->orientation=(OrientationType)parse;
1134 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1137 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1141 if (LocaleCompare("page",option+1) == 0)
1143 /* Only used for new images and image generators.
1144 SyncImageSettings() used to set per-image attribute. ?????
1145 That last is WRONG!!!!
1146 FUTURE: adjust named 'page' sizes according density
1150 page[MaxTextExtent];
1163 (void) DeleteImageOption(_image_info,option+1);
1164 (void) CloneString(&_image_info->page,(char *) NULL);
1167 (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1168 image_option=GetImageOption(_image_info,"page");
1169 if (image_option != (const char *) NULL)
1170 flags=ParseAbsoluteGeometry(image_option,&geometry);
1171 canonical_page=GetPageGeometry(arg1);
1172 flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1173 canonical_page=DestroyString(canonical_page);
1174 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1175 (unsigned long) geometry.width,(unsigned long) geometry.height);
1176 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1177 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1178 (unsigned long) geometry.width,(unsigned long) geometry.height,
1179 (long) geometry.x,(long) geometry.y);
1180 (void) SetImageOption(_image_info,option+1,page);
1181 (void) CloneString(&_image_info->page,page);
1184 if (LocaleCompare("ping",option+1) == 0)
1186 _image_info->ping = ArgBoolean;
1189 if (LocaleCompare("pointsize",option+1) == 0)
1192 if (IfMagickFalse(IsGeometry(arg1)))
1193 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1194 _image_info->pointsize =
1195 _draw_info->pointsize =
1196 StringToDouble(arg1,(char **) NULL);
1199 _image_info->pointsize=0.0; /* unset pointsize */
1200 _draw_info->pointsize=12.0;
1204 if (LocaleCompare("precision",option+1) == 0)
1206 arg1=ArgOption("-1");
1207 if (IfMagickFalse(IsGeometry(arg1)))
1208 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1209 (void) SetMagickPrecision(StringToInteger(arg1));
1212 /* FUTURE: Only the 'preview' coder appears to use this
1213 * DEPRECIATE the coder? Leaving only the 'preview' operator.
1214 if (LocaleCompare("preview",option+1) == 0)
1216 _image_info->preview_type=UndefinedPreview;
1218 _image_info->preview_type=(PreviewType) ParseCommandOption(
1219 MagickPreviewOptions,MagickFalse,arg1);
1223 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1227 if (LocaleCompare("quality",option+1) == 0)
1229 if (IfMagickFalse(IsGeometry(arg1)))
1230 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1231 _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1)
1232 : UNDEFINED_COMPRESSION_QUALITY;
1233 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1236 if (LocaleCompare("quantize",option+1) == 0)
1238 /* Just a set direct in _quantize_info */
1239 arg1=ArgOption("undefined");
1240 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
1242 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
1244 _quantize_info->colorspace=(ColorspaceType)parse;
1247 if (LocaleCompare("quiet",option+1) == 0)
1249 /* FUTURE: if two -quiet is performed you can not do +quiet!
1250 This needs to be checked over thoughly.
1252 static WarningHandler
1253 warning_handler = (WarningHandler) NULL;
1256 tmp = SetWarningHandler((WarningHandler) NULL);
1258 if ( tmp != (WarningHandler) NULL)
1259 warning_handler = tmp; /* remember the old handler */
1260 if (!IfSetOption) /* set the old handler */
1261 warning_handler=SetWarningHandler(warning_handler);
1264 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1268 if (LocaleCompare("red-primary",option+1) == 0)
1270 /* Image chromaticity X,Y NB: Y=X if Y not defined
1272 SyncImageSettings() used to set per-image attribute.
1274 arg1=ArgOption("0.0");
1275 if (IfMagickFalse(IsGeometry(arg1)))
1276 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1277 (void) SetImageOption(_image_info,option+1,arg1);
1280 if (LocaleCompare("regard-warnings",option+1) == 0)
1281 /* FUTURE: to be replaced by a 'fatal-level' type setting */
1283 if (LocaleCompare("render",option+1) == 0)
1285 /* _draw_info only setting */
1286 _draw_info->render= ArgBooleanNot;
1289 if (LocaleCompare("respect-parenthesis",option+1) == 0)
1291 /* link image and setting stacks - option is itself saved on stack! */
1292 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1295 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1299 if (LocaleCompare("sampling-factor",option+1) == 0)
1301 /* FUTURE: should be converted to jpeg:sampling_factor */
1302 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1303 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1304 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1307 if (LocaleCompare("scene",option+1) == 0)
1309 /* SyncImageSettings() used to set this as a per-image attribute.
1312 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1313 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1314 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1315 _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1318 if (LocaleCompare("seed",option+1) == 0)
1320 if (IfMagickFalse(IsGeometry(arg1)))
1321 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1323 IfSetOption ? (unsigned long) StringToUnsignedLong(arg1)
1324 : (unsigned long) time((time_t *) NULL) );
1327 if (LocaleCompare("size",option+1) == 0)
1329 /* FUTURE: string in _image_info -- convert to Option ???
1330 Look at the special handling for "size" in SetImageOption()
1332 (void) CloneString(&_image_info->size,ArgOption(NULL));
1335 if (LocaleCompare("stretch",option+1) == 0)
1337 arg1=ArgOption("undefined");
1338 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1340 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1342 _draw_info->stretch=(StretchType) parse;
1345 if (LocaleCompare("stroke",option+1) == 0)
1347 /* set stroke color OR stroke-pattern
1348 UPDATE: ensure stroke color is not destroyed is a pattern
1349 is given. Just in case the color is also used for other purposes.
1360 arg1 = ArgOption("none"); /* +fill turns it off! */
1361 (void) SetImageOption(_image_info,option+1,arg1);
1362 if (_draw_info->stroke_pattern != (Image *) NULL)
1363 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1365 /* is it a color or a image? -- ignore exceptions */
1366 sans=AcquireExceptionInfo();
1367 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1368 sans=DestroyExceptionInfo(sans);
1370 if (IfMagickFalse(status))
1371 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1373 _draw_info->stroke=color;
1376 if (LocaleCompare("strokewidth",option+1) == 0)
1378 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1379 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1380 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1381 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1385 if (LocaleCompare("style",option+1) == 0)
1387 arg1=ArgOption("undefined");
1388 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1390 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1392 _draw_info->style=(StyleType) parse;
1396 if (LocaleCompare("subimage-search",option+1) == 0)
1398 /* FUTURE: this is only used by CompareImages() which is used
1399 only by the "compare" CLI program at this time. */
1400 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1404 if (LocaleCompare("synchronize",option+1) == 0)
1406 /* FUTURE: syncronize to storage - but what does that mean? */
1407 _image_info->synchronize = ArgBoolean;
1410 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1414 if (LocaleCompare("taint",option+1) == 0)
1416 /* SyncImageSettings() used to set per-image attribute. */
1417 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1420 if (LocaleCompare("texture",option+1) == 0)
1422 /* Note: arguments do not have percent escapes expanded */
1423 /* FUTURE: move _image_info string to option splay-tree
1424 Other than "montage" what uses "texture" ????
1426 (void) CloneString(&_image_info->texture,ArgOption(NULL));
1429 if (LocaleCompare("tile",option+1) == 0)
1431 /* Note: arguments do not have percent escapes expanded */
1432 _draw_info->fill_pattern=IfSetOption
1433 ?GetImageCache(_image_info,arg1,_exception)
1434 :DestroyImage(_draw_info->fill_pattern);
1437 if (LocaleCompare("tile-offset",option+1) == 0)
1439 /* SyncImageSettings() used to set per-image attribute. ??? */
1440 arg1=ArgOption("0");
1441 if (IfMagickFalse(IsGeometry(arg1)))
1442 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1443 (void) SetImageOption(_image_info,option+1,arg1);
1446 if (LocaleCompare("transparent-color",option+1) == 0)
1448 /* FUTURE: both _image_info attribute & ImageOption in use!
1449 _image_info only used for generating new images.
1450 SyncImageSettings() used to set per-image attribute.
1452 Note that +transparent-color, means fall-back to image
1453 attribute so ImageOption is deleted, not set to a default.
1455 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1456 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1457 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1458 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1459 &_image_info->transparent_color,_exception);
1462 if (LocaleCompare("treedepth",option+1) == 0)
1464 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1465 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1468 if (LocaleCompare("type",option+1) == 0)
1470 /* SyncImageSettings() used to set per-image attribute. */
1471 parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1472 ArgOption("undefined"));
1474 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1476 _image_info->type=(ImageType) parse;
1477 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1480 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1484 if (LocaleCompare("undercolor",option+1) == 0)
1486 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1487 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1488 &_draw_info->undercolor,_exception);
1491 if (LocaleCompare("units",option+1) == 0)
1493 /* SyncImageSettings() used to set per-image attribute.
1494 Should this effect _draw_info X and Y resolution?
1495 FUTURE: this probably should be part of the density setting
1497 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1498 ArgOption("undefined"));
1500 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1502 _image_info->units=(ResolutionType) parse;
1503 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1506 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1510 if (LocaleCompare("verbose",option+1) == 0)
1512 /* FUTURE: Remember all options become image artifacts
1513 _image_info->verbose is only used by coders.
1515 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1516 _image_info->verbose= ArgBoolean;
1517 _image_info->ping=MagickFalse; /* verbose can't be a ping */
1520 if (LocaleCompare("view",option+1) == 0)
1522 /* FUTURE: Convert from _image_info to ImageOption
1523 Only used by coder FPX
1524 And it only tests existance, not its content!
1526 (void) CloneString(&_image_info->view,ArgOption(NULL));
1529 if (LocaleCompare("virtual-pixel",option+1) == 0)
1531 /* SyncImageSettings() used to set per-image attribute.
1532 This is VERY deep in the image caching structure.
1534 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1535 ArgOption("undefined"));
1537 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1539 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1542 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1546 if (LocaleCompare("weight",option+1) == 0)
1548 /* Just what does using a font 'weight' do ???
1549 There is no "-list weight" output (reference manual says there is)
1551 arg1=ArgOption("all");
1552 _draw_info->weight=StringToUnsignedLong(arg1);
1553 if (LocaleCompare(arg1,"all") == 0)
1554 _draw_info->weight=0;
1555 if (LocaleCompare(arg1,"bold") == 0)
1556 _draw_info->weight=700;
1557 if (LocaleCompare(arg1,"bolder") == 0)
1558 if (_draw_info->weight <= 800)
1559 _draw_info->weight+=100;
1560 if (LocaleCompare(arg1,"lighter") == 0)
1561 if (_draw_info->weight >= 100)
1562 _draw_info->weight-=100;
1563 if (LocaleCompare(arg1,"normal") == 0)
1564 _draw_info->weight=400;
1567 if (LocaleCompare("white-point",option+1) == 0)
1569 /* Used as a image chromaticity setting
1570 SyncImageSettings() used to set per-image attribute.
1572 arg1=ArgOption("0.0");
1573 if (IfMagickFalse(IsGeometry(arg1)))
1574 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1575 (void) SetImageOption(_image_info,option+1,arg1);
1578 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1581 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1585 /* clean up percent escape interpreted strings */
1587 arg1=DestroyString((char *)arg1);
1589 arg2=DestroyString((char *)arg2);
1595 #undef _quantize_info
1598 #undef ArgBooleanNot
1599 #undef ArgBooleanString
1606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1610 + C L I S i m p l e O p e r a t o r I m a g e s %
1614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616 % CLISimpleOperatorImages() applys one simple image operation given to all
1617 % the images in the CLI wand, using any per-image or global settings that was
1618 % previously saved in the CLI wand.
1620 % It is assumed that any such settings are up-to-date.
1622 % The format of the WandSimpleOperatorImages method is:
1624 % void CLISimpleOperatorImages(MagickCLI *cli_wand,
1625 % const char *option, const char *arg1, const char *arg2)
1627 % A description of each parameter follows:
1629 % o cli_wand: structure holding settings and images to be operated on
1631 % o option: The option string for the operation
1633 % o arg1, arg2: optional argument strings to the operation
1638 CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1639 image operation to the current image pointed to by the CLI wand.
1641 The image in the list may be modified in three different ways...
1642 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1643 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1644 * one image replace by a list of images (-separate and -crop only!)
1646 In each case the result replaces the single original image in the list, as
1647 well as the pointer to the modified image (last image added if replaced by a
1648 list of images) is returned.
1650 As the image pointed to may be replaced, the first image in the list may
1651 also change. GetFirstImageInList() should be used by caller if they wish
1652 return the Image pointer to the first image in list.
1654 static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand,
1655 const char *option, const char *arg1n, const char *arg2n)
1672 const char /* For percent escape interpretImageProperties() */
1676 #define _image_info (cli_wand->wand.image_info)
1677 #define _image (cli_wand->wand.images)
1678 #define _exception (cli_wand->wand.exception)
1679 #define _draw_info (cli_wand->draw_info)
1680 #define _quantize_info (cli_wand->quantize_info)
1681 #define _process_flags (cli_wand->process_flags)
1682 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
1683 #define IfNormalOp (*option=='-')
1684 #define IfPlusOp (*option!='-')
1685 #define normal_op IsMagickTrue(IfNormalOp)
1686 #define plus_alt_op IsMagickFalse(IfNormalOp)
1688 assert(cli_wand != (MagickCLI *) NULL);
1689 assert(cli_wand->signature == WandSignature);
1690 assert(cli_wand->wand.signature == WandSignature);
1691 assert(_image != (Image *) NULL); /* an image must be present */
1692 if (IfMagickTrue(cli_wand->wand.debug))
1693 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1695 /* Interpret Percent Escapes in Arguments - using first image */
1698 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
1699 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1700 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1701 /* Interpret Percent escapes in argument 1 */
1702 if (arg1n != (char *) NULL) {
1703 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1704 if (arg1 == (char *) NULL) {
1705 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1706 arg1=arg1n; /* use the given argument as is */
1709 if (arg2n != (char *) NULL) {
1710 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1711 if (arg2 == (char *) NULL) {
1712 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1713 arg2=arg2n; /* use the given argument as is */
1717 #undef _process_flags
1721 (void) FormatLocaleFile(stderr,
1722 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1725 new_image = (Image *)NULL; /* the replacement image, if not null at end */
1726 SetGeometryInfo(&geometry_info);
1728 switch (*(option+1))
1732 if (LocaleCompare("adaptive-blur",option+1) == 0)
1734 flags=ParseGeometry(arg1,&geometry_info);
1735 if ((flags & (RhoValue|SigmaValue)) == 0)
1736 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1737 if ((flags & SigmaValue) == 0)
1738 geometry_info.sigma=1.0;
1739 new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1740 geometry_info.sigma,_exception);
1743 if (LocaleCompare("adaptive-resize",option+1) == 0)
1745 /* FUTURE: Roll into a resize special operator */
1746 if (IfMagickFalse(IsGeometry(arg1)))
1747 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1748 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1749 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1753 if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1755 flags=ParseGeometry(arg1,&geometry_info);
1756 if ((flags & (RhoValue|SigmaValue)) == 0)
1757 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1758 if ((flags & SigmaValue) == 0)
1759 geometry_info.sigma=1.0;
1760 new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1761 geometry_info.sigma,_exception);
1764 if (LocaleCompare("alpha",option+1) == 0)
1766 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1768 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1770 (void) SetImageAlphaChannel(_image,(AlphaChannelOption)parse,
1774 if (LocaleCompare("annotate",option+1) == 0)
1777 geometry[MaxTextExtent];
1779 SetGeometryInfo(&geometry_info);
1780 flags=ParseGeometry(arg1,&geometry_info);
1782 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1783 if ((flags & SigmaValue) == 0)
1784 geometry_info.sigma=geometry_info.rho;
1785 (void) CloneString(&_draw_info->text,arg2);
1786 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1787 geometry_info.xi,geometry_info.psi);
1788 (void) CloneString(&_draw_info->geometry,geometry);
1789 _draw_info->affine.sx=cos(DegreesToRadians(
1790 fmod(geometry_info.rho,360.0)));
1791 _draw_info->affine.rx=sin(DegreesToRadians(
1792 fmod(geometry_info.rho,360.0)));
1793 _draw_info->affine.ry=(-sin(DegreesToRadians(
1794 fmod(geometry_info.sigma,360.0))));
1795 _draw_info->affine.sy=cos(DegreesToRadians(
1796 fmod(geometry_info.sigma,360.0)));
1797 (void) AnnotateImage(_image,_draw_info,_exception);
1798 GetAffineMatrix(&_draw_info->affine);
1801 if (LocaleCompare("auto-gamma",option+1) == 0)
1803 (void) AutoGammaImage(_image,_exception);
1806 if (LocaleCompare("auto-level",option+1) == 0)
1808 (void) AutoLevelImage(_image,_exception);
1811 if (LocaleCompare("auto-orient",option+1) == 0)
1813 new_image=AutoOrientImage(_image,_image->orientation,_exception);
1816 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1820 if (LocaleCompare("black-threshold",option+1) == 0)
1822 if (IfMagickFalse(IsGeometry(arg1)))
1823 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1824 (void) BlackThresholdImage(_image,arg1,_exception);
1827 if (LocaleCompare("blue-shift",option+1) == 0)
1829 geometry_info.rho=1.5;
1831 flags=ParseGeometry(arg1,&geometry_info);
1832 if ((flags & RhoValue) == 0)
1833 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1835 new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1838 if (LocaleCompare("blur",option+1) == 0)
1840 flags=ParseGeometry(arg1,&geometry_info);
1841 if ((flags & (RhoValue|SigmaValue)) == 0)
1842 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1843 if ((flags & SigmaValue) == 0)
1844 geometry_info.sigma=1.0;
1845 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1849 if (LocaleCompare("border",option+1) == 0)
1857 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1858 if ((flags & (WidthValue | HeightValue)) == 0)
1859 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1860 compose=OverCompositeOp;
1861 value=GetImageOption(_image_info,"compose");
1862 if (value != (const char *) NULL)
1863 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1865 new_image=BorderImage(_image,&geometry,compose,_exception);
1868 if (LocaleCompare("brightness-contrast",option+1) == 0)
1880 flags=ParseGeometry(arg1,&geometry_info);
1881 if ((flags & RhoValue) == 0)
1882 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1883 brightness=geometry_info.rho;
1885 if ((flags & SigmaValue) != 0)
1886 contrast=geometry_info.sigma;
1887 (void) BrightnessContrastImage(_image,brightness,contrast,
1891 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1895 if (LocaleCompare("cdl",option+1) == 0)
1897 /* Note: arguments do not have percent escapes expanded */
1899 *color_correction_collection;
1902 Color correct with a color decision list.
1904 color_correction_collection=FileToString(arg1,~0,_exception);
1905 if (color_correction_collection == (char *) NULL)
1907 (void) ColorDecisionListImage(_image,color_correction_collection,
1911 if (LocaleCompare("charcoal",option+1) == 0)
1913 flags=ParseGeometry(arg1,&geometry_info);
1914 if ((flags & (RhoValue|SigmaValue)) == 0)
1915 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1916 if ((flags & SigmaValue) == 0)
1917 geometry_info.sigma=1.0;
1918 if ((flags & XiValue) == 0)
1919 geometry_info.xi=1.0;
1920 new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1924 if (LocaleCompare("chop",option+1) == 0)
1926 if (IfMagickFalse(IsGeometry(arg1)))
1927 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1928 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
1929 new_image=ChopImage(_image,&geometry,_exception);
1932 if (LocaleCompare("clamp",option+1) == 0)
1934 (void) ClampImage(_image,_exception);
1937 if (LocaleCompare("clip",option+1) == 0)
1940 (void) ClipImage(_image,_exception);
1941 else /* "+mask" remove the write mask */
1942 (void) SetImageMask(_image,(Image *) NULL,_exception);
1945 if (LocaleCompare("clip-mask",option+1) == 0)
1947 /* Note: arguments do not have percent escapes expanded */
1964 /* use "+clip-mask" Remove the write mask for -clip-path */
1965 (void) SetImageMask(_image,(Image *) NULL,_exception);
1968 mask_image=GetImageCache(_image_info,arg1,_exception);
1969 if (mask_image == (Image *) NULL)
1971 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
1973 /* Create a write mask from cli_wand mask image */
1974 /* FUTURE: use Alpha operations instead and create a Grey Image */
1975 mask_view=AcquireAuthenticCacheView(mask_image,_exception);
1976 for (y=0; y < (ssize_t) mask_image->rows; y++)
1978 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1980 if (q == (Quantum *) NULL)
1982 for (x=0; x < (ssize_t) mask_image->columns; x++)
1984 if (mask_image->alpha_trait != BlendPixelTrait)
1985 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
1986 SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
1987 q+=GetPixelChannels(mask_image);
1989 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
1992 /* clean up and set the write mask */
1993 mask_view=DestroyCacheView(mask_view);
1994 mask_image->alpha_trait=BlendPixelTrait;
1995 (void) SetImageColorspace(_image,GRAYColorspace,_exception);
1996 (void) SetImageMask(_image,mask_image,_exception);
1997 mask_image=DestroyImage(mask_image);
2000 if (LocaleCompare("clip-path",option+1) == 0)
2002 (void) ClipImagePath(_image,arg1,normal_op,_exception);
2003 /* Note: Use "+clip-mask" remove the write mask added */
2006 if (LocaleCompare("colorize",option+1) == 0)
2008 if (IfMagickFalse(IsGeometry(arg1)))
2009 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2010 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2013 if (LocaleCompare("color-matrix",option+1) == 0)
2018 kernel=AcquireKernelInfo(arg1);
2019 if (kernel == (KernelInfo *) NULL)
2020 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2021 new_image=ColorMatrixImage(_image,kernel,_exception);
2022 kernel=DestroyKernelInfo(kernel);
2025 if (LocaleCompare("colors",option+1) == 0)
2027 /* Reduce the number of colors in the image.
2028 FUTURE: also provide 'plus version with image 'color counts'
2030 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2031 if (_quantize_info->number_colors == 0)
2032 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2033 if ((_image->storage_class == DirectClass) ||
2034 _image->colors > _quantize_info->number_colors)
2035 (void) QuantizeImage(_quantize_info,_image,_exception);
2037 (void) CompressImageColormap(_image,_exception);
2040 if (LocaleCompare("colorspace",option+1) == 0)
2042 /* WARNING: this is both a image_info setting (already done)
2043 and a operator to change image colorspace.
2045 FUTURE: default colorspace should be sRGB!
2046 Unless some type of 'linear colorspace' mode is set.
2048 Note that +colorspace sets "undefined" or no effect on
2049 new images, but forces images already in memory back to RGB!
2050 That seems to be a little strange!
2052 (void) TransformImageColorspace(_image,
2053 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2057 if (LocaleCompare("contrast",option+1) == 0)
2059 CLIWandWarnReplaced(normal_op?"-level":"+level");
2060 (void) ContrastImage(_image,normal_op,_exception);
2063 if (LocaleCompare("contrast-stretch",option+1) == 0)
2072 flags=ParseGeometry(arg1,&geometry_info);
2073 if ((flags & RhoValue) == 0)
2074 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2075 black_point=geometry_info.rho;
2076 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2078 if ((flags & PercentValue) != 0) {
2079 black_point*=(double) _image->columns*_image->rows/100.0;
2080 white_point*=(double) _image->columns*_image->rows/100.0;
2082 white_point=(double) _image->columns*_image->rows-
2084 (void) ContrastStretchImage(_image,black_point,white_point,
2088 if (LocaleCompare("convolve",option+1) == 0)
2093 kernel_info=AcquireKernelInfo(arg1);
2094 if (kernel_info == (KernelInfo *) NULL)
2095 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2096 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2098 kernel_info=DestroyKernelInfo(kernel_info);
2101 if (LocaleCompare("crop",option+1) == 0)
2103 /* WARNING: This can generate multiple images! */
2104 if (IfMagickFalse(IsGeometry(arg1)))
2105 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2106 new_image=CropImageToTiles(_image,arg1,_exception);
2109 if (LocaleCompare("cycle",option+1) == 0)
2111 if (IfMagickFalse(IsGeometry(arg1)))
2112 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2113 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2117 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2121 if (LocaleCompare("decipher",option+1) == 0)
2123 /* Note: arguments do not have percent escapes expanded */
2127 passkey=FileToStringInfo(arg1,~0,_exception);
2128 if (passkey == (StringInfo *) NULL)
2129 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2131 (void) PasskeyDecipherImage(_image,passkey,_exception);
2132 passkey=DestroyStringInfo(passkey);
2135 if (LocaleCompare("depth",option+1) == 0)
2137 /* The _image_info->depth setting has already been set
2138 We just need to apply it to all images in current sequence
2140 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2141 That is it really is an operation, not a setting! Arrgghhh
2143 FUTURE: this should not be an operator!!!
2145 (void) SetImageDepth(_image,_image_info->depth,_exception);
2148 if (LocaleCompare("deskew",option+1) == 0)
2154 if (IfMagickFalse(IsGeometry(arg1)))
2155 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2156 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2159 threshold=40.0*QuantumRange/100.0;
2160 new_image=DeskewImage(_image,threshold,_exception);
2163 if (LocaleCompare("despeckle",option+1) == 0)
2165 new_image=DespeckleImage(_image,_exception);
2168 if (LocaleCompare("distort",option+1) == 0)
2176 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2178 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2180 if ((DistortImageMethod) parse == ResizeDistortion)
2184 /* Special Case - Argument is actually a resize geometry!
2185 ** Convert that to an appropriate distortion argument array.
2186 ** FUTURE: make a separate special resize operator
2187 Roll into a resize special operator */
2188 if (IfMagickFalse(IsGeometry(arg2)))
2189 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2191 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2192 resize_args[0]=(double) geometry.width;
2193 resize_args[1]=(double) geometry.height;
2194 new_image=DistortImage(_image,(DistortImageMethod) parse,
2195 (size_t)2,resize_args,MagickTrue,_exception);
2198 /* convert argument string into an array of doubles */
2199 args = StringToArrayOfDoubles(arg2,&count,_exception);
2200 if (args == (double *)NULL )
2201 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2203 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2204 plus_alt_op,_exception);
2205 args=(double *) RelinquishMagickMemory(args);
2208 if (LocaleCompare("draw",option+1) == 0)
2210 (void) CloneString(&_draw_info->primitive,arg1);
2211 (void) DrawImage(_image,_draw_info,_exception);
2212 (void) CloneString(&_draw_info->primitive,(char *)NULL);
2215 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2219 if (LocaleCompare("edge",option+1) == 0)
2221 flags=ParseGeometry(arg1,&geometry_info);
2222 if ((flags & (RhoValue|SigmaValue)) == 0)
2223 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2224 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2227 if (LocaleCompare("emboss",option+1) == 0)
2229 flags=ParseGeometry(arg1,&geometry_info);
2230 if ((flags & (RhoValue|SigmaValue)) == 0)
2231 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2232 if ((flags & SigmaValue) == 0)
2233 geometry_info.sigma=1.0;
2234 new_image=EmbossImage(_image,geometry_info.rho,
2235 geometry_info.sigma,_exception);
2238 if (LocaleCompare("encipher",option+1) == 0)
2240 /* Note: arguments do not have percent escapes expanded */
2244 passkey=FileToStringInfo(arg1,~0,_exception);
2245 if (passkey != (StringInfo *) NULL)
2247 (void) PasskeyEncipherImage(_image,passkey,_exception);
2248 passkey=DestroyStringInfo(passkey);
2252 if (LocaleCompare("enhance",option+1) == 0)
2254 new_image=EnhanceImage(_image,_exception);
2257 if (LocaleCompare("equalize",option+1) == 0)
2259 (void) EqualizeImage(_image,_exception);
2262 if (LocaleCompare("evaluate",option+1) == 0)
2267 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2269 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2271 if (IfMagickFalse(IsGeometry(arg2)))
2272 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2273 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2274 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2278 if (LocaleCompare("extent",option+1) == 0)
2280 if (IfMagickFalse(IsGeometry(arg1)))
2281 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2282 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2283 if (geometry.width == 0)
2284 geometry.width=_image->columns;
2285 if (geometry.height == 0)
2286 geometry.height=_image->rows;
2287 new_image=ExtentImage(_image,&geometry,_exception);
2290 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2294 if (LocaleCompare("features",option+1) == 0)
2296 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
2298 (void) DeleteImageArtifact(_image,"identify:features");
2301 (void) SetImageArtifact(_image,"identify:features","true");
2302 (void) SetImageArtifact(_image,"verbose","true");
2305 if (LocaleCompare("flip",option+1) == 0)
2307 new_image=FlipImage(_image,_exception);
2310 if (LocaleCompare("flop",option+1) == 0)
2312 new_image=FlopImage(_image,_exception);
2315 if (LocaleCompare("floodfill",option+1) == 0)
2320 if (IfMagickFalse(IsGeometry(arg1)))
2321 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2322 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2323 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2324 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2325 geometry.y,plus_alt_op,_exception);
2328 if (LocaleCompare("frame",option+1) == 0)
2339 value=GetImageOption(_image_info,"compose");
2340 compose=OverCompositeOp; /* use Over not _image->compose */
2341 if (value != (const char *) NULL)
2342 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2344 if (IfMagickFalse(IsGeometry(arg1)))
2345 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2346 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2347 frame_info.width=geometry.width;
2348 frame_info.height=geometry.height;
2349 frame_info.outer_bevel=geometry.x;
2350 frame_info.inner_bevel=geometry.y;
2351 frame_info.x=(ssize_t) frame_info.width;
2352 frame_info.y=(ssize_t) frame_info.height;
2353 frame_info.width=_image->columns+2*frame_info.width;
2354 frame_info.height=_image->rows+2*frame_info.height;
2355 new_image=FrameImage(_image,&frame_info,compose,_exception);
2358 if (LocaleCompare("function",option+1) == 0)
2366 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2368 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2370 /* convert argument string into an array of doubles */
2371 args = StringToArrayOfDoubles(arg2,&count,_exception);
2372 if (args == (double *)NULL )
2373 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2375 (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2377 args=(double *) RelinquishMagickMemory(args);
2380 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2384 if (LocaleCompare("gamma",option+1) == 0)
2389 if (IfMagickFalse(IsGeometry(arg1)))
2390 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2391 constant=StringToDouble(arg1,(char **) NULL);
2393 /* Using Gamma, via a cache */
2395 constant=PerceptibleReciprocal(constant);
2396 (void) GammaImage(_image,constant,_exception);
2398 /* Using Evaluate POW, direct update of values - more accurite */
2400 constant=PerceptibleReciprocal(constant);
2401 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2403 /* Set gamma setting -- Old meaning of "+gamma"
2404 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2408 if (LocaleCompare("gaussian-blur",option+1) == 0)
2410 flags=ParseGeometry(arg1,&geometry_info);
2411 if ((flags & (RhoValue|SigmaValue)) == 0)
2412 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2413 if ((flags & SigmaValue) == 0)
2414 geometry_info.sigma=1.0;
2415 new_image=GaussianBlurImage(_image,geometry_info.rho,
2416 geometry_info.sigma,_exception);
2419 if (LocaleCompare("gaussian",option+1) == 0)
2421 CLIWandWarnReplaced("-gaussian-blur");
2422 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL);
2424 if (LocaleCompare("geometry",option+1) == 0)
2427 Record Image offset for composition. (A Setting)
2428 Resize last _image. (ListOperator) -- DEPRECIATE
2429 FUTURE: Why if no 'offset' does this resize ALL images?
2430 Also why is the setting recorded in the IMAGE non-sense!
2433 { /* remove the previous composition geometry offset! */
2434 if (_image->geometry != (char *) NULL)
2435 _image->geometry=DestroyString(_image->geometry);
2438 if (IfMagickFalse(IsGeometry(arg1)))
2439 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2440 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2441 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2442 (void) CloneString(&_image->geometry,arg1);
2444 new_image=ResizeImage(_image,geometry.width,geometry.height,
2445 _image->filter,_exception);
2448 if (LocaleCompare("grayscale",option+1) == 0)
2450 parse=ParseCommandOption(MagickPixelIntensityOptions,
2453 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2455 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2458 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2462 if (LocaleCompare("identify",option+1) == 0)
2468 format=GetImageOption(_image_info,"format");
2469 if (format == (char *) NULL) {
2470 (void) IdentifyImage(_image,stdout,_image_info->verbose,_exception);
2473 text=InterpretImageProperties(_image_info,_image,format,_exception);
2474 if (text == (char *) NULL)
2475 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2477 (void) fputs(text,stdout);
2478 (void) fputc('\n',stdout);
2479 text=DestroyString((char *)text);
2482 if (LocaleCompare("implode",option+1) == 0)
2484 flags=ParseGeometry(arg1,&geometry_info);
2485 if ((flags & RhoValue) == 0)
2486 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2487 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2491 if (LocaleCompare("interpolative-resize",option+1) == 0)
2493 /* FUTURE: New to IMv7
2494 Roll into a resize special operator */
2495 if (IfMagickFalse(IsGeometry(arg1)))
2496 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2497 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2498 new_image=InterpolativeResizeImage(_image,geometry.width,
2499 geometry.height,_image->interpolate,_exception);
2502 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2506 if (LocaleCompare("lat",option+1) == 0)
2508 flags=ParseGeometry(arg1,&geometry_info);
2509 if ((flags & (RhoValue|SigmaValue)) == 0)
2510 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2511 if ((flags & SigmaValue) == 0)
2512 geometry_info.sigma=1.0;
2513 if ((flags & PercentValue) != 0)
2514 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2515 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2516 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2520 if (LocaleCompare("level",option+1) == 0)
2530 flags=ParseGeometry(arg1,&geometry_info);
2531 if ((flags & RhoValue) == 0)
2532 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2533 black_point=geometry_info.rho;
2534 white_point=(double) QuantumRange;
2535 if ((flags & SigmaValue) != 0)
2536 white_point=geometry_info.sigma;
2538 if ((flags & XiValue) != 0)
2539 gamma=geometry_info.xi;
2540 if ((flags & PercentValue) != 0)
2542 black_point*=(double) (QuantumRange/100.0);
2543 white_point*=(double) (QuantumRange/100.0);
2545 if ((flags & SigmaValue) == 0)
2546 white_point=(double) QuantumRange-black_point;
2547 if (IfPlusOp || ((flags & AspectValue) != 0))
2548 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2550 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2553 if (LocaleCompare("level-colors",option+1) == 0)
2556 token[MaxTextExtent];
2565 p=(const char *) arg1;
2566 GetMagickToken(p,&p,token); /* get black point color */
2567 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2568 (void) QueryColorCompliance(token,AllCompliance,
2569 &black_point,_exception);
2571 (void) QueryColorCompliance("#000000",AllCompliance,
2572 &black_point,_exception);
2573 if (isalpha((int) token[0]) || (token[0] == '#'))
2574 GetMagickToken(p,&p,token);
2576 white_point=black_point; /* set everything to that color */
2579 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2580 GetMagickToken(p,&p,token); /* Get white point color. */
2581 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2582 (void) QueryColorCompliance(token,AllCompliance,
2583 &white_point,_exception);
2585 (void) QueryColorCompliance("#ffffff",AllCompliance,
2586 &white_point,_exception);
2588 (void) LevelImageColors(_image,&black_point,&white_point,
2589 plus_alt_op,_exception);
2592 if (LocaleCompare("linear-stretch",option+1) == 0)
2601 flags=ParseGeometry(arg1,&geometry_info);
2602 if ((flags & RhoValue) == 0)
2603 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2604 black_point=geometry_info.rho;
2605 white_point=(double) _image->columns*_image->rows;
2606 if ((flags & SigmaValue) != 0)
2607 white_point=geometry_info.sigma;
2608 if ((flags & PercentValue) != 0)
2610 black_point*=(double) _image->columns*_image->rows/100.0;
2611 white_point*=(double) _image->columns*_image->rows/100.0;
2613 if ((flags & SigmaValue) == 0)
2614 white_point=(double) _image->columns*_image->rows-
2616 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2619 if (LocaleCompare("liquid-rescale",option+1) == 0)
2621 /* FUTURE: Roll into a resize special operator */
2622 if (IfMagickFalse(IsGeometry(arg1)))
2623 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2624 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2625 if ((flags & XValue) == 0)
2627 if ((flags & YValue) == 0)
2629 new_image=LiquidRescaleImage(_image,geometry.width,
2630 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2633 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2637 if (LocaleCompare("map",option+1) == 0)
2639 CLIWandWarnReplaced("-remap");
2640 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL);
2643 if (LocaleCompare("mask",option+1) == 0)
2645 /* Note: arguments do not have percent escapes expanded */
2650 { /* Remove a mask. */
2651 (void) SetImageMask(_image,(Image *) NULL,_exception);
2654 /* Set the image mask. */
2655 mask=GetImageCache(_image_info,arg1,_exception);
2656 if (mask == (Image *) NULL)
2658 (void) SetImageMask(_image,mask,_exception);
2659 mask=DestroyImage(mask);
2662 if (LocaleCompare("matte",option+1) == 0)
2664 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2665 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2666 DeactivateAlphaChannel, _exception);
2669 if (LocaleCompare("median",option+1) == 0)
2671 CLIWandWarnReplaced("-statistic Median");
2672 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1);
2675 if (LocaleCompare("mode",option+1) == 0)
2677 /* FUTURE: note this is also a special "montage" option */
2678 CLIWandWarnReplaced("-statistic Mode");
2679 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1);
2682 if (LocaleCompare("modulate",option+1) == 0)
2684 if (IfMagickFalse(IsGeometry(arg1)))
2685 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2686 (void) ModulateImage(_image,arg1,_exception);
2689 if (LocaleCompare("monitor",option+1) == 0)
2691 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2692 (MagickProgressMonitor) NULL,(void *) NULL);
2695 if (LocaleCompare("monochrome",option+1) == 0)
2697 (void) SetImageType(_image,BilevelType,_exception);
2700 if (LocaleCompare("morphology",option+1) == 0)
2703 token[MaxTextExtent];
2715 GetMagickToken(p,&p,token);
2716 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2718 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2721 GetMagickToken(p,&p,token);
2722 if ((*p == ':') || (*p == ','))
2723 GetMagickToken(p,&p,token);
2725 iterations=(ssize_t) StringToLong(p);
2726 kernel=AcquireKernelInfo(arg2);
2727 if (kernel == (KernelInfo *) NULL)
2728 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",
2730 new_image=MorphologyImage(_image,(MorphologyMethod)parse,
2731 iterations,kernel,_exception);
2732 kernel=DestroyKernelInfo(kernel);
2735 if (LocaleCompare("motion-blur",option+1) == 0)
2737 flags=ParseGeometry(arg1,&geometry_info);
2738 if ((flags & (RhoValue|SigmaValue)) == 0)
2739 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2740 if ((flags & SigmaValue) == 0)
2741 geometry_info.sigma=1.0;
2742 new_image=MotionBlurImage(_image,geometry_info.rho,
2743 geometry_info.sigma,geometry_info.xi,_exception);
2746 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2750 if (LocaleCompare("negate",option+1) == 0)
2752 (void) NegateImage(_image, plus_alt_op, _exception);
2755 if (LocaleCompare("noise",option+1) == 0)
2765 CLIWandWarnReplaced("-statistic NonPeak");
2766 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1);
2769 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2771 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2774 value=GetImageOption(_image_info,"attenuate");
2775 if (value != (const char *) NULL)
2776 attenuate=StringToDouble(value,(char **) NULL);
2777 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2781 if (LocaleCompare("normalize",option+1) == 0)
2783 (void) NormalizeImage(_image,_exception);
2786 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2790 if (LocaleCompare("opaque",option+1) == 0)
2795 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2796 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,plus_alt_op,
2800 if (LocaleCompare("ordered-dither",option+1) == 0)
2802 (void) OrderedPosterizeImage(_image,arg1,_exception);
2805 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2809 if (LocaleCompare("paint",option+1) == 0)
2811 flags=ParseGeometry(arg1,&geometry_info);
2812 if ((flags & (RhoValue|SigmaValue)) == 0)
2813 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2814 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2818 if (LocaleCompare("perceptible",option+1) == 0)
2820 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2824 if (LocaleCompare("polaroid",option+1) == 0)
2836 random_info=AcquireRandomInfo();
2837 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2838 random_info=DestroyRandomInfo(random_info);
2841 flags=ParseGeometry(arg1,&geometry_info);
2842 if ((flags & RhoValue) == 0)
2843 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2844 angle=geometry_info.rho;
2846 caption=GetImageProperty(_image,"caption",_exception);
2847 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2848 _image->interpolate,_exception);
2851 if (LocaleCompare("posterize",option+1) == 0)
2853 flags=ParseGeometry(arg1,&geometry_info);
2854 if ((flags & RhoValue) == 0)
2855 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2856 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2857 _quantize_info->dither_method,_exception);
2860 if (LocaleCompare("preview",option+1) == 0)
2862 /* FUTURE: should be a 'Genesis' option?
2863 Option however is also in WandSettingOptionInfo()
2866 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2868 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2870 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2873 if (LocaleCompare("profile",option+1) == 0)
2875 /* Note: arguments do not have percent escapes expanded */
2889 { /* Remove a profile from the _image. */
2890 (void) ProfileImage(_image,arg1,(const unsigned char *)
2894 /* Associate a profile with the _image. */
2895 profile_info=CloneImageInfo(_image_info);
2896 profile=GetImageProfile(_image,"iptc");
2897 if (profile != (StringInfo *) NULL)
2898 profile_info->profile=(void *) CloneStringInfo(profile);
2899 profile_image=GetImageCache(profile_info,arg1,_exception);
2900 profile_info=DestroyImageInfo(profile_info);
2901 if (profile_image == (Image *) NULL)
2906 profile_info=CloneImageInfo(_image_info);
2907 (void) CopyMagickString(profile_info->filename,arg1,
2909 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
2910 if (profile != (StringInfo *) NULL)
2912 (void) ProfileImage(_image,profile_info->magick,
2913 GetStringInfoDatum(profile),(size_t)
2914 GetStringInfoLength(profile),_exception);
2915 profile=DestroyStringInfo(profile);
2917 profile_info=DestroyImageInfo(profile_info);
2920 ResetImageProfileIterator(profile_image);
2921 name=GetNextImageProfile(profile_image);
2922 while (name != (const char *) NULL)
2924 profile=GetImageProfile(profile_image,name);
2925 if (profile != (StringInfo *) NULL)
2926 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
2927 (size_t) GetStringInfoLength(profile),_exception);
2928 name=GetNextImageProfile(profile_image);
2930 profile_image=DestroyImage(profile_image);
2933 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2937 if (LocaleCompare("radial-blur",option+1) == 0)
2939 flags=ParseGeometry(arg1,&geometry_info);
2940 if ((flags & RhoValue) == 0)
2941 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2942 new_image=RadialBlurImage(_image,geometry_info.rho,_exception);
2945 if (LocaleCompare("raise",option+1) == 0)
2947 if (IfMagickFalse(IsGeometry(arg1)))
2948 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2949 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2950 (void) RaiseImage(_image,&geometry,normal_op,_exception);
2953 if (LocaleCompare("random-threshold",option+1) == 0)
2955 if (IfMagickFalse(IsGeometry(arg1)))
2956 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2957 (void) RandomThresholdImage(_image,arg1,_exception);
2960 if (LocaleCompare("recolor",option+1) == 0)
2962 CLIWandWarnReplaced("-color-matrix");
2963 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL);
2965 if (LocaleCompare("remap",option+1) == 0)
2967 /* Note: arguments do not have percent escapes expanded */
2971 remap_image=GetImageCache(_image_info,arg1,_exception);
2972 if (remap_image == (Image *) NULL)
2974 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
2975 remap_image=DestroyImage(remap_image);
2978 if (LocaleCompare("repage",option+1) == 0)
2982 if (IfMagickFalse(IsGeometry(arg1)))
2983 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
2985 (void) ResetImagePage(_image,arg1);
2988 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
2991 if (LocaleCompare("resample",option+1) == 0)
2993 /* FUTURE: Roll into a resize special operation */
2994 flags=ParseGeometry(arg1,&geometry_info);
2995 if ((flags & (RhoValue|SigmaValue)) == 0)
2996 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2997 if ((flags & SigmaValue) == 0)
2998 geometry_info.sigma=geometry_info.rho;
2999 new_image=ResampleImage(_image,geometry_info.rho,
3000 geometry_info.sigma,_image->filter,_exception);
3003 if (LocaleCompare("resize",option+1) == 0)
3005 if (IfMagickFalse(IsGeometry(arg1)))
3006 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3007 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3008 new_image=ResizeImage(_image,geometry.width,geometry.height,
3009 _image->filter,_exception);
3012 if (LocaleCompare("roll",option+1) == 0)
3014 if (IfMagickFalse(IsGeometry(arg1)))
3015 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3016 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3017 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3020 if (LocaleCompare("rotate",option+1) == 0)
3022 flags=ParseGeometry(arg1,&geometry_info);
3023 if ((flags & RhoValue) == 0)
3024 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3025 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3027 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3029 new_image=RotateImage(_image,geometry_info.rho,_exception);
3032 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3036 if (LocaleCompare("sample",option+1) == 0)
3038 /* FUTURE: Roll into a resize special operator */
3039 if (IfMagickFalse(IsGeometry(arg1)))
3040 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3041 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3042 new_image=SampleImage(_image,geometry.width,geometry.height,
3046 if (LocaleCompare("scale",option+1) == 0)
3048 /* FUTURE: Roll into a resize special operator */
3049 if (IfMagickFalse(IsGeometry(arg1)))
3050 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3051 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3052 new_image=ScaleImage(_image,geometry.width,geometry.height,
3056 if (LocaleCompare("segment",option+1) == 0)
3058 flags=ParseGeometry(arg1,&geometry_info);
3059 if ((flags & (RhoValue|SigmaValue)) == 0)
3060 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3061 if ((flags & SigmaValue) == 0)
3062 geometry_info.sigma=1.0;
3063 (void) SegmentImage(_image,_image->colorspace,
3064 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3068 if (LocaleCompare("selective-blur",option+1) == 0)
3070 flags=ParseGeometry(arg1,&geometry_info);
3071 if ((flags & (RhoValue|SigmaValue)) == 0)
3072 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3073 if ((flags & SigmaValue) == 0)
3074 geometry_info.sigma=1.0;
3075 if ((flags & PercentValue) != 0)
3076 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3077 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3078 geometry_info.sigma,geometry_info.xi,_exception);
3081 if (LocaleCompare("separate",option+1) == 0)
3083 /* WARNING: This can generate multiple images! */
3084 /* FUTURE - this may be replaced by a "-channel" method */
3085 new_image=SeparateImages(_image,_exception);
3088 if (LocaleCompare("sepia-tone",option+1) == 0)
3090 if (IfMagickFalse(IsGeometry(arg1)))
3091 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3092 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3093 (double) QuantumRange+1.0),_exception);
3096 if (LocaleCompare("shade",option+1) == 0)
3098 flags=ParseGeometry(arg1,&geometry_info);
3099 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3100 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3101 new_image=ShadeImage(_image,normal_op,geometry_info.rho,
3102 geometry_info.sigma,_exception);
3105 if (LocaleCompare("shadow",option+1) == 0)
3107 flags=ParseGeometry(arg1,&geometry_info);
3108 if ((flags & (RhoValue|SigmaValue)) == 0)
3109 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3110 if ((flags & SigmaValue) == 0)
3111 geometry_info.sigma=1.0;
3112 if ((flags & XiValue) == 0)
3113 geometry_info.xi=4.0;
3114 if ((flags & PsiValue) == 0)
3115 geometry_info.psi=4.0;
3116 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3117 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3118 ceil(geometry_info.psi-0.5),_exception);
3121 if (LocaleCompare("sharpen",option+1) == 0)
3123 flags=ParseGeometry(arg1,&geometry_info);
3124 if ((flags & (RhoValue|SigmaValue)) == 0)
3125 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3126 if ((flags & SigmaValue) == 0)
3127 geometry_info.sigma=1.0;
3128 if ((flags & XiValue) == 0)
3129 geometry_info.xi=0.0;
3130 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3134 if (LocaleCompare("shave",option+1) == 0)
3136 if (IfMagickFalse(IsGeometry(arg1)))
3137 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3138 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3139 new_image=ShaveImage(_image,&geometry,_exception);
3142 if (LocaleCompare("shear",option+1) == 0)
3144 flags=ParseGeometry(arg1,&geometry_info);
3145 if ((flags & RhoValue) == 0)
3146 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3147 if ((flags & SigmaValue) == 0)
3148 geometry_info.sigma=geometry_info.rho;
3149 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3153 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3155 flags=ParseGeometry(arg1,&geometry_info);
3156 if ((flags & RhoValue) == 0)
3157 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3158 if ((flags & SigmaValue) == 0)
3159 geometry_info.sigma=(double) QuantumRange/2.0;
3160 if ((flags & PercentValue) != 0)
3161 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3163 (void) SigmoidalContrastImage(_image,normal_op,geometry_info.rho,
3164 geometry_info.sigma,_exception);
3167 if (LocaleCompare("sketch",option+1) == 0)
3169 flags=ParseGeometry(arg1,&geometry_info);
3170 if ((flags & (RhoValue|SigmaValue)) == 0)
3171 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3172 if ((flags & SigmaValue) == 0)
3173 geometry_info.sigma=1.0;
3174 new_image=SketchImage(_image,geometry_info.rho,
3175 geometry_info.sigma,geometry_info.xi,_exception);
3178 if (LocaleCompare("solarize",option+1) == 0)
3180 if (IfMagickFalse(IsGeometry(arg1)))
3181 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3182 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3183 QuantumRange+1.0),_exception);
3186 if (LocaleCompare("sparse-color",option+1) == 0)
3188 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3190 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3192 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3196 if (LocaleCompare("splice",option+1) == 0)
3198 if (IfMagickFalse(IsGeometry(arg1)))
3199 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3200 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3201 new_image=SpliceImage(_image,&geometry,_exception);
3204 if (LocaleCompare("spread",option+1) == 0)
3206 flags=ParseGeometry(arg1,&geometry_info);
3207 if ((flags & RhoValue) == 0)
3208 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3209 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3213 if (LocaleCompare("statistic",option+1) == 0)
3215 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3217 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3219 flags=ParseGeometry(arg2,&geometry_info);
3220 if ((flags & RhoValue) == 0)
3221 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3222 if ((flags & SigmaValue) == 0)
3223 geometry_info.sigma=geometry_info.rho;
3224 new_image=StatisticImage(_image,(StatisticType)parse,
3225 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3229 if (LocaleCompare("strip",option+1) == 0)
3231 (void) StripImage(_image,_exception);
3234 if (LocaleCompare("swirl",option+1) == 0)
3236 flags=ParseGeometry(arg1,&geometry_info);
3237 if ((flags & RhoValue) == 0)
3238 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3239 new_image=SwirlImage(_image,geometry_info.rho,
3240 _image->interpolate,_exception);
3243 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3247 if (LocaleCompare("threshold",option+1) == 0)
3252 threshold=(double) QuantumRange/2;
3254 if (IfMagickFalse(IsGeometry(arg1)))
3255 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3256 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3258 (void) BilevelImage(_image,threshold,_exception);
3261 if (LocaleCompare("thumbnail",option+1) == 0)
3263 if (IfMagickFalse(IsGeometry(arg1)))
3264 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3265 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3266 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3270 if (LocaleCompare("tint",option+1) == 0)
3272 if (IfMagickFalse(IsGeometry(arg1)))
3273 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3274 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3277 if (LocaleCompare("transform",option+1) == 0)
3279 CLIWandWarnReplaced("+distort AffineProjection");
3280 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3283 if (LocaleCompare("transparent",option+1) == 0)
3288 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3289 (void) TransparentPaintImage(_image,&target,(Quantum)
3290 TransparentAlpha,plus_alt_op,_exception);
3293 if (LocaleCompare("transpose",option+1) == 0)
3295 new_image=TransposeImage(_image,_exception);
3298 if (LocaleCompare("transverse",option+1) == 0)
3300 new_image=TransverseImage(_image,_exception);
3303 if (LocaleCompare("trim",option+1) == 0)
3305 new_image=TrimImage(_image,_exception);
3308 if (LocaleCompare("type",option+1) == 0)
3310 /* Note that "type" setting should have already been defined */
3311 (void) SetImageType(_image,_image_info->type,_exception);
3314 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3318 if (LocaleCompare("unique",option+1) == 0)
3320 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3321 Option is not documented, bt appears to be for "identify".
3322 We may need a identify specific verbose!
3325 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3328 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3329 (void) SetImageArtifact(_image,"verbose","true");
3332 if (LocaleCompare("unique-colors",option+1) == 0)
3334 new_image=UniqueImageColors(_image,_exception);
3337 if (LocaleCompare("unsharp",option+1) == 0)
3339 flags=ParseGeometry(arg1,&geometry_info);
3340 if ((flags & (RhoValue|SigmaValue)) == 0)
3341 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3342 if ((flags & SigmaValue) == 0)
3343 geometry_info.sigma=1.0;
3344 if ((flags & XiValue) == 0)
3345 geometry_info.xi=1.0;
3346 if ((flags & PsiValue) == 0)
3347 geometry_info.psi=0.05;
3348 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3349 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3352 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3356 if (LocaleCompare("verbose",option+1) == 0)
3358 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3359 three places! ImageArtifact ImageOption _image_info->verbose
3360 Some how new images also get this artifact!
3362 (void) SetImageArtifact(_image,option+1,
3363 IfNormalOp ? "true" : "false" );
3366 if (LocaleCompare("vignette",option+1) == 0)
3368 flags=ParseGeometry(arg1,&geometry_info);
3369 if ((flags & (RhoValue|SigmaValue)) == 0)
3370 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3371 if ((flags & SigmaValue) == 0)
3372 geometry_info.sigma=1.0;
3373 if ((flags & XiValue) == 0)
3374 geometry_info.xi=0.1*_image->columns;
3375 if ((flags & PsiValue) == 0)
3376 geometry_info.psi=0.1*_image->rows;
3377 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3378 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3379 ceil(geometry_info.psi-0.5),_exception);
3382 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3386 if (LocaleCompare("wave",option+1) == 0)
3388 flags=ParseGeometry(arg1,&geometry_info);
3389 if ((flags & (RhoValue|SigmaValue)) == 0)
3390 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3391 if ((flags & SigmaValue) == 0)
3392 geometry_info.sigma=1.0;
3393 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3394 _image->interpolate,_exception);
3397 if (LocaleCompare("white-threshold",option+1) == 0)
3399 if (IfMagickFalse(IsGeometry(arg1)))
3400 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3401 (void) WhiteThresholdImage(_image,arg1,_exception);
3404 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3407 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3409 /* clean up percent escape interpreted strings */
3411 arg1=DestroyString((char *)arg1);
3413 arg2=DestroyString((char *)arg2);
3415 /* Replace current image with any image that was generated
3416 and set image point to last image (so image->next is correct) */
3417 if (new_image != (Image *) NULL)
3418 ReplaceImageInListReturnLast(&_image,new_image);
3423 #undef _quantize_info
3432 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3433 const char *option,const char *arg1,const char *arg2)
3435 #if !USE_WAND_METHODS
3441 assert(cli_wand != (MagickCLI *) NULL);
3442 assert(cli_wand->signature == WandSignature);
3443 assert(cli_wand->wand.signature == WandSignature);
3444 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3445 if (IfMagickTrue(cli_wand->wand.debug))
3446 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
3448 #if !USE_WAND_METHODS
3449 /* FUTURE add appropriate tracing */
3451 n=GetImageListLength(cli_wand->wand.images);
3452 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3455 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3456 if ( cli_wand->wand.images->next == (Image *) NULL )
3458 cli_wand->wand.images=cli_wand->wand.images->next;
3461 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3463 MagickResetIterator(&cli_wand->wand);
3464 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3465 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3466 MagickResetIterator(&cli_wand->wand);
3472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3476 + C L I L i s t O p e r a t o r I m a g e s %
3480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3482 % CLIListOperatorImages() applies a single operation that is apply to the
3483 % entire image list as a whole. The result is often a complete replacment
3484 % of the image list with a completely new list, or with just a single image
3487 % The format of the MogrifyImage method is:
3489 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3490 % const char *option,const char *arg1,const char *arg2)
3492 % A description of each parameter follows:
3494 % o cli_wand: structure holding settings to be applied
3496 % o option: The option string for the operation
3498 % o arg1, arg2: optional argument strings to the operation
3499 % arg2 is currently not used
3502 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3503 const char *option,const char *arg1n,const char *arg2n)
3505 const char /* For percent escape interpretImageProperties() */
3518 #define _image_info (cli_wand->wand.image_info)
3519 #define _images (cli_wand->wand.images)
3520 #define _exception (cli_wand->wand.exception)
3521 #define _draw_info (cli_wand->draw_info)
3522 #define _quantize_info (cli_wand->quantize_info)
3523 #define _process_flags (cli_wand->process_flags)
3524 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3525 #define IfNormalOp (*option=='-')
3526 #define IfPlusOp (*option!='-')
3527 #define normal_op IsMagickTrue(IfNormalOp)
3529 assert(cli_wand != (MagickCLI *) NULL);
3530 assert(cli_wand->signature == WandSignature);
3531 assert(cli_wand->wand.signature == WandSignature);
3532 assert(_images != (Image *) NULL); /* _images must be present */
3533 if (IfMagickTrue(cli_wand->wand.debug))
3534 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
3536 /* Interpret Percent Escapes in Arguments - using first image */
3539 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3540 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3541 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3542 /* Interpret Percent escapes in argument 1 */
3543 if (arg1n != (char *) NULL) {
3544 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3545 if (arg1 == (char *) NULL) {
3546 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3547 arg1=arg1n; /* use the given argument as is */
3550 if (arg2n != (char *) NULL) {
3551 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3552 if (arg2 == (char *) NULL) {
3553 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3554 arg2=arg2n; /* use the given argument as is */
3558 #undef _process_flags
3562 (void) FormatLocaleFile(stderr,
3563 "CLIListOperatorImages: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
3567 new_images=NewImageList();
3569 switch (*(option+1))
3573 if (LocaleCompare("append",option+1) == 0)
3575 new_images=AppendImages(_images,normal_op,_exception);
3578 if (LocaleCompare("average",option+1) == 0)
3580 CLIWandWarnReplaced("-evaluate-sequence Mean");
3581 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3584 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3588 if (LocaleCompare("channel-fx",option+1) == 0)
3590 new_images=ChannelFxImage(_images,arg1,_exception);
3593 if (LocaleCompare("clut",option+1) == 0)
3598 /* FUTURE - make this a compose option, and thus can be used
3599 with layers compose or even compose last image over all other
3602 new_images=RemoveFirstImageFromList(&_images);
3603 clut_image=RemoveLastImageFromList(&_images);
3604 /* FUTURE - produce Exception, rather than silent fail */
3605 if (clut_image == (Image *) NULL)
3607 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3608 clut_image=DestroyImage(clut_image);
3611 if (LocaleCompare("coalesce",option+1) == 0)
3613 new_images=CoalesceImages(_images,_exception);
3616 if (LocaleCompare("combine",option+1) == 0)
3618 /* FUTURE - this may be replaced by a 'channel' method */
3619 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3621 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3623 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3626 if (LocaleCompare("composite",option+1) == 0)
3644 /* Compose value from "-compose" option only */
3645 value=GetImageOption(_image_info,"compose");
3646 if (value == (const char *) NULL)
3647 compose=OverCompositeOp; /* use Over not source_image->compose */
3649 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3652 /* Get "clip-to-self" expert setting (false is normal) */
3653 value=GetImageOption(_image_info,"compose:clip-to-self");
3654 if (value == (const char *) NULL)
3655 clip_to_self=MagickTrue;
3657 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3658 "compose:clip-to-self")); /* if this is true */
3659 value=GetImageOption(_image_info,"compose:outside-overlay");
3660 if (value != (const char *) NULL) { /* or this false */
3661 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3662 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3665 new_images=RemoveFirstImageFromList(&_images);
3666 source_image=RemoveFirstImageFromList(&_images);
3667 if (source_image == (Image *) NULL)
3668 break; /* FUTURE - produce Exception, rather than silent fail */
3670 /* FUTURE - this should not be here! - should be part of -geometry */
3671 (void) TransformImage(&source_image,(char *) NULL,
3672 source_image->geometry,_exception);
3673 SetGeometry(source_image,&geometry);
3674 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3675 GravityAdjustGeometry(new_images->columns,new_images->rows,
3676 new_images->gravity, &geometry);
3677 mask_image=RemoveFirstImageFromList(&_images);
3678 if (mask_image != (Image *) NULL)
3680 if ((compose == DisplaceCompositeOp) ||
3681 (compose == DistortCompositeOp))
3682 status&=CompositeImage(source_image,mask_image,
3683 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3692 source_geometry.width=mask_image->columns;
3693 source_geometry.height=mask_image->rows;
3694 source_geometry.x=(-geometry.x);
3695 source_geometry.y=(-geometry.y);
3698 image=ExtentImage(source_image,&source_geometry,_exception);
3699 if (image != (Image *) NULL)
3701 source_image=DestroyImage(source_image);
3704 status&=CompositeImage(source_image,mask_image,
3705 IntensityCompositeOp,MagickTrue,0,0,_exception);
3707 mask_image=DestroyImage(mask_image);
3709 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3710 geometry.x,geometry.y,_exception);
3711 source_image=DestroyImage(source_image);
3714 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3718 if (LocaleCompare("deconstruct",option+1) == 0)
3720 CLIWandWarnReplaced("-layer CompareAny");
3721 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3724 if (LocaleCompare("delete",option+1) == 0)
3727 DeleteImages(&_images,arg1,_exception);
3729 DeleteImages(&_images,"-1",_exception);
3732 if (LocaleCompare("duplicate",option+1) == 0)
3742 if (IfMagickFalse(IsGeometry(arg1)))
3743 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3745 number_duplicates=(size_t) StringToLong(arg1);
3747 if (p == (const char *) NULL)
3748 new_images=DuplicateImages(_images,number_duplicates,"-1",
3751 new_images=DuplicateImages(_images,number_duplicates,p,
3755 new_images=DuplicateImages(_images,1,"-1",_exception);
3756 AppendImageToList(&_images, new_images);
3757 new_images=(Image *)NULL;
3760 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3764 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3766 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3768 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3770 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3774 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3778 if (LocaleCompare("fft",option+1) == 0)
3780 new_images=ForwardFourierTransformImage(_images,normal_op,_exception);
3783 if (LocaleCompare("flatten",option+1) == 0)
3785 /* REDIRECTED to use -layers flatten instead */
3786 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3789 if (LocaleCompare("fx",option+1) == 0)
3791 new_images=FxImage(_images,arg1,_exception);
3794 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3798 if (LocaleCompare("hald-clut",option+1) == 0)
3800 /* FUTURE - make this a compose option (and thus layers compose )
3801 or perhaps compose last image over all other _images.
3806 new_images=RemoveFirstImageFromList(&_images);
3807 hald_image=RemoveLastImageFromList(&_images);
3808 if (hald_image == (Image *) NULL)
3810 (void) HaldClutImage(new_images,hald_image,_exception);
3811 hald_image=DestroyImage(hald_image);
3814 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3818 if (LocaleCompare("ift",option+1) == 0)
3824 magnitude_image=RemoveFirstImageFromList(&_images);
3825 phase_image=RemoveFirstImageFromList(&_images);
3826 /* FUTURE - produce Exception, rather than silent fail */
3827 if (phase_image == (Image *) NULL)
3829 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3830 normal_op,_exception);
3831 magnitude_image=DestroyImage(magnitude_image);
3832 phase_image=DestroyImage(phase_image);
3835 if (LocaleCompare("insert",option+1) == 0)
3844 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3845 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3847 insert_image=RemoveLastImageFromList(&_images);
3849 index=(ssize_t) StringToLong(arg1);
3850 index_image=insert_image;
3852 PrependImageToList(&_images,insert_image);
3853 else if (index == (ssize_t) GetImageListLength(_images))
3854 AppendImageToList(&_images,insert_image);
3857 index_image=GetImageFromList(_images,index-1);
3858 if (index_image == (Image *) NULL)
3859 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3860 InsertImageInList(&index_image,insert_image);
3862 _images=GetFirstImageInList(index_image);
3865 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3869 if (LocaleCompare("layers",option+1) == 0)
3871 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3873 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3875 switch ((LayerMethod) parse)
3879 new_images=CoalesceImages(_images,_exception);
3882 case CompareAnyLayer:
3883 case CompareClearLayer:
3884 case CompareOverlayLayer:
3887 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
3894 case TrimBoundsLayer:
3896 new_images=MergeImageLayers(_images,(LayerMethod) parse,
3902 new_images=DisposeImages(_images,_exception);
3905 case OptimizeImageLayer:
3907 new_images=OptimizeImageLayers(_images,_exception);
3910 case OptimizePlusLayer:
3912 new_images=OptimizePlusImageLayers(_images,_exception);
3915 case OptimizeTransLayer:
3917 OptimizeImageTransparency(_images,_exception);
3920 case RemoveDupsLayer:
3922 RemoveDuplicateLayers(&_images,_exception);
3925 case RemoveZeroLayer:
3927 RemoveZeroDelayLayers(&_images,_exception);
3931 { /* General Purpose, GIF Animation Optimizer. */
3932 new_images=CoalesceImages(_images,_exception);
3933 if (new_images == (Image *) NULL)
3935 _images=DestroyImageList(_images);
3936 _images=OptimizeImageLayers(new_images,_exception);
3937 if (_images == (Image *) NULL)
3939 new_images=DestroyImageList(new_images);
3940 OptimizeImageTransparency(_images,_exception);
3941 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
3945 case CompositeLayer:
3959 value=GetImageOption(_image_info,"compose");
3960 compose=OverCompositeOp; /* Default to Over */
3961 if (value != (const char *) NULL)
3962 compose=(CompositeOperator) ParseCommandOption(
3963 MagickComposeOptions,MagickFalse,value);
3965 /* Split image sequence at the first 'NULL:' image. */
3967 while (source != (Image *) NULL)
3969 source=GetNextImageInList(source);
3970 if ((source != (Image *) NULL) &&
3971 (LocaleCompare(source->magick,"NULL") == 0))
3974 if (source != (Image *) NULL)
3976 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
3977 (GetNextImageInList(source) == (Image *) NULL))
3978 source=(Image *) NULL;
3980 { /* Separate the two lists, junk the null: image. */
3981 source=SplitImageList(source->previous);
3982 DeleteImageFromList(&source);
3985 if (source == (Image *) NULL)
3987 (void) ThrowMagickException(_exception,GetMagickModule(),
3988 OptionError,"MissingNullSeparator","layers Composite");
3991 /* Adjust offset with gravity and virtual canvas. */
3992 SetGeometry(_images,&geometry);
3993 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
3994 geometry.width=source->page.width != 0 ?
3995 source->page.width : source->columns;
3996 geometry.height=source->page.height != 0 ?
3997 source->page.height : source->rows;
3998 GravityAdjustGeometry(_images->page.width != 0 ?
3999 _images->page.width : _images->columns,
4000 _images->page.height != 0 ? _images->page.height :
4001 _images->rows,_images->gravity,&geometry);
4003 /* Compose the two image sequences together */
4004 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4006 source=DestroyImageList(source);
4012 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4016 if (LocaleCompare("map",option+1) == 0)
4018 CLIWandWarnReplaced("+remap");
4019 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4022 if (LocaleCompare("morph",option+1) == 0)
4027 if (IfMagickFalse(IsGeometry(arg1)))
4028 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4029 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4031 if (morph_image == (Image *) NULL)
4033 _images=DestroyImageList(_images);
4034 _images=morph_image;
4037 if (LocaleCompare("mosaic",option+1) == 0)
4039 /* REDIRECTED to use -layers mosaic instead */
4040 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4043 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4047 if (LocaleCompare("poly",option+1) == 0)
4055 /* convert argument string into an array of doubles */
4056 args = StringToArrayOfDoubles(arg2,&count,_exception);
4057 if (args == (double *)NULL )
4058 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4059 new_images=PolynomialImage(_images,count >> 1,args,_exception);
4060 args=(double *) RelinquishMagickMemory(args);
4063 if (LocaleCompare("print",option+1) == 0)
4065 (void) FormatLocaleFile(stdout,"%s",arg1);
4068 if (LocaleCompare("process",option+1) == 0)
4070 /* FUTURE: better parsing using ScriptToken() from string ??? */
4078 arguments=StringToArgv(arg1,&number_arguments);
4079 if (arguments == (char **) NULL)
4081 if (strchr(arguments[1],'=') != (char *) NULL)
4102 Support old style syntax, filter="-option arg1".
4104 length=strlen(arg1);
4105 token=(char *) NULL;
4106 if (~length >= (MaxTextExtent-1))
4107 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4109 if (token == (char *) NULL)
4113 token_info=AcquireTokenInfo();
4114 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4115 "\"",'\0',&breaker,&next,"e);
4116 token_info=DestroyTokenInfo(token_info);
4122 argv=(&(arguments[next]));
4123 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4126 token=DestroyString(token);
4129 (void) SubstituteString(&arguments[1],"-","");
4130 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4131 number_arguments-2,(const char **) arguments+2,_exception);
4132 for (j=0; j < number_arguments; j++)
4133 arguments[j]=DestroyString(arguments[j]);
4134 arguments=(char **) RelinquishMagickMemory(arguments);
4137 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4141 if (LocaleCompare("remap",option+1) == 0)
4143 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4146 if (LocaleCompare("reverse",option+1) == 0)
4148 ReverseImageList(&_images);
4151 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4155 if (LocaleCompare("smush",option+1) == 0)
4157 /* FUTURE: this option needs more work to make better */
4161 if (IfMagickFalse(IsGeometry(arg1)))
4162 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4163 offset=(ssize_t) StringToLong(arg1);
4164 new_images=SmushImages(_images,normal_op,offset,_exception);
4167 if (LocaleCompare("subimage",option+1) == 0)
4185 base_image=GetImageFromList(_images,0);
4186 compare_image=GetImageFromList(_images,1);
4188 /* Comparision Metric */
4189 metric=UndefinedMetric;
4190 value=GetImageOption(_image_info,"metric");
4191 if (value != (const char *) NULL)
4192 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4195 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4196 &offset,&similarity,_exception);
4198 if ( new_images != (Image *)NULL ) {
4200 result[MaxTextExtent];
4202 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4203 (void) SetImageProperty(new_images,"subimage:similarity",result,
4205 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4207 (void) SetImageProperty(new_images,"subimage:x",result,
4209 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4211 (void) SetImageProperty(new_images,"subimage:y",result,
4213 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4214 (unsigned long) offset.width,(unsigned long) offset.height,
4215 (long) offset.x,(long) offset.y);
4216 (void) SetImageProperty(new_images,"subimage:offset",result,
4221 if (LocaleCompare("swap",option+1) == 0) {
4241 flags=ParseGeometry(arg1,&geometry_info);
4242 if ((flags & RhoValue) == 0)
4243 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4244 index=(ssize_t) geometry_info.rho;
4245 if ((flags & SigmaValue) != 0)
4246 swap_index=(ssize_t) geometry_info.sigma;
4248 p=GetImageFromList(_images,index);
4249 q=GetImageFromList(_images,swap_index);
4250 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4252 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4254 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4257 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4258 swap=CloneImage(p,0,0,MagickTrue,_exception);
4259 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4260 ReplaceImageInList(&q,swap);
4261 _images=GetFirstImageInList(q);
4264 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4267 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4270 /* clean up percent escape interpreted strings */
4272 arg1=DestroyString((char *)arg1);
4274 arg2=DestroyString((char *)arg2);
4276 /* if new image list generated, replace existing image list */
4277 if (new_images == (Image *) NULL)
4279 _images=DestroyImageList(_images);
4280 _images=GetFirstImageInList(new_images);
4287 #undef _quantize_info
4294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4298 + C L I N o I m a g e O p e r a t i o n s %
4302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4304 % CLINoImageOperator() Applies operations that may not actually need images
4307 % The classic operators of this type is "-read", which actually creates
4308 % images even when no images are present. Or image stack operators, which
4309 % can be applied (push or pop) to an empty image list.
4311 % Note that these operators may involve other special 'option' prefix
4312 % characters other than '-' or '+', namely parenthesis and braces.
4314 % The format of the CLINoImageOption method is:
4316 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4317 % const char *arg1, const char *arg2)
4319 % A description of each parameter follows:
4321 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4323 % o option: The special option (with any switch char) to process
4325 % o arg1 & arg2: Argument for option, if required
4326 % Currently arg2 is not used.
4329 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4330 const char *option,const char *arg1,const char *arg2)
4333 const char /* For percent escape interpretImageProperties() */
4338 #define _image_info (cli_wand->wand.image_info)
4339 #define _images (cli_wand->wand.images)
4340 #define _exception (cli_wand->wand.exception)
4341 #define IfNormalOp (*option=='-')
4342 #define IfPlusOp (*option!='-')
4344 assert(cli_wand != (MagickCLI *) NULL);
4345 assert(cli_wand->signature == WandSignature);
4346 assert(cli_wand->wand.signature == WandSignature);
4347 if (IfMagickTrue(cli_wand->wand.debug))
4348 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4351 Not able to be used as their may not be any images!
4352 Also the only option that may have arguments that can be percent escaped is
4355 #define _process_flags (cli_wand->process_flags)
4356 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4357 /* Interpret Percent Escapes in Arguments - using first image */
4360 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4361 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4362 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4363 /* Interpret Percent escapes in argument 1 */
4364 if (arg1n != (char *) NULL) {
4365 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4366 if (arg1 == (char *) NULL) {
4367 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4368 arg1=arg1n; /* use the given argument as is */
4371 if (arg2n != (char *) NULL) {
4372 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4373 if (arg2 == (char *) NULL) {
4374 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4375 arg2=arg2n; /* use the given argument as is */
4379 #undef _process_flags
4383 do { /* break to exit code */
4385 No-op options (ignore these)
4387 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4389 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4391 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4393 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4395 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4400 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4401 ( LocaleCompare("--",option) == 0 ) ) {
4402 /* Do Glob filename Expansion for 'arg1' then read all images.
4404 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4405 * (but attaching to the filenames in the generated argument list) any
4406 * [...] read modifiers that may be present.
4408 * For example: It will expand '*.gif[20x20]' into a list such as
4409 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4411 * NOTE: In IMv6 this was done globally across all images. This
4412 * meant you could include IM options in '@filename' lists, but you
4413 * could not include comments. Doing it only for image read makes
4414 * it far more secure.
4416 * Note: arguments do not have percent escapes expanded for security
4424 argv = (char **) &arg1;
4426 /* Expand 'glob' expressions in the given filename.
4427 Expansion handles any 'coder:' prefix, or read modifiers attached
4428 to the filename, including them in the resulting expanded list.
4430 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4431 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4432 option,GetExceptionMessage(errno));
4434 /* loop over expanded filename list, and read then all in */
4435 for (i=0; i<argc; i++) {
4438 if (IfMagickTrue(_image_info->ping))
4439 new_images=PingImages(_image_info,argv[i],_exception);
4441 new_images=ReadImages(_image_info,argv[i],_exception);
4442 AppendImageToList(&_images, new_images);
4444 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4449 Note: Writing a empty image list is valid in specific cases
4451 if (LocaleCompare("write",option+1) == 0) {
4452 /* Note: arguments do not have percent escapes expanded */
4462 /* Need images, unless a "null:" output coder is used */
4463 if ( cli_wand->wand.images == (Image *) NULL ) {
4464 if ( LocaleCompare(arg1,"null:") == 0 )
4466 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4469 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4470 (void) DeleteImageRegistry(key);
4471 write_images=_images;
4473 write_images=CloneImageList(_images,_exception);
4474 write_info=CloneImageInfo(_image_info);
4475 (void) WriteImages(write_info,write_images,arg1,_exception);
4476 write_info=DestroyImageInfo(write_info);
4478 write_images=DestroyImageList(write_images);
4482 Parenthesis and Brace operations
4484 if (LocaleCompare("(",option) == 0) {
4485 /* stack 'push' images */
4493 node=cli_wand->image_list_stack;
4494 for ( ; node != (Stack *)NULL; node=node->next)
4496 if ( size >= MAX_STACK_DEPTH )
4497 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4498 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4499 if (node == (Stack *) NULL)
4500 CLIWandExceptionBreak(ResourceLimitFatalError,
4501 "MemoryAllocationFailed",option);
4502 node->data = (void *)cli_wand->wand.images;
4503 cli_wand->wand.images = NewImageList();
4504 node->next = cli_wand->image_list_stack;
4505 cli_wand->image_list_stack = node;
4507 /* handle respect-parenthesis */
4508 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4509 "respect-parenthesis"))))
4510 option="{"; /* fall-thru so as to push image settings too */
4513 /* fall thru to next if */
4515 if (LocaleCompare("{",option) == 0) {
4516 /* stack 'push' of image_info settings */
4524 node=cli_wand->image_info_stack;
4525 for ( ; node != (Stack *)NULL; node=node->next)
4527 if ( size >= MAX_STACK_DEPTH )
4528 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4529 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4530 if (node == (Stack *) NULL)
4531 CLIWandExceptionBreak(ResourceLimitFatalError,
4532 "MemoryAllocationFailed",option);
4534 node->data = (void *)cli_wand->wand.image_info;
4535 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4536 if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4537 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4539 cli_wand->wand.image_info = (ImageInfo *)node->data;
4540 node = (Stack *)RelinquishMagickMemory(node);
4544 node->next = cli_wand->image_info_stack;
4545 cli_wand->image_info_stack = node;
4549 if (LocaleCompare(")",option) == 0) {
4550 /* pop images from stack */
4554 node = (Stack *)cli_wand->image_list_stack;
4555 if ( node == (Stack *)NULL)
4556 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4557 cli_wand->image_list_stack = node->next;
4559 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4560 cli_wand->wand.images= (Image *)node->data;
4561 node = (Stack *)RelinquishMagickMemory(node);
4563 /* handle respect-parenthesis - of the previous 'pushed' settings */
4564 node = cli_wand->image_info_stack;
4565 if ( node != (Stack *)NULL)
4567 if (IfMagickTrue(IsStringTrue(GetImageOption(
4568 cli_wand->wand.image_info,"respect-parenthesis"))))
4569 option="}"; /* fall-thru so as to pop image settings too */
4575 /* fall thru to next if */
4577 if (LocaleCompare("}",option) == 0) {
4578 /* pop image_info settings from stack */
4582 node = (Stack *)cli_wand->image_info_stack;
4583 if ( node == (Stack *)NULL)
4584 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4585 cli_wand->image_info_stack = node->next;
4587 (void) DestroyImageInfo(cli_wand->wand.image_info);
4588 cli_wand->wand.image_info = (ImageInfo *)node->data;
4589 node = (Stack *)RelinquishMagickMemory(node);
4591 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4592 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4593 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4597 if (LocaleCompare("set",option+1) == 0)
4599 /* Note: arguments are not percent escapes expanded yet */
4600 /* Some settings are applied to each image in memory in turn.
4601 While others only need to be applied once globally.
4606 if (LocaleNCompare(arg1,"registry:",9) == 0)
4610 (void) DeleteImageRegistry(arg1+9);
4613 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4614 if (value == (char *) NULL)
4615 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4617 (void) SetImageRegistry(StringRegistryType,arg1+9,value,_exception);
4618 value=DestroyString(value);
4621 if (LocaleNCompare(arg1,"option:",7) == 0)
4623 /* delete equivelent artifact from all images (if any) */
4624 MagickResetIterator(&cli_wand->wand);
4625 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4626 (void) DeleteImageArtifact(_images,arg1+7);
4627 MagickResetIterator(&cli_wand->wand);
4628 /* now set/delete the global option as needed */
4630 (void) DeleteImageOption(_image_info,arg1+7);
4633 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4634 if (value == (char *) NULL)
4635 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4637 (void) SetImageOption(_image_info,arg1+7,value);
4638 value=DestroyString(value);
4641 if ( cli_wand->wand.images == (Image *) NULL )
4642 CLIWandExceptArgBreak(OptionError,"NoImagesFound",option,arg1);
4643 MagickResetIterator(&cli_wand->wand);
4644 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4650 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4651 (void) DeleteImageArtifact(_images,arg1+9);
4652 else if (LocaleNCompare(arg1,"property:",9) == 0)
4653 (void) DeleteImageProperty(_images,arg1+9);
4655 (void) DeleteImageProperty(_images,arg1);
4659 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
4661 value=InterpretImageProperties(_image_info,next,arg2,_exception);
4662 if (value == (char *) NULL)
4663 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4665 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4666 (void) SetImageArtifact(next,arg1+9,value);
4668 if (LocaleNCompare(arg1,"property:",9) == 0)
4669 (void) SetImageProperty(next,arg1+9,value,_exception);
4671 (void) SetImageProperty(next,arg1,value,_exception);
4672 value=DestroyString(value);
4676 MagickResetIterator(&cli_wand->wand);
4679 if (LocaleCompare("clone",option+1) == 0) {
4685 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4686 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4687 if ( cli_wand->image_list_stack == (Stack *)NULL)
4688 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4689 new_images = (Image *)cli_wand->image_list_stack->data;
4690 if (new_images == (Image *) NULL)
4691 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4692 new_images=CloneImages(new_images,arg1,_exception);
4693 if (new_images == (Image *) NULL)
4694 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4695 AppendImageToList(&_images,new_images);
4699 Informational Operations.
4701 Note that these do not require either a cli-wand or images!
4702 Though currently a cli-wand much be provided regardless.
4704 if (LocaleCompare("version",option+1) == 0)
4706 ListMagickVersion(stdout);
4709 if (LocaleCompare("list",option+1) == 0) {
4711 FUTURE: This 'switch' should really be part of MagickCore
4716 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4718 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4723 case MagickCoderOptions:
4725 (void) ListCoderInfo((FILE *) NULL,_exception);
4728 case MagickColorOptions:
4730 (void) ListColorInfo((FILE *) NULL,_exception);
4733 case MagickConfigureOptions:
4735 (void) ListConfigureInfo((FILE *) NULL,_exception);
4738 case MagickDelegateOptions:
4740 (void) ListDelegateInfo((FILE *) NULL,_exception);
4743 case MagickFontOptions:
4745 (void) ListTypeInfo((FILE *) NULL,_exception);
4748 case MagickFormatOptions:
4749 (void) ListMagickInfo((FILE *) NULL,_exception);
4751 case MagickLocaleOptions:
4752 (void) ListLocaleInfo((FILE *) NULL,_exception);
4754 case MagickLogOptions:
4755 (void) ListLogInfo((FILE *) NULL,_exception);
4757 case MagickMagicOptions:
4758 (void) ListMagicInfo((FILE *) NULL,_exception);
4760 case MagickMimeOptions:
4761 (void) ListMimeInfo((FILE *) NULL,_exception);
4763 case MagickModuleOptions:
4764 (void) ListModuleInfo((FILE *) NULL,_exception);
4766 case MagickPolicyOptions:
4767 (void) ListPolicyInfo((FILE *) NULL,_exception);
4769 case MagickResourceOptions:
4770 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4772 case MagickThresholdOptions:
4773 (void) ListThresholdMaps((FILE *) NULL,_exception);
4776 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4783 CLIWandException(OptionError,"UnrecognizedOption",option);
4785 } while (0); /* break to exit code. */
4788 /* clean up percent escape interpreted strings */
4790 arg1=DestroyString((char *)arg1);
4792 arg2=DestroyString((char *)arg2);
4803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4807 + C L I O p t i o n %
4811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4813 % CLIOption() Processes the given option using the given CLI Magick Wand.
4814 % The option arguments can be variable in number, though at this time no more
4815 % that two is actually used by any option (this may change). Excess options
4816 % are simply ignored.
4818 % If the cli_wand->command pointer is non-null, then it is assumed that the
4819 % option has already been search for up from the CommandOptions[] table in
4820 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4821 % routine will do the lookup instead. The pointer is reset afterward.
4823 % This action allows the caller to lookup and pre-handle any 'special'
4824 % options, (such as implicit reads) before calling this general option
4825 % handler to deal with 'standard' command line options.
4827 % The format of the CLIOption method is:
4829 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4831 % A description of each parameter follows:
4833 % o cli_wand: the main CLI Wand to use.
4835 % o option: The special option (with any switch char) to process
4837 % o args: any required arguments for an option (variable number)
4841 % CLIoption(cli_wand,"-read","rose:");
4842 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4843 % CLIoption(cli_wand,"-distort","SRT:","30");
4844 % CLIoption(cli_wand,"-write","rotated_rose.png");
4847 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4856 assert(cli_wand != (MagickCLI *) NULL);
4857 assert(cli_wand->signature == WandSignature);
4858 assert(cli_wand->wand.signature == WandSignature);
4859 if (IfMagickTrue(cli_wand->wand.debug))
4860 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4862 do { /* Break Code Block for error handling */
4864 /* get information about option */
4865 if ( cli_wand->command == (const OptionInfo *) NULL )
4866 cli_wand->command = GetCommandOptionInfo(option);
4868 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4869 option, cli_wand->command->mnemonic );
4871 option_type=(CommandOptionFlags) cli_wand->command->flags;
4873 if ( option_type == UndefinedOptionFlag )
4874 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4876 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4878 /* depreciated options */
4879 if ( (option_type & DeprecateOptionFlag) != 0 )
4880 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4882 /* options that this module does not handle */
4883 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
4884 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
4886 /* Get argument strings from VarArgs
4887 How can you determine arguments is enough was supplied? */
4889 count = cli_wand->command->type;
4894 va_start(operands,option);
4898 arg1=(const char *) va_arg(operands, const char *);
4900 arg2=(const char *) va_arg(operands, const char *);
4905 (void) FormatLocaleFile(stderr,
4906 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
4907 option,(long) count,option_type,arg1,arg2);
4912 Call the appropriate option handler
4915 /* FUTURE: this is temporary - get 'settings' to handle distribution of
4916 settings to images attributes,proprieties,artifacts */
4917 if ( cli_wand->wand.images != (Image *)NULL )
4918 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
4919 cli_wand->wand.exception);
4921 if ( (option_type & SettingOptionFlags) != 0 ) {
4922 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
4923 // FUTURE: Sync Specific Settings into Image Properities (not global)
4926 /* Operators that do not need images - read, write, stack, clone */
4927 if ( (option_type & NoImageOperatorFlag) != 0)
4928 CLINoImageOperator(cli_wand, option, arg1, arg2);
4930 /* FUTURE: The not a setting part below is a temporary hack due to
4931 * some options being both a Setting and a Simple operator.
4932 * Specifically -monitor, -depth, and -colorspace */
4933 if ( cli_wand->wand.images == (Image *)NULL )
4934 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
4935 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
4936 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
4938 /* Operators work on single images, and needs a loop over the images */
4939 if ( (option_type & SimpleOperatorFlag) != 0)
4940 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
4942 /* Operators that work on the image list as a whole */
4943 if ( (option_type & ListOperatorFlag) != 0 )
4944 CLIListOperatorImages(cli_wand, option, arg1, arg2);
4946 } while (0); /* end Break code block */
4948 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */