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