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