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