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