2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % OOO PPPP EEEE RRRR AA TTTTT III OOO N N %
7 % O O P P E R R A A T I O O NN N %
8 % O O PPPP EEE RRRR AAAA T I O O N N N %
9 % O O P E R R A A T I O O N NN %
10 % OOO P EEEE R RR A A T III OOO N N %
13 % CLI Magick Option Methods %
20 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % Apply the given options (settings, and simple, or sequence operations) to
37 % the given image(s) according to the current "image_info", "draw_info", and
38 % "quantize_info" settings, stored in a special CLI Image Wand.
40 % The final goal is to allow the execution in a strict one option at a time
41 % manner that is needed for 'pipelining and file scripting' of options in
44 % Anthony Thyssen, September 2011
50 #include "MagickWand/studio.h"
51 #include "MagickWand/MagickWand.h"
52 #include "MagickWand/magick-wand-private.h"
53 #include "MagickWand/wand.h"
54 #include "MagickWand/wandcli.h"
55 #include "MagickWand/wandcli-private.h"
56 #include "MagickWand/operation.h"
57 #include "MagickCore/monitor-private.h"
58 #include "MagickCore/thread-private.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/pixel-private.h"
65 #define USE_WAND_METHODS 1
66 #define MAX_STACK_DEPTH 32
67 #define UNDEFINED_COMPRESSION_QUALITY 0UL
69 /* FUTURE: why is this default so specific? */
70 #define DEFAULT_DISSIMILARITY_THRESHOLD "0.31830988618379067154"
73 Constant declaration. (temporary exports)
76 BackgroundColor[] = "#fff", /* white */
77 BorderColor[] = "#dfdfdf", /* sRGB gray */
78 MatteColor[] = "#bdbdbd"; /* slightly darker gray */
80 /* For Debugging Geometry Input */
81 #define ReportGeometry(flags,info) \
82 (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n", \
83 flags, info.rho, info.sigma, info.xi, info.psi )
86 ** Function to report on the progress of image operations
88 static MagickBooleanType MonitorProgress(const char *text,
89 const MagickOffsetType offset,const MagickSizeType extent,
90 void *wand_unused(cli_wandent_data))
93 message[MaxTextExtent],
104 (void) CopyMagickMemory(tag,text,MaxTextExtent);
106 if (p != (char *) NULL)
108 (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
109 locale_message=GetLocaleMessage(message);
110 if (locale_message == message)
112 if (p == (char *) NULL)
113 (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
114 locale_message,(long) offset,(unsigned long) extent,(long)
115 (100L*offset/(extent-1)));
117 (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
118 locale_message,p+1,(long) offset,(unsigned long) extent,(long)
119 (100L*offset/(extent-1)));
120 if (offset == (MagickOffsetType) (extent-1))
121 (void) FormatLocaleFile(stderr,"\n");
122 (void) fflush(stderr);
127 ** GetImageCache() will read an image into a image cache if not already
128 ** present then return the image that is in the cache under that filename.
130 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
131 ExceptionInfo *exception)
145 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
146 sans_exception=AcquireExceptionInfo();
147 image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
148 sans_exception=DestroyExceptionInfo(sans_exception);
149 if (image != (Image *) NULL)
151 read_info=CloneImageInfo(image_info);
152 (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
153 image=ReadImage(read_info,exception);
154 read_info=DestroyImageInfo(read_info);
155 if (image != (Image *) NULL)
156 (void) SetImageRegistry(ImageRegistryType,key,image,exception);
161 SparseColorOption() parse the complex -sparse-color argument into an
162 an array of floating point values than call SparseColorImage().
163 Argument is a complex mix of floating-point pixel coodinates, and color
164 specifications (or direct floating point numbers). The number of floats
165 needed to represent a color varies depending on teh current channel
168 This really should be in MagickCore, so that other API's can make use of it.
170 static Image *SparseColorOption(const Image *image,
171 const SparseColorMethod method,const char *arguments,
172 ExceptionInfo *exception)
175 token[MaxTextExtent];
199 assert(image != (Image *) NULL);
200 assert(image->signature == MagickSignature);
201 if (IfMagickTrue(image->debug))
202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
203 assert(exception != (ExceptionInfo *) NULL);
204 assert(exception->signature == MagickSignature);
206 Limit channels according to image
207 add up number of values needed per color.
210 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
212 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
214 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
216 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
217 (image->colorspace == CMYKColorspace))
219 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
220 image->alpha_trait == BlendPixelTrait)
224 Read string, to determine number of arguments needed,
230 GetMagickToken(p,&p,token);
231 if ( token[0] == ',' ) continue;
232 if ( isalpha((int) token[0]) || token[0] == '#' )
233 x += number_colors; /* color argument found */
235 x++; /* floating point argument */
237 /* control points and color values */
238 error = IsMagickTrue( x % (2+number_colors) );
240 if ( IfMagickTrue(error) ) {
241 (void) ThrowMagickException(exception,GetMagickModule(),
242 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
243 "Invalid number of Arguments");
244 return( (Image *)NULL);
247 /* Allocate and fill in the floating point arguments */
248 sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
249 sizeof(*sparse_arguments));
250 if (sparse_arguments == (double *) NULL) {
251 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
252 "MemoryAllocationFailed","%s","SparseColorOption");
253 return( (Image *)NULL);
255 (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
256 sizeof(*sparse_arguments));
259 while( *p != '\0' && x < number_arguments ) {
261 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
262 if ( token[0] == '\0' ) break;
263 if ( isalpha((int) token[0]) || token[0] == '#' ) {
264 (void) ThrowMagickException(exception,GetMagickModule(),
265 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
266 "Color found, instead of X-coord");
270 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
272 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
273 if ( token[0] == '\0' ) break;
274 if ( isalpha((int) token[0]) || token[0] == '#' ) {
275 (void) ThrowMagickException(exception,GetMagickModule(),
276 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
277 "Color found, instead of Y-coord");
281 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
282 /* color name or function given in string argument */
283 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
284 if ( token[0] == '\0' ) break;
285 if ( isalpha((int) token[0]) || token[0] == '#' ) {
286 /* Color string given */
287 (void) QueryColorCompliance(token,AllCompliance,&color,
289 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
290 sparse_arguments[x++] = QuantumScale*color.red;
291 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
292 sparse_arguments[x++] = QuantumScale*color.green;
293 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
294 sparse_arguments[x++] = QuantumScale*color.blue;
295 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
296 (image->colorspace == CMYKColorspace))
297 sparse_arguments[x++] = QuantumScale*color.black;
298 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
299 image->alpha_trait == BlendPixelTrait)
300 sparse_arguments[x++] = QuantumScale*color.alpha;
303 /* Colors given as a set of floating point values - experimental */
304 /* NB: token contains the first floating point value to use! */
305 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
307 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
308 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
310 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
311 token[0] = ','; /* used this token - get another */
313 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
315 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
316 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
318 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
319 token[0] = ','; /* used this token - get another */
321 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
323 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
324 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
326 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
327 token[0] = ','; /* used this token - get another */
329 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
330 (image->colorspace == CMYKColorspace))
332 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
333 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
335 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
336 token[0] = ','; /* used this token - get another */
338 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
339 image->alpha_trait == BlendPixelTrait)
341 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
342 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
344 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
345 token[0] = ','; /* used this token - get another */
349 if ( number_arguments != x && !error ) {
350 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
351 "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
352 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
353 return( (Image *)NULL);
356 return( (Image *)NULL);
358 /* Call the Sparse Color Interpolation function with the parsed arguments */
359 sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
361 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
362 return( sparse_image );
366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % C L I S e t t i n g O p t i o n I n f o %
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 % CLISettingOptionInfo() applies a single settings option into a CLI wand
377 % holding the image_info, draw_info, quantize_info structures that will be
378 % used when processing the images.
380 % These options do no require images to be present in the CLI wand for them
381 % to be able to be set, in which case they will generally be applied to image
382 % that are read in later
384 % Options handled by this function are listed in CommandOptions[] of
385 % "option.c" that is one of "SettingOptionFlags" option flags.
387 % The format of the CLISettingOptionInfo method is:
389 % void CLISettingOptionInfo(MagickCLI *cli_wand,
390 % const char *option, const char *arg1, const char *arg2)
392 % A description of each parameter follows:
394 % o cli_wand: structure holding settings to be applied
396 % o option: The option string to be set
398 % o arg1, arg2: optional argument strings to the operation
399 % arg2 is currently only used by "-limit"
402 WandExport void CLISettingOptionInfo(MagickCLI *cli_wand,
403 const char *option,const char *arg1, const char *arg2)
406 parse; /* option argument parsing (string to value table lookup) */
408 assert(cli_wand != (MagickCLI *) NULL);
409 assert(cli_wand->signature == WandSignature);
410 assert(cli_wand->wand.signature == WandSignature);
411 if (IfMagickTrue(cli_wand->wand.debug))
412 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
414 #define _image_info (cli_wand->wand.image_info)
415 #define _exception (cli_wand->wand.exception)
416 #define _draw_info (cli_wand->draw_info)
417 #define _quantize_info (cli_wand->quantize_info)
418 #define IfSetOption (*option=='-')
419 #define ArgBoolean IsMagickTrue(IfSetOption)
420 #define ArgBooleanNot IsMagickFalse(IfSetOption)
421 #define ArgBooleanString (IfSetOption?"true":"false")
422 #define ArgOption(def) (IfSetOption?arg1:(const char *)(def))
425 Setting are not directly involved with images, so can not
426 interpret Percent Escapes in Arguments, At least not yet */
428 #define _process_flags (cli_wand->process_flags)
429 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
430 /* Interpret Percent Escapes in Arguments - using first image */
433 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
434 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
435 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
436 /* Interpret Percent escapes in argument 1 */
437 if (arg1n != (char *) NULL) {
438 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
439 if (arg1 == (char *) NULL) {
440 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
441 arg1=arg1n; /* use the given argument as is */
444 if (arg2n != (char *) NULL) {
445 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
446 if (arg2 == (char *) NULL) {
447 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
448 arg2=arg2n; /* use the given argument as is */
452 #undef _process_flags
460 if (LocaleCompare("adjoin",option+1) == 0)
462 _image_info->adjoin = ArgBoolean;
465 if (LocaleCompare("affine",option+1) == 0)
467 CLIWandWarnReplaced("-draw 'affine ...'");
469 (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception);
471 GetAffineMatrix(&_draw_info->affine);
474 if (LocaleCompare("antialias",option+1) == 0)
476 _image_info->antialias =
477 _draw_info->stroke_antialias =
478 _draw_info->text_antialias = ArgBoolean;
481 if (LocaleCompare("attenuate",option+1) == 0)
483 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
484 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
485 (void) SetImageOption(_image_info,option+1,ArgOption("1.0"));
488 if (LocaleCompare("authenticate",option+1) == 0)
490 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
493 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
497 if (LocaleCompare("background",option+1) == 0)
499 /* FUTURE: both _image_info attribute & ImageOption in use!
500 _image_info only used directly for generating new images.
501 SyncImageSettings() used to set per-image attribute.
503 FUTURE: if _image_info->background_color is not set then
504 we should fall back to per-image background_color
506 At this time -background will 'wipe out' the per-image
509 Better error handling of QueryColorCompliance() needed.
511 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
512 (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance,
513 &_image_info->background_color,_exception);
516 if (LocaleCompare("bias",option+1) == 0)
518 /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias"
519 as it is actually rarely used except in direct convolve operations
520 Usage outside a direct convolve operation is actally non-sensible!
522 SyncImageSettings() used to set per-image attribute.
524 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
525 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
526 (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL));
529 if (LocaleCompare("black-point-compensation",option+1) == 0)
531 /* Used as a image chromaticity setting
532 SyncImageSettings() used to set per-image attribute.
534 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
537 if (LocaleCompare("blue-primary",option+1) == 0)
539 /* Image chromaticity X,Y NB: Y=X if Y not defined
540 Used by many coders including PNG
541 SyncImageSettings() used to set per-image attribute.
543 arg1=ArgOption("0.0");
544 if (IfMagickFalse(IsGeometry(arg1)))
545 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
546 (void) SetImageOption(_image_info,option+1,arg1);
549 if (LocaleCompare("bordercolor",option+1) == 0)
551 /* FUTURE: both _image_info attribute & ImageOption in use!
552 SyncImageSettings() used to set per-image attribute.
553 Better error checking of QueryColorCompliance().
557 (void) SetImageOption(_image_info,option+1,arg1);
558 (void) QueryColorCompliance(arg1,AllCompliance,
559 &_image_info->border_color,_exception);
560 (void) QueryColorCompliance(arg1,AllCompliance,
561 &_draw_info->border_color,_exception);
564 (void) DeleteImageOption(_image_info,option+1);
565 (void) QueryColorCompliance(BorderColor,AllCompliance,
566 &_image_info->border_color,_exception);
567 (void) QueryColorCompliance(BorderColor,AllCompliance,
568 &_draw_info->border_color,_exception);
571 if (LocaleCompare("box",option+1) == 0)
573 CLIWandWarnReplaced("-undercolor");
574 CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2);
577 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
581 if (LocaleCompare("cache",option+1) == 0)
586 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
587 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
588 limit=MagickResourceInfinity;
589 if (LocaleCompare("unlimited",arg1) != 0)
590 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0);
591 (void) SetMagickResourceLimit(MemoryResource,limit);
592 (void) SetMagickResourceLimit(MapResource,2*limit);
595 if (LocaleCompare("caption",option+1) == 0)
597 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
600 if (LocaleCompare("channel",option+1) == 0)
602 arg1=ArgOption("default");
603 parse=ParseChannelOption(arg1);
605 CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",
607 _image_info->channel=(ChannelType) parse;
608 (void) SetImageOption(_image_info,option+1,arg1);
611 if (LocaleCompare("colorspace",option+1) == 0)
613 /* Setting used for new images via AquireImage()
614 But also used as a SimpleImageOperator
615 Undefined colorspace means don't modify images on
616 read or as a operation */
617 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,
618 ArgOption("undefined"));
620 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
622 _image_info->colorspace=(ColorspaceType) parse;
625 if (LocaleCompare("comment",option+1) == 0)
627 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
630 if (LocaleCompare("compose",option+1) == 0)
632 /* FUTURE: _image_info should be used,
633 SyncImageSettings() used to set per-image attribute. - REMOVE
635 This setting should NOT be used to set image 'compose'
636 "-layer" operators shoud use _image_info if defined otherwise
637 they should use a per-image compose setting.
639 parse = ParseCommandOption(MagickComposeOptions,MagickFalse,
640 ArgOption("undefined"));
642 CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator",
644 _image_info->compose=(CompositeOperator) parse;
645 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
648 if (LocaleCompare("compress",option+1) == 0)
650 /* FUTURE: What should be used? _image_info or ImageOption ???
651 The former is more efficent, but Crisy prefers the latter!
652 SyncImageSettings() used to set per-image attribute.
654 The coders appears to use _image_info, not Image_Option
655 however the image attribute (for save) is set from the
658 Note that "undefined" is a different setting to "none".
660 parse = ParseCommandOption(MagickCompressOptions,MagickFalse,
661 ArgOption("undefined"));
663 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression",
665 _image_info->compression=(CompressionType) parse;
666 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
669 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
673 if (LocaleCompare("debug",option+1) == 0)
675 /* SyncImageSettings() used to set per-image attribute. */
676 arg1=ArgOption("none");
677 parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1);
679 CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType",
681 (void) SetLogEventMask(arg1);
682 _image_info->debug=IsEventLogging(); /* extract logging*/
683 cli_wand->wand.debug=IsEventLogging();
686 if (LocaleCompare("define",option+1) == 0)
688 if (LocaleNCompare(arg1,"registry:",9) == 0)
691 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception);
693 (void) DeleteImageRegistry(arg1+9);
696 /* DefineImageOption() equals SetImageOption() but with '=' */
698 (void) DefineImageOption(_image_info,arg1);
699 else if (IsMagickFalse(DeleteImageOption(_image_info,arg1)))
700 CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1);
703 if (LocaleCompare("delay",option+1) == 0)
705 /* Only used for new images via AcquireImage()
706 FUTURE: Option should also be used for "-morph" (color morphing)
709 if (IfMagickFalse(IsGeometry(arg1)))
710 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
711 (void) SetImageOption(_image_info,option+1,arg1);
714 if (LocaleCompare("density",option+1) == 0)
716 /* FUTURE: strings used in _image_info attr and _draw_info!
717 Basically as density can be in a XxY form!
719 SyncImageSettings() used to set per-image attribute.
721 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
722 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
723 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
724 (void) CloneString(&_image_info->density,ArgOption(NULL));
725 (void) CloneString(&_draw_info->density,_image_info->density);
728 if (LocaleCompare("depth",option+1) == 0)
730 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
731 SyncImageSettings() used to set per-image attribute.
733 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
734 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
735 _image_info->depth=IfSetOption?StringToUnsignedLong(arg1)
736 :MAGICKCORE_QUANTUM_DEPTH;
739 if (LocaleCompare("direction",option+1) == 0)
741 /* Image Option is only used to set _draw_info */
742 arg1=ArgOption("undefined");
743 parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1);
745 CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType",
747 _draw_info->direction=(DirectionType) parse;
748 (void) SetImageOption(_image_info,option+1,arg1);
751 if (LocaleCompare("display",option+1) == 0)
753 (void) CloneString(&_image_info->server_name,ArgOption(NULL));
754 (void) CloneString(&_draw_info->server_name,_image_info->server_name);
757 if (LocaleCompare("dispose",option+1) == 0)
759 /* only used in setting new images */
760 arg1=ArgOption("undefined");
761 parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1);
763 CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod",
765 (void) SetImageOption(_image_info,option+1,ArgOption("undefined"));
768 if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
770 /* FUTURE: this is only used by CompareImages() which is used
771 only by the "compare" CLI program at this time. */
772 arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD);
773 if (IfMagickFalse(IsGeometry(arg1)))
774 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
775 (void) SetImageOption(_image_info,option+1,arg1);
778 if (LocaleCompare("dither",option+1) == 0)
780 /* _image_info attr (on/off), _quantize_info attr (on/off)
781 but also ImageInfo and _quantize_info method!
782 FUTURE: merge the duality of the dithering options
784 _image_info->dither = ArgBoolean;
785 (void) SetImageOption(_image_info,option+1,ArgOption("none"));
786 _quantize_info->dither_method=(DitherMethod) ParseCommandOption(
787 MagickDitherOptions,MagickFalse,ArgOption("none"));
788 if (_quantize_info->dither_method == NoDitherMethod)
789 _image_info->dither = MagickFalse;
792 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
796 if (LocaleCompare("encoding",option+1) == 0)
798 (void) CloneString(&_draw_info->encoding,ArgOption("undefined"));
799 (void) SetImageOption(_image_info,option+1,_draw_info->encoding);
802 if (LocaleCompare("endian",option+1) == 0)
804 /* Both _image_info attr and ImageInfo */
805 arg1 = ArgOption("undefined");
806 parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1);
808 CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType",
810 /* FUTURE: check alloc/free of endian string! - remove? */
811 _image_info->endian=(EndianType) (*arg1);
812 (void) SetImageOption(_image_info,option+1,arg1);
815 if (LocaleCompare("extract",option+1) == 0)
817 (void) CloneString(&_image_info->extract,ArgOption(NULL));
820 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
824 if (LocaleCompare("family",option+1) == 0)
826 (void) CloneString(&_draw_info->family,ArgOption(NULL));
829 if (LocaleCompare("fill",option+1) == 0)
831 /* Set "fill" OR "fill-pattern" in _draw_info
832 The original fill color is preserved if a fill-pattern is given.
833 That way it does not effect other operations that directly using
834 the fill color and, can be retored using "+tile".
845 arg1 = ArgOption("none"); /* +fill turns it off! */
846 (void) SetImageOption(_image_info,option+1,arg1);
847 if (_draw_info->fill_pattern != (Image *) NULL)
848 _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern);
850 /* is it a color or a image? -- ignore exceptions */
851 sans=AcquireExceptionInfo();
852 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
853 sans=DestroyExceptionInfo(sans);
855 if (IfMagickFalse(status))
856 _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception);
858 _draw_info->fill=color;
861 if (LocaleCompare("filter",option+1) == 0)
863 /* SyncImageSettings() used to set per-image attribute. */
864 arg1 = ArgOption("undefined");
865 parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1);
867 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter",
869 (void) SetImageOption(_image_info,option+1,arg1);
872 if (LocaleCompare("font",option+1) == 0)
874 (void) CloneString(&_draw_info->font,ArgOption(NULL));
875 (void) CloneString(&_image_info->font,_draw_info->font);
878 if (LocaleCompare("format",option+1) == 0)
880 /* FUTURE: why the ping test, you could set ping after this! */
885 for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
886 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
887 _image_info->ping=MagickFalse;
889 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
892 if (LocaleCompare("fuzz",option+1) == 0)
894 /* Option used to set image fuzz! unless blank canvas (from color)
895 Image attribute used for color compare operations
896 SyncImageSettings() used to set per-image attribute.
898 FUTURE: Can't find anything else using _image_info->fuzz directly!
899 remove direct sttribute from image_info
902 if (IfMagickFalse(IsGeometry(arg1)))
903 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
904 _image_info->fuzz=StringToDoubleInterval(arg1,(double)
906 (void) SetImageOption(_image_info,option+1,arg1);
909 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
913 if (LocaleCompare("gravity",option+1) == 0)
915 /* SyncImageSettings() used to set per-image attribute. */
916 arg1 = ArgOption("none");
917 parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1);
919 CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType",
921 _draw_info->gravity=(GravityType) parse;
922 (void) SetImageOption(_image_info,option+1,arg1);
925 if (LocaleCompare("green-primary",option+1) == 0)
927 /* Image chromaticity X,Y NB: Y=X if Y not defined
928 SyncImageSettings() used to set per-image attribute.
929 Used directly by many coders
931 arg1=ArgOption("0.0");
932 if (IfMagickFalse(IsGeometry(arg1)))
933 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
934 (void) SetImageOption(_image_info,option+1,arg1);
937 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
941 if (LocaleCompare("highlight-color",option+1) == 0)
943 /* FUTURE: this is only used by CompareImages() which is used
944 only by the "compare" CLI program at this time. */
945 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
948 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
952 if (LocaleCompare("intent",option+1) == 0)
954 /* Only used by coders: MIFF, MPC, BMP, PNG
955 and for image profile call to AcquireTransformThreadSet()
956 SyncImageSettings() used to set per-image attribute.
958 arg1 = ArgOption("indefined");
959 parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1);
961 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType",
963 (void) SetImageOption(_image_info,option+1,arg1);
966 if (LocaleCompare("interlace",option+1) == 0)
968 /* _image_info is directly used by coders (so why an image setting?)
969 SyncImageSettings() used to set per-image attribute.
971 arg1 = ArgOption("undefined");
972 parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1);
974 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType",
976 _image_info->interlace=(InterlaceType) parse;
977 (void) SetImageOption(_image_info,option+1,arg1);
980 if (LocaleCompare("interline-spacing",option+1) == 0)
982 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
983 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
984 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
985 _draw_info->interline_spacing=StringToDouble(ArgOption("0"),
989 if (LocaleCompare("interpolate",option+1) == 0)
991 /* SyncImageSettings() used to set per-image attribute. */
992 arg1 = ArgOption("undefined");
993 parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1);
995 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod",
997 (void) SetImageOption(_image_info,option+1,arg1);
1000 if (LocaleCompare("interword-spacing",option+1) == 0)
1002 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1003 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1004 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1005 _draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
1008 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1012 if (LocaleCompare("kerning",option+1) == 0)
1014 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1015 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1016 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1017 _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
1020 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1024 if (LocaleCompare("label",option+1) == 0)
1026 /* only used for new images - not in SyncImageOptions() */
1027 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1030 if (LocaleCompare("limit",option+1) == 0)
1035 limit=MagickResourceInfinity;
1036 parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1);
1038 CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType",
1040 if (LocaleCompare("unlimited",arg2) != 0)
1041 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
1042 (void) SetMagickResourceLimit((ResourceType)parse,limit);
1045 if (LocaleCompare("log",option+1) == 0)
1048 if ((strchr(arg1,'%') == (char *) NULL))
1049 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1050 (void) SetLogFormat(arg1);
1054 if (LocaleCompare("lowlight-color",option+1) == 0)
1056 /* FUTURE: this is only used by CompareImages() which is used
1057 only by the "compare" CLI program at this time. */
1058 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1061 if (LocaleCompare("loop",option+1) == 0)
1063 /* SyncImageSettings() used to set per-image attribute. */
1064 arg1=ArgOption("0");
1065 if (IfMagickFalse(IsGeometry(arg1)))
1066 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1067 (void) SetImageOption(_image_info,option+1,arg1);
1070 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1074 if (LocaleCompare("mattecolor",option+1) == 0)
1076 /* SyncImageSettings() used to set per-image attribute. */
1077 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1078 (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance,
1079 &_image_info->matte_color,_exception);
1082 if (LocaleCompare("metric",option+1) == 0)
1084 /* FUTURE: this is only used by CompareImages() which is used
1085 only by the "compare" CLI program at this time. */
1086 parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1);
1088 CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType",
1090 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1093 if (LocaleCompare("monitor",option+1) == 0)
1095 (void) SetImageInfoProgressMonitor(_image_info, IfSetOption?
1096 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
1099 if (LocaleCompare("monochrome",option+1) == 0)
1101 /* Setting (used by some input coders!) -- why?
1102 Warning: This is also Special '-type' SimpleOperator
1104 _image_info->monochrome= ArgBoolean;
1107 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1111 if (LocaleCompare("orient",option+1) == 0)
1113 /* Is not used when defining for new images.
1114 This makes it more of a 'operation' than a setting
1115 FUTURE: make set meta-data operator instead.
1116 SyncImageSettings() used to set per-image attribute.
1118 parse=ParseCommandOption(MagickOrientationOptions,MagickFalse,
1119 ArgOption("undefined"));
1121 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation",
1123 _image_info->orientation=(OrientationType)parse;
1124 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1127 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1131 if (LocaleCompare("page",option+1) == 0)
1133 /* Only used for new images and image generators.
1134 SyncImageSettings() used to set per-image attribute. ?????
1135 That last is WRONG!!!!
1136 FUTURE: adjust named 'page' sizes according density
1140 page[MaxTextExtent];
1153 (void) DeleteImageOption(_image_info,option+1);
1154 (void) CloneString(&_image_info->page,(char *) NULL);
1157 (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1158 image_option=GetImageOption(_image_info,"page");
1159 if (image_option != (const char *) NULL)
1160 flags=ParseAbsoluteGeometry(image_option,&geometry);
1161 canonical_page=GetPageGeometry(arg1);
1162 flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1163 canonical_page=DestroyString(canonical_page);
1164 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1165 (unsigned long) geometry.width,(unsigned long) geometry.height);
1166 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1167 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1168 (unsigned long) geometry.width,(unsigned long) geometry.height,
1169 (long) geometry.x,(long) geometry.y);
1170 (void) SetImageOption(_image_info,option+1,page);
1171 (void) CloneString(&_image_info->page,page);
1174 if (LocaleCompare("ping",option+1) == 0)
1176 _image_info->ping = ArgBoolean;
1179 if (LocaleCompare("pointsize",option+1) == 0)
1182 if (IfMagickFalse(IsGeometry(arg1)))
1183 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1184 _image_info->pointsize =
1185 _draw_info->pointsize =
1186 StringToDouble(arg1,(char **) NULL);
1189 _image_info->pointsize=0.0; /* unset pointsize */
1190 _draw_info->pointsize=12.0;
1194 if (LocaleCompare("precision",option+1) == 0)
1196 arg1=ArgOption("-1");
1197 if (IfMagickFalse(IsGeometry(arg1)))
1198 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1199 (void) SetMagickPrecision(StringToInteger(arg1));
1202 /* FUTURE: Only the 'preview' coder appears to use this
1203 * DEPRECIATE the coder? Leaving only the 'preview' operator.
1204 if (LocaleCompare("preview",option+1) == 0)
1206 _image_info->preview_type=UndefinedPreview;
1208 _image_info->preview_type=(PreviewType) ParseCommandOption(
1209 MagickPreviewOptions,MagickFalse,arg1);
1213 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1217 if (LocaleCompare("quality",option+1) == 0)
1219 if (IfMagickFalse(IsGeometry(arg1)))
1220 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1221 _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1)
1222 : UNDEFINED_COMPRESSION_QUALITY;
1223 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1226 if (LocaleCompare("quantize",option+1) == 0)
1228 /* Just a set direct in _quantize_info */
1229 arg1=ArgOption("undefined");
1230 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
1232 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",
1234 _quantize_info->colorspace=(ColorspaceType)parse;
1237 if (LocaleCompare("quiet",option+1) == 0)
1239 /* FUTURE: if two -quiet is performed you can not do +quiet!
1240 This needs to be checked over thoughly.
1242 static WarningHandler
1243 warning_handler = (WarningHandler) NULL;
1246 tmp = SetWarningHandler((WarningHandler) NULL);
1248 if ( tmp != (WarningHandler) NULL)
1249 warning_handler = tmp; /* remember the old handler */
1250 if (!IfSetOption) /* set the old handler */
1251 warning_handler=SetWarningHandler(warning_handler);
1254 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1258 if (LocaleCompare("red-primary",option+1) == 0)
1260 /* Image chromaticity X,Y NB: Y=X if Y not defined
1262 SyncImageSettings() used to set per-image attribute.
1264 arg1=ArgOption("0.0");
1265 if (IfMagickFalse(IsGeometry(arg1)))
1266 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1267 (void) SetImageOption(_image_info,option+1,arg1);
1270 if (LocaleCompare("regard-warnings",option+1) == 0)
1271 /* FUTURE: to be replaced by a 'fatal-level' type setting */
1273 if (LocaleCompare("render",option+1) == 0)
1275 /* _draw_info only setting */
1276 _draw_info->render= ArgBooleanNot;
1279 if (LocaleCompare("respect-parenthesis",option+1) == 0)
1281 /* link image and setting stacks - option is itself saved on stack! */
1282 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1285 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1289 if (LocaleCompare("sampling-factor",option+1) == 0)
1291 /* FUTURE: should be converted to jpeg:sampling_factor */
1292 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1293 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1294 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1297 if (LocaleCompare("scene",option+1) == 0)
1299 /* SyncImageSettings() used to set this as a per-image attribute.
1302 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1303 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1304 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1305 _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1308 if (LocaleCompare("seed",option+1) == 0)
1310 if (IfMagickFalse(IsGeometry(arg1)))
1311 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1313 IfSetOption ? (const unsigned long) StringToUnsignedLong(arg1)
1314 : (const unsigned long) time((time_t *) NULL) );
1317 if (LocaleCompare("size",option+1) == 0)
1319 /* FUTURE: string in _image_info -- convert to Option ???
1320 Look at the special handling for "size" in SetImageOption()
1322 (void) CloneString(&_image_info->size,ArgOption(NULL));
1325 if (LocaleCompare("stretch",option+1) == 0)
1327 arg1=ArgOption("undefined");
1328 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1330 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1332 _draw_info->stretch=(StretchType) parse;
1335 if (LocaleCompare("stroke",option+1) == 0)
1337 /* set stroke color OR stroke-pattern
1338 UPDATE: ensure stroke color is not destroyed is a pattern
1339 is given. Just in case the color is also used for other purposes.
1350 arg1 = ArgOption("none"); /* +fill turns it off! */
1351 (void) SetImageOption(_image_info,option+1,arg1);
1352 if (_draw_info->stroke_pattern != (Image *) NULL)
1353 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1355 /* is it a color or a image? -- ignore exceptions */
1356 sans=AcquireExceptionInfo();
1357 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1358 sans=DestroyExceptionInfo(sans);
1360 if (IfMagickFalse(status))
1361 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1363 _draw_info->stroke=color;
1366 if (LocaleCompare("strokewidth",option+1) == 0)
1368 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1369 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1370 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1371 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1375 if (LocaleCompare("style",option+1) == 0)
1377 arg1=ArgOption("undefined");
1378 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1380 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1382 _draw_info->style=(StyleType) parse;
1386 if (LocaleCompare("subimage-search",option+1) == 0)
1388 /* FUTURE: this is only used by CompareImages() which is used
1389 only by the "compare" CLI program at this time. */
1390 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1394 if (LocaleCompare("synchronize",option+1) == 0)
1396 /* FUTURE: syncronize to storage - but what does that mean? */
1397 _image_info->synchronize = ArgBoolean;
1400 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1404 if (LocaleCompare("taint",option+1) == 0)
1406 /* SyncImageSettings() used to set per-image attribute. */
1407 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1410 if (LocaleCompare("texture",option+1) == 0)
1412 /* Note: arguments do not have percent escapes expanded */
1413 /* FUTURE: move _image_info string to option splay-tree
1414 Other than "montage" what uses "texture" ????
1416 (void) CloneString(&_image_info->texture,ArgOption(NULL));
1419 if (LocaleCompare("tile",option+1) == 0)
1421 /* Note: arguments do not have percent escapes expanded */
1422 _draw_info->fill_pattern=IfSetOption
1423 ?GetImageCache(_image_info,arg1,_exception)
1424 :DestroyImage(_draw_info->fill_pattern);
1427 if (LocaleCompare("tile-offset",option+1) == 0)
1429 /* SyncImageSettings() used to set per-image attribute. ??? */
1430 arg1=ArgOption("0");
1431 if (IfMagickFalse(IsGeometry(arg1)))
1432 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1433 (void) SetImageOption(_image_info,option+1,arg1);
1436 if (LocaleCompare("transparent-color",option+1) == 0)
1438 /* FUTURE: both _image_info attribute & ImageOption in use!
1439 _image_info only used for generating new images.
1440 SyncImageSettings() used to set per-image attribute.
1442 Note that +transparent-color, means fall-back to image
1443 attribute so ImageOption is deleted, not set to a default.
1445 if (IfSetOption && IfMagickFalse(IsGeometry(arg1)))
1446 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1447 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1448 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1449 &_image_info->transparent_color,_exception);
1452 if (LocaleCompare("treedepth",option+1) == 0)
1454 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1455 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1458 if (LocaleCompare("type",option+1) == 0)
1460 /* SyncImageSettings() used to set per-image attribute. */
1461 parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1462 ArgOption("undefined"));
1464 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1466 _image_info->type=(ImageType) parse;
1467 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1470 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1474 if (LocaleCompare("undercolor",option+1) == 0)
1476 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1477 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1478 &_draw_info->undercolor,_exception);
1481 if (LocaleCompare("units",option+1) == 0)
1483 /* SyncImageSettings() used to set per-image attribute.
1484 Should this effect _draw_info X and Y resolution?
1485 FUTURE: this probably should be part of the density setting
1487 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1488 ArgOption("undefined"));
1490 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1492 _image_info->units=(ResolutionType) parse;
1493 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1496 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1500 if (LocaleCompare("verbose",option+1) == 0)
1502 /* FUTURE: Remember all options become image artifacts
1503 _image_info->verbose is only used by coders.
1505 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1506 _image_info->verbose= ArgBoolean;
1507 _image_info->ping=MagickFalse; /* verbose can't be a ping */
1510 if (LocaleCompare("view",option+1) == 0)
1512 /* FUTURE: Convert from _image_info to ImageOption
1513 Only used by coder FPX
1514 And it only tests existance, not its content!
1516 (void) CloneString(&_image_info->view,ArgOption(NULL));
1519 if (LocaleCompare("virtual-pixel",option+1) == 0)
1521 /* SyncImageSettings() used to set per-image attribute.
1522 This is VERY deep in the image caching structure.
1524 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1525 ArgOption("undefined"));
1527 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1529 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1532 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1536 if (LocaleCompare("weight",option+1) == 0)
1538 /* Just what does using a font 'weight' do ???
1539 There is no "-list weight" output (reference manual says there is)
1541 arg1=ArgOption("all");
1542 _draw_info->weight=StringToUnsignedLong(arg1);
1543 if (LocaleCompare(arg1,"all") == 0)
1544 _draw_info->weight=0;
1545 if (LocaleCompare(arg1,"bold") == 0)
1546 _draw_info->weight=700;
1547 if (LocaleCompare(arg1,"bolder") == 0)
1548 if (_draw_info->weight <= 800)
1549 _draw_info->weight+=100;
1550 if (LocaleCompare(arg1,"lighter") == 0)
1551 if (_draw_info->weight >= 100)
1552 _draw_info->weight-=100;
1553 if (LocaleCompare(arg1,"normal") == 0)
1554 _draw_info->weight=400;
1557 if (LocaleCompare("white-point",option+1) == 0)
1559 /* Used as a image chromaticity setting
1560 SyncImageSettings() used to set per-image attribute.
1562 arg1=ArgOption("0.0");
1563 if (IfMagickFalse(IsGeometry(arg1)))
1564 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1565 (void) SetImageOption(_image_info,option+1,arg1);
1568 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1571 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1575 /* clean up percent escape interpreted strings */
1577 arg1=DestroyString((char *)arg1);
1579 arg2=DestroyString((char *)arg2);
1585 #undef _quantize_info
1588 #undef ArgBooleanNot
1589 #undef ArgBooleanString
1596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1600 + C L I S i m p l e O p e r a t o r I m a g e s %
1604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1606 % CLISimpleOperatorImages() applys one simple image operation given to all
1607 % the images in the CLI wand, using any per-image or global settings that was
1608 % previously saved in the CLI wand.
1610 % It is assumed that any such settings are up-to-date.
1612 % The format of the WandSimpleOperatorImages method is:
1614 % void CLISimpleOperatorImages(MagickCLI *cli_wand,
1615 % const char *option, const char *arg1, const char *arg2)
1617 % A description of each parameter follows:
1619 % o cli_wand: structure holding settings and images to be operated on
1621 % o option: The option string for the operation
1623 % o arg1, arg2: optional argument strings to the operation
1628 CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1629 image operation to the current image pointed to by the CLI wand.
1631 The image in the list may be modified in three different ways...
1632 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1633 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1634 * one image replace by a list of images (-separate and -crop only!)
1636 In each case the result replaces the single original image in the list, as
1637 well as the pointer to the modified image (last image added if replaced by a
1638 list of images) is returned.
1640 As the image pointed to may be replaced, the first image in the list may
1641 also change. GetFirstImageInList() should be used by caller if they wish
1642 return the Image pointer to the first image in list.
1644 static void CLISimpleOperatorImage(MagickCLI *cli_wand,
1645 const char *option, const char *arg1n, const char *arg2n)
1662 const char /* For percent escape interpretImageProperties() */
1666 #define _image_info (cli_wand->wand.image_info)
1667 #define _image (cli_wand->wand.images)
1668 #define _exception (cli_wand->wand.exception)
1669 #define _draw_info (cli_wand->draw_info)
1670 #define _quantize_info (cli_wand->quantize_info)
1671 #define _process_flags (cli_wand->process_flags)
1672 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
1673 #define IfNormalOp (*option=='-')
1674 #define IfPlusOp (*option!='-')
1675 #define normal_op IsMagickTrue(IfNormalOp)
1676 #define plus_alt_op IsMagickFalse(IfNormalOp)
1678 assert(cli_wand != (MagickCLI *) NULL);
1679 assert(cli_wand->signature == WandSignature);
1680 assert(cli_wand->wand.signature == WandSignature);
1681 assert(_image != (Image *) NULL); /* an image must be present */
1682 if (IfMagickTrue(cli_wand->wand.debug))
1683 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1685 /* Interpret Percent Escapes in Arguments - using first image */
1688 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
1689 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1690 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1691 /* Interpret Percent escapes in argument 1 */
1692 if (arg1n != (char *) NULL) {
1693 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1694 if (arg1 == (char *) NULL) {
1695 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1696 arg1=arg1n; /* use the given argument as is */
1699 if (arg2n != (char *) NULL) {
1700 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1701 if (arg2 == (char *) NULL) {
1702 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1703 arg2=arg2n; /* use the given argument as is */
1707 #undef _process_flags
1711 (void) FormatLocaleFile(stderr,
1712 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1715 new_image = (Image *)NULL; /* the replacement image, if not null at end */
1716 SetGeometryInfo(&geometry_info);
1718 switch (*(option+1))
1722 if (LocaleCompare("adaptive-blur",option+1) == 0)
1724 flags=ParseGeometry(arg1,&geometry_info);
1725 if ((flags & (RhoValue|SigmaValue)) == 0)
1726 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1727 if ((flags & SigmaValue) == 0)
1728 geometry_info.sigma=1.0;
1729 new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1730 geometry_info.sigma,_exception);
1733 if (LocaleCompare("adaptive-resize",option+1) == 0)
1735 /* FUTURE: Roll into a resize special operator */
1736 if (IfMagickFalse(IsGeometry(arg1)))
1737 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1738 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1739 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1743 if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1745 flags=ParseGeometry(arg1,&geometry_info);
1746 if ((flags & (RhoValue|SigmaValue)) == 0)
1747 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1748 if ((flags & SigmaValue) == 0)
1749 geometry_info.sigma=1.0;
1750 new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1751 geometry_info.sigma,_exception);
1754 if (LocaleCompare("alpha",option+1) == 0)
1756 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1758 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1760 (void) SetImageAlphaChannel(_image,(AlphaChannelOption)parse,
1764 if (LocaleCompare("annotate",option+1) == 0)
1767 geometry[MaxTextExtent];
1769 SetGeometryInfo(&geometry_info);
1770 flags=ParseGeometry(arg1,&geometry_info);
1771 if ((flags & RhoValue) == 0)
1772 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1773 if ((flags & SigmaValue) == 0)
1774 geometry_info.sigma=geometry_info.rho;
1775 (void) CloneString(&_draw_info->text,arg2);
1776 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1777 geometry_info.xi,geometry_info.psi);
1778 (void) CloneString(&_draw_info->geometry,geometry);
1779 _draw_info->affine.sx=cos(DegreesToRadians(
1780 fmod(geometry_info.rho,360.0)));
1781 _draw_info->affine.rx=sin(DegreesToRadians(
1782 fmod(geometry_info.rho,360.0)));
1783 _draw_info->affine.ry=(-sin(DegreesToRadians(
1784 fmod(geometry_info.sigma,360.0))));
1785 _draw_info->affine.sy=cos(DegreesToRadians(
1786 fmod(geometry_info.sigma,360.0)));
1787 (void) AnnotateImage(_image,_draw_info,_exception);
1788 GetAffineMatrix(&_draw_info->affine);
1791 if (LocaleCompare("auto-gamma",option+1) == 0)
1793 (void) AutoGammaImage(_image,_exception);
1796 if (LocaleCompare("auto-level",option+1) == 0)
1798 (void) AutoLevelImage(_image,_exception);
1801 if (LocaleCompare("auto-orient",option+1) == 0)
1803 /* This should probably be a MagickCore function */
1804 switch (_image->orientation)
1806 case TopRightOrientation:
1808 new_image=FlopImage(_image,_exception);
1811 case BottomRightOrientation:
1813 new_image=RotateImage(_image,180.0,_exception);
1816 case BottomLeftOrientation:
1818 new_image=FlipImage(_image,_exception);
1821 case LeftTopOrientation:
1823 new_image=TransposeImage(_image,_exception);
1826 case RightTopOrientation:
1828 new_image=RotateImage(_image,90.0,_exception);
1831 case RightBottomOrientation:
1833 new_image=TransverseImage(_image,_exception);
1836 case LeftBottomOrientation:
1838 new_image=RotateImage(_image,270.0,_exception);
1844 if (new_image != (Image *) NULL)
1845 new_image->orientation=TopLeftOrientation;
1848 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1852 if (LocaleCompare("black-threshold",option+1) == 0)
1854 if (IfMagickFalse(IsGeometry(arg1)))
1855 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1856 (void) BlackThresholdImage(_image,arg1,_exception);
1859 if (LocaleCompare("blue-shift",option+1) == 0)
1861 geometry_info.rho=1.5;
1863 flags=ParseGeometry(arg1,&geometry_info);
1864 if ((flags & RhoValue) == 0)
1865 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1867 new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1870 if (LocaleCompare("blur",option+1) == 0)
1872 flags=ParseGeometry(arg1,&geometry_info);
1873 if ((flags & (RhoValue|SigmaValue)) == 0)
1874 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1875 if ((flags & SigmaValue) == 0)
1876 geometry_info.sigma=1.0;
1877 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1881 if (LocaleCompare("border",option+1) == 0)
1889 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1890 if ((flags & (WidthValue | HeightValue)) == 0)
1891 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1892 compose=OverCompositeOp;
1893 value=GetImageOption(_image_info,"compose");
1894 if (value != (const char *) NULL)
1895 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1897 new_image=BorderImage(_image,&geometry,compose,_exception);
1900 if (LocaleCompare("brightness-contrast",option+1) == 0)
1912 flags=ParseGeometry(arg1,&geometry_info);
1913 if ((flags & RhoValue) == 0)
1914 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1915 brightness=geometry_info.rho;
1917 if ((flags & SigmaValue) != 0)
1918 contrast=geometry_info.sigma;
1919 (void) BrightnessContrastImage(_image,brightness,contrast,
1923 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1927 if (LocaleCompare("cdl",option+1) == 0)
1929 /* Note: arguments do not have percent escapes expanded */
1931 *color_correction_collection;
1934 Color correct with a color decision list.
1936 color_correction_collection=FileToString(arg1,~0,_exception);
1937 if (color_correction_collection == (char *) NULL)
1939 (void) ColorDecisionListImage(_image,color_correction_collection,
1943 if (LocaleCompare("charcoal",option+1) == 0)
1945 flags=ParseGeometry(arg1,&geometry_info);
1946 if ((flags & (RhoValue|SigmaValue)) == 0)
1947 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1948 if ((flags & SigmaValue) == 0)
1949 geometry_info.sigma=1.0;
1950 if ((flags & XiValue) == 0)
1951 geometry_info.xi=1.0;
1952 new_image=CharcoalImage(_image,geometry_info.rho,
1953 geometry_info.sigma,_exception);
1956 if (LocaleCompare("chop",option+1) == 0)
1958 if (IfMagickFalse(IsGeometry(arg1)))
1959 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1960 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
1961 new_image=ChopImage(_image,&geometry,_exception);
1964 if (LocaleCompare("clamp",option+1) == 0)
1966 (void) ClampImage(_image,_exception);
1969 if (LocaleCompare("clip",option+1) == 0)
1972 (void) ClipImage(_image,_exception);
1973 else /* "+mask" remove the write mask */
1974 (void) SetImageMask(_image,(Image *) NULL,_exception);
1977 if (LocaleCompare("clip-mask",option+1) == 0)
1979 /* Note: arguments do not have percent escapes expanded */
1996 /* use "+clip-mask" Remove the write mask for -clip-path */
1997 (void) SetImageMask(_image,(Image *) NULL,_exception);
2000 mask_image=GetImageCache(_image_info,arg1,_exception);
2001 if (mask_image == (Image *) NULL)
2003 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception)))
2005 /* Create a write mask from cli_wand mask image */
2006 /* FUTURE: use Alpha operations instead and create a Grey Image */
2007 mask_view=AcquireAuthenticCacheView(mask_image,_exception);
2008 for (y=0; y < (ssize_t) mask_image->rows; y++)
2010 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
2012 if (q == (Quantum *) NULL)
2014 for (x=0; x < (ssize_t) mask_image->columns; x++)
2016 if (IfMagickFalse(mask_image->alpha_trait))
2017 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
2018 SetPixelRed(mask_image,GetPixelAlpha(mask_image,q),q);
2019 SetPixelGreen(mask_image,GetPixelAlpha(mask_image,q),q);
2020 SetPixelBlue(mask_image,GetPixelAlpha(mask_image,q),q);
2021 q+=GetPixelChannels(mask_image);
2023 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception)))
2026 /* clean up and set the write mask */
2027 mask_view=DestroyCacheView(mask_view);
2028 mask_image->alpha_trait=BlendPixelTrait;
2029 (void) SetImageMask(_image,mask_image,_exception);
2030 mask_image=DestroyImage(mask_image);
2033 if (LocaleCompare("clip-path",option+1) == 0)
2035 (void) ClipImagePath(_image,arg1,normal_op,_exception);
2036 /* Note: Use "+clip-mask" remove the write mask added */
2039 if (LocaleCompare("colorize",option+1) == 0)
2041 if (IfMagickFalse(IsGeometry(arg1)))
2042 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2043 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2046 if (LocaleCompare("color-matrix",option+1) == 0)
2051 kernel=AcquireKernelInfo(arg1);
2052 if (kernel == (KernelInfo *) NULL)
2053 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2054 new_image=ColorMatrixImage(_image,kernel,_exception);
2055 kernel=DestroyKernelInfo(kernel);
2058 if (LocaleCompare("colors",option+1) == 0)
2060 /* Reduce the number of colors in the image.
2061 FUTURE: also provide 'plus version with image 'color counts'
2063 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2064 if (_quantize_info->number_colors == 0)
2065 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2066 if ((_image->storage_class == DirectClass) ||
2067 _image->colors > _quantize_info->number_colors)
2068 (void) QuantizeImage(_quantize_info,_image,_exception);
2070 (void) CompressImageColormap(_image,_exception);
2073 if (LocaleCompare("colorspace",option+1) == 0)
2075 /* WARNING: this is both a image_info setting (already done)
2076 and a operator to change image colorspace.
2078 FUTURE: default colorspace should be sRGB!
2079 Unless some type of 'linear colorspace' mode is set.
2081 Note that +colorspace sets "undefined" or no effect on
2082 new images, but forces images already in memory back to RGB!
2083 That seems to be a little strange!
2085 (void) TransformImageColorspace(_image,
2086 IfNormalOp ? _image_info->colorspace : RGBColorspace,
2090 if (LocaleCompare("contrast",option+1) == 0)
2092 CLIWandWarnReplaced(normal_op?"-level":"+level");
2093 (void) ContrastImage(_image,normal_op,_exception);
2096 if (LocaleCompare("contrast-stretch",option+1) == 0)
2105 flags=ParseGeometry(arg1,&geometry_info);
2106 if ((flags & RhoValue) == 0)
2107 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2108 black_point=geometry_info.rho;
2109 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2111 if ((flags & PercentValue) != 0) {
2112 black_point*=(double) _image->columns*_image->rows/100.0;
2113 white_point*=(double) _image->columns*_image->rows/100.0;
2115 white_point=(double) _image->columns*_image->rows-
2117 (void) ContrastStretchImage(_image,black_point,white_point,
2121 if (LocaleCompare("convolve",option+1) == 0)
2126 kernel_info=AcquireKernelInfo(arg1);
2127 if (kernel_info == (KernelInfo *) NULL)
2128 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2129 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2131 kernel_info=DestroyKernelInfo(kernel_info);
2134 if (LocaleCompare("crop",option+1) == 0)
2136 /* WARNING: This can generate multiple images! */
2137 if (IfMagickFalse(IsGeometry(arg1)))
2138 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2139 new_image=CropImageToTiles(_image,arg1,_exception);
2142 if (LocaleCompare("cycle",option+1) == 0)
2144 if (IfMagickFalse(IsGeometry(arg1)))
2145 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2146 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2150 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2154 if (LocaleCompare("decipher",option+1) == 0)
2156 /* Note: arguments do not have percent escapes expanded */
2160 passkey=FileToStringInfo(arg1,~0,_exception);
2161 if (passkey == (StringInfo *) NULL)
2162 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2164 (void) PasskeyDecipherImage(_image,passkey,_exception);
2165 passkey=DestroyStringInfo(passkey);
2168 if (LocaleCompare("depth",option+1) == 0)
2170 /* The _image_info->depth setting has already been set
2171 We just need to apply it to all images in current sequence
2173 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2174 That is it really is an operation, not a setting! Arrgghhh
2176 FUTURE: this should not be an operator!!!
2178 (void) SetImageDepth(_image,_image_info->depth,_exception);
2181 if (LocaleCompare("deskew",option+1) == 0)
2187 if (IfMagickFalse(IsGeometry(arg1)))
2188 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2189 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2192 threshold=40.0*QuantumRange/100.0;
2193 new_image=DeskewImage(_image,threshold,_exception);
2196 if (LocaleCompare("despeckle",option+1) == 0)
2198 new_image=DespeckleImage(_image,_exception);
2201 if (LocaleCompare("distort",option+1) == 0)
2209 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2211 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2213 if ((DistortImageMethod) parse == ResizeDistortion)
2217 /* Special Case - Argument is actually a resize geometry!
2218 ** Convert that to an appropriate distortion argument array.
2219 ** FUTURE: make a separate special resize operator
2220 Roll into a resize special operator */
2221 if (IfMagickFalse(IsGeometry(arg2)))
2222 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2224 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2225 resize_args[0]=(double) geometry.width;
2226 resize_args[1]=(double) geometry.height;
2227 new_image=DistortImage(_image,(DistortImageMethod) parse,
2228 (size_t)2,resize_args,MagickTrue,_exception);
2231 /* convert argument string into an array of doubles */
2232 args = StringToArrayOfDoubles(arg2,&count,_exception);
2233 if (args == (double *)NULL )
2234 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2236 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args,
2237 plus_alt_op,_exception);
2238 args=(double *) RelinquishMagickMemory(args);
2241 if (LocaleCompare("draw",option+1) == 0)
2243 (void) CloneString(&_draw_info->primitive,arg1);
2244 (void) DrawImage(_image,_draw_info,_exception);
2245 (void) CloneString(&_draw_info->primitive,(char *)NULL);
2248 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2252 if (LocaleCompare("edge",option+1) == 0)
2254 flags=ParseGeometry(arg1,&geometry_info);
2255 if ((flags & (RhoValue|SigmaValue)) == 0)
2256 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2257 if ((flags & SigmaValue) == 0)
2258 geometry_info.sigma=1.0;
2259 new_image=EdgeImage(_image,geometry_info.rho,geometry_info.sigma,
2263 if (LocaleCompare("emboss",option+1) == 0)
2265 flags=ParseGeometry(arg1,&geometry_info);
2266 if ((flags & (RhoValue|SigmaValue)) == 0)
2267 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2268 if ((flags & SigmaValue) == 0)
2269 geometry_info.sigma=1.0;
2270 new_image=EmbossImage(_image,geometry_info.rho,
2271 geometry_info.sigma,_exception);
2274 if (LocaleCompare("encipher",option+1) == 0)
2276 /* Note: arguments do not have percent escapes expanded */
2280 passkey=FileToStringInfo(arg1,~0,_exception);
2281 if (passkey != (StringInfo *) NULL)
2283 (void) PasskeyEncipherImage(_image,passkey,_exception);
2284 passkey=DestroyStringInfo(passkey);
2288 if (LocaleCompare("enhance",option+1) == 0)
2290 new_image=EnhanceImage(_image,_exception);
2293 if (LocaleCompare("equalize",option+1) == 0)
2295 (void) EqualizeImage(_image,_exception);
2298 if (LocaleCompare("evaluate",option+1) == 0)
2303 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2305 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2307 if (IfMagickFalse(IsGeometry(arg2)))
2308 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2309 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2310 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2314 if (LocaleCompare("extent",option+1) == 0)
2316 if (IfMagickFalse(IsGeometry(arg1)))
2317 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2318 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2319 if (geometry.width == 0)
2320 geometry.width=_image->columns;
2321 if (geometry.height == 0)
2322 geometry.height=_image->rows;
2323 new_image=ExtentImage(_image,&geometry,_exception);
2326 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2330 if (LocaleCompare("features",option+1) == 0)
2332 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
2334 (void) DeleteImageArtifact(_image,"identify:features");
2337 (void) SetImageArtifact(_image,"identify:features","true");
2338 (void) SetImageArtifact(_image,"verbose","true");
2341 if (LocaleCompare("flip",option+1) == 0)
2343 new_image=FlipImage(_image,_exception);
2346 if (LocaleCompare("flop",option+1) == 0)
2348 new_image=FlopImage(_image,_exception);
2351 if (LocaleCompare("floodfill",option+1) == 0)
2356 if (IfMagickFalse(IsGeometry(arg1)))
2357 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2358 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2359 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2360 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2361 geometry.y,plus_alt_op,_exception);
2364 if (LocaleCompare("frame",option+1) == 0)
2375 value=GetImageOption(_image_info,"compose");
2376 compose=OverCompositeOp; /* use Over not _image->compose */
2377 if (value != (const char *) NULL)
2378 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2380 if (IfMagickFalse(IsGeometry(arg1)))
2381 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2382 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2383 frame_info.width=geometry.width;
2384 frame_info.height=geometry.height;
2385 frame_info.outer_bevel=geometry.x;
2386 frame_info.inner_bevel=geometry.y;
2387 frame_info.x=(ssize_t) frame_info.width;
2388 frame_info.y=(ssize_t) frame_info.height;
2389 frame_info.width=_image->columns+2*frame_info.width;
2390 frame_info.height=_image->rows+2*frame_info.height;
2391 new_image=FrameImage(_image,&frame_info,compose,_exception);
2394 if (LocaleCompare("function",option+1) == 0)
2402 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2404 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2406 /* convert argument string into an array of doubles */
2407 args = StringToArrayOfDoubles(arg2,&count,_exception);
2408 if (args == (double *)NULL )
2409 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2411 (void) FunctionImage(_image,(MagickFunction)parse,count,args,
2413 args=(double *) RelinquishMagickMemory(args);
2416 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2420 if (LocaleCompare("gamma",option+1) == 0)
2425 if (IfMagickFalse(IsGeometry(arg1)))
2426 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2427 constant=StringToDouble(arg1,(char **) NULL);
2429 /* Using Gamma, via a cache */
2431 constant=PerceptibleReciprocal(constant);
2432 (void) GammaImage(_image,constant,_exception);
2434 /* Using Evaluate POW, direct update of values - more accurite */
2436 constant=PerceptibleReciprocal(constant);
2437 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2439 /* Set gamma setting -- Old meaning of "+gamma"
2440 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2444 if (LocaleCompare("gaussian-blur",option+1) == 0)
2446 flags=ParseGeometry(arg1,&geometry_info);
2447 if ((flags & (RhoValue|SigmaValue)) == 0)
2448 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2449 if ((flags & SigmaValue) == 0)
2450 geometry_info.sigma=1.0;
2451 new_image=GaussianBlurImage(_image,geometry_info.rho,
2452 geometry_info.sigma,_exception);
2455 if (LocaleCompare("gaussian",option+1) == 0)
2457 CLIWandWarnReplaced("-gaussian-blur");
2458 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL);
2460 if (LocaleCompare("geometry",option+1) == 0)
2463 Record Image offset for composition. (A Setting)
2464 Resize last _image. (ListOperator) -- DEPRECIATE
2465 FUTURE: Why if no 'offset' does this resize ALL images?
2466 Also why is the setting recorded in the IMAGE non-sense!
2469 { /* remove the previous composition geometry offset! */
2470 if (_image->geometry != (char *) NULL)
2471 _image->geometry=DestroyString(_image->geometry);
2474 if (IfMagickFalse(IsGeometry(arg1)))
2475 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2476 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2477 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2478 (void) CloneString(&_image->geometry,arg1);
2480 new_image=ResizeImage(_image,geometry.width,geometry.height,
2481 _image->filter,_exception);
2484 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2488 if (LocaleCompare("identify",option+1) == 0)
2494 format=GetImageOption(_image_info,"format");
2495 if (format == (char *) NULL) {
2496 (void) IdentifyImage(_image,stdout,_image_info->verbose,_exception);
2499 text=InterpretImageProperties(_image_info,_image,format,_exception);
2500 if (text == (char *) NULL)
2501 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2503 (void) fputs(text,stdout);
2504 (void) fputc('\n',stdout);
2505 text=DestroyString((char *)text);
2508 if (LocaleCompare("implode",option+1) == 0)
2510 flags=ParseGeometry(arg1,&geometry_info);
2511 if ((flags & RhoValue) == 0)
2512 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2513 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2517 if (LocaleCompare("interpolative-resize",option+1) == 0)
2519 /* FUTURE: New to IMv7
2520 Roll into a resize special operator */
2521 if (IfMagickFalse(IsGeometry(arg1)))
2522 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2523 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2524 new_image=InterpolativeResizeImage(_image,geometry.width,
2525 geometry.height,_image->interpolate,_exception);
2528 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2532 if (LocaleCompare("lat",option+1) == 0)
2534 flags=ParseGeometry(arg1,&geometry_info);
2535 if ((flags & (RhoValue|SigmaValue)) == 0)
2536 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2537 if ((flags & SigmaValue) == 0)
2538 geometry_info.sigma=1.0;
2539 if ((flags & PercentValue) != 0)
2540 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2541 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2542 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2546 if (LocaleCompare("level",option+1) == 0)
2556 flags=ParseGeometry(arg1,&geometry_info);
2557 if ((flags & RhoValue) == 0)
2558 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2559 black_point=geometry_info.rho;
2560 white_point=(double) QuantumRange;
2561 if ((flags & SigmaValue) != 0)
2562 white_point=geometry_info.sigma;
2564 if ((flags & XiValue) != 0)
2565 gamma=geometry_info.xi;
2566 if ((flags & PercentValue) != 0)
2568 black_point*=(double) (QuantumRange/100.0);
2569 white_point*=(double) (QuantumRange/100.0);
2571 if ((flags & SigmaValue) == 0)
2572 white_point=(double) QuantumRange-black_point;
2573 if (IfPlusOp || ((flags & AspectValue) != 0))
2574 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2576 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2579 if (LocaleCompare("level-colors",option+1) == 0)
2582 token[MaxTextExtent];
2591 p=(const char *) arg1;
2592 GetMagickToken(p,&p,token); /* get black point color */
2593 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2594 (void) QueryColorCompliance(token,AllCompliance,
2595 &black_point,_exception);
2597 (void) QueryColorCompliance("#000000",AllCompliance,
2598 &black_point,_exception);
2599 if (isalpha((int) token[0]) || (token[0] == '#'))
2600 GetMagickToken(p,&p,token);
2602 white_point=black_point; /* set everything to that color */
2605 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2606 GetMagickToken(p,&p,token); /* Get white point color. */
2607 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2608 (void) QueryColorCompliance(token,AllCompliance,
2609 &white_point,_exception);
2611 (void) QueryColorCompliance("#ffffff",AllCompliance,
2612 &white_point,_exception);
2614 (void) LevelImageColors(_image,&black_point,&white_point,
2615 plus_alt_op,_exception);
2618 if (LocaleCompare("linear-stretch",option+1) == 0)
2627 flags=ParseGeometry(arg1,&geometry_info);
2628 if ((flags & RhoValue) == 0)
2629 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2630 black_point=geometry_info.rho;
2631 white_point=(double) _image->columns*_image->rows;
2632 if ((flags & SigmaValue) != 0)
2633 white_point=geometry_info.sigma;
2634 if ((flags & PercentValue) != 0)
2636 black_point*=(double) _image->columns*_image->rows/100.0;
2637 white_point*=(double) _image->columns*_image->rows/100.0;
2639 if ((flags & SigmaValue) == 0)
2640 white_point=(double) _image->columns*_image->rows-
2642 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2645 if (LocaleCompare("liquid-rescale",option+1) == 0)
2647 /* FUTURE: Roll into a resize special operator */
2648 if (IfMagickFalse(IsGeometry(arg1)))
2649 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2650 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2651 if ((flags & XValue) == 0)
2653 if ((flags & YValue) == 0)
2655 new_image=LiquidRescaleImage(_image,geometry.width,
2656 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2659 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2663 if (LocaleCompare("map",option+1) == 0)
2665 CLIWandWarnReplaced("-remap");
2666 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL);
2669 if (LocaleCompare("mask",option+1) == 0)
2671 /* Note: arguments do not have percent escapes expanded */
2676 { /* Remove a mask. */
2677 (void) SetImageMask(_image,(Image *) NULL,_exception);
2680 /* Set the image mask. */
2681 mask=GetImageCache(_image_info,arg1,_exception);
2682 if (mask == (Image *) NULL)
2684 (void) SetImageMask(_image,mask,_exception);
2685 mask=DestroyImage(mask);
2688 if (LocaleCompare("matte",option+1) == 0)
2690 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2691 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2692 DeactivateAlphaChannel, _exception);
2695 if (LocaleCompare("median",option+1) == 0)
2697 CLIWandWarnReplaced("-statistic Median");
2698 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1);
2701 if (LocaleCompare("mode",option+1) == 0)
2703 /* FUTURE: note this is also a special "montage" option */
2704 CLIWandWarnReplaced("-statistic Mode");
2705 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1);
2708 if (LocaleCompare("modulate",option+1) == 0)
2710 if (IfMagickFalse(IsGeometry(arg1)))
2711 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2712 (void) ModulateImage(_image,arg1,_exception);
2715 if (LocaleCompare("monitor",option+1) == 0)
2717 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2718 (MagickProgressMonitor) NULL,(void *) NULL);
2721 if (LocaleCompare("monochrome",option+1) == 0)
2723 (void) SetImageType(_image,BilevelType,_exception);
2726 if (LocaleCompare("morphology",option+1) == 0)
2729 token[MaxTextExtent];
2741 GetMagickToken(p,&p,token);
2742 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2744 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2747 GetMagickToken(p,&p,token);
2748 if ((*p == ':') || (*p == ','))
2749 GetMagickToken(p,&p,token);
2751 iterations=(ssize_t) StringToLong(p);
2752 kernel=AcquireKernelInfo(arg2);
2753 if (kernel == (KernelInfo *) NULL)
2754 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",
2756 new_image=MorphologyImage(_image,(MorphologyMethod)parse,
2757 iterations,kernel,_exception);
2758 kernel=DestroyKernelInfo(kernel);
2761 if (LocaleCompare("motion-blur",option+1) == 0)
2763 flags=ParseGeometry(arg1,&geometry_info);
2764 if ((flags & (RhoValue|SigmaValue)) == 0)
2765 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2766 if ((flags & SigmaValue) == 0)
2767 geometry_info.sigma=1.0;
2768 new_image=MotionBlurImage(_image,geometry_info.rho,
2769 geometry_info.sigma,geometry_info.xi,_exception);
2772 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2776 if (LocaleCompare("negate",option+1) == 0)
2778 (void) NegateImage(_image, plus_alt_op, _exception);
2781 if (LocaleCompare("noise",option+1) == 0)
2791 CLIWandWarnReplaced("-statistic NonPeak");
2792 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1);
2795 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2797 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2800 value=GetImageOption(_image_info,"attenuate");
2801 if (value != (const char *) NULL)
2802 attenuate=StringToDouble(value,(char **) NULL);
2803 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2807 if (LocaleCompare("normalize",option+1) == 0)
2809 (void) NormalizeImage(_image,_exception);
2812 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2816 if (LocaleCompare("opaque",option+1) == 0)
2821 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2822 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,plus_alt_op,
2826 if (LocaleCompare("ordered-dither",option+1) == 0)
2828 (void) OrderedPosterizeImage(_image,arg1,_exception);
2831 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2835 if (LocaleCompare("paint",option+1) == 0)
2837 flags=ParseGeometry(arg1,&geometry_info);
2838 if ((flags & (RhoValue|SigmaValue)) == 0)
2839 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2840 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
2844 if (LocaleCompare("perceptible",option+1) == 0)
2846 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
2850 if (LocaleCompare("polaroid",option+1) == 0)
2862 random_info=AcquireRandomInfo();
2863 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2864 random_info=DestroyRandomInfo(random_info);
2867 flags=ParseGeometry(arg1,&geometry_info);
2868 if ((flags & RhoValue) == 0)
2869 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2870 angle=geometry_info.rho;
2872 caption=GetImageProperty(_image,"caption",_exception);
2873 new_image=PolaroidImage(_image,_draw_info,caption,angle,
2874 _image->interpolate,_exception);
2877 if (LocaleCompare("posterize",option+1) == 0)
2879 flags=ParseGeometry(arg1,&geometry_info);
2880 if ((flags & RhoValue) == 0)
2881 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2882 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
2883 _quantize_info->dither_method,_exception);
2886 if (LocaleCompare("preview",option+1) == 0)
2888 /* FUTURE: should be a 'Genesis' option?
2889 Option however is also in WandSettingOptionInfo()
2892 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
2894 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
2896 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
2899 if (LocaleCompare("profile",option+1) == 0)
2901 /* Note: arguments do not have percent escapes expanded */
2915 { /* Remove a profile from the _image. */
2916 (void) ProfileImage(_image,arg1,(const unsigned char *)
2920 /* Associate a profile with the _image. */
2921 profile_info=CloneImageInfo(_image_info);
2922 profile=GetImageProfile(_image,"iptc");
2923 if (profile != (StringInfo *) NULL)
2924 profile_info->profile=(void *) CloneStringInfo(profile);
2925 profile_image=GetImageCache(profile_info,arg1,_exception);
2926 profile_info=DestroyImageInfo(profile_info);
2927 if (profile_image == (Image *) NULL)
2932 profile_info=CloneImageInfo(_image_info);
2933 (void) CopyMagickString(profile_info->filename,arg1,
2935 profile=FileToStringInfo(profile_info->filename,~0UL,_exception);
2936 if (profile != (StringInfo *) NULL)
2938 (void) ProfileImage(_image,profile_info->magick,
2939 GetStringInfoDatum(profile),(size_t)
2940 GetStringInfoLength(profile),_exception);
2941 profile=DestroyStringInfo(profile);
2943 profile_info=DestroyImageInfo(profile_info);
2946 ResetImageProfileIterator(profile_image);
2947 name=GetNextImageProfile(profile_image);
2948 while (name != (const char *) NULL)
2950 profile=GetImageProfile(profile_image,name);
2951 if (profile != (StringInfo *) NULL)
2952 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
2953 (size_t) GetStringInfoLength(profile),_exception);
2954 name=GetNextImageProfile(profile_image);
2956 profile_image=DestroyImage(profile_image);
2959 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2963 if (LocaleCompare("radial-blur",option+1) == 0)
2965 flags=ParseGeometry(arg1,&geometry_info);
2966 if ((flags & RhoValue) == 0)
2967 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2968 new_image=RadialBlurImage(_image,geometry_info.rho,_exception);
2971 if (LocaleCompare("raise",option+1) == 0)
2973 if (IfMagickFalse(IsGeometry(arg1)))
2974 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2975 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2976 (void) RaiseImage(_image,&geometry,normal_op,_exception);
2979 if (LocaleCompare("random-threshold",option+1) == 0)
2981 if (IfMagickFalse(IsGeometry(arg1)))
2982 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2983 (void) RandomThresholdImage(_image,arg1,_exception);
2986 if (LocaleCompare("recolor",option+1) == 0)
2988 CLIWandWarnReplaced("-color-matrix");
2989 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL);
2991 if (LocaleCompare("remap",option+1) == 0)
2993 /* Note: arguments do not have percent escapes expanded */
2997 remap_image=GetImageCache(_image_info,arg1,_exception);
2998 if (remap_image == (Image *) NULL)
3000 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3001 remap_image=DestroyImage(remap_image);
3004 if (LocaleCompare("repage",option+1) == 0)
3008 if (IfMagickFalse(IsGeometry(arg1)))
3009 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3011 (void) ResetImagePage(_image,arg1);
3014 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3017 if (LocaleCompare("resample",option+1) == 0)
3019 /* FUTURE: Roll into a resize special operation */
3020 flags=ParseGeometry(arg1,&geometry_info);
3021 if ((flags & (RhoValue|SigmaValue)) == 0)
3022 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3023 if ((flags & SigmaValue) == 0)
3024 geometry_info.sigma=geometry_info.rho;
3025 new_image=ResampleImage(_image,geometry_info.rho,
3026 geometry_info.sigma,_image->filter,_exception);
3029 if (LocaleCompare("resize",option+1) == 0)
3031 if (IfMagickFalse(IsGeometry(arg1)))
3032 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3033 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3034 new_image=ResizeImage(_image,geometry.width,geometry.height,
3035 _image->filter,_exception);
3038 if (LocaleCompare("roll",option+1) == 0)
3040 if (IfMagickFalse(IsGeometry(arg1)))
3041 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3042 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
3043 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3046 if (LocaleCompare("rotate",option+1) == 0)
3048 flags=ParseGeometry(arg1,&geometry_info);
3049 if ((flags & RhoValue) == 0)
3050 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3051 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3053 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3055 new_image=RotateImage(_image,geometry_info.rho,_exception);
3058 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3062 if (LocaleCompare("sample",option+1) == 0)
3064 /* FUTURE: Roll into a resize special operator */
3065 if (IfMagickFalse(IsGeometry(arg1)))
3066 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3067 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3068 new_image=SampleImage(_image,geometry.width,geometry.height,
3072 if (LocaleCompare("scale",option+1) == 0)
3074 /* FUTURE: Roll into a resize special operator */
3075 if (IfMagickFalse(IsGeometry(arg1)))
3076 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3077 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3078 new_image=ScaleImage(_image,geometry.width,geometry.height,
3082 if (LocaleCompare("segment",option+1) == 0)
3084 flags=ParseGeometry(arg1,&geometry_info);
3085 if ((flags & (RhoValue|SigmaValue)) == 0)
3086 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3087 if ((flags & SigmaValue) == 0)
3088 geometry_info.sigma=1.0;
3089 (void) SegmentImage(_image,_image->colorspace,
3090 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3094 if (LocaleCompare("selective-blur",option+1) == 0)
3096 flags=ParseGeometry(arg1,&geometry_info);
3097 if ((flags & (RhoValue|SigmaValue)) == 0)
3098 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3099 if ((flags & SigmaValue) == 0)
3100 geometry_info.sigma=1.0;
3101 if ((flags & PercentValue) != 0)
3102 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3103 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3104 geometry_info.sigma,geometry_info.xi,_exception);
3107 if (LocaleCompare("separate",option+1) == 0)
3109 /* WARNING: This can generate multiple images! */
3110 /* FUTURE - this may be replaced by a "-channel" method */
3111 new_image=SeparateImages(_image,_exception);
3114 if (LocaleCompare("sepia-tone",option+1) == 0)
3116 if (IfMagickFalse(IsGeometry(arg1)))
3117 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3118 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3119 (double) QuantumRange+1.0),_exception);
3122 if (LocaleCompare("shade",option+1) == 0)
3124 flags=ParseGeometry(arg1,&geometry_info);
3125 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3126 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3127 new_image=ShadeImage(_image,normal_op,geometry_info.rho,
3128 geometry_info.sigma,_exception);
3131 if (LocaleCompare("shadow",option+1) == 0)
3133 flags=ParseGeometry(arg1,&geometry_info);
3134 if ((flags & (RhoValue|SigmaValue)) == 0)
3135 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3136 if ((flags & SigmaValue) == 0)
3137 geometry_info.sigma=1.0;
3138 if ((flags & XiValue) == 0)
3139 geometry_info.xi=4.0;
3140 if ((flags & PsiValue) == 0)
3141 geometry_info.psi=4.0;
3142 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3143 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3144 ceil(geometry_info.psi-0.5),_exception);
3147 if (LocaleCompare("sharpen",option+1) == 0)
3149 flags=ParseGeometry(arg1,&geometry_info);
3150 if ((flags & (RhoValue|SigmaValue)) == 0)
3151 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3152 if ((flags & SigmaValue) == 0)
3153 geometry_info.sigma=1.0;
3154 if ((flags & XiValue) == 0)
3155 geometry_info.xi=0.0;
3156 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3160 if (LocaleCompare("shave",option+1) == 0)
3162 if (IfMagickFalse(IsGeometry(arg1)))
3163 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3164 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3165 new_image=ShaveImage(_image,&geometry,_exception);
3168 if (LocaleCompare("shear",option+1) == 0)
3170 flags=ParseGeometry(arg1,&geometry_info);
3171 if ((flags & RhoValue) == 0)
3172 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3173 if ((flags & SigmaValue) == 0)
3174 geometry_info.sigma=geometry_info.rho;
3175 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3179 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3181 flags=ParseGeometry(arg1,&geometry_info);
3182 if ((flags & RhoValue) == 0)
3183 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3184 if ((flags & SigmaValue) == 0)
3185 geometry_info.sigma=(double) QuantumRange/2.0;
3186 if ((flags & PercentValue) != 0)
3187 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3189 (void) SigmoidalContrastImage(_image,normal_op,geometry_info.rho,
3190 geometry_info.sigma,_exception);
3193 if (LocaleCompare("sketch",option+1) == 0)
3195 flags=ParseGeometry(arg1,&geometry_info);
3196 if ((flags & (RhoValue|SigmaValue)) == 0)
3197 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3198 if ((flags & SigmaValue) == 0)
3199 geometry_info.sigma=1.0;
3200 new_image=SketchImage(_image,geometry_info.rho,
3201 geometry_info.sigma,geometry_info.xi,_exception);
3204 if (LocaleCompare("solarize",option+1) == 0)
3206 if (IfMagickFalse(IsGeometry(arg1)))
3207 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3208 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3209 QuantumRange+1.0),_exception);
3212 if (LocaleCompare("sparse-color",option+1) == 0)
3214 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3216 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3218 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3222 if (LocaleCompare("splice",option+1) == 0)
3224 if (IfMagickFalse(IsGeometry(arg1)))
3225 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3226 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3227 new_image=SpliceImage(_image,&geometry,_exception);
3230 if (LocaleCompare("spread",option+1) == 0)
3232 flags=ParseGeometry(arg1,&geometry_info);
3233 if ((flags & RhoValue) == 0)
3234 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3235 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate,
3239 if (LocaleCompare("statistic",option+1) == 0)
3241 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3243 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3245 flags=ParseGeometry(arg2,&geometry_info);
3246 if ((flags & RhoValue) == 0)
3247 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3248 if ((flags & SigmaValue) == 0)
3249 geometry_info.sigma=geometry_info.rho;
3250 new_image=StatisticImage(_image,(StatisticType)parse,
3251 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3255 if (LocaleCompare("strip",option+1) == 0)
3257 (void) StripImage(_image,_exception);
3260 if (LocaleCompare("swirl",option+1) == 0)
3262 flags=ParseGeometry(arg1,&geometry_info);
3263 if ((flags & RhoValue) == 0)
3264 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3265 new_image=SwirlImage(_image,geometry_info.rho,
3266 _image->interpolate,_exception);
3269 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3273 if (LocaleCompare("threshold",option+1) == 0)
3278 threshold=(double) QuantumRange/2;
3280 if (IfMagickFalse(IsGeometry(arg1)))
3281 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3282 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3284 (void) BilevelImage(_image,threshold,_exception);
3287 if (LocaleCompare("thumbnail",option+1) == 0)
3289 if (IfMagickFalse(IsGeometry(arg1)))
3290 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3291 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3292 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3296 if (LocaleCompare("tint",option+1) == 0)
3298 if (IfMagickFalse(IsGeometry(arg1)))
3299 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3300 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3303 if (LocaleCompare("transform",option+1) == 0)
3305 CLIWandWarnReplaced("+distort AffineProjection");
3306 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3309 if (LocaleCompare("transparent",option+1) == 0)
3314 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3315 (void) TransparentPaintImage(_image,&target,(Quantum)
3316 TransparentAlpha,plus_alt_op,_exception);
3319 if (LocaleCompare("transpose",option+1) == 0)
3321 new_image=TransposeImage(_image,_exception);
3324 if (LocaleCompare("transverse",option+1) == 0)
3326 new_image=TransverseImage(_image,_exception);
3329 if (LocaleCompare("trim",option+1) == 0)
3331 new_image=TrimImage(_image,_exception);
3334 if (LocaleCompare("type",option+1) == 0)
3336 /* Note that "type" setting should have already been defined */
3337 (void) SetImageType(_image,_image_info->type,_exception);
3340 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3344 if (LocaleCompare("unique",option+1) == 0)
3346 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3347 Option is not documented, bt appears to be for "identify".
3348 We may need a identify specific verbose!
3351 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3354 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3355 (void) SetImageArtifact(_image,"verbose","true");
3358 if (LocaleCompare("unique-colors",option+1) == 0)
3360 new_image=UniqueImageColors(_image,_exception);
3363 if (LocaleCompare("unsharp",option+1) == 0)
3365 flags=ParseGeometry(arg1,&geometry_info);
3366 if ((flags & (RhoValue|SigmaValue)) == 0)
3367 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3368 if ((flags & SigmaValue) == 0)
3369 geometry_info.sigma=1.0;
3370 if ((flags & XiValue) == 0)
3371 geometry_info.xi=1.0;
3372 if ((flags & PsiValue) == 0)
3373 geometry_info.psi=0.05;
3374 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3375 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3378 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3382 if (LocaleCompare("verbose",option+1) == 0)
3384 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3385 three places! ImageArtifact ImageOption _image_info->verbose
3386 Some how new images also get this artifact!
3388 (void) SetImageArtifact(_image,option+1,
3389 IfNormalOp ? "true" : "false" );
3392 if (LocaleCompare("vignette",option+1) == 0)
3394 flags=ParseGeometry(arg1,&geometry_info);
3395 if ((flags & (RhoValue|SigmaValue)) == 0)
3396 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3397 if ((flags & SigmaValue) == 0)
3398 geometry_info.sigma=1.0;
3399 if ((flags & XiValue) == 0)
3400 geometry_info.xi=0.1*_image->columns;
3401 if ((flags & PsiValue) == 0)
3402 geometry_info.psi=0.1*_image->rows;
3403 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3404 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3405 ceil(geometry_info.psi-0.5),_exception);
3408 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3412 if (LocaleCompare("wave",option+1) == 0)
3414 flags=ParseGeometry(arg1,&geometry_info);
3415 if ((flags & (RhoValue|SigmaValue)) == 0)
3416 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3417 if ((flags & SigmaValue) == 0)
3418 geometry_info.sigma=1.0;
3419 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3420 _image->interpolate,_exception);
3423 if (LocaleCompare("white-threshold",option+1) == 0)
3425 if (IfMagickFalse(IsGeometry(arg1)))
3426 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3427 (void) WhiteThresholdImage(_image,arg1,_exception);
3430 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3433 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3435 /* clean up percent escape interpreted strings */
3437 arg1=DestroyString((char *)arg1);
3439 arg2=DestroyString((char *)arg2);
3441 /* Replace current image with any image that was generated
3442 and set image point to last image (so image->next is correct) */
3443 if (new_image != (Image *) NULL)
3444 ReplaceImageInListReturnLast(&_image,new_image);
3449 #undef _quantize_info
3458 WandExport void CLISimpleOperatorImages(MagickCLI *cli_wand,
3459 const char *option, const char *arg1, const char *arg2)
3461 #if !USE_WAND_METHODS
3467 assert(cli_wand != (MagickCLI *) NULL);
3468 assert(cli_wand->signature == WandSignature);
3469 assert(cli_wand->wand.signature == WandSignature);
3470 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3471 if (IfMagickTrue(cli_wand->wand.debug))
3472 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
3474 #if !USE_WAND_METHODS
3475 /* FUTURE add appropriate tracing */
3477 n=GetImageListLength(cli_wand->wand.images);
3478 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3481 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3482 if ( cli_wand->wand.images->next == (Image *) NULL )
3484 cli_wand->wand.images=cli_wand->wand.images->next;
3487 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3489 MagickResetIterator(&cli_wand->wand);
3490 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
3491 CLISimpleOperatorImage(cli_wand, option, arg1, arg2);
3492 MagickResetIterator(&cli_wand->wand);
3498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3502 + C L I L i s t O p e r a t o r I m a g e s %
3506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508 % CLIListOperatorImages() applies a single operation that is apply to the
3509 % entire image list as a whole. The result is often a complete replacment
3510 % of the image list with a completely new list, or with just a single image
3513 % The format of the MogrifyImage method is:
3515 % void CLIListOperatorImages(MagickCLI *cli_wand,
3516 % const char *option, const char *arg1, const char *arg2)
3518 % A description of each parameter follows:
3520 % o cli_wand: structure holding settings to be applied
3522 % o option: The option string for the operation
3524 % o arg1, arg2: optional argument strings to the operation
3525 % arg2 is currently not used
3528 WandExport void CLIListOperatorImages(MagickCLI *cli_wand,
3529 const char *option,const char *arg1n, const char *arg2n)
3537 const char /* For percent escape interpretImageProperties() */
3541 #define _image_info (cli_wand->wand.image_info)
3542 #define _images (cli_wand->wand.images)
3543 #define _exception (cli_wand->wand.exception)
3544 #define _draw_info (cli_wand->draw_info)
3545 #define _quantize_info (cli_wand->quantize_info)
3546 #define _process_flags (cli_wand->process_flags)
3547 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3548 #define IfNormalOp (*option=='-')
3549 #define IfPlusOp (*option!='-')
3550 #define normal_op IsMagickTrue(IfNormalOp)
3552 assert(cli_wand != (MagickCLI *) NULL);
3553 assert(cli_wand->signature == WandSignature);
3554 assert(cli_wand->wand.signature == WandSignature);
3555 assert(_images != (Image *) NULL); /* _images must be present */
3556 if (IfMagickTrue(cli_wand->wand.debug))
3557 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
3559 /* Interpret Percent Escapes in Arguments - using first image */
3562 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
3563 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3564 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3565 /* Interpret Percent escapes in argument 1 */
3566 if (arg1n != (char *) NULL) {
3567 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3568 if (arg1 == (char *) NULL) {
3569 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3570 arg1=arg1n; /* use the given argument as is */
3573 if (arg2n != (char *) NULL) {
3574 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3575 if (arg2 == (char *) NULL) {
3576 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3577 arg2=arg2n; /* use the given argument as is */
3581 #undef _process_flags
3585 (void) FormatLocaleFile(stderr,
3586 "CLIListOperatorImages: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
3590 new_images=NewImageList();
3592 switch (*(option+1))
3596 if (LocaleCompare("append",option+1) == 0)
3598 new_images=AppendImages(_images,normal_op,_exception);
3601 if (LocaleCompare("average",option+1) == 0)
3603 CLIWandWarnReplaced("-evaluate-sequence Mean");
3604 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL);
3607 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3611 if (LocaleCompare("channel-fx",option+1) == 0)
3613 new_images=ChannelFxImage(_images,arg1,_exception);
3616 if (LocaleCompare("clut",option+1) == 0)
3621 /* FUTURE - make this a compose option, and thus can be used
3622 with layers compose or even compose last image over all other
3625 new_images=RemoveFirstImageFromList(&_images);
3626 clut_image=RemoveLastImageFromList(&_images);
3627 /* FUTURE - produce Exception, rather than silent fail */
3628 if (clut_image == (Image *) NULL)
3630 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception);
3631 clut_image=DestroyImage(clut_image);
3634 if (LocaleCompare("coalesce",option+1) == 0)
3636 new_images=CoalesceImages(_images,_exception);
3639 if (LocaleCompare("combine",option+1) == 0)
3641 /* FUTURE - this may be replaced by a 'channel' method */
3642 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3643 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3646 if (LocaleCompare("composite",option+1) == 0)
3664 /* Compose value from "-compose" option only */
3665 value=GetImageOption(_image_info,"compose");
3666 if (value == (const char *) NULL)
3667 compose=OverCompositeOp; /* use Over not source_image->compose */
3669 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3672 /* Get "clip-to-self" expert setting (false is normal) */
3673 value=GetImageOption(_image_info,"compose:clip-to-self");
3674 if (value == (const char *) NULL)
3675 clip_to_self=MagickTrue;
3677 clip_to_self=IsStringTrue(GetImageOption(_image_info,
3678 "compose:clip-to-self")); /* if this is true */
3679 value=GetImageOption(_image_info,"compose:outside-overlay");
3680 if (value != (const char *) NULL) { /* or this false */
3681 /* FUTURE: depreciate warning for "compose:outside-overlay"*/
3682 clip_to_self= IsMagickFalse(IsStringNotFalse(value));
3685 new_images=RemoveFirstImageFromList(&_images);
3686 source_image=RemoveFirstImageFromList(&_images);
3687 if (source_image == (Image *) NULL)
3688 break; /* FUTURE - produce Exception, rather than silent fail */
3690 /* FUTURE - this should not be here! - should be part of -geometry */
3691 (void) TransformImage(&source_image,(char *) NULL,
3692 source_image->geometry,_exception);
3694 SetGeometry(source_image,&geometry);
3695 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3696 GravityAdjustGeometry(new_images->columns,new_images->rows,
3697 new_images->gravity, &geometry);
3699 mask_image=RemoveFirstImageFromList(&_images);
3700 if (mask_image != (Image *) NULL)
3701 { /* handle a third write mask image */
3702 if ((compose == DisplaceCompositeOp) ||
3703 (compose == DistortCompositeOp)) {
3704 /* Merge Y displacement into X displace/distort map. */
3705 (void) CompositeImage(source_image,mask_image,
3706 CopyGreenCompositeOp,MagickTrue,0,0,_exception);
3707 mask_image=DestroyImage(mask_image);
3710 /* Set a blending mask for the composition. */
3711 (void) NegateImage(mask_image,MagickFalse,_exception);
3712 (void) SetImageMask(source_image,mask_image,_exception);
3713 mask_image=DestroyImage(mask_image);
3716 (void) CompositeImage(new_images,source_image,compose,clip_to_self,
3717 geometry.x,geometry.y,_exception);
3718 (void) SetImageMask(new_images,(Image *) NULL,_exception);
3719 source_image=DestroyImage(source_image);
3722 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3726 if (LocaleCompare("deconstruct",option+1) == 0)
3728 CLIWandWarnReplaced("-layer CompareAny");
3729 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL);
3732 if (LocaleCompare("delete",option+1) == 0)
3735 DeleteImages(&_images,arg1,_exception);
3737 DeleteImages(&_images,"-1",_exception);
3740 if (LocaleCompare("duplicate",option+1) == 0)
3750 if (IfMagickFalse(IsGeometry(arg1)))
3751 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3753 number_duplicates=(size_t) StringToLong(arg1);
3755 if (p == (const char *) NULL)
3756 new_images=DuplicateImages(_images,number_duplicates,"-1",
3759 new_images=DuplicateImages(_images,number_duplicates,p,
3763 new_images=DuplicateImages(_images,1,"-1",_exception);
3764 AppendImageToList(&_images, new_images);
3765 new_images=(Image *)NULL;
3768 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3772 if (LocaleCompare("evaluate-sequence",option+1) == 0)
3774 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
3776 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
3778 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse,
3782 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3786 if (LocaleCompare("fft",option+1) == 0)
3788 new_images=ForwardFourierTransformImage(_images,normal_op,_exception);
3791 if (LocaleCompare("flatten",option+1) == 0)
3793 /* REDIRECTED to use -layers flatten instead */
3794 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
3797 if (LocaleCompare("fx",option+1) == 0)
3799 new_images=FxImage(_images,arg1,_exception);
3802 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3806 if (LocaleCompare("hald-clut",option+1) == 0)
3808 /* FUTURE - make this a compose option (and thus layers compose )
3809 or perhaps compose last image over all other _images.
3814 new_images=RemoveFirstImageFromList(&_images);
3815 hald_image=RemoveLastImageFromList(&_images);
3816 if (hald_image == (Image *) NULL)
3818 (void) HaldClutImage(new_images,hald_image,_exception);
3819 hald_image=DestroyImage(hald_image);
3822 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3826 if (LocaleCompare("ift",option+1) == 0)
3832 magnitude_image=RemoveFirstImageFromList(&_images);
3833 phase_image=RemoveFirstImageFromList(&_images);
3834 /* FUTURE - produce Exception, rather than silent fail */
3835 if (phase_image == (Image *) NULL)
3837 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3838 normal_op,_exception);
3839 magnitude_image=DestroyImage(magnitude_image);
3840 phase_image=DestroyImage(phase_image);
3843 if (LocaleCompare("insert",option+1) == 0)
3852 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1)))
3853 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3855 insert_image=RemoveLastImageFromList(&_images);
3857 index=(ssize_t) StringToLong(arg1);
3858 index_image=insert_image;
3860 PrependImageToList(&_images,insert_image);
3861 else if (index == (ssize_t) GetImageListLength(_images))
3862 AppendImageToList(&_images,insert_image);
3865 index_image=GetImageFromList(_images,index-1);
3866 if (index_image == (Image *) NULL)
3867 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
3868 InsertImageInList(&index_image,insert_image);
3870 _images=GetFirstImageInList(index_image);
3873 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3877 if (LocaleCompare("layers",option+1) == 0)
3879 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
3881 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
3883 switch ((LayerMethod) parse)
3887 new_images=CoalesceImages(_images,_exception);
3890 case CompareAnyLayer:
3891 case CompareClearLayer:
3892 case CompareOverlayLayer:
3895 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
3902 case TrimBoundsLayer:
3904 new_images=MergeImageLayers(_images,(LayerMethod) parse,
3910 new_images=DisposeImages(_images,_exception);
3913 case OptimizeImageLayer:
3915 new_images=OptimizeImageLayers(_images,_exception);
3918 case OptimizePlusLayer:
3920 new_images=OptimizePlusImageLayers(_images,_exception);
3923 case OptimizeTransLayer:
3925 OptimizeImageTransparency(_images,_exception);
3928 case RemoveDupsLayer:
3930 RemoveDuplicateLayers(&_images,_exception);
3933 case RemoveZeroLayer:
3935 RemoveZeroDelayLayers(&_images,_exception);
3939 { /* General Purpose, GIF Animation Optimizer. */
3940 new_images=CoalesceImages(_images,_exception);
3941 if (new_images == (Image *) NULL)
3943 _images=DestroyImageList(_images);
3944 _images=OptimizeImageLayers(new_images,_exception);
3945 if (_images == (Image *) NULL)
3947 new_images=DestroyImageList(new_images);
3948 OptimizeImageTransparency(_images,_exception);
3949 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
3953 case CompositeLayer:
3967 value=GetImageOption(_image_info,"compose");
3968 compose=OverCompositeOp; /* Default to Over */
3969 if (value != (const char *) NULL)
3970 compose=(CompositeOperator) ParseCommandOption(
3971 MagickComposeOptions,MagickFalse,value);
3973 /* Split image sequence at the first 'NULL:' image. */
3975 while (source != (Image *) NULL)
3977 source=GetNextImageInList(source);
3978 if ((source != (Image *) NULL) &&
3979 (LocaleCompare(source->magick,"NULL") == 0))
3982 if (source != (Image *) NULL)
3984 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
3985 (GetNextImageInList(source) == (Image *) NULL))
3986 source=(Image *) NULL;
3988 { /* Separate the two lists, junk the null: image. */
3989 source=SplitImageList(source->previous);
3990 DeleteImageFromList(&source);
3993 if (source == (Image *) NULL)
3995 (void) ThrowMagickException(_exception,GetMagickModule(),
3996 OptionError,"MissingNullSeparator","layers Composite");
3999 /* Adjust offset with gravity and virtual canvas. */
4000 SetGeometry(_images,&geometry);
4001 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4002 geometry.width=source->page.width != 0 ?
4003 source->page.width : source->columns;
4004 geometry.height=source->page.height != 0 ?
4005 source->page.height : source->rows;
4006 GravityAdjustGeometry(_images->page.width != 0 ?
4007 _images->page.width : _images->columns,
4008 _images->page.height != 0 ? _images->page.height :
4009 _images->rows,_images->gravity,&geometry);
4011 /* Compose the two image sequences together */
4012 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4014 source=DestroyImageList(source);
4020 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4024 if (LocaleCompare("map",option+1) == 0)
4026 CLIWandWarnReplaced("+remap");
4027 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4030 if (LocaleCompare("morph",option+1) == 0)
4035 if (IfMagickFalse(IsGeometry(arg1)))
4036 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4037 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4039 if (morph_image == (Image *) NULL)
4041 _images=DestroyImageList(_images);
4042 _images=morph_image;
4045 if (LocaleCompare("mosaic",option+1) == 0)
4047 /* REDIRECTED to use -layers mosaic instead */
4048 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4051 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4055 if (LocaleCompare("poly",option+1) == 0)
4063 /* convert argument string into an array of doubles */
4064 args = StringToArrayOfDoubles(arg2,&count,_exception);
4065 if (args == (double *)NULL )
4066 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
4067 new_images=PolynomialImage(_images,count >> 1,args,_exception);
4068 args=(double *) RelinquishMagickMemory(args);
4071 if (LocaleCompare("print",option+1) == 0)
4073 (void) FormatLocaleFile(stdout,"%s",arg1);
4076 if (LocaleCompare("process",option+1) == 0)
4078 /* FUTURE: better parsing using ScriptToken() from string ??? */
4086 arguments=StringToArgv(arg1,&number_arguments);
4087 if (arguments == (char **) NULL)
4089 if (strchr(arguments[1],'=') != (char *) NULL)
4110 Support old style syntax, filter="-option arg1".
4112 length=strlen(arg1);
4113 token=(char *) NULL;
4114 if (~length >= (MaxTextExtent-1))
4115 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4117 if (token == (char *) NULL)
4121 token_info=AcquireTokenInfo();
4122 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4123 "\"",'\0',&breaker,&next,"e);
4124 token_info=DestroyTokenInfo(token_info);
4130 argv=(&(arguments[next]));
4131 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4134 token=DestroyString(token);
4137 (void) SubstituteString(&arguments[1],"-","");
4138 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4139 number_arguments-2,(const char **) arguments+2,_exception);
4140 for (j=0; j < number_arguments; j++)
4141 arguments[j]=DestroyString(arguments[j]);
4142 arguments=(char **) RelinquishMagickMemory(arguments);
4145 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4149 if (LocaleCompare("remap",option+1) == 0)
4151 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4154 if (LocaleCompare("reverse",option+1) == 0)
4156 ReverseImageList(&_images);
4159 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4163 if (LocaleCompare("smush",option+1) == 0)
4165 /* FUTURE: this option needs more work to make better */
4169 if (IfMagickFalse(IsGeometry(arg1)))
4170 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4171 offset=(ssize_t) StringToLong(arg1);
4172 new_images=SmushImages(_images,normal_op,offset,_exception);
4175 if (LocaleCompare("subimage",option+1) == 0)
4193 base_image=GetImageFromList(_images,0);
4194 compare_image=GetImageFromList(_images,1);
4196 /* Comparision Metric */
4197 metric=UndefinedMetric;
4198 value=GetImageOption(_image_info,"metric");
4199 if (value != (const char *) NULL)
4200 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4203 new_images=SimilarityImage(base_image,compare_image,metric,
4204 &offset,&similarity,_exception);
4206 if ( new_images != (Image *)NULL ) {
4208 result[MaxTextExtent];
4210 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity);
4211 (void) SetImageProperty(new_images,"subimage:similarity",result,
4213 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4215 (void) SetImageProperty(new_images,"subimage:x",result,
4217 (void) FormatLocaleString(result,MaxTextExtent,"%+ld",
4219 (void) SetImageProperty(new_images,"subimage:y",result,
4221 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld",
4222 (unsigned long) offset.width,(unsigned long) offset.height,
4223 (long) offset.x,(long) offset.y);
4224 (void) SetImageProperty(new_images,"subimage:offset",result,
4229 if (LocaleCompare("swap",option+1) == 0) {
4249 flags=ParseGeometry(arg1,&geometry_info);
4250 if ((flags & RhoValue) != 0)
4251 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4252 index=(ssize_t) geometry_info.rho;
4253 if ((flags & SigmaValue) != 0)
4254 swap_index=(ssize_t) geometry_info.sigma;
4256 p=GetImageFromList(_images,index);
4257 q=GetImageFromList(_images,swap_index);
4258 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4260 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4262 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4265 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4266 swap=CloneImage(p,0,0,MagickTrue,_exception);
4267 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4268 ReplaceImageInList(&q,swap);
4269 _images=GetFirstImageInList(q);
4272 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4275 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4278 /* clean up percent escape interpreted strings */
4280 arg1=DestroyString((char *)arg1);
4282 arg2=DestroyString((char *)arg2);
4284 /* if new image list generated, replace existing image list */
4285 if (new_images == (Image *) NULL)
4287 _images=DestroyImageList(_images);
4288 _images=GetFirstImageInList(new_images);
4295 #undef _quantize_info
4302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4306 + C L I N o I m a g e O p e r a t i o n s %
4310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312 % CLINoImageOperator() Applies operations that may not actually need images
4315 % The classic operators of this type is "-read", which actually creates
4316 % images even when no images are present. Or image stack operators, which
4317 % can be applied (push or pop) to an empty image list.
4319 % Note that these operators may involve other special 'option' prefix
4320 % characters other than '-' or '+', namely parenthesis and braces.
4322 % The format of the CLINoImageOption method is:
4324 % void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4325 % const char *arg1, const char *arg2)
4327 % A description of each parameter follows:
4329 % o cli_wand: the main CLI Wand to use. (sometimes not required)
4331 % o option: The special option (with any switch char) to process
4333 % o arg1 & arg2: Argument for option, if required
4334 % Currently arg2 is not used.
4337 WandExport void CLINoImageOperator(MagickCLI *cli_wand,
4338 const char *option, const char *arg1, const char *arg2)
4341 const char /* For percent escape interpretImageProperties() */
4346 #define _image_info (cli_wand->wand.image_info)
4347 #define _images (cli_wand->wand.images)
4348 #define _exception (cli_wand->wand.exception)
4349 #define IfNormalOp (*option=='-')
4350 #define IfPlusOp (*option!='-')
4352 assert(cli_wand != (MagickCLI *) NULL);
4353 assert(cli_wand->signature == WandSignature);
4354 assert(cli_wand->wand.signature == WandSignature);
4355 if (IfMagickTrue(cli_wand->wand.debug))
4356 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4359 Not able to be used as their may not be any images!
4360 Also the only option that may have arguments that can be percent escaped is
4363 #define _process_flags (cli_wand->process_flags)
4364 #define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4365 /* Interpret Percent Escapes in Arguments - using first image */
4368 if ( (((_process_flags & ProcessInterpretProperities) != 0 )
4369 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4370 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4371 /* Interpret Percent escapes in argument 1 */
4372 if (arg1n != (char *) NULL) {
4373 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4374 if (arg1 == (char *) NULL) {
4375 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4376 arg1=arg1n; /* use the given argument as is */
4379 if (arg2n != (char *) NULL) {
4380 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4381 if (arg2 == (char *) NULL) {
4382 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4383 arg2=arg2n; /* use the given argument as is */
4387 #undef _process_flags
4391 do { /* break to exit code */
4393 No-op options (ignore these)
4395 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4397 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4399 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4401 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4403 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4408 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4409 ( LocaleCompare("--",option) == 0 ) ) {
4410 /* Do Glob filename Expansion for 'arg1' then read all images.
4412 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring
4413 * (but attaching to the filenames in the generated argument list) any
4414 * [...] read modifiers that may be present.
4416 * For example: It will expand '*.gif[20x20]' into a list such as
4417 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]'
4419 * NOTE: In IMv6 this was done globally across all images. This
4420 * meant you could include IM options in '@filename' lists, but you
4421 * could not include comments. Doing it only for image read makes
4422 * it far more secure.
4424 * Note: arguments do not have percent escapes expanded for security
4432 argv = (char **) &arg1;
4434 /* Expand 'glob' expressions in the given filename.
4435 Expansion handles any 'coder:' prefix, or read modifiers attached
4436 to the filename, including them in the resulting expanded list.
4438 if (IfMagickFalse( ExpandFilenames(&argc,&argv) ))
4439 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4440 option,GetExceptionMessage(errno));
4442 /* loop over expanded filename list, and read then all in */
4443 for (i=0; i<argc; i++) {
4446 if (IfMagickTrue(_image_info->ping))
4447 new_images=PingImages(_image_info,argv[i],_exception);
4449 new_images=ReadImages(_image_info,argv[i],_exception);
4450 AppendImageToList(&_images, new_images);
4452 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */
4457 Note: Writing a empty image list is valid in specific cases
4459 if (LocaleCompare("write",option+1) == 0) {
4460 /* Note: arguments do not have percent escapes expanded */
4470 /* Need images, unless a "null:" output coder is used */
4471 if ( cli_wand->wand.images == (Image *) NULL ) {
4472 if ( LocaleCompare(arg1,"null:") == 0 )
4474 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4477 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
4478 (void) DeleteImageRegistry(key);
4479 write_images=_images;
4481 write_images=CloneImageList(_images,_exception);
4482 write_info=CloneImageInfo(_image_info);
4483 (void) WriteImages(write_info,write_images,arg1,_exception);
4484 write_info=DestroyImageInfo(write_info);
4486 write_images=DestroyImageList(write_images);
4490 Parenthesis and Brace operations
4492 if (LocaleCompare("(",option) == 0) {
4493 /* stack 'push' images */
4501 node=cli_wand->image_list_stack;
4502 for ( ; node != (Stack *)NULL; node=node->next)
4504 if ( size >= MAX_STACK_DEPTH )
4505 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4506 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4507 if (node == (Stack *) NULL)
4508 CLIWandExceptionBreak(ResourceLimitFatalError,
4509 "MemoryAllocationFailed",option);
4510 node->data = (void *)cli_wand->wand.images;
4511 cli_wand->wand.images = NewImageList();
4512 node->next = cli_wand->image_list_stack;
4513 cli_wand->image_list_stack = node;
4515 /* handle respect-parenthesis */
4516 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info,
4517 "respect-parenthesis"))))
4518 option="{"; /* fall-thru so as to push image settings too */
4521 /* fall thru to next if */
4523 if (LocaleCompare("{",option) == 0) {
4524 /* stack 'push' of image_info settings */
4532 node=cli_wand->image_info_stack;
4533 for ( ; node != (Stack *)NULL; node=node->next)
4535 if ( size >= MAX_STACK_DEPTH )
4536 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
4537 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4538 if (node == (Stack *) NULL)
4539 CLIWandExceptionBreak(ResourceLimitFatalError,
4540 "MemoryAllocationFailed",option);
4542 node->data = (void *)cli_wand->wand.image_info;
4543 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4544 if (cli_wand->wand.image_info == (ImageInfo *)NULL) {
4545 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
4547 cli_wand->wand.image_info = (ImageInfo *)node->data;
4548 node = (Stack *)RelinquishMagickMemory(node);
4552 node->next = cli_wand->image_info_stack;
4553 cli_wand->image_info_stack = node;
4557 if (LocaleCompare(")",option) == 0) {
4558 /* pop images from stack */
4562 node = (Stack *)cli_wand->image_list_stack;
4563 if ( node == (Stack *)NULL)
4564 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
4565 cli_wand->image_list_stack = node->next;
4567 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4568 cli_wand->wand.images= (Image *)node->data;
4569 node = (Stack *)RelinquishMagickMemory(node);
4571 /* handle respect-parenthesis - of the previous 'pushed' settings */
4572 node = cli_wand->image_info_stack;
4573 if ( node != (Stack *)NULL)
4575 if (IfMagickTrue(IsStringTrue(GetImageOption(
4576 cli_wand->wand.image_info,"respect-parenthesis"))))
4577 option="}"; /* fall-thru so as to pop image settings too */
4583 /* fall thru to next if */
4585 if (LocaleCompare("}",option) == 0) {
4586 /* pop image_info settings from stack */
4590 node = (Stack *)cli_wand->image_info_stack;
4591 if ( node == (Stack *)NULL)
4592 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
4593 cli_wand->image_info_stack = node->next;
4595 (void) DestroyImageInfo(cli_wand->wand.image_info);
4596 cli_wand->wand.image_info = (ImageInfo *)node->data;
4597 node = (Stack *)RelinquishMagickMemory(node);
4599 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4600 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4601 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4605 if (LocaleCompare("set",option+1) == 0)
4607 /* Note: arguments are not percent escapes expanded yet */
4608 /* Some settings are applied to each image in memory in turn.
4609 While others only need to be applied once globally.
4614 if (LocaleNCompare(arg1,"registry:",9) == 0)
4618 (void) DeleteImageRegistry(arg1+9);
4621 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4622 if (value == (char *) NULL)
4623 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4625 (void) SetImageRegistry(StringRegistryType,arg1+9,value,_exception);
4626 value=DestroyString(value);
4629 if (LocaleNCompare(arg1,"option:",7) == 0)
4631 /* delete equivelent artifact from all images (if any) */
4632 MagickResetIterator(&cli_wand->wand);
4633 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4634 (void) DeleteImageArtifact(_images,arg1+7);
4635 MagickResetIterator(&cli_wand->wand);
4636 /* now set/delete the global option as needed */
4638 (void) DeleteImageOption(_image_info,arg1+7);
4641 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4642 if (value == (char *) NULL)
4643 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4645 (void) SetImageOption(_image_info,arg1+7,value);
4646 value=DestroyString(value);
4649 if ( cli_wand->wand.images == (Image *) NULL )
4650 CLIWandExceptArgBreak(OptionError,"NoImagesFound",option,arg1);
4651 MagickResetIterator(&cli_wand->wand);
4652 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) )
4655 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4656 (void) DeleteImageArtifact(_images,arg1+9);
4657 else if (LocaleNCompare(arg1,"property:",9) == 0)
4658 (void) DeleteImageProperty(_images,arg1+9);
4660 (void) DeleteImageProperty(_images,arg1);
4663 value=InterpretImageProperties(_image_info,_images,arg2,_exception);
4664 if (value == (char *) NULL)
4665 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
4667 if (LocaleNCompare(arg1,"artifact:",9) == 0)
4668 (void) SetImageArtifact(_images,arg1+9,value);
4669 else if (LocaleNCompare(arg1,"property:",9) == 0)
4670 (void) SetImageProperty(_images,arg1+9,value,_exception);
4672 (void) SetImageProperty(_images,arg1,value,_exception);
4673 value=DestroyString(value);
4676 MagickResetIterator(&cli_wand->wand);
4679 if (LocaleCompare("clone",option+1) == 0) {
4685 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse)))
4686 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4687 if ( cli_wand->image_list_stack == (Stack *)NULL)
4688 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4689 new_images = (Image *)cli_wand->image_list_stack->data;
4690 if (new_images == (Image *) NULL)
4691 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
4692 new_images=CloneImages(new_images,arg1,_exception);
4693 if (new_images == (Image *) NULL)
4694 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
4695 AppendImageToList(&_images,new_images);
4699 Informational Operations
4701 Note that these do not require either a cli-wand or images!
4702 Though currently a cli-wand much be provided regardless.
4704 if (LocaleCompare("version",option+1) == 0) {
4705 (void) FormatLocaleFile(stdout,"Version: %s\n",
4706 GetMagickVersion((size_t *) NULL));
4707 (void) FormatLocaleFile(stdout,"Copyright: %s\n",
4708 GetMagickCopyright());
4709 (void) FormatLocaleFile(stdout,"Features: %s\n\n",
4710 GetMagickFeatures());
4713 if (LocaleCompare("list",option+1) == 0) {
4715 FUTURE: This 'switch' should really be part of MagickCore
4720 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
4722 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
4727 case MagickCoderOptions:
4729 (void) ListCoderInfo((FILE *) NULL,_exception);
4732 case MagickColorOptions:
4734 (void) ListColorInfo((FILE *) NULL,_exception);
4737 case MagickConfigureOptions:
4739 (void) ListConfigureInfo((FILE *) NULL,_exception);
4742 case MagickDelegateOptions:
4744 (void) ListDelegateInfo((FILE *) NULL,_exception);
4747 case MagickFontOptions:
4749 (void) ListTypeInfo((FILE *) NULL,_exception);
4752 case MagickFormatOptions:
4753 (void) ListMagickInfo((FILE *) NULL,_exception);
4755 case MagickLocaleOptions:
4756 (void) ListLocaleInfo((FILE *) NULL,_exception);
4758 case MagickLogOptions:
4759 (void) ListLogInfo((FILE *) NULL,_exception);
4761 case MagickMagicOptions:
4762 (void) ListMagicInfo((FILE *) NULL,_exception);
4764 case MagickMimeOptions:
4765 (void) ListMimeInfo((FILE *) NULL,_exception);
4767 case MagickModuleOptions:
4768 (void) ListModuleInfo((FILE *) NULL,_exception);
4770 case MagickPolicyOptions:
4771 (void) ListPolicyInfo((FILE *) NULL,_exception);
4773 case MagickResourceOptions:
4774 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
4776 case MagickThresholdOptions:
4777 (void) ListThresholdMaps((FILE *) NULL,_exception);
4780 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4787 CLIWandException(OptionError,"UnrecognizedOption",option);
4789 } while (0); /* break to exit code. */
4792 /* clean up percent escape interpreted strings */
4794 arg1=DestroyString((char *)arg1);
4796 arg2=DestroyString((char *)arg2);
4807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4811 + C L I O p t i o n %
4815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4817 % CLIOption() Processes the given option using the given CLI Magick Wand.
4818 % The option arguments can be variable in number, though at this time no more
4819 % that two is actually used by any option (this may change). Excess options
4820 % are simply ignored.
4822 % If the cli_wand->command pointer is non-null, then it is assumed that the
4823 % option has already been search for up from the CommandOptions[] table in
4824 % "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
4825 % routine will do the lookup instead. The pointer is reset afterward.
4827 % This action allows the caller to lookup and pre-handle any 'special'
4828 % options, (such as implicit reads) before calling this general option
4829 % handler to deal with 'standard' command line options.
4831 % The format of the CLIOption method is:
4833 % void CLIOption(MagickCLI *cli_wand,const char *option, ...)
4835 % A description of each parameter follows:
4837 % o cli_wand: the main CLI Wand to use.
4839 % o option: The special option (with any switch char) to process
4841 % o args: any required arguments for an option (variable number)
4845 % CLIoption(cli_wand,"-read","rose:");
4846 % CLIoption(cli_wand,"-virtual-pixel","transparent");
4847 % CLIoption(cli_wand,"-distort","SRT:","30");
4848 % CLIoption(cli_wand,"-write","rotated_rose.png");
4851 WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
4860 assert(cli_wand != (MagickCLI *) NULL);
4861 assert(cli_wand->signature == WandSignature);
4862 assert(cli_wand->wand.signature == WandSignature);
4863 if (IfMagickTrue(cli_wand->wand.debug))
4864 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4866 do { /* Break Code Block for error handling */
4868 /* get information about option */
4869 if ( cli_wand->command == (const OptionInfo *) NULL )
4870 cli_wand->command = GetCommandOptionInfo(option);
4872 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
4873 option, cli_wand->command->mnemonic );
4875 option_type=(CommandOptionFlags) cli_wand->command->flags;
4877 if ( option_type == UndefinedOptionFlag )
4878 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
4880 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
4882 /* depreciated options */
4883 if ( (option_type & DeprecateOptionFlag) != 0 )
4884 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
4886 /* options that this module does not handle */
4887 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
4888 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
4890 /* Get argument strings from VarArgs
4891 How can you determine arguments is enough was supplied? */
4893 count = cli_wand->command->type;
4898 va_start(operands,option);
4902 arg1=(const char *) va_arg(operands, const char *);
4904 arg2=(const char *) va_arg(operands, const char *);
4909 (void) FormatLocaleFile(stderr,
4910 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
4911 option,(long) count,option_type,arg1,arg2);
4916 Call the appropriate option handler
4919 /* FUTURE: this is temporary - get 'settings' to handle distribution of
4920 settings to images attributes,proprieties,artifacts */
4921 if ( cli_wand->wand.images != (Image *)NULL )
4922 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
4923 cli_wand->wand.exception);
4925 if ( (option_type & SettingOptionFlags) != 0 ) {
4926 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
4927 // FUTURE: Sync Specific Settings into Image Properities (not global)
4930 /* Operators that do not need images - read, write, stack, clone */
4931 if ( (option_type & NoImageOperatorFlag) != 0)
4932 CLINoImageOperator(cli_wand, option, arg1, arg2);
4934 /* FUTURE: The not a setting part below is a temporary hack due to
4935 * some options being both a Setting and a Simple operator.
4936 * Specifically -monitor, -depth, and -colorspace */
4937 if ( cli_wand->wand.images == (Image *)NULL )
4938 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
4939 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
4940 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
4942 /* Operators work on single images, and needs a loop over the images */
4943 if ( (option_type & SimpleOperatorFlag) != 0)
4944 CLISimpleOperatorImages(cli_wand, option, arg1, arg2);
4946 /* Operators that work on the image list as a whole */
4947 if ( (option_type & ListOperatorFlag) != 0 )
4948 CLIListOperatorImages(cli_wand, option, arg1, arg2);
4950 } while (0); /* end Break code block */
4952 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */