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