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 the 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 *arg1n, const char *arg2n)
405 parse; /* option argument parsing (string to value table lookup) */
407 const char /* percent escaped versions of the args */
411 #define _image_info (cli_wand->wand.image_info)
412 #define _image (cli_wand->wand.images)
413 #define _exception (cli_wand->wand.exception)
414 #define _draw_info (cli_wand->draw_info)
415 #define _quantize_info (cli_wand->quantize_info)
416 #define IfSetOption (*option=='-')
417 #define ArgBoolean IsMagickTrue(IfSetOption)
418 #define ArgBooleanNot IsMagickFalse(IfSetOption)
419 #define ArgBooleanString (IfSetOption?"true":"false")
420 #define ArgOption(def) (IfSetOption?arg1:(const char *)(def))
422 assert(cli_wand != (MagickCLI *) NULL);
423 assert(cli_wand->signature == WandSignature);
424 assert(cli_wand->wand.signature == WandSignature);
426 if (IfMagickTrue(cli_wand->wand.debug))
427 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
428 "- Setting Option: %s \"%s\" \"%s\"", option,arg1n,arg2n);
434 #define _process_flags (cli_wand->process_flags)
435 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
436 /* Interpret Percent Escapes in Arguments - using first image */
437 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
438 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
439 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
440 /* Interpret Percent escapes in argument 1 */
441 if (arg1n != (char *) NULL) {
442 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
443 if (arg1 == (char *) NULL) {
444 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
445 arg1=arg1n; /* use the given argument as is */
448 if (arg2n != (char *) NULL) {
449 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
450 if (arg2 == (char *) NULL) {
451 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
452 arg2=arg2n; /* use the given argument as is */
456 #undef _process_flags
464 if (LocaleCompare("adjoin",option+1) == 0)
466 _image_info->adjoin = ArgBoolean;
469 if (LocaleCompare("affine",option+1) == 0)
471 CLIWandWarnReplaced("-draw 'affine ...'");
473 (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception);
475 GetAffineMatrix(&_draw_info->affine);
478 if (LocaleCompare("antialias",option+1) == 0)
480 _image_info->antialias =
481 _draw_info->stroke_antialias =
482 _draw_info->text_antialias = ArgBoolean;
485 if (LocaleCompare("attenuate",option+1) == 0)
487 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
488 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
489 (void) SetImageOption(_image_info,option+1,ArgOption("1.0"));
492 if (LocaleCompare("authenticate",option+1) == 0)
494 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
497 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
501 if (LocaleCompare("background",option+1) == 0)
503 /* FUTURE: both _image_info attribute & ImageOption in use!
504 _image_info only used directly for generating new images.
505 SyncImageSettings() used to set per-image attribute.
507 FUTURE: if _image_info->background_color is not set then
508 we should fall back to per-image background_color
510 At this time -background will 'wipe out' the per-image
513 Better error handling of QueryColorCompliance() needed.
515 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
516 (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance,
517 &_image_info->background_color,_exception);
520 if (LocaleCompare("bias",option+1) == 0)
522 /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias"
523 as it is actually rarely used except in direct convolve operations
524 Usage outside a direct convolve operation is actally non-sensible!
526 SyncImageSettings() used to set per-image attribute.
528 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
529 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
530 (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL));
533 if (LocaleCompare("black-point-compensation",option+1) == 0)
535 /* Used as a image chromaticity setting
536 SyncImageSettings() used to set per-image attribute.
538 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
541 if (LocaleCompare("blue-primary",option+1) == 0)
543 /* Image chromaticity X,Y NB: Y=X if Y not defined
544 Used by many coders including PNG
545 SyncImageSettings() used to set per-image attribute.
547 arg1=ArgOption("0.0");
548 if (IfMagickFalse(IsGeometry(arg1)))
549 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
550 (void) SetImageOption(_image_info,option+1,arg1);
553 if (LocaleCompare("bordercolor",option+1) == 0)
555 /* FUTURE: both _image_info attribute & ImageOption in use!
556 SyncImageSettings() used to set per-image attribute.
557 Better error checking of QueryColorCompliance().
561 (void) SetImageOption(_image_info,option+1,arg1);
562 (void) QueryColorCompliance(arg1,AllCompliance,
563 &_image_info->border_color,_exception);
564 (void) QueryColorCompliance(arg1,AllCompliance,
565 &_draw_info->border_color,_exception);
568 (void) DeleteImageOption(_image_info,option+1);
569 (void) QueryColorCompliance(BorderColor,AllCompliance,
570 &_image_info->border_color,_exception);
571 (void) QueryColorCompliance(BorderColor,AllCompliance,
572 &_draw_info->border_color,_exception);
575 if (LocaleCompare("box",option+1) == 0)
577 CLIWandWarnReplaced("-undercolor");
578 CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2);
581 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
585 if (LocaleCompare("cache",option+1) == 0)
590 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
591 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
592 limit=MagickResourceInfinity;
593 if (LocaleCompare("unlimited",arg1) != 0)
594 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0);
595 (void) SetMagickResourceLimit(MemoryResource,limit);
596 (void) SetMagickResourceLimit(MapResource,2*limit);
599 if (LocaleCompare("caption",option+1) == 0)
601 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
604 if (LocaleCompare("channel",option+1) == 0)
606 parse=ParseChannelOption(ArgOption("Default"));
608 CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",
610 _image_info->channel=(ChannelType) parse;
611 (void) SetImageOption(_image_info,option+1,arg1);
614 if (LocaleCompare("colorspace",option+1) == 0)
616 /* Setting used for new images via AquireImage()
617 But also used as a SimpleImageOperator
618 Undefined colorspace means don't modify images on
619 read or as a operation */
620 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
621 ArgOption("undefined"));
623 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
625 _image_info->colorspace=(ColorspaceType) parse;
628 if (LocaleCompare("comment",option+1) == 0)
630 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
633 if (LocaleCompare("compose",option+1) == 0)
635 /* FUTURE: _image_info should be used,
636 SyncImageSettings() used to set per-image attribute. - REMOVE
638 This setting should NOT be used to set image 'compose'
639 "-layer" operators shoud use _image_info if defined otherwise
640 they should use a per-image compose setting.
642 parse = ParseCommandOption(MagickComposeOptions,MagickFalse,
643 ArgOption("undefined"));
645 CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator",
647 _image_info->compose=(CompositeOperator) parse;
648 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
651 if (LocaleCompare("compress",option+1) == 0)
653 /* FUTURE: What should be used? _image_info or ImageOption ???
654 The former is more efficent, but Crisy prefers the latter!
655 SyncImageSettings() used to set per-image attribute.
657 The coders appears to use _image_info, not Image_Option
658 however the image attribute (for save) is set from the
661 Note that "undefined" is a different setting to "none".
663 parse = ParseCommandOption(MagickCompressOptions,MagickFalse,
664 ArgOption("undefined"));
666 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression",
668 _image_info->compression=(CompressionType) parse;
669 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
672 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
676 if (LocaleCompare("debug",option+1) == 0)
678 /* SyncImageSettings() used to set per-image attribute. */
679 arg1=ArgOption("none");
680 parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1);
682 CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType",
684 (void) SetLogEventMask(arg1);
685 _image_info->debug=IsEventLogging(); /* extract logging*/
686 cli_wand->wand.debug=IsEventLogging();
689 if (LocaleCompare("define",option+1) == 0)
691 if (LocaleNCompare(arg1,"registry:",9) == 0)
694 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception);
696 (void) DeleteImageRegistry(arg1+9);
699 /* DefineImageOption() equals SetImageOption() but with '=' */
701 (void) DefineImageOption(_image_info,arg1);
702 else if (IsMagickFalse(DeleteImageOption(_image_info,arg1)))
703 CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1);
706 if (LocaleCompare("delay",option+1) == 0)
708 /* Only used for new images via AcquireImage()
709 FUTURE: Option should also be used for "-morph" (color morphing)
712 if (IfMagickFalse(IsGeometry(arg1)))
713 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
714 (void) SetImageOption(_image_info,option+1,arg1);
717 if (LocaleCompare("density",option+1) == 0)
719 /* FUTURE: strings used in _image_info attr and _draw_info!
720 Basically as density can be in a XxY form!
722 SyncImageSettings() used to set per-image attribute.
724 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
725 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
726 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
727 (void) CloneString(&_image_info->density,ArgOption(NULL));
728 (void) CloneString(&_draw_info->density,_image_info->density);
731 if (LocaleCompare("depth",option+1) == 0)
733 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
734 SyncImageSettings() used to set per-image attribute.
736 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
737 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
738 _image_info->depth=IfSetOption?StringToUnsignedLong(arg1)
739 :MAGICKCORE_QUANTUM_DEPTH;
742 if (LocaleCompare("direction",option+1) == 0)
744 /* Image Option is only used to set _draw_info */
745 arg1=ArgOption("undefined");
746 parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1);
748 CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType",
750 _draw_info->direction=(DirectionType) parse;
751 (void) SetImageOption(_image_info,option+1,arg1);
754 if (LocaleCompare("display",option+1) == 0)
756 (void) CloneString(&_image_info->server_name,ArgOption(NULL));
757 (void) CloneString(&_draw_info->server_name,_image_info->server_name);
760 if (LocaleCompare("dispose",option+1) == 0)
762 /* only used in setting new images */
763 arg1=ArgOption("undefined");
764 parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1);
766 CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod",
768 (void) SetImageOption(_image_info,option+1,ArgOption("undefined"));
771 if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
773 /* FUTURE: this is only used by CompareImages() which is used
774 only by the "compare" CLI program at this time. */
775 arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD);
776 if (IfMagickFalse(IsGeometry(arg1)))
777 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
778 (void) SetImageOption(_image_info,option+1,arg1);
781 if (LocaleCompare("dither",option+1) == 0)
783 /* _image_info attr (on/off), _quantize_info attr (on/off)
784 but also ImageInfo and _quantize_info method!
785 FUTURE: merge the duality of the dithering options
787 _image_info->dither = ArgBoolean;
788 (void) SetImageOption(_image_info,option+1,ArgOption("none"));
789 _quantize_info->dither_method=(DitherMethod) ParseCommandOption(
790 MagickDitherOptions,MagickFalse,ArgOption("none"));
791 if (_quantize_info->dither_method == NoDitherMethod)
792 _image_info->dither = MagickFalse;
795 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
799 if (LocaleCompare("encoding",option+1) == 0)
801 (void) CloneString(&_draw_info->encoding,ArgOption("undefined"));
802 (void) SetImageOption(_image_info,option+1,_draw_info->encoding);
805 if (LocaleCompare("endian",option+1) == 0)
807 /* Both _image_info attr and ImageInfo */
808 arg1 = ArgOption("undefined");
809 parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1);
811 CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType",
813 /* FUTURE: check alloc/free of endian string! - remove? */
814 _image_info->endian=(EndianType) (*arg1);
815 (void) SetImageOption(_image_info,option+1,arg1);
818 if (LocaleCompare("extract",option+1) == 0)
820 (void) CloneString(&_image_info->extract,ArgOption(NULL));
823 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
827 if (LocaleCompare("family",option+1) == 0)
829 (void) CloneString(&_draw_info->family,ArgOption(NULL));
832 if (LocaleCompare("features",option+1) == 0)
834 (void) SetImageOption(_image_info,"identify:features",
837 (void) SetImageArtifact(_image,"verbose","true");
840 if (LocaleCompare("fill",option+1) == 0)
842 /* Set "fill" OR "fill-pattern" in _draw_info
843 The original fill color is preserved if a fill-pattern is given.
844 That way it does not effect other operations that directly using
845 the fill color and, can be retored using "+tile".
856 arg1 = ArgOption("none"); /* +fill turns it off! */
857 (void) SetImageOption(_image_info,option+1,arg1);
858 if (_draw_info->fill_pattern != (Image *) NULL)
859 _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern);
861 /* is it a color or a image? -- ignore exceptions */
862 sans=AcquireExceptionInfo();
863 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
864 sans=DestroyExceptionInfo(sans);
866 if (IfMagickFalse(status))
867 _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception);
869 _draw_info->fill=color;
872 if (LocaleCompare("filter",option+1) == 0)
874 /* SyncImageSettings() used to set per-image attribute. */
875 arg1 = ArgOption("undefined");
876 parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1);
878 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter",
880 (void) SetImageOption(_image_info,option+1,arg1);
883 if (LocaleCompare("font",option+1) == 0)
885 (void) CloneString(&_draw_info->font,ArgOption(NULL));
886 (void) CloneString(&_image_info->font,_draw_info->font);
889 if (LocaleCompare("format",option+1) == 0)
891 /* FUTURE: why the ping test, you could set ping after this! */
896 for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
897 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
898 _image_info->ping=MagickFalse;
900 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
903 if (LocaleCompare("fuzz",option+1) == 0)
905 /* Option used to set image fuzz! unless blank canvas (from color)
906 Image attribute used for color compare operations
907 SyncImageSettings() used to set per-image attribute.
909 FUTURE: Can't find anything else using _image_info->fuzz directly!
910 convert structure attribute to 'option' string
913 if (IfMagickFalse(IsGeometry(arg1)))
914 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
915 _image_info->fuzz=StringToDoubleInterval(arg1,(double)
917 (void) SetImageOption(_image_info,option+1,arg1);
920 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
924 if (LocaleCompare("gravity",option+1) == 0)
926 /* SyncImageSettings() used to set per-image attribute. */
927 arg1 = ArgOption("none");
928 parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1);
930 CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType",
932 _draw_info->gravity=(GravityType) parse;
933 (void) SetImageOption(_image_info,option+1,arg1);
936 if (LocaleCompare("green-primary",option+1) == 0)
938 /* Image chromaticity X,Y NB: Y=X if Y not defined
939 SyncImageSettings() used to set per-image attribute.
940 Used directly by many coders
942 arg1=ArgOption("0.0");
943 if (IfMagickFalse(IsGeometry(arg1)))
944 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
945 (void) SetImageOption(_image_info,option+1,arg1);
948 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
952 if (LocaleCompare("highlight-color",option+1) == 0)
954 /* FUTURE: this is only used by CompareImages() which is used
955 only by the "compare" CLI program at this time. */
956 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
959 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
963 if (LocaleCompare("intensity",option+1) == 0)
965 arg1 = ArgOption("undefined");
966 parse = ParseCommandOption(MagickPixelIntensityOptions,MagickFalse,
969 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityType",
971 (void) SetImageOption(_image_info,option+1,arg1);
974 if (LocaleCompare("intent",option+1) == 0)
976 /* Only used by coders: MIFF, MPC, BMP, PNG
977 and for image profile call to AcquireTransformThreadSet()
978 SyncImageSettings() used to set per-image attribute.
980 arg1 = ArgOption("undefined");
981 parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1);
983 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType",
985 (void) SetImageOption(_image_info,option+1,arg1);
988 if (LocaleCompare("interlace",option+1) == 0)
990 /* _image_info is directly used by coders (so why an image setting?)
991 SyncImageSettings() used to set per-image attribute.
993 arg1 = ArgOption("undefined");
994 parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1);
996 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType",
998 _image_info->interlace=(InterlaceType) parse;
999 (void) SetImageOption(_image_info,option+1,arg1);
1002 if (LocaleCompare("interline-spacing",option+1) == 0)
1004 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1005 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1006 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1007 _draw_info->interline_spacing=StringToDouble(ArgOption("0"),
1011 if (LocaleCompare("interpolate",option+1) == 0)
1013 /* SyncImageSettings() used to set per-image attribute. */
1014 arg1 = ArgOption("undefined");
1015 parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1);
1017 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod",
1019 (void) SetImageOption(_image_info,option+1,arg1);
1022 if (LocaleCompare("interword-spacing",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->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
1030 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1034 if (LocaleCompare("kerning",option+1) == 0)
1036 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1037 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1038 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1039 _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
1042 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1046 if (LocaleCompare("label",option+1) == 0)
1048 /* only used for new images - not in SyncImageOptions() */
1049 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1052 if (LocaleCompare("limit",option+1) == 0)
1057 limit=MagickResourceInfinity;
1058 parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1);
1060 CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType",
1062 if (LocaleCompare("unlimited",arg2) != 0)
1063 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
1064 (void) SetMagickResourceLimit((ResourceType)parse,limit);
1067 if (LocaleCompare("log",option+1) == 0)
1070 if ((strchr(arg1,'%') == (char *) NULL))
1071 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1072 (void) SetLogFormat(arg1);
1076 if (LocaleCompare("lowlight-color",option+1) == 0)
1078 /* FUTURE: this is only used by CompareImages() which is used
1079 only by the "compare" CLI program at this time. */
1080 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1083 if (LocaleCompare("loop",option+1) == 0)
1085 /* SyncImageSettings() used to set per-image attribute. */
1086 arg1=ArgOption("0");
1087 if (IfMagickFalse(IsGeometry(arg1)))
1088 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1089 (void) SetImageOption(_image_info,option+1,arg1);
1092 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1096 if (LocaleCompare("mattecolor",option+1) == 0)
1098 /* SyncImageSettings() used to set per-image attribute. */
1099 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1100 (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance,
1101 &_image_info->matte_color,_exception);
1104 if (LocaleCompare("metric",option+1) == 0)
1106 /* FUTURE: this is only used by CompareImages() which is used
1107 only by the "compare" CLI program at this time. */
1108 parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1);
1110 CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType",
1112 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1115 if (LocaleCompare("monitor",option+1) == 0)
1117 (void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
1118 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1121 if (LocaleCompare("monochrome",option+1) == 0)
1123 /* Setting (used by some input coders!) -- why?
1124 Warning: This is also Special '-type' SimpleOperator
1126 _image_info->monochrome= ArgBoolean;
1129 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1133 if (LocaleCompare("orient",option+1) == 0)
1135 /* Is not used when defining for new images.
1136 This makes it more of a 'operation' than a setting
1137 FUTURE: make set meta-data operator instead.
1138 SyncImageSettings() used to set per-image attribute.
1140 parse=ParseCommandOption(MagickOrientationOptions,MagickFalse,
1141 ArgOption("undefined"));
1143 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation",
1145 _image_info->orientation=(OrientationType)parse;
1146 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1149 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1153 if (LocaleCompare("page",option+1) == 0)
1155 /* Only used for new images and image generators.
1156 SyncImageSettings() used to set per-image attribute. ?????
1157 That last is WRONG!!!!
1158 FUTURE: adjust named 'page' sizes according density
1162 page[MaxTextExtent];
1175 (void) DeleteImageOption(_image_info,option+1);
1176 (void) CloneString(&_image_info->page,(char *) NULL);
1179 (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1180 image_option=GetImageOption(_image_info,"page");
1181 if (image_option != (const char *) NULL)
1182 flags=ParseAbsoluteGeometry(image_option,&geometry);
1183 canonical_page=GetPageGeometry(arg1);
1184 flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1185 canonical_page=DestroyString(canonical_page);
1186 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1187 (unsigned long) geometry.width,(unsigned long) geometry.height);
1188 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1189 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1190 (unsigned long) geometry.width,(unsigned long) geometry.height,
1191 (long) geometry.x,(long) geometry.y);
1192 (void) SetImageOption(_image_info,option+1,page);
1193 (void) CloneString(&_image_info->page,page);
1196 if (LocaleCompare("ping",option+1) == 0)
1198 _image_info->ping = ArgBoolean;
1201 if (LocaleCompare("pointsize",option+1) == 0)
1204 if (IfMagickFalse(IsGeometry(arg1)))
1205 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1206 _image_info->pointsize =
1207 _draw_info->pointsize =
1208 StringToDouble(arg1,(char **) NULL);
1211 _image_info->pointsize=0.0; /* unset pointsize */
1212 _draw_info->pointsize=12.0;
1216 if (LocaleCompare("precision",option+1) == 0)
1218 arg1=ArgOption("-1");
1219 if (IfMagickFalse(IsGeometry(arg1)))
1220 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1221 (void) SetMagickPrecision(StringToInteger(arg1));
1224 /* FUTURE: Only the 'preview' coder appears to use this
1225 * DEPRECIATE the coder? Leaving only the 'preview' operator.
1226 if (LocaleCompare("preview",option+1) == 0)
1228 _image_info->preview_type=UndefinedPreview;
1230 _image_info->preview_type=(PreviewType) ParseCommandOption(
1231 MagickPreviewOptions,MagickFalse,arg1);
1235 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1239 if (LocaleCompare("quality",option+1) == 0)
1241 if (IfMagickFalse(IsGeometry(arg1)))
1242 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1243 _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1)
1244 : UNDEFINED_COMPRESSION_QUALITY;
1245 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1248 if (LocaleCompare("quantize",option+1) == 0)
1250 /* Just a set direct in _quantize_info */
1251 arg1=ArgOption("undefined");
1252 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
1254 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
1256 _quantize_info->colorspace=(ColorspaceType)parse;
1259 if (LocaleCompare("quiet",option+1) == 0)
1261 /* FUTURE: if two -quiet is performed you can not do +quiet!
1262 This needs to be checked over thoughly.
1264 static WarningHandler
1265 warning_handler = (WarningHandler) NULL;
1268 tmp = SetWarningHandler((WarningHandler) NULL);
1270 if ( tmp != (WarningHandler) NULL)
1271 warning_handler = tmp; /* remember the old handler */
1272 if (!IfSetOption) /* set the old handler */
1273 warning_handler=SetWarningHandler(warning_handler);
1276 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1280 if (LocaleCompare("red-primary",option+1) == 0)
1282 /* Image chromaticity X,Y NB: Y=X if Y not defined
1284 SyncImageSettings() used to set per-image attribute.
1286 arg1=ArgOption("0.0");
1287 if (IfMagickFalse(IsGeometry(arg1)))
1288 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1289 (void) SetImageOption(_image_info,option+1,arg1);
1292 if (LocaleCompare("regard-warnings",option+1) == 0)
1293 /* FUTURE: to be replaced by a 'fatal-level' type setting */
1295 if (LocaleCompare("render",option+1) == 0)
1297 /* _draw_info only setting */
1298 _draw_info->render= ArgBooleanNot;
1301 if (LocaleCompare("respect-parenthesis",option+1) == 0)
1303 /* link image and setting stacks - option is itself saved on stack! */
1304 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1307 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1311 if (LocaleCompare("sampling-factor",option+1) == 0)
1313 /* FUTURE: should be converted to jpeg:sampling_factor */
1314 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1315 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1316 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1319 if (LocaleCompare("scene",option+1) == 0)
1321 /* SyncImageSettings() used to set this as a per-image attribute.
1324 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1325 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1326 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1327 _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1330 if (LocaleCompare("seed",option+1) == 0)
1332 if (IfMagickFalse(IsGeometry(arg1)))
1333 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1335 IfSetOption ? (unsigned long) StringToUnsignedLong(arg1)
1336 : (unsigned long) time((time_t *) NULL) );
1339 if (LocaleCompare("size",option+1) == 0)
1341 /* FUTURE: string in _image_info -- convert to Option ???
1342 Look at the special handling for "size" in SetImageOption()
1344 (void) CloneString(&_image_info->size,ArgOption(NULL));
1347 if (LocaleCompare("stretch",option+1) == 0)
1349 arg1=ArgOption("undefined");
1350 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1352 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1354 _draw_info->stretch=(StretchType) parse;
1357 if (LocaleCompare("stroke",option+1) == 0)
1359 /* set stroke color OR stroke-pattern
1360 UPDATE: ensure stroke color is not destroyed is a pattern
1361 is given. Just in case the color is also used for other purposes.
1372 arg1 = ArgOption("none"); /* +fill turns it off! */
1373 (void) SetImageOption(_image_info,option+1,arg1);
1374 if (_draw_info->stroke_pattern != (Image *) NULL)
1375 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1377 /* is it a color or a image? -- ignore exceptions */
1378 sans=AcquireExceptionInfo();
1379 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1380 sans=DestroyExceptionInfo(sans);
1382 if (IfMagickFalse(status))
1383 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1385 _draw_info->stroke=color;
1388 if (LocaleCompare("strokewidth",option+1) == 0)
1390 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1391 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1392 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1393 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1397 if (LocaleCompare("style",option+1) == 0)
1399 arg1=ArgOption("undefined");
1400 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1402 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1404 _draw_info->style=(StyleType) parse;
1408 if (LocaleCompare("subimage-search",option+1) == 0)
1410 /* FUTURE: this is only used by CompareImages() which is used
1411 only by the "compare" CLI program at this time. */
1412 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1416 if (LocaleCompare("synchronize",option+1) == 0)
1418 /* FUTURE: syncronize to storage - but what does that mean? */
1419 _image_info->synchronize = ArgBoolean;
1422 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1426 if (LocaleCompare("taint",option+1) == 0)
1428 /* SyncImageSettings() used to set per-image attribute. */
1429 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1432 if (LocaleCompare("texture",option+1) == 0)
1434 /* Note: arguments do not have percent escapes expanded */
1435 /* FUTURE: move _image_info string to option splay-tree
1436 Other than "montage" what uses "texture" ????
1438 (void) CloneString(&_image_info->texture,ArgOption(NULL));
1441 if (LocaleCompare("tile",option+1) == 0)
1443 /* Note: arguments do not have percent escapes expanded */
1444 _draw_info->fill_pattern=IfSetOption
1445 ?GetImageCache(_image_info,arg1,_exception)
1446 :DestroyImage(_draw_info->fill_pattern);
1449 if (LocaleCompare("tile-offset",option+1) == 0)
1451 /* SyncImageSettings() used to set per-image attribute. ??? */
1452 arg1=ArgOption("0");
1453 if (IfMagickFalse(IsGeometry(arg1)))
1454 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1455 (void) SetImageOption(_image_info,option+1,arg1);
1458 if (LocaleCompare("transparent-color",option+1) == 0)
1460 /* FUTURE: both _image_info attribute & ImageOption in use!
1461 _image_info only used for generating new images.
1462 SyncImageSettings() used to set per-image attribute.
1464 Note that +transparent-color, means fall-back to image
1465 attribute so ImageOption is deleted, not set to a default.
1467 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1468 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1469 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1470 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1471 &_image_info->transparent_color,_exception);
1474 if (LocaleCompare("treedepth",option+1) == 0)
1476 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1477 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1480 if (LocaleCompare("type",option+1) == 0)
1482 /* SyncImageSettings() used to set per-image attribute. */
1483 parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1484 ArgOption("undefined"));
1486 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1488 _image_info->type=(ImageType) parse;
1489 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1492 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1496 if (LocaleCompare("undercolor",option+1) == 0)
1498 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1499 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1500 &_draw_info->undercolor,_exception);
1503 if (LocaleCompare("units",option+1) == 0)
1505 /* SyncImageSettings() used to set per-image attribute.
1506 Should this effect _draw_info X and Y resolution?
1507 FUTURE: this probably should be part of the density setting
1509 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1510 ArgOption("undefined"));
1512 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1514 _image_info->units=(ResolutionType) parse;
1515 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1518 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1522 if (LocaleCompare("verbose",option+1) == 0)
1524 /* FUTURE: Remember all options become image artifacts
1525 _image_info->verbose is only used by coders.
1527 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1528 _image_info->verbose= ArgBoolean;
1529 _image_info->ping=MagickFalse; /* verbose can't be a ping */
1532 if (LocaleCompare("view",option+1) == 0)
1534 /* FUTURE: Convert from _image_info to ImageOption
1535 Only used by coder FPX
1536 And it only tests existance, not its content!
1538 (void) CloneString(&_image_info->view,ArgOption(NULL));
1541 if (LocaleCompare("virtual-pixel",option+1) == 0)
1543 /* SyncImageSettings() used to set per-image attribute.
1544 This is VERY deep in the image caching structure.
1546 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1547 ArgOption("undefined"));
1549 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1551 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1554 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1558 if (LocaleCompare("weight",option+1) == 0)
1560 /* Just what does using a font 'weight' do ???
1561 There is no "-list weight" output (reference manual says there is)
1563 arg1=ArgOption("all");
1564 _draw_info->weight=StringToUnsignedLong(arg1);
1565 if (LocaleCompare(arg1,"all") == 0)
1566 _draw_info->weight=0;
1567 if (LocaleCompare(arg1,"bold") == 0)
1568 _draw_info->weight=700;
1569 if (LocaleCompare(arg1,"bolder") == 0)
1570 if (_draw_info->weight <= 800)
1571 _draw_info->weight+=100;
1572 if (LocaleCompare(arg1,"lighter") == 0)
1573 if (_draw_info->weight >= 100)
1574 _draw_info->weight-=100;
1575 if (LocaleCompare(arg1,"normal") == 0)
1576 _draw_info->weight=400;
1579 if (LocaleCompare("white-point",option+1) == 0)
1581 /* Used as a image chromaticity setting
1582 SyncImageSettings() used to set per-image attribute.
1584 arg1=ArgOption("0.0");
1585 if (IfMagickFalse(IsGeometry(arg1)))
1586 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1587 (void) SetImageOption(_image_info,option+1,arg1);
1590 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1593 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1596 /* clean up percent escape interpreted strings */
1598 arg1=DestroyString((char *)arg1);
1600 arg2=DestroyString((char *)arg2);
1605 #undef _quantize_info
1608 #undef ArgBooleanNot
1609 #undef ArgBooleanString
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1620 + C L I S i m p l e O p e r a t o r I m a g e s %
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626 % CLISimpleOperatorImages() applys one simple image operation given to all
1627 % the images in the CLI wand, using any per-image or global settings that was
1628 % previously saved in the CLI wand.
1630 % It is assumed that any such settings are up-to-date.
1632 % The format of the WandSimpleOperatorImages method is:
1634 % void CLISimpleOperatorImages(MagickCLI *cli_wand,
1635 % const char *option, const char *arg1, const char *arg2)
1637 % A description of each parameter follows:
1639 % o cli_wand: structure holding settings and images to be operated on
1641 % o option: The option string for the operation
1643 % o arg1, arg2: optional argument strings to the operation
1648 CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1649 image operation to the current image pointed to by the CLI wand.
1651 The image in the list may be modified in three different ways...
1652 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1653 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1654 * one image replace by a list of images (-separate and -crop only!)
1656 In each case the result replaces the single original image in the list, as
1657 well as the pointer to the modified image (last image added if replaced by a
1658 list of images) is returned.
1660 As the image pointed to may be replaced, the first image in the list may
1661 also change. GetFirstImageInList() should be used by caller if they wish
1662 return the Image pointer to the first image in list.
1664 static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand,
1665 const char *option, const char *arg1n, const char *arg2n)
1682 const char /* percent escaped versions of the args */
1686 #define _image_info (cli_wand->wand.image_info)
1687 #define _image (cli_wand->wand.images)
1688 #define _exception (cli_wand->wand.exception)
1689 #define _draw_info (cli_wand->draw_info)
1690 #define _quantize_info (cli_wand->quantize_info)
1691 #define _process_flags (cli_wand->process_flags)
1692 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
1693 #define IfNormalOp (*option=='-')
1694 #define IfPlusOp (*option!='-')
1695 #define IsNormalOp IsMagickTrue(IfNormalOp)
1696 #define IsPlusOp IsMagickFalse(IfNormalOp)
1698 assert(cli_wand != (MagickCLI *) NULL);
1699 assert(cli_wand->signature == WandSignature);
1700 assert(cli_wand->wand.signature == WandSignature);
1701 assert(_image != (Image *) NULL); /* an image must be present */
1702 if (IfMagickTrue(cli_wand->wand.debug))
1703 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1708 /* Interpret Percent Escapes in Arguments - using first image */
1709 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
1710 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1711 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1712 /* Interpret Percent escapes in argument 1 */
1713 if (arg1n != (char *) NULL) {
1714 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1715 if (arg1 == (char *) NULL) {
1716 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1717 arg1=arg1n; /* use the given argument as is */
1720 if (arg2n != (char *) NULL) {
1721 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1722 if (arg2 == (char *) NULL) {
1723 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1724 arg2=arg2n; /* use the given argument as is */
1728 #undef _process_flags
1732 (void) FormatLocaleFile(stderr,
1733 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1736 new_image = (Image *)NULL; /* the replacement image, if not null at end */
1737 SetGeometryInfo(&geometry_info);
1739 switch (*(option+1))
1743 if (LocaleCompare("adaptive-blur",option+1) == 0)
1745 flags=ParseGeometry(arg1,&geometry_info);
1746 if ((flags & (RhoValue|SigmaValue)) == 0)
1747 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1748 if ((flags & SigmaValue) == 0)
1749 geometry_info.sigma=1.0;
1750 new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1751 geometry_info.sigma,_exception);
1754 if (LocaleCompare("adaptive-resize",option+1) == 0)
1756 /* FUTURE: Roll into a resize special operator */
1757 if (IfMagickFalse(IsGeometry(arg1)))
1758 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1759 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1760 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1764 if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1766 flags=ParseGeometry(arg1,&geometry_info);
1767 if ((flags & (RhoValue|SigmaValue)) == 0)
1768 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1769 if ((flags & SigmaValue) == 0)
1770 geometry_info.sigma=1.0;
1771 new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1772 geometry_info.sigma,_exception);
1775 if (LocaleCompare("alpha",option+1) == 0)
1777 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1779 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1781 (void) SetImageAlphaChannel(_image,(AlphaChannelOption)parse,
1785 if (LocaleCompare("annotate",option+1) == 0)
1788 geometry[MaxTextExtent];
1790 SetGeometryInfo(&geometry_info);
1791 flags=ParseGeometry(arg1,&geometry_info);
1793 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1794 if ((flags & SigmaValue) == 0)
1795 geometry_info.sigma=geometry_info.rho;
1796 (void) CloneString(&_draw_info->text,arg2);
1797 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1798 geometry_info.xi,geometry_info.psi);
1799 (void) CloneString(&_draw_info->geometry,geometry);
1800 _draw_info->affine.sx=cos(DegreesToRadians(
1801 fmod(geometry_info.rho,360.0)));
1802 _draw_info->affine.rx=sin(DegreesToRadians(
1803 fmod(geometry_info.rho,360.0)));
1804 _draw_info->affine.ry=(-sin(DegreesToRadians(
1805 fmod(geometry_info.sigma,360.0))));
1806 _draw_info->affine.sy=cos(DegreesToRadians(
1807 fmod(geometry_info.sigma,360.0)));
1808 (void) AnnotateImage(_image,_draw_info,_exception);
1809 GetAffineMatrix(&_draw_info->affine);
1812 if (LocaleCompare("auto-gamma",option+1) == 0)
1814 (void) AutoGammaImage(_image,_exception);
1817 if (LocaleCompare("auto-level",option+1) == 0)
1819 (void) AutoLevelImage(_image,_exception);
1822 if (LocaleCompare("auto-orient",option+1) == 0)
1824 new_image=AutoOrientImage(_image,_image->orientation,_exception);
1827 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1831 if (LocaleCompare("black-threshold",option+1) == 0)
1833 if (IfMagickFalse(IsGeometry(arg1)))
1834 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1835 (void) BlackThresholdImage(_image,arg1,_exception);
1838 if (LocaleCompare("blue-shift",option+1) == 0)
1840 geometry_info.rho=1.5;
1842 flags=ParseGeometry(arg1,&geometry_info);
1843 if ((flags & RhoValue) == 0)
1844 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1846 new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1849 if (LocaleCompare("blur",option+1) == 0)
1851 flags=ParseGeometry(arg1,&geometry_info);
1852 if ((flags & (RhoValue|SigmaValue)) == 0)
1853 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1854 if ((flags & SigmaValue) == 0)
1855 geometry_info.sigma=1.0;
1856 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1860 if (LocaleCompare("border",option+1) == 0)
1868 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1869 if ((flags & (WidthValue | HeightValue)) == 0)
1870 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1871 compose=OverCompositeOp;
1872 value=GetImageOption(_image_info,"compose");
1873 if (value != (const char *) NULL)
1874 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1876 new_image=BorderImage(_image,&geometry,compose,_exception);
1879 if (LocaleCompare("brightness-contrast",option+1) == 0)
1891 flags=ParseGeometry(arg1,&geometry_info);
1892 if ((flags & RhoValue) == 0)
1893 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1894 brightness=geometry_info.rho;
1896 if ((flags & SigmaValue) != 0)
1897 contrast=geometry_info.sigma;
1898 (void) BrightnessContrastImage(_image,brightness,contrast,
1902 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1906 if (LocaleCompare("cdl",option+1) == 0)
1908 /* Note: arguments do not have percent escapes expanded */
1910 *color_correction_collection;
1913 Color correct with a color decision list.
1915 color_correction_collection=FileToString(arg1,~0,_exception);
1916 if (color_correction_collection == (char *) NULL)
1918 (void) ColorDecisionListImage(_image,color_correction_collection,
1922 if (LocaleCompare("charcoal",option+1) == 0)
1924 flags=ParseGeometry(arg1,&geometry_info);
1925 if ((flags & (RhoValue|SigmaValue)) == 0)
1926 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1927 if ((flags & SigmaValue) == 0)
1928 geometry_info.sigma=1.0;
1929 if ((flags & XiValue) == 0)
1930 geometry_info.xi=1.0;
1931 new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1935 if (LocaleCompare("chop",option+1) == 0)
1937 if (IfMagickFalse(IsGeometry(arg1)))
1938 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1939 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
1940 new_image=ChopImage(_image,&geometry,_exception);
1943 if (LocaleCompare("clamp",option+1) == 0)
1945 (void) ClampImage(_image,_exception);
1948 if (LocaleCompare("clip",option+1) == 0)
1951 (void) ClipImage(_image,_exception);
1952 else /* "+mask" remove the write mask */
1953 (void) SetImageMask(_image,(Image *) NULL,_exception);
1956 if (LocaleCompare("clip-mask",option+1) == 0)
1958 /* Note: arguments do not have percent escapes expanded */
1975 /* use "+clip-mask" Remove the write mask for -clip-path */
1976 (void) SetImageMask(_image,(Image *) NULL,_exception);
1979 mask_image=GetImageCache(_image_info,arg1,_exception);
1980 if (mask_image == (Image *) NULL)
1982 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
1984 /* Create a write mask from cli_wand mask image */
1985 /* FUTURE: use Alpha operations instead and create a Grey Image */
1986 mask_view=AcquireAuthenticCacheView(mask_image,_exception);
1987 for (y=0; y < (ssize_t) mask_image->rows; y++)
1989 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1991 if (q == (Quantum *) NULL)
1993 for (x=0; x < (ssize_t) mask_image->columns; x++)
1995 if (mask_image->alpha_trait != BlendPixelTrait)
1996 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
1997 SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
1998 q+=GetPixelChannels(mask_image);
2000 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2003 /* clean up and set the write mask */
2004 mask_view=DestroyCacheView(mask_view);
2005 mask_image->alpha_trait=BlendPixelTrait;
2006 (void) SetImageColorspace(_image,GRAYColorspace,_exception);
2007 (void) SetImageMask(_image,mask_image,_exception);
2008 mask_image=DestroyImage(mask_image);
2011 if (LocaleCompare("clip-path",option+1) == 0)
2013 (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2014 /* Note: Use "+clip-mask" remove the write mask added */
2017 if (LocaleCompare("colorize",option+1) == 0)
2019 if (IfMagickFalse(IsGeometry(arg1)))
2020 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2021 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2024 if (LocaleCompare("color-matrix",option+1) == 0)
2029 kernel=AcquireKernelInfo(arg1);
2030 if (kernel == (KernelInfo *) NULL)
2031 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2032 new_image=ColorMatrixImage(_image,kernel,_exception);
2033 kernel=DestroyKernelInfo(kernel);
2036 if (LocaleCompare("colors",option+1) == 0)
2038 /* Reduce the number of colors in the image.
2039 FUTURE: also provide 'plus version with image 'color counts'
2041 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2042 if (_quantize_info->number_colors == 0)
2043 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2044 if ((_image->storage_class == DirectClass) ||
2045 _image->colors > _quantize_info->number_colors)
2046 (void) QuantizeImage(_quantize_info,_image,_exception);
2048 (void) CompressImageColormap(_image,_exception);
2051 if (LocaleCompare("colorspace",option+1) == 0)
2053 /* WARNING: this is both a image_info setting (already done)
2054 and a operator to change image colorspace.
2056 FUTURE: default colorspace should be sRGB!
2057 Unless some type of 'linear colorspace' mode is set.
2059 Note that +colorspace sets "undefined" or no effect on
2060 new images, but forces images already in memory back to RGB!
2061 That seems to be a little strange!
2063 (void) TransformImageColorspace(_image,
2064 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2068 if (LocaleCompare("contrast",option+1) == 0)
2070 CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2071 (void) ContrastImage(_image,IsNormalOp,_exception);
2074 if (LocaleCompare("contrast-stretch",option+1) == 0)
2083 flags=ParseGeometry(arg1,&geometry_info);
2084 if ((flags & RhoValue) == 0)
2085 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2086 black_point=geometry_info.rho;
2087 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2089 if ((flags & PercentValue) != 0) {
2090 black_point*=(double) _image->columns*_image->rows/100.0;
2091 white_point*=(double) _image->columns*_image->rows/100.0;
2093 white_point=(double) _image->columns*_image->rows-
2095 (void) ContrastStretchImage(_image,black_point,white_point,
2099 if (LocaleCompare("convolve",option+1) == 0)
2104 kernel_info=AcquireKernelInfo(arg1);
2105 if (kernel_info == (KernelInfo *) NULL)
2106 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2107 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2109 kernel_info=DestroyKernelInfo(kernel_info);
2112 if (LocaleCompare("crop",option+1) == 0)
2114 /* WARNING: This can generate multiple images! */
2115 if (IfMagickFalse(IsGeometry(arg1)))
2116 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2117 new_image=CropImageToTiles(_image,arg1,_exception);
2120 if (LocaleCompare("cycle",option+1) == 0)
2122 if (IfMagickFalse(IsGeometry(arg1)))
2123 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2124 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2128 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2132 if (LocaleCompare("decipher",option+1) == 0)
2134 /* Note: arguments do not have percent escapes expanded */
2138 passkey=FileToStringInfo(arg1,~0,_exception);
2139 if (passkey == (StringInfo *) NULL)
2140 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2142 (void) PasskeyDecipherImage(_image,passkey,_exception);
2143 passkey=DestroyStringInfo(passkey);
2146 if (LocaleCompare("depth",option+1) == 0)
2148 /* The _image_info->depth setting has already been set
2149 We just need to apply it to all images in current sequence
2151 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2152 That is it really is an operation, not a setting! Arrgghhh
2154 FUTURE: this should not be an operator!!!
2156 (void) SetImageDepth(_image,_image_info->depth,_exception);
2159 if (LocaleCompare("deskew",option+1) == 0)
2165 if (IfMagickFalse(IsGeometry(arg1)))
2166 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2167 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2170 threshold=40.0*QuantumRange/100.0;
2171 new_image=DeskewImage(_image,threshold,_exception);
2174 if (LocaleCompare("despeckle",option+1) == 0)
2176 new_image=DespeckleImage(_image,_exception);
2179 if (LocaleCompare("distort",option+1) == 0)
2187 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2189 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2191 if ((DistortImageMethod) parse == ResizeDistortion)
2195 /* Special Case - Argument is actually a resize geometry!
2196 ** Convert that to an appropriate distortion argument array.
2197 ** FUTURE: make a separate special resize operator
2198 Roll into a resize special operator */
2199 if (IfMagickFalse(IsGeometry(arg2)))
2200 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2202 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2203 resize_args[0]=(double) geometry.width;
2204 resize_args[1]=(double) geometry.height;
2205 new_image=DistortImage(_image,(DistortImageMethod) parse,
2206 (size_t)2,resize_args,MagickTrue,_exception);
2209 /* convert argument string into an array of doubles */
2210 args = StringToArrayOfDoubles(arg2,&count,_exception);
2211 if (args == (double *)NULL )
2212 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2214 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2215 IsPlusOp,_exception);
2216 args=(double *) RelinquishMagickMemory(args);
2219 if (LocaleCompare("draw",option+1) == 0)
2221 (void) CloneString(&_draw_info->primitive,arg1);
2222 (void) DrawImage(_image,_draw_info,_exception);
2223 (void) CloneString(&_draw_info->primitive,(char *)NULL);
2226 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2230 if (LocaleCompare("edge",option+1) == 0)
2232 flags=ParseGeometry(arg1,&geometry_info);
2233 if ((flags & (RhoValue|SigmaValue)) == 0)
2234 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2235 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2238 if (LocaleCompare("emboss",option+1) == 0)
2240 flags=ParseGeometry(arg1,&geometry_info);
2241 if ((flags & (RhoValue|SigmaValue)) == 0)
2242 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2243 if ((flags & SigmaValue) == 0)
2244 geometry_info.sigma=1.0;
2245 new_image=EmbossImage(_image,geometry_info.rho,
2246 geometry_info.sigma,_exception);
2249 if (LocaleCompare("encipher",option+1) == 0)
2251 /* Note: arguments do not have percent escapes expanded */
2255 passkey=FileToStringInfo(arg1,~0,_exception);
2256 if (passkey != (StringInfo *) NULL)
2258 (void) PasskeyEncipherImage(_image,passkey,_exception);
2259 passkey=DestroyStringInfo(passkey);
2263 if (LocaleCompare("enhance",option+1) == 0)
2265 new_image=EnhanceImage(_image,_exception);
2268 if (LocaleCompare("equalize",option+1) == 0)
2270 (void) EqualizeImage(_image,_exception);
2273 if (LocaleCompare("evaluate",option+1) == 0)
2278 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2280 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2282 if (IfMagickFalse(IsGeometry(arg2)))
2283 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2284 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2285 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2289 if (LocaleCompare("extent",option+1) == 0)
2291 if (IfMagickFalse(IsGeometry(arg1)))
2292 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2293 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2294 if (geometry.width == 0)
2295 geometry.width=_image->columns;
2296 if (geometry.height == 0)
2297 geometry.height=_image->rows;
2298 new_image=ExtentImage(_image,&geometry,_exception);
2301 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2305 if (LocaleCompare("flip",option+1) == 0)
2307 new_image=FlipImage(_image,_exception);
2310 if (LocaleCompare("flop",option+1) == 0)
2312 new_image=FlopImage(_image,_exception);
2315 if (LocaleCompare("floodfill",option+1) == 0)
2320 if (IfMagickFalse(IsGeometry(arg1)))
2321 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2322 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2323 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2324 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2325 geometry.y,IsPlusOp,_exception);
2328 if (LocaleCompare("frame",option+1) == 0)
2339 value=GetImageOption(_image_info,"compose");
2340 compose=OverCompositeOp; /* use Over not _image->compose */
2341 if (value != (const char *) NULL)
2342 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2344 if (IfMagickFalse(IsGeometry(arg1)))
2345 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2346 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2347 frame_info.width=geometry.width;
2348 frame_info.height=geometry.height;
2349 frame_info.outer_bevel=geometry.x;
2350 frame_info.inner_bevel=geometry.y;
2351 frame_info.x=(ssize_t) frame_info.width;
2352 frame_info.y=(ssize_t) frame_info.height;
2353 frame_info.width=_image->columns+2*frame_info.width;
2354 frame_info.height=_image->rows+2*frame_info.height;
2355 new_image=FrameImage(_image,&frame_info,compose,_exception);
2358 if (LocaleCompare("function",option+1) == 0)
2366 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2368 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2370 /* convert argument string into an array of doubles */
2371 args = StringToArrayOfDoubles(arg2,&count,_exception);
2372 if (args == (double *)NULL )
2373 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2375 (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2377 args=(double *) RelinquishMagickMemory(args);
2380 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2384 if (LocaleCompare("gamma",option+1) == 0)
2389 if (IfMagickFalse(IsGeometry(arg1)))
2390 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2391 constant=StringToDouble(arg1,(char **) NULL);
2393 /* Using Gamma, via a cache */
2395 constant=PerceptibleReciprocal(constant);
2396 (void) GammaImage(_image,constant,_exception);
2398 /* Using Evaluate POW, direct update of values - more accurite */
2400 constant=PerceptibleReciprocal(constant);
2401 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2403 /* Set gamma setting -- Old meaning of "+gamma"
2404 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2408 if (LocaleCompare("gaussian-blur",option+1) == 0)
2410 flags=ParseGeometry(arg1,&geometry_info);
2411 if ((flags & (RhoValue|SigmaValue)) == 0)
2412 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2413 if ((flags & SigmaValue) == 0)
2414 geometry_info.sigma=1.0;
2415 new_image=GaussianBlurImage(_image,geometry_info.rho,
2416 geometry_info.sigma,_exception);
2419 if (LocaleCompare("gaussian",option+1) == 0)
2421 CLIWandWarnReplaced("-gaussian-blur");
2422 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL);
2424 if (LocaleCompare("geometry",option+1) == 0)
2427 Record Image offset for composition. (A Setting)
2428 Resize last _image. (ListOperator) -- DEPRECIATE
2429 FUTURE: Why if no 'offset' does this resize ALL images?
2430 Also why is the setting recorded in the IMAGE non-sense!
2433 { /* remove the previous composition geometry offset! */
2434 if (_image->geometry != (char *) NULL)
2435 _image->geometry=DestroyString(_image->geometry);
2438 if (IfMagickFalse(IsGeometry(arg1)))
2439 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2440 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2441 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2442 (void) CloneString(&_image->geometry,arg1);
2444 new_image=ResizeImage(_image,geometry.width,geometry.height,
2445 _image->filter,_exception);
2448 if (LocaleCompare("grayscale",option+1) == 0)
2450 parse=ParseCommandOption(MagickPixelIntensityOptions,
2453 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2455 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2458 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2462 if (LocaleCompare("identify",option+1) == 0)
2468 format=GetImageOption(_image_info,"format");
2469 if (format == (char *) NULL)
2471 (void) IdentifyImage(_image,stdout,_image_info->verbose,
2475 text=InterpretImageProperties(_image_info,_image,format,_exception);
2476 if (text == (char *) NULL)
2477 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2479 (void) fputs(text,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 IsPlusOp,_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("magnify",option+1) == 0)
2640 new_image=MagnifyImage(_image,_exception);
2643 if (LocaleCompare("map",option+1) == 0)
2645 CLIWandWarnReplaced("-remap");
2646 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL);
2649 if (LocaleCompare("mask",option+1) == 0)
2651 /* Note: arguments do not have percent escapes expanded */
2656 { /* Remove a mask. */
2657 (void) SetImageMask(_image,(Image *) NULL,_exception);
2660 /* Set the image mask. */
2661 mask=GetImageCache(_image_info,arg1,_exception);
2662 if (mask == (Image *) NULL)
2664 (void) SetImageMask(_image,mask,_exception);
2665 mask=DestroyImage(mask);
2668 if (LocaleCompare("matte",option+1) == 0)
2670 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2671 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2672 DeactivateAlphaChannel, _exception);
2675 if (LocaleCompare("median",option+1) == 0)
2677 CLIWandWarnReplaced("-statistic Median");
2678 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1);
2681 if (LocaleCompare("mode",option+1) == 0)
2683 /* FUTURE: note this is also a special "montage" option */
2684 CLIWandWarnReplaced("-statistic Mode");
2685 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1);
2688 if (LocaleCompare("modulate",option+1) == 0)
2690 if (IfMagickFalse(IsGeometry(arg1)))
2691 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2692 (void) ModulateImage(_image,arg1,_exception);
2695 if (LocaleCompare("monitor",option+1) == 0)
2697 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2698 (MagickProgressMonitor) NULL,(void *) NULL);
2701 if (LocaleCompare("monochrome",option+1) == 0)
2703 (void) SetImageType(_image,BilevelType,_exception);
2706 if (LocaleCompare("morphology",option+1) == 0)
2709 token[MaxTextExtent];
2721 GetMagickToken(p,&p,token);
2722 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2724 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2727 GetMagickToken(p,&p,token);
2728 if ((*p == ':') || (*p == ','))
2729 GetMagickToken(p,&p,token);
2731 iterations=(ssize_t) StringToLong(p);
2732 kernel=AcquireKernelInfo(arg2);
2733 if (kernel == (KernelInfo *) NULL)
2734 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",
2736 new_image=MorphologyImage(_image,(MorphologyMethod)parse,
2737 iterations,kernel,_exception);
2738 kernel=DestroyKernelInfo(kernel);
2741 if (LocaleCompare("motion-blur",option+1) == 0)
2743 flags=ParseGeometry(arg1,&geometry_info);
2744 if ((flags & (RhoValue|SigmaValue)) == 0)
2745 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2746 if ((flags & SigmaValue) == 0)
2747 geometry_info.sigma=1.0;
2748 new_image=MotionBlurImage(_image,geometry_info.rho,
2749 geometry_info.sigma,geometry_info.xi,_exception);
2752 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2756 if (LocaleCompare("negate",option+1) == 0)
2758 (void) NegateImage(_image, IsPlusOp, _exception);
2761 if (LocaleCompare("noise",option+1) == 0)
2771 CLIWandWarnReplaced("-statistic NonPeak");
2772 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1);
2775 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2777 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2780 value=GetImageOption(_image_info,"attenuate");
2781 if (value != (const char *) NULL)
2782 attenuate=StringToDouble(value,(char **) NULL);
2783 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2787 if (LocaleCompare("normalize",option+1) == 0)
2789 (void) NormalizeImage(_image,_exception);
2792 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2796 if (LocaleCompare("opaque",option+1) == 0)
2801 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2802 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2806 if (LocaleCompare("ordered-dither",option+1) == 0)
2808 (void) OrderedPosterizeImage(_image,arg1,_exception);
2811 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2815 if (LocaleCompare("paint",option+1) == 0)
2817 flags=ParseGeometry(arg1,&geometry_info);
2818 if ((flags & (RhoValue|SigmaValue)) == 0)
2819 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2820 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2824 if (LocaleCompare("perceptible",option+1) == 0)
2826 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2830 if (LocaleCompare("polaroid",option+1) == 0)
2842 random_info=AcquireRandomInfo();
2843 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2844 random_info=DestroyRandomInfo(random_info);
2847 flags=ParseGeometry(arg1,&geometry_info);
2848 if ((flags & RhoValue) == 0)
2849 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2850 angle=geometry_info.rho;
2852 caption=GetImageProperty(_image,"caption",_exception);
2853 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2854 _image->interpolate,_exception);
2857 if (LocaleCompare("posterize",option+1) == 0)
2859 flags=ParseGeometry(arg1,&geometry_info);
2860 if ((flags & RhoValue) == 0)
2861 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2862 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2863 _quantize_info->dither_method,_exception);
2866 if (LocaleCompare("preview",option+1) == 0)
2868 /* FUTURE: should be a 'Genesis' option?
2869 Option however is also in WandSettingOptionInfo()
2872 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2874 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2876 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2879 if (LocaleCompare("profile",option+1) == 0)
2881 /* Note: arguments do not have percent escapes expanded */
2895 { /* Remove a profile from the _image. */
2896 (void) ProfileImage(_image,arg1,(const unsigned char *)
2900 /* Associate a profile with the _image. */
2901 profile_info=CloneImageInfo(_image_info);
2902 profile=GetImageProfile(_image,"iptc");
2903 if (profile != (StringInfo *) NULL)
2904 profile_info->profile=(void *) CloneStringInfo(profile);
2905 profile_image=GetImageCache(profile_info,arg1,_exception);
2906 profile_info=DestroyImageInfo(profile_info);
2907 if (profile_image == (Image *) NULL)
2912 profile_info=CloneImageInfo(_image_info);
2913 (void) CopyMagickString(profile_info->filename,arg1,
2915 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
2916 if (profile != (StringInfo *) NULL)
2918 (void) ProfileImage(_image,profile_info->magick,
2919 GetStringInfoDatum(profile),(size_t)
2920 GetStringInfoLength(profile),_exception);
2921 profile=DestroyStringInfo(profile);
2923 profile_info=DestroyImageInfo(profile_info);
2926 ResetImageProfileIterator(profile_image);
2927 name=GetNextImageProfile(profile_image);
2928 while (name != (const char *) NULL)
2930 profile=GetImageProfile(profile_image,name);
2931 if (profile != (StringInfo *) NULL)
2932 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
2933 (size_t) GetStringInfoLength(profile),_exception);
2934 name=GetNextImageProfile(profile_image);
2936 profile_image=DestroyImage(profile_image);
2939 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2943 if (LocaleCompare("radial-blur",option+1) == 0)
2945 flags=ParseGeometry(arg1,&geometry_info);
2946 if ((flags & RhoValue) == 0)
2947 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2948 new_image=RadialBlurImage(_image,geometry_info.rho,_exception);
2951 if (LocaleCompare("raise",option+1) == 0)
2953 if (IfMagickFalse(IsGeometry(arg1)))
2954 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2955 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2956 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
2959 if (LocaleCompare("random-threshold",option+1) == 0)
2961 if (IfMagickFalse(IsGeometry(arg1)))
2962 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2963 (void) RandomThresholdImage(_image,arg1,_exception);
2966 if (LocaleCompare("recolor",option+1) == 0)
2968 CLIWandWarnReplaced("-color-matrix");
2969 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL);
2971 if (LocaleCompare("remap",option+1) == 0)
2973 /* Note: arguments do not have percent escapes expanded */
2977 remap_image=GetImageCache(_image_info,arg1,_exception);
2978 if (remap_image == (Image *) NULL)
2980 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
2981 remap_image=DestroyImage(remap_image);
2984 if (LocaleCompare("repage",option+1) == 0)
2988 if (IfMagickFalse(IsGeometry(arg1)))
2989 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
2991 (void) ResetImagePage(_image,arg1);
2994 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
2997 if (LocaleCompare("resample",option+1) == 0)
2999 /* FUTURE: Roll into a resize special operation */
3000 flags=ParseGeometry(arg1,&geometry_info);
3001 if ((flags & (RhoValue|SigmaValue)) == 0)
3002 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3003 if ((flags & SigmaValue) == 0)
3004 geometry_info.sigma=geometry_info.rho;
3005 new_image=ResampleImage(_image,geometry_info.rho,
3006 geometry_info.sigma,_image->filter,_exception);
3009 if (LocaleCompare("resize",option+1) == 0)
3011 if (IfMagickFalse(IsGeometry(arg1)))
3012 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3013 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3014 new_image=ResizeImage(_image,geometry.width,geometry.height,
3015 _image->filter,_exception);
3018 if (LocaleCompare("roll",option+1) == 0)
3020 if (IfMagickFalse(IsGeometry(arg1)))
3021 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3022 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3023 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3026 if (LocaleCompare("rotate",option+1) == 0)
3028 flags=ParseGeometry(arg1,&geometry_info);
3029 if ((flags & RhoValue) == 0)
3030 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3031 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3033 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3035 new_image=RotateImage(_image,geometry_info.rho,_exception);
3038 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3042 if (LocaleCompare("sample",option+1) == 0)
3044 /* FUTURE: Roll into a resize special operator */
3045 if (IfMagickFalse(IsGeometry(arg1)))
3046 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3047 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3048 new_image=SampleImage(_image,geometry.width,geometry.height,
3052 if (LocaleCompare("scale",option+1) == 0)
3054 /* FUTURE: Roll into a resize special operator */
3055 if (IfMagickFalse(IsGeometry(arg1)))
3056 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3057 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3058 new_image=ScaleImage(_image,geometry.width,geometry.height,
3062 if (LocaleCompare("segment",option+1) == 0)
3064 flags=ParseGeometry(arg1,&geometry_info);
3065 if ((flags & (RhoValue|SigmaValue)) == 0)
3066 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3067 if ((flags & SigmaValue) == 0)
3068 geometry_info.sigma=1.0;
3069 (void) SegmentImage(_image,_image->colorspace,
3070 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3074 if (LocaleCompare("selective-blur",option+1) == 0)
3076 flags=ParseGeometry(arg1,&geometry_info);
3077 if ((flags & (RhoValue|SigmaValue)) == 0)
3078 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3079 if ((flags & SigmaValue) == 0)
3080 geometry_info.sigma=1.0;
3081 if ((flags & PercentValue) != 0)
3082 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3083 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3084 geometry_info.sigma,geometry_info.xi,_exception);
3087 if (LocaleCompare("separate",option+1) == 0)
3089 /* WARNING: This can generate multiple images! */
3090 /* FUTURE - this may be replaced by a "-channel" method */
3091 new_image=SeparateImages(_image,_exception);
3094 if (LocaleCompare("sepia-tone",option+1) == 0)
3096 if (IfMagickFalse(IsGeometry(arg1)))
3097 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3098 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3099 (double) QuantumRange+1.0),_exception);
3102 if (LocaleCompare("shade",option+1) == 0)
3104 flags=ParseGeometry(arg1,&geometry_info);
3105 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3106 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3107 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3108 geometry_info.sigma,_exception);
3111 if (LocaleCompare("shadow",option+1) == 0)
3113 flags=ParseGeometry(arg1,&geometry_info);
3114 if ((flags & (RhoValue|SigmaValue)) == 0)
3115 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3116 if ((flags & SigmaValue) == 0)
3117 geometry_info.sigma=1.0;
3118 if ((flags & XiValue) == 0)
3119 geometry_info.xi=4.0;
3120 if ((flags & PsiValue) == 0)
3121 geometry_info.psi=4.0;
3122 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3123 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3124 ceil(geometry_info.psi-0.5),_exception);
3127 if (LocaleCompare("sharpen",option+1) == 0)
3129 flags=ParseGeometry(arg1,&geometry_info);
3130 if ((flags & (RhoValue|SigmaValue)) == 0)
3131 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3132 if ((flags & SigmaValue) == 0)
3133 geometry_info.sigma=1.0;
3134 if ((flags & XiValue) == 0)
3135 geometry_info.xi=0.0;
3136 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3140 if (LocaleCompare("shave",option+1) == 0)
3142 if (IfMagickFalse(IsGeometry(arg1)))
3143 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3144 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3145 new_image=ShaveImage(_image,&geometry,_exception);
3148 if (LocaleCompare("shear",option+1) == 0)
3150 flags=ParseGeometry(arg1,&geometry_info);
3151 if ((flags & RhoValue) == 0)
3152 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3153 if ((flags & SigmaValue) == 0)
3154 geometry_info.sigma=geometry_info.rho;
3155 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3159 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3161 flags=ParseGeometry(arg1,&geometry_info);
3162 if ((flags & RhoValue) == 0)
3163 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3164 if ((flags & SigmaValue) == 0)
3165 geometry_info.sigma=(double) QuantumRange/2.0;
3166 if ((flags & PercentValue) != 0)
3167 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3169 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3170 geometry_info.sigma,_exception);
3173 if (LocaleCompare("sketch",option+1) == 0)
3175 flags=ParseGeometry(arg1,&geometry_info);
3176 if ((flags & (RhoValue|SigmaValue)) == 0)
3177 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3178 if ((flags & SigmaValue) == 0)
3179 geometry_info.sigma=1.0;
3180 new_image=SketchImage(_image,geometry_info.rho,
3181 geometry_info.sigma,geometry_info.xi,_exception);
3184 if (LocaleCompare("solarize",option+1) == 0)
3186 if (IfMagickFalse(IsGeometry(arg1)))
3187 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3188 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3189 QuantumRange+1.0),_exception);
3192 if (LocaleCompare("sparse-color",option+1) == 0)
3194 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3196 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3198 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3202 if (LocaleCompare("splice",option+1) == 0)
3204 if (IfMagickFalse(IsGeometry(arg1)))
3205 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3206 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3207 new_image=SpliceImage(_image,&geometry,_exception);
3210 if (LocaleCompare("spread",option+1) == 0)
3212 flags=ParseGeometry(arg1,&geometry_info);
3213 if ((flags & RhoValue) == 0)
3214 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3215 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3219 if (LocaleCompare("statistic",option+1) == 0)
3221 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3223 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3225 flags=ParseGeometry(arg2,&geometry_info);
3226 if ((flags & RhoValue) == 0)
3227 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3228 if ((flags & SigmaValue) == 0)
3229 geometry_info.sigma=geometry_info.rho;
3230 new_image=StatisticImage(_image,(StatisticType)parse,
3231 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3235 if (LocaleCompare("strip",option+1) == 0)
3237 (void) StripImage(_image,_exception);
3240 if (LocaleCompare("swirl",option+1) == 0)
3242 flags=ParseGeometry(arg1,&geometry_info);
3243 if ((flags & RhoValue) == 0)
3244 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3245 new_image=SwirlImage(_image,geometry_info.rho,
3246 _image->interpolate,_exception);
3249 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3253 if (LocaleCompare("threshold",option+1) == 0)
3258 threshold=(double) QuantumRange/2;
3260 if (IfMagickFalse(IsGeometry(arg1)))
3261 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3262 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3264 (void) BilevelImage(_image,threshold,_exception);
3267 if (LocaleCompare("thumbnail",option+1) == 0)
3269 if (IfMagickFalse(IsGeometry(arg1)))
3270 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3271 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3272 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3276 if (LocaleCompare("tint",option+1) == 0)
3278 if (IfMagickFalse(IsGeometry(arg1)))
3279 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3280 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3283 if (LocaleCompare("transform",option+1) == 0)
3285 CLIWandWarnReplaced("+distort AffineProjection");
3286 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3289 if (LocaleCompare("transparent",option+1) == 0)
3294 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3295 (void) TransparentPaintImage(_image,&target,(Quantum)
3296 TransparentAlpha,IsPlusOp,_exception);
3299 if (LocaleCompare("transpose",option+1) == 0)
3301 new_image=TransposeImage(_image,_exception);
3304 if (LocaleCompare("transverse",option+1) == 0)
3306 new_image=TransverseImage(_image,_exception);
3309 if (LocaleCompare("trim",option+1) == 0)
3311 new_image=TrimImage(_image,_exception);
3314 if (LocaleCompare("type",option+1) == 0)
3316 /* Note that "type" setting should have already been defined */
3317 (void) SetImageType(_image,_image_info->type,_exception);
3320 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3324 if (LocaleCompare("unique",option+1) == 0)
3326 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3327 Option is not documented, bt appears to be for "identify".
3328 We may need a identify specific verbose!
3331 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3334 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3335 (void) SetImageArtifact(_image,"verbose","true");
3338 if (LocaleCompare("unique-colors",option+1) == 0)
3340 new_image=UniqueImageColors(_image,_exception);
3343 if (LocaleCompare("unsharp",option+1) == 0)
3345 flags=ParseGeometry(arg1,&geometry_info);
3346 if ((flags & (RhoValue|SigmaValue)) == 0)
3347 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3348 if ((flags & SigmaValue) == 0)
3349 geometry_info.sigma=1.0;
3350 if ((flags & XiValue) == 0)
3351 geometry_info.xi=1.0;
3352 if ((flags & PsiValue) == 0)
3353 geometry_info.psi=0.05;
3354 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3355 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3358 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3362 if (LocaleCompare("verbose",option+1) == 0)
3364 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3365 three places! ImageArtifact ImageOption _image_info->verbose
3366 Some how new images also get this artifact!
3368 (void) SetImageArtifact(_image,option+1,
3369 IfNormalOp ? "true" : "false" );
3372 if (LocaleCompare("vignette",option+1) == 0)
3374 flags=ParseGeometry(arg1,&geometry_info);
3375 if ((flags & (RhoValue|SigmaValue)) == 0)
3376 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3377 if ((flags & SigmaValue) == 0)
3378 geometry_info.sigma=1.0;
3379 if ((flags & XiValue) == 0)
3380 geometry_info.xi=0.1*_image->columns;
3381 if ((flags & PsiValue) == 0)
3382 geometry_info.psi=0.1*_image->rows;
3383 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3384 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3385 ceil(geometry_info.psi-0.5),_exception);
3388 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3392 if (LocaleCompare("wave",option+1) == 0)
3394 flags=ParseGeometry(arg1,&geometry_info);
3395 if ((flags & (RhoValue|SigmaValue)) == 0)
3396 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3397 if ((flags & SigmaValue) == 0)
3398 geometry_info.sigma=1.0;
3399 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3400 _image->interpolate,_exception);
3403 if (LocaleCompare("white-threshold",option+1) == 0)
3405 if (IfMagickFalse(IsGeometry(arg1)))
3406 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3407 (void) WhiteThresholdImage(_image,arg1,_exception);
3410 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3413 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3415 /* clean up percent escape interpreted strings */
3417 arg1=DestroyString((char *)arg1);
3419 arg2=DestroyString((char *)arg2);
3421 /* Replace current image with any image that was generated
3422 and set image point to last image (so image->next is correct) */
3423 if (new_image != (Image *) NULL)
3424 ReplaceImageInListReturnLast(&_image,new_image);
3429 #undef _quantize_info
3438 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3439 const char *option,const char *arg1,const char *arg2)
3441 #if !USE_WAND_METHODS
3447 assert(cli_wand != (MagickCLI *) NULL);
3448 assert(cli_wand->signature == WandSignature);
3449 assert(cli_wand->wand.signature == WandSignature);
3450 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3452 if (IfMagickTrue(cli_wand->wand.debug))
3453 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3454 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3456 #if !USE_WAND_METHODS
3457 /* FUTURE add appropriate tracing */
3459 n=GetImageListLength(cli_wand->wand.images);
3460 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3463 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3464 if ( cli_wand->wand.images->next == (Image *) NULL )
3466 cli_wand->wand.images=cli_wand->wand.images->next;
3469 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3471 MagickResetIterator(&cli_wand->wand);
3472 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3473 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3474 MagickResetIterator(&cli_wand->wand);
3480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3484 + C L I L i s t O p e r a t o r I m a g e s %
3488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3490 % CLIListOperatorImages() applies a single operation that is apply to the
3491 % entire image list as a whole. The result is often a complete replacment
3492 % of the image list with a completely new list, or with just a single image
3495 % The format of the MogrifyImage method is:
3497 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3498 % const char *option,const char *arg1,const char *arg2)
3500 % A description of each parameter follows:
3502 % o cli_wand: structure holding settings to be applied
3504 % o option: The option string for the operation
3506 % o arg1, arg2: optional argument strings to the operation
3507 % arg2 is currently not used
3510 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3511 const char *option,const char *arg1n,const char *arg2n)
3513 const char /* percent escaped versions of the args */
3526 #define _image_info (cli_wand->wand.image_info)
3527 #define _images (cli_wand->wand.images)
3528 #define _exception (cli_wand->wand.exception)
3529 #define _draw_info (cli_wand->draw_info)
3530 #define _quantize_info (cli_wand->quantize_info)
3531 #define _process_flags (cli_wand->process_flags)
3532 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3533 #define IfNormalOp (*option=='-')
3534 #define IfPlusOp (*option!='-')
3535 #define IsNormalOp IsMagickTrue(IfNormalOp)
3537 assert(cli_wand != (MagickCLI *) NULL);
3538 assert(cli_wand->signature == WandSignature);
3539 assert(cli_wand->wand.signature == WandSignature);
3540 assert(_images != (Image *) NULL); /* _images must be present */
3542 if (IfMagickTrue(cli_wand->wand.debug))
3543 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3544 "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
3549 /* Interpret Percent Escapes in Arguments - using first image */
3550 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3551 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3552 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3553 /* Interpret Percent escapes in argument 1 */
3554 if (arg1n != (char *) NULL) {
3555 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3556 if (arg1 == (char *) NULL) {
3557 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3558 arg1=arg1n; /* use the given argument as is */
3561 if (arg2n != (char *) NULL) {
3562 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3563 if (arg2 == (char *) NULL) {
3564 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3565 arg2=arg2n; /* use the given argument as is */
3569 #undef _process_flags
3573 new_images=NewImageList();
3575 switch (*(option+1))
3579 if (LocaleCompare("append",option+1) == 0)
3581 new_images=AppendImages(_images,IsNormalOp,_exception);
3584 if (LocaleCompare("average",option+1) == 0)
3586 CLIWandWarnReplaced("-evaluate-sequence Mean");
3587 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3590 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3594 if (LocaleCompare("channel-fx",option+1) == 0)
3596 new_images=ChannelFxImage(_images,arg1,_exception);
3599 if (LocaleCompare("clut",option+1) == 0)
3604 /* FUTURE - make this a compose option, and thus can be used
3605 with layers compose or even compose last image over all other
3608 new_images=RemoveFirstImageFromList(&_images);
3609 clut_image=RemoveLastImageFromList(&_images);
3610 /* FUTURE - produce Exception, rather than silent fail */
3611 if (clut_image == (Image *) NULL)
3613 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3614 clut_image=DestroyImage(clut_image);
3617 if (LocaleCompare("coalesce",option+1) == 0)
3619 new_images=CoalesceImages(_images,_exception);
3622 if (LocaleCompare("combine",option+1) == 0)
3624 parse = (ssize_t) sRGBColorspace; /* default (backward compatible) */
3626 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
3629 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3631 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3634 if (LocaleCompare("compare",option+1) == 0)
3647 Mathematically and visually annotate the difference between an
3648 image and its reconstruction.
3650 image=RemoveFirstImageFromList(&_images);
3651 reconstruct_image=RemoveFirstImageFromList(&_images);
3652 /* FUTURE - produce Exception, rather than silent fail */
3653 if (reconstruct_image == (Image *) NULL)
3655 metric=UndefinedErrorMetric;
3656 option=GetImageOption(_image_info,"metric");
3657 if (option != (const char *) NULL)
3658 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3659 MagickFalse,option);
3660 new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3663 reconstruct_image=DestroyImage(reconstruct_image);
3664 image=DestroyImage(image);
3667 if (LocaleCompare("complex",option+1) == 0)
3669 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3671 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3673 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3676 if (LocaleCompare("composite",option+1) == 0)
3694 /* Compose value from "-compose" option only */
3695 value=GetImageOption(_image_info,"compose");
3696 if (value == (const char *) NULL)
3697 compose=OverCompositeOp; /* use Over not source_image->compose */
3699 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3702 /* Get "clip-to-self" expert setting (false is normal) */
3703 value=GetImageOption(_image_info,"compose:clip-to-self");
3704 if (value == (const char *) NULL)
3705 clip_to_self=MagickTrue;
3707 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3708 "compose:clip-to-self")); /* if this is true */
3709 value=GetImageOption(_image_info,"compose:outside-overlay");
3710 if (value != (const char *) NULL) { /* or this false */
3711 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3712 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3715 new_images=RemoveFirstImageFromList(&_images);
3716 source_image=RemoveFirstImageFromList(&_images);
3717 if (source_image == (Image *) NULL)
3718 break; /* FUTURE - produce Exception, rather than silent fail */
3720 /* FUTURE - this should not be here! - should be part of -geometry */
3721 (void) TransformImage(&source_image,(char *) NULL,
3722 source_image->geometry,_exception);
3723 SetGeometry(source_image,&geometry);
3724 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3725 GravityAdjustGeometry(new_images->columns,new_images->rows,
3726 new_images->gravity, &geometry);
3727 mask_image=RemoveFirstImageFromList(&_images);
3728 if (mask_image != (Image *) NULL)
3730 if ((compose == DisplaceCompositeOp) ||
3731 (compose == DistortCompositeOp))
3732 status&=CompositeImage(source_image,mask_image,
3733 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3742 source_geometry.width=mask_image->columns;
3743 source_geometry.height=mask_image->rows;
3744 source_geometry.x=(-geometry.x);
3745 source_geometry.y=(-geometry.y);
3748 image=ExtentImage(source_image,&source_geometry,_exception);
3749 if (image != (Image *) NULL)
3751 source_image=DestroyImage(source_image);
3754 status&=CompositeImage(source_image,mask_image,
3755 IntensityCompositeOp,MagickTrue,0,0,_exception);
3757 mask_image=DestroyImage(mask_image);
3759 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3760 geometry.x,geometry.y,_exception);
3761 source_image=DestroyImage(source_image);
3764 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3768 if (LocaleCompare("deconstruct",option+1) == 0)
3770 CLIWandWarnReplaced("-layer CompareAny");
3771 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3774 if (LocaleCompare("delete",option+1) == 0)
3777 DeleteImages(&_images,arg1,_exception);
3779 DeleteImages(&_images,"-1",_exception);
3782 if (LocaleCompare("duplicate",option+1) == 0)
3792 if (IfMagickFalse(IsGeometry(arg1)))
3793 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3795 number_duplicates=(size_t) StringToLong(arg1);
3797 if (p == (const char *) NULL)
3798 new_images=DuplicateImages(_images,number_duplicates,"-1",
3801 new_images=DuplicateImages(_images,number_duplicates,p,
3805 new_images=DuplicateImages(_images,1,"-1",_exception);
3806 AppendImageToList(&_images, new_images);
3807 new_images=(Image *)NULL;
3810 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3814 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3816 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3818 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3820 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3824 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3828 if (LocaleCompare("fft",option+1) == 0)
3830 new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception);
3833 if (LocaleCompare("flatten",option+1) == 0)
3835 /* REDIRECTED to use -layers flatten instead */
3836 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3839 if (LocaleCompare("fx",option+1) == 0)
3841 new_images=FxImage(_images,arg1,_exception);
3844 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3848 if (LocaleCompare("hald-clut",option+1) == 0)
3850 /* FUTURE - make this a compose option (and thus layers compose )
3851 or perhaps compose last image over all other _images.
3856 new_images=RemoveFirstImageFromList(&_images);
3857 hald_image=RemoveLastImageFromList(&_images);
3858 if (hald_image == (Image *) NULL)
3860 (void) HaldClutImage(new_images,hald_image,_exception);
3861 hald_image=DestroyImage(hald_image);
3864 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3868 if (LocaleCompare("ift",option+1) == 0)
3874 magnitude_image=RemoveFirstImageFromList(&_images);
3875 phase_image=RemoveFirstImageFromList(&_images);
3876 /* FUTURE - produce Exception, rather than silent fail */
3877 if (phase_image == (Image *) NULL)
3879 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3880 IsNormalOp,_exception);
3881 magnitude_image=DestroyImage(magnitude_image);
3882 phase_image=DestroyImage(phase_image);
3885 if (LocaleCompare("insert",option+1) == 0)
3894 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3895 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3897 insert_image=RemoveLastImageFromList(&_images);
3899 index=(ssize_t) StringToLong(arg1);
3900 index_image=insert_image;
3902 PrependImageToList(&_images,insert_image);
3903 else if (index == (ssize_t) GetImageListLength(_images))
3904 AppendImageToList(&_images,insert_image);
3907 index_image=GetImageFromList(_images,index-1);
3908 if (index_image == (Image *) NULL)
3909 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3910 InsertImageInList(&index_image,insert_image);
3912 _images=GetFirstImageInList(index_image);
3915 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3919 if (LocaleCompare("layers",option+1) == 0)
3921 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3923 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3925 switch ((LayerMethod) parse)
3929 new_images=CoalesceImages(_images,_exception);
3932 case CompareAnyLayer:
3933 case CompareClearLayer:
3934 case CompareOverlayLayer:
3937 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
3944 case TrimBoundsLayer:
3946 new_images=MergeImageLayers(_images,(LayerMethod) parse,
3952 new_images=DisposeImages(_images,_exception);
3955 case OptimizeImageLayer:
3957 new_images=OptimizeImageLayers(_images,_exception);
3960 case OptimizePlusLayer:
3962 new_images=OptimizePlusImageLayers(_images,_exception);
3965 case OptimizeTransLayer:
3967 OptimizeImageTransparency(_images,_exception);
3970 case RemoveDupsLayer:
3972 RemoveDuplicateLayers(&_images,_exception);
3975 case RemoveZeroLayer:
3977 RemoveZeroDelayLayers(&_images,_exception);
3981 { /* General Purpose, GIF Animation Optimizer. */
3982 new_images=CoalesceImages(_images,_exception);
3983 if (new_images == (Image *) NULL)
3985 _images=DestroyImageList(_images);
3986 _images=OptimizeImageLayers(new_images,_exception);
3987 if (_images == (Image *) NULL)
3989 new_images=DestroyImageList(new_images);
3990 OptimizeImageTransparency(_images,_exception);
3991 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
3995 case CompositeLayer:
4009 value=GetImageOption(_image_info,"compose");
4010 compose=OverCompositeOp; /* Default to Over */
4011 if (value != (const char *) NULL)
4012 compose=(CompositeOperator) ParseCommandOption(
4013 MagickComposeOptions,MagickFalse,value);
4015 /* Split image sequence at the first 'NULL:' image. */
4017 while (source != (Image *) NULL)
4019 source=GetNextImageInList(source);
4020 if ((source != (Image *) NULL) &&
4021 (LocaleCompare(source->magick,"NULL") == 0))
4024 if (source != (Image *) NULL)
4026 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4027 (GetNextImageInList(source) == (Image *) NULL))
4028 source=(Image *) NULL;
4030 { /* Separate the two lists, junk the null: image. */
4031 source=SplitImageList(source->previous);
4032 DeleteImageFromList(&source);
4035 if (source == (Image *) NULL)
4037 (void) ThrowMagickException(_exception,GetMagickModule(),
4038 OptionError,"MissingNullSeparator","layers Composite");
4041 /* Adjust offset with gravity and virtual canvas. */
4042 SetGeometry(_images,&geometry);
4043 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4044 geometry.width=source->page.width != 0 ?
4045 source->page.width : source->columns;
4046 geometry.height=source->page.height != 0 ?
4047 source->page.height : source->rows;
4048 GravityAdjustGeometry(_images->page.width != 0 ?
4049 _images->page.width : _images->columns,
4050 _images->page.height != 0 ? _images->page.height :
4051 _images->rows,_images->gravity,&geometry);
4053 /* Compose the two image sequences together */
4054 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4056 source=DestroyImageList(source);
4062 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4066 if (LocaleCompare("map",option+1) == 0)
4068 CLIWandWarnReplaced("+remap");
4069 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4072 if (LocaleCompare("metric",option+1) == 0)
4074 if (LocaleCompare("morph",option+1) == 0)
4079 if (IfMagickFalse(IsGeometry(arg1)))
4080 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4081 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4083 if (morph_image == (Image *) NULL)
4085 _images=DestroyImageList(_images);
4086 _images=morph_image;
4089 if (LocaleCompare("mosaic",option+1) == 0)
4091 /* REDIRECTED to use -layers mosaic instead */
4092 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4095 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4099 if (LocaleCompare("poly",option+1) == 0)
4107 /* convert argument string into an array of doubles */
4108 args = StringToArrayOfDoubles(arg2,&count,_exception);
4109 if (args == (double *)NULL )
4110 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4111 new_images=PolynomialImage(_images,count >> 1,args,_exception);
4112 args=(double *) RelinquishMagickMemory(args);
4115 if (LocaleCompare("process",option+1) == 0)
4117 /* FUTURE: better parsing using ScriptToken() from string ??? */
4125 arguments=StringToArgv(arg1,&number_arguments);
4126 if (arguments == (char **) NULL)
4128 if (strchr(arguments[1],'=') != (char *) NULL)
4149 Support old style syntax, filter="-option arg1".
4151 length=strlen(arg1);
4152 token=(char *) NULL;
4153 if (~length >= (MaxTextExtent-1))
4154 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4156 if (token == (char *) NULL)
4160 token_info=AcquireTokenInfo();
4161 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4162 "\"",'\0',&breaker,&next,"e);
4163 token_info=DestroyTokenInfo(token_info);
4169 argv=(&(arguments[next]));
4170 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4173 token=DestroyString(token);
4176 (void) SubstituteString(&arguments[1],"-","");
4177 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4178 number_arguments-2,(const char **) arguments+2,_exception);
4179 for (j=0; j < number_arguments; j++)
4180 arguments[j]=DestroyString(arguments[j]);
4181 arguments=(char **) RelinquishMagickMemory(arguments);
4184 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4188 if (LocaleCompare("remap",option+1) == 0)
4190 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4193 if (LocaleCompare("reverse",option+1) == 0)
4195 ReverseImageList(&_images);
4198 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4202 if (LocaleCompare("smush",option+1) == 0)
4204 /* FUTURE: this option needs more work to make better */
4208 if (IfMagickFalse(IsGeometry(arg1)))
4209 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4210 offset=(ssize_t) StringToLong(arg1);
4211 new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4214 if (LocaleCompare("subimage",option+1) == 0)
4232 base_image=GetImageFromList(_images,0);
4233 compare_image=GetImageFromList(_images,1);
4235 /* Comparision Metric */
4236 metric=UndefinedErrorMetric;
4237 value=GetImageOption(_image_info,"metric");
4238 if (value != (const char *) NULL)
4239 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4242 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4243 &offset,&similarity,_exception);
4245 if ( new_images != (Image *)NULL ) {
4247 result[MaxTextExtent];
4249 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4250 (void) SetImageProperty(new_images,"subimage:similarity",result,
4252 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4254 (void) SetImageProperty(new_images,"subimage:x",result,
4256 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4258 (void) SetImageProperty(new_images,"subimage:y",result,
4260 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4261 (unsigned long) offset.width,(unsigned long) offset.height,
4262 (long) offset.x,(long) offset.y);
4263 (void) SetImageProperty(new_images,"subimage:offset",result,
4268 if (LocaleCompare("swap",option+1) == 0) {
4288 flags=ParseGeometry(arg1,&geometry_info);
4289 if ((flags & RhoValue) == 0)
4290 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4291 index=(ssize_t) geometry_info.rho;
4292 if ((flags & SigmaValue) != 0)
4293 swap_index=(ssize_t) geometry_info.sigma;
4295 p=GetImageFromList(_images,index);
4296 q=GetImageFromList(_images,swap_index);
4297 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4299 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4301 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4304 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4305 swap=CloneImage(p,0,0,MagickTrue,_exception);
4306 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4307 ReplaceImageInList(&q,swap);
4308 _images=GetFirstImageInList(q);
4311 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4314 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4317 /* clean up percent escape interpreted strings */
4319 arg1=DestroyString((char *)arg1);
4321 arg2=DestroyString((char *)arg2);
4323 /* if new image list generated, replace existing image list */
4324 if (new_images == (Image *) NULL)
4325 return(status == MagickFalse ? 0 : 1);
4326 _images=DestroyImageList(_images);
4327 _images=GetFirstImageInList(new_images);
4328 return(status == MagickFalse ? 0 : 1);
4334 #undef _quantize_info
4341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4345 + C L I N o I m a g e O p e r a t i o n s %
4349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4351 % CLINoImageOperator() Applies operations that may not actually need images
4354 % The classic operators of this type is "-read", which actually creates
4355 % images even when no images are present. Or image stack operators, which
4356 % can be applied (push or pop) to an empty image list.
4358 % Note that these operators may involve other special 'option' prefix
4359 % characters other than '-' or '+', namely parenthesis and braces.
4361 % The format of the CLINoImageOption method is:
4363 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4364 % const char *arg1, const char *arg2)
4366 % A description of each parameter follows:
4368 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4370 % o option: The special option (with any switch char) to process
4372 % o arg1 & arg2: Argument for option, if required
4373 % Currently arg2 is not used.
4376 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4377 const char *option,const char *arg1n,const char *arg2n)
4379 const char /* percent escaped versions of the args */
4383 #define _image_info (cli_wand->wand.image_info)
4384 #define _images (cli_wand->wand.images)
4385 #define _exception (cli_wand->wand.exception)
4386 #define _process_flags (cli_wand->process_flags)
4387 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4388 #define IfNormalOp (*option=='-')
4389 #define IfPlusOp (*option!='-')
4391 assert(cli_wand != (MagickCLI *) NULL);
4392 assert(cli_wand->signature == WandSignature);
4393 assert(cli_wand->wand.signature == WandSignature);
4395 if (IfMagickTrue(cli_wand->wand.debug))
4396 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4397 "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
4402 /* Interpret Percent Escapes in Arguments - using first image */
4403 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4404 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4405 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4406 /* Interpret Percent escapes in argument 1 */
4407 if (arg1n != (char *) NULL) {
4408 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4409 if (arg1 == (char *) NULL) {
4410 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4411 arg1=arg1n; /* use the given argument as is */
4414 if (arg2n != (char *) NULL) {
4415 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4416 if (arg2 == (char *) NULL) {
4417 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4418 arg2=arg2n; /* use the given argument as is */
4422 #undef _process_flags
4425 do { /* break to exit code */
4427 No-op options (ignore these)
4429 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4431 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4433 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4435 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4437 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4442 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4443 ( LocaleCompare("--",option) == 0 ) ) {
4444 /* Do Glob filename Expansion for 'arg1' then read all images.
4446 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4447 * (but attaching to the filenames in the generated argument list) any
4448 * [...] read modifiers that may be present.
4450 * For example: It will expand '*.gif[20x20]' into a list such as
4451 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4453 * NOTE: In IMv6 this was done globally across all images. This
4454 * meant you could include IM options in '@filename' lists, but you
4455 * could not include comments. Doing it only for image read makes
4456 * it far more secure.
4458 * Note: arguments do not have percent escapes expanded for security
4466 argv = (char **) &arg1;
4468 /* Expand 'glob' expressions in the given filename.
4469 Expansion handles any 'coder:' prefix, or read modifiers attached
4470 to the filename, including them in the resulting expanded list.
4472 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4473 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4474 option,GetExceptionMessage(errno));
4476 /* loop over expanded filename list, and read then all in */
4477 for (i=0; i<argc; i++) {
4480 if (IfMagickTrue(_image_info->ping))
4481 new_images=PingImages(_image_info,argv[i],_exception);
4483 new_images=ReadImages(_image_info,argv[i],_exception);
4484 AppendImageToList(&_images, new_images);
4486 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4491 Note: Writing a empty image list is valid in specific cases
4493 if (LocaleCompare("write",option+1) == 0) {
4494 /* Note: arguments do not have percent escapes expanded */
4504 /* Need images, unless a "null:" output coder is used */
4505 if ( _images == (Image *) NULL ) {
4506 if ( LocaleCompare(arg1,"null:") == 0 )
4508 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4511 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4512 (void) DeleteImageRegistry(key);
4513 write_images=_images;
4515 write_images=CloneImageList(_images,_exception);
4516 write_info=CloneImageInfo(_image_info);
4517 (void) WriteImages(write_info,write_images,arg1,_exception);
4518 write_info=DestroyImageInfo(write_info);
4520 write_images=DestroyImageList(write_images);
4524 Parenthesis and Brace operations
4526 if (LocaleCompare("(",option) == 0) {
4527 /* stack 'push' images */
4535 node=cli_wand->image_list_stack;
4536 for ( ; node != (Stack *)NULL; node=node->next)
4538 if ( size >= MAX_STACK_DEPTH )
4539 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4540 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4541 if (node == (Stack *) NULL)
4542 CLIWandExceptionBreak(ResourceLimitFatalError,
4543 "MemoryAllocationFailed",option);
4544 node->data = (void *)cli_wand->wand.images;
4545 node->next = cli_wand->image_list_stack;
4546 cli_wand->image_list_stack = node;
4547 cli_wand->wand.images = NewImageList();
4549 /* handle respect-parenthesis */
4550 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4551 "respect-parenthesis"))))
4552 option="{"; /* fall-thru so as to push image settings too */
4555 /* fall thru to operation */
4557 if (LocaleCompare("{",option) == 0) {
4558 /* stack 'push' of image_info settings */
4566 node=cli_wand->image_info_stack;
4567 for ( ; node != (Stack *)NULL; node=node->next)
4569 if ( size >= MAX_STACK_DEPTH )
4570 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4571 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4572 if (node == (Stack *) NULL)
4573 CLIWandExceptionBreak(ResourceLimitFatalError,
4574 "MemoryAllocationFailed",option);
4576 node->data = (void *)cli_wand->wand.image_info;
4577 node->next = cli_wand->image_info_stack;
4579 cli_wand->image_info_stack = node;
4580 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4581 if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4582 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4584 cli_wand->wand.image_info = (ImageInfo *)node->data;
4585 node = (Stack *)RelinquishMagickMemory(node);
4591 if (LocaleCompare(")",option) == 0) {
4592 /* pop images from stack */
4596 node = (Stack *)cli_wand->image_list_stack;
4597 if ( node == (Stack *)NULL)
4598 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4599 cli_wand->image_list_stack = node->next;
4601 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4602 cli_wand->wand.images= (Image *)node->data;
4603 node = (Stack *)RelinquishMagickMemory(node);
4605 /* handle respect-parenthesis - of the previous 'pushed' settings */
4606 node = cli_wand->image_info_stack;
4607 if ( node != (Stack *)NULL)
4609 if (IfMagickTrue(IsStringTrue(GetImageOption(
4610 cli_wand->wand.image_info,"respect-parenthesis"))))
4611 option="}"; /* fall-thru so as to pop image settings too */
4617 /* fall thru to next if */
4619 if (LocaleCompare("}",option) == 0) {
4620 /* pop image_info settings from stack */
4624 node = (Stack *)cli_wand->image_info_stack;
4625 if ( node == (Stack *)NULL)
4626 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4627 cli_wand->image_info_stack = node->next;
4629 (void) DestroyImageInfo(cli_wand->wand.image_info);
4630 cli_wand->wand.image_info = (ImageInfo *)node->data;
4631 node = (Stack *)RelinquishMagickMemory(node);
4633 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4634 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4635 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4639 if (LocaleCompare("print",option+1) == 0)
4641 (void) FormatLocaleFile(stdout,"%s",arg1);
4644 if (LocaleCompare("set",option+1) == 0)
4646 /* Settings are applied to each image in memory in turn (if any).
4647 While a option: only need to be applied once globally.
4649 NOTE: rguments have not been automatically percent expaneded
4652 /* escape the 'key' once only, using first image. */
4653 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4654 if (arg1 == (char *) NULL)
4655 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4658 if (LocaleNCompare(arg1,"registry:",9) == 0)
4662 (void) DeleteImageRegistry(arg1+9);
4663 arg1=DestroyString((char *)arg1);
4666 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4667 if (arg2 == (char *) NULL) {
4668 arg1=DestroyString((char *)arg1);
4669 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4672 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4673 arg1=DestroyString((char *)arg1);
4674 arg2=DestroyString((char *)arg2);
4677 if (LocaleNCompare(arg1,"option:",7) == 0)
4679 /* delete equivelent artifact from all images (if any) */
4680 if (_images != (Image *)NULL)
4682 MagickResetIterator(&cli_wand->wand);
4683 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4684 (void) DeleteImageArtifact(_images,arg1+7);
4685 MagickResetIterator(&cli_wand->wand);
4687 /* now set/delete the global option as needed */
4688 /* FUTURE: make escapes in a global 'option:' delayed */
4692 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4693 if (arg2 == (char *) NULL)
4694 CLIWandExceptionBreak(OptionWarning,
4695 "InterpretPropertyFailure",option);
4697 (void) SetImageOption(_image_info,arg1+7,arg2);
4698 arg1=DestroyString((char *)arg1);
4699 arg2=DestroyString((char *)arg2);
4702 /* Set Artifacts/Properties/Attributes all images (required) */
4703 if ( _images == (Image *) NULL )
4704 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4706 MagickResetIterator(&cli_wand->wand);
4707 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4712 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4713 if (arg2 == (char *) NULL)
4714 CLIWandExceptionBreak(OptionWarning,
4715 "InterpretPropertyFailure",option);
4717 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4718 (void) SetImageArtifact(_images,arg1+9,arg2);
4719 else if (LocaleNCompare(arg1,"property:",9) == 0)
4720 (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4722 (void) SetImageProperty(_images,arg1,arg2,_exception);
4723 arg2=DestroyString((char *)arg2);
4725 MagickResetIterator(&cli_wand->wand);
4726 arg1=DestroyString((char *)arg1);
4729 if (LocaleCompare("clone",option+1) == 0) {
4735 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4736 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4737 if ( cli_wand->image_list_stack == (Stack *)NULL)
4738 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4739 new_images = (Image *)cli_wand->image_list_stack->data;
4740 if (new_images == (Image *) NULL)
4741 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4742 new_images=CloneImages(new_images,arg1,_exception);
4743 if (new_images == (Image *) NULL)
4744 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4745 AppendImageToList(&_images,new_images);
4749 Informational Operations.
4751 Note that these do not require either a cli-wand or images!
4752 Though currently a cli-wand much be provided regardless.
4754 if (LocaleCompare("version",option+1) == 0)
4756 ListMagickVersion(stdout);
4759 if (LocaleCompare("list",option+1) == 0) {
4761 FUTURE: This 'switch' should really be part of MagickCore
4766 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4768 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4773 case MagickCoderOptions:
4775 (void) ListCoderInfo((FILE *) NULL,_exception);
4778 case MagickColorOptions:
4780 (void) ListColorInfo((FILE *) NULL,_exception);
4783 case MagickConfigureOptions:
4785 (void) ListConfigureInfo((FILE *) NULL,_exception);
4788 case MagickDelegateOptions:
4790 (void) ListDelegateInfo((FILE *) NULL,_exception);
4793 case MagickFontOptions:
4795 (void) ListTypeInfo((FILE *) NULL,_exception);
4798 case MagickFormatOptions:
4799 (void) ListMagickInfo((FILE *) NULL,_exception);
4801 case MagickLocaleOptions:
4802 (void) ListLocaleInfo((FILE *) NULL,_exception);
4804 case MagickLogOptions:
4805 (void) ListLogInfo((FILE *) NULL,_exception);
4807 case MagickMagicOptions:
4808 (void) ListMagicInfo((FILE *) NULL,_exception);
4810 case MagickMimeOptions:
4811 (void) ListMimeInfo((FILE *) NULL,_exception);
4813 case MagickModuleOptions:
4814 (void) ListModuleInfo((FILE *) NULL,_exception);
4816 case MagickPolicyOptions:
4817 (void) ListPolicyInfo((FILE *) NULL,_exception);
4819 case MagickResourceOptions:
4820 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4822 case MagickThresholdOptions:
4823 (void) ListThresholdMaps((FILE *) NULL,_exception);
4826 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4833 CLIWandException(OptionError,"UnrecognizedOption",option);
4835 } while (0); /* break to exit code. */
4837 /* clean up percent escape interpreted strings */
4839 arg1=DestroyString((char *)arg1);
4841 arg2=DestroyString((char *)arg2);
4851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4855 + C L I O p t i o n %
4859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861 % CLIOption() Processes the given option using the given CLI Magick Wand.
4862 % The option arguments can be variable in number, though at this time no more
4863 % that two is actually used by any option (this may change). Excess options
4864 % are simply ignored.
4866 % If the cli_wand->command pointer is non-null, then it is assumed that the
4867 % option has already been search for up from the CommandOptions[] table in
4868 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4869 % routine will do the lookup instead. The pointer is reset afterward.
4871 % This action allows the caller to lookup and pre-handle any 'special'
4872 % options, (such as implicit reads) before calling this general option
4873 % handler to deal with 'standard' command line options.
4875 % The format of the CLIOption method is:
4877 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4879 % A description of each parameter follows:
4881 % o cli_wand: the main CLI Wand to use.
4883 % o option: The special option (with any switch char) to process
4885 % o args: any required arguments for an option (variable number)
4889 % CLIoption(cli_wand,"-read","rose:");
4890 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4891 % CLIoption(cli_wand,"-distort","SRT:","30");
4892 % CLIoption(cli_wand,"-write","rotated_rose.png");
4895 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4897 const char /* extracted option args from args */
4904 assert(cli_wand != (MagickCLI *) NULL);
4905 assert(cli_wand->signature == WandSignature);
4906 assert(cli_wand->wand.signature == WandSignature);
4908 do { /* Break Code Block for error handling */
4910 /* get information about option */
4911 if ( cli_wand->command == (const OptionInfo *) NULL )
4912 cli_wand->command = GetCommandOptionInfo(option);
4914 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4915 option, cli_wand->command->mnemonic );
4917 option_type=(CommandOptionFlags) cli_wand->command->flags;
4919 if ( option_type == UndefinedOptionFlag )
4920 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4922 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4924 /* depreciated options */
4925 if ( (option_type & DeprecateOptionFlag) != 0 )
4926 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4928 /* options that this module does not handle */
4929 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
4930 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
4932 /* Get argument strings from VarArgs
4933 How can you determine if enough arguments was supplied?
4934 What happens if not enough arguments were supplied?
4937 count = cli_wand->command->type;
4942 va_start(operands,option);
4946 arg1=(const char *) va_arg(operands, const char *);
4948 arg2=(const char *) va_arg(operands, const char *);
4952 (void) FormatLocaleFile(stderr,
4953 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
4954 option,(long) count,option_type,arg1,arg2);
4959 Call the appropriate option handler
4962 /* FUTURE: this is temporary - get 'settings' to handle distribution of
4963 settings to images attributes,proprieties,artifacts */
4964 if ( cli_wand->wand.images != (Image *)NULL )
4965 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
4966 cli_wand->wand.exception);
4968 if ( (option_type & SettingOptionFlags) != 0 ) {
4969 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
4970 // FUTURE: Sync Specific Settings into Image Properities (not global)
4973 /* Operators that do not need images - read, write, stack, clone */
4974 if ( (option_type & NoImageOperatorFlag) != 0)
4975 CLINoImageOperator(cli_wand, option, arg1, arg2);
4977 /* FUTURE: The not a setting part below is a temporary hack due to
4978 * some options being both a Setting and a Simple operator.
4979 * Specifically -monitor, -depth, and -colorspace */
4980 if ( cli_wand->wand.images == (Image *)NULL )
4981 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
4982 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
4983 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
4985 /* Operators which loop of individual images, simply */
4986 if ( (option_type & SimpleOperatorFlag) != 0 &&
4987 cli_wand->wand.images != (Image *)NULL) /* temp hack */
4988 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
4990 /* Operators that work on the image list as a whole */
4991 if ( (option_type & ListOperatorFlag) != 0 )
4992 CLIListOperatorImages(cli_wand, option, arg1, arg2);
4994 } while (0); /* end Break code block */
4996 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */