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