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