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