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