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