2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % OOO PPPP EEEE RRRR AA TTTTT III OOO N N %
7 % O O P P E R R A A T I O O NN N %
8 % O O PPPP EEE RRRR AAAA T I O O N N N %
9 % O O P E R R A A T I O O N NN %
10 % OOO P EEEE R RR A A T III OOO N N %
13 % CLI Magick Option Methods %
20 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % Apply the given options (settings, and simple, or sequence operations) to
37 % the given image(s) according to the current "image_info", "draw_info", and
38 % "quantize_info" settings, stored in a special CLI Image Wand.
40 % The final goal is to allow the execution in a strict one option at a time
41 % manner that is needed for 'pipelining and file scripting' of options in
44 % Anthony Thyssen, September 2011
50 #include "MagickWand/studio.h"
51 #include "MagickWand/MagickWand.h"
52 #include "MagickWand/magick-wand-private.h"
53 #include "MagickWand/mogrify.h"
54 #include "MagickWand/wand.h"
55 #include "MagickWand/wandcli.h"
56 #include "MagickWand/wandcli-private.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/monitor-private.h"
59 #include "MagickWand/operation.h"
60 #include "MagickCore/thread-private.h"
61 #include "MagickCore/string-private.h"
62 #include "MagickCore/pixel-private.h"
68 MogrifyBackgroundColor[] = "#fff", /* white */
69 MogrifyBorderColor[] = "#dfdfdf", /* sRGB gray */
70 MogrifyMatteColor[] = "#bdbdbd"; /* slightly darker gray */
75 #define USE_WAND_METHODS 1
76 #define MAX_STACK_DEPTH 32
77 #define UNDEFINED_COMPRESSION_QUALITY 0UL
79 /* FUTURE: why is this default so specific? */
80 #define DEFAULT_DISSIMILARITY_THRESHOLD "0.31830988618379067154"
82 /* For Debugging Geometry Input */
83 #define ReportGeometry(flags,info) \
84 (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", \
85 flags, info.rho, info.sigma, info.xi, info.psi )
88 ** Function to report on the progress of image operations
90 static MagickBooleanType MonitorProgress(const char *text,
91 const MagickOffsetType offset,const MagickSizeType extent,
92 void *wand_unused(cli_wandent_data))
95 message[MaxTextExtent],
106 (void) CopyMagickMemory(tag,text,MaxTextExtent);
108 if (p != (char *) NULL)
110 (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
111 locale_message=GetLocaleMessage(message);
112 if (locale_message == message)
114 if (p == (char *) NULL)
115 (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
116 locale_message,(long) offset,(unsigned long) extent,(long)
117 (100L*offset/(extent-1)));
119 (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
120 locale_message,p+1,(long) offset,(unsigned long) extent,(long)
121 (100L*offset/(extent-1)));
122 if (offset == (MagickOffsetType) (extent-1))
123 (void) FormatLocaleFile(stderr,"\n");
124 (void) fflush(stderr);
129 ** GetImageCache() will read an image into a image cache if not already
130 ** present then return the image that is in the cache under that filename.
132 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
133 ExceptionInfo *exception)
147 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
148 sans_exception=AcquireExceptionInfo();
149 image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
150 sans_exception=DestroyExceptionInfo(sans_exception);
151 if (image != (Image *) NULL)
153 read_info=CloneImageInfo(image_info);
154 if (path != (const char *) NULL)
155 (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
156 image=ReadImage(read_info,exception);
157 read_info=DestroyImageInfo(read_info);
158 if (image != (Image *) NULL)
159 (void) SetImageRegistry(ImageRegistryType,key,image,exception);
164 SparseColorOption() parse the complex -sparse-color argument into an
165 an array of floating point values than call SparseColorImage().
166 Argument is a complex mix of floating-point pixel coodinates, and color
167 specifications (or direct floating point numbers). The number of floats
168 needed to represent a color varies depending on the current channel
171 This really should be in MagickCore, so that other API's can make use of it.
173 static Image *SparseColorOption(const Image *image,
174 const SparseColorMethod method,const char *arguments,ExceptionInfo *exception)
177 token[MaxTextExtent];
201 assert(image != (Image *) NULL);
202 assert(image->signature == MagickSignature);
203 if (IfMagickTrue(image->debug))
204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
205 assert(exception != (ExceptionInfo *) NULL);
206 assert(exception->signature == MagickSignature);
208 Limit channels according to image
209 add up number of values needed per color.
212 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
214 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
216 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
218 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
219 (image->colorspace == CMYKColorspace))
221 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
222 image->alpha_trait == BlendPixelTrait)
226 Read string, to determine number of arguments needed,
232 GetMagickToken(p,&p,token);
233 if ( token[0] == ',' ) continue;
234 if ( isalpha((int) token[0]) || token[0] == '#' )
235 x += number_colors; /* color argument found */
237 x++; /* floating point argument */
239 /* control points and color values */
240 error = IsMagickTrue( x % (2+number_colors) );
242 if ( IfMagickTrue(error) ) {
243 (void) ThrowMagickException(exception,GetMagickModule(),
244 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
245 "Invalid number of Arguments");
246 return( (Image *)NULL);
249 /* Allocate and fill in the floating point arguments */
250 sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
251 sizeof(*sparse_arguments));
252 if (sparse_arguments == (double *) NULL) {
253 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
254 "MemoryAllocationFailed","%s","SparseColorOption");
255 return( (Image *)NULL);
257 (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
258 sizeof(*sparse_arguments));
261 while( *p != '\0' && x < number_arguments ) {
263 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
264 if ( token[0] == '\0' ) break;
265 if ( isalpha((int) token[0]) || token[0] == '#' ) {
266 (void) ThrowMagickException(exception,GetMagickModule(),
267 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
268 "Color found, instead of X-coord");
272 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
274 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
275 if ( token[0] == '\0' ) break;
276 if ( isalpha((int) token[0]) || token[0] == '#' ) {
277 (void) ThrowMagickException(exception,GetMagickModule(),
278 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
279 "Color found, instead of Y-coord");
283 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
284 /* color name or function given in string argument */
285 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
286 if ( token[0] == '\0' ) break;
287 if ( isalpha((int) token[0]) || token[0] == '#' ) {
288 /* Color string given */
289 (void) QueryColorCompliance(token,AllCompliance,&color,
291 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
292 sparse_arguments[x++] = QuantumScale*color.red;
293 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
294 sparse_arguments[x++] = QuantumScale*color.green;
295 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
296 sparse_arguments[x++] = QuantumScale*color.blue;
297 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
298 (image->colorspace == CMYKColorspace))
299 sparse_arguments[x++] = QuantumScale*color.black;
300 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
301 image->alpha_trait == BlendPixelTrait)
302 sparse_arguments[x++] = QuantumScale*color.alpha;
305 /* Colors given as a set of floating point values - experimental */
306 /* NB: token contains the first floating point value to use! */
307 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
309 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
310 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
312 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
313 token[0] = ','; /* used this token - get another */
315 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
317 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
318 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
320 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
321 token[0] = ','; /* used this token - get another */
323 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
325 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
326 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
328 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
329 token[0] = ','; /* used this token - get another */
331 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
332 (image->colorspace == CMYKColorspace))
334 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
335 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
337 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
338 token[0] = ','; /* used this token - get another */
340 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
341 image->alpha_trait == BlendPixelTrait)
343 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
344 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
346 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
347 token[0] = ','; /* used this token - get another */
351 if ( number_arguments != x && !error ) {
352 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
353 "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
354 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
355 return( (Image *)NULL);
358 return( (Image *)NULL);
360 /* Call the Sparse Color Interpolation function with the parsed arguments */
361 sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
363 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
364 return( sparse_image );
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372 % C L I S e t t i n g O p t i o n I n f o %
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 % CLISettingOptionInfo() applies a single settings option into a CLI wand
379 % holding the image_info, draw_info, quantize_info structures that will be
380 % used when processing the images.
382 % These options do no require images to be present in the CLI wand for them
383 % to be able to be set, in which case they will generally be applied to image
384 % that are read in later
386 % Options handled by this function are listed in CommandOptions[] of
387 % "option.c" that is one of "SettingOptionFlags" option flags.
389 % The format of the CLISettingOptionInfo method is:
391 % void CLISettingOptionInfo(MagickCLI *cli_wand,
392 % const char *option, const char *arg1, const char *arg2)
394 % A description of each parameter follows:
396 % o cli_wand: structure holding settings to be applied
398 % o option: The option string to be set
400 % o arg1, arg2: optional argument strings to the operation
401 % arg2 is currently only used by "-limit"
404 WandPrivate void CLISettingOptionInfo(MagickCLI *cli_wand,
405 const char *option,const char *arg1n, const char *arg2n)
408 parse; /* option argument parsing (string to value table lookup) */
410 const char /* percent escaped versions of the args */
414 #define _image_info (cli_wand->wand.image_info)
415 #define _image (cli_wand->wand.images)
416 #define _exception (cli_wand->wand.exception)
417 #define _draw_info (cli_wand->draw_info)
418 #define _quantize_info (cli_wand->quantize_info)
419 #define IfSetOption (*option=='-')
420 #define ArgBoolean IsMagickTrue(IfSetOption)
421 #define ArgBooleanNot IsMagickFalse(IfSetOption)
422 #define ArgBooleanString (IfSetOption?"true":"false")
423 #define ArgOption(def) (IfSetOption?arg1:(const char *)(def))
425 assert(cli_wand != (MagickCLI *) NULL);
426 assert(cli_wand->signature == WandSignature);
427 assert(cli_wand->wand.signature == WandSignature);
429 if (IfMagickTrue(cli_wand->wand.debug))
430 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
431 "- Setting Option: %s \"%s\" \"%s\"", option,arg1n,arg2n);
437 #define _process_flags (cli_wand->process_flags)
438 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
439 /* Interpret Percent Escapes in Arguments - using first image */
440 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
441 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
442 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
443 /* Interpret Percent escapes in argument 1 */
444 if (arg1n != (char *) NULL) {
445 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
446 if (arg1 == (char *) NULL) {
447 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
448 arg1=arg1n; /* use the given argument as is */
451 if (arg2n != (char *) NULL) {
452 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
453 if (arg2 == (char *) NULL) {
454 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
455 arg2=arg2n; /* use the given argument as is */
459 #undef _process_flags
467 if (LocaleCompare("adjoin",option+1) == 0)
469 _image_info->adjoin = ArgBoolean;
472 if (LocaleCompare("affine",option+1) == 0)
474 CLIWandWarnReplaced("-draw 'affine ...'");
476 (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception);
478 GetAffineMatrix(&_draw_info->affine);
481 if (LocaleCompare("antialias",option+1) == 0)
483 _image_info->antialias =
484 _draw_info->stroke_antialias =
485 _draw_info->text_antialias = ArgBoolean;
488 if (LocaleCompare("attenuate",option+1) == 0)
490 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
491 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
492 (void) SetImageOption(_image_info,option+1,ArgOption("1.0"));
495 if (LocaleCompare("authenticate",option+1) == 0)
497 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
500 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
504 if (LocaleCompare("background",option+1) == 0)
506 /* FUTURE: both _image_info attribute & ImageOption in use!
507 _image_info only used directly for generating new images.
508 SyncImageSettings() used to set per-image attribute.
510 FUTURE: if _image_info->background_color is not set then
511 we should fall back to per-image background_color
513 At this time -background will 'wipe out' the per-image
516 Better error handling of QueryColorCompliance() needed.
518 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
519 (void) QueryColorCompliance(ArgOption(MogrifyBackgroundColor),AllCompliance,
520 &_image_info->background_color,_exception);
523 if (LocaleCompare("bias",option+1) == 0)
525 /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias"
526 as it is actually rarely used except in direct convolve operations
527 Usage outside a direct convolve operation is actally non-sensible!
529 SyncImageSettings() used to set per-image attribute.
531 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
532 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
533 (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL));
536 if (LocaleCompare("black-point-compensation",option+1) == 0)
538 /* Used as a image chromaticity setting
539 SyncImageSettings() used to set per-image attribute.
541 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
544 if (LocaleCompare("blue-primary",option+1) == 0)
546 /* Image chromaticity X,Y NB: Y=X if Y not defined
547 Used by many coders including PNG
548 SyncImageSettings() used to set per-image attribute.
550 arg1=ArgOption("0.0");
551 if (IfMagickFalse(IsGeometry(arg1)))
552 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
553 (void) SetImageOption(_image_info,option+1,arg1);
556 if (LocaleCompare("bordercolor",option+1) == 0)
558 /* FUTURE: both _image_info attribute & ImageOption in use!
559 SyncImageSettings() used to set per-image attribute.
560 Better error checking of QueryColorCompliance().
564 (void) SetImageOption(_image_info,option+1,arg1);
565 (void) QueryColorCompliance(arg1,AllCompliance,
566 &_image_info->border_color,_exception);
567 (void) QueryColorCompliance(arg1,AllCompliance,
568 &_draw_info->border_color,_exception);
571 (void) DeleteImageOption(_image_info,option+1);
572 (void) QueryColorCompliance(MogrifyBorderColor,AllCompliance,
573 &_image_info->border_color,_exception);
574 (void) QueryColorCompliance(MogrifyBorderColor,AllCompliance,
575 &_draw_info->border_color,_exception);
578 if (LocaleCompare("box",option+1) == 0)
580 CLIWandWarnReplaced("-undercolor");
581 CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2);
584 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
588 if (LocaleCompare("cache",option+1) == 0)
593 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
594 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
595 limit=MagickResourceInfinity;
596 if (LocaleCompare("unlimited",arg1) != 0)
597 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0);
598 (void) SetMagickResourceLimit(MemoryResource,limit);
599 (void) SetMagickResourceLimit(MapResource,2*limit);
602 if (LocaleCompare("caption",option+1) == 0)
604 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
607 if (LocaleCompare("channel",option+1) == 0)
609 parse=ParseChannelOption(ArgOption("Default"));
611 CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",
613 _image_info->channel=(ChannelType) parse;
614 (void) SetImageOption(_image_info,option+1,arg1);
617 if (LocaleCompare("colorspace",option+1) == 0)
619 /* Setting used for new images via AquireImage()
620 But also used as a SimpleImageOperator
621 Undefined colorspace means don't modify images on
622 read or as a operation */
623 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
624 ArgOption("undefined"));
626 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
628 _image_info->colorspace=(ColorspaceType) parse;
631 if (LocaleCompare("comment",option+1) == 0)
633 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
636 if (LocaleCompare("compose",option+1) == 0)
638 /* FUTURE: _image_info should be used,
639 SyncImageSettings() used to set per-image attribute. - REMOVE
641 This setting should NOT be used to set image 'compose'
642 "-layer" operators shoud use _image_info if defined otherwise
643 they should use a per-image compose setting.
645 parse = ParseCommandOption(MagickComposeOptions,MagickFalse,
646 ArgOption("undefined"));
648 CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator",
650 _image_info->compose=(CompositeOperator) parse;
651 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
654 if (LocaleCompare("compress",option+1) == 0)
656 /* FUTURE: What should be used? _image_info or ImageOption ???
657 The former is more efficent, but Crisy prefers the latter!
658 SyncImageSettings() used to set per-image attribute.
660 The coders appears to use _image_info, not Image_Option
661 however the image attribute (for save) is set from the
664 Note that "undefined" is a different setting to "none".
666 parse = ParseCommandOption(MagickCompressOptions,MagickFalse,
667 ArgOption("undefined"));
669 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression",
671 _image_info->compression=(CompressionType) parse;
672 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
675 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
679 if (LocaleCompare("debug",option+1) == 0)
681 /* SyncImageSettings() used to set per-image attribute. */
682 arg1=ArgOption("none");
683 parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1);
685 CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType",
687 (void) SetLogEventMask(arg1);
688 _image_info->debug=IsEventLogging(); /* extract logging*/
689 cli_wand->wand.debug=IsEventLogging();
692 if (LocaleCompare("define",option+1) == 0)
694 if (LocaleNCompare(arg1,"registry:",9) == 0)
697 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception);
699 (void) DeleteImageRegistry(arg1+9);
702 /* DefineImageOption() equals SetImageOption() but with '=' */
704 (void) DefineImageOption(_image_info,arg1);
705 else if (IsMagickFalse(DeleteImageOption(_image_info,arg1)))
706 CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1);
709 if (LocaleCompare("delay",option+1) == 0)
711 /* Only used for new images via AcquireImage()
712 FUTURE: Option should also be used for "-morph" (color morphing)
715 if (IfMagickFalse(IsGeometry(arg1)))
716 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
717 (void) SetImageOption(_image_info,option+1,arg1);
720 if (LocaleCompare("density",option+1) == 0)
722 /* FUTURE: strings used in _image_info attr and _draw_info!
723 Basically as density can be in a XxY form!
725 SyncImageSettings() used to set per-image attribute.
727 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
728 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
729 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
730 (void) CloneString(&_image_info->density,ArgOption(NULL));
731 (void) CloneString(&_draw_info->density,_image_info->density);
734 if (LocaleCompare("depth",option+1) == 0)
736 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
737 SyncImageSettings() used to set per-image attribute.
739 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
740 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
741 _image_info->depth=IfSetOption?StringToUnsignedLong(arg1)
742 :MAGICKCORE_QUANTUM_DEPTH;
745 if (LocaleCompare("direction",option+1) == 0)
747 /* Image Option is only used to set _draw_info */
748 arg1=ArgOption("undefined");
749 parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1);
751 CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType",
753 _draw_info->direction=(DirectionType) parse;
754 (void) SetImageOption(_image_info,option+1,arg1);
757 if (LocaleCompare("display",option+1) == 0)
759 (void) CloneString(&_image_info->server_name,ArgOption(NULL));
760 (void) CloneString(&_draw_info->server_name,_image_info->server_name);
763 if (LocaleCompare("dispose",option+1) == 0)
765 /* only used in setting new images */
766 arg1=ArgOption("undefined");
767 parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1);
769 CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod",
771 (void) SetImageOption(_image_info,option+1,ArgOption("undefined"));
774 if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
776 /* FUTURE: this is only used by CompareImages() which is used
777 only by the "compare" CLI program at this time. */
778 arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD);
779 if (IfMagickFalse(IsGeometry(arg1)))
780 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
781 (void) SetImageOption(_image_info,option+1,arg1);
784 if (LocaleCompare("dither",option+1) == 0)
786 /* _image_info attr (on/off), _quantize_info attr (on/off)
787 but also ImageInfo and _quantize_info method!
788 FUTURE: merge the duality of the dithering options
790 _image_info->dither = ArgBoolean;
791 (void) SetImageOption(_image_info,option+1,ArgOption("none"));
792 _quantize_info->dither_method=(DitherMethod) ParseCommandOption(
793 MagickDitherOptions,MagickFalse,ArgOption("none"));
794 if (_quantize_info->dither_method == NoDitherMethod)
795 _image_info->dither = MagickFalse;
798 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
802 if (LocaleCompare("encoding",option+1) == 0)
804 (void) CloneString(&_draw_info->encoding,ArgOption("undefined"));
805 (void) SetImageOption(_image_info,option+1,_draw_info->encoding);
808 if (LocaleCompare("endian",option+1) == 0)
810 /* Both _image_info attr and ImageInfo */
811 arg1 = ArgOption("undefined");
812 parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1);
814 CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType",
816 /* FUTURE: check alloc/free of endian string! - remove? */
817 _image_info->endian=(EndianType) (*arg1);
818 (void) SetImageOption(_image_info,option+1,arg1);
821 if (LocaleCompare("extract",option+1) == 0)
823 (void) CloneString(&_image_info->extract,ArgOption(NULL));
826 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
830 if (LocaleCompare("family",option+1) == 0)
832 (void) CloneString(&_draw_info->family,ArgOption(NULL));
835 if (LocaleCompare("features",option+1) == 0)
837 (void) SetImageOption(_image_info,"identify:features",
840 (void) SetImageArtifact(_image,"verbose","true");
843 if (LocaleCompare("fill",option+1) == 0)
845 /* Set "fill" OR "fill-pattern" in _draw_info
846 The original fill color is preserved if a fill-pattern is given.
847 That way it does not effect other operations that directly using
848 the fill color and, can be retored using "+tile".
859 arg1 = ArgOption("none"); /* +fill turns it off! */
860 (void) SetImageOption(_image_info,option+1,arg1);
861 if (_draw_info->fill_pattern != (Image *) NULL)
862 _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern);
864 /* is it a color or a image? -- ignore exceptions */
865 sans=AcquireExceptionInfo();
866 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
867 sans=DestroyExceptionInfo(sans);
869 if (IfMagickFalse(status))
870 _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception);
872 _draw_info->fill=color;
875 if (LocaleCompare("filter",option+1) == 0)
877 /* SyncImageSettings() used to set per-image attribute. */
878 arg1 = ArgOption("undefined");
879 parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1);
881 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter",
883 (void) SetImageOption(_image_info,option+1,arg1);
886 if (LocaleCompare("font",option+1) == 0)
888 (void) CloneString(&_draw_info->font,ArgOption(NULL));
889 (void) CloneString(&_image_info->font,_draw_info->font);
892 if (LocaleCompare("format",option+1) == 0)
894 /* FUTURE: why the ping test, you could set ping after this! */
899 for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
900 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
901 _image_info->ping=MagickFalse;
903 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
906 if (LocaleCompare("fuzz",option+1) == 0)
908 /* Option used to set image fuzz! unless blank canvas (from color)
909 Image attribute used for color compare operations
910 SyncImageSettings() used to set per-image attribute.
912 FUTURE: Can't find anything else using _image_info->fuzz directly!
913 convert structure attribute to 'option' string
916 if (IfMagickFalse(IsGeometry(arg1)))
917 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
918 _image_info->fuzz=StringToDoubleInterval(arg1,(double)
920 (void) SetImageOption(_image_info,option+1,arg1);
923 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
927 if (LocaleCompare("gravity",option+1) == 0)
929 /* SyncImageSettings() used to set per-image attribute. */
930 arg1 = ArgOption("none");
931 parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1);
933 CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType",
935 _draw_info->gravity=(GravityType) parse;
936 (void) SetImageOption(_image_info,option+1,arg1);
939 if (LocaleCompare("green-primary",option+1) == 0)
941 /* Image chromaticity X,Y NB: Y=X if Y not defined
942 SyncImageSettings() used to set per-image attribute.
943 Used directly by many coders
945 arg1=ArgOption("0.0");
946 if (IfMagickFalse(IsGeometry(arg1)))
947 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
948 (void) SetImageOption(_image_info,option+1,arg1);
951 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
955 if (LocaleCompare("highlight-color",option+1) == 0)
957 /* FUTURE: this is only used by CompareImages() which is used
958 only by the "compare" CLI program at this time. */
959 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
962 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
966 if (LocaleCompare("intensity",option+1) == 0)
968 arg1 = ArgOption("undefined");
969 parse = ParseCommandOption(MagickPixelIntensityOptions,MagickFalse,
972 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityType",
974 (void) SetImageOption(_image_info,option+1,arg1);
977 if (LocaleCompare("intent",option+1) == 0)
979 /* Only used by coders: MIFF, MPC, BMP, PNG
980 and for image profile call to AcquireTransformThreadSet()
981 SyncImageSettings() used to set per-image attribute.
983 arg1 = ArgOption("undefined");
984 parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1);
986 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType",
988 (void) SetImageOption(_image_info,option+1,arg1);
991 if (LocaleCompare("interlace",option+1) == 0)
993 /* _image_info is directly used by coders (so why an image setting?)
994 SyncImageSettings() used to set per-image attribute.
996 arg1 = ArgOption("undefined");
997 parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1);
999 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType",
1001 _image_info->interlace=(InterlaceType) parse;
1002 (void) SetImageOption(_image_info,option+1,arg1);
1005 if (LocaleCompare("interline-spacing",option+1) == 0)
1007 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1008 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1009 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1010 _draw_info->interline_spacing=StringToDouble(ArgOption("0"),
1014 if (LocaleCompare("interpolate",option+1) == 0)
1016 /* SyncImageSettings() used to set per-image attribute. */
1017 arg1 = ArgOption("undefined");
1018 parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1);
1020 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod",
1022 (void) SetImageOption(_image_info,option+1,arg1);
1025 if (LocaleCompare("interword-spacing",option+1) == 0)
1027 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1028 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1029 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1030 _draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
1033 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1037 if (LocaleCompare("kerning",option+1) == 0)
1039 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1040 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1041 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1042 _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
1045 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1049 if (LocaleCompare("label",option+1) == 0)
1051 /* only used for new images - not in SyncImageOptions() */
1052 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1055 if (LocaleCompare("limit",option+1) == 0)
1060 limit=MagickResourceInfinity;
1061 parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1);
1063 CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType",
1065 if (LocaleCompare("unlimited",arg2) != 0)
1066 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
1067 (void) SetMagickResourceLimit((ResourceType)parse,limit);
1070 if (LocaleCompare("log",option+1) == 0)
1073 if ((strchr(arg1,'%') == (char *) NULL))
1074 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1075 (void) SetLogFormat(arg1);
1079 if (LocaleCompare("lowlight-color",option+1) == 0)
1081 /* FUTURE: this is only used by CompareImages() which is used
1082 only by the "compare" CLI program at this time. */
1083 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1086 if (LocaleCompare("loop",option+1) == 0)
1088 /* SyncImageSettings() used to set per-image attribute. */
1089 arg1=ArgOption("0");
1090 if (IfMagickFalse(IsGeometry(arg1)))
1091 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1092 (void) SetImageOption(_image_info,option+1,arg1);
1095 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1099 if (LocaleCompare("mattecolor",option+1) == 0)
1101 /* SyncImageSettings() used to set per-image attribute. */
1102 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1103 (void) QueryColorCompliance(ArgOption(MogrifyMatteColor),AllCompliance,
1104 &_image_info->matte_color,_exception);
1107 if (LocaleCompare("metric",option+1) == 0)
1109 /* FUTURE: this is only used by CompareImages() which is used
1110 only by the "compare" CLI program at this time. */
1111 parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1);
1113 CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType",
1115 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1118 if (LocaleCompare("moments",option+1) == 0)
1120 (void) SetImageOption(_image_info,"identify:moments",
1123 (void) SetImageArtifact(_image,"verbose","true");
1126 if (LocaleCompare("monitor",option+1) == 0)
1128 (void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
1129 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1132 if (LocaleCompare("monochrome",option+1) == 0)
1134 /* Setting (used by some input coders!) -- why?
1135 Warning: This is also Special '-type' SimpleOperator
1137 _image_info->monochrome= ArgBoolean;
1140 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1144 if (LocaleCompare("orient",option+1) == 0)
1146 /* Is not used when defining for new images.
1147 This makes it more of a 'operation' than a setting
1148 FUTURE: make set meta-data operator instead.
1149 SyncImageSettings() used to set per-image attribute.
1151 parse=ParseCommandOption(MagickOrientationOptions,MagickFalse,
1152 ArgOption("undefined"));
1154 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation",
1156 _image_info->orientation=(OrientationType)parse;
1157 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1160 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1164 if (LocaleCompare("page",option+1) == 0)
1166 /* Only used for new images and image generators.
1167 SyncImageSettings() used to set per-image attribute. ?????
1168 That last is WRONG!!!!
1169 FUTURE: adjust named 'page' sizes according density
1173 page[MaxTextExtent];
1186 (void) DeleteImageOption(_image_info,option+1);
1187 (void) CloneString(&_image_info->page,(char *) NULL);
1190 (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1191 image_option=GetImageOption(_image_info,"page");
1192 if (image_option != (const char *) NULL)
1193 flags=ParseAbsoluteGeometry(image_option,&geometry);
1194 canonical_page=GetPageGeometry(arg1);
1195 flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1196 canonical_page=DestroyString(canonical_page);
1197 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1198 (unsigned long) geometry.width,(unsigned long) geometry.height);
1199 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1200 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1201 (unsigned long) geometry.width,(unsigned long) geometry.height,
1202 (long) geometry.x,(long) geometry.y);
1203 (void) SetImageOption(_image_info,option+1,page);
1204 (void) CloneString(&_image_info->page,page);
1207 if (LocaleCompare("ping",option+1) == 0)
1209 _image_info->ping = ArgBoolean;
1212 if (LocaleCompare("pointsize",option+1) == 0)
1215 if (IfMagickFalse(IsGeometry(arg1)))
1216 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1217 _image_info->pointsize =
1218 _draw_info->pointsize =
1219 StringToDouble(arg1,(char **) NULL);
1222 _image_info->pointsize=0.0; /* unset pointsize */
1223 _draw_info->pointsize=12.0;
1227 if (LocaleCompare("precision",option+1) == 0)
1229 arg1=ArgOption("-1");
1230 if (IfMagickFalse(IsGeometry(arg1)))
1231 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1232 (void) SetMagickPrecision(StringToInteger(arg1));
1235 /* FUTURE: Only the 'preview' coder appears to use this
1236 * DEPRECIATE the coder? Leaving only the 'preview' operator.
1237 if (LocaleCompare("preview",option+1) == 0)
1239 _image_info->preview_type=UndefinedPreview;
1241 _image_info->preview_type=(PreviewType) ParseCommandOption(
1242 MagickPreviewOptions,MagickFalse,arg1);
1246 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1250 if (LocaleCompare("quality",option+1) == 0)
1252 if (IfMagickFalse(IsGeometry(arg1)))
1253 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1254 _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1)
1255 : UNDEFINED_COMPRESSION_QUALITY;
1256 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1259 if (LocaleCompare("quantize",option+1) == 0)
1261 /* Just a set direct in _quantize_info */
1262 arg1=ArgOption("undefined");
1263 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
1265 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
1267 _quantize_info->colorspace=(ColorspaceType)parse;
1270 if (LocaleCompare("quiet",option+1) == 0)
1272 /* FUTURE: if two -quiet is performed you can not do +quiet!
1273 This needs to be checked over thoughly.
1275 static WarningHandler
1276 warning_handler = (WarningHandler) NULL;
1279 tmp = SetWarningHandler((WarningHandler) NULL);
1281 if ( tmp != (WarningHandler) NULL)
1282 warning_handler = tmp; /* remember the old handler */
1283 if (!IfSetOption) /* set the old handler */
1284 warning_handler=SetWarningHandler(warning_handler);
1287 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1291 if (LocaleCompare("red-primary",option+1) == 0)
1293 /* Image chromaticity X,Y NB: Y=X if Y not defined
1295 SyncImageSettings() used to set per-image attribute.
1297 arg1=ArgOption("0.0");
1298 if (IfMagickFalse(IsGeometry(arg1)))
1299 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1300 (void) SetImageOption(_image_info,option+1,arg1);
1303 if (LocaleCompare("regard-warnings",option+1) == 0)
1304 /* FUTURE: to be replaced by a 'fatal-level' type setting */
1306 if (LocaleCompare("render",option+1) == 0)
1308 /* _draw_info only setting */
1309 _draw_info->render= ArgBooleanNot;
1312 if (LocaleCompare("respect-parenthesis",option+1) == 0)
1314 /* link image and setting stacks - option is itself saved on stack! */
1315 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1318 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1322 if (LocaleCompare("sampling-factor",option+1) == 0)
1324 /* FUTURE: should be converted to jpeg:sampling_factor */
1325 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1326 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1327 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1330 if (LocaleCompare("scene",option+1) == 0)
1332 /* SyncImageSettings() used to set this as a per-image attribute.
1335 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1336 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1337 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1338 _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1341 if (LocaleCompare("seed",option+1) == 0)
1343 if (IfMagickFalse(IsGeometry(arg1)))
1344 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1346 IfSetOption ? (unsigned long) StringToUnsignedLong(arg1)
1347 : (unsigned long) time((time_t *) NULL) );
1350 if (LocaleCompare("size",option+1) == 0)
1352 /* FUTURE: string in _image_info -- convert to Option ???
1353 Look at the special handling for "size" in SetImageOption()
1355 (void) CloneString(&_image_info->size,ArgOption(NULL));
1358 if (LocaleCompare("stretch",option+1) == 0)
1360 arg1=ArgOption("undefined");
1361 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1363 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1365 _draw_info->stretch=(StretchType) parse;
1368 if (LocaleCompare("stroke",option+1) == 0)
1370 /* set stroke color OR stroke-pattern
1371 UPDATE: ensure stroke color is not destroyed is a pattern
1372 is given. Just in case the color is also used for other purposes.
1383 arg1 = ArgOption("none"); /* +fill turns it off! */
1384 (void) SetImageOption(_image_info,option+1,arg1);
1385 if (_draw_info->stroke_pattern != (Image *) NULL)
1386 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1388 /* is it a color or a image? -- ignore exceptions */
1389 sans=AcquireExceptionInfo();
1390 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1391 sans=DestroyExceptionInfo(sans);
1393 if (IfMagickFalse(status))
1394 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1396 _draw_info->stroke=color;
1399 if (LocaleCompare("strokewidth",option+1) == 0)
1401 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1402 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1403 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1404 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1408 if (LocaleCompare("style",option+1) == 0)
1410 arg1=ArgOption("undefined");
1411 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1413 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1415 _draw_info->style=(StyleType) parse;
1419 if (LocaleCompare("subimage-search",option+1) == 0)
1421 /* FUTURE: this is only used by CompareImages() which is used
1422 only by the "compare" CLI program at this time. */
1423 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1427 if (LocaleCompare("synchronize",option+1) == 0)
1429 /* FUTURE: syncronize to storage - but what does that mean? */
1430 _image_info->synchronize = ArgBoolean;
1433 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1437 if (LocaleCompare("taint",option+1) == 0)
1439 /* SyncImageSettings() used to set per-image attribute. */
1440 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1443 if (LocaleCompare("texture",option+1) == 0)
1445 /* Note: arguments do not have percent escapes expanded */
1446 /* FUTURE: move _image_info string to option splay-tree
1447 Other than "montage" what uses "texture" ????
1449 (void) CloneString(&_image_info->texture,ArgOption(NULL));
1452 if (LocaleCompare("tile",option+1) == 0)
1454 /* Note: arguments do not have percent escapes expanded */
1455 _draw_info->fill_pattern=IfSetOption
1456 ?GetImageCache(_image_info,arg1,_exception)
1457 :DestroyImage(_draw_info->fill_pattern);
1460 if (LocaleCompare("tile-offset",option+1) == 0)
1462 /* SyncImageSettings() used to set per-image attribute. ??? */
1463 arg1=ArgOption("0");
1464 if (IfMagickFalse(IsGeometry(arg1)))
1465 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1466 (void) SetImageOption(_image_info,option+1,arg1);
1469 if (LocaleCompare("transparent-color",option+1) == 0)
1471 /* FUTURE: both _image_info attribute & ImageOption in use!
1472 _image_info only used for generating new images.
1473 SyncImageSettings() used to set per-image attribute.
1475 Note that +transparent-color, means fall-back to image
1476 attribute so ImageOption is deleted, not set to a default.
1478 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1479 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1480 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1481 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1482 &_image_info->transparent_color,_exception);
1485 if (LocaleCompare("treedepth",option+1) == 0)
1487 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1488 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1491 if (LocaleCompare("type",option+1) == 0)
1493 /* SyncImageSettings() used to set per-image attribute. */
1494 parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1495 ArgOption("undefined"));
1497 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1499 _image_info->type=(ImageType) parse;
1500 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1503 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1507 if (LocaleCompare("undercolor",option+1) == 0)
1509 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1510 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1511 &_draw_info->undercolor,_exception);
1514 if (LocaleCompare("units",option+1) == 0)
1516 /* SyncImageSettings() used to set per-image attribute.
1517 Should this effect _draw_info X and Y resolution?
1518 FUTURE: this probably should be part of the density setting
1520 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1521 ArgOption("undefined"));
1523 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1525 _image_info->units=(ResolutionType) parse;
1526 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1529 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1533 if (LocaleCompare("verbose",option+1) == 0)
1535 /* FUTURE: Remember all options become image artifacts
1536 _image_info->verbose is only used by coders.
1538 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1539 _image_info->verbose= ArgBoolean;
1540 _image_info->ping=MagickFalse; /* verbose can't be a ping */
1543 if (LocaleCompare("view",option+1) == 0)
1545 /* FUTURE: Convert from _image_info to ImageOption
1546 Only used by coder FPX
1547 And it only tests existance, not its content!
1549 (void) CloneString(&_image_info->view,ArgOption(NULL));
1552 if (LocaleCompare("virtual-pixel",option+1) == 0)
1554 /* SyncImageSettings() used to set per-image attribute.
1555 This is VERY deep in the image caching structure.
1557 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1558 ArgOption("undefined"));
1560 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1562 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1565 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1569 if (LocaleCompare("weight",option+1) == 0)
1571 /* Just what does using a font 'weight' do ???
1572 There is no "-list weight" output (reference manual says there is)
1574 arg1=ArgOption("all");
1575 _draw_info->weight=StringToUnsignedLong(arg1);
1576 if (LocaleCompare(arg1,"all") == 0)
1577 _draw_info->weight=0;
1578 if (LocaleCompare(arg1,"bold") == 0)
1579 _draw_info->weight=700;
1580 if (LocaleCompare(arg1,"bolder") == 0)
1581 if (_draw_info->weight <= 800)
1582 _draw_info->weight+=100;
1583 if (LocaleCompare(arg1,"lighter") == 0)
1584 if (_draw_info->weight >= 100)
1585 _draw_info->weight-=100;
1586 if (LocaleCompare(arg1,"normal") == 0)
1587 _draw_info->weight=400;
1590 if (LocaleCompare("white-point",option+1) == 0)
1592 /* Used as a image chromaticity setting
1593 SyncImageSettings() used to set per-image attribute.
1595 arg1=ArgOption("0.0");
1596 if (IfMagickFalse(IsGeometry(arg1)))
1597 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1598 (void) SetImageOption(_image_info,option+1,arg1);
1601 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1604 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1607 /* clean up percent escape interpreted strings */
1609 arg1=DestroyString((char *)arg1);
1611 arg2=DestroyString((char *)arg2);
1616 #undef _quantize_info
1619 #undef ArgBooleanNot
1620 #undef ArgBooleanString
1627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 + C L I S i m p l e O p e r a t o r I m a g e s %
1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637 % CLISimpleOperatorImages() applys one simple image operation given to all
1638 % the images in the CLI wand, using any per-image or global settings that was
1639 % previously saved in the CLI wand.
1641 % It is assumed that any such settings are up-to-date.
1643 % The format of the WandSimpleOperatorImages method is:
1645 % void CLISimpleOperatorImages(MagickCLI *cli_wand,
1646 % const char *option, const char *arg1, const char *arg2)
1648 % A description of each parameter follows:
1650 % o cli_wand: structure holding settings and images to be operated on
1652 % o option: The option string for the operation
1654 % o arg1, arg2: optional argument strings to the operation
1659 CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1660 image operation to the current image pointed to by the CLI wand.
1662 The image in the list may be modified in three different ways...
1663 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1664 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1665 * one image replace by a list of images (-separate and -crop only!)
1667 In each case the result replaces the single original image in the list, as
1668 well as the pointer to the modified image (last image added if replaced by a
1669 list of images) is returned.
1671 As the image pointed to may be replaced, the first image in the list may
1672 also change. GetFirstImageInList() should be used by caller if they wish
1673 return the Image pointer to the first image in list.
1675 static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand,
1676 const char *option, const char *arg1n, const char *arg2n)
1693 const char /* percent escaped versions of the args */
1697 #define _image_info (cli_wand->wand.image_info)
1698 #define _image (cli_wand->wand.images)
1699 #define _exception (cli_wand->wand.exception)
1700 #define _draw_info (cli_wand->draw_info)
1701 #define _quantize_info (cli_wand->quantize_info)
1702 #define _process_flags (cli_wand->process_flags)
1703 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
1704 #define IfNormalOp (*option=='-')
1705 #define IfPlusOp (*option!='-')
1706 #define IsNormalOp IsMagickTrue(IfNormalOp)
1707 #define IsPlusOp IsMagickFalse(IfNormalOp)
1709 assert(cli_wand != (MagickCLI *) NULL);
1710 assert(cli_wand->signature == WandSignature);
1711 assert(cli_wand->wand.signature == WandSignature);
1712 assert(_image != (Image *) NULL); /* an image must be present */
1713 if (IfMagickTrue(cli_wand->wand.debug))
1714 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1719 /* Interpret Percent Escapes in Arguments - using first image */
1720 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
1721 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1722 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1723 /* Interpret Percent escapes in argument 1 */
1724 if (arg1n != (char *) NULL) {
1725 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1726 if (arg1 == (char *) NULL) {
1727 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1728 arg1=arg1n; /* use the given argument as is */
1731 if (arg2n != (char *) NULL) {
1732 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1733 if (arg2 == (char *) NULL) {
1734 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1735 arg2=arg2n; /* use the given argument as is */
1739 #undef _process_flags
1743 (void) FormatLocaleFile(stderr,
1744 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1747 new_image = (Image *)NULL; /* the replacement image, if not null at end */
1748 SetGeometryInfo(&geometry_info);
1750 switch (*(option+1))
1754 if (LocaleCompare("adaptive-blur",option+1) == 0)
1756 flags=ParseGeometry(arg1,&geometry_info);
1757 if ((flags & (RhoValue|SigmaValue)) == 0)
1758 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1759 if ((flags & SigmaValue) == 0)
1760 geometry_info.sigma=1.0;
1761 new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1762 geometry_info.sigma,_exception);
1765 if (LocaleCompare("adaptive-resize",option+1) == 0)
1767 /* FUTURE: Roll into a resize special operator */
1768 if (IfMagickFalse(IsGeometry(arg1)))
1769 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1770 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1771 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1775 if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1777 flags=ParseGeometry(arg1,&geometry_info);
1778 if ((flags & (RhoValue|SigmaValue)) == 0)
1779 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1780 if ((flags & SigmaValue) == 0)
1781 geometry_info.sigma=1.0;
1782 new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1783 geometry_info.sigma,_exception);
1786 if (LocaleCompare("alpha",option+1) == 0)
1788 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1790 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1792 (void) SetImageAlphaChannel(_image,(AlphaChannelOption)parse,
1796 if (LocaleCompare("annotate",option+1) == 0)
1799 geometry[MaxTextExtent];
1801 SetGeometryInfo(&geometry_info);
1802 flags=ParseGeometry(arg1,&geometry_info);
1804 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1805 if ((flags & SigmaValue) == 0)
1806 geometry_info.sigma=geometry_info.rho;
1807 (void) CloneString(&_draw_info->text,arg2);
1808 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1809 geometry_info.xi,geometry_info.psi);
1810 (void) CloneString(&_draw_info->geometry,geometry);
1811 _draw_info->affine.sx=cos(DegreesToRadians(
1812 fmod(geometry_info.rho,360.0)));
1813 _draw_info->affine.rx=sin(DegreesToRadians(
1814 fmod(geometry_info.rho,360.0)));
1815 _draw_info->affine.ry=(-sin(DegreesToRadians(
1816 fmod(geometry_info.sigma,360.0))));
1817 _draw_info->affine.sy=cos(DegreesToRadians(
1818 fmod(geometry_info.sigma,360.0)));
1819 (void) AnnotateImage(_image,_draw_info,_exception);
1820 GetAffineMatrix(&_draw_info->affine);
1823 if (LocaleCompare("auto-gamma",option+1) == 0)
1825 (void) AutoGammaImage(_image,_exception);
1828 if (LocaleCompare("auto-level",option+1) == 0)
1830 (void) AutoLevelImage(_image,_exception);
1833 if (LocaleCompare("auto-orient",option+1) == 0)
1835 new_image=AutoOrientImage(_image,_image->orientation,_exception);
1838 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1842 if (LocaleCompare("black-threshold",option+1) == 0)
1844 if (IfMagickFalse(IsGeometry(arg1)))
1845 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1846 (void) BlackThresholdImage(_image,arg1,_exception);
1849 if (LocaleCompare("blue-shift",option+1) == 0)
1851 geometry_info.rho=1.5;
1853 flags=ParseGeometry(arg1,&geometry_info);
1854 if ((flags & RhoValue) == 0)
1855 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1857 new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1860 if (LocaleCompare("blur",option+1) == 0)
1862 flags=ParseGeometry(arg1,&geometry_info);
1863 if ((flags & (RhoValue|SigmaValue)) == 0)
1864 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1865 if ((flags & SigmaValue) == 0)
1866 geometry_info.sigma=1.0;
1867 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1871 if (LocaleCompare("border",option+1) == 0)
1879 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1880 if ((flags & (WidthValue | HeightValue)) == 0)
1881 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1882 compose=OverCompositeOp;
1883 value=GetImageOption(_image_info,"compose");
1884 if (value != (const char *) NULL)
1885 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1887 new_image=BorderImage(_image,&geometry,compose,_exception);
1890 if (LocaleCompare("brightness-contrast",option+1) == 0)
1902 flags=ParseGeometry(arg1,&geometry_info);
1903 if ((flags & RhoValue) == 0)
1904 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1905 brightness=geometry_info.rho;
1907 if ((flags & SigmaValue) != 0)
1908 contrast=geometry_info.sigma;
1909 (void) BrightnessContrastImage(_image,brightness,contrast,
1913 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1917 if (LocaleCompare("canny",option+1) == 0)
1919 flags=ParseGeometry(arg1,&geometry_info);
1920 if ((flags & (RhoValue|SigmaValue)) == 0)
1921 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1922 if ((flags & SigmaValue) == 0)
1923 geometry_info.sigma=1.0;
1924 if ((flags & XiValue) == 0)
1925 geometry_info.xi=10;
1926 if ((flags & PsiValue) == 0)
1927 geometry_info.psi=30;
1928 if ((flags & PercentValue) != 0)
1930 geometry_info.xi/=100.0;
1931 geometry_info.psi/=100.0;
1933 new_image=CannyEdgeImage(_image,geometry_info.rho,geometry_info.sigma,
1934 geometry_info.xi,geometry_info.psi,_exception);
1937 if (LocaleCompare("cdl",option+1) == 0)
1939 /* Note: arguments do not have percent escapes expanded */
1941 *color_correction_collection;
1944 Color correct with a color decision list.
1946 color_correction_collection=FileToString(arg1,~0UL,_exception);
1947 if (color_correction_collection == (char *) NULL)
1949 (void) ColorDecisionListImage(_image,color_correction_collection,
1953 if (LocaleCompare("charcoal",option+1) == 0)
1955 flags=ParseGeometry(arg1,&geometry_info);
1956 if ((flags & (RhoValue|SigmaValue)) == 0)
1957 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1958 if ((flags & SigmaValue) == 0)
1959 geometry_info.sigma=1.0;
1960 if ((flags & XiValue) == 0)
1961 geometry_info.xi=1.0;
1962 new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1966 if (LocaleCompare("chop",option+1) == 0)
1968 if (IfMagickFalse(IsGeometry(arg1)))
1969 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1970 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
1971 new_image=ChopImage(_image,&geometry,_exception);
1974 if (LocaleCompare("clamp",option+1) == 0)
1976 (void) ClampImage(_image,_exception);
1979 if (LocaleCompare("clip",option+1) == 0)
1982 (void) ClipImage(_image,_exception);
1983 else /* "+mask" remove the write mask */
1984 (void) SetImageMask(_image,(Image *) NULL,_exception);
1987 if (LocaleCompare("clip-mask",option+1) == 0)
1989 /* Note: arguments do not have percent escapes expanded */
2006 /* use "+clip-mask" Remove the write mask for -clip-path */
2007 (void) SetImageMask(_image,(Image *) NULL,_exception);
2010 mask_image=GetImageCache(_image_info,arg1,_exception);
2011 if (mask_image == (Image *) NULL)
2013 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
2015 /* Create a write mask from cli_wand mask image */
2016 /* FUTURE: use Alpha operations instead and create a Grey Image */
2017 mask_view=AcquireAuthenticCacheView(mask_image,_exception);
2018 for (y=0; y < (ssize_t) mask_image->rows; y++)
2020 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
2022 if (q == (Quantum *) NULL)
2024 for (x=0; x < (ssize_t) mask_image->columns; x++)
2026 if (mask_image->alpha_trait != BlendPixelTrait)
2027 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
2028 SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q);
2029 q+=GetPixelChannels(mask_image);
2031 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2034 /* clean up and set the write mask */
2035 mask_view=DestroyCacheView(mask_view);
2036 mask_image->alpha_trait=BlendPixelTrait;
2037 (void) SetImageColorspace(_image,GRAYColorspace,_exception);
2038 (void) SetImageMask(_image,mask_image,_exception);
2039 mask_image=DestroyImage(mask_image);
2042 if (LocaleCompare("clip-path",option+1) == 0)
2044 (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2045 /* Note: Use "+clip-mask" remove the write mask added */
2048 if (LocaleCompare("colorize",option+1) == 0)
2050 if (IfMagickFalse(IsGeometry(arg1)))
2051 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2052 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2055 if (LocaleCompare("color-matrix",option+1) == 0)
2060 kernel=AcquireKernelInfo(arg1);
2061 if (kernel == (KernelInfo *) NULL)
2062 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2063 new_image=ColorMatrixImage(_image,kernel,_exception);
2064 kernel=DestroyKernelInfo(kernel);
2067 if (LocaleCompare("colors",option+1) == 0)
2069 /* Reduce the number of colors in the image.
2070 FUTURE: also provide 'plus version with image 'color counts'
2072 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2073 if (_quantize_info->number_colors == 0)
2074 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2075 if ((_image->storage_class == DirectClass) ||
2076 _image->colors > _quantize_info->number_colors)
2077 (void) QuantizeImage(_quantize_info,_image,_exception);
2079 (void) CompressImageColormap(_image,_exception);
2082 if (LocaleCompare("colorspace",option+1) == 0)
2084 /* WARNING: this is both a image_info setting (already done)
2085 and a operator to change image colorspace.
2087 FUTURE: default colorspace should be sRGB!
2088 Unless some type of 'linear colorspace' mode is set.
2090 Note that +colorspace sets "undefined" or no effect on
2091 new images, but forces images already in memory back to RGB!
2092 That seems to be a little strange!
2094 (void) TransformImageColorspace(_image,
2095 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2099 if (LocaleCompare("contrast",option+1) == 0)
2101 CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2102 (void) ContrastImage(_image,IsNormalOp,_exception);
2105 if (LocaleCompare("contrast-stretch",option+1) == 0)
2114 flags=ParseGeometry(arg1,&geometry_info);
2115 if ((flags & RhoValue) == 0)
2116 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2117 black_point=geometry_info.rho;
2118 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2120 if ((flags & PercentValue) != 0) {
2121 black_point*=(double) _image->columns*_image->rows/100.0;
2122 white_point*=(double) _image->columns*_image->rows/100.0;
2124 white_point=(double) _image->columns*_image->rows-
2126 (void) ContrastStretchImage(_image,black_point,white_point,
2130 if (LocaleCompare("convolve",option+1) == 0)
2135 kernel_info=AcquireKernelInfo(arg1);
2136 if (kernel_info == (KernelInfo *) NULL)
2137 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2138 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2140 kernel_info=DestroyKernelInfo(kernel_info);
2143 if (LocaleCompare("crop",option+1) == 0)
2145 /* WARNING: This can generate multiple images! */
2146 if (IfMagickFalse(IsGeometry(arg1)))
2147 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2148 new_image=CropImageToTiles(_image,arg1,_exception);
2151 if (LocaleCompare("cycle",option+1) == 0)
2153 if (IfMagickFalse(IsGeometry(arg1)))
2154 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2155 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2159 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2163 if (LocaleCompare("decipher",option+1) == 0)
2165 /* Note: arguments do not have percent escapes expanded */
2169 passkey=FileToStringInfo(arg1,~0UL,_exception);
2170 if (passkey == (StringInfo *) NULL)
2171 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2173 (void) PasskeyDecipherImage(_image,passkey,_exception);
2174 passkey=DestroyStringInfo(passkey);
2177 if (LocaleCompare("depth",option+1) == 0)
2179 /* The _image_info->depth setting has already been set
2180 We just need to apply it to all images in current sequence
2182 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2183 That is it really is an operation, not a setting! Arrgghhh
2185 FUTURE: this should not be an operator!!!
2187 (void) SetImageDepth(_image,_image_info->depth,_exception);
2190 if (LocaleCompare("deskew",option+1) == 0)
2196 if (IfMagickFalse(IsGeometry(arg1)))
2197 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2198 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2201 threshold=40.0*QuantumRange/100.0;
2202 new_image=DeskewImage(_image,threshold,_exception);
2205 if (LocaleCompare("despeckle",option+1) == 0)
2207 new_image=DespeckleImage(_image,_exception);
2210 if (LocaleCompare("distort",option+1) == 0)
2218 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2220 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2222 if ((DistortImageMethod) parse == ResizeDistortion)
2226 /* Special Case - Argument is actually a resize geometry!
2227 ** Convert that to an appropriate distortion argument array.
2228 ** FUTURE: make a separate special resize operator
2229 Roll into a resize special operator */
2230 if (IfMagickFalse(IsGeometry(arg2)))
2231 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2233 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2234 resize_args[0]=(double) geometry.width;
2235 resize_args[1]=(double) geometry.height;
2236 new_image=DistortImage(_image,(DistortImageMethod) parse,
2237 (size_t)2,resize_args,MagickTrue,_exception);
2240 /* convert argument string into an array of doubles */
2241 args = StringToArrayOfDoubles(arg2,&count,_exception);
2242 if (args == (double *)NULL )
2243 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2245 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2246 IsPlusOp,_exception);
2247 args=(double *) RelinquishMagickMemory(args);
2250 if (LocaleCompare("draw",option+1) == 0)
2252 (void) CloneString(&_draw_info->primitive,arg1);
2253 (void) DrawImage(_image,_draw_info,_exception);
2254 (void) CloneString(&_draw_info->primitive,(char *)NULL);
2257 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2261 if (LocaleCompare("edge",option+1) == 0)
2263 flags=ParseGeometry(arg1,&geometry_info);
2264 if ((flags & (RhoValue|SigmaValue)) == 0)
2265 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2266 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2269 if (LocaleCompare("emboss",option+1) == 0)
2271 flags=ParseGeometry(arg1,&geometry_info);
2272 if ((flags & (RhoValue|SigmaValue)) == 0)
2273 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2274 if ((flags & SigmaValue) == 0)
2275 geometry_info.sigma=1.0;
2276 new_image=EmbossImage(_image,geometry_info.rho,
2277 geometry_info.sigma,_exception);
2280 if (LocaleCompare("encipher",option+1) == 0)
2282 /* Note: arguments do not have percent escapes expanded */
2286 passkey=FileToStringInfo(arg1,~0UL,_exception);
2287 if (passkey != (StringInfo *) NULL)
2289 (void) PasskeyEncipherImage(_image,passkey,_exception);
2290 passkey=DestroyStringInfo(passkey);
2294 if (LocaleCompare("enhance",option+1) == 0)
2296 new_image=EnhanceImage(_image,_exception);
2299 if (LocaleCompare("equalize",option+1) == 0)
2301 (void) EqualizeImage(_image,_exception);
2304 if (LocaleCompare("evaluate",option+1) == 0)
2309 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2311 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2313 if (IfMagickFalse(IsGeometry(arg2)))
2314 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2315 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2316 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2320 if (LocaleCompare("extent",option+1) == 0)
2322 if (IfMagickFalse(IsGeometry(arg1)))
2323 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2324 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2325 if (geometry.width == 0)
2326 geometry.width=_image->columns;
2327 if (geometry.height == 0)
2328 geometry.height=_image->rows;
2329 new_image=ExtentImage(_image,&geometry,_exception);
2332 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2336 if (LocaleCompare("flip",option+1) == 0)
2338 new_image=FlipImage(_image,_exception);
2341 if (LocaleCompare("flop",option+1) == 0)
2343 new_image=FlopImage(_image,_exception);
2346 if (LocaleCompare("floodfill",option+1) == 0)
2351 if (IfMagickFalse(IsGeometry(arg1)))
2352 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2353 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2354 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2355 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2356 geometry.y,IsPlusOp,_exception);
2359 if (LocaleCompare("frame",option+1) == 0)
2370 value=GetImageOption(_image_info,"compose");
2371 compose=OverCompositeOp; /* use Over not _image->compose */
2372 if (value != (const char *) NULL)
2373 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2375 if (IfMagickFalse(IsGeometry(arg1)))
2376 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2377 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2378 frame_info.width=geometry.width;
2379 frame_info.height=geometry.height;
2380 frame_info.outer_bevel=geometry.x;
2381 frame_info.inner_bevel=geometry.y;
2382 frame_info.x=(ssize_t) frame_info.width;
2383 frame_info.y=(ssize_t) frame_info.height;
2384 frame_info.width=_image->columns+2*frame_info.width;
2385 frame_info.height=_image->rows+2*frame_info.height;
2386 new_image=FrameImage(_image,&frame_info,compose,_exception);
2389 if (LocaleCompare("function",option+1) == 0)
2397 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2399 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2401 /* convert argument string into an array of doubles */
2402 args = StringToArrayOfDoubles(arg2,&count,_exception);
2403 if (args == (double *)NULL )
2404 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2406 (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2408 args=(double *) RelinquishMagickMemory(args);
2411 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2415 if (LocaleCompare("gamma",option+1) == 0)
2420 if (IfMagickFalse(IsGeometry(arg1)))
2421 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2422 constant=StringToDouble(arg1,(char **) NULL);
2424 /* Using Gamma, via a cache */
2426 constant=PerceptibleReciprocal(constant);
2427 (void) GammaImage(_image,constant,_exception);
2429 /* Using Evaluate POW, direct update of values - more accurite */
2431 constant=PerceptibleReciprocal(constant);
2432 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2434 /* Set gamma setting -- Old meaning of "+gamma"
2435 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2439 if (LocaleCompare("gaussian-blur",option+1) == 0)
2441 flags=ParseGeometry(arg1,&geometry_info);
2442 if ((flags & (RhoValue|SigmaValue)) == 0)
2443 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2444 if ((flags & SigmaValue) == 0)
2445 geometry_info.sigma=1.0;
2446 new_image=GaussianBlurImage(_image,geometry_info.rho,
2447 geometry_info.sigma,_exception);
2450 if (LocaleCompare("gaussian",option+1) == 0)
2452 CLIWandWarnReplaced("-gaussian-blur");
2453 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL);
2455 if (LocaleCompare("geometry",option+1) == 0)
2458 Record Image offset for composition. (A Setting)
2459 Resize last _image. (ListOperator) -- DEPRECIATE
2460 FUTURE: Why if no 'offset' does this resize ALL images?
2461 Also why is the setting recorded in the IMAGE non-sense!
2464 { /* remove the previous composition geometry offset! */
2465 if (_image->geometry != (char *) NULL)
2466 _image->geometry=DestroyString(_image->geometry);
2469 if (IfMagickFalse(IsGeometry(arg1)))
2470 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2471 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2472 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2473 (void) CloneString(&_image->geometry,arg1);
2475 new_image=ResizeImage(_image,geometry.width,geometry.height,
2476 _image->filter,_exception);
2479 if (LocaleCompare("grayscale",option+1) == 0)
2481 parse=ParseCommandOption(MagickPixelIntensityOptions,
2484 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2486 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2489 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2493 if (LocaleCompare("hough-lines",option+1) == 0)
2495 flags=ParseGeometry(arg1,&geometry_info);
2496 if ((flags & (RhoValue|SigmaValue)) == 0)
2497 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2498 if ((flags & SigmaValue) == 0)
2499 geometry_info.sigma=geometry_info.rho;
2500 if ((flags & XiValue) == 0)
2501 geometry_info.xi=40;
2502 new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2503 (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2506 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2510 if (LocaleCompare("identify",option+1) == 0)
2516 format=GetImageOption(_image_info,"format");
2517 if (format == (char *) NULL)
2519 (void) IdentifyImage(_image,stdout,_image_info->verbose,
2523 text=InterpretImageProperties(_image_info,_image,format,_exception);
2524 if (text == (char *) NULL)
2525 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2527 (void) fputs(text,stdout);
2528 text=DestroyString((char *)text);
2531 if (LocaleCompare("implode",option+1) == 0)
2533 flags=ParseGeometry(arg1,&geometry_info);
2534 if ((flags & RhoValue) == 0)
2535 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2536 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2540 if (LocaleCompare("interpolative-resize",option+1) == 0)
2542 /* FUTURE: New to IMv7
2543 Roll into a resize special operator */
2544 if (IfMagickFalse(IsGeometry(arg1)))
2545 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2546 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2547 new_image=InterpolativeResizeImage(_image,geometry.width,
2548 geometry.height,_image->interpolate,_exception);
2551 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2555 if (LocaleCompare("lat",option+1) == 0)
2557 flags=ParseGeometry(arg1,&geometry_info);
2558 if ((flags & (RhoValue|SigmaValue)) == 0)
2559 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2560 if ((flags & SigmaValue) == 0)
2561 geometry_info.sigma=1.0;
2562 if ((flags & PercentValue) != 0)
2563 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2564 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2565 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2569 if (LocaleCompare("level",option+1) == 0)
2579 flags=ParseGeometry(arg1,&geometry_info);
2580 if ((flags & RhoValue) == 0)
2581 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2582 black_point=geometry_info.rho;
2583 white_point=(double) QuantumRange;
2584 if ((flags & SigmaValue) != 0)
2585 white_point=geometry_info.sigma;
2587 if ((flags & XiValue) != 0)
2588 gamma=geometry_info.xi;
2589 if ((flags & PercentValue) != 0)
2591 black_point*=(double) (QuantumRange/100.0);
2592 white_point*=(double) (QuantumRange/100.0);
2594 if ((flags & SigmaValue) == 0)
2595 white_point=(double) QuantumRange-black_point;
2596 if (IfPlusOp || ((flags & AspectValue) != 0))
2597 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2599 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2602 if (LocaleCompare("level-colors",option+1) == 0)
2605 token[MaxTextExtent];
2614 p=(const char *) arg1;
2615 GetMagickToken(p,&p,token); /* get black point color */
2616 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2617 (void) QueryColorCompliance(token,AllCompliance,
2618 &black_point,_exception);
2620 (void) QueryColorCompliance("#000000",AllCompliance,
2621 &black_point,_exception);
2622 if (isalpha((int) token[0]) || (token[0] == '#'))
2623 GetMagickToken(p,&p,token);
2625 white_point=black_point; /* set everything to that color */
2628 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2629 GetMagickToken(p,&p,token); /* Get white point color. */
2630 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2631 (void) QueryColorCompliance(token,AllCompliance,
2632 &white_point,_exception);
2634 (void) QueryColorCompliance("#ffffff",AllCompliance,
2635 &white_point,_exception);
2637 (void) LevelImageColors(_image,&black_point,&white_point,
2638 IsPlusOp,_exception);
2641 if (LocaleCompare("linear-stretch",option+1) == 0)
2650 flags=ParseGeometry(arg1,&geometry_info);
2651 if ((flags & RhoValue) == 0)
2652 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2653 black_point=geometry_info.rho;
2654 white_point=(double) _image->columns*_image->rows;
2655 if ((flags & SigmaValue) != 0)
2656 white_point=geometry_info.sigma;
2657 if ((flags & PercentValue) != 0)
2659 black_point*=(double) _image->columns*_image->rows/100.0;
2660 white_point*=(double) _image->columns*_image->rows/100.0;
2662 if ((flags & SigmaValue) == 0)
2663 white_point=(double) _image->columns*_image->rows-
2665 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2668 if (LocaleCompare("liquid-rescale",option+1) == 0)
2670 /* FUTURE: Roll into a resize special operator */
2671 if (IfMagickFalse(IsGeometry(arg1)))
2672 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2673 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2674 if ((flags & XValue) == 0)
2676 if ((flags & YValue) == 0)
2678 new_image=LiquidRescaleImage(_image,geometry.width,
2679 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2682 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2686 if (LocaleCompare("magnify",option+1) == 0)
2688 new_image=MagnifyImage(_image,_exception);
2691 if (LocaleCompare("map",option+1) == 0)
2693 CLIWandWarnReplaced("-remap");
2694 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL);
2697 if (LocaleCompare("mask",option+1) == 0)
2699 /* Note: arguments do not have percent escapes expanded */
2704 { /* Remove a mask. */
2705 (void) SetImageMask(_image,(Image *) NULL,_exception);
2708 /* Set the image mask. */
2709 mask=GetImageCache(_image_info,arg1,_exception);
2710 if (mask == (Image *) NULL)
2712 (void) SetImageMask(_image,mask,_exception);
2713 mask=DestroyImage(mask);
2716 if (LocaleCompare("matte",option+1) == 0)
2718 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2719 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2720 DeactivateAlphaChannel, _exception);
2723 if (LocaleCompare("mean-shift",option+1) == 0)
2725 flags=ParseGeometry(arg1,&geometry_info);
2726 if ((flags & (RhoValue|SigmaValue)) == 0)
2727 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2728 if ((flags & SigmaValue) == 0)
2729 geometry_info.sigma=1.0;
2730 if ((flags & XiValue) == 0)
2731 geometry_info.xi=0.10*QuantumRange;
2732 if ((flags & PercentValue) != 0)
2733 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2734 new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2735 (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2738 if (LocaleCompare("median",option+1) == 0)
2740 CLIWandWarnReplaced("-statistic Median");
2741 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1);
2744 if (LocaleCompare("mode",option+1) == 0)
2746 /* FUTURE: note this is also a special "montage" option */
2747 CLIWandWarnReplaced("-statistic Mode");
2748 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1);
2751 if (LocaleCompare("modulate",option+1) == 0)
2753 if (IfMagickFalse(IsGeometry(arg1)))
2754 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2755 (void) ModulateImage(_image,arg1,_exception);
2758 if (LocaleCompare("monitor",option+1) == 0)
2760 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2761 (MagickProgressMonitor) NULL,(void *) NULL);
2764 if (LocaleCompare("monochrome",option+1) == 0)
2766 (void) SetImageType(_image,BilevelType,_exception);
2769 if (LocaleCompare("morphology",option+1) == 0)
2772 token[MaxTextExtent];
2784 GetMagickToken(p,&p,token);
2785 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2787 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2790 GetMagickToken(p,&p,token);
2791 if ((*p == ':') || (*p == ','))
2792 GetMagickToken(p,&p,token);
2794 iterations=(ssize_t) StringToLong(p);
2795 kernel=AcquireKernelInfo(arg2);
2796 if (kernel == (KernelInfo *) NULL)
2797 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",
2799 new_image=MorphologyImage(_image,(MorphologyMethod)parse,
2800 iterations,kernel,_exception);
2801 kernel=DestroyKernelInfo(kernel);
2804 if (LocaleCompare("motion-blur",option+1) == 0)
2806 flags=ParseGeometry(arg1,&geometry_info);
2807 if ((flags & (RhoValue|SigmaValue)) == 0)
2808 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2809 if ((flags & SigmaValue) == 0)
2810 geometry_info.sigma=1.0;
2811 new_image=MotionBlurImage(_image,geometry_info.rho,
2812 geometry_info.sigma,geometry_info.xi,_exception);
2815 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2819 if (LocaleCompare("negate",option+1) == 0)
2821 (void) NegateImage(_image, IsPlusOp, _exception);
2824 if (LocaleCompare("noise",option+1) == 0)
2834 CLIWandWarnReplaced("-statistic NonPeak");
2835 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1);
2838 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2840 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2843 value=GetImageOption(_image_info,"attenuate");
2844 if (value != (const char *) NULL)
2845 attenuate=StringToDouble(value,(char **) NULL);
2846 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2850 if (LocaleCompare("normalize",option+1) == 0)
2852 (void) NormalizeImage(_image,_exception);
2855 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2859 if (LocaleCompare("opaque",option+1) == 0)
2864 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2865 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2869 if (LocaleCompare("ordered-dither",option+1) == 0)
2871 (void) OrderedPosterizeImage(_image,arg1,_exception);
2874 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2878 if (LocaleCompare("paint",option+1) == 0)
2880 flags=ParseGeometry(arg1,&geometry_info);
2881 if ((flags & (RhoValue|SigmaValue)) == 0)
2882 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2883 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2887 if (LocaleCompare("perceptible",option+1) == 0)
2889 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2893 if (LocaleCompare("polaroid",option+1) == 0)
2905 random_info=AcquireRandomInfo();
2906 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2907 random_info=DestroyRandomInfo(random_info);
2910 flags=ParseGeometry(arg1,&geometry_info);
2911 if ((flags & RhoValue) == 0)
2912 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2913 angle=geometry_info.rho;
2915 caption=GetImageProperty(_image,"caption",_exception);
2916 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2917 _image->interpolate,_exception);
2920 if (LocaleCompare("posterize",option+1) == 0)
2922 flags=ParseGeometry(arg1,&geometry_info);
2923 if ((flags & RhoValue) == 0)
2924 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2925 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2926 _quantize_info->dither_method,_exception);
2929 if (LocaleCompare("preview",option+1) == 0)
2931 /* FUTURE: should be a 'Genesis' option?
2932 Option however is also in WandSettingOptionInfo()
2935 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2937 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2939 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2942 if (LocaleCompare("profile",option+1) == 0)
2944 /* Note: arguments do not have percent escapes expanded */
2958 { /* Remove a profile from the _image. */
2959 (void) ProfileImage(_image,arg1,(const unsigned char *)
2963 /* Associate a profile with the _image. */
2964 profile_info=CloneImageInfo(_image_info);
2965 profile=GetImageProfile(_image,"iptc");
2966 if (profile != (StringInfo *) NULL)
2967 profile_info->profile=(void *) CloneStringInfo(profile);
2968 profile_image=GetImageCache(profile_info,arg1,_exception);
2969 profile_info=DestroyImageInfo(profile_info);
2970 if (profile_image == (Image *) NULL)
2975 profile_info=CloneImageInfo(_image_info);
2976 (void) CopyMagickString(profile_info->filename,arg1,
2978 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
2979 if (profile != (StringInfo *) NULL)
2981 (void) ProfileImage(_image,profile_info->magick,
2982 GetStringInfoDatum(profile),(size_t)
2983 GetStringInfoLength(profile),_exception);
2984 profile=DestroyStringInfo(profile);
2986 profile_info=DestroyImageInfo(profile_info);
2989 ResetImageProfileIterator(profile_image);
2990 name=GetNextImageProfile(profile_image);
2991 while (name != (const char *) NULL)
2993 profile=GetImageProfile(profile_image,name);
2994 if (profile != (StringInfo *) NULL)
2995 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
2996 (size_t) GetStringInfoLength(profile),_exception);
2997 name=GetNextImageProfile(profile_image);
2999 profile_image=DestroyImage(profile_image);
3002 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3006 if (LocaleCompare("rotational-blur",option+1) == 0)
3008 flags=ParseGeometry(arg1,&geometry_info);
3009 if ((flags & RhoValue) == 0)
3010 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3011 new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3014 if (LocaleCompare("raise",option+1) == 0)
3016 if (IfMagickFalse(IsGeometry(arg1)))
3017 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3018 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3019 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3022 if (LocaleCompare("random-threshold",option+1) == 0)
3024 if (IfMagickFalse(IsGeometry(arg1)))
3025 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3026 (void) RandomThresholdImage(_image,arg1,_exception);
3029 if (LocaleCompare("recolor",option+1) == 0)
3031 CLIWandWarnReplaced("-color-matrix");
3032 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL);
3034 if (LocaleCompare("remap",option+1) == 0)
3036 /* Note: arguments do not have percent escapes expanded */
3040 remap_image=GetImageCache(_image_info,arg1,_exception);
3041 if (remap_image == (Image *) NULL)
3043 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3044 remap_image=DestroyImage(remap_image);
3047 if (LocaleCompare("repage",option+1) == 0)
3051 if (IfMagickFalse(IsGeometry(arg1)))
3052 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3054 (void) ResetImagePage(_image,arg1);
3057 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3060 if (LocaleCompare("resample",option+1) == 0)
3062 /* FUTURE: Roll into a resize special operation */
3063 flags=ParseGeometry(arg1,&geometry_info);
3064 if ((flags & (RhoValue|SigmaValue)) == 0)
3065 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3066 if ((flags & SigmaValue) == 0)
3067 geometry_info.sigma=geometry_info.rho;
3068 new_image=ResampleImage(_image,geometry_info.rho,
3069 geometry_info.sigma,_image->filter,_exception);
3072 if (LocaleCompare("resize",option+1) == 0)
3074 if (IfMagickFalse(IsGeometry(arg1)))
3075 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3076 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3077 new_image=ResizeImage(_image,geometry.width,geometry.height,
3078 _image->filter,_exception);
3081 if (LocaleCompare("roll",option+1) == 0)
3083 if (IfMagickFalse(IsGeometry(arg1)))
3084 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3085 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3086 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3089 if (LocaleCompare("rotate",option+1) == 0)
3091 flags=ParseGeometry(arg1,&geometry_info);
3092 if ((flags & RhoValue) == 0)
3093 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3094 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3096 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3098 new_image=RotateImage(_image,geometry_info.rho,_exception);
3101 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3105 if (LocaleCompare("sample",option+1) == 0)
3107 /* FUTURE: Roll into a resize special operator */
3108 if (IfMagickFalse(IsGeometry(arg1)))
3109 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3110 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3111 new_image=SampleImage(_image,geometry.width,geometry.height,
3115 if (LocaleCompare("scale",option+1) == 0)
3117 /* FUTURE: Roll into a resize special operator */
3118 if (IfMagickFalse(IsGeometry(arg1)))
3119 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3120 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3121 new_image=ScaleImage(_image,geometry.width,geometry.height,
3125 if (LocaleCompare("segment",option+1) == 0)
3127 flags=ParseGeometry(arg1,&geometry_info);
3128 if ((flags & (RhoValue|SigmaValue)) == 0)
3129 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3130 if ((flags & SigmaValue) == 0)
3131 geometry_info.sigma=1.0;
3132 (void) SegmentImage(_image,_image->colorspace,
3133 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3137 if (LocaleCompare("selective-blur",option+1) == 0)
3139 flags=ParseGeometry(arg1,&geometry_info);
3140 if ((flags & (RhoValue|SigmaValue)) == 0)
3141 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3142 if ((flags & SigmaValue) == 0)
3143 geometry_info.sigma=1.0;
3144 if ((flags & PercentValue) != 0)
3145 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3146 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3147 geometry_info.sigma,geometry_info.xi,_exception);
3150 if (LocaleCompare("separate",option+1) == 0)
3152 /* WARNING: This can generate multiple images! */
3153 /* FUTURE - this may be replaced by a "-channel" method */
3154 new_image=SeparateImages(_image,_exception);
3157 if (LocaleCompare("sepia-tone",option+1) == 0)
3159 if (IfMagickFalse(IsGeometry(arg1)))
3160 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3161 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3162 (double) QuantumRange+1.0),_exception);
3165 if (LocaleCompare("shade",option+1) == 0)
3167 flags=ParseGeometry(arg1,&geometry_info);
3168 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3169 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3170 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3171 geometry_info.sigma,_exception);
3174 if (LocaleCompare("shadow",option+1) == 0)
3176 flags=ParseGeometry(arg1,&geometry_info);
3177 if ((flags & (RhoValue|SigmaValue)) == 0)
3178 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3179 if ((flags & SigmaValue) == 0)
3180 geometry_info.sigma=1.0;
3181 if ((flags & XiValue) == 0)
3182 geometry_info.xi=4.0;
3183 if ((flags & PsiValue) == 0)
3184 geometry_info.psi=4.0;
3185 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3186 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3187 ceil(geometry_info.psi-0.5),_exception);
3190 if (LocaleCompare("sharpen",option+1) == 0)
3192 flags=ParseGeometry(arg1,&geometry_info);
3193 if ((flags & (RhoValue|SigmaValue)) == 0)
3194 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3195 if ((flags & SigmaValue) == 0)
3196 geometry_info.sigma=1.0;
3197 if ((flags & XiValue) == 0)
3198 geometry_info.xi=0.0;
3199 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3203 if (LocaleCompare("shave",option+1) == 0)
3205 if (IfMagickFalse(IsGeometry(arg1)))
3206 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3207 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3208 new_image=ShaveImage(_image,&geometry,_exception);
3211 if (LocaleCompare("shear",option+1) == 0)
3213 flags=ParseGeometry(arg1,&geometry_info);
3214 if ((flags & RhoValue) == 0)
3215 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3216 if ((flags & SigmaValue) == 0)
3217 geometry_info.sigma=geometry_info.rho;
3218 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3222 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3224 flags=ParseGeometry(arg1,&geometry_info);
3225 if ((flags & RhoValue) == 0)
3226 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3227 if ((flags & SigmaValue) == 0)
3228 geometry_info.sigma=(double) QuantumRange/2.0;
3229 if ((flags & PercentValue) != 0)
3230 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3232 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3233 geometry_info.sigma,_exception);
3236 if (LocaleCompare("sketch",option+1) == 0)
3238 flags=ParseGeometry(arg1,&geometry_info);
3239 if ((flags & (RhoValue|SigmaValue)) == 0)
3240 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3241 if ((flags & SigmaValue) == 0)
3242 geometry_info.sigma=1.0;
3243 new_image=SketchImage(_image,geometry_info.rho,
3244 geometry_info.sigma,geometry_info.xi,_exception);
3247 if (LocaleCompare("solarize",option+1) == 0)
3249 if (IfMagickFalse(IsGeometry(arg1)))
3250 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3251 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3252 QuantumRange+1.0),_exception);
3255 if (LocaleCompare("sparse-color",option+1) == 0)
3257 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3259 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3261 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3265 if (LocaleCompare("splice",option+1) == 0)
3267 if (IfMagickFalse(IsGeometry(arg1)))
3268 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3269 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3270 new_image=SpliceImage(_image,&geometry,_exception);
3273 if (LocaleCompare("spread",option+1) == 0)
3275 flags=ParseGeometry(arg1,&geometry_info);
3276 if ((flags & RhoValue) == 0)
3277 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3278 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3282 if (LocaleCompare("statistic",option+1) == 0)
3284 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3286 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3288 flags=ParseGeometry(arg2,&geometry_info);
3289 if ((flags & RhoValue) == 0)
3290 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3291 if ((flags & SigmaValue) == 0)
3292 geometry_info.sigma=geometry_info.rho;
3293 new_image=StatisticImage(_image,(StatisticType)parse,
3294 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3298 if (LocaleCompare("strip",option+1) == 0)
3300 (void) StripImage(_image,_exception);
3303 if (LocaleCompare("swirl",option+1) == 0)
3305 flags=ParseGeometry(arg1,&geometry_info);
3306 if ((flags & RhoValue) == 0)
3307 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3308 new_image=SwirlImage(_image,geometry_info.rho,
3309 _image->interpolate,_exception);
3312 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3316 if (LocaleCompare("threshold",option+1) == 0)
3321 threshold=(double) QuantumRange/2;
3323 if (IfMagickFalse(IsGeometry(arg1)))
3324 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3325 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3327 (void) BilevelImage(_image,threshold,_exception);
3330 if (LocaleCompare("thumbnail",option+1) == 0)
3332 if (IfMagickFalse(IsGeometry(arg1)))
3333 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3334 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3335 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3339 if (LocaleCompare("tint",option+1) == 0)
3341 if (IfMagickFalse(IsGeometry(arg1)))
3342 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3343 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3346 if (LocaleCompare("transform",option+1) == 0)
3348 CLIWandWarnReplaced("+distort AffineProjection");
3349 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3352 if (LocaleCompare("transparent",option+1) == 0)
3357 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3358 (void) TransparentPaintImage(_image,&target,(Quantum)
3359 TransparentAlpha,IsPlusOp,_exception);
3362 if (LocaleCompare("transpose",option+1) == 0)
3364 new_image=TransposeImage(_image,_exception);
3367 if (LocaleCompare("transverse",option+1) == 0)
3369 new_image=TransverseImage(_image,_exception);
3372 if (LocaleCompare("trim",option+1) == 0)
3374 new_image=TrimImage(_image,_exception);
3377 if (LocaleCompare("type",option+1) == 0)
3379 /* Note that "type" setting should have already been defined */
3380 (void) SetImageType(_image,_image_info->type,_exception);
3383 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3387 if (LocaleCompare("unique",option+1) == 0)
3389 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3390 Option is not documented, bt appears to be for "identify".
3391 We may need a identify specific verbose!
3394 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3397 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3398 (void) SetImageArtifact(_image,"verbose","true");
3401 if (LocaleCompare("unique-colors",option+1) == 0)
3403 new_image=UniqueImageColors(_image,_exception);
3406 if (LocaleCompare("unsharp",option+1) == 0)
3408 flags=ParseGeometry(arg1,&geometry_info);
3409 if ((flags & (RhoValue|SigmaValue)) == 0)
3410 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3411 if ((flags & SigmaValue) == 0)
3412 geometry_info.sigma=1.0;
3413 if ((flags & XiValue) == 0)
3414 geometry_info.xi=1.0;
3415 if ((flags & PsiValue) == 0)
3416 geometry_info.psi=0.05;
3417 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3418 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3421 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3425 if (LocaleCompare("verbose",option+1) == 0)
3427 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3428 three places! ImageArtifact ImageOption _image_info->verbose
3429 Some how new images also get this artifact!
3431 (void) SetImageArtifact(_image,option+1,
3432 IfNormalOp ? "true" : "false" );
3435 if (LocaleCompare("vignette",option+1) == 0)
3437 flags=ParseGeometry(arg1,&geometry_info);
3438 if ((flags & (RhoValue|SigmaValue)) == 0)
3439 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3440 if ((flags & SigmaValue) == 0)
3441 geometry_info.sigma=1.0;
3442 if ((flags & XiValue) == 0)
3443 geometry_info.xi=0.1*_image->columns;
3444 if ((flags & PsiValue) == 0)
3445 geometry_info.psi=0.1*_image->rows;
3446 if ((flags & PercentValue) != 0)
3448 geometry_info.xi*=(double) _image->columns/100.0;
3449 geometry_info.psi*=(double) _image->rows/100.0;
3451 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3452 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3453 ceil(geometry_info.psi-0.5),_exception);
3456 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3460 if (LocaleCompare("wave",option+1) == 0)
3462 flags=ParseGeometry(arg1,&geometry_info);
3463 if ((flags & (RhoValue|SigmaValue)) == 0)
3464 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3465 if ((flags & SigmaValue) == 0)
3466 geometry_info.sigma=1.0;
3467 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3468 _image->interpolate,_exception);
3471 if (LocaleCompare("white-threshold",option+1) == 0)
3473 if (IfMagickFalse(IsGeometry(arg1)))
3474 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3475 (void) WhiteThresholdImage(_image,arg1,_exception);
3478 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3481 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3483 /* clean up percent escape interpreted strings */
3485 arg1=DestroyString((char *)arg1);
3487 arg2=DestroyString((char *)arg2);
3489 /* Replace current image with any image that was generated
3490 and set image point to last image (so image->next is correct) */
3491 if (new_image != (Image *) NULL)
3492 ReplaceImageInListReturnLast(&_image,new_image);
3497 #undef _quantize_info
3506 WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3507 const char *option,const char *arg1,const char *arg2)
3509 #if !USE_WAND_METHODS
3515 assert(cli_wand != (MagickCLI *) NULL);
3516 assert(cli_wand->signature == WandSignature);
3517 assert(cli_wand->wand.signature == WandSignature);
3518 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3520 if (IfMagickTrue(cli_wand->wand.debug))
3521 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3522 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3524 #if !USE_WAND_METHODS
3525 /* FUTURE add appropriate tracing */
3527 n=GetImageListLength(cli_wand->wand.images);
3528 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3531 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3532 if ( cli_wand->wand.images->next == (Image *) NULL )
3534 cli_wand->wand.images=cli_wand->wand.images->next;
3537 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3539 MagickResetIterator(&cli_wand->wand);
3540 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3541 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3542 MagickResetIterator(&cli_wand->wand);
3548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3552 + C L I L i s t O p e r a t o r I m a g e s %
3556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558 % CLIListOperatorImages() applies a single operation that is apply to the
3559 % entire image list as a whole. The result is often a complete replacment
3560 % of the image list with a completely new list, or with just a single image
3563 % The format of the MogrifyImage method is:
3565 % MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3566 % const char *option,const char *arg1,const char *arg2)
3568 % A description of each parameter follows:
3570 % o cli_wand: structure holding settings to be applied
3572 % o option: The option string for the operation
3574 % o arg1, arg2: optional argument strings to the operation
3575 % arg2 is currently not used
3578 WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3579 const char *option,const char *arg1n,const char *arg2n)
3581 const char /* percent escaped versions of the args */
3594 #define _image_info (cli_wand->wand.image_info)
3595 #define _images (cli_wand->wand.images)
3596 #define _exception (cli_wand->wand.exception)
3597 #define _draw_info (cli_wand->draw_info)
3598 #define _quantize_info (cli_wand->quantize_info)
3599 #define _process_flags (cli_wand->process_flags)
3600 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3601 #define IfNormalOp (*option=='-')
3602 #define IfPlusOp (*option!='-')
3603 #define IsNormalOp IsMagickTrue(IfNormalOp)
3605 assert(cli_wand != (MagickCLI *) NULL);
3606 assert(cli_wand->signature == WandSignature);
3607 assert(cli_wand->wand.signature == WandSignature);
3608 assert(_images != (Image *) NULL); /* _images must be present */
3610 if (IfMagickTrue(cli_wand->wand.debug))
3611 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3612 "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
3617 /* Interpret Percent Escapes in Arguments - using first image */
3618 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3619 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3620 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3621 /* Interpret Percent escapes in argument 1 */
3622 if (arg1n != (char *) NULL) {
3623 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3624 if (arg1 == (char *) NULL) {
3625 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3626 arg1=arg1n; /* use the given argument as is */
3629 if (arg2n != (char *) NULL) {
3630 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3631 if (arg2 == (char *) NULL) {
3632 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3633 arg2=arg2n; /* use the given argument as is */
3637 #undef _process_flags
3641 new_images=NewImageList();
3643 switch (*(option+1))
3647 if (LocaleCompare("append",option+1) == 0)
3649 new_images=AppendImages(_images,IsNormalOp,_exception);
3652 if (LocaleCompare("average",option+1) == 0)
3654 CLIWandWarnReplaced("-evaluate-sequence Mean");
3655 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3658 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3662 if (LocaleCompare("channel-fx",option+1) == 0)
3664 new_images=ChannelFxImage(_images,arg1,_exception);
3667 if (LocaleCompare("clut",option+1) == 0)
3672 /* FUTURE - make this a compose option, and thus can be used
3673 with layers compose or even compose last image over all other
3676 new_images=RemoveFirstImageFromList(&_images);
3677 clut_image=RemoveLastImageFromList(&_images);
3678 /* FUTURE - produce Exception, rather than silent fail */
3679 if (clut_image == (Image *) NULL)
3681 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3682 clut_image=DestroyImage(clut_image);
3685 if (LocaleCompare("coalesce",option+1) == 0)
3687 new_images=CoalesceImages(_images,_exception);
3690 if (LocaleCompare("combine",option+1) == 0)
3692 parse = (ssize_t) sRGBColorspace; /* default (backward compatible) */
3694 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
3697 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3699 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3702 if (LocaleCompare("compare",option+1) == 0)
3715 Mathematically and visually annotate the difference between an
3716 image and its reconstruction.
3718 image=RemoveFirstImageFromList(&_images);
3719 reconstruct_image=RemoveFirstImageFromList(&_images);
3720 /* FUTURE - produce Exception, rather than silent fail */
3721 if (reconstruct_image == (Image *) NULL)
3723 metric=UndefinedErrorMetric;
3724 option=GetImageOption(_image_info,"metric");
3725 if (option != (const char *) NULL)
3726 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
3727 MagickFalse,option);
3728 new_images=CompareImages(image,reconstruct_image,metric,&distortion,
3731 reconstruct_image=DestroyImage(reconstruct_image);
3732 image=DestroyImage(image);
3735 if (LocaleCompare("complex",option+1) == 0)
3737 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
3739 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3741 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
3744 if (LocaleCompare("composite",option+1) == 0)
3762 /* Compose value from "-compose" option only */
3763 value=GetImageOption(_image_info,"compose");
3764 if (value == (const char *) NULL)
3765 compose=OverCompositeOp; /* use Over not source_image->compose */
3767 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3770 /* Get "clip-to-self" expert setting (false is normal) */
3771 value=GetImageOption(_image_info,"compose:clip-to-self");
3772 if (value == (const char *) NULL)
3773 clip_to_self=MagickTrue;
3775 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3776 "compose:clip-to-self")); /* if this is true */
3777 value=GetImageOption(_image_info,"compose:outside-overlay");
3778 if (value != (const char *) NULL) { /* or this false */
3779 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3780 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3783 new_images=RemoveFirstImageFromList(&_images);
3784 source_image=RemoveFirstImageFromList(&_images);
3785 if (source_image == (Image *) NULL)
3786 break; /* FUTURE - produce Exception, rather than silent fail */
3788 /* FUTURE - this should not be here! - should be part of -geometry */
3789 (void) TransformImage(&source_image,(char *) NULL,
3790 source_image->geometry,_exception);
3791 SetGeometry(source_image,&geometry);
3792 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3793 GravityAdjustGeometry(new_images->columns,new_images->rows,
3794 new_images->gravity, &geometry);
3795 mask_image=RemoveFirstImageFromList(&_images);
3796 if (mask_image != (Image *) NULL)
3798 if ((compose == DisplaceCompositeOp) ||
3799 (compose == DistortCompositeOp))
3800 status&=CompositeImage(source_image,mask_image,
3801 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3810 source_geometry.width=mask_image->columns;
3811 source_geometry.height=mask_image->rows;
3812 source_geometry.x=(-geometry.x);
3813 source_geometry.y=(-geometry.y);
3816 image=ExtentImage(source_image,&source_geometry,_exception);
3817 if (image != (Image *) NULL)
3819 source_image=DestroyImage(source_image);
3822 status&=CompositeImage(source_image,mask_image,
3823 IntensityCompositeOp,MagickTrue,0,0,_exception);
3825 mask_image=DestroyImage(mask_image);
3827 status&=CompositeImage(new_images,source_image,compose,clip_to_self,
3828 geometry.x,geometry.y,_exception);
3829 source_image=DestroyImage(source_image);
3832 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3836 if (LocaleCompare("deconstruct",option+1) == 0)
3838 CLIWandWarnReplaced("-layer CompareAny");
3839 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3842 if (LocaleCompare("delete",option+1) == 0)
3845 DeleteImages(&_images,arg1,_exception);
3847 DeleteImages(&_images,"-1",_exception);
3850 if (LocaleCompare("duplicate",option+1) == 0)
3860 if (IfMagickFalse(IsGeometry(arg1)))
3861 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3863 number_duplicates=(size_t) StringToLong(arg1);
3865 if (p == (const char *) NULL)
3866 new_images=DuplicateImages(_images,number_duplicates,"-1",
3869 new_images=DuplicateImages(_images,number_duplicates,p,
3873 new_images=DuplicateImages(_images,1,"-1",_exception);
3874 AppendImageToList(&_images, new_images);
3875 new_images=(Image *)NULL;
3878 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3882 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3884 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3886 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3888 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3892 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3896 if (LocaleCompare("fft",option+1) == 0)
3898 new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception);
3901 if (LocaleCompare("flatten",option+1) == 0)
3903 /* REDIRECTED to use -layers flatten instead */
3904 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3907 if (LocaleCompare("fx",option+1) == 0)
3909 new_images=FxImage(_images,arg1,_exception);
3912 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3916 if (LocaleCompare("hald-clut",option+1) == 0)
3918 /* FUTURE - make this a compose option (and thus layers compose )
3919 or perhaps compose last image over all other _images.
3924 new_images=RemoveFirstImageFromList(&_images);
3925 hald_image=RemoveLastImageFromList(&_images);
3926 if (hald_image == (Image *) NULL)
3928 (void) HaldClutImage(new_images,hald_image,_exception);
3929 hald_image=DestroyImage(hald_image);
3932 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3936 if (LocaleCompare("ift",option+1) == 0)
3942 magnitude_image=RemoveFirstImageFromList(&_images);
3943 phase_image=RemoveFirstImageFromList(&_images);
3944 /* FUTURE - produce Exception, rather than silent fail */
3945 if (phase_image == (Image *) NULL)
3947 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3948 IsNormalOp,_exception);
3949 magnitude_image=DestroyImage(magnitude_image);
3950 phase_image=DestroyImage(phase_image);
3953 if (LocaleCompare("insert",option+1) == 0)
3962 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3963 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3965 insert_image=RemoveLastImageFromList(&_images);
3967 index=(ssize_t) StringToLong(arg1);
3968 index_image=insert_image;
3970 PrependImageToList(&_images,insert_image);
3971 else if (index == (ssize_t) GetImageListLength(_images))
3972 AppendImageToList(&_images,insert_image);
3975 index_image=GetImageFromList(_images,index-1);
3976 if (index_image == (Image *) NULL)
3977 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3978 InsertImageInList(&index_image,insert_image);
3980 _images=GetFirstImageInList(index_image);
3983 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3987 if (LocaleCompare("layers",option+1) == 0)
3989 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3991 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3993 switch ((LayerMethod) parse)
3997 new_images=CoalesceImages(_images,_exception);
4000 case CompareAnyLayer:
4001 case CompareClearLayer:
4002 case CompareOverlayLayer:
4005 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4012 case TrimBoundsLayer:
4014 new_images=MergeImageLayers(_images,(LayerMethod) parse,
4020 new_images=DisposeImages(_images,_exception);
4023 case OptimizeImageLayer:
4025 new_images=OptimizeImageLayers(_images,_exception);
4028 case OptimizePlusLayer:
4030 new_images=OptimizePlusImageLayers(_images,_exception);
4033 case OptimizeTransLayer:
4035 OptimizeImageTransparency(_images,_exception);
4038 case RemoveDupsLayer:
4040 RemoveDuplicateLayers(&_images,_exception);
4043 case RemoveZeroLayer:
4045 RemoveZeroDelayLayers(&_images,_exception);
4049 { /* General Purpose, GIF Animation Optimizer. */
4050 new_images=CoalesceImages(_images,_exception);
4051 if (new_images == (Image *) NULL)
4053 _images=DestroyImageList(_images);
4054 _images=OptimizeImageLayers(new_images,_exception);
4055 if (_images == (Image *) NULL)
4057 new_images=DestroyImageList(new_images);
4058 OptimizeImageTransparency(_images,_exception);
4059 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4063 case CompositeLayer:
4077 value=GetImageOption(_image_info,"compose");
4078 compose=OverCompositeOp; /* Default to Over */
4079 if (value != (const char *) NULL)
4080 compose=(CompositeOperator) ParseCommandOption(
4081 MagickComposeOptions,MagickFalse,value);
4083 /* Split image sequence at the first 'NULL:' image. */
4085 while (source != (Image *) NULL)
4087 source=GetNextImageInList(source);
4088 if ((source != (Image *) NULL) &&
4089 (LocaleCompare(source->magick,"NULL") == 0))
4092 if (source != (Image *) NULL)
4094 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4095 (GetNextImageInList(source) == (Image *) NULL))
4096 source=(Image *) NULL;
4098 { /* Separate the two lists, junk the null: image. */
4099 source=SplitImageList(source->previous);
4100 DeleteImageFromList(&source);
4103 if (source == (Image *) NULL)
4105 (void) ThrowMagickException(_exception,GetMagickModule(),
4106 OptionError,"MissingNullSeparator","layers Composite");
4109 /* Adjust offset with gravity and virtual canvas. */
4110 SetGeometry(_images,&geometry);
4111 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4112 geometry.width=source->page.width != 0 ?
4113 source->page.width : source->columns;
4114 geometry.height=source->page.height != 0 ?
4115 source->page.height : source->rows;
4116 GravityAdjustGeometry(_images->page.width != 0 ?
4117 _images->page.width : _images->columns,
4118 _images->page.height != 0 ? _images->page.height :
4119 _images->rows,_images->gravity,&geometry);
4121 /* Compose the two image sequences together */
4122 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4124 source=DestroyImageList(source);
4130 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4134 if (LocaleCompare("map",option+1) == 0)
4136 CLIWandWarnReplaced("+remap");
4137 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4140 if (LocaleCompare("metric",option+1) == 0)
4142 if (LocaleCompare("morph",option+1) == 0)
4147 if (IfMagickFalse(IsGeometry(arg1)))
4148 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4149 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4151 if (morph_image == (Image *) NULL)
4153 _images=DestroyImageList(_images);
4154 _images=morph_image;
4157 if (LocaleCompare("mosaic",option+1) == 0)
4159 /* REDIRECTED to use -layers mosaic instead */
4160 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4163 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4167 if (LocaleCompare("poly",option+1) == 0)
4175 /* convert argument string into an array of doubles */
4176 args = StringToArrayOfDoubles(arg2,&count,_exception);
4177 if (args == (double *)NULL )
4178 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4179 new_images=PolynomialImage(_images,count >> 1,args,_exception);
4180 args=(double *) RelinquishMagickMemory(args);
4183 if (LocaleCompare("process",option+1) == 0)
4185 /* FUTURE: better parsing using ScriptToken() from string ??? */
4193 arguments=StringToArgv(arg1,&number_arguments);
4194 if (arguments == (char **) NULL)
4196 if (strchr(arguments[1],'=') != (char *) NULL)
4217 Support old style syntax, filter="-option arg1".
4219 assert(arg1 != (const char *) NULL);
4220 length=strlen(arg1);
4221 token=(char *) NULL;
4222 if (~length >= (MaxTextExtent-1))
4223 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4225 if (token == (char *) NULL)
4229 token_info=AcquireTokenInfo();
4230 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4231 "\"",'\0',&breaker,&next,"e);
4232 token_info=DestroyTokenInfo(token_info);
4238 argv=(&(arguments[next]));
4239 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4242 token=DestroyString(token);
4245 (void) SubstituteString(&arguments[1],"-","");
4246 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4247 number_arguments-2,(const char **) arguments+2,_exception);
4248 for (j=0; j < number_arguments; j++)
4249 arguments[j]=DestroyString(arguments[j]);
4250 arguments=(char **) RelinquishMagickMemory(arguments);
4253 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4257 if (LocaleCompare("remap",option+1) == 0)
4259 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4262 if (LocaleCompare("reverse",option+1) == 0)
4264 ReverseImageList(&_images);
4267 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4271 if (LocaleCompare("smush",option+1) == 0)
4273 /* FUTURE: this option needs more work to make better */
4277 if (IfMagickFalse(IsGeometry(arg1)))
4278 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4279 offset=(ssize_t) StringToLong(arg1);
4280 new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4283 if (LocaleCompare("subimage",option+1) == 0)
4301 base_image=GetImageFromList(_images,0);
4302 compare_image=GetImageFromList(_images,1);
4304 /* Comparision Metric */
4305 metric=UndefinedErrorMetric;
4306 value=GetImageOption(_image_info,"metric");
4307 if (value != (const char *) NULL)
4308 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4311 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4312 &offset,&similarity,_exception);
4314 if ( new_images != (Image *)NULL ) {
4316 result[MaxTextExtent];
4318 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4319 (void) SetImageProperty(new_images,"subimage:similarity",result,
4321 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4323 (void) SetImageProperty(new_images,"subimage:x",result,
4325 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4327 (void) SetImageProperty(new_images,"subimage:y",result,
4329 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4330 (unsigned long) offset.width,(unsigned long) offset.height,
4331 (long) offset.x,(long) offset.y);
4332 (void) SetImageProperty(new_images,"subimage:offset",result,
4337 if (LocaleCompare("swap",option+1) == 0) {
4357 flags=ParseGeometry(arg1,&geometry_info);
4358 if ((flags & RhoValue) == 0)
4359 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4360 index=(ssize_t) geometry_info.rho;
4361 if ((flags & SigmaValue) != 0)
4362 swap_index=(ssize_t) geometry_info.sigma;
4364 p=GetImageFromList(_images,index);
4365 q=GetImageFromList(_images,swap_index);
4366 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4368 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4370 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4373 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4374 swap=CloneImage(p,0,0,MagickTrue,_exception);
4375 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4376 ReplaceImageInList(&q,swap);
4377 _images=GetFirstImageInList(q);
4380 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4383 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4386 /* clean up percent escape interpreted strings */
4388 arg1=DestroyString((char *)arg1);
4390 arg2=DestroyString((char *)arg2);
4392 /* if new image list generated, replace existing image list */
4393 if (new_images == (Image *) NULL)
4394 return(status == 0 ? MagickFalse : MagickTrue);
4395 _images=DestroyImageList(_images);
4396 _images=GetFirstImageInList(new_images);
4397 return(status == 0 ? MagickFalse : MagickTrue);
4403 #undef _quantize_info
4410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4414 + C L I N o I m a g e O p e r a t i o n s %
4418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4420 % CLINoImageOperator() Applies operations that may not actually need images
4423 % The classic operators of this type is "-read", which actually creates
4424 % images even when no images are present. Or image stack operators, which
4425 % can be applied (push or pop) to an empty image list.
4427 % Note that these operators may involve other special 'option' prefix
4428 % characters other than '-' or '+', namely parenthesis and braces.
4430 % The format of the CLINoImageOption method is:
4432 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4433 % const char *arg1, const char *arg2)
4435 % A description of each parameter follows:
4437 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4439 % o option: The special option (with any switch char) to process
4441 % o arg1 & arg2: Argument for option, if required
4442 % Currently arg2 is not used.
4445 WandPrivate void CLINoImageOperator(MagickCLI *cli_wand,
4446 const char *option,const char *arg1n,const char *arg2n)
4448 const char /* percent escaped versions of the args */
4452 #define _image_info (cli_wand->wand.image_info)
4453 #define _images (cli_wand->wand.images)
4454 #define _exception (cli_wand->wand.exception)
4455 #define _process_flags (cli_wand->process_flags)
4456 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4457 #define IfNormalOp (*option=='-')
4458 #define IfPlusOp (*option!='-')
4460 assert(cli_wand != (MagickCLI *) NULL);
4461 assert(cli_wand->signature == WandSignature);
4462 assert(cli_wand->wand.signature == WandSignature);
4464 if (IfMagickTrue(cli_wand->wand.debug))
4465 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4466 "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n);
4471 /* Interpret Percent Escapes in Arguments - using first image */
4472 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4473 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4474 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4475 /* Interpret Percent escapes in argument 1 */
4476 if (arg1n != (char *) NULL) {
4477 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4478 if (arg1 == (char *) NULL) {
4479 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4480 arg1=arg1n; /* use the given argument as is */
4483 if (arg2n != (char *) NULL) {
4484 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4485 if (arg2 == (char *) NULL) {
4486 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4487 arg2=arg2n; /* use the given argument as is */
4491 #undef _process_flags
4494 do { /* break to exit code */
4496 No-op options (ignore these)
4498 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4500 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4502 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4504 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4506 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4511 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4512 ( LocaleCompare("--",option) == 0 ) ) {
4513 /* Do Glob filename Expansion for 'arg1' then read all images.
4515 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4516 * (but attaching to the filenames in the generated argument list) any
4517 * [...] read modifiers that may be present.
4519 * For example: It will expand '*.gif[20x20]' into a list such as
4520 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4522 * NOTE: In IMv6 this was done globally across all images. This
4523 * meant you could include IM options in '@filename' lists, but you
4524 * could not include comments. Doing it only for image read makes
4525 * it far more secure.
4527 * Note: arguments do not have percent escapes expanded for security
4535 argv = (char **) &arg1;
4537 /* Expand 'glob' expressions in the given filename.
4538 Expansion handles any 'coder:' prefix, or read modifiers attached
4539 to the filename, including them in the resulting expanded list.
4541 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4542 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4543 option,GetExceptionMessage(errno));
4545 /* loop over expanded filename list, and read then all in */
4546 for (i=0; i<argc; i++) {
4549 if (IfMagickTrue(_image_info->ping))
4550 new_images=PingImages(_image_info,argv[i],_exception);
4552 new_images=ReadImages(_image_info,argv[i],_exception);
4553 AppendImageToList(&_images, new_images);
4555 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4560 Note: Writing a empty image list is valid in specific cases
4562 if (LocaleCompare("write",option+1) == 0) {
4563 /* Note: arguments do not have percent escapes expanded */
4573 /* Need images, unless a "null:" output coder is used */
4574 if ( _images == (Image *) NULL ) {
4575 if ( LocaleCompare(arg1,"null:") == 0 )
4577 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4580 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4581 (void) DeleteImageRegistry(key);
4582 write_images=_images;
4584 write_images=CloneImageList(_images,_exception);
4585 write_info=CloneImageInfo(_image_info);
4586 (void) WriteImages(write_info,write_images,arg1,_exception);
4587 write_info=DestroyImageInfo(write_info);
4589 write_images=DestroyImageList(write_images);
4593 Parenthesis and Brace operations
4595 if (LocaleCompare("(",option) == 0) {
4596 /* stack 'push' images */
4604 node=cli_wand->image_list_stack;
4605 for ( ; node != (Stack *)NULL; node=node->next)
4607 if ( size >= MAX_STACK_DEPTH )
4608 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4609 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4610 if (node == (Stack *) NULL)
4611 CLIWandExceptionBreak(ResourceLimitFatalError,
4612 "MemoryAllocationFailed",option);
4613 node->data = (void *)cli_wand->wand.images;
4614 node->next = cli_wand->image_list_stack;
4615 cli_wand->image_list_stack = node;
4616 cli_wand->wand.images = NewImageList();
4618 /* handle respect-parenthesis */
4619 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4620 "respect-parenthesis"))))
4621 option="{"; /* fall-thru so as to push image settings too */
4624 /* fall thru to operation */
4626 if (LocaleCompare("{",option) == 0) {
4627 /* stack 'push' of image_info settings */
4635 node=cli_wand->image_info_stack;
4636 for ( ; node != (Stack *)NULL; node=node->next)
4638 if ( size >= MAX_STACK_DEPTH )
4639 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4640 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4641 if (node == (Stack *) NULL)
4642 CLIWandExceptionBreak(ResourceLimitFatalError,
4643 "MemoryAllocationFailed",option);
4645 node->data = (void *)cli_wand->wand.image_info;
4646 node->next = cli_wand->image_info_stack;
4648 cli_wand->image_info_stack = node;
4649 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4650 if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4651 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4653 cli_wand->wand.image_info = (ImageInfo *)node->data;
4654 node = (Stack *)RelinquishMagickMemory(node);
4660 if (LocaleCompare(")",option) == 0) {
4661 /* pop images from stack */
4665 node = (Stack *)cli_wand->image_list_stack;
4666 if ( node == (Stack *)NULL)
4667 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4668 cli_wand->image_list_stack = node->next;
4670 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4671 cli_wand->wand.images= (Image *)node->data;
4672 node = (Stack *)RelinquishMagickMemory(node);
4674 /* handle respect-parenthesis - of the previous 'pushed' settings */
4675 node = cli_wand->image_info_stack;
4676 if ( node != (Stack *)NULL)
4678 if (IfMagickTrue(IsStringTrue(GetImageOption(
4679 cli_wand->wand.image_info,"respect-parenthesis"))))
4680 option="}"; /* fall-thru so as to pop image settings too */
4686 /* fall thru to next if */
4688 if (LocaleCompare("}",option) == 0) {
4689 /* pop image_info settings from stack */
4693 node = (Stack *)cli_wand->image_info_stack;
4694 if ( node == (Stack *)NULL)
4695 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4696 cli_wand->image_info_stack = node->next;
4698 (void) DestroyImageInfo(cli_wand->wand.image_info);
4699 cli_wand->wand.image_info = (ImageInfo *)node->data;
4700 node = (Stack *)RelinquishMagickMemory(node);
4702 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4703 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4704 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4708 if (LocaleCompare("print",option+1) == 0)
4710 (void) FormatLocaleFile(stdout,"%s",arg1);
4713 if (LocaleCompare("set",option+1) == 0)
4715 /* Settings are applied to each image in memory in turn (if any).
4716 While a option: only need to be applied once globally.
4718 NOTE: rguments have not been automatically percent expaneded
4721 /* escape the 'key' once only, using first image. */
4722 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4723 if (arg1 == (char *) NULL)
4724 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4727 if (LocaleNCompare(arg1,"registry:",9) == 0)
4731 (void) DeleteImageRegistry(arg1+9);
4732 arg1=DestroyString((char *)arg1);
4735 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4736 if (arg2 == (char *) NULL) {
4737 arg1=DestroyString((char *)arg1);
4738 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4741 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
4742 arg1=DestroyString((char *)arg1);
4743 arg2=DestroyString((char *)arg2);
4746 if (LocaleNCompare(arg1,"option:",7) == 0)
4748 /* delete equivelent artifact from all images (if any) */
4749 if (_images != (Image *)NULL)
4751 MagickResetIterator(&cli_wand->wand);
4752 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4753 (void) DeleteImageArtifact(_images,arg1+7);
4754 MagickResetIterator(&cli_wand->wand);
4756 /* now set/delete the global option as needed */
4757 /* FUTURE: make escapes in a global 'option:' delayed */
4761 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4762 if (arg2 == (char *) NULL)
4763 CLIWandExceptionBreak(OptionWarning,
4764 "InterpretPropertyFailure",option);
4766 (void) SetImageOption(_image_info,arg1+7,arg2);
4767 arg1=DestroyString((char *)arg1);
4768 arg2=DestroyString((char *)arg2);
4771 /* Set Artifacts/Properties/Attributes all images (required) */
4772 if ( _images == (Image *) NULL )
4773 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
4775 MagickResetIterator(&cli_wand->wand);
4776 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4781 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4782 if (arg2 == (char *) NULL)
4783 CLIWandExceptionBreak(OptionWarning,
4784 "InterpretPropertyFailure",option);
4786 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4787 (void) SetImageArtifact(_images,arg1+9,arg2);
4788 else if (LocaleNCompare(arg1,"property:",9) == 0)
4789 (void) SetImageProperty(_images,arg1+9,arg2,_exception);
4791 (void) SetImageProperty(_images,arg1,arg2,_exception);
4792 arg2=DestroyString((char *)arg2);
4794 MagickResetIterator(&cli_wand->wand);
4795 arg1=DestroyString((char *)arg1);
4798 if (LocaleCompare("clone",option+1) == 0) {
4804 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4805 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4806 if ( cli_wand->image_list_stack == (Stack *)NULL)
4807 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4808 new_images = (Image *)cli_wand->image_list_stack->data;
4809 if (new_images == (Image *) NULL)
4810 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4811 new_images=CloneImages(new_images,arg1,_exception);
4812 if (new_images == (Image *) NULL)
4813 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4814 AppendImageToList(&_images,new_images);
4818 Informational Operations.
4820 Note that these do not require either a cli-wand or images!
4821 Though currently a cli-wand much be provided regardless.
4823 if (LocaleCompare("version",option+1) == 0)
4825 ListMagickVersion(stdout);
4828 if (LocaleCompare("list",option+1) == 0) {
4830 FUTURE: This 'switch' should really be part of MagickCore
4835 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4837 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4842 case MagickCoderOptions:
4844 (void) ListCoderInfo((FILE *) NULL,_exception);
4847 case MagickColorOptions:
4849 (void) ListColorInfo((FILE *) NULL,_exception);
4852 case MagickConfigureOptions:
4854 (void) ListConfigureInfo((FILE *) NULL,_exception);
4857 case MagickDelegateOptions:
4859 (void) ListDelegateInfo((FILE *) NULL,_exception);
4862 case MagickFontOptions:
4864 (void) ListTypeInfo((FILE *) NULL,_exception);
4867 case MagickFormatOptions:
4868 (void) ListMagickInfo((FILE *) NULL,_exception);
4870 case MagickLocaleOptions:
4871 (void) ListLocaleInfo((FILE *) NULL,_exception);
4873 case MagickLogOptions:
4874 (void) ListLogInfo((FILE *) NULL,_exception);
4876 case MagickMagicOptions:
4877 (void) ListMagicInfo((FILE *) NULL,_exception);
4879 case MagickMimeOptions:
4880 (void) ListMimeInfo((FILE *) NULL,_exception);
4882 case MagickModuleOptions:
4883 (void) ListModuleInfo((FILE *) NULL,_exception);
4885 case MagickPolicyOptions:
4886 (void) ListPolicyInfo((FILE *) NULL,_exception);
4888 case MagickResourceOptions:
4889 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4891 case MagickThresholdOptions:
4892 (void) ListThresholdMaps((FILE *) NULL,_exception);
4895 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4902 CLIWandException(OptionError,"UnrecognizedOption",option);
4904 DisableMSCWarning(4127)
4905 } while (0); /* break to exit code. */
4908 /* clean up percent escape interpreted strings */
4910 arg1=DestroyString((char *)arg1);
4912 arg2=DestroyString((char *)arg2);
4922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4926 + C L I O p t i o n %
4930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4932 % CLIOption() Processes the given option using the given CLI Magick Wand.
4933 % The option arguments can be variable in number, though at this time no more
4934 % that two is actually used by any option (this may change). Excess options
4935 % are simply ignored.
4937 % If the cli_wand->command pointer is non-null, then it is assumed that the
4938 % option has already been search for up from the CommandOptions[] table in
4939 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4940 % routine will do the lookup instead. The pointer is reset afterward.
4942 % This action allows the caller to lookup and pre-handle any 'special'
4943 % options, (such as implicit reads) before calling this general option
4944 % handler to deal with 'standard' command line options.
4946 % The format of the CLIOption method is:
4948 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4950 % A description of each parameter follows:
4952 % o cli_wand: the main CLI Wand to use.
4954 % o option: The special option (with any switch char) to process
4956 % o args: any required arguments for an option (variable number)
4960 % CLIoption(cli_wand,"-read","rose:");
4961 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4962 % CLIoption(cli_wand,"-distort","SRT:","30");
4963 % CLIoption(cli_wand,"-write","rotated_rose.png");
4966 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4968 const char /* extracted option args from args */
4975 assert(cli_wand != (MagickCLI *) NULL);
4976 assert(cli_wand->signature == WandSignature);
4977 assert(cli_wand->wand.signature == WandSignature);
4979 do { /* Break Code Block for error handling */
4981 /* get information about option */
4982 if ( cli_wand->command == (const OptionInfo *) NULL )
4983 cli_wand->command = GetCommandOptionInfo(option);
4985 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4986 option, cli_wand->command->mnemonic );
4988 option_type=(CommandOptionFlags) cli_wand->command->flags;
4990 if ( option_type == UndefinedOptionFlag )
4991 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4993 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4995 /* depreciated options */
4996 if ( (option_type & DeprecateOptionFlag) != 0 )
4997 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4999 /* options that this module does not handle */
5000 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5001 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5003 /* Get argument strings from VarArgs
5004 How can you determine if enough arguments was supplied?
5005 What happens if not enough arguments were supplied?
5008 count = cli_wand->command->type;
5013 va_start(operands,option);
5017 arg1=(const char *) va_arg(operands, const char *);
5019 arg2=(const char *) va_arg(operands, const char *);
5023 (void) FormatLocaleFile(stderr,
5024 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5025 option,(long) count,option_type,arg1,arg2);
5030 Call the appropriate option handler
5033 /* FUTURE: this is temporary - get 'settings' to handle distribution of
5034 settings to images attributes,proprieties,artifacts */
5035 if ( cli_wand->wand.images != (Image *)NULL )
5036 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5037 cli_wand->wand.exception);
5039 if ( (option_type & SettingOptionFlags) != 0 ) {
5040 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5041 // FUTURE: Sync Specific Settings into Image Properities (not global)
5044 /* Operators that do not need images - read, write, stack, clone */
5045 if ( (option_type & NoImageOperatorFlag) != 0)
5046 CLINoImageOperator(cli_wand, option, arg1, arg2);
5048 /* FUTURE: The not a setting part below is a temporary hack due to
5049 * some options being both a Setting and a Simple operator.
5050 * Specifically -monitor, -depth, and -colorspace */
5051 if ( cli_wand->wand.images == (Image *)NULL )
5052 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5053 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5054 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5056 /* Operators which loop of individual images, simply */
5057 if ( (option_type & SimpleOperatorFlag) != 0 &&
5058 cli_wand->wand.images != (Image *)NULL) /* temp hack */
5059 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
5061 /* Operators that work on the image list as a whole */
5062 if ( (option_type & ListOperatorFlag) != 0 )
5063 CLIListOperatorImages(cli_wand, option, arg1, arg2);
5065 DisableMSCWarning(4127)
5066 } while (0); /* end Break code block */
5069 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */