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