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 SetPixelRed(mask_image,GetPixelAlpha(mask_image,q),q);
1987 SetPixelGreen(mask_image,GetPixelAlpha(mask_image,q),q);
1988 SetPixelBlue(mask_image,GetPixelAlpha(mask_image,q),q);
1989 q+=GetPixelChannels(mask_image);
1991 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
1994 /* clean up and set the write mask */
1995 mask_view=DestroyCacheView(mask_view);
1996 mask_image->alpha_trait=BlendPixelTrait;
1997 (void) SetImageMask(_image,mask_image,_exception);
1998 mask_image=DestroyImage(mask_image);
2001 if (LocaleCompare("clip-path",option+1) == 0)
2003 (void) ClipImagePath(_image,arg1,normal_op,_exception);
2004 /* Note: Use "+clip-mask" remove the write mask added */
2007 if (LocaleCompare("colorize",option+1) == 0)
2009 if (IfMagickFalse(IsGeometry(arg1)))
2010 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2011 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2014 if (LocaleCompare("color-matrix",option+1) == 0)
2019 kernel=AcquireKernelInfo(arg1);
2020 if (kernel == (KernelInfo *) NULL)
2021 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2022 new_image=ColorMatrixImage(_image,kernel,_exception);
2023 kernel=DestroyKernelInfo(kernel);
2026 if (LocaleCompare("colors",option+1) == 0)
2028 /* Reduce the number of colors in the image.
2029 FUTURE: also provide 'plus version with image 'color counts'
2031 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2032 if (_quantize_info->number_colors == 0)
2033 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2034 if ((_image->storage_class == DirectClass) ||
2035 _image->colors > _quantize_info->number_colors)
2036 (void) QuantizeImage(_quantize_info,_image,_exception);
2038 (void) CompressImageColormap(_image,_exception);
2041 if (LocaleCompare("colorspace",option+1) == 0)
2043 /* WARNING: this is both a image_info setting (already done)
2044 and a operator to change image colorspace.
2046 FUTURE: default colorspace should be sRGB!
2047 Unless some type of 'linear colorspace' mode is set.
2049 Note that +colorspace sets "undefined" or no effect on
2050 new images, but forces images already in memory back to RGB!
2051 That seems to be a little strange!
2053 (void) TransformImageColorspace(_image,
2054 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2058 if (LocaleCompare("contrast",option+1) == 0)
2060 CLIWandWarnReplaced(normal_op?"-level":"+level");
2061 (void) ContrastImage(_image,normal_op,_exception);
2064 if (LocaleCompare("contrast-stretch",option+1) == 0)
2073 flags=ParseGeometry(arg1,&geometry_info);
2074 if ((flags & RhoValue) == 0)
2075 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2076 black_point=geometry_info.rho;
2077 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2079 if ((flags & PercentValue) != 0) {
2080 black_point*=(double) _image->columns*_image->rows/100.0;
2081 white_point*=(double) _image->columns*_image->rows/100.0;
2083 white_point=(double) _image->columns*_image->rows-
2085 (void) ContrastStretchImage(_image,black_point,white_point,
2089 if (LocaleCompare("convolve",option+1) == 0)
2094 kernel_info=AcquireKernelInfo(arg1);
2095 if (kernel_info == (KernelInfo *) NULL)
2096 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2097 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2099 kernel_info=DestroyKernelInfo(kernel_info);
2102 if (LocaleCompare("crop",option+1) == 0)
2104 /* WARNING: This can generate multiple images! */
2105 if (IfMagickFalse(IsGeometry(arg1)))
2106 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2107 new_image=CropImageToTiles(_image,arg1,_exception);
2110 if (LocaleCompare("cycle",option+1) == 0)
2112 if (IfMagickFalse(IsGeometry(arg1)))
2113 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2114 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2118 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2122 if (LocaleCompare("decipher",option+1) == 0)
2124 /* Note: arguments do not have percent escapes expanded */
2128 passkey=FileToStringInfo(arg1,~0,_exception);
2129 if (passkey == (StringInfo *) NULL)
2130 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2132 (void) PasskeyDecipherImage(_image,passkey,_exception);
2133 passkey=DestroyStringInfo(passkey);
2136 if (LocaleCompare("depth",option+1) == 0)
2138 /* The _image_info->depth setting has already been set
2139 We just need to apply it to all images in current sequence
2141 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2142 That is it really is an operation, not a setting! Arrgghhh
2144 FUTURE: this should not be an operator!!!
2146 (void) SetImageDepth(_image,_image_info->depth,_exception);
2149 if (LocaleCompare("deskew",option+1) == 0)
2155 if (IfMagickFalse(IsGeometry(arg1)))
2156 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2157 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2160 threshold=40.0*QuantumRange/100.0;
2161 new_image=DeskewImage(_image,threshold,_exception);
2164 if (LocaleCompare("despeckle",option+1) == 0)
2166 new_image=DespeckleImage(_image,_exception);
2169 if (LocaleCompare("distort",option+1) == 0)
2177 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2179 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2181 if ((DistortImageMethod) parse == ResizeDistortion)
2185 /* Special Case - Argument is actually a resize geometry!
2186 ** Convert that to an appropriate distortion argument array.
2187 ** FUTURE: make a separate special resize operator
2188 Roll into a resize special operator */
2189 if (IfMagickFalse(IsGeometry(arg2)))
2190 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2192 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2193 resize_args[0]=(double) geometry.width;
2194 resize_args[1]=(double) geometry.height;
2195 new_image=DistortImage(_image,(DistortImageMethod) parse,
2196 (size_t)2,resize_args,MagickTrue,_exception);
2199 /* convert argument string into an array of doubles */
2200 args = StringToArrayOfDoubles(arg2,&count,_exception);
2201 if (args == (double *)NULL )
2202 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2204 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2205 plus_alt_op,_exception);
2206 args=(double *) RelinquishMagickMemory(args);
2209 if (LocaleCompare("draw",option+1) == 0)
2211 (void) CloneString(&_draw_info->primitive,arg1);
2212 (void) DrawImage(_image,_draw_info,_exception);
2213 (void) CloneString(&_draw_info->primitive,(char *)NULL);
2216 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2220 if (LocaleCompare("edge",option+1) == 0)
2222 flags=ParseGeometry(arg1,&geometry_info);
2223 if ((flags & (RhoValue|SigmaValue)) == 0)
2224 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2225 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2228 if (LocaleCompare("emboss",option+1) == 0)
2230 flags=ParseGeometry(arg1,&geometry_info);
2231 if ((flags & (RhoValue|SigmaValue)) == 0)
2232 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2233 if ((flags & SigmaValue) == 0)
2234 geometry_info.sigma=1.0;
2235 new_image=EmbossImage(_image,geometry_info.rho,
2236 geometry_info.sigma,_exception);
2239 if (LocaleCompare("encipher",option+1) == 0)
2241 /* Note: arguments do not have percent escapes expanded */
2245 passkey=FileToStringInfo(arg1,~0,_exception);
2246 if (passkey != (StringInfo *) NULL)
2248 (void) PasskeyEncipherImage(_image,passkey,_exception);
2249 passkey=DestroyStringInfo(passkey);
2253 if (LocaleCompare("enhance",option+1) == 0)
2255 new_image=EnhanceImage(_image,_exception);
2258 if (LocaleCompare("equalize",option+1) == 0)
2260 (void) EqualizeImage(_image,_exception);
2263 if (LocaleCompare("evaluate",option+1) == 0)
2268 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2270 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2272 if (IfMagickFalse(IsGeometry(arg2)))
2273 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2274 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2275 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2279 if (LocaleCompare("extent",option+1) == 0)
2281 if (IfMagickFalse(IsGeometry(arg1)))
2282 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2283 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2284 if (geometry.width == 0)
2285 geometry.width=_image->columns;
2286 if (geometry.height == 0)
2287 geometry.height=_image->rows;
2288 new_image=ExtentImage(_image,&geometry,_exception);
2291 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2295 if (LocaleCompare("features",option+1) == 0)
2297 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
2299 (void) DeleteImageArtifact(_image,"identify:features");
2302 (void) SetImageArtifact(_image,"identify:features","true");
2303 (void) SetImageArtifact(_image,"verbose","true");
2306 if (LocaleCompare("flip",option+1) == 0)
2308 new_image=FlipImage(_image,_exception);
2311 if (LocaleCompare("flop",option+1) == 0)
2313 new_image=FlopImage(_image,_exception);
2316 if (LocaleCompare("floodfill",option+1) == 0)
2321 if (IfMagickFalse(IsGeometry(arg1)))
2322 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2323 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2324 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2325 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2326 geometry.y,plus_alt_op,_exception);
2329 if (LocaleCompare("frame",option+1) == 0)
2340 value=GetImageOption(_image_info,"compose");
2341 compose=OverCompositeOp; /* use Over not _image->compose */
2342 if (value != (const char *) NULL)
2343 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2345 if (IfMagickFalse(IsGeometry(arg1)))
2346 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2347 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2348 frame_info.width=geometry.width;
2349 frame_info.height=geometry.height;
2350 frame_info.outer_bevel=geometry.x;
2351 frame_info.inner_bevel=geometry.y;
2352 frame_info.x=(ssize_t) frame_info.width;
2353 frame_info.y=(ssize_t) frame_info.height;
2354 frame_info.width=_image->columns+2*frame_info.width;
2355 frame_info.height=_image->rows+2*frame_info.height;
2356 new_image=FrameImage(_image,&frame_info,compose,_exception);
2359 if (LocaleCompare("function",option+1) == 0)
2367 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2369 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2371 /* convert argument string into an array of doubles */
2372 args = StringToArrayOfDoubles(arg2,&count,_exception);
2373 if (args == (double *)NULL )
2374 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2376 (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2378 args=(double *) RelinquishMagickMemory(args);
2381 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2385 if (LocaleCompare("gamma",option+1) == 0)
2390 if (IfMagickFalse(IsGeometry(arg1)))
2391 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2392 constant=StringToDouble(arg1,(char **) NULL);
2394 /* Using Gamma, via a cache */
2396 constant=PerceptibleReciprocal(constant);
2397 (void) GammaImage(_image,constant,_exception);
2399 /* Using Evaluate POW, direct update of values - more accurite */
2401 constant=PerceptibleReciprocal(constant);
2402 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2404 /* Set gamma setting -- Old meaning of "+gamma"
2405 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2409 if (LocaleCompare("gaussian-blur",option+1) == 0)
2411 flags=ParseGeometry(arg1,&geometry_info);
2412 if ((flags & (RhoValue|SigmaValue)) == 0)
2413 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2414 if ((flags & SigmaValue) == 0)
2415 geometry_info.sigma=1.0;
2416 new_image=GaussianBlurImage(_image,geometry_info.rho,
2417 geometry_info.sigma,_exception);
2420 if (LocaleCompare("gaussian",option+1) == 0)
2422 CLIWandWarnReplaced("-gaussian-blur");
2423 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL);
2425 if (LocaleCompare("geometry",option+1) == 0)
2428 Record Image offset for composition. (A Setting)
2429 Resize last _image. (ListOperator) -- DEPRECIATE
2430 FUTURE: Why if no 'offset' does this resize ALL images?
2431 Also why is the setting recorded in the IMAGE non-sense!
2434 { /* remove the previous composition geometry offset! */
2435 if (_image->geometry != (char *) NULL)
2436 _image->geometry=DestroyString(_image->geometry);
2439 if (IfMagickFalse(IsGeometry(arg1)))
2440 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2441 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2442 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2443 (void) CloneString(&_image->geometry,arg1);
2445 new_image=ResizeImage(_image,geometry.width,geometry.height,
2446 _image->filter,_exception);
2449 if (LocaleCompare("grayscale",option+1) == 0)
2451 parse=ParseCommandOption(MagickPixelIntensityOptions,
2454 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2456 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2459 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2463 if (LocaleCompare("identify",option+1) == 0)
2469 format=GetImageOption(_image_info,"format");
2470 if (format == (char *) NULL) {
2471 (void) IdentifyImage(_image,stdout,_image_info->verbose,_exception);
2474 text=InterpretImageProperties(_image_info,_image,format,_exception);
2475 if (text == (char *) NULL)
2476 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2478 (void) fputs(text,stdout);
2479 (void) fputc('\n',stdout);
2480 text=DestroyString((char *)text);
2483 if (LocaleCompare("implode",option+1) == 0)
2485 flags=ParseGeometry(arg1,&geometry_info);
2486 if ((flags & RhoValue) == 0)
2487 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2488 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2492 if (LocaleCompare("interpolative-resize",option+1) == 0)
2494 /* FUTURE: New to IMv7
2495 Roll into a resize special operator */
2496 if (IfMagickFalse(IsGeometry(arg1)))
2497 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2498 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2499 new_image=InterpolativeResizeImage(_image,geometry.width,
2500 geometry.height,_image->interpolate,_exception);
2503 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2507 if (LocaleCompare("lat",option+1) == 0)
2509 flags=ParseGeometry(arg1,&geometry_info);
2510 if ((flags & (RhoValue|SigmaValue)) == 0)
2511 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2512 if ((flags & SigmaValue) == 0)
2513 geometry_info.sigma=1.0;
2514 if ((flags & PercentValue) != 0)
2515 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2516 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2517 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2521 if (LocaleCompare("level",option+1) == 0)
2531 flags=ParseGeometry(arg1,&geometry_info);
2532 if ((flags & RhoValue) == 0)
2533 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2534 black_point=geometry_info.rho;
2535 white_point=(double) QuantumRange;
2536 if ((flags & SigmaValue) != 0)
2537 white_point=geometry_info.sigma;
2539 if ((flags & XiValue) != 0)
2540 gamma=geometry_info.xi;
2541 if ((flags & PercentValue) != 0)
2543 black_point*=(double) (QuantumRange/100.0);
2544 white_point*=(double) (QuantumRange/100.0);
2546 if ((flags & SigmaValue) == 0)
2547 white_point=(double) QuantumRange-black_point;
2548 if (IfPlusOp || ((flags & AspectValue) != 0))
2549 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2551 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2554 if (LocaleCompare("level-colors",option+1) == 0)
2557 token[MaxTextExtent];
2566 p=(const char *) arg1;
2567 GetMagickToken(p,&p,token); /* get black point color */
2568 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2569 (void) QueryColorCompliance(token,AllCompliance,
2570 &black_point,_exception);
2572 (void) QueryColorCompliance("#000000",AllCompliance,
2573 &black_point,_exception);
2574 if (isalpha((int) token[0]) || (token[0] == '#'))
2575 GetMagickToken(p,&p,token);
2577 white_point=black_point; /* set everything to that color */
2580 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2581 GetMagickToken(p,&p,token); /* Get white point color. */
2582 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2583 (void) QueryColorCompliance(token,AllCompliance,
2584 &white_point,_exception);
2586 (void) QueryColorCompliance("#ffffff",AllCompliance,
2587 &white_point,_exception);
2589 (void) LevelImageColors(_image,&black_point,&white_point,
2590 plus_alt_op,_exception);
2593 if (LocaleCompare("linear-stretch",option+1) == 0)
2602 flags=ParseGeometry(arg1,&geometry_info);
2603 if ((flags & RhoValue) == 0)
2604 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2605 black_point=geometry_info.rho;
2606 white_point=(double) _image->columns*_image->rows;
2607 if ((flags & SigmaValue) != 0)
2608 white_point=geometry_info.sigma;
2609 if ((flags & PercentValue) != 0)
2611 black_point*=(double) _image->columns*_image->rows/100.0;
2612 white_point*=(double) _image->columns*_image->rows/100.0;
2614 if ((flags & SigmaValue) == 0)
2615 white_point=(double) _image->columns*_image->rows-
2617 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2620 if (LocaleCompare("liquid-rescale",option+1) == 0)
2622 /* FUTURE: Roll into a resize special operator */
2623 if (IfMagickFalse(IsGeometry(arg1)))
2624 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2625 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2626 if ((flags & XValue) == 0)
2628 if ((flags & YValue) == 0)
2630 new_image=LiquidRescaleImage(_image,geometry.width,
2631 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2634 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2638 if (LocaleCompare("map",option+1) == 0)
2640 CLIWandWarnReplaced("-remap");
2641 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL);
2644 if (LocaleCompare("mask",option+1) == 0)
2646 /* Note: arguments do not have percent escapes expanded */
2651 { /* Remove a mask. */
2652 (void) SetImageMask(_image,(Image *) NULL,_exception);
2655 /* Set the image mask. */
2656 mask=GetImageCache(_image_info,arg1,_exception);
2657 if (mask == (Image *) NULL)
2659 (void) SetImageMask(_image,mask,_exception);
2660 mask=DestroyImage(mask);
2663 if (LocaleCompare("matte",option+1) == 0)
2665 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2666 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2667 DeactivateAlphaChannel, _exception);
2670 if (LocaleCompare("median",option+1) == 0)
2672 CLIWandWarnReplaced("-statistic Median");
2673 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1);
2676 if (LocaleCompare("mode",option+1) == 0)
2678 /* FUTURE: note this is also a special "montage" option */
2679 CLIWandWarnReplaced("-statistic Mode");
2680 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1);
2683 if (LocaleCompare("modulate",option+1) == 0)
2685 if (IfMagickFalse(IsGeometry(arg1)))
2686 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2687 (void) ModulateImage(_image,arg1,_exception);
2690 if (LocaleCompare("monitor",option+1) == 0)
2692 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2693 (MagickProgressMonitor) NULL,(void *) NULL);
2696 if (LocaleCompare("monochrome",option+1) == 0)
2698 (void) SetImageType(_image,BilevelType,_exception);
2701 if (LocaleCompare("morphology",option+1) == 0)
2704 token[MaxTextExtent];
2716 GetMagickToken(p,&p,token);
2717 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2719 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2722 GetMagickToken(p,&p,token);
2723 if ((*p == ':') || (*p == ','))
2724 GetMagickToken(p,&p,token);
2726 iterations=(ssize_t) StringToLong(p);
2727 kernel=AcquireKernelInfo(arg2);
2728 if (kernel == (KernelInfo *) NULL)
2729 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",
2731 new_image=MorphologyImage(_image,(MorphologyMethod)parse,
2732 iterations,kernel,_exception);
2733 kernel=DestroyKernelInfo(kernel);
2736 if (LocaleCompare("motion-blur",option+1) == 0)
2738 flags=ParseGeometry(arg1,&geometry_info);
2739 if ((flags & (RhoValue|SigmaValue)) == 0)
2740 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2741 if ((flags & SigmaValue) == 0)
2742 geometry_info.sigma=1.0;
2743 new_image=MotionBlurImage(_image,geometry_info.rho,
2744 geometry_info.sigma,geometry_info.xi,_exception);
2747 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2751 if (LocaleCompare("negate",option+1) == 0)
2753 (void) NegateImage(_image, plus_alt_op, _exception);
2756 if (LocaleCompare("noise",option+1) == 0)
2766 CLIWandWarnReplaced("-statistic NonPeak");
2767 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1);
2770 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2772 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2775 value=GetImageOption(_image_info,"attenuate");
2776 if (value != (const char *) NULL)
2777 attenuate=StringToDouble(value,(char **) NULL);
2778 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2782 if (LocaleCompare("normalize",option+1) == 0)
2784 (void) NormalizeImage(_image,_exception);
2787 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2791 if (LocaleCompare("opaque",option+1) == 0)
2796 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2797 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,plus_alt_op,
2801 if (LocaleCompare("ordered-dither",option+1) == 0)
2803 (void) OrderedPosterizeImage(_image,arg1,_exception);
2806 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2810 if (LocaleCompare("paint",option+1) == 0)
2812 flags=ParseGeometry(arg1,&geometry_info);
2813 if ((flags & (RhoValue|SigmaValue)) == 0)
2814 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2815 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2819 if (LocaleCompare("perceptible",option+1) == 0)
2821 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2825 if (LocaleCompare("polaroid",option+1) == 0)
2837 random_info=AcquireRandomInfo();
2838 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2839 random_info=DestroyRandomInfo(random_info);
2842 flags=ParseGeometry(arg1,&geometry_info);
2843 if ((flags & RhoValue) == 0)
2844 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2845 angle=geometry_info.rho;
2847 caption=GetImageProperty(_image,"caption",_exception);
2848 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2849 _image->interpolate,_exception);
2852 if (LocaleCompare("posterize",option+1) == 0)
2854 flags=ParseGeometry(arg1,&geometry_info);
2855 if ((flags & RhoValue) == 0)
2856 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2857 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2858 _quantize_info->dither_method,_exception);
2861 if (LocaleCompare("preview",option+1) == 0)
2863 /* FUTURE: should be a 'Genesis' option?
2864 Option however is also in WandSettingOptionInfo()
2867 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2869 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2871 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2874 if (LocaleCompare("profile",option+1) == 0)
2876 /* Note: arguments do not have percent escapes expanded */
2890 { /* Remove a profile from the _image. */
2891 (void) ProfileImage(_image,arg1,(const unsigned char *)
2895 /* Associate a profile with the _image. */
2896 profile_info=CloneImageInfo(_image_info);
2897 profile=GetImageProfile(_image,"iptc");
2898 if (profile != (StringInfo *) NULL)
2899 profile_info->profile=(void *) CloneStringInfo(profile);
2900 profile_image=GetImageCache(profile_info,arg1,_exception);
2901 profile_info=DestroyImageInfo(profile_info);
2902 if (profile_image == (Image *) NULL)
2907 profile_info=CloneImageInfo(_image_info);
2908 (void) CopyMagickString(profile_info->filename,arg1,
2910 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
2911 if (profile != (StringInfo *) NULL)
2913 (void) ProfileImage(_image,profile_info->magick,
2914 GetStringInfoDatum(profile),(size_t)
2915 GetStringInfoLength(profile),_exception);
2916 profile=DestroyStringInfo(profile);
2918 profile_info=DestroyImageInfo(profile_info);
2921 ResetImageProfileIterator(profile_image);
2922 name=GetNextImageProfile(profile_image);
2923 while (name != (const char *) NULL)
2925 profile=GetImageProfile(profile_image,name);
2926 if (profile != (StringInfo *) NULL)
2927 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
2928 (size_t) GetStringInfoLength(profile),_exception);
2929 name=GetNextImageProfile(profile_image);
2931 profile_image=DestroyImage(profile_image);
2934 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2938 if (LocaleCompare("radial-blur",option+1) == 0)
2940 flags=ParseGeometry(arg1,&geometry_info);
2941 if ((flags & RhoValue) == 0)
2942 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2943 new_image=RadialBlurImage(_image,geometry_info.rho,_exception);
2946 if (LocaleCompare("raise",option+1) == 0)
2948 if (IfMagickFalse(IsGeometry(arg1)))
2949 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2950 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2951 (void) RaiseImage(_image,&geometry,normal_op,_exception);
2954 if (LocaleCompare("random-threshold",option+1) == 0)
2956 if (IfMagickFalse(IsGeometry(arg1)))
2957 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2958 (void) RandomThresholdImage(_image,arg1,_exception);
2961 if (LocaleCompare("recolor",option+1) == 0)
2963 CLIWandWarnReplaced("-color-matrix");
2964 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL);
2966 if (LocaleCompare("remap",option+1) == 0)
2968 /* Note: arguments do not have percent escapes expanded */
2972 remap_image=GetImageCache(_image_info,arg1,_exception);
2973 if (remap_image == (Image *) NULL)
2975 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
2976 remap_image=DestroyImage(remap_image);
2979 if (LocaleCompare("repage",option+1) == 0)
2983 if (IfMagickFalse(IsGeometry(arg1)))
2984 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
2986 (void) ResetImagePage(_image,arg1);
2989 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
2992 if (LocaleCompare("resample",option+1) == 0)
2994 /* FUTURE: Roll into a resize special operation */
2995 flags=ParseGeometry(arg1,&geometry_info);
2996 if ((flags & (RhoValue|SigmaValue)) == 0)
2997 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2998 if ((flags & SigmaValue) == 0)
2999 geometry_info.sigma=geometry_info.rho;
3000 new_image=ResampleImage(_image,geometry_info.rho,
3001 geometry_info.sigma,_image->filter,_exception);
3004 if (LocaleCompare("resize",option+1) == 0)
3006 if (IfMagickFalse(IsGeometry(arg1)))
3007 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3008 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3009 new_image=ResizeImage(_image,geometry.width,geometry.height,
3010 _image->filter,_exception);
3013 if (LocaleCompare("roll",option+1) == 0)
3015 if (IfMagickFalse(IsGeometry(arg1)))
3016 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3017 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3018 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3021 if (LocaleCompare("rotate",option+1) == 0)
3023 flags=ParseGeometry(arg1,&geometry_info);
3024 if ((flags & RhoValue) == 0)
3025 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3026 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3028 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3030 new_image=RotateImage(_image,geometry_info.rho,_exception);
3033 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3037 if (LocaleCompare("sample",option+1) == 0)
3039 /* FUTURE: Roll into a resize special operator */
3040 if (IfMagickFalse(IsGeometry(arg1)))
3041 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3042 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3043 new_image=SampleImage(_image,geometry.width,geometry.height,
3047 if (LocaleCompare("scale",option+1) == 0)
3049 /* FUTURE: Roll into a resize special operator */
3050 if (IfMagickFalse(IsGeometry(arg1)))
3051 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3052 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3053 new_image=ScaleImage(_image,geometry.width,geometry.height,
3057 if (LocaleCompare("segment",option+1) == 0)
3059 flags=ParseGeometry(arg1,&geometry_info);
3060 if ((flags & (RhoValue|SigmaValue)) == 0)
3061 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3062 if ((flags & SigmaValue) == 0)
3063 geometry_info.sigma=1.0;
3064 (void) SegmentImage(_image,_image->colorspace,
3065 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3069 if (LocaleCompare("selective-blur",option+1) == 0)
3071 flags=ParseGeometry(arg1,&geometry_info);
3072 if ((flags & (RhoValue|SigmaValue)) == 0)
3073 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3074 if ((flags & SigmaValue) == 0)
3075 geometry_info.sigma=1.0;
3076 if ((flags & PercentValue) != 0)
3077 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3078 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3079 geometry_info.sigma,geometry_info.xi,_exception);
3082 if (LocaleCompare("separate",option+1) == 0)
3084 /* WARNING: This can generate multiple images! */
3085 /* FUTURE - this may be replaced by a "-channel" method */
3086 new_image=SeparateImages(_image,_exception);
3089 if (LocaleCompare("sepia-tone",option+1) == 0)
3091 if (IfMagickFalse(IsGeometry(arg1)))
3092 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3093 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3094 (double) QuantumRange+1.0),_exception);
3097 if (LocaleCompare("shade",option+1) == 0)
3099 flags=ParseGeometry(arg1,&geometry_info);
3100 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3101 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3102 new_image=ShadeImage(_image,normal_op,geometry_info.rho,
3103 geometry_info.sigma,_exception);
3106 if (LocaleCompare("shadow",option+1) == 0)
3108 flags=ParseGeometry(arg1,&geometry_info);
3109 if ((flags & (RhoValue|SigmaValue)) == 0)
3110 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3111 if ((flags & SigmaValue) == 0)
3112 geometry_info.sigma=1.0;
3113 if ((flags & XiValue) == 0)
3114 geometry_info.xi=4.0;
3115 if ((flags & PsiValue) == 0)
3116 geometry_info.psi=4.0;
3117 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3118 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3119 ceil(geometry_info.psi-0.5),_exception);
3122 if (LocaleCompare("sharpen",option+1) == 0)
3124 flags=ParseGeometry(arg1,&geometry_info);
3125 if ((flags & (RhoValue|SigmaValue)) == 0)
3126 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3127 if ((flags & SigmaValue) == 0)
3128 geometry_info.sigma=1.0;
3129 if ((flags & XiValue) == 0)
3130 geometry_info.xi=0.0;
3131 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3135 if (LocaleCompare("shave",option+1) == 0)
3137 if (IfMagickFalse(IsGeometry(arg1)))
3138 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3139 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3140 new_image=ShaveImage(_image,&geometry,_exception);
3143 if (LocaleCompare("shear",option+1) == 0)
3145 flags=ParseGeometry(arg1,&geometry_info);
3146 if ((flags & RhoValue) == 0)
3147 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3148 if ((flags & SigmaValue) == 0)
3149 geometry_info.sigma=geometry_info.rho;
3150 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3154 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3156 flags=ParseGeometry(arg1,&geometry_info);
3157 if ((flags & RhoValue) == 0)
3158 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3159 if ((flags & SigmaValue) == 0)
3160 geometry_info.sigma=(double) QuantumRange/2.0;
3161 if ((flags & PercentValue) != 0)
3162 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3164 (void) SigmoidalContrastImage(_image,normal_op,geometry_info.rho,
3165 geometry_info.sigma,_exception);
3168 if (LocaleCompare("sketch",option+1) == 0)
3170 flags=ParseGeometry(arg1,&geometry_info);
3171 if ((flags & (RhoValue|SigmaValue)) == 0)
3172 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3173 if ((flags & SigmaValue) == 0)
3174 geometry_info.sigma=1.0;
3175 new_image=SketchImage(_image,geometry_info.rho,
3176 geometry_info.sigma,geometry_info.xi,_exception);
3179 if (LocaleCompare("solarize",option+1) == 0)
3181 if (IfMagickFalse(IsGeometry(arg1)))
3182 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3183 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3184 QuantumRange+1.0),_exception);
3187 if (LocaleCompare("sparse-color",option+1) == 0)
3189 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3191 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3193 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3197 if (LocaleCompare("splice",option+1) == 0)
3199 if (IfMagickFalse(IsGeometry(arg1)))
3200 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3201 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3202 new_image=SpliceImage(_image,&geometry,_exception);
3205 if (LocaleCompare("spread",option+1) == 0)
3207 flags=ParseGeometry(arg1,&geometry_info);
3208 if ((flags & RhoValue) == 0)
3209 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3210 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3214 if (LocaleCompare("statistic",option+1) == 0)
3216 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3218 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3220 flags=ParseGeometry(arg2,&geometry_info);
3221 if ((flags & RhoValue) == 0)
3222 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3223 if ((flags & SigmaValue) == 0)
3224 geometry_info.sigma=geometry_info.rho;
3225 new_image=StatisticImage(_image,(StatisticType)parse,
3226 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3230 if (LocaleCompare("strip",option+1) == 0)
3232 (void) StripImage(_image,_exception);
3235 if (LocaleCompare("swirl",option+1) == 0)
3237 flags=ParseGeometry(arg1,&geometry_info);
3238 if ((flags & RhoValue) == 0)
3239 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3240 new_image=SwirlImage(_image,geometry_info.rho,
3241 _image->interpolate,_exception);
3244 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3248 if (LocaleCompare("threshold",option+1) == 0)
3253 threshold=(double) QuantumRange/2;
3255 if (IfMagickFalse(IsGeometry(arg1)))
3256 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3257 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3259 (void) BilevelImage(_image,threshold,_exception);
3262 if (LocaleCompare("thumbnail",option+1) == 0)
3264 if (IfMagickFalse(IsGeometry(arg1)))
3265 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3266 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3267 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3271 if (LocaleCompare("tint",option+1) == 0)
3273 if (IfMagickFalse(IsGeometry(arg1)))
3274 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3275 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3278 if (LocaleCompare("transform",option+1) == 0)
3280 CLIWandWarnReplaced("+distort AffineProjection");
3281 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3284 if (LocaleCompare("transparent",option+1) == 0)
3289 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3290 (void) TransparentPaintImage(_image,&target,(Quantum)
3291 TransparentAlpha,plus_alt_op,_exception);
3294 if (LocaleCompare("transpose",option+1) == 0)
3296 new_image=TransposeImage(_image,_exception);
3299 if (LocaleCompare("transverse",option+1) == 0)
3301 new_image=TransverseImage(_image,_exception);
3304 if (LocaleCompare("trim",option+1) == 0)
3306 new_image=TrimImage(_image,_exception);
3309 if (LocaleCompare("type",option+1) == 0)
3311 /* Note that "type" setting should have already been defined */
3312 (void) SetImageType(_image,_image_info->type,_exception);
3315 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3319 if (LocaleCompare("unique",option+1) == 0)
3321 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3322 Option is not documented, bt appears to be for "identify".
3323 We may need a identify specific verbose!
3326 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3329 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3330 (void) SetImageArtifact(_image,"verbose","true");
3333 if (LocaleCompare("unique-colors",option+1) == 0)
3335 new_image=UniqueImageColors(_image,_exception);
3338 if (LocaleCompare("unsharp",option+1) == 0)
3340 flags=ParseGeometry(arg1,&geometry_info);
3341 if ((flags & (RhoValue|SigmaValue)) == 0)
3342 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3343 if ((flags & SigmaValue) == 0)
3344 geometry_info.sigma=1.0;
3345 if ((flags & XiValue) == 0)
3346 geometry_info.xi=1.0;
3347 if ((flags & PsiValue) == 0)
3348 geometry_info.psi=0.05;
3349 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3350 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3353 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3357 if (LocaleCompare("verbose",option+1) == 0)
3359 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3360 three places! ImageArtifact ImageOption _image_info->verbose
3361 Some how new images also get this artifact!
3363 (void) SetImageArtifact(_image,option+1,
3364 IfNormalOp ? "true" : "false" );
3367 if (LocaleCompare("vignette",option+1) == 0)
3369 flags=ParseGeometry(arg1,&geometry_info);
3370 if ((flags & (RhoValue|SigmaValue)) == 0)
3371 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3372 if ((flags & SigmaValue) == 0)
3373 geometry_info.sigma=1.0;
3374 if ((flags & XiValue) == 0)
3375 geometry_info.xi=0.1*_image->columns;
3376 if ((flags & PsiValue) == 0)
3377 geometry_info.psi=0.1*_image->rows;
3378 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3379 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3380 ceil(geometry_info.psi-0.5),_exception);
3383 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3387 if (LocaleCompare("wave",option+1) == 0)
3389 flags=ParseGeometry(arg1,&geometry_info);
3390 if ((flags & (RhoValue|SigmaValue)) == 0)
3391 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3392 if ((flags & SigmaValue) == 0)
3393 geometry_info.sigma=1.0;
3394 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3395 _image->interpolate,_exception);
3398 if (LocaleCompare("white-threshold",option+1) == 0)
3400 if (IfMagickFalse(IsGeometry(arg1)))
3401 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3402 (void) WhiteThresholdImage(_image,arg1,_exception);
3405 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3408 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3410 /* clean up percent escape interpreted strings */
3412 arg1=DestroyString((char *)arg1);
3414 arg2=DestroyString((char *)arg2);
3416 /* Replace current image with any image that was generated
3417 and set image point to last image (so image->next is correct) */
3418 if (new_image != (Image *) NULL)
3419 ReplaceImageInListReturnLast(&_image,new_image);
3424 #undef _quantize_info
3433 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3434 const char *option,const char *arg1,const char *arg2)
3436 #if !USE_WAND_METHODS
3442 assert(cli_wand != (MagickCLI *) NULL);
3443 assert(cli_wand->signature == WandSignature);
3444 assert(cli_wand->wand.signature == WandSignature);
3445 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3446 if (IfMagickTrue(cli_wand->wand.debug))
3447 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
3449 #if !USE_WAND_METHODS
3450 /* FUTURE add appropriate tracing */
3452 n=GetImageListLength(cli_wand->wand.images);
3453 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3456 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3457 if ( cli_wand->wand.images->next == (Image *) NULL )
3459 cli_wand->wand.images=cli_wand->wand.images->next;
3462 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3464 MagickResetIterator(&cli_wand->wand);
3465 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3466 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3467 MagickResetIterator(&cli_wand->wand);
3473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3477 + C L I L i s t O p e r a t o r I m a g e s %
3481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3483 % CLIListOperatorImages() applies a single operation that is apply to the
3484 % entire image list as a whole. The result is often a complete replacment
3485 % of the image list with a completely new list, or with just a single image
3488 % The format of the MogrifyImage method is:
3490 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3491 % const char *option,const char *arg1,const char *arg2)
3493 % A description of each parameter follows:
3495 % o cli_wand: structure holding settings to be applied
3497 % o option: The option string for the operation
3499 % o arg1, arg2: optional argument strings to the operation
3500 % arg2 is currently not used
3503 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3504 const char *option,const char *arg1n,const char *arg2n)
3506 const char /* For percent escape interpretImageProperties() */
3519 #define _image_info (cli_wand->wand.image_info)
3520 #define _images (cli_wand->wand.images)
3521 #define _exception (cli_wand->wand.exception)
3522 #define _draw_info (cli_wand->draw_info)
3523 #define _quantize_info (cli_wand->quantize_info)
3524 #define _process_flags (cli_wand->process_flags)
3525 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3526 #define IfNormalOp (*option=='-')
3527 #define IfPlusOp (*option!='-')
3528 #define normal_op IsMagickTrue(IfNormalOp)
3530 assert(cli_wand != (MagickCLI *) NULL);
3531 assert(cli_wand->signature == WandSignature);
3532 assert(cli_wand->wand.signature == WandSignature);
3533 assert(_images != (Image *) NULL); /* _images must be present */
3534 if (IfMagickTrue(cli_wand->wand.debug))
3535 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
3537 /* Interpret Percent Escapes in Arguments - using first image */
3540 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3541 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3542 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3543 /* Interpret Percent escapes in argument 1 */
3544 if (arg1n != (char *) NULL) {
3545 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3546 if (arg1 == (char *) NULL) {
3547 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3548 arg1=arg1n; /* use the given argument as is */
3551 if (arg2n != (char *) NULL) {
3552 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3553 if (arg2 == (char *) NULL) {
3554 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3555 arg2=arg2n; /* use the given argument as is */
3559 #undef _process_flags
3563 (void) FormatLocaleFile(stderr,
3564 "CLIListOperatorImages: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
3568 new_images=NewImageList();
3570 switch (*(option+1))
3574 if (LocaleCompare("append",option+1) == 0)
3576 new_images=AppendImages(_images,normal_op,_exception);
3579 if (LocaleCompare("average",option+1) == 0)
3581 CLIWandWarnReplaced("-evaluate-sequence Mean");
3582 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3585 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3589 if (LocaleCompare("channel-fx",option+1) == 0)
3591 new_images=ChannelFxImage(_images,arg1,_exception);
3594 if (LocaleCompare("clut",option+1) == 0)
3599 /* FUTURE - make this a compose option, and thus can be used
3600 with layers compose or even compose last image over all other
3603 new_images=RemoveFirstImageFromList(&_images);
3604 clut_image=RemoveLastImageFromList(&_images);
3605 /* FUTURE - produce Exception, rather than silent fail */
3606 if (clut_image == (Image *) NULL)
3608 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3609 clut_image=DestroyImage(clut_image);
3612 if (LocaleCompare("coalesce",option+1) == 0)
3614 new_images=CoalesceImages(_images,_exception);
3617 if (LocaleCompare("combine",option+1) == 0)
3619 /* FUTURE - this may be replaced by a 'channel' method */
3620 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3622 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3624 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3627 if (LocaleCompare("composite",option+1) == 0)
3645 /* Compose value from "-compose" option only */
3646 value=GetImageOption(_image_info,"compose");
3647 if (value == (const char *) NULL)
3648 compose=OverCompositeOp; /* use Over not source_image->compose */
3650 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3653 /* Get "clip-to-self" expert setting (false is normal) */
3654 value=GetImageOption(_image_info,"compose:clip-to-self");
3655 if (value == (const char *) NULL)
3656 clip_to_self=MagickTrue;
3658 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3659 "compose:clip-to-self")); /* if this is true */
3660 value=GetImageOption(_image_info,"compose:outside-overlay");
3661 if (value != (const char *) NULL) { /* or this false */
3662 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3663 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3666 new_images=RemoveFirstImageFromList(&_images);
3667 source_image=RemoveFirstImageFromList(&_images);
3668 if (source_image == (Image *) NULL)
3669 break; /* FUTURE - produce Exception, rather than silent fail */
3671 /* FUTURE - this should not be here! - should be part of -geometry */
3672 (void) TransformImage(&source_image,(char *) NULL,
3673 source_image->geometry,_exception);
3674 SetGeometry(source_image,&geometry);
3675 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3676 GravityAdjustGeometry(new_images->columns,new_images->rows,
3677 new_images->gravity, &geometry);
3678 mask_image=RemoveFirstImageFromList(&_images);
3679 if (mask_image != (Image *) NULL)
3681 if ((compose == DisplaceCompositeOp) ||
3682 (compose == DistortCompositeOp))
3683 status&=CompositeImage(source_image,mask_image,
3684 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3693 source_geometry.width=mask_image->columns;
3694 source_geometry.height=mask_image->rows;
3695 source_geometry.x=(-geometry.x);
3696 source_geometry.y=(-geometry.y);
3699 image=ExtentImage(source_image,&source_geometry,_exception);
3700 if (image != (Image *) NULL)
3702 source_image=DestroyImage(source_image);
3705 status&=CompositeImage(source_image,mask_image,
3706 IntensityCompositeOp,MagickTrue,0,0,_exception);
3708 mask_image=DestroyImage(mask_image);
3710 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3711 geometry.x,geometry.y,_exception);
3712 source_image=DestroyImage(source_image);
3715 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3719 if (LocaleCompare("deconstruct",option+1) == 0)
3721 CLIWandWarnReplaced("-layer CompareAny");
3722 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3725 if (LocaleCompare("delete",option+1) == 0)
3728 DeleteImages(&_images,arg1,_exception);
3730 DeleteImages(&_images,"-1",_exception);
3733 if (LocaleCompare("duplicate",option+1) == 0)
3743 if (IfMagickFalse(IsGeometry(arg1)))
3744 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3746 number_duplicates=(size_t) StringToLong(arg1);
3748 if (p == (const char *) NULL)
3749 new_images=DuplicateImages(_images,number_duplicates,"-1",
3752 new_images=DuplicateImages(_images,number_duplicates,p,
3756 new_images=DuplicateImages(_images,1,"-1",_exception);
3757 AppendImageToList(&_images, new_images);
3758 new_images=(Image *)NULL;
3761 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3765 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3767 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3769 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3771 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3775 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3779 if (LocaleCompare("fft",option+1) == 0)
3781 new_images=ForwardFourierTransformImage(_images,normal_op,_exception);
3784 if (LocaleCompare("flatten",option+1) == 0)
3786 /* REDIRECTED to use -layers flatten instead */
3787 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3790 if (LocaleCompare("fx",option+1) == 0)
3792 new_images=FxImage(_images,arg1,_exception);
3795 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3799 if (LocaleCompare("hald-clut",option+1) == 0)
3801 /* FUTURE - make this a compose option (and thus layers compose )
3802 or perhaps compose last image over all other _images.
3807 new_images=RemoveFirstImageFromList(&_images);
3808 hald_image=RemoveLastImageFromList(&_images);
3809 if (hald_image == (Image *) NULL)
3811 (void) HaldClutImage(new_images,hald_image,_exception);
3812 hald_image=DestroyImage(hald_image);
3815 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3819 if (LocaleCompare("ift",option+1) == 0)
3825 magnitude_image=RemoveFirstImageFromList(&_images);
3826 phase_image=RemoveFirstImageFromList(&_images);
3827 /* FUTURE - produce Exception, rather than silent fail */
3828 if (phase_image == (Image *) NULL)
3830 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3831 normal_op,_exception);
3832 magnitude_image=DestroyImage(magnitude_image);
3833 phase_image=DestroyImage(phase_image);
3836 if (LocaleCompare("insert",option+1) == 0)
3845 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3846 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3848 insert_image=RemoveLastImageFromList(&_images);
3850 index=(ssize_t) StringToLong(arg1);
3851 index_image=insert_image;
3853 PrependImageToList(&_images,insert_image);
3854 else if (index == (ssize_t) GetImageListLength(_images))
3855 AppendImageToList(&_images,insert_image);
3858 index_image=GetImageFromList(_images,index-1);
3859 if (index_image == (Image *) NULL)
3860 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3861 InsertImageInList(&index_image,insert_image);
3863 _images=GetFirstImageInList(index_image);
3866 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3870 if (LocaleCompare("layers",option+1) == 0)
3872 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3874 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3876 switch ((LayerMethod) parse)
3880 new_images=CoalesceImages(_images,_exception);
3883 case CompareAnyLayer:
3884 case CompareClearLayer:
3885 case CompareOverlayLayer:
3888 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
3895 case TrimBoundsLayer:
3897 new_images=MergeImageLayers(_images,(LayerMethod) parse,
3903 new_images=DisposeImages(_images,_exception);
3906 case OptimizeImageLayer:
3908 new_images=OptimizeImageLayers(_images,_exception);
3911 case OptimizePlusLayer:
3913 new_images=OptimizePlusImageLayers(_images,_exception);
3916 case OptimizeTransLayer:
3918 OptimizeImageTransparency(_images,_exception);
3921 case RemoveDupsLayer:
3923 RemoveDuplicateLayers(&_images,_exception);
3926 case RemoveZeroLayer:
3928 RemoveZeroDelayLayers(&_images,_exception);
3932 { /* General Purpose, GIF Animation Optimizer. */
3933 new_images=CoalesceImages(_images,_exception);
3934 if (new_images == (Image *) NULL)
3936 _images=DestroyImageList(_images);
3937 _images=OptimizeImageLayers(new_images,_exception);
3938 if (_images == (Image *) NULL)
3940 new_images=DestroyImageList(new_images);
3941 OptimizeImageTransparency(_images,_exception);
3942 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
3946 case CompositeLayer:
3960 value=GetImageOption(_image_info,"compose");
3961 compose=OverCompositeOp; /* Default to Over */
3962 if (value != (const char *) NULL)
3963 compose=(CompositeOperator) ParseCommandOption(
3964 MagickComposeOptions,MagickFalse,value);
3966 /* Split image sequence at the first 'NULL:' image. */
3968 while (source != (Image *) NULL)
3970 source=GetNextImageInList(source);
3971 if ((source != (Image *) NULL) &&
3972 (LocaleCompare(source->magick,"NULL") == 0))
3975 if (source != (Image *) NULL)
3977 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
3978 (GetNextImageInList(source) == (Image *) NULL))
3979 source=(Image *) NULL;
3981 { /* Separate the two lists, junk the null: image. */
3982 source=SplitImageList(source->previous);
3983 DeleteImageFromList(&source);
3986 if (source == (Image *) NULL)
3988 (void) ThrowMagickException(_exception,GetMagickModule(),
3989 OptionError,"MissingNullSeparator","layers Composite");
3992 /* Adjust offset with gravity and virtual canvas. */
3993 SetGeometry(_images,&geometry);
3994 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
3995 geometry.width=source->page.width != 0 ?
3996 source->page.width : source->columns;
3997 geometry.height=source->page.height != 0 ?
3998 source->page.height : source->rows;
3999 GravityAdjustGeometry(_images->page.width != 0 ?
4000 _images->page.width : _images->columns,
4001 _images->page.height != 0 ? _images->page.height :
4002 _images->rows,_images->gravity,&geometry);
4004 /* Compose the two image sequences together */
4005 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4007 source=DestroyImageList(source);
4013 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4017 if (LocaleCompare("map",option+1) == 0)
4019 CLIWandWarnReplaced("+remap");
4020 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4023 if (LocaleCompare("morph",option+1) == 0)
4028 if (IfMagickFalse(IsGeometry(arg1)))
4029 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4030 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4032 if (morph_image == (Image *) NULL)
4034 _images=DestroyImageList(_images);
4035 _images=morph_image;
4038 if (LocaleCompare("mosaic",option+1) == 0)
4040 /* REDIRECTED to use -layers mosaic instead */
4041 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4044 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4048 if (LocaleCompare("poly",option+1) == 0)
4056 /* convert argument string into an array of doubles */
4057 args = StringToArrayOfDoubles(arg2,&count,_exception);
4058 if (args == (double *)NULL )
4059 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4060 new_images=PolynomialImage(_images,count >> 1,args,_exception);
4061 args=(double *) RelinquishMagickMemory(args);
4064 if (LocaleCompare("print",option+1) == 0)
4066 (void) FormatLocaleFile(stdout,"%s",arg1);
4069 if (LocaleCompare("process",option+1) == 0)
4071 /* FUTURE: better parsing using ScriptToken() from string ??? */
4079 arguments=StringToArgv(arg1,&number_arguments);
4080 if (arguments == (char **) NULL)
4082 if (strchr(arguments[1],'=') != (char *) NULL)
4103 Support old style syntax, filter="-option arg1".
4105 length=strlen(arg1);
4106 token=(char *) NULL;
4107 if (~length >= (MaxTextExtent-1))
4108 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4110 if (token == (char *) NULL)
4114 token_info=AcquireTokenInfo();
4115 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4116 "\"",'\0',&breaker,&next,"e);
4117 token_info=DestroyTokenInfo(token_info);
4123 argv=(&(arguments[next]));
4124 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4127 token=DestroyString(token);
4130 (void) SubstituteString(&arguments[1],"-","");
4131 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4132 number_arguments-2,(const char **) arguments+2,_exception);
4133 for (j=0; j < number_arguments; j++)
4134 arguments[j]=DestroyString(arguments[j]);
4135 arguments=(char **) RelinquishMagickMemory(arguments);
4138 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4142 if (LocaleCompare("remap",option+1) == 0)
4144 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4147 if (LocaleCompare("reverse",option+1) == 0)
4149 ReverseImageList(&_images);
4152 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4156 if (LocaleCompare("smush",option+1) == 0)
4158 /* FUTURE: this option needs more work to make better */
4162 if (IfMagickFalse(IsGeometry(arg1)))
4163 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4164 offset=(ssize_t) StringToLong(arg1);
4165 new_images=SmushImages(_images,normal_op,offset,_exception);
4168 if (LocaleCompare("subimage",option+1) == 0)
4186 base_image=GetImageFromList(_images,0);
4187 compare_image=GetImageFromList(_images,1);
4189 /* Comparision Metric */
4190 metric=UndefinedMetric;
4191 value=GetImageOption(_image_info,"metric");
4192 if (value != (const char *) NULL)
4193 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4196 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4197 &offset,&similarity,_exception);
4199 if ( new_images != (Image *)NULL ) {
4201 result[MaxTextExtent];
4203 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4204 (void) SetImageProperty(new_images,"subimage:similarity",result,
4206 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4208 (void) SetImageProperty(new_images,"subimage:x",result,
4210 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4212 (void) SetImageProperty(new_images,"subimage:y",result,
4214 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4215 (unsigned long) offset.width,(unsigned long) offset.height,
4216 (long) offset.x,(long) offset.y);
4217 (void) SetImageProperty(new_images,"subimage:offset",result,
4222 if (LocaleCompare("swap",option+1) == 0) {
4242 flags=ParseGeometry(arg1,&geometry_info);
4243 if ((flags & RhoValue) == 0)
4244 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4245 index=(ssize_t) geometry_info.rho;
4246 if ((flags & SigmaValue) != 0)
4247 swap_index=(ssize_t) geometry_info.sigma;
4249 p=GetImageFromList(_images,index);
4250 q=GetImageFromList(_images,swap_index);
4251 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4253 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4255 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4258 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4259 swap=CloneImage(p,0,0,MagickTrue,_exception);
4260 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4261 ReplaceImageInList(&q,swap);
4262 _images=GetFirstImageInList(q);
4265 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4268 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4271 /* clean up percent escape interpreted strings */
4273 arg1=DestroyString((char *)arg1);
4275 arg2=DestroyString((char *)arg2);
4277 /* if new image list generated, replace existing image list */
4278 if (new_images == (Image *) NULL)
4280 _images=DestroyImageList(_images);
4281 _images=GetFirstImageInList(new_images);
4288 #undef _quantize_info
4295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4299 + C L I N o I m a g e O p e r a t i o n s %
4303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4305 % CLINoImageOperator() Applies operations that may not actually need images
4308 % The classic operators of this type is "-read", which actually creates
4309 % images even when no images are present. Or image stack operators, which
4310 % can be applied (push or pop) to an empty image list.
4312 % Note that these operators may involve other special 'option' prefix
4313 % characters other than '-' or '+', namely parenthesis and braces.
4315 % The format of the CLINoImageOption method is:
4317 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4318 % const char *arg1, const char *arg2)
4320 % A description of each parameter follows:
4322 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4324 % o option: The special option (with any switch char) to process
4326 % o arg1 & arg2: Argument for option, if required
4327 % Currently arg2 is not used.
4330 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4331 const char *option,const char *arg1,const char *arg2)
4334 const char /* For percent escape interpretImageProperties() */
4339 #define _image_info (cli_wand->wand.image_info)
4340 #define _images (cli_wand->wand.images)
4341 #define _exception (cli_wand->wand.exception)
4342 #define IfNormalOp (*option=='-')
4343 #define IfPlusOp (*option!='-')
4345 assert(cli_wand != (MagickCLI *) NULL);
4346 assert(cli_wand->signature == WandSignature);
4347 assert(cli_wand->wand.signature == WandSignature);
4348 if (IfMagickTrue(cli_wand->wand.debug))
4349 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4352 Not able to be used as their may not be any images!
4353 Also the only option that may have arguments that can be percent escaped is
4356 #define _process_flags (cli_wand->process_flags)
4357 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4358 /* Interpret Percent Escapes in Arguments - using first image */
4361 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4362 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4363 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4364 /* Interpret Percent escapes in argument 1 */
4365 if (arg1n != (char *) NULL) {
4366 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4367 if (arg1 == (char *) NULL) {
4368 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4369 arg1=arg1n; /* use the given argument as is */
4372 if (arg2n != (char *) NULL) {
4373 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4374 if (arg2 == (char *) NULL) {
4375 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4376 arg2=arg2n; /* use the given argument as is */
4380 #undef _process_flags
4384 do { /* break to exit code */
4386 No-op options (ignore these)
4388 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4390 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4392 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4394 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4396 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4401 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4402 ( LocaleCompare("--",option) == 0 ) ) {
4403 /* Do Glob filename Expansion for 'arg1' then read all images.
4405 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4406 * (but attaching to the filenames in the generated argument list) any
4407 * [...] read modifiers that may be present.
4409 * For example: It will expand '*.gif[20x20]' into a list such as
4410 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4412 * NOTE: In IMv6 this was done globally across all images. This
4413 * meant you could include IM options in '@filename' lists, but you
4414 * could not include comments. Doing it only for image read makes
4415 * it far more secure.
4417 * Note: arguments do not have percent escapes expanded for security
4425 argv = (char **) &arg1;
4427 /* Expand 'glob' expressions in the given filename.
4428 Expansion handles any 'coder:' prefix, or read modifiers attached
4429 to the filename, including them in the resulting expanded list.
4431 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4432 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4433 option,GetExceptionMessage(errno));
4435 /* loop over expanded filename list, and read then all in */
4436 for (i=0; i<argc; i++) {
4439 if (IfMagickTrue(_image_info->ping))
4440 new_images=PingImages(_image_info,argv[i],_exception);
4442 new_images=ReadImages(_image_info,argv[i],_exception);
4443 AppendImageToList(&_images, new_images);
4445 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4450 Note: Writing a empty image list is valid in specific cases
4452 if (LocaleCompare("write",option+1) == 0) {
4453 /* Note: arguments do not have percent escapes expanded */
4463 /* Need images, unless a "null:" output coder is used */
4464 if ( cli_wand->wand.images == (Image *) NULL ) {
4465 if ( LocaleCompare(arg1,"null:") == 0 )
4467 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4470 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4471 (void) DeleteImageRegistry(key);
4472 write_images=_images;
4474 write_images=CloneImageList(_images,_exception);
4475 write_info=CloneImageInfo(_image_info);
4476 (void) WriteImages(write_info,write_images,arg1,_exception);
4477 write_info=DestroyImageInfo(write_info);
4479 write_images=DestroyImageList(write_images);
4483 Parenthesis and Brace operations
4485 if (LocaleCompare("(",option) == 0) {
4486 /* stack 'push' images */
4494 node=cli_wand->image_list_stack;
4495 for ( ; node != (Stack *)NULL; node=node->next)
4497 if ( size >= MAX_STACK_DEPTH )
4498 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4499 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4500 if (node == (Stack *) NULL)
4501 CLIWandExceptionBreak(ResourceLimitFatalError,
4502 "MemoryAllocationFailed",option);
4503 node->data = (void *)cli_wand->wand.images;
4504 cli_wand->wand.images = NewImageList();
4505 node->next = cli_wand->image_list_stack;
4506 cli_wand->image_list_stack = node;
4508 /* handle respect-parenthesis */
4509 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4510 "respect-parenthesis"))))
4511 option="{"; /* fall-thru so as to push image settings too */
4514 /* fall thru to next if */
4516 if (LocaleCompare("{",option) == 0) {
4517 /* stack 'push' of image_info settings */
4525 node=cli_wand->image_info_stack;
4526 for ( ; node != (Stack *)NULL; node=node->next)
4528 if ( size >= MAX_STACK_DEPTH )
4529 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4530 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4531 if (node == (Stack *) NULL)
4532 CLIWandExceptionBreak(ResourceLimitFatalError,
4533 "MemoryAllocationFailed",option);
4535 node->data = (void *)cli_wand->wand.image_info;
4536 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4537 if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4538 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4540 cli_wand->wand.image_info = (ImageInfo *)node->data;
4541 node = (Stack *)RelinquishMagickMemory(node);
4545 node->next = cli_wand->image_info_stack;
4546 cli_wand->image_info_stack = node;
4550 if (LocaleCompare(")",option) == 0) {
4551 /* pop images from stack */
4555 node = (Stack *)cli_wand->image_list_stack;
4556 if ( node == (Stack *)NULL)
4557 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4558 cli_wand->image_list_stack = node->next;
4560 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4561 cli_wand->wand.images= (Image *)node->data;
4562 node = (Stack *)RelinquishMagickMemory(node);
4564 /* handle respect-parenthesis - of the previous 'pushed' settings */
4565 node = cli_wand->image_info_stack;
4566 if ( node != (Stack *)NULL)
4568 if (IfMagickTrue(IsStringTrue(GetImageOption(
4569 cli_wand->wand.image_info,"respect-parenthesis"))))
4570 option="}"; /* fall-thru so as to pop image settings too */
4576 /* fall thru to next if */
4578 if (LocaleCompare("}",option) == 0) {
4579 /* pop image_info settings from stack */
4583 node = (Stack *)cli_wand->image_info_stack;
4584 if ( node == (Stack *)NULL)
4585 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4586 cli_wand->image_info_stack = node->next;
4588 (void) DestroyImageInfo(cli_wand->wand.image_info);
4589 cli_wand->wand.image_info = (ImageInfo *)node->data;
4590 node = (Stack *)RelinquishMagickMemory(node);
4592 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4593 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4594 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4598 if (LocaleCompare("set",option+1) == 0)
4600 /* Note: arguments are not percent escapes expanded yet */
4601 /* Some settings are applied to each image in memory in turn.
4602 While others only need to be applied once globally.
4607 if (LocaleNCompare(arg1,"registry:",9) == 0)
4611 (void) DeleteImageRegistry(arg1+9);
4614 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4615 if (value == (char *) NULL)
4616 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4618 (void) SetImageRegistry(StringRegistryType,arg1+9,value,_exception);
4619 value=DestroyString(value);
4622 if (LocaleNCompare(arg1,"option:",7) == 0)
4624 /* delete equivelent artifact from all images (if any) */
4625 MagickResetIterator(&cli_wand->wand);
4626 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4627 (void) DeleteImageArtifact(_images,arg1+7);
4628 MagickResetIterator(&cli_wand->wand);
4629 /* now set/delete the global option as needed */
4631 (void) DeleteImageOption(_image_info,arg1+7);
4634 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4635 if (value == (char *) NULL)
4636 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4638 (void) SetImageOption(_image_info,arg1+7,value);
4639 value=DestroyString(value);
4642 if ( cli_wand->wand.images == (Image *) NULL )
4643 CLIWandExceptArgBreak(OptionError,"NoImagesFound",option,arg1);
4644 MagickResetIterator(&cli_wand->wand);
4645 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4651 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4652 (void) DeleteImageArtifact(_images,arg1+9);
4653 else if (LocaleNCompare(arg1,"property:",9) == 0)
4654 (void) DeleteImageProperty(_images,arg1+9);
4656 (void) DeleteImageProperty(_images,arg1);
4660 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
4662 value=InterpretImageProperties(_image_info,next,arg2,_exception);
4663 if (value == (char *) NULL)
4664 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4666 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4667 (void) SetImageArtifact(next,arg1+9,value);
4669 if (LocaleNCompare(arg1,"property:",9) == 0)
4670 (void) SetImageProperty(next,arg1+9,value,_exception);
4672 (void) SetImageProperty(next,arg1,value,_exception);
4673 value=DestroyString(value);
4677 MagickResetIterator(&cli_wand->wand);
4680 if (LocaleCompare("clone",option+1) == 0) {
4686 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4687 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4688 if ( cli_wand->image_list_stack == (Stack *)NULL)
4689 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4690 new_images = (Image *)cli_wand->image_list_stack->data;
4691 if (new_images == (Image *) NULL)
4692 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4693 new_images=CloneImages(new_images,arg1,_exception);
4694 if (new_images == (Image *) NULL)
4695 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4696 AppendImageToList(&_images,new_images);
4700 Informational Operations.
4702 Note that these do not require either a cli-wand or images!
4703 Though currently a cli-wand much be provided regardless.
4705 if (LocaleCompare("version",option+1) == 0)
4707 ListMagickVersion(stdout);
4710 if (LocaleCompare("list",option+1) == 0) {
4712 FUTURE: This 'switch' should really be part of MagickCore
4717 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4719 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4724 case MagickCoderOptions:
4726 (void) ListCoderInfo((FILE *) NULL,_exception);
4729 case MagickColorOptions:
4731 (void) ListColorInfo((FILE *) NULL,_exception);
4734 case MagickConfigureOptions:
4736 (void) ListConfigureInfo((FILE *) NULL,_exception);
4739 case MagickDelegateOptions:
4741 (void) ListDelegateInfo((FILE *) NULL,_exception);
4744 case MagickFontOptions:
4746 (void) ListTypeInfo((FILE *) NULL,_exception);
4749 case MagickFormatOptions:
4750 (void) ListMagickInfo((FILE *) NULL,_exception);
4752 case MagickLocaleOptions:
4753 (void) ListLocaleInfo((FILE *) NULL,_exception);
4755 case MagickLogOptions:
4756 (void) ListLogInfo((FILE *) NULL,_exception);
4758 case MagickMagicOptions:
4759 (void) ListMagicInfo((FILE *) NULL,_exception);
4761 case MagickMimeOptions:
4762 (void) ListMimeInfo((FILE *) NULL,_exception);
4764 case MagickModuleOptions:
4765 (void) ListModuleInfo((FILE *) NULL,_exception);
4767 case MagickPolicyOptions:
4768 (void) ListPolicyInfo((FILE *) NULL,_exception);
4770 case MagickResourceOptions:
4771 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4773 case MagickThresholdOptions:
4774 (void) ListThresholdMaps((FILE *) NULL,_exception);
4777 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4784 CLIWandException(OptionError,"UnrecognizedOption",option);
4786 } while (0); /* break to exit code. */
4789 /* clean up percent escape interpreted strings */
4791 arg1=DestroyString((char *)arg1);
4793 arg2=DestroyString((char *)arg2);
4804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4808 + C L I O p t i o n %
4812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4814 % CLIOption() Processes the given option using the given CLI Magick Wand.
4815 % The option arguments can be variable in number, though at this time no more
4816 % that two is actually used by any option (this may change). Excess options
4817 % are simply ignored.
4819 % If the cli_wand->command pointer is non-null, then it is assumed that the
4820 % option has already been search for up from the CommandOptions[] table in
4821 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4822 % routine will do the lookup instead. The pointer is reset afterward.
4824 % This action allows the caller to lookup and pre-handle any 'special'
4825 % options, (such as implicit reads) before calling this general option
4826 % handler to deal with 'standard' command line options.
4828 % The format of the CLIOption method is:
4830 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4832 % A description of each parameter follows:
4834 % o cli_wand: the main CLI Wand to use.
4836 % o option: The special option (with any switch char) to process
4838 % o args: any required arguments for an option (variable number)
4842 % CLIoption(cli_wand,"-read","rose:");
4843 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4844 % CLIoption(cli_wand,"-distort","SRT:","30");
4845 % CLIoption(cli_wand,"-write","rotated_rose.png");
4848 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4857 assert(cli_wand != (MagickCLI *) NULL);
4858 assert(cli_wand->signature == WandSignature);
4859 assert(cli_wand->wand.signature == WandSignature);
4860 if (IfMagickTrue(cli_wand->wand.debug))
4861 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4863 do { /* Break Code Block for error handling */
4865 /* get information about option */
4866 if ( cli_wand->command == (const OptionInfo *) NULL )
4867 cli_wand->command = GetCommandOptionInfo(option);
4869 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4870 option, cli_wand->command->mnemonic );
4872 option_type=(CommandOptionFlags) cli_wand->command->flags;
4874 if ( option_type == UndefinedOptionFlag )
4875 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4877 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4879 /* depreciated options */
4880 if ( (option_type & DeprecateOptionFlag) != 0 )
4881 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4883 /* options that this module does not handle */
4884 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
4885 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
4887 /* Get argument strings from VarArgs
4888 How can you determine arguments is enough was supplied? */
4890 count = cli_wand->command->type;
4895 va_start(operands,option);
4899 arg1=(const char *) va_arg(operands, const char *);
4901 arg2=(const char *) va_arg(operands, const char *);
4906 (void) FormatLocaleFile(stderr,
4907 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
4908 option,(long) count,option_type,arg1,arg2);
4913 Call the appropriate option handler
4916 /* FUTURE: this is temporary - get 'settings' to handle distribution of
4917 settings to images attributes,proprieties,artifacts */
4918 if ( cli_wand->wand.images != (Image *)NULL )
4919 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
4920 cli_wand->wand.exception);
4922 if ( (option_type & SettingOptionFlags) != 0 ) {
4923 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
4924 // FUTURE: Sync Specific Settings into Image Properities (not global)
4927 /* Operators that do not need images - read, write, stack, clone */
4928 if ( (option_type & NoImageOperatorFlag) != 0)
4929 CLINoImageOperator(cli_wand, option, arg1, arg2);
4931 /* FUTURE: The not a setting part below is a temporary hack due to
4932 * some options being both a Setting and a Simple operator.
4933 * Specifically -monitor, -depth, and -colorspace */
4934 if ( cli_wand->wand.images == (Image *)NULL )
4935 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
4936 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
4937 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
4939 /* Operators work on single images, and needs a loop over the images */
4940 if ( (option_type & SimpleOperatorFlag) != 0)
4941 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
4943 /* Operators that work on the image list as a whole */
4944 if ( (option_type & ListOperatorFlag) != 0 )
4945 CLIListOperatorImages(cli_wand, option, arg1, arg2);
4947 } while (0); /* end Break code block */
4949 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */