operation.c revision fe676ee3a9cf43404bdc9ba8b27f597b5e4e28f7
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 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 % 11% % 12% % 13% CLI Magick Option Methods % 14% % 15% Dragon Computing % 16% Anthony Thyssen % 17% September 2011 % 18% % 19% % 20% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 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. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 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. 39% 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 42% IMv7. 43% 44% Anthony Thyssen, September 2011 45*/ 46 47/* 48 Include declarations. 49*/ 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" 61 62/* 63 Define declarations. 64*/ 65#define USE_WAND_METHODS 1 66#define MAX_STACK_DEPTH 32 67#define UNDEFINED_COMPRESSION_QUALITY 0UL 68 69/* FUTURE: why is this default so specific? */ 70#define DEFAULT_DISSIMILARITY_THRESHOLD "0.31830988618379067154" 71 72/* 73 Constant declaration. (temporary exports) 74*/ 75static const char 76 BackgroundColor[] = "#fff", /* white */ 77 BorderColor[] = "#dfdfdf", /* sRGB gray */ 78 MatteColor[] = "#bdbdbd"; /* slightly darker gray */ 79 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 ) 84 85/* 86** Function to report on the progress of image operations 87*/ 88static MagickBooleanType MonitorProgress(const char *text, 89 const MagickOffsetType offset,const MagickSizeType extent, 90 void *wand_unused(cli_wandent_data)) 91{ 92 char 93 message[MaxTextExtent], 94 tag[MaxTextExtent]; 95 96 const char 97 *locale_message; 98 99 register char 100 *p; 101 102 if (extent < 2) 103 return(MagickTrue); 104 (void) CopyMagickMemory(tag,text,MaxTextExtent); 105 p=strrchr(tag,'/'); 106 if (p != (char *) NULL) 107 *p='\0'; 108 (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag); 109 locale_message=GetLocaleMessage(message); 110 if (locale_message == message) 111 locale_message=tag; 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))); 116 else 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); 123 return(MagickTrue); 124} 125 126/* 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. 129*/ 130static inline Image *GetImageCache(const ImageInfo *image_info,const char *path, 131 ExceptionInfo *exception) 132{ 133 char 134 key[MaxTextExtent]; 135 136 ExceptionInfo 137 *sans_exception; 138 139 Image 140 *image; 141 142 ImageInfo 143 *read_info; 144 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) 150 return(image); 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); 157 return(image); 158} 159 160/* 161 SparseColorOption() parse the complex -sparse-color argument into an 162 an array of floating point values than call SparseColorImage(). 163 Argument is a complex mix of floating-point pixel coodinates, and color 164 specifications (or direct floating point numbers). The number of floats 165 needed to represent a color varies depending on the current channel 166 setting. 167 168 This really should be in MagickCore, so that other API's can make use of it. 169*/ 170static Image *SparseColorOption(const Image *image, 171 const SparseColorMethod method,const char *arguments,ExceptionInfo *exception) 172{ 173 char 174 token[MaxTextExtent]; 175 176 const char 177 *p; 178 179 double 180 *sparse_arguments; 181 182 Image 183 *sparse_image; 184 185 PixelInfo 186 color; 187 188 MagickBooleanType 189 error; 190 191 register size_t 192 x; 193 194 size_t 195 number_arguments, 196 number_colors; 197 198 assert(image != (Image *) NULL); 199 assert(image->signature == MagickSignature); 200 if (IfMagickTrue(image->debug)) 201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 202 assert(exception != (ExceptionInfo *) NULL); 203 assert(exception->signature == MagickSignature); 204 /* 205 Limit channels according to image 206 add up number of values needed per color. 207 */ 208 number_colors=0; 209 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 210 number_colors++; 211 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 212 number_colors++; 213 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 214 number_colors++; 215 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 216 (image->colorspace == CMYKColorspace)) 217 number_colors++; 218 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 219 image->alpha_trait == BlendPixelTrait) 220 number_colors++; 221 222 /* 223 Read string, to determine number of arguments needed, 224 */ 225 p=arguments; 226 x=0; 227 while( *p != '\0' ) 228 { 229 GetMagickToken(p,&p,token); 230 if ( token[0] == ',' ) continue; 231 if ( isalpha((int) token[0]) || token[0] == '#' ) 232 x += number_colors; /* color argument found */ 233 else 234 x++; /* floating point argument */ 235 } 236 /* control points and color values */ 237 error = IsMagickTrue( x % (2+number_colors) ); 238 number_arguments=x; 239 if ( IfMagickTrue(error) ) { 240 (void) ThrowMagickException(exception,GetMagickModule(), 241 OptionError, "InvalidArgument", "'%s': %s", "sparse-color", 242 "Invalid number of Arguments"); 243 return( (Image *)NULL); 244 } 245 246 /* Allocate and fill in the floating point arguments */ 247 sparse_arguments=(double *) AcquireQuantumMemory(number_arguments, 248 sizeof(*sparse_arguments)); 249 if (sparse_arguments == (double *) NULL) { 250 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, 251 "MemoryAllocationFailed","%s","SparseColorOption"); 252 return( (Image *)NULL); 253 } 254 (void) ResetMagickMemory(sparse_arguments,0,number_arguments* 255 sizeof(*sparse_arguments)); 256 p=arguments; 257 x=0; 258 while( *p != '\0' && x < number_arguments ) { 259 /* X coordinate */ 260 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token); 261 if ( token[0] == '\0' ) break; 262 if ( isalpha((int) token[0]) || token[0] == '#' ) { 263 (void) ThrowMagickException(exception,GetMagickModule(), 264 OptionError, "InvalidArgument", "'%s': %s", "sparse-color", 265 "Color found, instead of X-coord"); 266 error = MagickTrue; 267 break; 268 } 269 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 270 /* Y coordinate */ 271 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token); 272 if ( token[0] == '\0' ) break; 273 if ( isalpha((int) token[0]) || token[0] == '#' ) { 274 (void) ThrowMagickException(exception,GetMagickModule(), 275 OptionError, "InvalidArgument", "'%s': %s", "sparse-color", 276 "Color found, instead of Y-coord"); 277 error = MagickTrue; 278 break; 279 } 280 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 281 /* color name or function given in string argument */ 282 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token); 283 if ( token[0] == '\0' ) break; 284 if ( isalpha((int) token[0]) || token[0] == '#' ) { 285 /* Color string given */ 286 (void) QueryColorCompliance(token,AllCompliance,&color, 287 exception); 288 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 289 sparse_arguments[x++] = QuantumScale*color.red; 290 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 291 sparse_arguments[x++] = QuantumScale*color.green; 292 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 293 sparse_arguments[x++] = QuantumScale*color.blue; 294 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 295 (image->colorspace == CMYKColorspace)) 296 sparse_arguments[x++] = QuantumScale*color.black; 297 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 298 image->alpha_trait == BlendPixelTrait) 299 sparse_arguments[x++] = QuantumScale*color.alpha; 300 } 301 else { 302 /* Colors given as a set of floating point values - experimental */ 303 /* NB: token contains the first floating point value to use! */ 304 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0) 305 { 306 while ( token[0] == ',' ) GetMagickToken(p,&p,token); 307 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' ) 308 break; 309 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 310 token[0] = ','; /* used this token - get another */ 311 } 312 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0) 313 { 314 while ( token[0] == ',' ) GetMagickToken(p,&p,token); 315 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' ) 316 break; 317 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 318 token[0] = ','; /* used this token - get another */ 319 } 320 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0) 321 { 322 while ( token[0] == ',' ) GetMagickToken(p,&p,token); 323 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' ) 324 break; 325 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 326 token[0] = ','; /* used this token - get another */ 327 } 328 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) && 329 (image->colorspace == CMYKColorspace)) 330 { 331 while ( token[0] == ',' ) GetMagickToken(p,&p,token); 332 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' ) 333 break; 334 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 335 token[0] = ','; /* used this token - get another */ 336 } 337 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) && 338 image->alpha_trait == BlendPixelTrait) 339 { 340 while ( token[0] == ',' ) GetMagickToken(p,&p,token); 341 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' ) 342 break; 343 sparse_arguments[x++]=StringToDouble(token,(char **) NULL); 344 token[0] = ','; /* used this token - get another */ 345 } 346 } 347 } 348 if ( number_arguments != x && !error ) { 349 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, 350 "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error"); 351 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments); 352 return( (Image *)NULL); 353 } 354 if ( error ) 355 return( (Image *)NULL); 356 357 /* Call the Sparse Color Interpolation function with the parsed arguments */ 358 sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments, 359 exception); 360 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments); 361 return( sparse_image ); 362} 363 364/* 365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 366% % 367% % 368% % 369% C L I S e t t i n g O p t i o n I n f o % 370% % 371% % 372% % 373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 374% 375% CLISettingOptionInfo() applies a single settings option into a CLI wand 376% holding the image_info, draw_info, quantize_info structures that will be 377% used when processing the images. 378% 379% These options do no require images to be present in the CLI wand for them 380% to be able to be set, in which case they will generally be applied to image 381% that are read in later 382% 383% Options handled by this function are listed in CommandOptions[] of 384% "option.c" that is one of "SettingOptionFlags" option flags. 385% 386% The format of the CLISettingOptionInfo method is: 387% 388% void CLISettingOptionInfo(MagickCLI *cli_wand, 389% const char *option, const char *arg1, const char *arg2) 390% 391% A description of each parameter follows: 392% 393% o cli_wand: structure holding settings to be applied 394% 395% o option: The option string to be set 396% 397% o arg1, arg2: optional argument strings to the operation 398% arg2 is currently only used by "-limit" 399% 400*/ 401WandPrivate void CLISettingOptionInfo(MagickCLI *cli_wand, 402 const char *option,const char *arg1n, const char *arg2n) 403{ 404 ssize_t 405 parse; /* option argument parsing (string to value table lookup) */ 406 407 const char /* percent escaped versions of the args */ 408 *arg1, 409 *arg2; 410 411#define _image_info (cli_wand->wand.image_info) 412#define _image (cli_wand->wand.images) 413#define _exception (cli_wand->wand.exception) 414#define _draw_info (cli_wand->draw_info) 415#define _quantize_info (cli_wand->quantize_info) 416#define IfSetOption (*option=='-') 417#define ArgBoolean IsMagickTrue(IfSetOption) 418#define ArgBooleanNot IsMagickFalse(IfSetOption) 419#define ArgBooleanString (IfSetOption?"true":"false") 420#define ArgOption(def) (IfSetOption?arg1:(const char *)(def)) 421 422 assert(cli_wand != (MagickCLI *) NULL); 423 assert(cli_wand->signature == WandSignature); 424 assert(cli_wand->wand.signature == WandSignature); 425 426 if (IfMagickTrue(cli_wand->wand.debug)) 427 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(), 428 "- Setting Option: %s \"%s\" \"%s\"", option,arg1n,arg2n); 429 430 arg1 = arg1n, 431 arg2 = arg2n; 432 433#if 1 434#define _process_flags (cli_wand->process_flags) 435#define _option_type ((CommandOptionFlags) cli_wand->command->flags) 436 /* Interpret Percent Escapes in Arguments - using first image */ 437 if ( (((_process_flags & ProcessInterpretProperities) != 0 ) 438 || ((_option_type & AlwaysInterpretArgsFlag) != 0) 439 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) { 440 /* Interpret Percent escapes in argument 1 */ 441 if (arg1n != (char *) NULL) { 442 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception); 443 if (arg1 == (char *) NULL) { 444 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 445 arg1=arg1n; /* use the given argument as is */ 446 } 447 } 448 if (arg2n != (char *) NULL) { 449 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception); 450 if (arg2 == (char *) NULL) { 451 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 452 arg2=arg2n; /* use the given argument as is */ 453 } 454 } 455 } 456#undef _process_flags 457#undef _option_type 458#endif 459 460 switch (*(option+1)) 461 { 462 case 'a': 463 { 464 if (LocaleCompare("adjoin",option+1) == 0) 465 { 466 _image_info->adjoin = ArgBoolean; 467 break; 468 } 469 if (LocaleCompare("affine",option+1) == 0) 470 { 471 CLIWandWarnReplaced("-draw 'affine ...'"); 472 if (IfSetOption) 473 (void) ParseAffineGeometry(arg1,&_draw_info->affine,_exception); 474 else 475 GetAffineMatrix(&_draw_info->affine); 476 break; 477 } 478 if (LocaleCompare("antialias",option+1) == 0) 479 { 480 _image_info->antialias = 481 _draw_info->stroke_antialias = 482 _draw_info->text_antialias = ArgBoolean; 483 break; 484 } 485 if (LocaleCompare("attenuate",option+1) == 0) 486 { 487 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 488 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 489 (void) SetImageOption(_image_info,option+1,ArgOption("1.0")); 490 break; 491 } 492 if (LocaleCompare("authenticate",option+1) == 0) 493 { 494 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 495 break; 496 } 497 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 498 } 499 case 'b': 500 { 501 if (LocaleCompare("background",option+1) == 0) 502 { 503 /* FUTURE: both _image_info attribute & ImageOption in use! 504 _image_info only used directly for generating new images. 505 SyncImageSettings() used to set per-image attribute. 506 507 FUTURE: if _image_info->background_color is not set then 508 we should fall back to per-image background_color 509 510 At this time -background will 'wipe out' the per-image 511 background color! 512 513 Better error handling of QueryColorCompliance() needed. 514 */ 515 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 516 (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance, 517 &_image_info->background_color,_exception); 518 break; 519 } 520 if (LocaleCompare("bias",option+1) == 0) 521 { 522 /* FUTURE: bias OBSOLETED, replaced by Artifact "convolve:bias" 523 as it is actually rarely used except in direct convolve operations 524 Usage outside a direct convolve operation is actally non-sensible! 525 526 SyncImageSettings() used to set per-image attribute. 527 */ 528 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 529 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 530 (void) SetImageOption(_image_info,"convolve:bias",ArgOption(NULL)); 531 break; 532 } 533 if (LocaleCompare("black-point-compensation",option+1) == 0) 534 { 535 /* Used as a image chromaticity setting 536 SyncImageSettings() used to set per-image attribute. 537 */ 538 (void) SetImageOption(_image_info,option+1,ArgBooleanString); 539 break; 540 } 541 if (LocaleCompare("blue-primary",option+1) == 0) 542 { 543 /* Image chromaticity X,Y NB: Y=X if Y not defined 544 Used by many coders including PNG 545 SyncImageSettings() used to set per-image attribute. 546 */ 547 arg1=ArgOption("0.0"); 548 if (IfMagickFalse(IsGeometry(arg1))) 549 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 550 (void) SetImageOption(_image_info,option+1,arg1); 551 break; 552 } 553 if (LocaleCompare("bordercolor",option+1) == 0) 554 { 555 /* FUTURE: both _image_info attribute & ImageOption in use! 556 SyncImageSettings() used to set per-image attribute. 557 Better error checking of QueryColorCompliance(). 558 */ 559 if (IfSetOption) 560 { 561 (void) SetImageOption(_image_info,option+1,arg1); 562 (void) QueryColorCompliance(arg1,AllCompliance, 563 &_image_info->border_color,_exception); 564 (void) QueryColorCompliance(arg1,AllCompliance, 565 &_draw_info->border_color,_exception); 566 break; 567 } 568 (void) DeleteImageOption(_image_info,option+1); 569 (void) QueryColorCompliance(BorderColor,AllCompliance, 570 &_image_info->border_color,_exception); 571 (void) QueryColorCompliance(BorderColor,AllCompliance, 572 &_draw_info->border_color,_exception); 573 break; 574 } 575 if (LocaleCompare("box",option+1) == 0) 576 { 577 CLIWandWarnReplaced("-undercolor"); 578 CLISettingOptionInfo(cli_wand,"-undercolor",arg1, arg2); 579 break; 580 } 581 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 582 } 583 case 'c': 584 { 585 if (LocaleCompare("cache",option+1) == 0) 586 { 587 MagickSizeType 588 limit; 589 590 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 591 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 592 limit=MagickResourceInfinity; 593 if (LocaleCompare("unlimited",arg1) != 0) 594 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg1,100.0); 595 (void) SetMagickResourceLimit(MemoryResource,limit); 596 (void) SetMagickResourceLimit(MapResource,2*limit); 597 break; 598 } 599 if (LocaleCompare("caption",option+1) == 0) 600 { 601 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 602 break; 603 } 604 if (LocaleCompare("channel",option+1) == 0) 605 { 606 parse=ParseChannelOption(ArgOption("Default")); 607 if (parse < 0) 608 CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType", 609 option,arg1); 610 _image_info->channel=(ChannelType) parse; 611 (void) SetImageOption(_image_info,option+1,arg1); 612 break; 613 } 614 if (LocaleCompare("colorspace",option+1) == 0) 615 { 616 /* Setting used for new images via AquireImage() 617 But also used as a SimpleImageOperator 618 Undefined colorspace means don't modify images on 619 read or as a operation */ 620 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse, 621 ArgOption("undefined")); 622 if (parse < 0) 623 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace", 624 option,arg1); 625 _image_info->colorspace=(ColorspaceType) parse; 626 break; 627 } 628 if (LocaleCompare("comment",option+1) == 0) 629 { 630 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 631 break; 632 } 633 if (LocaleCompare("compose",option+1) == 0) 634 { 635 /* FUTURE: _image_info should be used, 636 SyncImageSettings() used to set per-image attribute. - REMOVE 637 638 This setting should NOT be used to set image 'compose' 639 "-layer" operators shoud use _image_info if defined otherwise 640 they should use a per-image compose setting. 641 */ 642 parse = ParseCommandOption(MagickComposeOptions,MagickFalse, 643 ArgOption("undefined")); 644 if (parse < 0) 645 CLIWandExceptArgBreak(OptionError,"UnrecognizedComposeOperator", 646 option,arg1); 647 _image_info->compose=(CompositeOperator) parse; 648 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 649 break; 650 } 651 if (LocaleCompare("compress",option+1) == 0) 652 { 653 /* FUTURE: What should be used? _image_info or ImageOption ??? 654 The former is more efficent, but Crisy prefers the latter! 655 SyncImageSettings() used to set per-image attribute. 656 657 The coders appears to use _image_info, not Image_Option 658 however the image attribute (for save) is set from the 659 ImageOption! 660 661 Note that "undefined" is a different setting to "none". 662 */ 663 parse = ParseCommandOption(MagickCompressOptions,MagickFalse, 664 ArgOption("undefined")); 665 if (parse < 0) 666 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageCompression", 667 option,arg1); 668 _image_info->compression=(CompressionType) parse; 669 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 670 break; 671 } 672 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 673 } 674 case 'd': 675 { 676 if (LocaleCompare("debug",option+1) == 0) 677 { 678 /* SyncImageSettings() used to set per-image attribute. */ 679 arg1=ArgOption("none"); 680 parse = ParseCommandOption(MagickLogEventOptions,MagickFalse,arg1); 681 if (parse < 0) 682 CLIWandExceptArgBreak(OptionError,"UnrecognizedEventType", 683 option,arg1); 684 (void) SetLogEventMask(arg1); 685 _image_info->debug=IsEventLogging(); /* extract logging*/ 686 cli_wand->wand.debug=IsEventLogging(); 687 break; 688 } 689 if (LocaleCompare("define",option+1) == 0) 690 { 691 if (LocaleNCompare(arg1,"registry:",9) == 0) 692 { 693 if (IfSetOption) 694 (void) DefineImageRegistry(StringRegistryType,arg1+9,_exception); 695 else 696 (void) DeleteImageRegistry(arg1+9); 697 break; 698 } 699 /* DefineImageOption() equals SetImageOption() but with '=' */ 700 if (IfSetOption) 701 (void) DefineImageOption(_image_info,arg1); 702 else if (IsMagickFalse(DeleteImageOption(_image_info,arg1))) 703 CLIWandExceptArgBreak(OptionError,"NoSuchOption",option,arg1); 704 break; 705 } 706 if (LocaleCompare("delay",option+1) == 0) 707 { 708 /* Only used for new images via AcquireImage() 709 FUTURE: Option should also be used for "-morph" (color morphing) 710 */ 711 arg1=ArgOption("0"); 712 if (IfMagickFalse(IsGeometry(arg1))) 713 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 714 (void) SetImageOption(_image_info,option+1,arg1); 715 break; 716 } 717 if (LocaleCompare("density",option+1) == 0) 718 { 719 /* FUTURE: strings used in _image_info attr and _draw_info! 720 Basically as density can be in a XxY form! 721 722 SyncImageSettings() used to set per-image attribute. 723 */ 724 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 725 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 726 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 727 (void) CloneString(&_image_info->density,ArgOption(NULL)); 728 (void) CloneString(&_draw_info->density,_image_info->density); 729 break; 730 } 731 if (LocaleCompare("depth",option+1) == 0) 732 { 733 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!! 734 SyncImageSettings() used to set per-image attribute. 735 */ 736 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 737 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 738 _image_info->depth=IfSetOption?StringToUnsignedLong(arg1) 739 :MAGICKCORE_QUANTUM_DEPTH; 740 break; 741 } 742 if (LocaleCompare("direction",option+1) == 0) 743 { 744 /* Image Option is only used to set _draw_info */ 745 arg1=ArgOption("undefined"); 746 parse = ParseCommandOption(MagickDirectionOptions,MagickFalse,arg1); 747 if (parse < 0) 748 CLIWandExceptArgBreak(OptionError,"UnrecognizedDirectionType", 749 option,arg1); 750 _draw_info->direction=(DirectionType) parse; 751 (void) SetImageOption(_image_info,option+1,arg1); 752 break; 753 } 754 if (LocaleCompare("display",option+1) == 0) 755 { 756 (void) CloneString(&_image_info->server_name,ArgOption(NULL)); 757 (void) CloneString(&_draw_info->server_name,_image_info->server_name); 758 break; 759 } 760 if (LocaleCompare("dispose",option+1) == 0) 761 { 762 /* only used in setting new images */ 763 arg1=ArgOption("undefined"); 764 parse = ParseCommandOption(MagickDisposeOptions,MagickFalse,arg1); 765 if (parse < 0) 766 CLIWandExceptArgBreak(OptionError,"UnrecognizedDisposeMethod", 767 option,arg1); 768 (void) SetImageOption(_image_info,option+1,ArgOption("undefined")); 769 break; 770 } 771 if (LocaleCompare("dissimilarity-threshold",option+1) == 0) 772 { 773 /* FUTURE: this is only used by CompareImages() which is used 774 only by the "compare" CLI program at this time. */ 775 arg1=ArgOption(DEFAULT_DISSIMILARITY_THRESHOLD); 776 if (IfMagickFalse(IsGeometry(arg1))) 777 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 778 (void) SetImageOption(_image_info,option+1,arg1); 779 break; 780 } 781 if (LocaleCompare("dither",option+1) == 0) 782 { 783 /* _image_info attr (on/off), _quantize_info attr (on/off) 784 but also ImageInfo and _quantize_info method! 785 FUTURE: merge the duality of the dithering options 786 */ 787 _image_info->dither = ArgBoolean; 788 (void) SetImageOption(_image_info,option+1,ArgOption("none")); 789 _quantize_info->dither_method=(DitherMethod) ParseCommandOption( 790 MagickDitherOptions,MagickFalse,ArgOption("none")); 791 if (_quantize_info->dither_method == NoDitherMethod) 792 _image_info->dither = MagickFalse; 793 break; 794 } 795 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 796 } 797 case 'e': 798 { 799 if (LocaleCompare("encoding",option+1) == 0) 800 { 801 (void) CloneString(&_draw_info->encoding,ArgOption("undefined")); 802 (void) SetImageOption(_image_info,option+1,_draw_info->encoding); 803 break; 804 } 805 if (LocaleCompare("endian",option+1) == 0) 806 { 807 /* Both _image_info attr and ImageInfo */ 808 arg1 = ArgOption("undefined"); 809 parse = ParseCommandOption(MagickEndianOptions,MagickFalse,arg1); 810 if (parse < 0) 811 CLIWandExceptArgBreak(OptionError,"UnrecognizedEndianType", 812 option,arg1); 813 /* FUTURE: check alloc/free of endian string! - remove? */ 814 _image_info->endian=(EndianType) (*arg1); 815 (void) SetImageOption(_image_info,option+1,arg1); 816 break; 817 } 818 if (LocaleCompare("extract",option+1) == 0) 819 { 820 (void) CloneString(&_image_info->extract,ArgOption(NULL)); 821 break; 822 } 823 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 824 } 825 case 'f': 826 { 827 if (LocaleCompare("family",option+1) == 0) 828 { 829 (void) CloneString(&_draw_info->family,ArgOption(NULL)); 830 break; 831 } 832 if (LocaleCompare("features",option+1) == 0) 833 { 834 (void) SetImageOption(_image_info,"identify:features", 835 ArgBooleanString); 836 if (IfSetOption) 837 (void) SetImageArtifact(_image,"verbose","true"); 838 break; 839 } 840 if (LocaleCompare("fill",option+1) == 0) 841 { 842 /* Set "fill" OR "fill-pattern" in _draw_info 843 The original fill color is preserved if a fill-pattern is given. 844 That way it does not effect other operations that directly using 845 the fill color and, can be retored using "+tile". 846 */ 847 MagickBooleanType 848 status; 849 850 ExceptionInfo 851 *sans; 852 853 PixelInfo 854 color; 855 856 arg1 = ArgOption("none"); /* +fill turns it off! */ 857 (void) SetImageOption(_image_info,option+1,arg1); 858 if (_draw_info->fill_pattern != (Image *) NULL) 859 _draw_info->fill_pattern=DestroyImage(_draw_info->fill_pattern); 860 861 /* is it a color or a image? -- ignore exceptions */ 862 sans=AcquireExceptionInfo(); 863 status=QueryColorCompliance(arg1,AllCompliance,&color,sans); 864 sans=DestroyExceptionInfo(sans); 865 866 if (IfMagickFalse(status)) 867 _draw_info->fill_pattern=GetImageCache(_image_info,arg1,_exception); 868 else 869 _draw_info->fill=color; 870 break; 871 } 872 if (LocaleCompare("filter",option+1) == 0) 873 { 874 /* SyncImageSettings() used to set per-image attribute. */ 875 arg1 = ArgOption("undefined"); 876 parse = ParseCommandOption(MagickFilterOptions,MagickFalse,arg1); 877 if (parse < 0) 878 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageFilter", 879 option,arg1); 880 (void) SetImageOption(_image_info,option+1,arg1); 881 break; 882 } 883 if (LocaleCompare("font",option+1) == 0) 884 { 885 (void) CloneString(&_draw_info->font,ArgOption(NULL)); 886 (void) CloneString(&_image_info->font,_draw_info->font); 887 break; 888 } 889 if (LocaleCompare("format",option+1) == 0) 890 { 891 /* FUTURE: why the ping test, you could set ping after this! */ 892 /* 893 register const char 894 *q; 895 896 for (q=strchr(arg1,'%'); q != (char *) NULL; q=strchr(q+1,'%')) 897 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL) 898 _image_info->ping=MagickFalse; 899 */ 900 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 901 break; 902 } 903 if (LocaleCompare("fuzz",option+1) == 0) 904 { 905 /* Option used to set image fuzz! unless blank canvas (from color) 906 Image attribute used for color compare operations 907 SyncImageSettings() used to set per-image attribute. 908 909 FUTURE: Can't find anything else using _image_info->fuzz directly! 910 convert structure attribute to 'option' string 911 */ 912 arg1=ArgOption("0"); 913 if (IfMagickFalse(IsGeometry(arg1))) 914 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 915 _image_info->fuzz=StringToDoubleInterval(arg1,(double) 916 QuantumRange+1.0); 917 (void) SetImageOption(_image_info,option+1,arg1); 918 break; 919 } 920 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 921 } 922 case 'g': 923 { 924 if (LocaleCompare("gravity",option+1) == 0) 925 { 926 /* SyncImageSettings() used to set per-image attribute. */ 927 arg1 = ArgOption("none"); 928 parse = ParseCommandOption(MagickGravityOptions,MagickFalse,arg1); 929 if (parse < 0) 930 CLIWandExceptArgBreak(OptionError,"UnrecognizedGravityType", 931 option,arg1); 932 _draw_info->gravity=(GravityType) parse; 933 (void) SetImageOption(_image_info,option+1,arg1); 934 break; 935 } 936 if (LocaleCompare("green-primary",option+1) == 0) 937 { 938 /* Image chromaticity X,Y NB: Y=X if Y not defined 939 SyncImageSettings() used to set per-image attribute. 940 Used directly by many coders 941 */ 942 arg1=ArgOption("0.0"); 943 if (IfMagickFalse(IsGeometry(arg1))) 944 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 945 (void) SetImageOption(_image_info,option+1,arg1); 946 break; 947 } 948 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 949 } 950 case 'h': 951 { 952 if (LocaleCompare("highlight-color",option+1) == 0) 953 { 954 /* FUTURE: this is only used by CompareImages() which is used 955 only by the "compare" CLI program at this time. */ 956 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 957 break; 958 } 959 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 960 } 961 case 'i': 962 { 963 if (LocaleCompare("intensity",option+1) == 0) 964 { 965 arg1 = ArgOption("undefined"); 966 parse = ParseCommandOption(MagickPixelIntensityOptions,MagickFalse, 967 arg1); 968 if (parse < 0) 969 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityType", 970 option,arg1); 971 (void) SetImageOption(_image_info,option+1,arg1); 972 break; 973 } 974 if (LocaleCompare("intent",option+1) == 0) 975 { 976 /* Only used by coders: MIFF, MPC, BMP, PNG 977 and for image profile call to AcquireTransformThreadSet() 978 SyncImageSettings() used to set per-image attribute. 979 */ 980 arg1 = ArgOption("undefined"); 981 parse = ParseCommandOption(MagickIntentOptions,MagickFalse,arg1); 982 if (parse < 0) 983 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntentType", 984 option,arg1); 985 (void) SetImageOption(_image_info,option+1,arg1); 986 break; 987 } 988 if (LocaleCompare("interlace",option+1) == 0) 989 { 990 /* _image_info is directly used by coders (so why an image setting?) 991 SyncImageSettings() used to set per-image attribute. 992 */ 993 arg1 = ArgOption("undefined"); 994 parse = ParseCommandOption(MagickInterlaceOptions,MagickFalse,arg1); 995 if (parse < 0) 996 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterlaceType", 997 option,arg1); 998 _image_info->interlace=(InterlaceType) parse; 999 (void) SetImageOption(_image_info,option+1,arg1); 1000 break; 1001 } 1002 if (LocaleCompare("interline-spacing",option+1) == 0) 1003 { 1004 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1005 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1006 (void) SetImageOption(_image_info,option+1, ArgOption(NULL)); 1007 _draw_info->interline_spacing=StringToDouble(ArgOption("0"), 1008 (char **) NULL); 1009 break; 1010 } 1011 if (LocaleCompare("interpolate",option+1) == 0) 1012 { 1013 /* SyncImageSettings() used to set per-image attribute. */ 1014 arg1 = ArgOption("undefined"); 1015 parse = ParseCommandOption(MagickInterpolateOptions,MagickFalse,arg1); 1016 if (parse < 0) 1017 CLIWandExceptArgBreak(OptionError,"UnrecognizedInterpolateMethod", 1018 option,arg1); 1019 (void) SetImageOption(_image_info,option+1,arg1); 1020 break; 1021 } 1022 if (LocaleCompare("interword-spacing",option+1) == 0) 1023 { 1024 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1025 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1026 (void) SetImageOption(_image_info,option+1, ArgOption(NULL)); 1027 _draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL); 1028 break; 1029 } 1030 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1031 } 1032 case 'k': 1033 { 1034 if (LocaleCompare("kerning",option+1) == 0) 1035 { 1036 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1037 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1038 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1039 _draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL); 1040 break; 1041 } 1042 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1043 } 1044 case 'l': 1045 { 1046 if (LocaleCompare("label",option+1) == 0) 1047 { 1048 /* only used for new images - not in SyncImageOptions() */ 1049 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1050 break; 1051 } 1052 if (LocaleCompare("limit",option+1) == 0) 1053 { 1054 MagickSizeType 1055 limit; 1056 1057 limit=MagickResourceInfinity; 1058 parse= ParseCommandOption(MagickResourceOptions,MagickFalse,arg1); 1059 if ( parse < 0 ) 1060 CLIWandExceptArgBreak(OptionError,"UnrecognizedResourceType", 1061 option,arg1); 1062 if (LocaleCompare("unlimited",arg2) != 0) 1063 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0); 1064 (void) SetMagickResourceLimit((ResourceType)parse,limit); 1065 break; 1066 } 1067 if (LocaleCompare("log",option+1) == 0) 1068 { 1069 if (IfSetOption) { 1070 if ((strchr(arg1,'%') == (char *) NULL)) 1071 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1072 (void) SetLogFormat(arg1); 1073 } 1074 break; 1075 } 1076 if (LocaleCompare("lowlight-color",option+1) == 0) 1077 { 1078 /* FUTURE: this is only used by CompareImages() which is used 1079 only by the "compare" CLI program at this time. */ 1080 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1081 break; 1082 } 1083 if (LocaleCompare("loop",option+1) == 0) 1084 { 1085 /* SyncImageSettings() used to set per-image attribute. */ 1086 arg1=ArgOption("0"); 1087 if (IfMagickFalse(IsGeometry(arg1))) 1088 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1089 (void) SetImageOption(_image_info,option+1,arg1); 1090 break; 1091 } 1092 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1093 } 1094 case 'm': 1095 { 1096 if (LocaleCompare("mattecolor",option+1) == 0) 1097 { 1098 /* SyncImageSettings() used to set per-image attribute. */ 1099 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1100 (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance, 1101 &_image_info->matte_color,_exception); 1102 break; 1103 } 1104 if (LocaleCompare("metric",option+1) == 0) 1105 { 1106 /* FUTURE: this is only used by CompareImages() which is used 1107 only by the "compare" CLI program at this time. */ 1108 parse=ParseCommandOption(MagickMetricOptions,MagickFalse,arg1); 1109 if ( parse < 0 ) 1110 CLIWandExceptArgBreak(OptionError,"UnrecognizedMetricType", 1111 option,arg1); 1112 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1113 break; 1114 } 1115 if (LocaleCompare("monitor",option+1) == 0) 1116 { 1117 (void) SetImageInfoProgressMonitor(_image_info, IfSetOption? 1118 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL); 1119 break; 1120 } 1121 if (LocaleCompare("monochrome",option+1) == 0) 1122 { 1123 /* Setting (used by some input coders!) -- why? 1124 Warning: This is also Special '-type' SimpleOperator 1125 */ 1126 _image_info->monochrome= ArgBoolean; 1127 break; 1128 } 1129 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1130 } 1131 case 'o': 1132 { 1133 if (LocaleCompare("orient",option+1) == 0) 1134 { 1135 /* Is not used when defining for new images. 1136 This makes it more of a 'operation' than a setting 1137 FUTURE: make set meta-data operator instead. 1138 SyncImageSettings() used to set per-image attribute. 1139 */ 1140 parse=ParseCommandOption(MagickOrientationOptions,MagickFalse, 1141 ArgOption("undefined")); 1142 if (parse < 0) 1143 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageOrientation", 1144 option,arg1); 1145 _image_info->orientation=(OrientationType)parse; 1146 (void) SetImageOption(_image_info,option+1, ArgOption(NULL)); 1147 break; 1148 } 1149 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1150 } 1151 case 'p': 1152 { 1153 if (LocaleCompare("page",option+1) == 0) 1154 { 1155 /* Only used for new images and image generators. 1156 SyncImageSettings() used to set per-image attribute. ????? 1157 That last is WRONG!!!! 1158 FUTURE: adjust named 'page' sizes according density 1159 */ 1160 char 1161 *canonical_page, 1162 page[MaxTextExtent]; 1163 1164 const char 1165 *image_option; 1166 1167 MagickStatusType 1168 flags; 1169 1170 RectangleInfo 1171 geometry; 1172 1173 if (!IfSetOption) 1174 { 1175 (void) DeleteImageOption(_image_info,option+1); 1176 (void) CloneString(&_image_info->page,(char *) NULL); 1177 break; 1178 } 1179 (void) ResetMagickMemory(&geometry,0,sizeof(geometry)); 1180 image_option=GetImageOption(_image_info,"page"); 1181 if (image_option != (const char *) NULL) 1182 flags=ParseAbsoluteGeometry(image_option,&geometry); 1183 canonical_page=GetPageGeometry(arg1); 1184 flags=ParseAbsoluteGeometry(canonical_page,&geometry); 1185 canonical_page=DestroyString(canonical_page); 1186 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu", 1187 (unsigned long) geometry.width,(unsigned long) geometry.height); 1188 if (((flags & XValue) != 0) || ((flags & YValue) != 0)) 1189 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld", 1190 (unsigned long) geometry.width,(unsigned long) geometry.height, 1191 (long) geometry.x,(long) geometry.y); 1192 (void) SetImageOption(_image_info,option+1,page); 1193 (void) CloneString(&_image_info->page,page); 1194 break; 1195 } 1196 if (LocaleCompare("ping",option+1) == 0) 1197 { 1198 _image_info->ping = ArgBoolean; 1199 break; 1200 } 1201 if (LocaleCompare("pointsize",option+1) == 0) 1202 { 1203 if (IfSetOption) { 1204 if (IfMagickFalse(IsGeometry(arg1))) 1205 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1206 _image_info->pointsize = 1207 _draw_info->pointsize = 1208 StringToDouble(arg1,(char **) NULL); 1209 } 1210 else { 1211 _image_info->pointsize=0.0; /* unset pointsize */ 1212 _draw_info->pointsize=12.0; 1213 } 1214 break; 1215 } 1216 if (LocaleCompare("precision",option+1) == 0) 1217 { 1218 arg1=ArgOption("-1"); 1219 if (IfMagickFalse(IsGeometry(arg1))) 1220 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1221 (void) SetMagickPrecision(StringToInteger(arg1)); 1222 break; 1223 } 1224 /* FUTURE: Only the 'preview' coder appears to use this 1225 * DEPRECIATE the coder? Leaving only the 'preview' operator. 1226 if (LocaleCompare("preview",option+1) == 0) 1227 { 1228 _image_info->preview_type=UndefinedPreview; 1229 if (IfSetOption) 1230 _image_info->preview_type=(PreviewType) ParseCommandOption( 1231 MagickPreviewOptions,MagickFalse,arg1); 1232 break; 1233 } 1234 */ 1235 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1236 } 1237 case 'q': 1238 { 1239 if (LocaleCompare("quality",option+1) == 0) 1240 { 1241 if (IfMagickFalse(IsGeometry(arg1))) 1242 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1243 _image_info->quality= IfSetOption ? StringToUnsignedLong(arg1) 1244 : UNDEFINED_COMPRESSION_QUALITY; 1245 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1246 break; 1247 } 1248 if (LocaleCompare("quantize",option+1) == 0) 1249 { 1250 /* Just a set direct in _quantize_info */ 1251 arg1=ArgOption("undefined"); 1252 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1); 1253 if (parse < 0) 1254 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace", 1255 option,arg1); 1256 _quantize_info->colorspace=(ColorspaceType)parse; 1257 break; 1258 } 1259 if (LocaleCompare("quiet",option+1) == 0) 1260 { 1261 /* FUTURE: if two -quiet is performed you can not do +quiet! 1262 This needs to be checked over thoughly. 1263 */ 1264 static WarningHandler 1265 warning_handler = (WarningHandler) NULL; 1266 1267 WarningHandler 1268 tmp = SetWarningHandler((WarningHandler) NULL); 1269 1270 if ( tmp != (WarningHandler) NULL) 1271 warning_handler = tmp; /* remember the old handler */ 1272 if (!IfSetOption) /* set the old handler */ 1273 warning_handler=SetWarningHandler(warning_handler); 1274 break; 1275 } 1276 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1277 } 1278 case 'r': 1279 { 1280 if (LocaleCompare("red-primary",option+1) == 0) 1281 { 1282 /* Image chromaticity X,Y NB: Y=X if Y not defined 1283 Used by many coders 1284 SyncImageSettings() used to set per-image attribute. 1285 */ 1286 arg1=ArgOption("0.0"); 1287 if (IfMagickFalse(IsGeometry(arg1))) 1288 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1289 (void) SetImageOption(_image_info,option+1,arg1); 1290 break; 1291 } 1292 if (LocaleCompare("regard-warnings",option+1) == 0) 1293 /* FUTURE: to be replaced by a 'fatal-level' type setting */ 1294 break; 1295 if (LocaleCompare("render",option+1) == 0) 1296 { 1297 /* _draw_info only setting */ 1298 _draw_info->render= ArgBooleanNot; 1299 break; 1300 } 1301 if (LocaleCompare("respect-parenthesis",option+1) == 0) 1302 { 1303 /* link image and setting stacks - option is itself saved on stack! */ 1304 (void) SetImageOption(_image_info,option+1,ArgBooleanString); 1305 break; 1306 } 1307 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1308 } 1309 case 's': 1310 { 1311 if (LocaleCompare("sampling-factor",option+1) == 0) 1312 { 1313 /* FUTURE: should be converted to jpeg:sampling_factor */ 1314 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1315 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1316 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL)); 1317 break; 1318 } 1319 if (LocaleCompare("scene",option+1) == 0) 1320 { 1321 /* SyncImageSettings() used to set this as a per-image attribute. 1322 What ??? Why ???? 1323 */ 1324 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1325 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1326 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1327 _image_info->scene=StringToUnsignedLong(ArgOption("0")); 1328 break; 1329 } 1330 if (LocaleCompare("seed",option+1) == 0) 1331 { 1332 if (IfMagickFalse(IsGeometry(arg1))) 1333 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1334 SetRandomSecretKey( 1335 IfSetOption ? (unsigned long) StringToUnsignedLong(arg1) 1336 : (unsigned long) time((time_t *) NULL) ); 1337 break; 1338 } 1339 if (LocaleCompare("size",option+1) == 0) 1340 { 1341 /* FUTURE: string in _image_info -- convert to Option ??? 1342 Look at the special handling for "size" in SetImageOption() 1343 */ 1344 (void) CloneString(&_image_info->size,ArgOption(NULL)); 1345 break; 1346 } 1347 if (LocaleCompare("stretch",option+1) == 0) 1348 { 1349 arg1=ArgOption("undefined"); 1350 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1); 1351 if (parse < 0) 1352 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType", 1353 option,arg1); 1354 _draw_info->stretch=(StretchType) parse; 1355 break; 1356 } 1357 if (LocaleCompare("stroke",option+1) == 0) 1358 { 1359 /* set stroke color OR stroke-pattern 1360 UPDATE: ensure stroke color is not destroyed is a pattern 1361 is given. Just in case the color is also used for other purposes. 1362 */ 1363 MagickBooleanType 1364 status; 1365 1366 ExceptionInfo 1367 *sans; 1368 1369 PixelInfo 1370 color; 1371 1372 arg1 = ArgOption("none"); /* +fill turns it off! */ 1373 (void) SetImageOption(_image_info,option+1,arg1); 1374 if (_draw_info->stroke_pattern != (Image *) NULL) 1375 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern); 1376 1377 /* is it a color or a image? -- ignore exceptions */ 1378 sans=AcquireExceptionInfo(); 1379 status=QueryColorCompliance(arg1,AllCompliance,&color,sans); 1380 sans=DestroyExceptionInfo(sans); 1381 1382 if (IfMagickFalse(status)) 1383 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception); 1384 else 1385 _draw_info->stroke=color; 1386 break; 1387 } 1388 if (LocaleCompare("strokewidth",option+1) == 0) 1389 { 1390 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1391 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1392 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1393 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"), 1394 (char **) NULL); 1395 break; 1396 } 1397 if (LocaleCompare("style",option+1) == 0) 1398 { 1399 arg1=ArgOption("undefined"); 1400 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1); 1401 if (parse < 0) 1402 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType", 1403 option,arg1); 1404 _draw_info->style=(StyleType) parse; 1405 break; 1406 } 1407#if 0 1408 if (LocaleCompare("subimage-search",option+1) == 0) 1409 { 1410 /* FUTURE: this is only used by CompareImages() which is used 1411 only by the "compare" CLI program at this time. */ 1412 (void) SetImageOption(_image_info,option+1,ArgBooleanString); 1413 break; 1414 } 1415#endif 1416 if (LocaleCompare("synchronize",option+1) == 0) 1417 { 1418 /* FUTURE: syncronize to storage - but what does that mean? */ 1419 _image_info->synchronize = ArgBoolean; 1420 break; 1421 } 1422 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1423 } 1424 case 't': 1425 { 1426 if (LocaleCompare("taint",option+1) == 0) 1427 { 1428 /* SyncImageSettings() used to set per-image attribute. */ 1429 (void) SetImageOption(_image_info,option+1,ArgBooleanString); 1430 break; 1431 } 1432 if (LocaleCompare("texture",option+1) == 0) 1433 { 1434 /* Note: arguments do not have percent escapes expanded */ 1435 /* FUTURE: move _image_info string to option splay-tree 1436 Other than "montage" what uses "texture" ???? 1437 */ 1438 (void) CloneString(&_image_info->texture,ArgOption(NULL)); 1439 break; 1440 } 1441 if (LocaleCompare("tile",option+1) == 0) 1442 { 1443 /* Note: arguments do not have percent escapes expanded */ 1444 _draw_info->fill_pattern=IfSetOption 1445 ?GetImageCache(_image_info,arg1,_exception) 1446 :DestroyImage(_draw_info->fill_pattern); 1447 break; 1448 } 1449 if (LocaleCompare("tile-offset",option+1) == 0) 1450 { 1451 /* SyncImageSettings() used to set per-image attribute. ??? */ 1452 arg1=ArgOption("0"); 1453 if (IfMagickFalse(IsGeometry(arg1))) 1454 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1455 (void) SetImageOption(_image_info,option+1,arg1); 1456 break; 1457 } 1458 if (LocaleCompare("transparent-color",option+1) == 0) 1459 { 1460 /* FUTURE: both _image_info attribute & ImageOption in use! 1461 _image_info only used for generating new images. 1462 SyncImageSettings() used to set per-image attribute. 1463 1464 Note that +transparent-color, means fall-back to image 1465 attribute so ImageOption is deleted, not set to a default. 1466 */ 1467 if (IfSetOption && IfMagickFalse(IsGeometry(arg1))) 1468 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1469 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1470 (void) QueryColorCompliance(ArgOption("none"),AllCompliance, 1471 &_image_info->transparent_color,_exception); 1472 break; 1473 } 1474 if (LocaleCompare("treedepth",option+1) == 0) 1475 { 1476 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1477 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0")); 1478 break; 1479 } 1480 if (LocaleCompare("type",option+1) == 0) 1481 { 1482 /* SyncImageSettings() used to set per-image attribute. */ 1483 parse=ParseCommandOption(MagickTypeOptions,MagickFalse, 1484 ArgOption("undefined")); 1485 if (parse < 0) 1486 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType", 1487 option,arg1); 1488 _image_info->type=(ImageType) parse; 1489 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1490 break; 1491 } 1492 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1493 } 1494 case 'u': 1495 { 1496 if (LocaleCompare("undercolor",option+1) == 0) 1497 { 1498 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1499 (void) QueryColorCompliance(ArgOption("none"),AllCompliance, 1500 &_draw_info->undercolor,_exception); 1501 break; 1502 } 1503 if (LocaleCompare("units",option+1) == 0) 1504 { 1505 /* SyncImageSettings() used to set per-image attribute. 1506 Should this effect _draw_info X and Y resolution? 1507 FUTURE: this probably should be part of the density setting 1508 */ 1509 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse, 1510 ArgOption("undefined")); 1511 if (parse < 0) 1512 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType", 1513 option,arg1); 1514 _image_info->units=(ResolutionType) parse; 1515 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1516 break; 1517 } 1518 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1519 } 1520 case 'v': 1521 { 1522 if (LocaleCompare("verbose",option+1) == 0) 1523 { 1524 /* FUTURE: Remember all options become image artifacts 1525 _image_info->verbose is only used by coders. 1526 */ 1527 (void) SetImageOption(_image_info,option+1,ArgBooleanString); 1528 _image_info->verbose= ArgBoolean; 1529 _image_info->ping=MagickFalse; /* verbose can't be a ping */ 1530 break; 1531 } 1532 if (LocaleCompare("view",option+1) == 0) 1533 { 1534 /* FUTURE: Convert from _image_info to ImageOption 1535 Only used by coder FPX 1536 And it only tests existance, not its content! 1537 */ 1538 (void) CloneString(&_image_info->view,ArgOption(NULL)); 1539 break; 1540 } 1541 if (LocaleCompare("virtual-pixel",option+1) == 0) 1542 { 1543 /* SyncImageSettings() used to set per-image attribute. 1544 This is VERY deep in the image caching structure. 1545 */ 1546 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse, 1547 ArgOption("undefined")); 1548 if (parse < 0) 1549 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod", 1550 option,arg1); 1551 (void) SetImageOption(_image_info,option+1,ArgOption(NULL)); 1552 break; 1553 } 1554 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1555 } 1556 case 'w': 1557 { 1558 if (LocaleCompare("weight",option+1) == 0) 1559 { 1560 /* Just what does using a font 'weight' do ??? 1561 There is no "-list weight" output (reference manual says there is) 1562 */ 1563 arg1=ArgOption("all"); 1564 _draw_info->weight=StringToUnsignedLong(arg1); 1565 if (LocaleCompare(arg1,"all") == 0) 1566 _draw_info->weight=0; 1567 if (LocaleCompare(arg1,"bold") == 0) 1568 _draw_info->weight=700; 1569 if (LocaleCompare(arg1,"bolder") == 0) 1570 if (_draw_info->weight <= 800) 1571 _draw_info->weight+=100; 1572 if (LocaleCompare(arg1,"lighter") == 0) 1573 if (_draw_info->weight >= 100) 1574 _draw_info->weight-=100; 1575 if (LocaleCompare(arg1,"normal") == 0) 1576 _draw_info->weight=400; 1577 break; 1578 } 1579 if (LocaleCompare("white-point",option+1) == 0) 1580 { 1581 /* Used as a image chromaticity setting 1582 SyncImageSettings() used to set per-image attribute. 1583 */ 1584 arg1=ArgOption("0.0"); 1585 if (IfMagickFalse(IsGeometry(arg1))) 1586 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1587 (void) SetImageOption(_image_info,option+1,arg1); 1588 break; 1589 } 1590 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1591 } 1592 default: 1593 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1594 } 1595 1596 /* clean up percent escape interpreted strings */ 1597 if (arg1 != arg1n ) 1598 arg1=DestroyString((char *)arg1); 1599 if (arg2 != arg2n ) 1600 arg2=DestroyString((char *)arg2); 1601 1602#undef _image_info 1603#undef _exception 1604#undef _draw_info 1605#undef _quantize_info 1606#undef IfSetOption 1607#undef ArgBoolean 1608#undef ArgBooleanNot 1609#undef ArgBooleanString 1610#undef ArgOption 1611 1612 return; 1613} 1614 1615/* 1616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1617% % 1618% % 1619% % 1620+ C L I S i m p l e O p e r a t o r I m a g e s % 1621% % 1622% % 1623% % 1624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1625% 1626% CLISimpleOperatorImages() applys one simple image operation given to all 1627% the images in the CLI wand, using any per-image or global settings that was 1628% previously saved in the CLI wand. 1629% 1630% It is assumed that any such settings are up-to-date. 1631% 1632% The format of the WandSimpleOperatorImages method is: 1633% 1634% void CLISimpleOperatorImages(MagickCLI *cli_wand, 1635% const char *option, const char *arg1, const char *arg2) 1636% 1637% A description of each parameter follows: 1638% 1639% o cli_wand: structure holding settings and images to be operated on 1640% 1641% o option: The option string for the operation 1642% 1643% o arg1, arg2: optional argument strings to the operation 1644% 1645*/ 1646 1647/* 1648 CLISimpleOperatorImage() is an Internal subrountine to apply one simple 1649 image operation to the current image pointed to by the CLI wand. 1650 1651 The image in the list may be modified in three different ways... 1652 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw), 1653 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology) 1654 * one image replace by a list of images (-separate and -crop only!) 1655 1656 In each case the result replaces the single original image in the list, as 1657 well as the pointer to the modified image (last image added if replaced by a 1658 list of images) is returned. 1659 1660 As the image pointed to may be replaced, the first image in the list may 1661 also change. GetFirstImageInList() should be used by caller if they wish 1662 return the Image pointer to the first image in list. 1663*/ 1664static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand, 1665 const char *option, const char *arg1n, const char *arg2n) 1666{ 1667 Image * 1668 new_image; 1669 1670 GeometryInfo 1671 geometry_info; 1672 1673 RectangleInfo 1674 geometry; 1675 1676 MagickStatusType 1677 flags; 1678 1679 ssize_t 1680 parse; 1681 1682 const char /* percent escaped versions of the args */ 1683 *arg1, 1684 *arg2; 1685 1686#define _image_info (cli_wand->wand.image_info) 1687#define _image (cli_wand->wand.images) 1688#define _exception (cli_wand->wand.exception) 1689#define _draw_info (cli_wand->draw_info) 1690#define _quantize_info (cli_wand->quantize_info) 1691#define _process_flags (cli_wand->process_flags) 1692#define _option_type ((CommandOptionFlags) cli_wand->command->flags) 1693#define IfNormalOp (*option=='-') 1694#define IfPlusOp (*option!='-') 1695#define IsNormalOp IsMagickTrue(IfNormalOp) 1696#define IsPlusOp IsMagickFalse(IfNormalOp) 1697 1698 assert(cli_wand != (MagickCLI *) NULL); 1699 assert(cli_wand->signature == WandSignature); 1700 assert(cli_wand->wand.signature == WandSignature); 1701 assert(_image != (Image *) NULL); /* an image must be present */ 1702 if (IfMagickTrue(cli_wand->wand.debug)) 1703 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 1704 1705 arg1 = arg1n, 1706 arg2 = arg2n; 1707 1708 /* Interpret Percent Escapes in Arguments - using first image */ 1709 if ( (((_process_flags & ProcessInterpretProperities) != 0 ) 1710 || ((_option_type & AlwaysInterpretArgsFlag) != 0) 1711 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) { 1712 /* Interpret Percent escapes in argument 1 */ 1713 if (arg1n != (char *) NULL) { 1714 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception); 1715 if (arg1 == (char *) NULL) { 1716 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 1717 arg1=arg1n; /* use the given argument as is */ 1718 } 1719 } 1720 if (arg2n != (char *) NULL) { 1721 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception); 1722 if (arg2 == (char *) NULL) { 1723 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 1724 arg2=arg2n; /* use the given argument as is */ 1725 } 1726 } 1727 } 1728#undef _process_flags 1729#undef _option_type 1730 1731#if 0 1732 (void) FormatLocaleFile(stderr, 1733 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2); 1734#endif 1735 1736 new_image = (Image *)NULL; /* the replacement image, if not null at end */ 1737 SetGeometryInfo(&geometry_info); 1738 1739 switch (*(option+1)) 1740 { 1741 case 'a': 1742 { 1743 if (LocaleCompare("adaptive-blur",option+1) == 0) 1744 { 1745 flags=ParseGeometry(arg1,&geometry_info); 1746 if ((flags & (RhoValue|SigmaValue)) == 0) 1747 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1748 if ((flags & SigmaValue) == 0) 1749 geometry_info.sigma=1.0; 1750 new_image=AdaptiveBlurImage(_image,geometry_info.rho, 1751 geometry_info.sigma,_exception); 1752 break; 1753 } 1754 if (LocaleCompare("adaptive-resize",option+1) == 0) 1755 { 1756 /* FUTURE: Roll into a resize special operator */ 1757 if (IfMagickFalse(IsGeometry(arg1))) 1758 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1759 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 1760 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height, 1761 _exception); 1762 break; 1763 } 1764 if (LocaleCompare("adaptive-sharpen",option+1) == 0) 1765 { 1766 flags=ParseGeometry(arg1,&geometry_info); 1767 if ((flags & (RhoValue|SigmaValue)) == 0) 1768 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1769 if ((flags & SigmaValue) == 0) 1770 geometry_info.sigma=1.0; 1771 new_image=AdaptiveSharpenImage(_image,geometry_info.rho, 1772 geometry_info.sigma,_exception); 1773 break; 1774 } 1775 if (LocaleCompare("alpha",option+1) == 0) 1776 { 1777 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1); 1778 if (parse < 0) 1779 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption", 1780 option,arg1); 1781 (void) SetImageAlphaChannel(_image,(AlphaChannelOption)parse, 1782 _exception); 1783 break; 1784 } 1785 if (LocaleCompare("annotate",option+1) == 0) 1786 { 1787 char 1788 geometry[MaxTextExtent]; 1789 1790 SetGeometryInfo(&geometry_info); 1791 flags=ParseGeometry(arg1,&geometry_info); 1792 if (flags == 0) 1793 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1794 if ((flags & SigmaValue) == 0) 1795 geometry_info.sigma=geometry_info.rho; 1796 (void) CloneString(&_draw_info->text,arg2); 1797 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f", 1798 geometry_info.xi,geometry_info.psi); 1799 (void) CloneString(&_draw_info->geometry,geometry); 1800 _draw_info->affine.sx=cos(DegreesToRadians( 1801 fmod(geometry_info.rho,360.0))); 1802 _draw_info->affine.rx=sin(DegreesToRadians( 1803 fmod(geometry_info.rho,360.0))); 1804 _draw_info->affine.ry=(-sin(DegreesToRadians( 1805 fmod(geometry_info.sigma,360.0)))); 1806 _draw_info->affine.sy=cos(DegreesToRadians( 1807 fmod(geometry_info.sigma,360.0))); 1808 (void) AnnotateImage(_image,_draw_info,_exception); 1809 GetAffineMatrix(&_draw_info->affine); 1810 break; 1811 } 1812 if (LocaleCompare("auto-gamma",option+1) == 0) 1813 { 1814 (void) AutoGammaImage(_image,_exception); 1815 break; 1816 } 1817 if (LocaleCompare("auto-level",option+1) == 0) 1818 { 1819 (void) AutoLevelImage(_image,_exception); 1820 break; 1821 } 1822 if (LocaleCompare("auto-orient",option+1) == 0) 1823 { 1824 new_image=AutoOrientImage(_image,_image->orientation,_exception); 1825 break; 1826 } 1827 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1828 } 1829 case 'b': 1830 { 1831 if (LocaleCompare("black-threshold",option+1) == 0) 1832 { 1833 if (IfMagickFalse(IsGeometry(arg1))) 1834 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1835 (void) BlackThresholdImage(_image,arg1,_exception); 1836 break; 1837 } 1838 if (LocaleCompare("blue-shift",option+1) == 0) 1839 { 1840 geometry_info.rho=1.5; 1841 if (IfNormalOp) { 1842 flags=ParseGeometry(arg1,&geometry_info); 1843 if ((flags & RhoValue) == 0) 1844 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1845 } 1846 new_image=BlueShiftImage(_image,geometry_info.rho,_exception); 1847 break; 1848 } 1849 if (LocaleCompare("blur",option+1) == 0) 1850 { 1851 flags=ParseGeometry(arg1,&geometry_info); 1852 if ((flags & (RhoValue|SigmaValue)) == 0) 1853 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1854 if ((flags & SigmaValue) == 0) 1855 geometry_info.sigma=1.0; 1856 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma, 1857 _exception); 1858 break; 1859 } 1860 if (LocaleCompare("border",option+1) == 0) 1861 { 1862 CompositeOperator 1863 compose; 1864 1865 const char* 1866 value; 1867 1868 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 1869 if ((flags & (WidthValue | HeightValue)) == 0) 1870 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1871 compose=OverCompositeOp; 1872 value=GetImageOption(_image_info,"compose"); 1873 if (value != (const char *) NULL) 1874 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions, 1875 MagickFalse,value); 1876 new_image=BorderImage(_image,&geometry,compose,_exception); 1877 break; 1878 } 1879 if (LocaleCompare("brightness-contrast",option+1) == 0) 1880 { 1881 double 1882 brightness, 1883 contrast; 1884 1885 GeometryInfo 1886 geometry_info; 1887 1888 MagickStatusType 1889 flags; 1890 1891 flags=ParseGeometry(arg1,&geometry_info); 1892 if ((flags & RhoValue) == 0) 1893 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1894 brightness=geometry_info.rho; 1895 contrast=0.0; 1896 if ((flags & SigmaValue) != 0) 1897 contrast=geometry_info.sigma; 1898 (void) BrightnessContrastImage(_image,brightness,contrast, 1899 _exception); 1900 break; 1901 } 1902 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1903 } 1904 case 'c': 1905 { 1906 if (LocaleCompare("cdl",option+1) == 0) 1907 { 1908 /* Note: arguments do not have percent escapes expanded */ 1909 char 1910 *color_correction_collection; 1911 1912 /* 1913 Color correct with a color decision list. 1914 */ 1915 color_correction_collection=FileToString(arg1,~0UL,_exception); 1916 if (color_correction_collection == (char *) NULL) 1917 break; 1918 (void) ColorDecisionListImage(_image,color_correction_collection, 1919 _exception); 1920 break; 1921 } 1922 if (LocaleCompare("charcoal",option+1) == 0) 1923 { 1924 flags=ParseGeometry(arg1,&geometry_info); 1925 if ((flags & (RhoValue|SigmaValue)) == 0) 1926 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1927 if ((flags & SigmaValue) == 0) 1928 geometry_info.sigma=1.0; 1929 if ((flags & XiValue) == 0) 1930 geometry_info.xi=1.0; 1931 new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma, 1932 _exception); 1933 break; 1934 } 1935 if (LocaleCompare("chop",option+1) == 0) 1936 { 1937 if (IfMagickFalse(IsGeometry(arg1))) 1938 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1939 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception); 1940 new_image=ChopImage(_image,&geometry,_exception); 1941 break; 1942 } 1943 if (LocaleCompare("clamp",option+1) == 0) 1944 { 1945 (void) ClampImage(_image,_exception); 1946 break; 1947 } 1948 if (LocaleCompare("clip",option+1) == 0) 1949 { 1950 if (IfNormalOp) 1951 (void) ClipImage(_image,_exception); 1952 else /* "+mask" remove the write mask */ 1953 (void) SetImageMask(_image,(Image *) NULL,_exception); 1954 break; 1955 } 1956 if (LocaleCompare("clip-mask",option+1) == 0) 1957 { 1958 /* Note: arguments do not have percent escapes expanded */ 1959 CacheView 1960 *mask_view; 1961 1962 Image 1963 *mask_image; 1964 1965 register Quantum 1966 *restrict q; 1967 1968 register ssize_t 1969 x; 1970 1971 ssize_t 1972 y; 1973 1974 if (IfPlusOp) { 1975 /* use "+clip-mask" Remove the write mask for -clip-path */ 1976 (void) SetImageMask(_image,(Image *) NULL,_exception); 1977 break; 1978 } 1979 mask_image=GetImageCache(_image_info,arg1,_exception); 1980 if (mask_image == (Image *) NULL) 1981 break; 1982 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception))) 1983 break; 1984 /* Create a write mask from cli_wand mask image */ 1985 /* FUTURE: use Alpha operations instead and create a Grey Image */ 1986 mask_view=AcquireAuthenticCacheView(mask_image,_exception); 1987 for (y=0; y < (ssize_t) mask_image->rows; y++) 1988 { 1989 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1, 1990 _exception); 1991 if (q == (Quantum *) NULL) 1992 break; 1993 for (x=0; x < (ssize_t) mask_image->columns; x++) 1994 { 1995 if (mask_image->alpha_trait != BlendPixelTrait) 1996 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q); 1997 SetPixelGray(mask_image,GetPixelAlpha(mask_image,q),q); 1998 q+=GetPixelChannels(mask_image); 1999 } 2000 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception))) 2001 break; 2002 } 2003 /* clean up and set the write mask */ 2004 mask_view=DestroyCacheView(mask_view); 2005 mask_image->alpha_trait=BlendPixelTrait; 2006 (void) SetImageColorspace(_image,GRAYColorspace,_exception); 2007 (void) SetImageMask(_image,mask_image,_exception); 2008 mask_image=DestroyImage(mask_image); 2009 break; 2010 } 2011 if (LocaleCompare("clip-path",option+1) == 0) 2012 { 2013 (void) ClipImagePath(_image,arg1,IsNormalOp,_exception); 2014 /* Note: Use "+clip-mask" remove the write mask added */ 2015 break; 2016 } 2017 if (LocaleCompare("colorize",option+1) == 0) 2018 { 2019 if (IfMagickFalse(IsGeometry(arg1))) 2020 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2021 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception); 2022 break; 2023 } 2024 if (LocaleCompare("color-matrix",option+1) == 0) 2025 { 2026 KernelInfo 2027 *kernel; 2028 2029 kernel=AcquireKernelInfo(arg1); 2030 if (kernel == (KernelInfo *) NULL) 2031 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2032 new_image=ColorMatrixImage(_image,kernel,_exception); 2033 kernel=DestroyKernelInfo(kernel); 2034 break; 2035 } 2036 if (LocaleCompare("colors",option+1) == 0) 2037 { 2038 /* Reduce the number of colors in the image. 2039 FUTURE: also provide 'plus version with image 'color counts' 2040 */ 2041 _quantize_info->number_colors=StringToUnsignedLong(arg1); 2042 if (_quantize_info->number_colors == 0) 2043 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2044 if ((_image->storage_class == DirectClass) || 2045 _image->colors > _quantize_info->number_colors) 2046 (void) QuantizeImage(_quantize_info,_image,_exception); 2047 else 2048 (void) CompressImageColormap(_image,_exception); 2049 break; 2050 } 2051 if (LocaleCompare("colorspace",option+1) == 0) 2052 { 2053 /* WARNING: this is both a image_info setting (already done) 2054 and a operator to change image colorspace. 2055 2056 FUTURE: default colorspace should be sRGB! 2057 Unless some type of 'linear colorspace' mode is set. 2058 2059 Note that +colorspace sets "undefined" or no effect on 2060 new images, but forces images already in memory back to RGB! 2061 That seems to be a little strange! 2062 */ 2063 (void) TransformImageColorspace(_image, 2064 IfNormalOp ? _image_info->colorspace : sRGBColorspace, 2065 _exception); 2066 break; 2067 } 2068 if (LocaleCompare("contrast",option+1) == 0) 2069 { 2070 CLIWandWarnReplaced(IfNormalOp?"-level":"+level"); 2071 (void) ContrastImage(_image,IsNormalOp,_exception); 2072 break; 2073 } 2074 if (LocaleCompare("contrast-stretch",option+1) == 0) 2075 { 2076 double 2077 black_point, 2078 white_point; 2079 2080 MagickStatusType 2081 flags; 2082 2083 flags=ParseGeometry(arg1,&geometry_info); 2084 if ((flags & RhoValue) == 0) 2085 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2086 black_point=geometry_info.rho; 2087 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : 2088 black_point; 2089 if ((flags & PercentValue) != 0) { 2090 black_point*=(double) _image->columns*_image->rows/100.0; 2091 white_point*=(double) _image->columns*_image->rows/100.0; 2092 } 2093 white_point=(double) _image->columns*_image->rows- 2094 white_point; 2095 (void) ContrastStretchImage(_image,black_point,white_point, 2096 _exception); 2097 break; 2098 } 2099 if (LocaleCompare("convolve",option+1) == 0) 2100 { 2101 KernelInfo 2102 *kernel_info; 2103 2104 kernel_info=AcquireKernelInfo(arg1); 2105 if (kernel_info == (KernelInfo *) NULL) 2106 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2107 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info, 2108 _exception); 2109 kernel_info=DestroyKernelInfo(kernel_info); 2110 break; 2111 } 2112 if (LocaleCompare("crop",option+1) == 0) 2113 { 2114 /* WARNING: This can generate multiple images! */ 2115 if (IfMagickFalse(IsGeometry(arg1))) 2116 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2117 new_image=CropImageToTiles(_image,arg1,_exception); 2118 break; 2119 } 2120 if (LocaleCompare("cycle",option+1) == 0) 2121 { 2122 if (IfMagickFalse(IsGeometry(arg1))) 2123 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2124 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1), 2125 _exception); 2126 break; 2127 } 2128 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2129 } 2130 case 'd': 2131 { 2132 if (LocaleCompare("decipher",option+1) == 0) 2133 { 2134 /* Note: arguments do not have percent escapes expanded */ 2135 StringInfo 2136 *passkey; 2137 2138 passkey=FileToStringInfo(arg1,~0UL,_exception); 2139 if (passkey == (StringInfo *) NULL) 2140 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2141 2142 (void) PasskeyDecipherImage(_image,passkey,_exception); 2143 passkey=DestroyStringInfo(passkey); 2144 break; 2145 } 2146 if (LocaleCompare("depth",option+1) == 0) 2147 { 2148 /* The _image_info->depth setting has already been set 2149 We just need to apply it to all images in current sequence 2150 2151 WARNING: Depth from 8 to 16 causes 'quantum rounding to images! 2152 That is it really is an operation, not a setting! Arrgghhh 2153 2154 FUTURE: this should not be an operator!!! 2155 */ 2156 (void) SetImageDepth(_image,_image_info->depth,_exception); 2157 break; 2158 } 2159 if (LocaleCompare("deskew",option+1) == 0) 2160 { 2161 double 2162 threshold; 2163 2164 if (IfNormalOp) { 2165 if (IfMagickFalse(IsGeometry(arg1))) 2166 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2167 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0); 2168 } 2169 else 2170 threshold=40.0*QuantumRange/100.0; 2171 new_image=DeskewImage(_image,threshold,_exception); 2172 break; 2173 } 2174 if (LocaleCompare("despeckle",option+1) == 0) 2175 { 2176 new_image=DespeckleImage(_image,_exception); 2177 break; 2178 } 2179 if (LocaleCompare("distort",option+1) == 0) 2180 { 2181 double 2182 *args; 2183 2184 ssize_t 2185 count; 2186 2187 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1); 2188 if ( parse < 0 ) 2189 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod", 2190 option,arg1); 2191 if ((DistortImageMethod) parse == ResizeDistortion) 2192 { 2193 double 2194 resize_args[2]; 2195 /* Special Case - Argument is actually a resize geometry! 2196 ** Convert that to an appropriate distortion argument array. 2197 ** FUTURE: make a separate special resize operator 2198 Roll into a resize special operator */ 2199 if (IfMagickFalse(IsGeometry(arg2))) 2200 CLIWandExceptArgBreak(OptionError,"InvalidGeometry", 2201 option,arg2); 2202 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception); 2203 resize_args[0]=(double) geometry.width; 2204 resize_args[1]=(double) geometry.height; 2205 new_image=DistortImage(_image,(DistortImageMethod) parse, 2206 (size_t)2,resize_args,MagickTrue,_exception); 2207 break; 2208 } 2209 /* convert argument string into an array of doubles */ 2210 args = StringToArrayOfDoubles(arg2,&count,_exception); 2211 if (args == (double *)NULL ) 2212 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2); 2213 2214 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args, 2215 IsPlusOp,_exception); 2216 args=(double *) RelinquishMagickMemory(args); 2217 break; 2218 } 2219 if (LocaleCompare("draw",option+1) == 0) 2220 { 2221 (void) CloneString(&_draw_info->primitive,arg1); 2222 (void) DrawImage(_image,_draw_info,_exception); 2223 (void) CloneString(&_draw_info->primitive,(char *)NULL); 2224 break; 2225 } 2226 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2227 } 2228 case 'e': 2229 { 2230 if (LocaleCompare("edge",option+1) == 0) 2231 { 2232 flags=ParseGeometry(arg1,&geometry_info); 2233 if ((flags & (RhoValue|SigmaValue)) == 0) 2234 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2235 new_image=EdgeImage(_image,geometry_info.rho,_exception); 2236 break; 2237 } 2238 if (LocaleCompare("emboss",option+1) == 0) 2239 { 2240 flags=ParseGeometry(arg1,&geometry_info); 2241 if ((flags & (RhoValue|SigmaValue)) == 0) 2242 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2243 if ((flags & SigmaValue) == 0) 2244 geometry_info.sigma=1.0; 2245 new_image=EmbossImage(_image,geometry_info.rho, 2246 geometry_info.sigma,_exception); 2247 break; 2248 } 2249 if (LocaleCompare("encipher",option+1) == 0) 2250 { 2251 /* Note: arguments do not have percent escapes expanded */ 2252 StringInfo 2253 *passkey; 2254 2255 passkey=FileToStringInfo(arg1,~0UL,_exception); 2256 if (passkey != (StringInfo *) NULL) 2257 { 2258 (void) PasskeyEncipherImage(_image,passkey,_exception); 2259 passkey=DestroyStringInfo(passkey); 2260 } 2261 break; 2262 } 2263 if (LocaleCompare("enhance",option+1) == 0) 2264 { 2265 new_image=EnhanceImage(_image,_exception); 2266 break; 2267 } 2268 if (LocaleCompare("equalize",option+1) == 0) 2269 { 2270 (void) EqualizeImage(_image,_exception); 2271 break; 2272 } 2273 if (LocaleCompare("evaluate",option+1) == 0) 2274 { 2275 double 2276 constant; 2277 2278 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1); 2279 if ( parse < 0 ) 2280 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator", 2281 option,arg1); 2282 if (IfMagickFalse(IsGeometry(arg2))) 2283 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 2284 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0); 2285 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant, 2286 _exception); 2287 break; 2288 } 2289 if (LocaleCompare("extent",option+1) == 0) 2290 { 2291 if (IfMagickFalse(IsGeometry(arg1))) 2292 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2293 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception); 2294 if (geometry.width == 0) 2295 geometry.width=_image->columns; 2296 if (geometry.height == 0) 2297 geometry.height=_image->rows; 2298 new_image=ExtentImage(_image,&geometry,_exception); 2299 break; 2300 } 2301 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2302 } 2303 case 'f': 2304 { 2305 if (LocaleCompare("flip",option+1) == 0) 2306 { 2307 new_image=FlipImage(_image,_exception); 2308 break; 2309 } 2310 if (LocaleCompare("flop",option+1) == 0) 2311 { 2312 new_image=FlopImage(_image,_exception); 2313 break; 2314 } 2315 if (LocaleCompare("floodfill",option+1) == 0) 2316 { 2317 PixelInfo 2318 target; 2319 2320 if (IfMagickFalse(IsGeometry(arg1))) 2321 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2322 (void) ParsePageGeometry(_image,arg1,&geometry,_exception); 2323 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception); 2324 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x, 2325 geometry.y,IsPlusOp,_exception); 2326 break; 2327 } 2328 if (LocaleCompare("frame",option+1) == 0) 2329 { 2330 FrameInfo 2331 frame_info; 2332 2333 CompositeOperator 2334 compose; 2335 2336 const char* 2337 value; 2338 2339 value=GetImageOption(_image_info,"compose"); 2340 compose=OverCompositeOp; /* use Over not _image->compose */ 2341 if (value != (const char *) NULL) 2342 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions, 2343 MagickFalse,value); 2344 if (IfMagickFalse(IsGeometry(arg1))) 2345 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2346 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 2347 frame_info.width=geometry.width; 2348 frame_info.height=geometry.height; 2349 frame_info.outer_bevel=geometry.x; 2350 frame_info.inner_bevel=geometry.y; 2351 frame_info.x=(ssize_t) frame_info.width; 2352 frame_info.y=(ssize_t) frame_info.height; 2353 frame_info.width=_image->columns+2*frame_info.width; 2354 frame_info.height=_image->rows+2*frame_info.height; 2355 new_image=FrameImage(_image,&frame_info,compose,_exception); 2356 break; 2357 } 2358 if (LocaleCompare("function",option+1) == 0) 2359 { 2360 double 2361 *args; 2362 2363 ssize_t 2364 count; 2365 2366 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1); 2367 if ( parse < 0 ) 2368 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction", 2369 option,arg1); 2370 /* convert argument string into an array of doubles */ 2371 args = StringToArrayOfDoubles(arg2,&count,_exception); 2372 if (args == (double *)NULL ) 2373 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2); 2374 2375 (void) FunctionImage(_image,(MagickFunction)parse,count,args, 2376 _exception); 2377 args=(double *) RelinquishMagickMemory(args); 2378 break; 2379 } 2380 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2381 } 2382 case 'g': 2383 { 2384 if (LocaleCompare("gamma",option+1) == 0) 2385 { 2386 double 2387 constant; 2388 2389 if (IfMagickFalse(IsGeometry(arg1))) 2390 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2391 constant=StringToDouble(arg1,(char **) NULL); 2392#if 0 2393 /* Using Gamma, via a cache */ 2394 if (IfPlusOp) 2395 constant=PerceptibleReciprocal(constant); 2396 (void) GammaImage(_image,constant,_exception); 2397#else 2398 /* Using Evaluate POW, direct update of values - more accurite */ 2399 if (IfNormalOp) 2400 constant=PerceptibleReciprocal(constant); 2401 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception); 2402#endif 2403 /* Set gamma setting -- Old meaning of "+gamma" 2404 * _image->gamma=StringToDouble(arg1,(char **) NULL); 2405 */ 2406 break; 2407 } 2408 if (LocaleCompare("gaussian-blur",option+1) == 0) 2409 { 2410 flags=ParseGeometry(arg1,&geometry_info); 2411 if ((flags & (RhoValue|SigmaValue)) == 0) 2412 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2413 if ((flags & SigmaValue) == 0) 2414 geometry_info.sigma=1.0; 2415 new_image=GaussianBlurImage(_image,geometry_info.rho, 2416 geometry_info.sigma,_exception); 2417 break; 2418 } 2419 if (LocaleCompare("gaussian",option+1) == 0) 2420 { 2421 CLIWandWarnReplaced("-gaussian-blur"); 2422 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL); 2423 } 2424 if (LocaleCompare("geometry",option+1) == 0) 2425 { 2426 /* 2427 Record Image offset for composition. (A Setting) 2428 Resize last _image. (ListOperator) -- DEPRECIATE 2429 FUTURE: Why if no 'offset' does this resize ALL images? 2430 Also why is the setting recorded in the IMAGE non-sense! 2431 */ 2432 if (IfPlusOp) 2433 { /* remove the previous composition geometry offset! */ 2434 if (_image->geometry != (char *) NULL) 2435 _image->geometry=DestroyString(_image->geometry); 2436 break; 2437 } 2438 if (IfMagickFalse(IsGeometry(arg1))) 2439 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2440 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception); 2441 if (((flags & XValue) != 0) || ((flags & YValue) != 0)) 2442 (void) CloneString(&_image->geometry,arg1); 2443 else 2444 new_image=ResizeImage(_image,geometry.width,geometry.height, 2445 _image->filter,_exception); 2446 break; 2447 } 2448 if (LocaleCompare("grayscale",option+1) == 0) 2449 { 2450 parse=ParseCommandOption(MagickPixelIntensityOptions, 2451 MagickFalse,arg1); 2452 if (parse < 0) 2453 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod", 2454 option,arg1); 2455 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception); 2456 break; 2457 } 2458 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2459 } 2460 case 'i': 2461 { 2462 if (LocaleCompare("identify",option+1) == 0) 2463 { 2464 const char 2465 *format, 2466 *text; 2467 2468 format=GetImageOption(_image_info,"format"); 2469 if (format == (char *) NULL) 2470 { 2471 (void) IdentifyImage(_image,stdout,_image_info->verbose, 2472 _exception); 2473 break; 2474 } 2475 text=InterpretImageProperties(_image_info,_image,format,_exception); 2476 if (text == (char *) NULL) 2477 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure", 2478 option); 2479 (void) fputs(text,stdout); 2480 text=DestroyString((char *)text); 2481 break; 2482 } 2483 if (LocaleCompare("implode",option+1) == 0) 2484 { 2485 flags=ParseGeometry(arg1,&geometry_info); 2486 if ((flags & RhoValue) == 0) 2487 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2488 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate, 2489 _exception); 2490 break; 2491 } 2492 if (LocaleCompare("interpolative-resize",option+1) == 0) 2493 { 2494 /* FUTURE: New to IMv7 2495 Roll into a resize special operator */ 2496 if (IfMagickFalse(IsGeometry(arg1))) 2497 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2498 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 2499 new_image=InterpolativeResizeImage(_image,geometry.width, 2500 geometry.height,_image->interpolate,_exception); 2501 break; 2502 } 2503 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2504 } 2505 case 'l': 2506 { 2507 if (LocaleCompare("lat",option+1) == 0) 2508 { 2509 flags=ParseGeometry(arg1,&geometry_info); 2510 if ((flags & (RhoValue|SigmaValue)) == 0) 2511 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2512 if ((flags & SigmaValue) == 0) 2513 geometry_info.sigma=1.0; 2514 if ((flags & PercentValue) != 0) 2515 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0; 2516 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho, 2517 (size_t) geometry_info.sigma,(double) geometry_info.xi, 2518 _exception); 2519 break; 2520 } 2521 if (LocaleCompare("level",option+1) == 0) 2522 { 2523 double 2524 black_point, 2525 gamma, 2526 white_point; 2527 2528 MagickStatusType 2529 flags; 2530 2531 flags=ParseGeometry(arg1,&geometry_info); 2532 if ((flags & RhoValue) == 0) 2533 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2534 black_point=geometry_info.rho; 2535 white_point=(double) QuantumRange; 2536 if ((flags & SigmaValue) != 0) 2537 white_point=geometry_info.sigma; 2538 gamma=1.0; 2539 if ((flags & XiValue) != 0) 2540 gamma=geometry_info.xi; 2541 if ((flags & PercentValue) != 0) 2542 { 2543 black_point*=(double) (QuantumRange/100.0); 2544 white_point*=(double) (QuantumRange/100.0); 2545 } 2546 if ((flags & SigmaValue) == 0) 2547 white_point=(double) QuantumRange-black_point; 2548 if (IfPlusOp || ((flags & AspectValue) != 0)) 2549 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception); 2550 else 2551 (void) LevelImage(_image,black_point,white_point,gamma,_exception); 2552 break; 2553 } 2554 if (LocaleCompare("level-colors",option+1) == 0) 2555 { 2556 char 2557 token[MaxTextExtent]; 2558 2559 const char 2560 *p; 2561 2562 PixelInfo 2563 black_point, 2564 white_point; 2565 2566 p=(const char *) arg1; 2567 GetMagickToken(p,&p,token); /* get black point color */ 2568 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0)) 2569 (void) QueryColorCompliance(token,AllCompliance, 2570 &black_point,_exception); 2571 else 2572 (void) QueryColorCompliance("#000000",AllCompliance, 2573 &black_point,_exception); 2574 if (isalpha((int) token[0]) || (token[0] == '#')) 2575 GetMagickToken(p,&p,token); 2576 if (*token == '\0') 2577 white_point=black_point; /* set everything to that color */ 2578 else 2579 { 2580 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0)) 2581 GetMagickToken(p,&p,token); /* Get white point color. */ 2582 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0)) 2583 (void) QueryColorCompliance(token,AllCompliance, 2584 &white_point,_exception); 2585 else 2586 (void) QueryColorCompliance("#ffffff",AllCompliance, 2587 &white_point,_exception); 2588 } 2589 (void) LevelImageColors(_image,&black_point,&white_point, 2590 IsPlusOp,_exception); 2591 break; 2592 } 2593 if (LocaleCompare("linear-stretch",option+1) == 0) 2594 { 2595 double 2596 black_point, 2597 white_point; 2598 2599 MagickStatusType 2600 flags; 2601 2602 flags=ParseGeometry(arg1,&geometry_info); 2603 if ((flags & RhoValue) == 0) 2604 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2605 black_point=geometry_info.rho; 2606 white_point=(double) _image->columns*_image->rows; 2607 if ((flags & SigmaValue) != 0) 2608 white_point=geometry_info.sigma; 2609 if ((flags & PercentValue) != 0) 2610 { 2611 black_point*=(double) _image->columns*_image->rows/100.0; 2612 white_point*=(double) _image->columns*_image->rows/100.0; 2613 } 2614 if ((flags & SigmaValue) == 0) 2615 white_point=(double) _image->columns*_image->rows- 2616 black_point; 2617 (void) LinearStretchImage(_image,black_point,white_point,_exception); 2618 break; 2619 } 2620 if (LocaleCompare("liquid-rescale",option+1) == 0) 2621 { 2622 /* FUTURE: Roll into a resize special operator */ 2623 if (IfMagickFalse(IsGeometry(arg1))) 2624 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2625 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception); 2626 if ((flags & XValue) == 0) 2627 geometry.x=1; 2628 if ((flags & YValue) == 0) 2629 geometry.y=0; 2630 new_image=LiquidRescaleImage(_image,geometry.width, 2631 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception); 2632 break; 2633 } 2634 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2635 } 2636 case 'm': 2637 { 2638 if (LocaleCompare("magnify",option+1) == 0) 2639 { 2640 new_image=MagnifyImage(_image,_exception); 2641 break; 2642 } 2643 if (LocaleCompare("map",option+1) == 0) 2644 { 2645 CLIWandWarnReplaced("-remap"); 2646 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL); 2647 break; 2648 } 2649 if (LocaleCompare("mask",option+1) == 0) 2650 { 2651 /* Note: arguments do not have percent escapes expanded */ 2652 Image 2653 *mask; 2654 2655 if (IfPlusOp) 2656 { /* Remove a mask. */ 2657 (void) SetImageMask(_image,(Image *) NULL,_exception); 2658 break; 2659 } 2660 /* Set the image mask. */ 2661 mask=GetImageCache(_image_info,arg1,_exception); 2662 if (mask == (Image *) NULL) 2663 break; 2664 (void) SetImageMask(_image,mask,_exception); 2665 mask=DestroyImage(mask); 2666 break; 2667 } 2668 if (LocaleCompare("matte",option+1) == 0) 2669 { 2670 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off"); 2671 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel : 2672 DeactivateAlphaChannel, _exception); 2673 break; 2674 } 2675 if (LocaleCompare("median",option+1) == 0) 2676 { 2677 CLIWandWarnReplaced("-statistic Median"); 2678 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1); 2679 break; 2680 } 2681 if (LocaleCompare("mode",option+1) == 0) 2682 { 2683 /* FUTURE: note this is also a special "montage" option */ 2684 CLIWandWarnReplaced("-statistic Mode"); 2685 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1); 2686 break; 2687 } 2688 if (LocaleCompare("modulate",option+1) == 0) 2689 { 2690 if (IfMagickFalse(IsGeometry(arg1))) 2691 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2692 (void) ModulateImage(_image,arg1,_exception); 2693 break; 2694 } 2695 if (LocaleCompare("monitor",option+1) == 0) 2696 { 2697 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress : 2698 (MagickProgressMonitor) NULL,(void *) NULL); 2699 break; 2700 } 2701 if (LocaleCompare("monochrome",option+1) == 0) 2702 { 2703 (void) SetImageType(_image,BilevelType,_exception); 2704 break; 2705 } 2706 if (LocaleCompare("morphology",option+1) == 0) 2707 { 2708 char 2709 token[MaxTextExtent]; 2710 2711 const char 2712 *p; 2713 2714 KernelInfo 2715 *kernel; 2716 2717 ssize_t 2718 iterations; 2719 2720 p=arg1; 2721 GetMagickToken(p,&p,token); 2722 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token); 2723 if ( parse < 0 ) 2724 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction", 2725 option,arg1); 2726 iterations=1L; 2727 GetMagickToken(p,&p,token); 2728 if ((*p == ':') || (*p == ',')) 2729 GetMagickToken(p,&p,token); 2730 if ((*p != '\0')) 2731 iterations=(ssize_t) StringToLong(p); 2732 kernel=AcquireKernelInfo(arg2); 2733 if (kernel == (KernelInfo *) NULL) 2734 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel", 2735 option,arg2); 2736 new_image=MorphologyImage(_image,(MorphologyMethod)parse, 2737 iterations,kernel,_exception); 2738 kernel=DestroyKernelInfo(kernel); 2739 break; 2740 } 2741 if (LocaleCompare("motion-blur",option+1) == 0) 2742 { 2743 flags=ParseGeometry(arg1,&geometry_info); 2744 if ((flags & (RhoValue|SigmaValue)) == 0) 2745 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2746 if ((flags & SigmaValue) == 0) 2747 geometry_info.sigma=1.0; 2748 new_image=MotionBlurImage(_image,geometry_info.rho, 2749 geometry_info.sigma,geometry_info.xi,_exception); 2750 break; 2751 } 2752 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2753 } 2754 case 'n': 2755 { 2756 if (LocaleCompare("negate",option+1) == 0) 2757 { 2758 (void) NegateImage(_image, IsPlusOp, _exception); 2759 break; 2760 } 2761 if (LocaleCompare("noise",option+1) == 0) 2762 { 2763 double 2764 attenuate; 2765 2766 const char* 2767 value; 2768 2769 if (IfNormalOp) 2770 { 2771 CLIWandWarnReplaced("-statistic NonPeak"); 2772 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1); 2773 break; 2774 } 2775 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1); 2776 if ( parse < 0 ) 2777 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType", 2778 option,arg1); 2779 attenuate=1.0; 2780 value=GetImageOption(_image_info,"attenuate"); 2781 if (value != (const char *) NULL) 2782 attenuate=StringToDouble(value,(char **) NULL); 2783 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate, 2784 _exception); 2785 break; 2786 } 2787 if (LocaleCompare("normalize",option+1) == 0) 2788 { 2789 (void) NormalizeImage(_image,_exception); 2790 break; 2791 } 2792 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2793 } 2794 case 'o': 2795 { 2796 if (LocaleCompare("opaque",option+1) == 0) 2797 { 2798 PixelInfo 2799 target; 2800 2801 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception); 2802 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp, 2803 _exception); 2804 break; 2805 } 2806 if (LocaleCompare("ordered-dither",option+1) == 0) 2807 { 2808 (void) OrderedPosterizeImage(_image,arg1,_exception); 2809 break; 2810 } 2811 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2812 } 2813 case 'p': 2814 { 2815 if (LocaleCompare("paint",option+1) == 0) 2816 { 2817 flags=ParseGeometry(arg1,&geometry_info); 2818 if ((flags & (RhoValue|SigmaValue)) == 0) 2819 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2820 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma, 2821 _exception); 2822 break; 2823 } 2824 if (LocaleCompare("perceptible",option+1) == 0) 2825 { 2826 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL), 2827 _exception); 2828 break; 2829 } 2830 if (LocaleCompare("polaroid",option+1) == 0) 2831 { 2832 const char 2833 *caption; 2834 2835 double 2836 angle; 2837 2838 if (IfPlusOp) { 2839 RandomInfo 2840 *random_info; 2841 2842 random_info=AcquireRandomInfo(); 2843 angle=22.5*(GetPseudoRandomValue(random_info)-0.5); 2844 random_info=DestroyRandomInfo(random_info); 2845 } 2846 else { 2847 flags=ParseGeometry(arg1,&geometry_info); 2848 if ((flags & RhoValue) == 0) 2849 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2850 angle=geometry_info.rho; 2851 } 2852 caption=GetImageProperty(_image,"caption",_exception); 2853 new_image=PolaroidImage(_image,_draw_info,caption,angle, 2854 _image->interpolate,_exception); 2855 break; 2856 } 2857 if (LocaleCompare("posterize",option+1) == 0) 2858 { 2859 flags=ParseGeometry(arg1,&geometry_info); 2860 if ((flags & RhoValue) == 0) 2861 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2862 (void) PosterizeImage(_image,(size_t) geometry_info.rho, 2863 _quantize_info->dither_method,_exception); 2864 break; 2865 } 2866 if (LocaleCompare("preview",option+1) == 0) 2867 { 2868 /* FUTURE: should be a 'Genesis' option? 2869 Option however is also in WandSettingOptionInfo() 2870 Why??? 2871 */ 2872 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1); 2873 if ( parse < 0 ) 2874 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType", 2875 option,arg1); 2876 new_image=PreviewImage(_image,(PreviewType)parse,_exception); 2877 break; 2878 } 2879 if (LocaleCompare("profile",option+1) == 0) 2880 { 2881 /* Note: arguments do not have percent escapes expanded */ 2882 const char 2883 *name; 2884 2885 const StringInfo 2886 *profile; 2887 2888 Image 2889 *profile_image; 2890 2891 ImageInfo 2892 *profile_info; 2893 2894 if (IfPlusOp) 2895 { /* Remove a profile from the _image. */ 2896 (void) ProfileImage(_image,arg1,(const unsigned char *) 2897 NULL,0,_exception); 2898 break; 2899 } 2900 /* Associate a profile with the _image. */ 2901 profile_info=CloneImageInfo(_image_info); 2902 profile=GetImageProfile(_image,"iptc"); 2903 if (profile != (StringInfo *) NULL) 2904 profile_info->profile=(void *) CloneStringInfo(profile); 2905 profile_image=GetImageCache(profile_info,arg1,_exception); 2906 profile_info=DestroyImageInfo(profile_info); 2907 if (profile_image == (Image *) NULL) 2908 { 2909 StringInfo 2910 *profile; 2911 2912 profile_info=CloneImageInfo(_image_info); 2913 (void) CopyMagickString(profile_info->filename,arg1, 2914 MaxTextExtent); 2915 profile=FileToStringInfo(profile_info->filename,~0UL,_exception); 2916 if (profile != (StringInfo *) NULL) 2917 { 2918 (void) ProfileImage(_image,profile_info->magick, 2919 GetStringInfoDatum(profile),(size_t) 2920 GetStringInfoLength(profile),_exception); 2921 profile=DestroyStringInfo(profile); 2922 } 2923 profile_info=DestroyImageInfo(profile_info); 2924 break; 2925 } 2926 ResetImageProfileIterator(profile_image); 2927 name=GetNextImageProfile(profile_image); 2928 while (name != (const char *) NULL) 2929 { 2930 profile=GetImageProfile(profile_image,name); 2931 if (profile != (StringInfo *) NULL) 2932 (void) ProfileImage(_image,name,GetStringInfoDatum(profile), 2933 (size_t) GetStringInfoLength(profile),_exception); 2934 name=GetNextImageProfile(profile_image); 2935 } 2936 profile_image=DestroyImage(profile_image); 2937 break; 2938 } 2939 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2940 } 2941 case 'r': 2942 { 2943 if (LocaleCompare("radial-blur",option+1) == 0) 2944 { 2945 flags=ParseGeometry(arg1,&geometry_info); 2946 if ((flags & RhoValue) == 0) 2947 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2948 new_image=RadialBlurImage(_image,geometry_info.rho,_exception); 2949 break; 2950 } 2951 if (LocaleCompare("raise",option+1) == 0) 2952 { 2953 if (IfMagickFalse(IsGeometry(arg1))) 2954 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2955 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 2956 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception); 2957 break; 2958 } 2959 if (LocaleCompare("random-threshold",option+1) == 0) 2960 { 2961 if (IfMagickFalse(IsGeometry(arg1))) 2962 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2963 (void) RandomThresholdImage(_image,arg1,_exception); 2964 break; 2965 } 2966 if (LocaleCompare("recolor",option+1) == 0) 2967 { 2968 CLIWandWarnReplaced("-color-matrix"); 2969 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL); 2970 } 2971 if (LocaleCompare("remap",option+1) == 0) 2972 { 2973 /* Note: arguments do not have percent escapes expanded */ 2974 Image 2975 *remap_image; 2976 2977 remap_image=GetImageCache(_image_info,arg1,_exception); 2978 if (remap_image == (Image *) NULL) 2979 break; 2980 (void) RemapImage(_quantize_info,_image,remap_image,_exception); 2981 remap_image=DestroyImage(remap_image); 2982 break; 2983 } 2984 if (LocaleCompare("repage",option+1) == 0) 2985 { 2986 if (IfNormalOp) 2987 { 2988 if (IfMagickFalse(IsGeometry(arg1))) 2989 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option, 2990 arg1); 2991 (void) ResetImagePage(_image,arg1); 2992 } 2993 else 2994 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page); 2995 break; 2996 } 2997 if (LocaleCompare("resample",option+1) == 0) 2998 { 2999 /* FUTURE: Roll into a resize special operation */ 3000 flags=ParseGeometry(arg1,&geometry_info); 3001 if ((flags & (RhoValue|SigmaValue)) == 0) 3002 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3003 if ((flags & SigmaValue) == 0) 3004 geometry_info.sigma=geometry_info.rho; 3005 new_image=ResampleImage(_image,geometry_info.rho, 3006 geometry_info.sigma,_image->filter,_exception); 3007 break; 3008 } 3009 if (LocaleCompare("resize",option+1) == 0) 3010 { 3011 if (IfMagickFalse(IsGeometry(arg1))) 3012 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3013 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 3014 new_image=ResizeImage(_image,geometry.width,geometry.height, 3015 _image->filter,_exception); 3016 break; 3017 } 3018 if (LocaleCompare("roll",option+1) == 0) 3019 { 3020 if (IfMagickFalse(IsGeometry(arg1))) 3021 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3022 (void) ParsePageGeometry(_image,arg1,&geometry,_exception); 3023 new_image=RollImage(_image,geometry.x,geometry.y,_exception); 3024 break; 3025 } 3026 if (LocaleCompare("rotate",option+1) == 0) 3027 { 3028 flags=ParseGeometry(arg1,&geometry_info); 3029 if ((flags & RhoValue) == 0) 3030 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3031 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows)) 3032 break; 3033 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows)) 3034 break; 3035 new_image=RotateImage(_image,geometry_info.rho,_exception); 3036 break; 3037 } 3038 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3039 } 3040 case 's': 3041 { 3042 if (LocaleCompare("sample",option+1) == 0) 3043 { 3044 /* FUTURE: Roll into a resize special operator */ 3045 if (IfMagickFalse(IsGeometry(arg1))) 3046 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3047 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 3048 new_image=SampleImage(_image,geometry.width,geometry.height, 3049 _exception); 3050 break; 3051 } 3052 if (LocaleCompare("scale",option+1) == 0) 3053 { 3054 /* FUTURE: Roll into a resize special operator */ 3055 if (IfMagickFalse(IsGeometry(arg1))) 3056 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3057 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 3058 new_image=ScaleImage(_image,geometry.width,geometry.height, 3059 _exception); 3060 break; 3061 } 3062 if (LocaleCompare("segment",option+1) == 0) 3063 { 3064 flags=ParseGeometry(arg1,&geometry_info); 3065 if ((flags & (RhoValue|SigmaValue)) == 0) 3066 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3067 if ((flags & SigmaValue) == 0) 3068 geometry_info.sigma=1.0; 3069 (void) SegmentImage(_image,_image->colorspace, 3070 _image_info->verbose,geometry_info.rho,geometry_info.sigma, 3071 _exception); 3072 break; 3073 } 3074 if (LocaleCompare("selective-blur",option+1) == 0) 3075 { 3076 flags=ParseGeometry(arg1,&geometry_info); 3077 if ((flags & (RhoValue|SigmaValue)) == 0) 3078 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3079 if ((flags & SigmaValue) == 0) 3080 geometry_info.sigma=1.0; 3081 if ((flags & PercentValue) != 0) 3082 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0; 3083 new_image=SelectiveBlurImage(_image,geometry_info.rho, 3084 geometry_info.sigma,geometry_info.xi,_exception); 3085 break; 3086 } 3087 if (LocaleCompare("separate",option+1) == 0) 3088 { 3089 /* WARNING: This can generate multiple images! */ 3090 /* FUTURE - this may be replaced by a "-channel" method */ 3091 new_image=SeparateImages(_image,_exception); 3092 break; 3093 } 3094 if (LocaleCompare("sepia-tone",option+1) == 0) 3095 { 3096 if (IfMagickFalse(IsGeometry(arg1))) 3097 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3098 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1, 3099 (double) QuantumRange+1.0),_exception); 3100 break; 3101 } 3102 if (LocaleCompare("shade",option+1) == 0) 3103 { 3104 flags=ParseGeometry(arg1,&geometry_info); 3105 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0)) 3106 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3107 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho, 3108 geometry_info.sigma,_exception); 3109 break; 3110 } 3111 if (LocaleCompare("shadow",option+1) == 0) 3112 { 3113 flags=ParseGeometry(arg1,&geometry_info); 3114 if ((flags & (RhoValue|SigmaValue)) == 0) 3115 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3116 if ((flags & SigmaValue) == 0) 3117 geometry_info.sigma=1.0; 3118 if ((flags & XiValue) == 0) 3119 geometry_info.xi=4.0; 3120 if ((flags & PsiValue) == 0) 3121 geometry_info.psi=4.0; 3122 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma, 3123 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) 3124 ceil(geometry_info.psi-0.5),_exception); 3125 break; 3126 } 3127 if (LocaleCompare("sharpen",option+1) == 0) 3128 { 3129 flags=ParseGeometry(arg1,&geometry_info); 3130 if ((flags & (RhoValue|SigmaValue)) == 0) 3131 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3132 if ((flags & SigmaValue) == 0) 3133 geometry_info.sigma=1.0; 3134 if ((flags & XiValue) == 0) 3135 geometry_info.xi=0.0; 3136 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma, 3137 _exception); 3138 break; 3139 } 3140 if (LocaleCompare("shave",option+1) == 0) 3141 { 3142 if (IfMagickFalse(IsGeometry(arg1))) 3143 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3144 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 3145 new_image=ShaveImage(_image,&geometry,_exception); 3146 break; 3147 } 3148 if (LocaleCompare("shear",option+1) == 0) 3149 { 3150 flags=ParseGeometry(arg1,&geometry_info); 3151 if ((flags & RhoValue) == 0) 3152 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3153 if ((flags & SigmaValue) == 0) 3154 geometry_info.sigma=geometry_info.rho; 3155 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma, 3156 _exception); 3157 break; 3158 } 3159 if (LocaleCompare("sigmoidal-contrast",option+1) == 0) 3160 { 3161 flags=ParseGeometry(arg1,&geometry_info); 3162 if ((flags & RhoValue) == 0) 3163 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3164 if ((flags & SigmaValue) == 0) 3165 geometry_info.sigma=(double) QuantumRange/2.0; 3166 if ((flags & PercentValue) != 0) 3167 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/ 3168 100.0; 3169 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho, 3170 geometry_info.sigma,_exception); 3171 break; 3172 } 3173 if (LocaleCompare("sketch",option+1) == 0) 3174 { 3175 flags=ParseGeometry(arg1,&geometry_info); 3176 if ((flags & (RhoValue|SigmaValue)) == 0) 3177 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3178 if ((flags & SigmaValue) == 0) 3179 geometry_info.sigma=1.0; 3180 new_image=SketchImage(_image,geometry_info.rho, 3181 geometry_info.sigma,geometry_info.xi,_exception); 3182 break; 3183 } 3184 if (LocaleCompare("solarize",option+1) == 0) 3185 { 3186 if (IfMagickFalse(IsGeometry(arg1))) 3187 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3188 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double) 3189 QuantumRange+1.0),_exception); 3190 break; 3191 } 3192 if (LocaleCompare("sparse-color",option+1) == 0) 3193 { 3194 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1); 3195 if ( parse < 0 ) 3196 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod", 3197 option,arg1); 3198 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2, 3199 _exception); 3200 break; 3201 } 3202 if (LocaleCompare("splice",option+1) == 0) 3203 { 3204 if (IfMagickFalse(IsGeometry(arg1))) 3205 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3206 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception); 3207 new_image=SpliceImage(_image,&geometry,_exception); 3208 break; 3209 } 3210 if (LocaleCompare("spread",option+1) == 0) 3211 { 3212 flags=ParseGeometry(arg1,&geometry_info); 3213 if ((flags & RhoValue) == 0) 3214 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 3215 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate, 3216 _exception); 3217 break; 3218 } 3219 if (LocaleCompare("statistic",option+1) == 0) 3220 { 3221 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1); 3222 if ( parse < 0 ) 3223 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType", 3224 option,arg1); 3225 flags=ParseGeometry(arg2,&geometry_info); 3226 if ((flags & RhoValue) == 0) 3227 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 3228 if ((flags & SigmaValue) == 0) 3229 geometry_info.sigma=geometry_info.rho; 3230 new_image=StatisticImage(_image,(StatisticType)parse, 3231 (size_t) geometry_info.rho,(size_t) geometry_info.sigma, 3232 _exception); 3233 break; 3234 } 3235 if (LocaleCompare("strip",option+1) == 0) 3236 { 3237 (void) StripImage(_image,_exception); 3238 break; 3239 } 3240 if (LocaleCompare("swirl",option+1) == 0) 3241 { 3242 flags=ParseGeometry(arg1,&geometry_info); 3243 if ((flags & RhoValue) == 0) 3244 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3245 new_image=SwirlImage(_image,geometry_info.rho, 3246 _image->interpolate,_exception); 3247 break; 3248 } 3249 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3250 } 3251 case 't': 3252 { 3253 if (LocaleCompare("threshold",option+1) == 0) 3254 { 3255 double 3256 threshold; 3257 3258 threshold=(double) QuantumRange/2; 3259 if (IfNormalOp) { 3260 if (IfMagickFalse(IsGeometry(arg1))) 3261 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3262 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0); 3263 } 3264 (void) BilevelImage(_image,threshold,_exception); 3265 break; 3266 } 3267 if (LocaleCompare("thumbnail",option+1) == 0) 3268 { 3269 if (IfMagickFalse(IsGeometry(arg1))) 3270 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3271 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 3272 new_image=ThumbnailImage(_image,geometry.width,geometry.height, 3273 _exception); 3274 break; 3275 } 3276 if (LocaleCompare("tint",option+1) == 0) 3277 { 3278 if (IfMagickFalse(IsGeometry(arg1))) 3279 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3280 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception); 3281 break; 3282 } 3283 if (LocaleCompare("transform",option+1) == 0) 3284 { 3285 CLIWandWarnReplaced("+distort AffineProjection"); 3286 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception); 3287 break; 3288 } 3289 if (LocaleCompare("transparent",option+1) == 0) 3290 { 3291 PixelInfo 3292 target; 3293 3294 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception); 3295 (void) TransparentPaintImage(_image,&target,(Quantum) 3296 TransparentAlpha,IsPlusOp,_exception); 3297 break; 3298 } 3299 if (LocaleCompare("transpose",option+1) == 0) 3300 { 3301 new_image=TransposeImage(_image,_exception); 3302 break; 3303 } 3304 if (LocaleCompare("transverse",option+1) == 0) 3305 { 3306 new_image=TransverseImage(_image,_exception); 3307 break; 3308 } 3309 if (LocaleCompare("trim",option+1) == 0) 3310 { 3311 new_image=TrimImage(_image,_exception); 3312 break; 3313 } 3314 if (LocaleCompare("type",option+1) == 0) 3315 { 3316 /* Note that "type" setting should have already been defined */ 3317 (void) SetImageType(_image,_image_info->type,_exception); 3318 break; 3319 } 3320 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3321 } 3322 case 'u': 3323 { 3324 if (LocaleCompare("unique",option+1) == 0) 3325 { 3326 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? 3327 Option is not documented, bt appears to be for "identify". 3328 We may need a identify specific verbose! 3329 */ 3330 if (IsPlusOp) { 3331 (void) DeleteImageArtifact(_image,"identify:unique-colors"); 3332 break; 3333 } 3334 (void) SetImageArtifact(_image,"identify:unique-colors","true"); 3335 (void) SetImageArtifact(_image,"verbose","true"); 3336 break; 3337 } 3338 if (LocaleCompare("unique-colors",option+1) == 0) 3339 { 3340 new_image=UniqueImageColors(_image,_exception); 3341 break; 3342 } 3343 if (LocaleCompare("unsharp",option+1) == 0) 3344 { 3345 flags=ParseGeometry(arg1,&geometry_info); 3346 if ((flags & (RhoValue|SigmaValue)) == 0) 3347 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3348 if ((flags & SigmaValue) == 0) 3349 geometry_info.sigma=1.0; 3350 if ((flags & XiValue) == 0) 3351 geometry_info.xi=1.0; 3352 if ((flags & PsiValue) == 0) 3353 geometry_info.psi=0.05; 3354 new_image=UnsharpMaskImage(_image,geometry_info.rho, 3355 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception); 3356 break; 3357 } 3358 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3359 } 3360 case 'v': 3361 { 3362 if (LocaleCompare("verbose",option+1) == 0) 3363 { 3364 /* FUTURE: move to SyncImageSettings() and AcquireImage()??? 3365 three places! ImageArtifact ImageOption _image_info->verbose 3366 Some how new images also get this artifact! 3367 */ 3368 (void) SetImageArtifact(_image,option+1, 3369 IfNormalOp ? "true" : "false" ); 3370 break; 3371 } 3372 if (LocaleCompare("vignette",option+1) == 0) 3373 { 3374 flags=ParseGeometry(arg1,&geometry_info); 3375 if ((flags & (RhoValue|SigmaValue)) == 0) 3376 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3377 if ((flags & SigmaValue) == 0) 3378 geometry_info.sigma=1.0; 3379 if ((flags & XiValue) == 0) 3380 geometry_info.xi=0.1*_image->columns; 3381 if ((flags & PsiValue) == 0) 3382 geometry_info.psi=0.1*_image->rows; 3383 if ((flags & PercentValue) != 0) 3384 { 3385 geometry_info.xi*=(double) _image->columns/100.0; 3386 geometry_info.psi*=(double) _image->rows/100.0; 3387 } 3388 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma, 3389 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) 3390 ceil(geometry_info.psi-0.5),_exception); 3391 break; 3392 } 3393 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3394 } 3395 case 'w': 3396 { 3397 if (LocaleCompare("wave",option+1) == 0) 3398 { 3399 flags=ParseGeometry(arg1,&geometry_info); 3400 if ((flags & (RhoValue|SigmaValue)) == 0) 3401 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3402 if ((flags & SigmaValue) == 0) 3403 geometry_info.sigma=1.0; 3404 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma, 3405 _image->interpolate,_exception); 3406 break; 3407 } 3408 if (LocaleCompare("white-threshold",option+1) == 0) 3409 { 3410 if (IfMagickFalse(IsGeometry(arg1))) 3411 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3412 (void) WhiteThresholdImage(_image,arg1,_exception); 3413 break; 3414 } 3415 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3416 } 3417 default: 3418 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3419 } 3420 /* clean up percent escape interpreted strings */ 3421 if (arg1 != arg1n ) 3422 arg1=DestroyString((char *)arg1); 3423 if (arg2 != arg2n ) 3424 arg2=DestroyString((char *)arg2); 3425 3426 /* Replace current image with any image that was generated 3427 and set image point to last image (so image->next is correct) */ 3428 if (new_image != (Image *) NULL) 3429 ReplaceImageInListReturnLast(&_image,new_image); 3430 3431 return(MagickTrue); 3432#undef _image_info 3433#undef _draw_info 3434#undef _quantize_info 3435#undef _image 3436#undef _exception 3437#undef IfNormalOp 3438#undef IfPlusOp 3439#undef IsNormalOp 3440#undef IsPlusOp 3441} 3442 3443WandPrivate MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand, 3444 const char *option,const char *arg1,const char *arg2) 3445{ 3446#if !USE_WAND_METHODS 3447 size_t 3448 n, 3449 i; 3450#endif 3451 3452 assert(cli_wand != (MagickCLI *) NULL); 3453 assert(cli_wand->signature == WandSignature); 3454 assert(cli_wand->wand.signature == WandSignature); 3455 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */ 3456 3457 if (IfMagickTrue(cli_wand->wand.debug)) 3458 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(), 3459 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2); 3460 3461#if !USE_WAND_METHODS 3462 /* FUTURE add appropriate tracing */ 3463 i=0; 3464 n=GetImageListLength(cli_wand->wand.images); 3465 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images); 3466 while (1) { 3467 i++; 3468 CLISimpleOperatorImage(cli_wand, option, arg1, arg2); 3469 if ( cli_wand->wand.images->next == (Image *) NULL ) 3470 break; 3471 cli_wand->wand.images=cli_wand->wand.images->next; 3472 } 3473 assert( i == n ); 3474 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images); 3475#else 3476 MagickResetIterator(&cli_wand->wand); 3477 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) ) 3478 CLISimpleOperatorImage(cli_wand, option, arg1, arg2); 3479 MagickResetIterator(&cli_wand->wand); 3480#endif 3481 return(MagickTrue); 3482} 3483 3484/* 3485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3486% % 3487% % 3488% % 3489+ C L I L i s t O p e r a t o r I m a g e s % 3490% % 3491% % 3492% % 3493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3494% 3495% CLIListOperatorImages() applies a single operation that is apply to the 3496% entire image list as a whole. The result is often a complete replacment 3497% of the image list with a completely new list, or with just a single image 3498% result. 3499% 3500% The format of the MogrifyImage method is: 3501% 3502% MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand, 3503% const char *option,const char *arg1,const char *arg2) 3504% 3505% A description of each parameter follows: 3506% 3507% o cli_wand: structure holding settings to be applied 3508% 3509% o option: The option string for the operation 3510% 3511% o arg1, arg2: optional argument strings to the operation 3512% arg2 is currently not used 3513% 3514*/ 3515WandPrivate MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand, 3516 const char *option,const char *arg1n,const char *arg2n) 3517{ 3518 const char /* percent escaped versions of the args */ 3519 *arg1, 3520 *arg2; 3521 3522 Image 3523 *new_images; 3524 3525 MagickStatusType 3526 status; 3527 3528 ssize_t 3529 parse; 3530 3531#define _image_info (cli_wand->wand.image_info) 3532#define _images (cli_wand->wand.images) 3533#define _exception (cli_wand->wand.exception) 3534#define _draw_info (cli_wand->draw_info) 3535#define _quantize_info (cli_wand->quantize_info) 3536#define _process_flags (cli_wand->process_flags) 3537#define _option_type ((CommandOptionFlags) cli_wand->command->flags) 3538#define IfNormalOp (*option=='-') 3539#define IfPlusOp (*option!='-') 3540#define IsNormalOp IsMagickTrue(IfNormalOp) 3541 3542 assert(cli_wand != (MagickCLI *) NULL); 3543 assert(cli_wand->signature == WandSignature); 3544 assert(cli_wand->wand.signature == WandSignature); 3545 assert(_images != (Image *) NULL); /* _images must be present */ 3546 3547 if (IfMagickTrue(cli_wand->wand.debug)) 3548 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(), 3549 "- List Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n); 3550 3551 arg1 = arg1n; 3552 arg2 = arg2n; 3553 3554 /* Interpret Percent Escapes in Arguments - using first image */ 3555 if ( (((_process_flags & ProcessInterpretProperities) != 0 ) 3556 || ((_option_type & AlwaysInterpretArgsFlag) != 0) 3557 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) { 3558 /* Interpret Percent escapes in argument 1 */ 3559 if (arg1n != (char *) NULL) { 3560 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception); 3561 if (arg1 == (char *) NULL) { 3562 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 3563 arg1=arg1n; /* use the given argument as is */ 3564 } 3565 } 3566 if (arg2n != (char *) NULL) { 3567 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception); 3568 if (arg2 == (char *) NULL) { 3569 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 3570 arg2=arg2n; /* use the given argument as is */ 3571 } 3572 } 3573 } 3574#undef _process_flags 3575#undef _option_type 3576 3577 status=MagickTrue; 3578 new_images=NewImageList(); 3579 3580 switch (*(option+1)) 3581 { 3582 case 'a': 3583 { 3584 if (LocaleCompare("append",option+1) == 0) 3585 { 3586 new_images=AppendImages(_images,IsNormalOp,_exception); 3587 break; 3588 } 3589 if (LocaleCompare("average",option+1) == 0) 3590 { 3591 CLIWandWarnReplaced("-evaluate-sequence Mean"); 3592 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL); 3593 break; 3594 } 3595 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3596 } 3597 case 'c': 3598 { 3599 if (LocaleCompare("channel-fx",option+1) == 0) 3600 { 3601 new_images=ChannelFxImage(_images,arg1,_exception); 3602 break; 3603 } 3604 if (LocaleCompare("clut",option+1) == 0) 3605 { 3606 Image 3607 *clut_image; 3608 3609 /* FUTURE - make this a compose option, and thus can be used 3610 with layers compose or even compose last image over all other 3611 _images. 3612 */ 3613 new_images=RemoveFirstImageFromList(&_images); 3614 clut_image=RemoveLastImageFromList(&_images); 3615 /* FUTURE - produce Exception, rather than silent fail */ 3616 if (clut_image == (Image *) NULL) 3617 break; 3618 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception); 3619 clut_image=DestroyImage(clut_image); 3620 break; 3621 } 3622 if (LocaleCompare("coalesce",option+1) == 0) 3623 { 3624 new_images=CoalesceImages(_images,_exception); 3625 break; 3626 } 3627 if (LocaleCompare("combine",option+1) == 0) 3628 { 3629 parse = (ssize_t) sRGBColorspace; /* default (backward compatible) */ 3630 if ( IfPlusOp ) 3631 parse = ParseCommandOption(MagickColorspaceOptions,MagickFalse, 3632 arg1); 3633 if (parse < 0) 3634 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option, 3635 arg1); 3636 new_images=CombineImages(_images,(ColorspaceType) parse,_exception); 3637 break; 3638 } 3639 if (LocaleCompare("compare",option+1) == 0) 3640 { 3641 double 3642 distortion; 3643 3644 Image 3645 *image, 3646 *reconstruct_image; 3647 3648 MetricType 3649 metric; 3650 3651 /* 3652 Mathematically and visually annotate the difference between an 3653 image and its reconstruction. 3654 */ 3655 image=RemoveFirstImageFromList(&_images); 3656 reconstruct_image=RemoveFirstImageFromList(&_images); 3657 /* FUTURE - produce Exception, rather than silent fail */ 3658 if (reconstruct_image == (Image *) NULL) 3659 break; 3660 metric=UndefinedErrorMetric; 3661 option=GetImageOption(_image_info,"metric"); 3662 if (option != (const char *) NULL) 3663 metric=(MetricType) ParseCommandOption(MagickMetricOptions, 3664 MagickFalse,option); 3665 new_images=CompareImages(image,reconstruct_image,metric,&distortion, 3666 _exception); 3667 (void) distortion; 3668 reconstruct_image=DestroyImage(reconstruct_image); 3669 image=DestroyImage(image); 3670 break; 3671 } 3672 if (LocaleCompare("complex",option+1) == 0) 3673 { 3674 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1); 3675 if (parse < 0) 3676 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator", 3677 option,arg1); 3678 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception); 3679 break; 3680 } 3681 if (LocaleCompare("composite",option+1) == 0) 3682 { 3683 CompositeOperator 3684 compose; 3685 3686 const char* 3687 value; 3688 3689 MagickBooleanType 3690 clip_to_self; 3691 3692 Image 3693 *mask_image, 3694 *source_image; 3695 3696 RectangleInfo 3697 geometry; 3698 3699 /* Compose value from "-compose" option only */ 3700 value=GetImageOption(_image_info,"compose"); 3701 if (value == (const char *) NULL) 3702 compose=OverCompositeOp; /* use Over not source_image->compose */ 3703 else 3704 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions, 3705 MagickFalse,value); 3706 3707 /* Get "clip-to-self" expert setting (false is normal) */ 3708 value=GetImageOption(_image_info,"compose:clip-to-self"); 3709 if (value == (const char *) NULL) 3710 clip_to_self=MagickTrue; 3711 else 3712 clip_to_self=IsStringTrue(GetImageOption(_image_info, 3713 "compose:clip-to-self")); /* if this is true */ 3714 value=GetImageOption(_image_info,"compose:outside-overlay"); 3715 if (value != (const char *) NULL) { /* or this false */ 3716 /* FUTURE: depreciate warning for "compose:outside-overlay"*/ 3717 clip_to_self= IsMagickFalse(IsStringNotFalse(value)); 3718 } 3719 3720 new_images=RemoveFirstImageFromList(&_images); 3721 source_image=RemoveFirstImageFromList(&_images); 3722 if (source_image == (Image *) NULL) 3723 break; /* FUTURE - produce Exception, rather than silent fail */ 3724 3725 /* FUTURE - this should not be here! - should be part of -geometry */ 3726 (void) TransformImage(&source_image,(char *) NULL, 3727 source_image->geometry,_exception); 3728 SetGeometry(source_image,&geometry); 3729 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry); 3730 GravityAdjustGeometry(new_images->columns,new_images->rows, 3731 new_images->gravity, &geometry); 3732 mask_image=RemoveFirstImageFromList(&_images); 3733 if (mask_image != (Image *) NULL) 3734 { 3735 if ((compose == DisplaceCompositeOp) || 3736 (compose == DistortCompositeOp)) 3737 status&=CompositeImage(source_image,mask_image, 3738 CopyGreenCompositeOp,MagickTrue,0,0,_exception); 3739 else 3740 { 3741 Image 3742 *image; 3743 3744 RectangleInfo 3745 source_geometry; 3746 3747 source_geometry.width=mask_image->columns; 3748 source_geometry.height=mask_image->rows; 3749 source_geometry.x=(-geometry.x); 3750 source_geometry.y=(-geometry.y); 3751 geometry.x=0; 3752 geometry.y=0; 3753 image=ExtentImage(source_image,&source_geometry,_exception); 3754 if (image != (Image *) NULL) 3755 { 3756 source_image=DestroyImage(source_image); 3757 source_image=image; 3758 } 3759 status&=CompositeImage(source_image,mask_image, 3760 IntensityCompositeOp,MagickTrue,0,0,_exception); 3761 } 3762 mask_image=DestroyImage(mask_image); 3763 } 3764 status&=CompositeImage(new_images,source_image,compose,clip_to_self, 3765 geometry.x,geometry.y,_exception); 3766 source_image=DestroyImage(source_image); 3767 break; 3768 } 3769 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3770 } 3771 case 'd': 3772 { 3773 if (LocaleCompare("deconstruct",option+1) == 0) 3774 { 3775 CLIWandWarnReplaced("-layer CompareAny"); 3776 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL); 3777 break; 3778 } 3779 if (LocaleCompare("delete",option+1) == 0) 3780 { 3781 if (IfNormalOp) 3782 DeleteImages(&_images,arg1,_exception); 3783 else 3784 DeleteImages(&_images,"-1",_exception); 3785 break; 3786 } 3787 if (LocaleCompare("duplicate",option+1) == 0) 3788 { 3789 if (IfNormalOp) 3790 { 3791 const char 3792 *p; 3793 3794 size_t 3795 number_duplicates; 3796 3797 if (IfMagickFalse(IsGeometry(arg1))) 3798 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option, 3799 arg1); 3800 number_duplicates=(size_t) StringToLong(arg1); 3801 p=strchr(arg1,','); 3802 if (p == (const char *) NULL) 3803 new_images=DuplicateImages(_images,number_duplicates,"-1", 3804 _exception); 3805 else 3806 new_images=DuplicateImages(_images,number_duplicates,p, 3807 _exception); 3808 } 3809 else 3810 new_images=DuplicateImages(_images,1,"-1",_exception); 3811 AppendImageToList(&_images, new_images); 3812 new_images=(Image *)NULL; 3813 break; 3814 } 3815 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3816 } 3817 case 'e': 3818 { 3819 if (LocaleCompare("evaluate-sequence",option+1) == 0) 3820 { 3821 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1); 3822 if (parse < 0) 3823 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator", 3824 option,arg1); 3825 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse, 3826 _exception); 3827 break; 3828 } 3829 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3830 } 3831 case 'f': 3832 { 3833 if (LocaleCompare("fft",option+1) == 0) 3834 { 3835 new_images=ForwardFourierTransformImage(_images,IsNormalOp,_exception); 3836 break; 3837 } 3838 if (LocaleCompare("flatten",option+1) == 0) 3839 { 3840 /* REDIRECTED to use -layers flatten instead */ 3841 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL); 3842 break; 3843 } 3844 if (LocaleCompare("fx",option+1) == 0) 3845 { 3846 new_images=FxImage(_images,arg1,_exception); 3847 break; 3848 } 3849 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3850 } 3851 case 'h': 3852 { 3853 if (LocaleCompare("hald-clut",option+1) == 0) 3854 { 3855 /* FUTURE - make this a compose option (and thus layers compose ) 3856 or perhaps compose last image over all other _images. 3857 */ 3858 Image 3859 *hald_image; 3860 3861 new_images=RemoveFirstImageFromList(&_images); 3862 hald_image=RemoveLastImageFromList(&_images); 3863 if (hald_image == (Image *) NULL) 3864 break; 3865 (void) HaldClutImage(new_images,hald_image,_exception); 3866 hald_image=DestroyImage(hald_image); 3867 break; 3868 } 3869 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3870 } 3871 case 'i': 3872 { 3873 if (LocaleCompare("ift",option+1) == 0) 3874 { 3875 Image 3876 *magnitude_image, 3877 *phase_image; 3878 3879 magnitude_image=RemoveFirstImageFromList(&_images); 3880 phase_image=RemoveFirstImageFromList(&_images); 3881 /* FUTURE - produce Exception, rather than silent fail */ 3882 if (phase_image == (Image *) NULL) 3883 break; 3884 new_images=InverseFourierTransformImage(magnitude_image,phase_image, 3885 IsNormalOp,_exception); 3886 magnitude_image=DestroyImage(magnitude_image); 3887 phase_image=DestroyImage(phase_image); 3888 break; 3889 } 3890 if (LocaleCompare("insert",option+1) == 0) 3891 { 3892 Image 3893 *insert_image, 3894 *index_image; 3895 3896 ssize_t 3897 index; 3898 3899 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1))) 3900 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3901 index=0; 3902 insert_image=RemoveLastImageFromList(&_images); 3903 if (IfNormalOp) 3904 index=(ssize_t) StringToLong(arg1); 3905 index_image=insert_image; 3906 if (index == 0) 3907 PrependImageToList(&_images,insert_image); 3908 else if (index == (ssize_t) GetImageListLength(_images)) 3909 AppendImageToList(&_images,insert_image); 3910 else 3911 { 3912 index_image=GetImageFromList(_images,index-1); 3913 if (index_image == (Image *) NULL) 3914 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1); 3915 InsertImageInList(&index_image,insert_image); 3916 } 3917 _images=GetFirstImageInList(index_image); 3918 break; 3919 } 3920 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3921 } 3922 case 'l': 3923 { 3924 if (LocaleCompare("layers",option+1) == 0) 3925 { 3926 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1); 3927 if ( parse < 0 ) 3928 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod", 3929 option,arg1); 3930 switch ((LayerMethod) parse) 3931 { 3932 case CoalesceLayer: 3933 { 3934 new_images=CoalesceImages(_images,_exception); 3935 break; 3936 } 3937 case CompareAnyLayer: 3938 case CompareClearLayer: 3939 case CompareOverlayLayer: 3940 default: 3941 { 3942 new_images=CompareImagesLayers(_images,(LayerMethod) parse, 3943 _exception); 3944 break; 3945 } 3946 case MergeLayer: 3947 case FlattenLayer: 3948 case MosaicLayer: 3949 case TrimBoundsLayer: 3950 { 3951 new_images=MergeImageLayers(_images,(LayerMethod) parse, 3952 _exception); 3953 break; 3954 } 3955 case DisposeLayer: 3956 { 3957 new_images=DisposeImages(_images,_exception); 3958 break; 3959 } 3960 case OptimizeImageLayer: 3961 { 3962 new_images=OptimizeImageLayers(_images,_exception); 3963 break; 3964 } 3965 case OptimizePlusLayer: 3966 { 3967 new_images=OptimizePlusImageLayers(_images,_exception); 3968 break; 3969 } 3970 case OptimizeTransLayer: 3971 { 3972 OptimizeImageTransparency(_images,_exception); 3973 break; 3974 } 3975 case RemoveDupsLayer: 3976 { 3977 RemoveDuplicateLayers(&_images,_exception); 3978 break; 3979 } 3980 case RemoveZeroLayer: 3981 { 3982 RemoveZeroDelayLayers(&_images,_exception); 3983 break; 3984 } 3985 case OptimizeLayer: 3986 { /* General Purpose, GIF Animation Optimizer. */ 3987 new_images=CoalesceImages(_images,_exception); 3988 if (new_images == (Image *) NULL) 3989 break; 3990 _images=DestroyImageList(_images); 3991 _images=OptimizeImageLayers(new_images,_exception); 3992 if (_images == (Image *) NULL) 3993 break; 3994 new_images=DestroyImageList(new_images); 3995 OptimizeImageTransparency(_images,_exception); 3996 (void) RemapImages(_quantize_info,_images,(Image *) NULL, 3997 _exception); 3998 break; 3999 } 4000 case CompositeLayer: 4001 { 4002 Image 4003 *source; 4004 4005 RectangleInfo 4006 geometry; 4007 4008 CompositeOperator 4009 compose; 4010 4011 const char* 4012 value; 4013 4014 value=GetImageOption(_image_info,"compose"); 4015 compose=OverCompositeOp; /* Default to Over */ 4016 if (value != (const char *) NULL) 4017 compose=(CompositeOperator) ParseCommandOption( 4018 MagickComposeOptions,MagickFalse,value); 4019 4020 /* Split image sequence at the first 'NULL:' image. */ 4021 source=_images; 4022 while (source != (Image *) NULL) 4023 { 4024 source=GetNextImageInList(source); 4025 if ((source != (Image *) NULL) && 4026 (LocaleCompare(source->magick,"NULL") == 0)) 4027 break; 4028 } 4029 if (source != (Image *) NULL) 4030 { 4031 if ((GetPreviousImageInList(source) == (Image *) NULL) || 4032 (GetNextImageInList(source) == (Image *) NULL)) 4033 source=(Image *) NULL; 4034 else 4035 { /* Separate the two lists, junk the null: image. */ 4036 source=SplitImageList(source->previous); 4037 DeleteImageFromList(&source); 4038 } 4039 } 4040 if (source == (Image *) NULL) 4041 { 4042 (void) ThrowMagickException(_exception,GetMagickModule(), 4043 OptionError,"MissingNullSeparator","layers Composite"); 4044 break; 4045 } 4046 /* Adjust offset with gravity and virtual canvas. */ 4047 SetGeometry(_images,&geometry); 4048 (void) ParseAbsoluteGeometry(_images->geometry,&geometry); 4049 geometry.width=source->page.width != 0 ? 4050 source->page.width : source->columns; 4051 geometry.height=source->page.height != 0 ? 4052 source->page.height : source->rows; 4053 GravityAdjustGeometry(_images->page.width != 0 ? 4054 _images->page.width : _images->columns, 4055 _images->page.height != 0 ? _images->page.height : 4056 _images->rows,_images->gravity,&geometry); 4057 4058 /* Compose the two image sequences together */ 4059 CompositeLayers(_images,compose,source,geometry.x,geometry.y, 4060 _exception); 4061 source=DestroyImageList(source); 4062 break; 4063 } 4064 } 4065 break; 4066 } 4067 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4068 } 4069 case 'm': 4070 { 4071 if (LocaleCompare("map",option+1) == 0) 4072 { 4073 CLIWandWarnReplaced("+remap"); 4074 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception); 4075 break; 4076 } 4077 if (LocaleCompare("metric",option+1) == 0) 4078 break; 4079 if (LocaleCompare("morph",option+1) == 0) 4080 { 4081 Image 4082 *morph_image; 4083 4084 if (IfMagickFalse(IsGeometry(arg1))) 4085 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 4086 morph_image=MorphImages(_images,StringToUnsignedLong(arg1), 4087 _exception); 4088 if (morph_image == (Image *) NULL) 4089 break; 4090 _images=DestroyImageList(_images); 4091 _images=morph_image; 4092 break; 4093 } 4094 if (LocaleCompare("mosaic",option+1) == 0) 4095 { 4096 /* REDIRECTED to use -layers mosaic instead */ 4097 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL); 4098 break; 4099 } 4100 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4101 } 4102 case 'p': 4103 { 4104 if (LocaleCompare("poly",option+1) == 0) 4105 { 4106 double 4107 *args; 4108 4109 ssize_t 4110 count; 4111 4112 /* convert argument string into an array of doubles */ 4113 args = StringToArrayOfDoubles(arg2,&count,_exception); 4114 if (args == (double *)NULL ) 4115 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2); 4116 new_images=PolynomialImage(_images,count >> 1,args,_exception); 4117 args=(double *) RelinquishMagickMemory(args); 4118 break; 4119 } 4120 if (LocaleCompare("process",option+1) == 0) 4121 { 4122 /* FUTURE: better parsing using ScriptToken() from string ??? */ 4123 char 4124 **arguments; 4125 4126 int 4127 j, 4128 number_arguments; 4129 4130 arguments=StringToArgv(arg1,&number_arguments); 4131 if (arguments == (char **) NULL) 4132 break; 4133 if (strchr(arguments[1],'=') != (char *) NULL) 4134 { 4135 char 4136 breaker, 4137 quote, 4138 *token; 4139 4140 const char 4141 *arguments; 4142 4143 int 4144 next, 4145 status; 4146 4147 size_t 4148 length; 4149 4150 TokenInfo 4151 *token_info; 4152 4153 /* 4154 Support old style syntax, filter="-option arg1". 4155 */ 4156 length=strlen(arg1); 4157 token=(char *) NULL; 4158 if (~length >= (MaxTextExtent-1)) 4159 token=(char *) AcquireQuantumMemory(length+MaxTextExtent, 4160 sizeof(*token)); 4161 if (token == (char *) NULL) 4162 break; 4163 next=0; 4164 arguments=arg1; 4165 token_info=AcquireTokenInfo(); 4166 status=Tokenizer(token_info,0,token,length,arguments,"","=", 4167 "\"",'\0',&breaker,&next,"e); 4168 token_info=DestroyTokenInfo(token_info); 4169 if (status == 0) 4170 { 4171 const char 4172 *argv; 4173 4174 argv=(&(arguments[next])); 4175 (void) InvokeDynamicImageFilter(token,&_images,1,&argv, 4176 _exception); 4177 } 4178 token=DestroyString(token); 4179 break; 4180 } 4181 (void) SubstituteString(&arguments[1],"-",""); 4182 (void) InvokeDynamicImageFilter(arguments[1],&_images, 4183 number_arguments-2,(const char **) arguments+2,_exception); 4184 for (j=0; j < number_arguments; j++) 4185 arguments[j]=DestroyString(arguments[j]); 4186 arguments=(char **) RelinquishMagickMemory(arguments); 4187 break; 4188 } 4189 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4190 } 4191 case 'r': 4192 { 4193 if (LocaleCompare("remap",option+1) == 0) 4194 { 4195 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception); 4196 break; 4197 } 4198 if (LocaleCompare("reverse",option+1) == 0) 4199 { 4200 ReverseImageList(&_images); 4201 break; 4202 } 4203 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4204 } 4205 case 's': 4206 { 4207 if (LocaleCompare("smush",option+1) == 0) 4208 { 4209 /* FUTURE: this option needs more work to make better */ 4210 ssize_t 4211 offset; 4212 4213 if (IfMagickFalse(IsGeometry(arg1))) 4214 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 4215 offset=(ssize_t) StringToLong(arg1); 4216 new_images=SmushImages(_images,IsNormalOp,offset,_exception); 4217 break; 4218 } 4219 if (LocaleCompare("subimage",option+1) == 0) 4220 { 4221 Image 4222 *base_image, 4223 *compare_image; 4224 4225 const char * 4226 value; 4227 4228 MetricType 4229 metric; 4230 4231 double 4232 similarity; 4233 4234 RectangleInfo 4235 offset; 4236 4237 base_image=GetImageFromList(_images,0); 4238 compare_image=GetImageFromList(_images,1); 4239 4240 /* Comparision Metric */ 4241 metric=UndefinedErrorMetric; 4242 value=GetImageOption(_image_info,"metric"); 4243 if (value != (const char *) NULL) 4244 metric=(MetricType) ParseCommandOption(MagickMetricOptions, 4245 MagickFalse,value); 4246 4247 new_images=SimilarityImage(base_image,compare_image,metric,0.0, 4248 &offset,&similarity,_exception); 4249 4250 if ( new_images != (Image *)NULL ) { 4251 char 4252 result[MaxTextExtent]; 4253 4254 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity); 4255 (void) SetImageProperty(new_images,"subimage:similarity",result, 4256 _exception); 4257 (void) FormatLocaleString(result,MaxTextExtent,"%+ld", 4258 (long) offset.x); 4259 (void) SetImageProperty(new_images,"subimage:x",result, 4260 _exception); 4261 (void) FormatLocaleString(result,MaxTextExtent,"%+ld", 4262 (long) offset.y); 4263 (void) SetImageProperty(new_images,"subimage:y",result, 4264 _exception); 4265 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld", 4266 (unsigned long) offset.width,(unsigned long) offset.height, 4267 (long) offset.x,(long) offset.y); 4268 (void) SetImageProperty(new_images,"subimage:offset",result, 4269 _exception); 4270 } 4271 break; 4272 } 4273 if (LocaleCompare("swap",option+1) == 0) { 4274 Image 4275 *p, 4276 *q, 4277 *swap; 4278 4279 ssize_t 4280 index, 4281 swap_index; 4282 4283 index=(-1); 4284 swap_index=(-2); 4285 if (IfNormalOp) { 4286 GeometryInfo 4287 geometry_info; 4288 4289 MagickStatusType 4290 flags; 4291 4292 swap_index=(-1); 4293 flags=ParseGeometry(arg1,&geometry_info); 4294 if ((flags & RhoValue) == 0) 4295 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 4296 index=(ssize_t) geometry_info.rho; 4297 if ((flags & SigmaValue) != 0) 4298 swap_index=(ssize_t) geometry_info.sigma; 4299 } 4300 p=GetImageFromList(_images,index); 4301 q=GetImageFromList(_images,swap_index); 4302 if ((p == (Image *) NULL) || (q == (Image *) NULL)) { 4303 if (IfNormalOp) 4304 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1) 4305 else 4306 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option); 4307 } 4308 if (p == q) 4309 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1); 4310 swap=CloneImage(p,0,0,MagickTrue,_exception); 4311 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception)); 4312 ReplaceImageInList(&q,swap); 4313 _images=GetFirstImageInList(q); 4314 break; 4315 } 4316 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4317 } 4318 default: 4319 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4320 } 4321 4322 /* clean up percent escape interpreted strings */ 4323 if (arg1 != arg1n ) 4324 arg1=DestroyString((char *)arg1); 4325 if (arg2 != arg2n ) 4326 arg2=DestroyString((char *)arg2); 4327 4328 /* if new image list generated, replace existing image list */ 4329 if (new_images == (Image *) NULL) 4330 return(status == MagickFalse ? 0 : 1); 4331 _images=DestroyImageList(_images); 4332 _images=GetFirstImageInList(new_images); 4333 return(status == MagickFalse ? 0 : 1); 4334 4335#undef _image_info 4336#undef _images 4337#undef _exception 4338#undef _draw_info 4339#undef _quantize_info 4340#undef IfNormalOp 4341#undef IfPlusOp 4342#undef IsNormalOp 4343} 4344 4345/* 4346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4347% % 4348% % 4349% % 4350+ C L I N o I m a g e O p e r a t i o n s % 4351% % 4352% % 4353% % 4354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4355% 4356% CLINoImageOperator() Applies operations that may not actually need images 4357% in an image list. 4358% 4359% The classic operators of this type is "-read", which actually creates 4360% images even when no images are present. Or image stack operators, which 4361% can be applied (push or pop) to an empty image list. 4362% 4363% Note that these operators may involve other special 'option' prefix 4364% characters other than '-' or '+', namely parenthesis and braces. 4365% 4366% The format of the CLINoImageOption method is: 4367% 4368% void CLINoImageOption(MagickCLI *cli_wand,const char *option, 4369% const char *arg1, const char *arg2) 4370% 4371% A description of each parameter follows: 4372% 4373% o cli_wand: the main CLI Wand to use. (sometimes not required) 4374% 4375% o option: The special option (with any switch char) to process 4376% 4377% o arg1 & arg2: Argument for option, if required 4378% Currently arg2 is not used. 4379% 4380*/ 4381WandPrivate void CLINoImageOperator(MagickCLI *cli_wand, 4382 const char *option,const char *arg1n,const char *arg2n) 4383{ 4384 const char /* percent escaped versions of the args */ 4385 *arg1, 4386 *arg2; 4387 4388#define _image_info (cli_wand->wand.image_info) 4389#define _images (cli_wand->wand.images) 4390#define _exception (cli_wand->wand.exception) 4391#define _process_flags (cli_wand->process_flags) 4392#define _option_type ((CommandOptionFlags) cli_wand->command->flags) 4393#define IfNormalOp (*option=='-') 4394#define IfPlusOp (*option!='-') 4395 4396 assert(cli_wand != (MagickCLI *) NULL); 4397 assert(cli_wand->signature == WandSignature); 4398 assert(cli_wand->wand.signature == WandSignature); 4399 4400 if (IfMagickTrue(cli_wand->wand.debug)) 4401 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(), 4402 "- NoImage Operator: %s \"%s\" \"%s\"", option,arg1n,arg2n); 4403 4404 arg1 = arg1n; 4405 arg2 = arg2n; 4406 4407 /* Interpret Percent Escapes in Arguments - using first image */ 4408 if ( (((_process_flags & ProcessInterpretProperities) != 0 ) 4409 || ((_option_type & AlwaysInterpretArgsFlag) != 0) 4410 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) { 4411 /* Interpret Percent escapes in argument 1 */ 4412 if (arg1n != (char *) NULL) { 4413 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception); 4414 if (arg1 == (char *) NULL) { 4415 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 4416 arg1=arg1n; /* use the given argument as is */ 4417 } 4418 } 4419 if (arg2n != (char *) NULL) { 4420 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception); 4421 if (arg2 == (char *) NULL) { 4422 CLIWandException(OptionWarning,"InterpretPropertyFailure",option); 4423 arg2=arg2n; /* use the given argument as is */ 4424 } 4425 } 4426 } 4427#undef _process_flags 4428#undef _option_type 4429 4430 do { /* break to exit code */ 4431 /* 4432 No-op options (ignore these) 4433 */ 4434 if (LocaleCompare("noop",option+1) == 0) /* zero argument */ 4435 break; 4436 if (LocaleCompare("sans",option+1) == 0) /* one argument */ 4437 break; 4438 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */ 4439 break; 4440 if (LocaleCompare("sans1",option+1) == 0) /* one argument */ 4441 break; 4442 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */ 4443 break; 4444 /* 4445 Image Reading 4446 */ 4447 if ( ( LocaleCompare("read",option+1) == 0 ) || 4448 ( LocaleCompare("--",option) == 0 ) ) { 4449 /* Do Glob filename Expansion for 'arg1' then read all images. 4450 * 4451 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring 4452 * (but attaching to the filenames in the generated argument list) any 4453 * [...] read modifiers that may be present. 4454 * 4455 * For example: It will expand '*.gif[20x20]' into a list such as 4456 * 'abc.gif[20x20]', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]' 4457 * 4458 * NOTE: In IMv6 this was done globally across all images. This 4459 * meant you could include IM options in '@filename' lists, but you 4460 * could not include comments. Doing it only for image read makes 4461 * it far more secure. 4462 * 4463 * Note: arguments do not have percent escapes expanded for security 4464 * reasons. 4465 */ 4466 int argc; 4467 char **argv; 4468 ssize_t i; 4469 4470 argc = 1; 4471 argv = (char **) &arg1; 4472 4473 /* Expand 'glob' expressions in the given filename. 4474 Expansion handles any 'coder:' prefix, or read modifiers attached 4475 to the filename, including them in the resulting expanded list. 4476 */ 4477 if (IfMagickFalse( ExpandFilenames(&argc,&argv) )) 4478 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed", 4479 option,GetExceptionMessage(errno)); 4480 4481 /* loop over expanded filename list, and read then all in */ 4482 for (i=0; i<argc; i++) { 4483 Image * 4484 new_images; 4485 if (IfMagickTrue(_image_info->ping)) 4486 new_images=PingImages(_image_info,argv[i],_exception); 4487 else 4488 new_images=ReadImages(_image_info,argv[i],_exception); 4489 AppendImageToList(&_images, new_images); 4490 } 4491 argv=DestroyStringList(argv); /* Destroy the Expanded Filename list */ 4492 break; 4493 } 4494 /* 4495 Image Writing 4496 Note: Writing a empty image list is valid in specific cases 4497 */ 4498 if (LocaleCompare("write",option+1) == 0) { 4499 /* Note: arguments do not have percent escapes expanded */ 4500 char 4501 key[MaxTextExtent]; 4502 4503 Image 4504 *write_images; 4505 4506 ImageInfo 4507 *write_info; 4508 4509 /* Need images, unless a "null:" output coder is used */ 4510 if ( _images == (Image *) NULL ) { 4511 if ( LocaleCompare(arg1,"null:") == 0 ) 4512 break; 4513 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1); 4514 } 4515 4516 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1); 4517 (void) DeleteImageRegistry(key); 4518 write_images=_images; 4519 if (IfPlusOp) 4520 write_images=CloneImageList(_images,_exception); 4521 write_info=CloneImageInfo(_image_info); 4522 (void) WriteImages(write_info,write_images,arg1,_exception); 4523 write_info=DestroyImageInfo(write_info); 4524 if (IfPlusOp) 4525 write_images=DestroyImageList(write_images); 4526 break; 4527 } 4528 /* 4529 Parenthesis and Brace operations 4530 */ 4531 if (LocaleCompare("(",option) == 0) { 4532 /* stack 'push' images */ 4533 Stack 4534 *node; 4535 4536 size_t 4537 size; 4538 4539 size=0; 4540 node=cli_wand->image_list_stack; 4541 for ( ; node != (Stack *)NULL; node=node->next) 4542 size++; 4543 if ( size >= MAX_STACK_DEPTH ) 4544 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option); 4545 node=(Stack *) AcquireMagickMemory(sizeof(*node)); 4546 if (node == (Stack *) NULL) 4547 CLIWandExceptionBreak(ResourceLimitFatalError, 4548 "MemoryAllocationFailed",option); 4549 node->data = (void *)cli_wand->wand.images; 4550 node->next = cli_wand->image_list_stack; 4551 cli_wand->image_list_stack = node; 4552 cli_wand->wand.images = NewImageList(); 4553 4554 /* handle respect-parenthesis */ 4555 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info, 4556 "respect-parenthesis")))) 4557 option="{"; /* fall-thru so as to push image settings too */ 4558 else 4559 break; 4560 /* fall thru to operation */ 4561 } 4562 if (LocaleCompare("{",option) == 0) { 4563 /* stack 'push' of image_info settings */ 4564 Stack 4565 *node; 4566 4567 size_t 4568 size; 4569 4570 size=0; 4571 node=cli_wand->image_info_stack; 4572 for ( ; node != (Stack *)NULL; node=node->next) 4573 size++; 4574 if ( size >= MAX_STACK_DEPTH ) 4575 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option); 4576 node=(Stack *) AcquireMagickMemory(sizeof(*node)); 4577 if (node == (Stack *) NULL) 4578 CLIWandExceptionBreak(ResourceLimitFatalError, 4579 "MemoryAllocationFailed",option); 4580 4581 node->data = (void *)cli_wand->wand.image_info; 4582 node->next = cli_wand->image_info_stack; 4583 4584 cli_wand->image_info_stack = node; 4585 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info); 4586 if (cli_wand->wand.image_info == (ImageInfo *)NULL) { 4587 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed", 4588 option); 4589 cli_wand->wand.image_info = (ImageInfo *)node->data; 4590 node = (Stack *)RelinquishMagickMemory(node); 4591 break; 4592 } 4593 4594 break; 4595 } 4596 if (LocaleCompare(")",option) == 0) { 4597 /* pop images from stack */ 4598 Stack 4599 *node; 4600 4601 node = (Stack *)cli_wand->image_list_stack; 4602 if ( node == (Stack *)NULL) 4603 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option); 4604 cli_wand->image_list_stack = node->next; 4605 4606 AppendImageToList((Image **)&node->data,cli_wand->wand.images); 4607 cli_wand->wand.images= (Image *)node->data; 4608 node = (Stack *)RelinquishMagickMemory(node); 4609 4610 /* handle respect-parenthesis - of the previous 'pushed' settings */ 4611 node = cli_wand->image_info_stack; 4612 if ( node != (Stack *)NULL) 4613 { 4614 if (IfMagickTrue(IsStringTrue(GetImageOption( 4615 cli_wand->wand.image_info,"respect-parenthesis")))) 4616 option="}"; /* fall-thru so as to pop image settings too */ 4617 else 4618 break; 4619 } 4620 else 4621 break; 4622 /* fall thru to next if */ 4623 } 4624 if (LocaleCompare("}",option) == 0) { 4625 /* pop image_info settings from stack */ 4626 Stack 4627 *node; 4628 4629 node = (Stack *)cli_wand->image_info_stack; 4630 if ( node == (Stack *)NULL) 4631 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option); 4632 cli_wand->image_info_stack = node->next; 4633 4634 (void) DestroyImageInfo(cli_wand->wand.image_info); 4635 cli_wand->wand.image_info = (ImageInfo *)node->data; 4636 node = (Stack *)RelinquishMagickMemory(node); 4637 4638 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info); 4639 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info); 4640 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info); 4641 4642 break; 4643 } 4644 if (LocaleCompare("print",option+1) == 0) 4645 { 4646 (void) FormatLocaleFile(stdout,"%s",arg1); 4647 break; 4648 } 4649 if (LocaleCompare("set",option+1) == 0) 4650 { 4651 /* Settings are applied to each image in memory in turn (if any). 4652 While a option: only need to be applied once globally. 4653 4654 NOTE: rguments have not been automatically percent expaneded 4655 */ 4656 4657 /* escape the 'key' once only, using first image. */ 4658 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception); 4659 if (arg1 == (char *) NULL) 4660 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure", 4661 option); 4662 4663 if (LocaleNCompare(arg1,"registry:",9) == 0) 4664 { 4665 if (IfPlusOp) 4666 { 4667 (void) DeleteImageRegistry(arg1+9); 4668 arg1=DestroyString((char *)arg1); 4669 break; 4670 } 4671 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception); 4672 if (arg2 == (char *) NULL) { 4673 arg1=DestroyString((char *)arg1); 4674 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure", 4675 option); 4676 } 4677 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception); 4678 arg1=DestroyString((char *)arg1); 4679 arg2=DestroyString((char *)arg2); 4680 break; 4681 } 4682 if (LocaleNCompare(arg1,"option:",7) == 0) 4683 { 4684 /* delete equivelent artifact from all images (if any) */ 4685 if (_images != (Image *)NULL) 4686 { 4687 MagickResetIterator(&cli_wand->wand); 4688 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) ) 4689 (void) DeleteImageArtifact(_images,arg1+7); 4690 MagickResetIterator(&cli_wand->wand); 4691 } 4692 /* now set/delete the global option as needed */ 4693 /* FUTURE: make escapes in a global 'option:' delayed */ 4694 arg2=(char *)NULL; 4695 if (IfNormalOp) 4696 { 4697 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception); 4698 if (arg2 == (char *) NULL) 4699 CLIWandExceptionBreak(OptionWarning, 4700 "InterpretPropertyFailure",option); 4701 } 4702 (void) SetImageOption(_image_info,arg1+7,arg2); 4703 arg1=DestroyString((char *)arg1); 4704 arg2=DestroyString((char *)arg2); 4705 break; 4706 } 4707 /* Set Artifacts/Properties/Attributes all images (required) */ 4708 if ( _images == (Image *) NULL ) 4709 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1); 4710 4711 MagickResetIterator(&cli_wand->wand); 4712 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) ) 4713 { 4714 arg2=(char *)NULL; 4715 if (IfNormalOp) 4716 { 4717 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception); 4718 if (arg2 == (char *) NULL) 4719 CLIWandExceptionBreak(OptionWarning, 4720 "InterpretPropertyFailure",option); 4721 } 4722 if (LocaleNCompare(arg1,"artifact:",9) == 0) 4723 (void) SetImageArtifact(_images,arg1+9,arg2); 4724 else if (LocaleNCompare(arg1,"property:",9) == 0) 4725 (void) SetImageProperty(_images,arg1+9,arg2,_exception); 4726 else 4727 (void) SetImageProperty(_images,arg1,arg2,_exception); 4728 arg2=DestroyString((char *)arg2); 4729 } 4730 MagickResetIterator(&cli_wand->wand); 4731 arg1=DestroyString((char *)arg1); 4732 break; 4733 } 4734 if (LocaleCompare("clone",option+1) == 0) { 4735 Image 4736 *new_images; 4737 4738 if (*option == '+') 4739 arg1="-1"; 4740 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse))) 4741 CLIWandExceptionBreak(OptionError,"InvalidArgument",option); 4742 if ( cli_wand->image_list_stack == (Stack *)NULL) 4743 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option); 4744 new_images = (Image *)cli_wand->image_list_stack->data; 4745 if (new_images == (Image *) NULL) 4746 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option); 4747 new_images=CloneImages(new_images,arg1,_exception); 4748 if (new_images == (Image *) NULL) 4749 CLIWandExceptionBreak(OptionError,"NoSuchImage",option); 4750 AppendImageToList(&_images,new_images); 4751 break; 4752 } 4753 /* 4754 Informational Operations. 4755 4756 Note that these do not require either a cli-wand or images! 4757 Though currently a cli-wand much be provided regardless. 4758 */ 4759 if (LocaleCompare("version",option+1) == 0) 4760 { 4761 ListMagickVersion(stdout); 4762 break; 4763 } 4764 if (LocaleCompare("list",option+1) == 0) { 4765 /* 4766 FUTURE: This 'switch' should really be part of MagickCore 4767 */ 4768 ssize_t 4769 list; 4770 4771 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1); 4772 if ( list < 0 ) { 4773 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1); 4774 break; 4775 } 4776 switch (list) 4777 { 4778 case MagickCoderOptions: 4779 { 4780 (void) ListCoderInfo((FILE *) NULL,_exception); 4781 break; 4782 } 4783 case MagickColorOptions: 4784 { 4785 (void) ListColorInfo((FILE *) NULL,_exception); 4786 break; 4787 } 4788 case MagickConfigureOptions: 4789 { 4790 (void) ListConfigureInfo((FILE *) NULL,_exception); 4791 break; 4792 } 4793 case MagickDelegateOptions: 4794 { 4795 (void) ListDelegateInfo((FILE *) NULL,_exception); 4796 break; 4797 } 4798 case MagickFontOptions: 4799 { 4800 (void) ListTypeInfo((FILE *) NULL,_exception); 4801 break; 4802 } 4803 case MagickFormatOptions: 4804 (void) ListMagickInfo((FILE *) NULL,_exception); 4805 break; 4806 case MagickLocaleOptions: 4807 (void) ListLocaleInfo((FILE *) NULL,_exception); 4808 break; 4809 case MagickLogOptions: 4810 (void) ListLogInfo((FILE *) NULL,_exception); 4811 break; 4812 case MagickMagicOptions: 4813 (void) ListMagicInfo((FILE *) NULL,_exception); 4814 break; 4815 case MagickMimeOptions: 4816 (void) ListMimeInfo((FILE *) NULL,_exception); 4817 break; 4818 case MagickModuleOptions: 4819 (void) ListModuleInfo((FILE *) NULL,_exception); 4820 break; 4821 case MagickPolicyOptions: 4822 (void) ListPolicyInfo((FILE *) NULL,_exception); 4823 break; 4824 case MagickResourceOptions: 4825 (void) ListMagickResourceInfo((FILE *) NULL,_exception); 4826 break; 4827 case MagickThresholdOptions: 4828 (void) ListThresholdMaps((FILE *) NULL,_exception); 4829 break; 4830 default: 4831 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list, 4832 _exception); 4833 break; 4834 } 4835 break; 4836 } 4837 4838 CLIWandException(OptionError,"UnrecognizedOption",option); 4839 4840DisableMSCWarning(4127) 4841 } while (0); /* break to exit code. */ 4842RestoreMSCWarning 4843 4844 /* clean up percent escape interpreted strings */ 4845 if (arg1 != arg1n ) 4846 arg1=DestroyString((char *)arg1); 4847 if (arg2 != arg2n ) 4848 arg2=DestroyString((char *)arg2); 4849 4850#undef _image_info 4851#undef _images 4852#undef _exception 4853#undef IfNormalOp 4854#undef IfPlusOp 4855} 4856 4857/* 4858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4859% % 4860% % 4861% % 4862+ C L I O p t i o n % 4863% % 4864% % 4865% % 4866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4867% 4868% CLIOption() Processes the given option using the given CLI Magick Wand. 4869% The option arguments can be variable in number, though at this time no more 4870% that two is actually used by any option (this may change). Excess options 4871% are simply ignored. 4872% 4873% If the cli_wand->command pointer is non-null, then it is assumed that the 4874% option has already been search for up from the CommandOptions[] table in 4875% "MagickCore/options.c" using GetCommandOptionInfo(). If not set this 4876% routine will do the lookup instead. The pointer is reset afterward. 4877% 4878% This action allows the caller to lookup and pre-handle any 'special' 4879% options, (such as implicit reads) before calling this general option 4880% handler to deal with 'standard' command line options. 4881% 4882% The format of the CLIOption method is: 4883% 4884% void CLIOption(MagickCLI *cli_wand,const char *option, ...) 4885% 4886% A description of each parameter follows: 4887% 4888% o cli_wand: the main CLI Wand to use. 4889% 4890% o option: The special option (with any switch char) to process 4891% 4892% o args: any required arguments for an option (variable number) 4893% 4894% Example Usage... 4895% 4896% CLIoption(cli_wand,"-read","rose:"); 4897% CLIoption(cli_wand,"-virtual-pixel","transparent"); 4898% CLIoption(cli_wand,"-distort","SRT:","30"); 4899% CLIoption(cli_wand,"-write","rotated_rose.png"); 4900% 4901*/ 4902WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...) 4903{ 4904 const char /* extracted option args from args */ 4905 *arg1, 4906 *arg2; 4907 4908 CommandOptionFlags 4909 option_type; 4910 4911 assert(cli_wand != (MagickCLI *) NULL); 4912 assert(cli_wand->signature == WandSignature); 4913 assert(cli_wand->wand.signature == WandSignature); 4914 4915 do { /* Break Code Block for error handling */ 4916 4917 /* get information about option */ 4918 if ( cli_wand->command == (const OptionInfo *) NULL ) 4919 cli_wand->command = GetCommandOptionInfo(option); 4920#if 0 4921 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n", 4922 option, cli_wand->command->mnemonic ); 4923#endif 4924 option_type=(CommandOptionFlags) cli_wand->command->flags; 4925 4926 if ( option_type == UndefinedOptionFlag ) 4927 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option); 4928 4929 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 ); 4930 4931 /* depreciated options */ 4932 if ( (option_type & DeprecateOptionFlag) != 0 ) 4933 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option); 4934 4935 /* options that this module does not handle */ 4936 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 ) 4937 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option); 4938 4939 /* Get argument strings from VarArgs 4940 How can you determine if enough arguments was supplied? 4941 What happens if not enough arguments were supplied? 4942 */ 4943 { size_t 4944 count = cli_wand->command->type; 4945 4946 va_list 4947 operands; 4948 4949 va_start(operands,option); 4950 4951 arg1=arg2=NULL; 4952 if ( count >= 1 ) 4953 arg1=(const char *) va_arg(operands, const char *); 4954 if ( count >= 2 ) 4955 arg2=(const char *) va_arg(operands, const char *); 4956 4957 va_end(operands); 4958#if 0 4959 (void) FormatLocaleFile(stderr, 4960 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n", 4961 option,(long) count,option_type,arg1,arg2); 4962#endif 4963 } 4964 4965 /* 4966 Call the appropriate option handler 4967 */ 4968 4969 /* FUTURE: this is temporary - get 'settings' to handle distribution of 4970 settings to images attributes,proprieties,artifacts */ 4971 if ( cli_wand->wand.images != (Image *)NULL ) 4972 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 4973 cli_wand->wand.exception); 4974 4975 if ( (option_type & SettingOptionFlags) != 0 ) { 4976 CLISettingOptionInfo(cli_wand, option, arg1, arg2); 4977 // FUTURE: Sync Specific Settings into Image Properities (not global) 4978 } 4979 4980 /* Operators that do not need images - read, write, stack, clone */ 4981 if ( (option_type & NoImageOperatorFlag) != 0) 4982 CLINoImageOperator(cli_wand, option, arg1, arg2); 4983 4984 /* FUTURE: The not a setting part below is a temporary hack due to 4985 * some options being both a Setting and a Simple operator. 4986 * Specifically -monitor, -depth, and -colorspace */ 4987 if ( cli_wand->wand.images == (Image *)NULL ) 4988 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) && 4989 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */ 4990 CLIWandExceptionBreak(OptionError,"NoImagesFound",option); 4991 4992 /* Operators which loop of individual images, simply */ 4993 if ( (option_type & SimpleOperatorFlag) != 0 && 4994 cli_wand->wand.images != (Image *)NULL) /* temp hack */ 4995 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 4996 4997 /* Operators that work on the image list as a whole */ 4998 if ( (option_type & ListOperatorFlag) != 0 ) 4999 CLIListOperatorImages(cli_wand, option, arg1, arg2); 5000 5001DisableMSCWarning(4127) 5002 } while (0); /* end Break code block */ 5003RestoreMSCWarning 5004 5005 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */ 5006} 5007