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