operation.c revision a12d8ba3a815842797e8f9d92f52b83c3d1f07a0
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 *arg1, const char *arg2) 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#define _image_info (cli_wand->wand.image_info) 1621#define _image (cli_wand->wand.images) 1622#define _exception (cli_wand->wand.exception) 1623#define _draw_info (cli_wand->draw_info) 1624#define _quantize_info (cli_wand->quantize_info) 1625#define IfNormalOp (*option=='-') 1626#define IfPlusOp (*option!='-') 1627#define normal_op IsMagickTrue(IfNormalOp) 1628#define plus_alt_op IsMagickFalse(IfNormalOp) 1629 1630 assert(cli_wand != (MagickCLI *) NULL); 1631 assert(cli_wand->signature == WandSignature); 1632 assert(cli_wand->wand.signature == WandSignature); 1633 assert(_image != (Image *) NULL); /* an image must be present */ 1634 if (IfMagickTrue(cli_wand->wand.debug)) 1635 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 1636 1637 SetGeometryInfo(&geometry_info); 1638 1639 new_image = (Image *)NULL; /* the replacement image, if not null at end */ 1640 1641 /* FUTURE: We may need somthing a little more optimized than this! 1642 Perhaps, do the 'sync' if 'settings tainted' before next operator. 1643 */ 1644 switch (*(option+1)) 1645 { 1646 case 'a': 1647 { 1648 if (LocaleCompare("adaptive-blur",option+1) == 0) 1649 { 1650 flags=ParseGeometry(arg1,&geometry_info); 1651 if ((flags & (RhoValue|SigmaValue)) == 0) 1652 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1653 if ((flags & SigmaValue) == 0) 1654 geometry_info.sigma=1.0; 1655 new_image=AdaptiveBlurImage(_image,geometry_info.rho, 1656 geometry_info.sigma,_exception); 1657 break; 1658 } 1659 if (LocaleCompare("adaptive-resize",option+1) == 0) 1660 { 1661 /* FUTURE: Roll into a resize special operator */ 1662 if (IfMagickFalse(IsGeometry(arg1))) 1663 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1664 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 1665 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height, 1666 _exception); 1667 break; 1668 } 1669 if (LocaleCompare("adaptive-sharpen",option+1) == 0) 1670 { 1671 flags=ParseGeometry(arg1,&geometry_info); 1672 if ((flags & (RhoValue|SigmaValue)) == 0) 1673 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1674 if ((flags & SigmaValue) == 0) 1675 geometry_info.sigma=1.0; 1676 new_image=AdaptiveSharpenImage(_image,geometry_info.rho, 1677 geometry_info.sigma,_exception); 1678 break; 1679 } 1680 if (LocaleCompare("alpha",option+1) == 0) 1681 { 1682 parse=ParseCommandOption(MagickAlphaOptions,MagickFalse,arg1); 1683 if (parse < 0) 1684 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelType", 1685 option,arg1); 1686 (void) SetImageAlphaChannel(_image,(AlphaChannelType)parse, 1687 _exception); 1688 break; 1689 } 1690 if (LocaleCompare("annotate",option+1) == 0) 1691 { 1692 char 1693 *text, 1694 geometry[MaxTextExtent]; 1695 1696 SetGeometryInfo(&geometry_info); 1697 flags=ParseGeometry(arg1,&geometry_info); 1698 if ((flags & RhoValue) == 0) 1699 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1700 if ((flags & SigmaValue) == 0) 1701 geometry_info.sigma=geometry_info.rho; 1702 text=InterpretImageProperties(_image_info,_image,arg2, 1703 _exception); 1704 if (text == (char *) NULL) 1705 break; 1706 (void) CloneString(&_draw_info->text,text); 1707 text=DestroyString(text); 1708 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f", 1709 geometry_info.xi,geometry_info.psi); 1710 (void) CloneString(&_draw_info->geometry,geometry); 1711 _draw_info->affine.sx=cos(DegreesToRadians( 1712 fmod(geometry_info.rho,360.0))); 1713 _draw_info->affine.rx=sin(DegreesToRadians( 1714 fmod(geometry_info.rho,360.0))); 1715 _draw_info->affine.ry=(-sin(DegreesToRadians( 1716 fmod(geometry_info.sigma,360.0)))); 1717 _draw_info->affine.sy=cos(DegreesToRadians( 1718 fmod(geometry_info.sigma,360.0))); 1719 (void) AnnotateImage(_image,_draw_info,_exception); 1720 GetAffineMatrix(&_draw_info->affine); 1721 break; 1722 } 1723 if (LocaleCompare("auto-gamma",option+1) == 0) 1724 { 1725 (void) AutoGammaImage(_image,_exception); 1726 break; 1727 } 1728 if (LocaleCompare("auto-level",option+1) == 0) 1729 { 1730 (void) AutoLevelImage(_image,_exception); 1731 break; 1732 } 1733 if (LocaleCompare("auto-orient",option+1) == 0) 1734 { 1735 /* This should probably be a MagickCore function */ 1736 switch (_image->orientation) 1737 { 1738 case TopRightOrientation: 1739 { 1740 new_image=FlopImage(_image,_exception); 1741 break; 1742 } 1743 case BottomRightOrientation: 1744 { 1745 new_image=RotateImage(_image,180.0,_exception); 1746 break; 1747 } 1748 case BottomLeftOrientation: 1749 { 1750 new_image=FlipImage(_image,_exception); 1751 break; 1752 } 1753 case LeftTopOrientation: 1754 { 1755 new_image=TransposeImage(_image,_exception); 1756 break; 1757 } 1758 case RightTopOrientation: 1759 { 1760 new_image=RotateImage(_image,90.0,_exception); 1761 break; 1762 } 1763 case RightBottomOrientation: 1764 { 1765 new_image=TransverseImage(_image,_exception); 1766 break; 1767 } 1768 case LeftBottomOrientation: 1769 { 1770 new_image=RotateImage(_image,270.0,_exception); 1771 break; 1772 } 1773 default: 1774 break; 1775 } 1776 if (new_image != (Image *) NULL) 1777 new_image->orientation=TopLeftOrientation; 1778 break; 1779 } 1780 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1781 } 1782 case 'b': 1783 { 1784 if (LocaleCompare("black-threshold",option+1) == 0) 1785 { 1786 if (IfMagickFalse(IsGeometry(arg1))) 1787 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1788 (void) BlackThresholdImage(_image,arg1,_exception); 1789 break; 1790 } 1791 if (LocaleCompare("blue-shift",option+1) == 0) 1792 { 1793 geometry_info.rho=1.5; 1794 if (IfNormalOp) { 1795 flags=ParseGeometry(arg1,&geometry_info); 1796 if ((flags & RhoValue) == 0) 1797 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1798 } 1799 new_image=BlueShiftImage(_image,geometry_info.rho,_exception); 1800 break; 1801 } 1802 if (LocaleCompare("blur",option+1) == 0) 1803 { 1804 flags=ParseGeometry(arg1,&geometry_info); 1805 if ((flags & (RhoValue|SigmaValue)) == 0) 1806 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1807 if ((flags & SigmaValue) == 0) 1808 geometry_info.sigma=1.0; 1809 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma, 1810 _exception); 1811 break; 1812 } 1813 if (LocaleCompare("border",option+1) == 0) 1814 { 1815 CompositeOperator 1816 compose; 1817 1818 const char* 1819 value; 1820 1821 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 1822 if ((flags & RhoValue) == 0) 1823 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1824 if ((flags & SigmaValue) == 0) 1825 geometry.height=geometry.width; 1826 1827 value=GetImageOption(_image_info,"compose"); 1828 if (value != (const char *) NULL) 1829 compose=(CompositeOperator) ParseCommandOption( 1830 MagickComposeOptions,MagickFalse,value); 1831 else 1832 compose=OverCompositeOp; /* use Over not _image->compose */ 1833 1834 new_image=BorderImage(_image,&geometry,compose,_exception); 1835 break; 1836 } 1837 if (LocaleCompare("brightness-contrast",option+1) == 0) 1838 { 1839 double 1840 brightness, 1841 contrast; 1842 1843 GeometryInfo 1844 geometry_info; 1845 1846 MagickStatusType 1847 flags; 1848 1849 flags=ParseGeometry(arg1,&geometry_info); 1850 if ((flags & RhoValue) == 0) 1851 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1852 brightness=geometry_info.rho; 1853 contrast=0.0; 1854 if ((flags & SigmaValue) != 0) 1855 contrast=geometry_info.sigma; 1856 (void) BrightnessContrastImage(_image,brightness,contrast, 1857 _exception); 1858 break; 1859 } 1860 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 1861 } 1862 case 'c': 1863 { 1864 if (LocaleCompare("cdl",option+1) == 0) 1865 { 1866 char 1867 *color_correction_collection; 1868 1869 /* 1870 Color correct with a color decision list. 1871 */ 1872 color_correction_collection=FileToString(arg1,~0,_exception); 1873 if (color_correction_collection == (char *) NULL) 1874 break; 1875 (void) ColorDecisionListImage(_image,color_correction_collection, 1876 _exception); 1877 break; 1878 } 1879 if (LocaleCompare("charcoal",option+1) == 0) 1880 { 1881 flags=ParseGeometry(arg1,&geometry_info); 1882 if ((flags & (RhoValue|SigmaValue)) == 0) 1883 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1884 if ((flags & SigmaValue) == 0) 1885 geometry_info.sigma=1.0; 1886 if ((flags & XiValue) == 0) 1887 geometry_info.xi=1.0; 1888 new_image=CharcoalImage(_image,geometry_info.rho, 1889 geometry_info.sigma,_exception); 1890 break; 1891 } 1892 if (LocaleCompare("chop",option+1) == 0) 1893 { 1894 if (IfMagickFalse(IsGeometry(arg1))) 1895 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1896 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception); 1897 new_image=ChopImage(_image,&geometry,_exception); 1898 break; 1899 } 1900 if (LocaleCompare("clamp",option+1) == 0) 1901 { 1902 (void) ClampImage(_image,_exception); 1903 break; 1904 } 1905 if (LocaleCompare("clip",option+1) == 0) 1906 { 1907 if (IfNormalOp) 1908 (void) ClipImage(_image,_exception); 1909 else /* "+mask" remove the write mask */ 1910 (void) SetImageMask(_image,(Image *) NULL,_exception); 1911 break; 1912 } 1913 if (LocaleCompare("clip-mask",option+1) == 0) 1914 { 1915 CacheView 1916 *mask_view; 1917 1918 Image 1919 *mask_image; 1920 1921 register Quantum 1922 *restrict q; 1923 1924 register ssize_t 1925 x; 1926 1927 ssize_t 1928 y; 1929 1930 if (IfPlusOp) { 1931 /* "+clip-mask" Remove the write mask */ 1932 (void) SetImageMask(_image,(Image *) NULL,_exception); 1933 break; 1934 } 1935 mask_image=GetImageCache(_image_info,arg1,_exception); 1936 if (mask_image == (Image *) NULL) 1937 break; 1938 if (IfMagickFalse(SetImageStorageClass(mask_image,DirectClass,_exception))) 1939 break; 1940 /* Create a write mask from cli_wand mask image */ 1941 /* FUTURE: use Alpha operations instead and create a Grey Image */ 1942 mask_view=AcquireAuthenticCacheView(mask_image,_exception); 1943 for (y=0; y < (ssize_t) mask_image->rows; y++) 1944 { 1945 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1, 1946 _exception); 1947 if (q == (Quantum *) NULL) 1948 break; 1949 for (x=0; x < (ssize_t) mask_image->columns; x++) 1950 { 1951 if (IfMagickFalse(mask_image->matte)) 1952 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q); 1953 SetPixelRed(mask_image,GetPixelAlpha(mask_image,q),q); 1954 SetPixelGreen(mask_image,GetPixelAlpha(mask_image,q),q); 1955 SetPixelBlue(mask_image,GetPixelAlpha(mask_image,q),q); 1956 q+=GetPixelChannels(mask_image); 1957 } 1958 if (IfMagickFalse(SyncCacheViewAuthenticPixels(mask_view,_exception))) 1959 break; 1960 } 1961 /* clean up and set the write mask */ 1962 mask_view=DestroyCacheView(mask_view); 1963 mask_image->matte=MagickTrue; 1964 (void) SetImageMask(_image,mask_image,_exception); 1965 mask_image=DestroyImage(mask_image); 1966 break; 1967 } 1968 if (LocaleCompare("clip-path",option+1) == 0) 1969 { 1970 (void) ClipImagePath(_image,arg1,normal_op,_exception); 1971 break; 1972 } 1973 if (LocaleCompare("colorize",option+1) == 0) 1974 { 1975 if (IfMagickFalse(IsGeometry(arg1))) 1976 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1977 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception); 1978 break; 1979 } 1980 if (LocaleCompare("color-matrix",option+1) == 0) 1981 { 1982 KernelInfo 1983 *kernel; 1984 1985 kernel=AcquireKernelInfo(arg1); 1986 if (kernel == (KernelInfo *) NULL) 1987 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 1988 new_image=ColorMatrixImage(_image,kernel,_exception); 1989 kernel=DestroyKernelInfo(kernel); 1990 break; 1991 } 1992 if (LocaleCompare("colors",option+1) == 0) 1993 { 1994 /* Reduce the number of colors in the image. 1995 FUTURE: also provide 'plus version with image 'color counts' 1996 */ 1997 _quantize_info->number_colors=StringToUnsignedLong(arg1); 1998 if (_quantize_info->number_colors == 0) 1999 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2000 if ((_image->storage_class == DirectClass) || 2001 _image->colors > _quantize_info->number_colors) 2002 (void) QuantizeImage(_quantize_info,_image,_exception); 2003 else 2004 (void) CompressImageColormap(_image,_exception); 2005 break; 2006 } 2007 if (LocaleCompare("colorspace",option+1) == 0) 2008 { 2009 /* WARNING: this is both a image_info setting (already done) 2010 and a operator to change image colorspace. 2011 2012 FUTURE: default colorspace should be sRGB! 2013 Unless some type of 'linear colorspace' mode is set. 2014 2015 Note that +colorspace sets "undefined" or no effect on 2016 new images, but forces images already in memory back to RGB! 2017 That seems to be a little strange! 2018 */ 2019 (void) TransformImageColorspace(_image, 2020 IfNormalOp ? _image_info->colorspace : RGBColorspace, 2021 _exception); 2022 break; 2023 } 2024 if (LocaleCompare("contrast",option+1) == 0) 2025 { 2026 CLIWandWarnReplaced(normal_op?"-level":"+level"); 2027 (void) ContrastImage(_image,normal_op,_exception); 2028 break; 2029 } 2030 if (LocaleCompare("contrast-stretch",option+1) == 0) 2031 { 2032 double 2033 black_point, 2034 white_point; 2035 2036 MagickStatusType 2037 flags; 2038 2039 flags=ParseGeometry(arg1,&geometry_info); 2040 if ((flags & RhoValue) == 0) 2041 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2042 black_point=geometry_info.rho; 2043 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : 2044 black_point; 2045 if ((flags & PercentValue) != 0) { 2046 black_point*=(double) _image->columns*_image->rows/100.0; 2047 white_point*=(double) _image->columns*_image->rows/100.0; 2048 } 2049 white_point=(MagickRealType) _image->columns*_image->rows- 2050 white_point; 2051 (void) ContrastStretchImage(_image,black_point,white_point, 2052 _exception); 2053 break; 2054 } 2055 if (LocaleCompare("convolve",option+1) == 0) 2056 { 2057 KernelInfo 2058 *kernel_info; 2059 2060 kernel_info=AcquireKernelInfo(arg1); 2061 if (kernel_info == (KernelInfo *) NULL) 2062 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2063 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info, 2064 _exception); 2065 kernel_info=DestroyKernelInfo(kernel_info); 2066 break; 2067 } 2068 if (LocaleCompare("crop",option+1) == 0) 2069 { 2070 /* WARNING: This can generate multiple images! */ 2071 if (IfMagickFalse(IsGeometry(arg1))) 2072 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2073 new_image=CropImageToTiles(_image,arg1,_exception); 2074 break; 2075 } 2076 if (LocaleCompare("cycle",option+1) == 0) 2077 { 2078 if (IfMagickFalse(IsGeometry(arg1))) 2079 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2080 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1), 2081 _exception); 2082 break; 2083 } 2084 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2085 } 2086 case 'd': 2087 { 2088 if (LocaleCompare("decipher",option+1) == 0) 2089 { 2090 StringInfo 2091 *passkey; 2092 2093 passkey=FileToStringInfo(arg1,~0,_exception); 2094 if (passkey == (StringInfo *) NULL) 2095 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2096 2097 (void) PasskeyDecipherImage(_image,passkey,_exception); 2098 passkey=DestroyStringInfo(passkey); 2099 break; 2100 } 2101 if (LocaleCompare("depth",option+1) == 0) 2102 { 2103 /* The _image_info->depth setting has already been set 2104 We just need to apply it to all images in current sequence 2105 2106 WARNING: Depth from 8 to 16 causes 'quantum rounding to images! 2107 That is it really is an operation, not a setting! Arrgghhh 2108 2109 FUTURE: this should not be an operator!!! 2110 */ 2111 (void) SetImageDepth(_image,_image_info->depth,_exception); 2112 break; 2113 } 2114 if (LocaleCompare("deskew",option+1) == 0) 2115 { 2116 double 2117 threshold; 2118 2119 if (IfNormalOp) { 2120 if (IfMagickFalse(IsGeometry(arg1))) 2121 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2122 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0); 2123 } 2124 else 2125 threshold=40.0*QuantumRange/100.0; 2126 new_image=DeskewImage(_image,threshold,_exception); 2127 break; 2128 } 2129 if (LocaleCompare("despeckle",option+1) == 0) 2130 { 2131 new_image=DespeckleImage(_image,_exception); 2132 break; 2133 } 2134 if (LocaleCompare("distort",option+1) == 0) 2135 { 2136 char 2137 *arg; 2138 2139 double 2140 *args; 2141 2142 ssize_t 2143 count; 2144 2145 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1); 2146 if ( parse < 0 ) 2147 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod", 2148 option,arg1); 2149 if ((DistortImageMethod) parse == ResizeDistortion) 2150 { 2151 double 2152 resize_args[2]; 2153 /* Special Case - Argument is actually a resize geometry! 2154 ** Convert that to an appropriate distortion argument array. 2155 ** FUTURE: make a separate special resize operator 2156 Roll into a resize special operator */ 2157 if (IfMagickFalse(IsGeometry(arg2))) 2158 CLIWandExceptArgBreak(OptionError,"InvalidGeometry", 2159 option,arg2); 2160 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception); 2161 resize_args[0]=(double) geometry.width; 2162 resize_args[1]=(double) geometry.height; 2163 new_image=DistortImage(_image,(DistortImageMethod) parse, 2164 (size_t)2,resize_args,MagickTrue,_exception); 2165 break; 2166 } 2167 /* allow percent escapes in argument string */ 2168 arg=InterpretImageProperties(_image_info,_image,arg2,_exception); 2169 if (arg == (char *) NULL) 2170 break; 2171 /* convert argument string into an array of doubles */ 2172 args = StringToArrayOfDoubles(arg,&count,_exception); 2173 arg=DestroyString(arg); 2174 if (args == (double *)NULL ) 2175 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2); 2176 2177 new_image=DistortImage(_image,(DistortImageMethod) parse,count,args, 2178 plus_alt_op,_exception); 2179 args=(double *) RelinquishMagickMemory(args); 2180 break; 2181 } 2182 if (LocaleCompare("draw",option+1) == 0) 2183 { 2184 (void) CloneString(&_draw_info->primitive,arg1); 2185 (void) DrawImage(_image,_draw_info,_exception); 2186 (void) CloneString(&_draw_info->primitive,(char *)NULL); 2187 break; 2188 } 2189 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2190 } 2191 case 'e': 2192 { 2193 if (LocaleCompare("edge",option+1) == 0) 2194 { 2195 flags=ParseGeometry(arg1,&geometry_info); 2196 if ((flags & (RhoValue|SigmaValue)) == 0) 2197 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2198 if ((flags & SigmaValue) == 0) 2199 geometry_info.sigma=1.0; 2200 new_image=EdgeImage(_image,geometry_info.rho,geometry_info.sigma, 2201 _exception); 2202 break; 2203 } 2204 if (LocaleCompare("emboss",option+1) == 0) 2205 { 2206 flags=ParseGeometry(arg1,&geometry_info); 2207 if ((flags & (RhoValue|SigmaValue)) == 0) 2208 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2209 if ((flags & SigmaValue) == 0) 2210 geometry_info.sigma=1.0; 2211 new_image=EmbossImage(_image,geometry_info.rho, 2212 geometry_info.sigma,_exception); 2213 break; 2214 } 2215 if (LocaleCompare("encipher",option+1) == 0) 2216 { 2217 StringInfo 2218 *passkey; 2219 2220 passkey=FileToStringInfo(arg1,~0,_exception); 2221 if (passkey != (StringInfo *) NULL) 2222 { 2223 (void) PasskeyEncipherImage(_image,passkey,_exception); 2224 passkey=DestroyStringInfo(passkey); 2225 } 2226 break; 2227 } 2228 if (LocaleCompare("enhance",option+1) == 0) 2229 { 2230 new_image=EnhanceImage(_image,_exception); 2231 break; 2232 } 2233 if (LocaleCompare("equalize",option+1) == 0) 2234 { 2235 (void) EqualizeImage(_image,_exception); 2236 break; 2237 } 2238 if (LocaleCompare("evaluate",option+1) == 0) 2239 { 2240 double 2241 constant; 2242 2243 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1); 2244 if ( parse < 0 ) 2245 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator", 2246 option,arg1); 2247 if (IfMagickFalse(IsGeometry(arg2))) 2248 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 2249 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0); 2250 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant, 2251 _exception); 2252 break; 2253 } 2254 if (LocaleCompare("extent",option+1) == 0) 2255 { 2256 if (IfMagickFalse(IsGeometry(arg1))) 2257 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2258 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception); 2259 if (geometry.width == 0) 2260 geometry.width=_image->columns; 2261 if (geometry.height == 0) 2262 geometry.height=_image->rows; 2263 new_image=ExtentImage(_image,&geometry,_exception); 2264 break; 2265 } 2266 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2267 } 2268 case 'f': 2269 { 2270 if (LocaleCompare("features",option+1) == 0) 2271 { 2272 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */ 2273 if (IfPlusOp) { 2274 (void) DeleteImageArtifact(_image,"identify:features"); 2275 break; 2276 } 2277 (void) SetImageArtifact(_image,"identify:features","true"); 2278 (void) SetImageArtifact(_image,"verbose","true"); 2279 break; 2280 } 2281 if (LocaleCompare("flip",option+1) == 0) 2282 { 2283 new_image=FlipImage(_image,_exception); 2284 break; 2285 } 2286 if (LocaleCompare("flop",option+1) == 0) 2287 { 2288 new_image=FlopImage(_image,_exception); 2289 break; 2290 } 2291 if (LocaleCompare("floodfill",option+1) == 0) 2292 { 2293 PixelInfo 2294 target; 2295 2296 if (IfMagickFalse(IsGeometry(arg1))) 2297 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2298 (void) ParsePageGeometry(_image,arg1,&geometry,_exception); 2299 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception); 2300 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x, 2301 geometry.y,plus_alt_op,_exception); 2302 break; 2303 } 2304 if (LocaleCompare("frame",option+1) == 0) 2305 { 2306 FrameInfo 2307 frame_info; 2308 2309 CompositeOperator 2310 compose; 2311 2312 const char* 2313 value; 2314 2315 value=GetImageOption(_image_info,"compose"); 2316 if (value != (const char *) NULL) 2317 compose=(CompositeOperator) ParseCommandOption( 2318 MagickComposeOptions,MagickFalse,value); 2319 else 2320 compose=OverCompositeOp; /* use Over not _image->compose */ 2321 2322 if (IfMagickFalse(IsGeometry(arg1))) 2323 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2324 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 2325 frame_info.width=geometry.width; 2326 frame_info.height=geometry.height; 2327 if ((flags & HeightValue) == 0) 2328 frame_info.height=geometry.width; 2329 frame_info.outer_bevel=geometry.x; 2330 frame_info.inner_bevel=geometry.y; 2331 frame_info.x=(ssize_t) frame_info.width; 2332 frame_info.y=(ssize_t) frame_info.height; 2333 frame_info.width=_image->columns+2*frame_info.width; 2334 frame_info.height=_image->rows+2*frame_info.height; 2335 new_image=FrameImage(_image,&frame_info,compose,_exception); 2336 break; 2337 } 2338 if (LocaleCompare("function",option+1) == 0) 2339 { 2340 char 2341 *arg; 2342 2343 double 2344 *args; 2345 2346 ssize_t 2347 count; 2348 2349 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1); 2350 if ( parse < 0 ) 2351 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction", 2352 option,arg1); 2353 /* allow percent escapes in argument string */ 2354 arg=InterpretImageProperties(_image_info,_image,arg2,_exception); 2355 if (arg == (char *) NULL) 2356 break; 2357 /* convert argument string into an array of doubles */ 2358 args = StringToArrayOfDoubles(arg,&count,_exception); 2359 arg=DestroyString(arg); 2360 if (args == (double *)NULL ) 2361 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2); 2362 2363 (void) FunctionImage(_image,(MagickFunction)parse,count,args, 2364 _exception); 2365 args=(double *) RelinquishMagickMemory(args); 2366 break; 2367 } 2368 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2369 } 2370 case 'g': 2371 { 2372 if (LocaleCompare("gamma",option+1) == 0) 2373 { 2374 if (IfMagickFalse(IsGeometry(arg1))) 2375 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2376 if (IfNormalOp) 2377 (void) GammaImage(_image,StringToDouble(arg1,(char **) NULL), 2378 _exception); 2379 else 2380 _image->gamma=StringToDouble(arg1,(char **) NULL); 2381 break; 2382 } 2383 if (LocaleCompare("gaussian-blur",option+1) == 0) 2384 { 2385 flags=ParseGeometry(arg1,&geometry_info); 2386 if ((flags & (RhoValue|SigmaValue)) == 0) 2387 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2388 if ((flags & SigmaValue) == 0) 2389 geometry_info.sigma=1.0; 2390 new_image=GaussianBlurImage(_image,geometry_info.rho, 2391 geometry_info.sigma,_exception); 2392 break; 2393 } 2394 if (LocaleCompare("gaussian",option+1) == 0) 2395 { 2396 CLIWandWarnReplaced("-gaussian-blur"); 2397 CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL); 2398 } 2399 if (LocaleCompare("geometry",option+1) == 0) 2400 { 2401 /* 2402 Record Image offset for composition. (A Setting) 2403 Resize last _image. (ListOperator) -- DEPRECIATE 2404 FUTURE: Why if no 'offset' does this resize ALL images? 2405 Also why is the setting recorded in the IMAGE non-sense! 2406 */ 2407 if (IfPlusOp) 2408 { /* remove the previous composition geometry offset! */ 2409 if (_image->geometry != (char *) NULL) 2410 _image->geometry=DestroyString(_image->geometry); 2411 break; 2412 } 2413 if (IfMagickFalse(IsGeometry(arg1))) 2414 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2415 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception); 2416 if (((flags & XValue) != 0) || ((flags & YValue) != 0)) 2417 (void) CloneString(&_image->geometry,arg1); 2418 else 2419 new_image=ResizeImage(_image,geometry.width,geometry.height, 2420 _image->filter,_exception); 2421 break; 2422 } 2423 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2424 } 2425 case 'i': 2426 { 2427 if (LocaleCompare("identify",option+1) == 0) 2428 { 2429 const char 2430 *format, 2431 *text; 2432 2433 format=GetImageOption(_image_info,"format"); 2434 if (format == (char *) NULL) 2435 { 2436 (void) IdentifyImage(_image,stdout,_image_info->verbose, 2437 _exception); 2438 break; 2439 } 2440 text=InterpretImageProperties(_image_info,_image,format,_exception); 2441 if (text == (char *) NULL) 2442 break; 2443 (void) fputs(text,stdout); 2444 (void) fputc('\n',stdout); 2445 text=DestroyString((char *)text); 2446 break; 2447 } 2448 if (LocaleCompare("implode",option+1) == 0) 2449 { 2450 flags=ParseGeometry(arg1,&geometry_info); 2451 if ((flags & RhoValue) == 0) 2452 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2453 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate, 2454 _exception); 2455 break; 2456 } 2457 if (LocaleCompare("interpolative-resize",option+1) == 0) 2458 { 2459 /* FUTURE: New to IMv7 2460 Roll into a resize special operator */ 2461 if (IfMagickFalse(IsGeometry(arg1))) 2462 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2463 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 2464 new_image=InterpolativeResizeImage(_image,geometry.width, 2465 geometry.height,_image->interpolate,_exception); 2466 break; 2467 } 2468 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2469 } 2470 case 'l': 2471 { 2472 if (LocaleCompare("lat",option+1) == 0) 2473 { 2474 flags=ParseGeometry(arg1,&geometry_info); 2475 if ((flags & (RhoValue|SigmaValue)) == 0) 2476 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2477 if ((flags & PercentValue) != 0) 2478 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0; 2479 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho, 2480 (size_t) geometry_info.sigma,(double) geometry_info.xi, 2481 _exception); 2482 break; 2483 } 2484 if (LocaleCompare("level",option+1) == 0) 2485 { 2486 MagickRealType 2487 black_point, 2488 gamma, 2489 white_point; 2490 2491 MagickStatusType 2492 flags; 2493 2494 flags=ParseGeometry(arg1,&geometry_info); 2495 if ((flags & RhoValue) == 0) 2496 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2497 black_point=geometry_info.rho; 2498 white_point=(MagickRealType) QuantumRange; 2499 if ((flags & SigmaValue) != 0) 2500 white_point=geometry_info.sigma; 2501 gamma=1.0; 2502 if ((flags & XiValue) != 0) 2503 gamma=geometry_info.xi; 2504 if ((flags & PercentValue) != 0) 2505 { 2506 black_point*=(MagickRealType) (QuantumRange/100.0); 2507 white_point*=(MagickRealType) (QuantumRange/100.0); 2508 } 2509 if ((flags & SigmaValue) == 0) 2510 white_point=(MagickRealType) QuantumRange-black_point; 2511 if (IfPlusOp || ((flags & AspectValue) != 0)) 2512 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception); 2513 else 2514 (void) LevelImage(_image,black_point,white_point,gamma,_exception); 2515 break; 2516 } 2517 if (LocaleCompare("level-colors",option+1) == 0) 2518 { 2519 char 2520 token[MaxTextExtent]; 2521 2522 const char 2523 *p; 2524 2525 PixelInfo 2526 black_point, 2527 white_point; 2528 2529 p=(const char *) arg1; 2530 GetMagickToken(p,&p,token); /* get black point color */ 2531 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0)) 2532 (void) QueryColorCompliance(token,AllCompliance, 2533 &black_point,_exception); 2534 else 2535 (void) QueryColorCompliance("#000000",AllCompliance, 2536 &black_point,_exception); 2537 if (isalpha((int) token[0]) || (token[0] == '#')) 2538 GetMagickToken(p,&p,token); 2539 if (*token == '\0') 2540 white_point=black_point; /* set everything to that color */ 2541 else 2542 { 2543 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0)) 2544 GetMagickToken(p,&p,token); /* Get white point color. */ 2545 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0)) 2546 (void) QueryColorCompliance(token,AllCompliance, 2547 &white_point,_exception); 2548 else 2549 (void) QueryColorCompliance("#ffffff",AllCompliance, 2550 &white_point,_exception); 2551 } 2552 (void) LevelImageColors(_image,&black_point,&white_point, 2553 plus_alt_op,_exception); 2554 break; 2555 } 2556 if (LocaleCompare("linear-stretch",option+1) == 0) 2557 { 2558 double 2559 black_point, 2560 white_point; 2561 2562 MagickStatusType 2563 flags; 2564 2565 flags=ParseGeometry(arg1,&geometry_info); 2566 if ((flags & RhoValue) == 0) 2567 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2568 black_point=geometry_info.rho; 2569 white_point=(MagickRealType) _image->columns*_image->rows; 2570 if ((flags & SigmaValue) != 0) 2571 white_point=geometry_info.sigma; 2572 if ((flags & PercentValue) != 0) 2573 { 2574 black_point*=(double) _image->columns*_image->rows/100.0; 2575 white_point*=(double) _image->columns*_image->rows/100.0; 2576 } 2577 if ((flags & SigmaValue) == 0) 2578 white_point=(MagickRealType) _image->columns*_image->rows- 2579 black_point; 2580 (void) LinearStretchImage(_image,black_point,white_point,_exception); 2581 break; 2582 } 2583 if (LocaleCompare("liquid-rescale",option+1) == 0) 2584 { 2585 /* FUTURE: Roll into a resize special operator */ 2586 if (IfMagickFalse(IsGeometry(arg1))) 2587 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2588 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception); 2589 if ((flags & XValue) == 0) 2590 geometry.x=1; 2591 if ((flags & YValue) == 0) 2592 geometry.y=0; 2593 new_image=LiquidRescaleImage(_image,geometry.width, 2594 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception); 2595 break; 2596 } 2597 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2598 } 2599 case 'm': 2600 { 2601 if (LocaleCompare("map",option+1) == 0) 2602 { 2603 CLIWandWarnReplaced("-remap"); 2604 CLISimpleOperatorImage(cli_wand,"-remap",NULL,NULL); 2605 break; 2606 } 2607 if (LocaleCompare("mask",option+1) == 0) 2608 { 2609 Image 2610 *mask; 2611 2612 if (IfPlusOp) 2613 { /* Remove a mask. */ 2614 (void) SetImageMask(_image,(Image *) NULL,_exception); 2615 break; 2616 } 2617 /* Set the image mask. */ 2618 mask=GetImageCache(_image_info,arg1,_exception); 2619 if (mask == (Image *) NULL) 2620 break; 2621 (void) SetImageMask(_image,mask,_exception); 2622 mask=DestroyImage(mask); 2623 break; 2624 } 2625 if (LocaleCompare("matte",option+1) == 0) 2626 { 2627 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off"); 2628 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel : 2629 DeactivateAlphaChannel, _exception); 2630 break; 2631 } 2632 if (LocaleCompare("median",option+1) == 0) 2633 { 2634 CLIWandWarnReplaced("-statistic Median"); 2635 CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1); 2636 break; 2637 } 2638 if (LocaleCompare("mode",option+1) == 0) 2639 { 2640 /* FUTURE: note this is also a special "montage" option */ 2641 CLIWandWarnReplaced("-statistic Mode"); 2642 CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1); 2643 break; 2644 } 2645 if (LocaleCompare("modulate",option+1) == 0) 2646 { 2647 if (IfMagickFalse(IsGeometry(arg1))) 2648 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2649 (void) ModulateImage(_image,arg1,_exception); 2650 break; 2651 } 2652 if (LocaleCompare("monitor",option+1) == 0) 2653 { 2654 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress : 2655 (MagickProgressMonitor) NULL,(void *) NULL); 2656 break; 2657 } 2658 if (LocaleCompare("monochrome",option+1) == 0) 2659 { 2660 (void) SetImageType(_image,BilevelType,_exception); 2661 break; 2662 } 2663 if (LocaleCompare("morphology",option+1) == 0) 2664 { 2665 char 2666 token[MaxTextExtent]; 2667 2668 const char 2669 *p; 2670 2671 KernelInfo 2672 *kernel; 2673 2674 ssize_t 2675 iterations; 2676 2677 p=arg1; 2678 GetMagickToken(p,&p,token); 2679 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token); 2680 if ( parse < 0 ) 2681 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction", 2682 option,arg1); 2683 iterations=1L; 2684 GetMagickToken(p,&p,token); 2685 if ((*p == ':') || (*p == ',')) 2686 GetMagickToken(p,&p,token); 2687 if ((*p != '\0')) 2688 iterations=(ssize_t) StringToLong(p); 2689 kernel=AcquireKernelInfo(arg2); 2690 if (kernel == (KernelInfo *) NULL) 2691 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel", 2692 option,arg2); 2693 new_image=MorphologyImage(_image,(MorphologyMethod)parse, 2694 iterations,kernel,_exception); 2695 kernel=DestroyKernelInfo(kernel); 2696 break; 2697 } 2698 if (LocaleCompare("motion-blur",option+1) == 0) 2699 { 2700 flags=ParseGeometry(arg1,&geometry_info); 2701 if ((flags & (RhoValue|SigmaValue)) == 0) 2702 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2703 if ((flags & SigmaValue) == 0) 2704 geometry_info.sigma=1.0; 2705 new_image=MotionBlurImage(_image,geometry_info.rho, 2706 geometry_info.sigma,geometry_info.xi,_exception); 2707 break; 2708 } 2709 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2710 } 2711 case 'n': 2712 { 2713 if (LocaleCompare("negate",option+1) == 0) 2714 { 2715 (void) NegateImage(_image, plus_alt_op, _exception); 2716 break; 2717 } 2718 if (LocaleCompare("noise",option+1) == 0) 2719 { 2720 double 2721 attenuate; 2722 2723 const char* 2724 value; 2725 2726 if (IfNormalOp) 2727 { 2728 CLIWandWarnReplaced("-statistic NonPeak"); 2729 CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1); 2730 break; 2731 } 2732 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1); 2733 if ( parse < 0 ) 2734 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType", 2735 option,arg1); 2736 attenuate=1.0; 2737 value=GetImageOption(_image_info,"attenuate"); 2738 if (value != (const char *) NULL) 2739 attenuate=StringToDouble(value,(char **) NULL); 2740 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate, 2741 _exception); 2742 break; 2743 } 2744 if (LocaleCompare("normalize",option+1) == 0) 2745 { 2746 (void) NormalizeImage(_image,_exception); 2747 break; 2748 } 2749 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2750 } 2751 case 'o': 2752 { 2753 if (LocaleCompare("opaque",option+1) == 0) 2754 { 2755 PixelInfo 2756 target; 2757 2758 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception); 2759 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,plus_alt_op, 2760 _exception); 2761 break; 2762 } 2763 if (LocaleCompare("ordered-dither",option+1) == 0) 2764 { 2765 (void) OrderedPosterizeImage(_image,arg1,_exception); 2766 break; 2767 } 2768 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2769 } 2770 case 'p': 2771 { 2772 if (LocaleCompare("paint",option+1) == 0) 2773 { 2774 flags=ParseGeometry(arg1,&geometry_info); 2775 if ((flags & (RhoValue|SigmaValue)) == 0) 2776 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2777 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma, 2778 _exception); 2779 break; 2780 } 2781 if (LocaleCompare("polaroid",option+1) == 0) 2782 { 2783 const char 2784 *caption; 2785 2786 double 2787 angle; 2788 2789 if (IfPlusOp) { 2790 RandomInfo 2791 *random_info; 2792 2793 random_info=AcquireRandomInfo(); 2794 angle=22.5*(GetPseudoRandomValue(random_info)-0.5); 2795 random_info=DestroyRandomInfo(random_info); 2796 } 2797 else { 2798 flags=ParseGeometry(arg1,&geometry_info); 2799 if ((flags & RhoValue) == 0) 2800 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2801 angle=geometry_info.rho; 2802 } 2803 caption=GetImageProperty(_image,"caption",_exception); 2804 new_image=PolaroidImage(_image,_draw_info,caption,angle, 2805 _image->interpolate,_exception); 2806 break; 2807 } 2808 if (LocaleCompare("posterize",option+1) == 0) 2809 { 2810 flags=ParseGeometry(arg1,&geometry_info); 2811 if ((flags & RhoValue) == 0) 2812 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2813 (void) PosterizeImage(_image,(size_t) geometry_info.rho, 2814 _quantize_info->dither,_exception); 2815 break; 2816 } 2817 if (LocaleCompare("preview",option+1) == 0) 2818 { 2819 /* FUTURE: should be a 'Genesis' option? 2820 Option however is also in WandSettingOptionInfo() 2821 Why??? 2822 */ 2823 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1); 2824 if ( parse < 0 ) 2825 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType", 2826 option,arg1); 2827 new_image=PreviewImage(_image,(PreviewType)parse,_exception); 2828 break; 2829 } 2830 if (LocaleCompare("profile",option+1) == 0) 2831 { 2832 const char 2833 *name; 2834 2835 const StringInfo 2836 *profile; 2837 2838 Image 2839 *profile_image; 2840 2841 ImageInfo 2842 *profile_info; 2843 2844 if (IfPlusOp) 2845 { /* Remove a profile from the _image. */ 2846 (void) ProfileImage(_image,arg1,(const unsigned char *) 2847 NULL,0,_exception); 2848 break; 2849 } 2850 /* Associate a profile with the _image. */ 2851 profile_info=CloneImageInfo(_image_info); 2852 profile=GetImageProfile(_image,"iptc"); 2853 if (profile != (StringInfo *) NULL) 2854 profile_info->profile=(void *) CloneStringInfo(profile); 2855 profile_image=GetImageCache(profile_info,arg1,_exception); 2856 profile_info=DestroyImageInfo(profile_info); 2857 if (profile_image == (Image *) NULL) 2858 { 2859 StringInfo 2860 *profile; 2861 2862 profile_info=CloneImageInfo(_image_info); 2863 (void) CopyMagickString(profile_info->filename,arg1, 2864 MaxTextExtent); 2865 profile=FileToStringInfo(profile_info->filename,~0UL,_exception); 2866 if (profile != (StringInfo *) NULL) 2867 { 2868 (void) ProfileImage(_image,profile_info->magick, 2869 GetStringInfoDatum(profile),(size_t) 2870 GetStringInfoLength(profile),_exception); 2871 profile=DestroyStringInfo(profile); 2872 } 2873 profile_info=DestroyImageInfo(profile_info); 2874 break; 2875 } 2876 ResetImageProfileIterator(profile_image); 2877 name=GetNextImageProfile(profile_image); 2878 while (name != (const char *) NULL) 2879 { 2880 profile=GetImageProfile(profile_image,name); 2881 if (profile != (StringInfo *) NULL) 2882 (void) ProfileImage(_image,name,GetStringInfoDatum(profile), 2883 (size_t) GetStringInfoLength(profile),_exception); 2884 name=GetNextImageProfile(profile_image); 2885 } 2886 profile_image=DestroyImage(profile_image); 2887 break; 2888 } 2889 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2890 } 2891 case 'r': 2892 { 2893 if (LocaleCompare("radial-blur",option+1) == 0) 2894 { 2895 flags=ParseGeometry(arg1,&geometry_info); 2896 if ((flags & RhoValue) == 0) 2897 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2898 new_image=RadialBlurImage(_image,geometry_info.rho,_exception); 2899 break; 2900 } 2901 if (LocaleCompare("raise",option+1) == 0) 2902 { 2903 if (IfMagickFalse(IsGeometry(arg1))) 2904 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2905 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 2906 if ((flags & SigmaValue) == 0) 2907 geometry.height=geometry.width; 2908 (void) RaiseImage(_image,&geometry,normal_op,_exception); 2909 break; 2910 } 2911 if (LocaleCompare("random-threshold",option+1) == 0) 2912 { 2913 if (IfMagickFalse(IsGeometry(arg1))) 2914 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2915 (void) RandomThresholdImage(_image,arg1,_exception); 2916 break; 2917 } 2918 if (LocaleCompare("recolor",option+1) == 0) 2919 { 2920 CLIWandWarnReplaced("-color-matrix"); 2921 CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL); 2922 } 2923 if (LocaleCompare("remap",option+1) == 0) 2924 { 2925 Image 2926 *remap_image; 2927 2928 remap_image=GetImageCache(_image_info,arg1,_exception); 2929 if (remap_image == (Image *) NULL) 2930 break; 2931 (void) RemapImage(_quantize_info,_image,remap_image,_exception); 2932 remap_image=DestroyImage(remap_image); 2933 break; 2934 } 2935 if (LocaleCompare("repage",option+1) == 0) 2936 { 2937 if (IfNormalOp) 2938 { 2939 if (IfMagickFalse(IsGeometry(arg1))) 2940 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option, 2941 arg1); 2942 (void) ResetImagePage(_image,arg1); 2943 } 2944 else 2945 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page); 2946 break; 2947 } 2948 if (LocaleCompare("resample",option+1) == 0) 2949 { 2950 /* FUTURE: Roll into a resize special operation */ 2951 flags=ParseGeometry(arg1,&geometry_info); 2952 if ((flags & (RhoValue|SigmaValue)) == 0) 2953 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2954 if ((flags & SigmaValue) == 0) 2955 geometry_info.sigma=geometry_info.rho; 2956 new_image=ResampleImage(_image,geometry_info.rho, 2957 geometry_info.sigma,_image->filter,_exception); 2958 break; 2959 } 2960 if (LocaleCompare("resize",option+1) == 0) 2961 { 2962 if (IfMagickFalse(IsGeometry(arg1))) 2963 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2964 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 2965 new_image=ResizeImage(_image,geometry.width,geometry.height, 2966 _image->filter,_exception); 2967 break; 2968 } 2969 if (LocaleCompare("roll",option+1) == 0) 2970 { 2971 if (IfMagickFalse(IsGeometry(arg1))) 2972 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2973 (void) ParsePageGeometry(_image,arg1,&geometry,_exception); 2974 new_image=RollImage(_image,geometry.x,geometry.y,_exception); 2975 break; 2976 } 2977 if (LocaleCompare("rotate",option+1) == 0) 2978 { 2979 flags=ParseGeometry(arg1,&geometry_info); 2980 if ((flags & RhoValue) == 0) 2981 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2982 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows)) 2983 break; 2984 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows)) 2985 break; 2986 new_image=RotateImage(_image,geometry_info.rho,_exception); 2987 break; 2988 } 2989 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 2990 } 2991 case 's': 2992 { 2993 if (LocaleCompare("sample",option+1) == 0) 2994 { 2995 /* FUTURE: Roll into a resize special operator */ 2996 if (IfMagickFalse(IsGeometry(arg1))) 2997 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 2998 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 2999 new_image=SampleImage(_image,geometry.width,geometry.height, 3000 _exception); 3001 break; 3002 } 3003 if (LocaleCompare("scale",option+1) == 0) 3004 { 3005 /* FUTURE: Roll into a resize special operator */ 3006 if (IfMagickFalse(IsGeometry(arg1))) 3007 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3008 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 3009 new_image=ScaleImage(_image,geometry.width,geometry.height, 3010 _exception); 3011 break; 3012 } 3013 if (LocaleCompare("segment",option+1) == 0) 3014 { 3015 flags=ParseGeometry(arg1,&geometry_info); 3016 if ((flags & (RhoValue|SigmaValue)) == 0) 3017 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3018 if ((flags & SigmaValue) == 0) 3019 geometry_info.sigma=1.0; 3020 (void) SegmentImage(_image,_image->colorspace, 3021 _image_info->verbose,geometry_info.rho,geometry_info.sigma, 3022 _exception); 3023 break; 3024 } 3025 if (LocaleCompare("selective-blur",option+1) == 0) 3026 { 3027 flags=ParseGeometry(arg1,&geometry_info); 3028 if ((flags & (RhoValue|SigmaValue)) == 0) 3029 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3030 if ((flags & SigmaValue) == 0) 3031 geometry_info.sigma=1.0; 3032 if ((flags & PercentValue) != 0) 3033 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0; 3034 new_image=SelectiveBlurImage(_image,geometry_info.rho, 3035 geometry_info.sigma,geometry_info.xi,_exception); 3036 break; 3037 } 3038 if (LocaleCompare("separate",option+1) == 0) 3039 { 3040 /* WARNING: This can generate multiple images! */ 3041 /* FUTURE - this may be replaced by a "-channel" method */ 3042 new_image=SeparateImages(_image,_exception); 3043 break; 3044 } 3045 if (LocaleCompare("sepia-tone",option+1) == 0) 3046 { 3047 if (IfMagickFalse(IsGeometry(arg1))) 3048 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3049 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1, 3050 (double) QuantumRange+1.0),_exception); 3051 break; 3052 } 3053 if (LocaleCompare("set",option+1) == 0) 3054 { 3055 char 3056 *value; 3057 3058 if (IfPlusOp) { 3059 if (LocaleNCompare(arg1,"registry:",9) == 0) 3060 (void) DeleteImageRegistry(arg1+9); 3061 else 3062 if (LocaleNCompare(arg1,"option:",7) == 0) 3063 { 3064 (void) DeleteImageOption(_image_info,arg1+7); 3065 (void) DeleteImageArtifact(_image,arg1+7); 3066 } 3067 else 3068 (void) DeleteImageProperty(_image,arg1); 3069 break; 3070 } 3071 value=InterpretImageProperties(_image_info,_image,arg2,_exception); 3072 if (value == (char *) NULL) 3073 break; 3074 if (LocaleNCompare(arg1,"registry:",9) == 0) 3075 (void) SetImageRegistry(StringRegistryType,arg1+9,value,_exception); 3076 else 3077 if (LocaleNCompare(arg1,"option:",7) == 0) 3078 { 3079 (void) SetImageOption(_image_info,arg1+7,value); 3080 (void) SetImageArtifact(_image,arg1+7,value); 3081 } 3082 else 3083 (void) SetImageProperty(_image,arg1,value,_exception); 3084 value=DestroyString(value); 3085 break; 3086 } 3087 if (LocaleCompare("shade",option+1) == 0) 3088 { 3089 flags=ParseGeometry(arg1,&geometry_info); 3090 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0)) 3091 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3092 new_image=ShadeImage(_image,normal_op,geometry_info.rho, 3093 geometry_info.sigma,_exception); 3094 break; 3095 } 3096 if (LocaleCompare("shadow",option+1) == 0) 3097 { 3098 flags=ParseGeometry(arg1,&geometry_info); 3099 if ((flags & (RhoValue|SigmaValue)) == 0) 3100 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3101 if ((flags & SigmaValue) == 0) 3102 geometry_info.sigma=1.0; 3103 if ((flags & XiValue) == 0) 3104 geometry_info.xi=4.0; 3105 if ((flags & PsiValue) == 0) 3106 geometry_info.psi=4.0; 3107 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma, 3108 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) 3109 ceil(geometry_info.psi-0.5),_exception); 3110 break; 3111 } 3112 if (LocaleCompare("sharpen",option+1) == 0) 3113 { 3114 flags=ParseGeometry(arg1,&geometry_info); 3115 if ((flags & (RhoValue|SigmaValue)) == 0) 3116 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3117 if ((flags & SigmaValue) == 0) 3118 geometry_info.sigma=1.0; 3119 if ((flags & XiValue) == 0) 3120 geometry_info.xi=0.0; 3121 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma, 3122 _exception); 3123 break; 3124 } 3125 if (LocaleCompare("shave",option+1) == 0) 3126 { 3127 if (IfMagickFalse(IsGeometry(arg1))) 3128 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3129 flags=ParsePageGeometry(_image,arg1,&geometry,_exception); 3130 new_image=ShaveImage(_image,&geometry,_exception); 3131 break; 3132 } 3133 if (LocaleCompare("shear",option+1) == 0) 3134 { 3135 flags=ParseGeometry(arg1,&geometry_info); 3136 if ((flags & RhoValue) == 0) 3137 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3138 if ((flags & SigmaValue) == 0) 3139 geometry_info.sigma=geometry_info.rho; 3140 new_image=ShearImage(_image,geometry_info.rho, 3141 geometry_info.sigma,_exception); 3142 break; 3143 } 3144 if (LocaleCompare("sigmoidal-contrast",option+1) == 0) 3145 { 3146 flags=ParseGeometry(arg1,&geometry_info); 3147 if ((flags & RhoValue) == 0) 3148 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3149 if ((flags & SigmaValue) == 0) 3150 geometry_info.sigma=(double) QuantumRange/2.0; 3151 if ((flags & PercentValue) != 0) 3152 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/ 3153 100.0; 3154 (void) SigmoidalContrastImage(_image,normal_op,geometry_info.rho, 3155 geometry_info.sigma,_exception); 3156 break; 3157 } 3158 if (LocaleCompare("sketch",option+1) == 0) 3159 { 3160 flags=ParseGeometry(arg1,&geometry_info); 3161 if ((flags & (RhoValue|SigmaValue)) == 0) 3162 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3163 if ((flags & SigmaValue) == 0) 3164 geometry_info.sigma=1.0; 3165 new_image=SketchImage(_image,geometry_info.rho, 3166 geometry_info.sigma,geometry_info.xi,_exception); 3167 break; 3168 } 3169 if (LocaleCompare("solarize",option+1) == 0) 3170 { 3171 if (IfMagickFalse(IsGeometry(arg1))) 3172 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3173 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double) 3174 QuantumRange+1.0),_exception); 3175 break; 3176 } 3177 if (LocaleCompare("sparse-color",option+1) == 0) 3178 { 3179 char 3180 *arguments; 3181 3182 parse= ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1); 3183 if ( parse < 0 ) 3184 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod", 3185 option,arg1); 3186 arguments=InterpretImageProperties(_image_info,_image,arg2,_exception); 3187 if (arguments == (char *) NULL) 3188 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 3189 new_image=SparseColorOption(_image,(SparseColorMethod)parse, 3190 arguments,_exception); 3191 arguments=DestroyString(arguments); 3192 break; 3193 } 3194 if (LocaleCompare("splice",option+1) == 0) 3195 { 3196 if (IfMagickFalse(IsGeometry(arg1))) 3197 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3198 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception); 3199 new_image=SpliceImage(_image,&geometry,_exception); 3200 break; 3201 } 3202 if (LocaleCompare("spread",option+1) == 0) 3203 { 3204 flags=ParseGeometry(arg1,&geometry_info); 3205 if ((flags & RhoValue) == 0) 3206 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 3207 new_image=SpreadImage(_image,geometry_info.rho,_image->interpolate, 3208 _exception); 3209 break; 3210 } 3211 if (LocaleCompare("statistic",option+1) == 0) 3212 { 3213 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1); 3214 if ( parse < 0 ) 3215 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType", 3216 option,arg1); 3217 flags=ParseGeometry(arg2,&geometry_info); 3218 if ((flags & RhoValue) == 0) 3219 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 3220 if ((flags & SigmaValue) == 0) 3221 geometry_info.sigma=geometry_info.rho; 3222 new_image=StatisticImage(_image,(StatisticType)parse, 3223 (size_t) geometry_info.rho,(size_t) geometry_info.sigma, 3224 _exception); 3225 break; 3226 } 3227 if (LocaleCompare("strip",option+1) == 0) 3228 { 3229 (void) StripImage(_image,_exception); 3230 break; 3231 } 3232 if (LocaleCompare("swirl",option+1) == 0) 3233 { 3234 flags=ParseGeometry(arg2,&geometry_info); 3235 if ((flags & RhoValue) == 0) 3236 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2); 3237 new_image=SwirlImage(_image,geometry_info.rho, 3238 _image->interpolate,_exception); 3239 break; 3240 } 3241 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3242 } 3243 case 't': 3244 { 3245 if (LocaleCompare("threshold",option+1) == 0) 3246 { 3247 double 3248 threshold; 3249 3250 threshold=(double) QuantumRange/2; 3251 if (normal_op) { 3252 if (IfMagickFalse(IsGeometry(arg1))) 3253 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3254 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0); 3255 } 3256 (void) BilevelImage(_image,threshold,_exception); 3257 break; 3258 } 3259 if (LocaleCompare("thumbnail",option+1) == 0) 3260 { 3261 if (IfMagickFalse(IsGeometry(arg1))) 3262 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3263 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception); 3264 new_image=ThumbnailImage(_image,geometry.width,geometry.height, 3265 _exception); 3266 break; 3267 } 3268 if (LocaleCompare("tint",option+1) == 0) 3269 { 3270 if (IfMagickFalse(IsGeometry(arg1))) 3271 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3272 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception); 3273 break; 3274 } 3275 if (LocaleCompare("transform",option+1) == 0) 3276 { 3277 CLIWandWarnReplaced("+distort AffineProjection"); 3278 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception); 3279 break; 3280 } 3281 if (LocaleCompare("transparent",option+1) == 0) 3282 { 3283 PixelInfo 3284 target; 3285 3286 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception); 3287 (void) TransparentPaintImage(_image,&target,(Quantum) 3288 TransparentAlpha,plus_alt_op,_exception); 3289 break; 3290 } 3291 if (LocaleCompare("transpose",option+1) == 0) 3292 { 3293 new_image=TransposeImage(_image,_exception); 3294 break; 3295 } 3296 if (LocaleCompare("transverse",option+1) == 0) 3297 { 3298 new_image=TransverseImage(_image,_exception); 3299 break; 3300 } 3301 if (LocaleCompare("trim",option+1) == 0) 3302 { 3303 new_image=TrimImage(_image,_exception); 3304 break; 3305 } 3306 if (LocaleCompare("type",option+1) == 0) 3307 { 3308 /* Note that "type" setting should have already been defined */ 3309 (void) SetImageType(_image,_image_info->type,_exception); 3310 break; 3311 } 3312 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3313 } 3314 case 'u': 3315 { 3316 if (LocaleCompare("unique",option+1) == 0) 3317 { 3318 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? 3319 Option is not documented, bt appears to be for "identify". 3320 We may need a identify specific verbose! 3321 */ 3322 if (plus_alt_op) { 3323 (void) DeleteImageArtifact(_image,"identify:unique-colors"); 3324 break; 3325 } 3326 (void) SetImageArtifact(_image,"identify:unique-colors","true"); 3327 (void) SetImageArtifact(_image,"verbose","true"); 3328 break; 3329 } 3330 if (LocaleCompare("unique-colors",option+1) == 0) 3331 { 3332 new_image=UniqueImageColors(_image,_exception); 3333 break; 3334 } 3335 if (LocaleCompare("unsharp",option+1) == 0) 3336 { 3337 flags=ParseGeometry(arg1,&geometry_info); 3338 if ((flags & (RhoValue|SigmaValue)) == 0) 3339 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3340 if ((flags & SigmaValue) == 0) 3341 geometry_info.sigma=1.0; 3342 if ((flags & XiValue) == 0) 3343 geometry_info.xi=1.0; 3344 if ((flags & PsiValue) == 0) 3345 geometry_info.psi=0.05; 3346 new_image=UnsharpMaskImage(_image,geometry_info.rho, 3347 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception); 3348 break; 3349 } 3350 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3351 } 3352 case 'v': 3353 { 3354 if (LocaleCompare("verbose",option+1) == 0) 3355 { 3356 /* FUTURE: move to SyncImageSettings() and AcquireImage()??? 3357 three places! ImageArtifact ImageOption _image_info->verbose 3358 Some how new images also get this artifact! 3359 */ 3360 (void) SetImageArtifact(_image,option+1, 3361 IfNormalOp ? "true" : "false" ); 3362 break; 3363 } 3364 if (LocaleCompare("vignette",option+1) == 0) 3365 { 3366 flags=ParseGeometry(arg1,&geometry_info); 3367 if ((flags & (RhoValue|SigmaValue)) == 0) 3368 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3369 if ((flags & SigmaValue) == 0) 3370 geometry_info.sigma=1.0; 3371 if ((flags & XiValue) == 0) 3372 geometry_info.xi=0.1*_image->columns; 3373 if ((flags & PsiValue) == 0) 3374 geometry_info.psi=0.1*_image->rows; 3375 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma, 3376 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) 3377 ceil(geometry_info.psi-0.5),_exception); 3378 break; 3379 } 3380 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3381 } 3382 case 'w': 3383 { 3384 if (LocaleCompare("wave",option+1) == 0) 3385 { 3386 flags=ParseGeometry(arg1,&geometry_info); 3387 if ((flags & (RhoValue|SigmaValue)) == 0) 3388 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3389 if ((flags & SigmaValue) == 0) 3390 geometry_info.sigma=1.0; 3391 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma, 3392 _image->interpolate,_exception); 3393 break; 3394 } 3395 if (LocaleCompare("white-threshold",option+1) == 0) 3396 { 3397 if (IfMagickFalse(IsGeometry(arg1))) 3398 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3399 (void) WhiteThresholdImage(_image,arg1,_exception); 3400 break; 3401 } 3402 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3403 } 3404 default: 3405 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3406 } 3407 /* 3408 Replace current image with any image that was generated 3409 and set image point to last image (so image->next is correct) 3410 */ 3411 if (new_image != (Image *) NULL) 3412 ReplaceImageInListReturnLast(&_image,new_image); 3413 3414 return; 3415#undef _image_info 3416#undef _draw_info 3417#undef _quantize_info 3418#undef _image 3419#undef _exception 3420#undef IfNormalOp 3421#undef IfPlusOp 3422#undef normal_op 3423#undef plus_alt_op 3424} 3425 3426WandExport void CLISimpleOperatorImages(MagickCLI *cli_wand, 3427 const char *option, const char *arg1, const char *arg2) 3428{ 3429 size_t 3430 n, 3431 i; 3432 3433 assert(cli_wand != (MagickCLI *) NULL); 3434 assert(cli_wand->signature == WandSignature); 3435 assert(cli_wand->wand.signature == WandSignature); 3436 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */ 3437 if (IfMagickTrue(cli_wand->wand.debug)) 3438 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 3439 3440#if !USE_WAND_METHODS 3441 /* FUTURE add appropriate tracing */ 3442 i=0; 3443 n=GetImageListLength(cli_wand->wand.images); 3444 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images); 3445 while (1) { 3446 i++; 3447 CLISimpleOperatorImage(cli_wand, option, arg1, arg2); 3448 if ( cli_wand->wand.images->next == (Image *) NULL ) 3449 break; 3450 cli_wand->wand.images=cli_wand->wand.images->next; 3451 } 3452 assert( i == n ); 3453 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images); 3454#else 3455 MagickResetIterator(&cli_wand->wand); 3456 while ( IfMagickTrue(MagickNextImage(&cli_wand->wand)) ) 3457 CLISimpleOperatorImage(cli_wand, option, arg1, arg2); 3458 MagickResetIterator(&cli_wand->wand); 3459#endif 3460 return; 3461} 3462 3463/* 3464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3465% % 3466% % 3467% % 3468+ C L I L i s t O p e r a t o r I m a g e s % 3469% % 3470% % 3471% % 3472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3473% 3474% CLIListOperatorImages() applies a single operation that is apply to the 3475% entire image list as a whole. The result is often a complete replacment 3476% of the image list with a completely new list, or just a single image. 3477% 3478% The format of the MogrifyImage method is: 3479% 3480% void CLIListOperatorImages(MagickCLI *cli_wand, 3481% const char *option, const char *arg1, const char *arg2) 3482% 3483% A description of each parameter follows: 3484% 3485% o cli_wand: structure holding settings to be applied 3486% 3487% o option: The option string for the operation 3488% 3489% o arg1, arg2: optional argument strings to the operation 3490% arg2 is currently not used 3491% 3492*/ 3493WandExport void CLIListOperatorImages(MagickCLI *cli_wand, 3494 const char *option,const char *arg1, const char *magick_unused(arg2)) 3495{ 3496 ssize_t 3497 parse; 3498 3499 Image 3500 *new_images; 3501 3502#define _image_info (cli_wand->wand.image_info) 3503#define _images (cli_wand->wand.images) 3504#define _exception (cli_wand->wand.exception) 3505#define _draw_info (cli_wand->draw_info) 3506#define _quantize_info (cli_wand->quantize_info) 3507#define IfNormalOp (*option=='-') 3508#define IfPlusOp (*option!='-') 3509#define normal_op IsMagickTrue(IfNormalOp) 3510 3511 assert(cli_wand != (MagickCLI *) NULL); 3512 assert(cli_wand->signature == WandSignature); 3513 assert(cli_wand->wand.signature == WandSignature); 3514 assert(_images != (Image *) NULL); /* _images must be present */ 3515 if (IfMagickTrue(cli_wand->wand.debug)) 3516 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 3517 3518 new_images=NewImageList(); 3519 3520 switch (*(option+1)) 3521 { 3522 case 'a': 3523 { 3524 if (LocaleCompare("append",option+1) == 0) 3525 { 3526 new_images=AppendImages(_images,normal_op,_exception); 3527 break; 3528 } 3529 if (LocaleCompare("average",option+1) == 0) 3530 { 3531 CLIWandWarnReplaced("-evaluate-sequence Mean"); 3532 CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",NULL); 3533 break; 3534 } 3535 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3536 } 3537 case 'c': 3538 { 3539 if (LocaleCompare("channel-fx",option+1) == 0) 3540 { 3541 new_images=ChannelFxImage(_images,arg1,_exception); 3542 break; 3543 } 3544 if (LocaleCompare("clut",option+1) == 0) 3545 { 3546 Image 3547 *clut_image; 3548 3549 /* FUTURE - make this a compose option, and thus can be used 3550 with layers compose or even compose last image over all other 3551 _images. 3552 */ 3553 new_images=RemoveFirstImageFromList(&_images); 3554 clut_image=RemoveLastImageFromList(&_images); 3555 /* FUTURE - produce Exception, rather than silent fail */ 3556 if (clut_image == (Image *) NULL) 3557 break; 3558 (void) ClutImage(new_images,clut_image,new_images->interpolate,_exception); 3559 clut_image=DestroyImage(clut_image); 3560 break; 3561 } 3562 if (LocaleCompare("coalesce",option+1) == 0) 3563 { 3564 new_images=CoalesceImages(_images,_exception); 3565 break; 3566 } 3567 if (LocaleCompare("combine",option+1) == 0) 3568 { 3569 /* FUTURE - this may be replaced by a 'channel' method */ 3570 new_images=CombineImages(_images,_exception); 3571 break; 3572 } 3573 if (LocaleCompare("composite",option+1) == 0) 3574 { 3575 CompositeOperator 3576 compose; 3577 3578 const char* 3579 value; 3580 3581 MagickBooleanType 3582 clip_to_self; 3583 3584 Image 3585 *mask_image, 3586 *source_image; 3587 3588 RectangleInfo 3589 geometry; 3590 3591 /* Compose value from "-compose" option only */ 3592 value=GetImageOption(_image_info,"compose"); 3593 if (value == (const char *) NULL) 3594 compose=OverCompositeOp; /* use Over not source_image->compose */ 3595 else 3596 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions, 3597 MagickFalse,value); 3598 3599 /* Get "clip-to-self" expert setting (false is normal) */ 3600 value=GetImageOption(_image_info,"compose:clip-to-self"); 3601 if (value == (const char *) NULL) 3602 clip_to_self=MagickTrue; 3603 else 3604 clip_to_self=IsStringTrue(GetImageOption(_image_info, 3605 "compose:clip-to-self")); /* if this is true */ 3606 value=GetImageOption(_image_info,"compose:outside-overlay"); 3607 if (value != (const char *) NULL) { /* or this false */ 3608 /* FUTURE: depreciate warning for "compose:outside-overlay"*/ 3609 clip_to_self= IsMagickFalse(IsStringNotFalse(value)); 3610 } 3611 3612 new_images=RemoveFirstImageFromList(&_images); 3613 source_image=RemoveFirstImageFromList(&_images); 3614 if (source_image == (Image *) NULL) 3615 break; /* FUTURE - produce Exception, rather than silent fail */ 3616 3617 /* FUTURE - this should not be here! - should be part of -geometry */ 3618 (void) TransformImage(&source_image,(char *) NULL, 3619 source_image->geometry,_exception); 3620 3621 SetGeometry(source_image,&geometry); 3622 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry); 3623 GravityAdjustGeometry(new_images->columns,new_images->rows, 3624 new_images->gravity, &geometry); 3625 3626 mask_image=RemoveFirstImageFromList(&_images); 3627 if (mask_image != (Image *) NULL) 3628 { /* handle a third write mask image */ 3629 if ((compose == DisplaceCompositeOp) || 3630 (compose == DistortCompositeOp)) { 3631 /* Merge Y displacement into X displace/distort map. */ 3632 (void) CompositeImage(source_image,mask_image, 3633 CopyGreenCompositeOp,MagickTrue,0,0,_exception); 3634 mask_image=DestroyImage(mask_image); 3635 } 3636 else { 3637 /* Set a blending mask for the composition. */ 3638 (void) NegateImage(mask_image,MagickFalse,_exception); 3639 (void) SetImageMask(new_images,mask_image,_exception); 3640 mask_image=DestroyImage(mask_image); 3641 } 3642 } 3643 (void) CompositeImage(new_images,source_image,compose,clip_to_self, 3644 geometry.x,geometry.y,_exception); 3645 (void) SetImageMask(new_images,(Image *) NULL,_exception); 3646 source_image=DestroyImage(source_image); 3647 break; 3648 } 3649 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3650 } 3651 case 'd': 3652 { 3653 if (LocaleCompare("deconstruct",option+1) == 0) 3654 { 3655 CLIWandWarnReplaced("-layer CompareAny"); 3656 CLIListOperatorImages(cli_wand,"-layer","CompareAny",NULL); 3657 break; 3658 } 3659 if (LocaleCompare("delete",option+1) == 0) 3660 { 3661 if (IfNormalOp) 3662 DeleteImages(&_images,arg1,_exception); 3663 else 3664 DeleteImages(&_images,"-1",_exception); 3665 break; 3666 } 3667 if (LocaleCompare("duplicate",option+1) == 0) 3668 { 3669 if (IfNormalOp) 3670 { 3671 const char 3672 *p; 3673 3674 size_t 3675 number_duplicates; 3676 3677 if (IfMagickFalse(IsGeometry(arg1))) 3678 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option, 3679 arg1); 3680 number_duplicates=(size_t) StringToLong(arg1); 3681 p=strchr(arg1,','); 3682 if (p == (const char *) NULL) 3683 new_images=DuplicateImages(_images,number_duplicates,"-1", 3684 _exception); 3685 else 3686 new_images=DuplicateImages(_images,number_duplicates,p, 3687 _exception); 3688 } 3689 else 3690 new_images=DuplicateImages(_images,1,"-1",_exception); 3691 AppendImageToList(&_images, new_images); 3692 new_images=(Image *)NULL; 3693 break; 3694 } 3695 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3696 } 3697 case 'e': 3698 { 3699 if (LocaleCompare("evaluate-sequence",option+1) == 0) 3700 { 3701 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1); 3702 if ( parse < 0 ) 3703 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator", 3704 option,arg1); 3705 new_images=EvaluateImages(_images,(MagickEvaluateOperator)parse, 3706 _exception); 3707 break; 3708 } 3709 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3710 } 3711 case 'f': 3712 { 3713 if (LocaleCompare("fft",option+1) == 0) 3714 { 3715 new_images=ForwardFourierTransformImage(_images,normal_op,_exception); 3716 break; 3717 } 3718 if (LocaleCompare("flatten",option+1) == 0) 3719 { 3720 /* REDIRECTED to use -layers flatten instead */ 3721 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL); 3722 break; 3723 } 3724 if (LocaleCompare("fx",option+1) == 0) 3725 { 3726 new_images=FxImage(_images,arg1,_exception); 3727 break; 3728 } 3729 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3730 } 3731 case 'h': 3732 { 3733 if (LocaleCompare("hald-clut",option+1) == 0) 3734 { 3735 /* FUTURE - make this a compose option (and thus layers compose ) 3736 or perhaps compose last image over all other _images. 3737 */ 3738 Image 3739 *hald_image; 3740 3741 new_images=RemoveFirstImageFromList(&_images); 3742 hald_image=RemoveLastImageFromList(&_images); 3743 if (hald_image == (Image *) NULL) 3744 break; 3745 (void) HaldClutImage(new_images,hald_image,_exception); 3746 hald_image=DestroyImage(hald_image); 3747 break; 3748 } 3749 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3750 } 3751 case 'i': 3752 { 3753 if (LocaleCompare("ift",option+1) == 0) 3754 { 3755 Image 3756 *magnitude_image, 3757 *phase_image; 3758 3759 magnitude_image=RemoveFirstImageFromList(&_images); 3760 phase_image=RemoveFirstImageFromList(&_images); 3761 /* FUTURE - produce Exception, rather than silent fail */ 3762 if (phase_image == (Image *) NULL) 3763 break; 3764 new_images=InverseFourierTransformImage(magnitude_image,phase_image, 3765 normal_op,_exception); 3766 magnitude_image=DestroyImage(magnitude_image); 3767 phase_image=DestroyImage(phase_image); 3768 break; 3769 } 3770 if (LocaleCompare("insert",option+1) == 0) 3771 { 3772 Image 3773 *insert_image, 3774 *index_image; 3775 3776 ssize_t 3777 index; 3778 3779 if (IfNormalOp && IfMagickFalse(IsGeometry(arg1))) 3780 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3781 index=0; 3782 insert_image=RemoveLastImageFromList(&_images); 3783 if (IfNormalOp) 3784 index=(ssize_t) StringToLong(arg1); 3785 index_image=insert_image; 3786 if (index == 0) 3787 PrependImageToList(&_images,insert_image); 3788 else if (index == (ssize_t) GetImageListLength(_images)) 3789 AppendImageToList(&_images,insert_image); 3790 else 3791 { 3792 index_image=GetImageFromList(_images,index-1); 3793 if (index_image == (Image *) NULL) 3794 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1); 3795 InsertImageInList(&index_image,insert_image); 3796 } 3797 _images=GetFirstImageInList(index_image); 3798 break; 3799 } 3800 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3801 } 3802 case 'l': 3803 { 3804 if (LocaleCompare("layers",option+1) == 0) 3805 { 3806 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1); 3807 if ( parse < 0 ) 3808 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod", 3809 option,arg1); 3810 switch ((ImageLayerMethod) parse) 3811 { 3812 case CoalesceLayer: 3813 { 3814 new_images=CoalesceImages(_images,_exception); 3815 break; 3816 } 3817 case CompareAnyLayer: 3818 case CompareClearLayer: 3819 case CompareOverlayLayer: 3820 default: 3821 { 3822 new_images=CompareImagesLayers(_images,(ImageLayerMethod) parse, 3823 _exception); 3824 break; 3825 } 3826 case MergeLayer: 3827 case FlattenLayer: 3828 case MosaicLayer: 3829 case TrimBoundsLayer: 3830 { 3831 new_images=MergeImageLayers(_images,(ImageLayerMethod) parse, 3832 _exception); 3833 break; 3834 } 3835 case DisposeLayer: 3836 { 3837 new_images=DisposeImages(_images,_exception); 3838 break; 3839 } 3840 case OptimizeImageLayer: 3841 { 3842 new_images=OptimizeImageLayers(_images,_exception); 3843 break; 3844 } 3845 case OptimizePlusLayer: 3846 { 3847 new_images=OptimizePlusImageLayers(_images,_exception); 3848 break; 3849 } 3850 case OptimizeTransLayer: 3851 { 3852 OptimizeImageTransparency(_images,_exception); 3853 break; 3854 } 3855 case RemoveDupsLayer: 3856 { 3857 RemoveDuplicateLayers(&_images,_exception); 3858 break; 3859 } 3860 case RemoveZeroLayer: 3861 { 3862 RemoveZeroDelayLayers(&_images,_exception); 3863 break; 3864 } 3865 case OptimizeLayer: 3866 { /* General Purpose, GIF Animation Optimizer. */ 3867 new_images=CoalesceImages(_images,_exception); 3868 if (new_images == (Image *) NULL) 3869 break; 3870 _images=DestroyImageList(_images); 3871 _images=OptimizeImageLayers(new_images,_exception); 3872 if (_images == (Image *) NULL) 3873 break; 3874 new_images=DestroyImageList(new_images); 3875 OptimizeImageTransparency(_images,_exception); 3876 (void) RemapImages(_quantize_info,_images,(Image *) NULL, 3877 _exception); 3878 break; 3879 } 3880 case CompositeLayer: 3881 { 3882 Image 3883 *source; 3884 3885 RectangleInfo 3886 geometry; 3887 3888 CompositeOperator 3889 compose; 3890 3891 const char* 3892 value; 3893 3894 value=GetImageOption(_image_info,"compose"); 3895 compose=OverCompositeOp; /* Default to Over */ 3896 if (value != (const char *) NULL) 3897 compose=(CompositeOperator) ParseCommandOption( 3898 MagickComposeOptions,MagickFalse,value); 3899 3900 /* Split image sequence at the first 'NULL:' image. */ 3901 source=_images; 3902 while (source != (Image *) NULL) 3903 { 3904 source=GetNextImageInList(source); 3905 if ((source != (Image *) NULL) && 3906 (LocaleCompare(source->magick,"NULL") == 0)) 3907 break; 3908 } 3909 if (source != (Image *) NULL) 3910 { 3911 if ((GetPreviousImageInList(source) == (Image *) NULL) || 3912 (GetNextImageInList(source) == (Image *) NULL)) 3913 source=(Image *) NULL; 3914 else 3915 { /* Separate the two lists, junk the null: image. */ 3916 source=SplitImageList(source->previous); 3917 DeleteImageFromList(&source); 3918 } 3919 } 3920 if (source == (Image *) NULL) 3921 { 3922 (void) ThrowMagickException(_exception,GetMagickModule(), 3923 OptionError,"MissingNullSeparator","layers Composite"); 3924 break; 3925 } 3926 /* Adjust offset with gravity and virtual canvas. */ 3927 SetGeometry(_images,&geometry); 3928 (void) ParseAbsoluteGeometry(_images->geometry,&geometry); 3929 geometry.width=source->page.width != 0 ? 3930 source->page.width : source->columns; 3931 geometry.height=source->page.height != 0 ? 3932 source->page.height : source->rows; 3933 GravityAdjustGeometry(_images->page.width != 0 ? 3934 _images->page.width : _images->columns, 3935 _images->page.height != 0 ? _images->page.height : 3936 _images->rows,_images->gravity,&geometry); 3937 3938 /* Compose the two image sequences together */ 3939 CompositeLayers(_images,compose,source,geometry.x,geometry.y, 3940 _exception); 3941 source=DestroyImageList(source); 3942 break; 3943 } 3944 } 3945 break; 3946 } 3947 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3948 } 3949 case 'm': 3950 { 3951 if (LocaleCompare("map",option+1) == 0) 3952 { 3953 CLIWandWarnReplaced("+remap"); 3954 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception); 3955 break; 3956 } 3957 if (LocaleCompare("morph",option+1) == 0) 3958 { 3959 Image 3960 *morph_image; 3961 3962 if (IfMagickFalse(IsGeometry(arg1))) 3963 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 3964 morph_image=MorphImages(_images,StringToUnsignedLong(arg1), 3965 _exception); 3966 if (morph_image == (Image *) NULL) 3967 break; 3968 _images=DestroyImageList(_images); 3969 _images=morph_image; 3970 break; 3971 } 3972 if (LocaleCompare("mosaic",option+1) == 0) 3973 { 3974 /* REDIRECTED to use -layers mosaic instead */ 3975 CLIListOperatorImages(cli_wand,"-layers",option+1,NULL); 3976 break; 3977 } 3978 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 3979 } 3980 case 'p': 3981 { 3982 if (LocaleCompare("print",option+1) == 0) 3983 { 3984 char 3985 *string; 3986 3987 string=InterpretImageProperties(_image_info,_images,arg1,_exception); 3988 if (string == (char *) NULL) 3989 break; 3990 (void) FormatLocaleFile(stdout,"%s",string); 3991 string=DestroyString(string); 3992 break; 3993 } 3994 if (LocaleCompare("process",option+1) == 0) 3995 { 3996 /* FUTURE: better parsing using ScriptToken() from string ??? */ 3997 char 3998 **arguments; 3999 4000 int 4001 j, 4002 number_arguments; 4003 4004 arguments=StringToArgv(arg1,&number_arguments); 4005 if (arguments == (char **) NULL) 4006 break; 4007 if (strchr(arguments[1],'=') != (char *) NULL) 4008 { 4009 char 4010 breaker, 4011 quote, 4012 *token; 4013 4014 const char 4015 *arguments; 4016 4017 int 4018 next, 4019 status; 4020 4021 size_t 4022 length; 4023 4024 TokenInfo 4025 *token_info; 4026 4027 /* 4028 Support old style syntax, filter="-option arg1". 4029 */ 4030 length=strlen(arg1); 4031 token=(char *) NULL; 4032 if (~length >= (MaxTextExtent-1)) 4033 token=(char *) AcquireQuantumMemory(length+MaxTextExtent, 4034 sizeof(*token)); 4035 if (token == (char *) NULL) 4036 break; 4037 next=0; 4038 arguments=arg1; 4039 token_info=AcquireTokenInfo(); 4040 status=Tokenizer(token_info,0,token,length,arguments,"","=", 4041 "\"",'\0',&breaker,&next,"e); 4042 token_info=DestroyTokenInfo(token_info); 4043 if (status == 0) 4044 { 4045 const char 4046 *argv; 4047 4048 argv=(&(arguments[next])); 4049 (void) InvokeDynamicImageFilter(token,&_images,1,&argv, 4050 _exception); 4051 } 4052 token=DestroyString(token); 4053 break; 4054 } 4055 (void) SubstituteString(&arguments[1],"-",""); 4056 (void) InvokeDynamicImageFilter(arguments[1],&_images, 4057 number_arguments-2,(const char **) arguments+2,_exception); 4058 for (j=0; j < number_arguments; j++) 4059 arguments[j]=DestroyString(arguments[j]); 4060 arguments=(char **) RelinquishMagickMemory(arguments); 4061 break; 4062 } 4063 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4064 } 4065 case 'r': 4066 { 4067 if (LocaleCompare("remap",option+1) == 0) 4068 { 4069 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception); 4070 break; 4071 } 4072 if (LocaleCompare("reverse",option+1) == 0) 4073 { 4074 ReverseImageList(&_images); 4075 break; 4076 } 4077 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4078 } 4079 case 's': 4080 { 4081 if (LocaleCompare("smush",option+1) == 0) 4082 { 4083 /* FUTURE: this option needs more work to make better */ 4084 ssize_t 4085 offset; 4086 4087 if (IfMagickFalse(IsGeometry(arg1))) 4088 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 4089 offset=(ssize_t) StringToLong(arg1); 4090 new_images=SmushImages(_images,normal_op,offset,_exception); 4091 break; 4092 } 4093 if (LocaleCompare("subimage",option+1) == 0) 4094 { 4095 Image 4096 *base_image, 4097 *compare_image; 4098 4099 const char * 4100 value; 4101 4102 MetricType 4103 metric; 4104 4105 double 4106 similarity; 4107 4108 RectangleInfo 4109 offset; 4110 4111 base_image=GetImageFromList(_images,0); 4112 compare_image=GetImageFromList(_images,1); 4113 4114 /* Comparision Metric */ 4115 metric=UndefinedMetric; 4116 value=GetImageOption(_image_info,"metric"); 4117 if (value != (const char *) NULL) 4118 metric=(MetricType) ParseCommandOption(MagickMetricOptions, 4119 MagickFalse,value); 4120 4121 new_images=SimilarityImage(base_image,compare_image,metric, 4122 &offset,&similarity,_exception); 4123 4124 if ( new_images != (Image *)NULL ) { 4125 char 4126 result[MaxTextExtent]; 4127 4128 (void) FormatLocaleString(result,MaxTextExtent,"%lf",similarity); 4129 (void) SetImageProperty(new_images,"subimage:similarity",result, 4130 _exception); 4131 (void) FormatLocaleString(result,MaxTextExtent,"%+ld", 4132 (long) offset.x); 4133 (void) SetImageProperty(new_images,"subimage:x",result, 4134 _exception); 4135 (void) FormatLocaleString(result,MaxTextExtent,"%+ld", 4136 (long) offset.y); 4137 (void) SetImageProperty(new_images,"subimage:y",result, 4138 _exception); 4139 (void) FormatLocaleString(result,MaxTextExtent,"%lux%lu%+ld%+ld", 4140 (unsigned long) offset.width,(unsigned long) offset.height, 4141 (long) offset.x,(long) offset.y); 4142 (void) SetImageProperty(new_images,"subimage:offset",result, 4143 _exception); 4144 } 4145 break; 4146 } 4147 if (LocaleCompare("swap",option+1) == 0) { 4148 Image 4149 *p, 4150 *q, 4151 *swap; 4152 4153 ssize_t 4154 index, 4155 swap_index; 4156 4157 index=-1; 4158 swap_index=-2; 4159 if (IfNormalOp) { 4160 GeometryInfo 4161 geometry_info; 4162 4163 MagickStatusType 4164 flags; 4165 4166 swap_index=(-1); 4167 flags=ParseGeometry(arg1,&geometry_info); 4168 if ((flags & RhoValue) != 0) 4169 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1); 4170 index=(ssize_t) geometry_info.rho; 4171 if ((flags & SigmaValue) != 0) 4172 swap_index=(ssize_t) geometry_info.sigma; 4173 } 4174 p=GetImageFromList(_images,index); 4175 q=GetImageFromList(_images,swap_index); 4176 if ((p == (Image *) NULL) || (q == (Image *) NULL)) { 4177 if (IfNormalOp) 4178 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1) 4179 else 4180 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option); 4181 } 4182 if (p == q) 4183 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1); 4184 swap=CloneImage(p,0,0,MagickTrue,_exception); 4185 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception)); 4186 ReplaceImageInList(&q,swap); 4187 _images=GetFirstImageInList(q); 4188 break; 4189 } 4190 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4191 } 4192 default: 4193 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option); 4194 } 4195 if (new_images == (Image *) NULL) 4196 return; 4197 4198 if (_images != (Image *) NULL) 4199 _images=DestroyImageList(_images); 4200 _images=GetFirstImageInList(new_images); 4201 return; 4202 4203#undef _image_info 4204#undef _images 4205#undef _exception 4206#undef _draw_info 4207#undef _quantize_info 4208#undef IfNormalOp 4209#undef IfPlusOp 4210#undef normal_op 4211} 4212 4213/* 4214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4215% % 4216% % 4217% % 4218+ C L I S p e c i a l O p e r a t i o n s % 4219% % 4220% % 4221% % 4222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4223% 4224% CLINoImageOperator() Applies operations that may not actually need images 4225% in an image list wen it is applied. 4226% 4227% The classic operators of this type is -read, which actually creates images 4228% even when no images are present. Or image stack operators, which can be 4229% applied to empty image lists. 4230% 4231% Note: unlike other Operators, these may involve other special 'option' 4232% character prefixes, other than simply '-' or '+'. 4233% 4234% The format of the CLINoImageOption method is: 4235% 4236% void CLINoImageOption(MagickCLI *cli_wand,const char *option, 4237% const char *arg1, const char *arg2) 4238% 4239% A description of each parameter follows: 4240% 4241% o cli_wand: the main CLI Wand to use. 4242% 4243% o option: The special option (with any switch char) to process 4244% 4245% o arg1 & arg2: Argument for option, if required 4246% Currently arg2 is not used. 4247% 4248*/ 4249WandExport void CLINoImageOperator(MagickCLI *cli_wand, 4250 const char *option, const char *arg1, const char *magick_unused(arg2)) 4251{ 4252#define _image_info (cli_wand->wand.image_info) 4253#define _images (cli_wand->wand.images) 4254#define _exception (cli_wand->wand.exception) 4255#define IfNormalOp (*option=='-') 4256#define IfPlusOp (*option!='-') 4257 4258 assert(cli_wand != (MagickCLI *) NULL); 4259 assert(cli_wand->signature == WandSignature); 4260 assert(cli_wand->wand.signature == WandSignature); 4261 if (IfMagickTrue(cli_wand->wand.debug)) 4262 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 4263 4264 /* 4265 No-op options (ignore these) 4266 */ 4267 if (LocaleCompare("noop",option+1) == 0) /* no argument */ 4268 return; 4269 if (LocaleCompare("sans",option+1) == 0) /* one argument */ 4270 return; 4271 if (LocaleCompare("sans0",option+1) == 0) /* no argument */ 4272 return; 4273 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */ 4274 return; 4275 /* 4276 Image Reading 4277 */ 4278 if ( ( LocaleCompare("read",option+1) == 0 ) || 4279 ( LocaleCompare("--",option) == 0 ) ) { 4280#if 0 4281 /* Directly read 'arg1' without filename expansion handling (see below). 4282 This does NOT turn off the 'coder:' prefix, or '[...]' read modifiers. 4283 */ 4284# if !USE_WAND_METHODS 4285 Image *new_images; 4286 4287 if (IfMagickTrue(_image_info->ping)) 4288 new_images=PingImages(_image_info,arg1,_exception); 4289 else 4290 new_images=ReadImages(_image_info,arg1,_exception); 4291 AppendImageToList(&_images, new_images); 4292# else 4293 /* read images using MagickWand method - no ping */ 4294 /* This is not working! - it locks up in a CPU loop! */ 4295 MagickSetLastIterator(&cli_wand->wand); 4296 MagickReadImage(&cli_wand->wand,arg1); 4297 MagickSetFirstIterator(&cli_wand->wand); 4298# endif 4299#else 4300 /* Do Filename Expansion for 'arg1' then read all images. 4301 * 4302 * Expansion handles '@', '~', '*', and '?' meta-characters while ignoring 4303 * (but attaching to generated argument list) any [...] read modifiers 4304 * that may be present. 4305 * 4306 * For example: correctly expand '*.gif[20x20]' into a list such as 4307 * 'abc.gif[20x20', 'foobar.gif[20x20]', 'xyzzy.gif[20x20]' 4308 * 4309 * NOTE: In IMv6 this was done globally across all images. This 4310 * meant you could include IM options in '@filename' lists, but you 4311 * could not include comments. Doing it only for image read makes 4312 * it far more secure. 4313 */ 4314 int argc; 4315 char **argv; 4316 ssize_t i; 4317 4318 argc = 1; 4319 argv = (char **) &arg1; 4320 4321 if (IfMagickFalse(ExpandFilenames(&argc,&argv))) 4322 CLIWandExceptArgReturn(ResourceLimitError,"MemoryAllocationFailed", 4323 option,GetExceptionMessage(errno)); 4324 4325 /* loop over expanded filename list, and read then all in */ 4326 for (i=0; i<argc; i++) { 4327 Image * 4328 new_images; 4329#if 1 4330fprintf(stderr, "DEBUG: Reading image: \"%s\"\n", argv[i]); 4331#endif 4332 if (IfMagickTrue(_image_info->ping)) 4333 new_images=PingImages(_image_info,argv[i],_exception); 4334 else 4335 new_images=ReadImages(_image_info,argv[i],_exception); 4336 AppendImageToList(&_images, new_images); 4337 } 4338 /* FUTURE: how do I free the expanded filename array memory ??? */ 4339 //argv=DestroyStringList(argv); /* Is this correct? */ 4340#endif 4341 return; 4342 } 4343 /* 4344 Image Writing 4345 Note: Writing a empty image list is valid in specific cases 4346 */ 4347 if (LocaleCompare("write",option+1) == 0) { 4348 char 4349 key[MaxTextExtent]; 4350 4351 Image 4352 *write_images; 4353 4354 ImageInfo 4355 *write_info; 4356 4357 /* Need images, unless a "null:" output coder is used */ 4358 if ( cli_wand->wand.images == (Image *) NULL ) { 4359 if ( LocaleCompare(arg1,"null:") == 0 ) 4360 return; 4361 CLIWandExceptArgReturn(OptionError,"NoImagesForWrite",option,arg1); 4362 } 4363 4364 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1); 4365 (void) DeleteImageRegistry(key); 4366 write_images=_images; 4367 if (IfPlusOp) 4368 write_images=CloneImageList(_images,_exception); 4369 write_info=CloneImageInfo(_image_info); 4370 (void) WriteImages(write_info,write_images,arg1,_exception); 4371 write_info=DestroyImageInfo(write_info); 4372 if (IfPlusOp) 4373 write_images=DestroyImageList(write_images); 4374 return; 4375 } 4376 /* 4377 Parenthesis and Brace operations 4378 */ 4379 if (LocaleCompare("(",option) == 0) { 4380 /* stack 'push' images */ 4381 Stack 4382 *node; 4383 4384 size_t 4385 size; 4386 4387 size=0; 4388 node=cli_wand->image_list_stack; 4389 for ( ; node != (Stack *)NULL; node=node->next) 4390 size++; 4391 if ( size >= MAX_STACK_DEPTH ) 4392 CLIWandExceptionReturn(OptionError,"ParenthesisNestedTooDeeply",option); 4393 node=(Stack *) AcquireMagickMemory(sizeof(*node)); 4394 if (node == (Stack *) NULL) 4395 CLIWandExceptionReturn(ResourceLimitFatalError, 4396 "MemoryAllocationFailed",option); 4397 node->data = (void *)cli_wand->wand.images; 4398 cli_wand->wand.images = NewImageList(); 4399 node->next = cli_wand->image_list_stack; 4400 cli_wand->image_list_stack = node; 4401 4402 /* handle respect-parenthesis */ 4403 if (IfMagickTrue(IsStringTrue(GetImageOption(cli_wand->wand.image_info, 4404 "respect-parenthesis")))) 4405 option="{"; /* fall-thru so as to push image settings too */ 4406 else 4407 return; 4408 } 4409 if (LocaleCompare("{",option) == 0) { 4410 /* stack 'push' of image_info settings */ 4411 Stack 4412 *node; 4413 4414 size_t 4415 size; 4416 4417 size=0; 4418 node=cli_wand->image_info_stack; 4419 for ( ; node != (Stack *)NULL; node=node->next) 4420 size++; 4421 if ( size >= MAX_STACK_DEPTH ) 4422 CLIWandExceptionReturn(OptionError,"CurlyBracesNestedTooDeeply",option); 4423 node=(Stack *) AcquireMagickMemory(sizeof(*node)); 4424 if (node == (Stack *) NULL) 4425 CLIWandExceptionReturn(ResourceLimitFatalError, 4426 "MemoryAllocationFailed",option); 4427 4428 node->data = (void *)cli_wand->wand.image_info; 4429 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info); 4430 if (cli_wand->wand.image_info == (ImageInfo *)NULL) { 4431 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed", 4432 option); 4433 cli_wand->wand.image_info = (ImageInfo *)node->data; 4434 node = (Stack *)RelinquishMagickMemory(node); 4435 return; 4436 } 4437 4438 node->next = cli_wand->image_info_stack; 4439 cli_wand->image_info_stack = node; 4440 4441 return; 4442 } 4443 if (LocaleCompare(")",option) == 0) { 4444 /* pop images from stack */ 4445 Stack 4446 *node; 4447 4448 node = (Stack *)cli_wand->image_list_stack; 4449 if ( node == (Stack *)NULL) 4450 CLIWandExceptionReturn(OptionError,"UnbalancedParenthesis",option); 4451 cli_wand->image_list_stack = node->next; 4452 4453 AppendImageToList((Image **)&node->data,cli_wand->wand.images); 4454 cli_wand->wand.images= (Image *)node->data; 4455 node = (Stack *)RelinquishMagickMemory(node); 4456 4457 /* handle respect-parenthesis - of the previous 'pushed' settings */ 4458 node = cli_wand->image_info_stack; 4459 if ( node != (Stack *)NULL) 4460 { 4461 if (IfMagickTrue(IsStringTrue(GetImageOption( 4462 cli_wand->wand.image_info,"respect-parenthesis")))) 4463 option="}"; /* fall-thru so as to pop image settings too */ 4464 else 4465 return; 4466 } 4467 else 4468 return; 4469 } 4470 if (LocaleCompare("}",option) == 0) { 4471 /* pop image_info settings from stack */ 4472 Stack 4473 *node; 4474 4475 node = (Stack *)cli_wand->image_info_stack; 4476 if ( node == (Stack *)NULL) 4477 CLIWandExceptionReturn(OptionError,"UnbalancedCurlyBraces",option); 4478 cli_wand->image_info_stack = node->next; 4479 4480 (void) DestroyImageInfo(cli_wand->wand.image_info); 4481 cli_wand->wand.image_info = (ImageInfo *)node->data; 4482 node = (Stack *)RelinquishMagickMemory(node); 4483 4484 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info); 4485 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info); 4486 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info); 4487 4488 return; 4489 } 4490 if (LocaleCompare("clone",option+1) == 0) { 4491 Image 4492 *new_images; 4493 4494 if (*option == '+') 4495 arg1="-1"; 4496 if (IfMagickFalse(IsSceneGeometry(arg1,MagickFalse))) 4497 CLIWandExceptionReturn(OptionError,"InvalidArgument",option); 4498 if ( cli_wand->image_list_stack == (Stack *)NULL) 4499 CLIWandExceptionReturn(OptionError,"UnableToCloneImage",option); 4500 new_images = (Image *)cli_wand->image_list_stack->data; 4501 if (new_images == (Image *) NULL) 4502 CLIWandExceptionReturn(OptionError,"UnableToCloneImage",option); 4503 new_images=CloneImages(new_images,arg1,_exception); 4504 if (new_images == (Image *) NULL) 4505 CLIWandExceptionReturn(OptionError,"NoSuchImage",option); 4506 AppendImageToList(&_images,new_images); 4507 return; 4508 } 4509 /* 4510 Informational Operations 4511 */ 4512 if (LocaleCompare("version",option+1) == 0) { 4513 (void) FormatLocaleFile(stdout,"Version: %s\n", 4514 GetMagickVersion((size_t *) NULL)); 4515 (void) FormatLocaleFile(stdout,"Copyright: %s\n", 4516 GetMagickCopyright()); 4517 (void) FormatLocaleFile(stdout,"Features: %s\n\n", 4518 GetMagickFeatures()); 4519 return; 4520 } 4521 if (LocaleCompare("list",option+1) == 0) { 4522 /* FUTURE: This should really be built into the MagickCore 4523 It does not actually require a cli-wand or and images! 4524 */ 4525 ssize_t 4526 list; 4527 4528 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1); 4529 if ( list < 0 ) { 4530 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1); 4531 return; 4532 } 4533 switch (list) 4534 { 4535 case MagickCoderOptions: 4536 { 4537 (void) ListCoderInfo((FILE *) NULL,_exception); 4538 break; 4539 } 4540 case MagickColorOptions: 4541 { 4542 (void) ListColorInfo((FILE *) NULL,_exception); 4543 break; 4544 } 4545 case MagickConfigureOptions: 4546 { 4547 (void) ListConfigureInfo((FILE *) NULL,_exception); 4548 break; 4549 } 4550 case MagickDelegateOptions: 4551 { 4552 (void) ListDelegateInfo((FILE *) NULL,_exception); 4553 break; 4554 } 4555 case MagickFontOptions: 4556 { 4557 (void) ListTypeInfo((FILE *) NULL,_exception); 4558 break; 4559 } 4560 case MagickFormatOptions: 4561 (void) ListMagickInfo((FILE *) NULL,_exception); 4562 break; 4563 case MagickLocaleOptions: 4564 (void) ListLocaleInfo((FILE *) NULL,_exception); 4565 break; 4566 case MagickLogOptions: 4567 (void) ListLogInfo((FILE *) NULL,_exception); 4568 break; 4569 case MagickMagicOptions: 4570 (void) ListMagicInfo((FILE *) NULL,_exception); 4571 break; 4572 case MagickMimeOptions: 4573 (void) ListMimeInfo((FILE *) NULL,_exception); 4574 break; 4575 case MagickModuleOptions: 4576 (void) ListModuleInfo((FILE *) NULL,_exception); 4577 break; 4578 case MagickPolicyOptions: 4579 (void) ListPolicyInfo((FILE *) NULL,_exception); 4580 break; 4581 case MagickResourceOptions: 4582 (void) ListMagickResourceInfo((FILE *) NULL,_exception); 4583 break; 4584 case MagickThresholdOptions: 4585 (void) ListThresholdMaps((FILE *) NULL,_exception); 4586 break; 4587 default: 4588 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list, 4589 _exception); 4590 break; 4591 } 4592 return; 4593 } 4594 4595#if 0 4596 // Other 'special' options this should handle 4597 // "region" "reset" "arg" 4598 if ( ( process_flags & ProcessUnknownOptionError ) != 0 ) 4599#endif 4600 CLIWandException(OptionError,"UnrecognizedOption",option); 4601 4602#undef _image_info 4603#undef _images 4604#undef _exception 4605#undef IfNormalOp 4606#undef IfPlusOp 4607} 4608 4609/* 4610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4611% % 4612% % 4613% % 4614+ C L I O p t i o n O p e r a t i o n s % 4615% % 4616% % 4617% % 4618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4619% 4620% CLIOption() Processes the given option using the given CLI Magick Wand. 4621% 4622% If the cli_wand->command pointer is non-null, then it is assumed that the 4623% option has already been search for up from the CommandOptions[] table in 4624% "MagickCore/options.c" using GetCommandOptionInfo(), so that any command 4625% specific options (such as "magick" scripting options, or "display" settings) 4626% can be handled separatally. 4627% 4628% The format of the CLIOption method is: 4629% 4630% void CLIOption(MagickCLI *cli_wand,const char *option, ...) 4631% 4632% A description of each parameter follows: 4633% 4634% o cli_wand: the main CLI Wand to use. 4635% 4636% o option: The special option (with any switch char) to process 4637% 4638% o args: any required arguments for an option 4639% 4640% Example Usage... 4641% 4642% CLIoption(cli_wand,"-read","rose:"); 4643% CLIoption(cli_wand,"-virtual-pixel","transparent"); 4644% CLIoption(cli_wand,"-distort","SRT:","30"); 4645% CLIoption(cli_wand,"-write","rotated_rose.png"); 4646% 4647*/ 4648WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...) 4649{ 4650 const char 4651 *arg1, 4652 *arg2; 4653 4654 CommandOptionFlags 4655 option_type; 4656 4657 assert(cli_wand != (MagickCLI *) NULL); 4658 assert(cli_wand->signature == WandSignature); 4659 assert(cli_wand->wand.signature == WandSignature); 4660 if (IfMagickTrue(cli_wand->wand.debug)) 4661 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name); 4662 4663 if ( cli_wand->command == (const OptionInfo *) NULL ) 4664 cli_wand->command = GetCommandOptionInfo(option); 4665#if 0 4666 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n", 4667 option, cli_wand->command->mnemonic ); 4668#endif 4669 4670 option_type=(CommandOptionFlags) cli_wand->command->flags; 4671 4672 if ( option_type == UndefinedOptionFlag ) 4673 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option); 4674 4675 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 ); 4676 4677 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 ) 4678 CLIWandExceptionReturn(OptionFatalError,"InvalidUseOfOption",option); 4679 4680 if ( (option_type & DeprecateOptionFlag) != 0 ) 4681 CLIWandExceptionReturn(OptionError,"DeprecatedOptionNoCode",option); 4682 4683 if ( IfMagickTrue(CLICatchException(cli_wand, MagickFalse)) ) 4684 return; 4685 4686 4687 { size_t 4688 count = cli_wand->command->type; 4689 4690 va_list 4691 operands; 4692 4693 va_start(operands,option); 4694 4695 arg1=arg2=NULL; 4696 if ( count >= 1 ) 4697 arg1=(const char *) va_arg(operands, const char *); 4698 if ( count >= 2 ) 4699 arg2=(const char *) va_arg(operands, const char *); 4700 4701 va_end(operands); 4702 4703#if 0 4704 (void) FormatLocaleFile(stderr, 4705 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n", 4706 option,(long) count,option_type,arg1,arg2); 4707#endif 4708 } 4709 4710 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */ 4711 4712 4713 /* 4714 Call the appropriate option handler 4715 */ 4716 4717 /* FUTURE: this is temporary - get 'settings' to handle 4718 distribution of settings to images attributes,proprieties,artifacts */ 4719 if ( cli_wand->wand.images != (Image *)NULL ) 4720 SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images, 4721 cli_wand->wand.exception); 4722 4723 if ( (option_type & SettingOptionFlags) != 0 ) { 4724 CLISettingOptionInfo(cli_wand, option, arg1, arg2); 4725 // FUTURE: Sync Specific Settings into Image Properities (not global) 4726 } 4727 4728 if ( (option_type & NoImageOperatorFlag) != 0) 4729 CLINoImageOperator(cli_wand, option, arg1, arg2); 4730 4731 /* FUTURE: The not a setting part below is a temporary hack due to 4732 * some options being both a Setting and a Simple operator. 4733 * Specifically -monitor, -depth, and -colorspace */ 4734 if ( cli_wand->wand.images == (Image *)NULL ) { 4735 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) && 4736 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */ 4737 CLIWandException(OptionError,"NoImagesFound",option); 4738 return; /* on its own this is not an error */ 4739 } 4740 4741 if ( (option_type & SimpleOperatorFlag) != 0) 4742 CLISimpleOperatorImages(cli_wand, option, arg1, arg2); 4743 4744 if ( (option_type & ListOperatorFlag) != 0 ) 4745 CLIListOperatorImages(cli_wand, option, arg1, arg2); 4746 4747} 4748