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