|
MagickWand
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % CCCC OOO M M PPPP AAA RRRR EEEEE % 00007 % C O O MM MM P P A A R R E % 00008 % C O O M M M PPPP AAAAA RRRR EEE % 00009 % C O O M M P A A R R E % 00010 % CCCC OOO M M P A A R R EEEEE % 00011 % % 00012 % % 00013 % Image Comparison Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % December 2003 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % Use the compare program to mathematically and visually annotate the 00037 % difference between an image and its reconstruction. 00038 % 00039 */ 00040 00041 /* 00042 Include declarations. 00043 */ 00044 #include "MagickWand/studio.h" 00045 #include "MagickWand/MagickWand.h" 00046 #include "MagickWand/mogrify-private.h" 00047 #include "MagickCore/string-private.h" 00048 00049 /* 00050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00051 % % 00052 % % 00053 % % 00054 % C o m p a r e I m a g e C o m m a n d % 00055 % % 00056 % % 00057 % % 00058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00059 % 00060 % CompareImagesCommand() compares two images and returns the difference between 00061 % them as a distortion metric and as a new image visually annotating their 00062 % differences. 00063 % 00064 % The format of the CompareImagesCommand method is: 00065 % 00066 % MagickBooleanType CompareImagesCommand(ImageInfo *image_info,int argc, 00067 % char **argv,char **metadata,ExceptionInfo *exception) 00068 % 00069 % A description of each parameter follows: 00070 % 00071 % o image_info: the image info. 00072 % 00073 % o argc: the number of elements in the argument vector. 00074 % 00075 % o argv: A text array containing the command line arguments. 00076 % 00077 % o metadata: any metadata is returned here. 00078 % 00079 % o exception: return any errors or warnings in this structure. 00080 % 00081 */ 00082 00083 static MagickBooleanType CompareUsage(void) 00084 { 00085 const char 00086 **p; 00087 00088 static const char 00089 *miscellaneous[]= 00090 { 00091 "-debug events display copious debugging information", 00092 "-help print program options", 00093 "-list type print a list of supported option arguments", 00094 "-log format format of debugging information", 00095 (char *) NULL 00096 }, 00097 *settings[]= 00098 { 00099 "-alpha option on, activate, off, deactivate, set, opaque, copy", 00100 " transparent, extract, background, or shape", 00101 "-authenticate password", 00102 " decipher image with this password", 00103 "-channel type apply option to select image channels", 00104 "-colorspace type alternate image colorspace", 00105 "-compose operator set image composite operator", 00106 "-compress type type of pixel compression when writing the image", 00107 "-decipher filename convert cipher pixels to plain pixels", 00108 "-define format:option", 00109 " define one or more image format options", 00110 "-density geometry horizontal and vertical density of the image", 00111 "-depth value image depth", 00112 "-dissimilarity-threshold value", 00113 " maximum distortion for (sub)image match", 00114 "-encipher filename convert plain pixels to cipher pixels", 00115 "-extract geometry extract area from image", 00116 "-format \"string\" output formatted image characteristics", 00117 "-fuzz distance colors within this distance are considered equal", 00118 "-highlight-color color", 00119 " empasize pixel differences with this color", 00120 "-identify identify the format and characteristics of the image", 00121 "-interlace type type of image interlacing scheme", 00122 "-limit type value pixel cache resource limit", 00123 "-lowlight-color color", 00124 " de-emphasize pixel differences with this color", 00125 "-metric type measure differences between images with this metric", 00126 "-monitor monitor progress", 00127 "-passphrase filename get the passphrase from this file", 00128 "-profile filename add, delete, or apply an image profile", 00129 "-quality value JPEG/MIFF/PNG compression level", 00130 "-quiet suppress all warning messages", 00131 "-quantize colorspace reduce colors in this colorspace", 00132 "-regard-warnings pay attention to warning messages", 00133 "-respect-parentheses settings remain in effect until parenthesis boundary", 00134 "-sampling-factor geometry", 00135 " horizontal and vertical sampling factor", 00136 "-seed value seed a new sequence of pseudo-random numbers", 00137 "-set attribute value set an image attribute", 00138 "-quality value JPEG/MIFF/PNG compression level", 00139 "-size geometry width and height of image", 00140 "-subimage-search search for subimage", 00141 "-transparent-color color", 00142 " transparent color", 00143 "-type type image type", 00144 "-verbose print detailed information about the image", 00145 "-version print version information", 00146 "-virtual-pixel method", 00147 " virtual pixel access method", 00148 (char *) NULL 00149 }; 00150 00151 (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL)); 00152 (void) printf("Copyright: %s\n",GetMagickCopyright()); 00153 (void) printf("Features: %s\n\n",GetMagickFeatures()); 00154 (void) printf("Usage: %s [options ...] image reconstruct difference\n", 00155 GetClientName()); 00156 (void) printf("\nImage Settings:\n"); 00157 for (p=settings; *p != (char *) NULL; p++) 00158 (void) printf(" %s\n",*p); 00159 (void) printf("\nMiscellaneous Options:\n"); 00160 for (p=miscellaneous; *p != (char *) NULL; p++) 00161 (void) printf(" %s\n",*p); 00162 (void) printf( 00163 "\nBy default, the image format of `file' is determined by its magic\n"); 00164 (void) printf( 00165 "number. To specify a particular image format, precede the filename\n"); 00166 (void) printf( 00167 "with an image format name and a colon (i.e. ps:image) or specify the\n"); 00168 (void) printf( 00169 "image type as the filename suffix (i.e. image.ps). Specify 'file' as\n"); 00170 (void) printf("'-' for standard input or output.\n"); 00171 return(MagickFalse); 00172 } 00173 00174 WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info, 00175 int argc,char **argv,char **metadata,ExceptionInfo *exception) 00176 { 00177 #define DefaultDissimilarityThreshold 0.31830988618379067154 00178 #define DestroyCompare() \ 00179 { \ 00180 if (similarity_image != (Image *) NULL) \ 00181 similarity_image=DestroyImageList(similarity_image); \ 00182 if (difference_image != (Image *) NULL) \ 00183 difference_image=DestroyImageList(difference_image); \ 00184 DestroyImageStack(); \ 00185 for (i=0; i < (ssize_t) argc; i++) \ 00186 argv[i]=DestroyString(argv[i]); \ 00187 argv=(char **) RelinquishMagickMemory(argv); \ 00188 } 00189 #define ThrowCompareException(asperity,tag,option) \ 00190 { \ 00191 if (exception->severity < (asperity)) \ 00192 (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \ 00193 "`%s'",option); \ 00194 DestroyCompare(); \ 00195 return(MagickFalse); \ 00196 } 00197 #define ThrowCompareInvalidArgumentException(option,argument) \ 00198 { \ 00199 (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \ 00200 "InvalidArgument","`%s': %s",option,argument); \ 00201 DestroyCompare(); \ 00202 return(MagickFalse); \ 00203 } 00204 00205 char 00206 *filename, 00207 *option; 00208 00209 const char 00210 *format; 00211 00212 double 00213 dissimilarity_threshold, 00214 distortion, 00215 similarity_metric; 00216 00217 Image 00218 *difference_image, 00219 *image, 00220 *reconstruct_image, 00221 *similarity_image; 00222 00223 ImageStack 00224 image_stack[MaxImageStackDepth+1]; 00225 00226 MagickBooleanType 00227 fire, 00228 pend, 00229 respect_parenthesis, 00230 subimage_search; 00231 00232 MagickStatusType 00233 status; 00234 00235 MetricType 00236 metric; 00237 00238 RectangleInfo 00239 offset; 00240 00241 register ssize_t 00242 i; 00243 00244 ssize_t 00245 j, 00246 k; 00247 00248 /* 00249 Set defaults. 00250 */ 00251 assert(image_info != (ImageInfo *) NULL); 00252 assert(image_info->signature == MagickSignature); 00253 if (image_info->debug != MagickFalse) 00254 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00255 assert(exception != (ExceptionInfo *) NULL); 00256 if (argc == 2) 00257 { 00258 option=argv[1]; 00259 if ((LocaleCompare("version",option+1) == 0) || 00260 (LocaleCompare("-version",option+1) == 0)) 00261 { 00262 (void) FormatLocaleFile(stdout,"Version: %s\n", 00263 GetMagickVersion((size_t *) NULL)); 00264 (void) FormatLocaleFile(stdout,"Copyright: %s\n", 00265 GetMagickCopyright()); 00266 (void) FormatLocaleFile(stdout,"Features: %s\n\n", 00267 GetMagickFeatures()); 00268 return(MagickFalse); 00269 } 00270 } 00271 if (argc < 3) 00272 return(CompareUsage()); 00273 difference_image=NewImageList(); 00274 similarity_image=NewImageList(); 00275 dissimilarity_threshold=DefaultDissimilarityThreshold; 00276 distortion=0.0; 00277 format=(char *) NULL; 00278 j=1; 00279 k=0; 00280 metric=UndefinedMetric; 00281 NewImageStack(); 00282 option=(char *) NULL; 00283 pend=MagickFalse; 00284 reconstruct_image=NewImageList(); 00285 respect_parenthesis=MagickFalse; 00286 status=MagickTrue; 00287 subimage_search=MagickFalse; 00288 /* 00289 Compare an image. 00290 */ 00291 ReadCommandlLine(argc,&argv); 00292 status=ExpandFilenames(&argc,&argv); 00293 if (status == MagickFalse) 00294 ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed", 00295 GetExceptionMessage(errno)); 00296 for (i=1; i < (ssize_t) (argc-1); i++) 00297 { 00298 option=argv[i]; 00299 if (LocaleCompare(option,"(") == 0) 00300 { 00301 FireImageStack(MagickTrue,MagickTrue,pend); 00302 if (k == MaxImageStackDepth) 00303 ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply", 00304 option); 00305 PushImageStack(); 00306 continue; 00307 } 00308 if (LocaleCompare(option,")") == 0) 00309 { 00310 FireImageStack(MagickTrue,MagickTrue,MagickTrue); 00311 if (k == 0) 00312 ThrowCompareException(OptionError,"UnableToParseExpression",option); 00313 PopImageStack(); 00314 continue; 00315 } 00316 if (IsCommandOption(option) == MagickFalse) 00317 { 00318 Image 00319 *images; 00320 00321 /* 00322 Read input image. 00323 */ 00324 FireImageStack(MagickFalse,MagickFalse,pend); 00325 filename=argv[i]; 00326 if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1))) 00327 filename=argv[++i]; 00328 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 00329 images=ReadImages(image_info,exception); 00330 status&=(images != (Image *) NULL) && 00331 (exception->severity < ErrorException); 00332 if (images == (Image *) NULL) 00333 continue; 00334 AppendImageStack(images); 00335 continue; 00336 } 00337 pend=image != (Image *) NULL ? MagickTrue : MagickFalse; 00338 switch (*(option+1)) 00339 { 00340 case 'a': 00341 { 00342 if (LocaleCompare("alpha",option+1) == 0) 00343 { 00344 ssize_t 00345 type; 00346 00347 if (*option == '+') 00348 break; 00349 i++; 00350 if (i == (ssize_t) argc) 00351 ThrowCompareException(OptionError,"MissingArgument",option); 00352 type=ParseCommandOption(MagickAlphaOptions,MagickFalse,argv[i]); 00353 if (type < 0) 00354 ThrowCompareException(OptionError,"UnrecognizedAlphaChannelType", 00355 argv[i]); 00356 break; 00357 } 00358 if (LocaleCompare("authenticate",option+1) == 0) 00359 { 00360 if (*option == '+') 00361 break; 00362 i++; 00363 if (i == (ssize_t) argc) 00364 ThrowCompareException(OptionError,"MissingArgument",option); 00365 break; 00366 } 00367 ThrowCompareException(OptionError,"UnrecognizedOption",option); 00368 } 00369 case 'c': 00370 { 00371 if (LocaleCompare("cache",option+1) == 0) 00372 { 00373 if (*option == '+') 00374 break; 00375 i++; 00376 if (i == (ssize_t) argc) 00377 ThrowCompareException(OptionError,"MissingArgument",option); 00378 if (IsGeometry(argv[i]) == MagickFalse) 00379 ThrowCompareInvalidArgumentException(option,argv[i]); 00380 break; 00381 } 00382 if (LocaleCompare("channel",option+1) == 0) 00383 { 00384 ssize_t 00385 channel; 00386 00387 if (*option == '+') 00388 break; 00389 i++; 00390 if (i == (ssize_t) (argc-1)) 00391 ThrowCompareException(OptionError,"MissingArgument",option); 00392 channel=ParseChannelOption(argv[i]); 00393 if (channel < 0) 00394 ThrowCompareException(OptionError,"UnrecognizedChannelType", 00395 argv[i]); 00396 SetPixelChannelMapMask(image,(ChannelType) channel); 00397 break; 00398 } 00399 if (LocaleCompare("colorspace",option+1) == 0) 00400 { 00401 ssize_t 00402 colorspace; 00403 00404 if (*option == '+') 00405 break; 00406 i++; 00407 if (i == (ssize_t) (argc-1)) 00408 ThrowCompareException(OptionError,"MissingArgument",option); 00409 colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse, 00410 argv[i]); 00411 if (colorspace < 0) 00412 ThrowCompareException(OptionError,"UnrecognizedColorspace", 00413 argv[i]); 00414 break; 00415 } 00416 if (LocaleCompare("compose",option+1) == 0) 00417 { 00418 ssize_t 00419 compose; 00420 00421 if (*option == '+') 00422 break; 00423 i++; 00424 if (i == (ssize_t) argc) 00425 ThrowCompareException(OptionError,"MissingArgument",option); 00426 compose=ParseCommandOption(MagickComposeOptions,MagickFalse, 00427 argv[i]); 00428 if (compose < 0) 00429 ThrowCompareException(OptionError,"UnrecognizedComposeOperator", 00430 argv[i]); 00431 break; 00432 } 00433 if (LocaleCompare("compress",option+1) == 0) 00434 { 00435 ssize_t 00436 compress; 00437 00438 if (*option == '+') 00439 break; 00440 i++; 00441 if (i == (ssize_t) (argc-1)) 00442 ThrowCompareException(OptionError,"MissingArgument",option); 00443 compress=ParseCommandOption(MagickCompressOptions,MagickFalse, 00444 argv[i]); 00445 if (compress < 0) 00446 ThrowCompareException(OptionError,"UnrecognizedImageCompression", 00447 argv[i]); 00448 break; 00449 } 00450 if (LocaleCompare("concurrent",option+1) == 0) 00451 break; 00452 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00453 } 00454 case 'd': 00455 { 00456 if (LocaleCompare("debug",option+1) == 0) 00457 { 00458 LogEventType 00459 event_mask; 00460 00461 if (*option == '+') 00462 break; 00463 i++; 00464 if (i == (ssize_t) argc) 00465 ThrowCompareException(OptionError,"MissingArgument",option); 00466 event_mask=SetLogEventMask(argv[i]); 00467 if (event_mask == UndefinedEvents) 00468 ThrowCompareException(OptionError,"UnrecognizedEventType", 00469 argv[i]); 00470 break; 00471 } 00472 if (LocaleCompare("decipher",option+1) == 0) 00473 { 00474 if (*option == '+') 00475 break; 00476 i++; 00477 if (i == (ssize_t) (argc-1)) 00478 ThrowCompareException(OptionError,"MissingArgument",option); 00479 break; 00480 } 00481 if (LocaleCompare("define",option+1) == 0) 00482 { 00483 i++; 00484 if (i == (ssize_t) argc) 00485 ThrowCompareException(OptionError,"MissingArgument",option); 00486 if (*option == '+') 00487 { 00488 const char 00489 *define; 00490 00491 define=GetImageOption(image_info,argv[i]); 00492 if (define == (const char *) NULL) 00493 ThrowCompareException(OptionError,"NoSuchOption",argv[i]); 00494 break; 00495 } 00496 break; 00497 } 00498 if (LocaleCompare("density",option+1) == 0) 00499 { 00500 if (*option == '+') 00501 break; 00502 i++; 00503 if (i == (ssize_t) argc) 00504 ThrowCompareException(OptionError,"MissingArgument",option); 00505 if (IsGeometry(argv[i]) == MagickFalse) 00506 ThrowCompareInvalidArgumentException(option,argv[i]); 00507 break; 00508 } 00509 if (LocaleCompare("depth",option+1) == 0) 00510 { 00511 if (*option == '+') 00512 break; 00513 i++; 00514 if (i == (ssize_t) argc) 00515 ThrowCompareException(OptionError,"MissingArgument",option); 00516 if (IsGeometry(argv[i]) == MagickFalse) 00517 ThrowCompareInvalidArgumentException(option,argv[i]); 00518 break; 00519 } 00520 if (LocaleCompare("dissimilarity-threshold",option+1) == 0) 00521 { 00522 if (*option == '+') 00523 break; 00524 i++; 00525 if (i == (ssize_t) argc) 00526 ThrowCompareException(OptionError,"MissingArgument",option); 00527 if (IsGeometry(argv[i]) == MagickFalse) 00528 ThrowCompareInvalidArgumentException(option,argv[i]); 00529 if (*option == '+') 00530 dissimilarity_threshold=DefaultDissimilarityThreshold; 00531 else 00532 dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL); 00533 break; 00534 } 00535 if (LocaleCompare("duration",option+1) == 0) 00536 { 00537 if (*option == '+') 00538 break; 00539 i++; 00540 if (i == (ssize_t) (argc-1)) 00541 ThrowCompareException(OptionError,"MissingArgument",option); 00542 if (IsGeometry(argv[i]) == MagickFalse) 00543 ThrowCompareInvalidArgumentException(option,argv[i]); 00544 break; 00545 } 00546 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00547 } 00548 case 'e': 00549 { 00550 if (LocaleCompare("encipher",option+1) == 0) 00551 { 00552 if (*option == '+') 00553 break; 00554 i++; 00555 if (i == (ssize_t) (argc-1)) 00556 ThrowCompareException(OptionError,"MissingArgument",option); 00557 break; 00558 } 00559 if (LocaleCompare("extract",option+1) == 0) 00560 { 00561 if (*option == '+') 00562 break; 00563 i++; 00564 if (i == (ssize_t) (argc-1)) 00565 ThrowCompareException(OptionError,"MissingArgument",option); 00566 if (IsGeometry(argv[i]) == MagickFalse) 00567 ThrowCompareInvalidArgumentException(option,argv[i]); 00568 break; 00569 } 00570 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00571 } 00572 case 'f': 00573 { 00574 if (LocaleCompare("format",option+1) == 0) 00575 { 00576 if (*option == '+') 00577 break; 00578 i++; 00579 if (i == (ssize_t) argc) 00580 ThrowCompareException(OptionError,"MissingArgument",option); 00581 format=argv[i]; 00582 break; 00583 } 00584 if (LocaleCompare("fuzz",option+1) == 0) 00585 { 00586 if (*option == '+') 00587 break; 00588 i++; 00589 if (i == (ssize_t) (argc-1)) 00590 ThrowCompareException(OptionError,"MissingArgument",option); 00591 if (IsGeometry(argv[i]) == MagickFalse) 00592 ThrowCompareInvalidArgumentException(option,argv[i]); 00593 break; 00594 } 00595 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00596 } 00597 case 'h': 00598 { 00599 if ((LocaleCompare("help",option+1) == 0) || 00600 (LocaleCompare("-help",option+1) == 0)) 00601 return(CompareUsage()); 00602 if (LocaleCompare("highlight-color",option+1) == 0) 00603 { 00604 if (*option == '+') 00605 break; 00606 i++; 00607 if (i == (ssize_t) (argc-1)) 00608 ThrowCompareException(OptionError,"MissingArgument",option); 00609 break; 00610 } 00611 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00612 } 00613 case 'i': 00614 { 00615 if (LocaleCompare("identify",option+1) == 0) 00616 break; 00617 if (LocaleCompare("interlace",option+1) == 0) 00618 { 00619 ssize_t 00620 interlace; 00621 00622 if (*option == '+') 00623 break; 00624 i++; 00625 if (i == (ssize_t) argc) 00626 ThrowCompareException(OptionError,"MissingArgument",option); 00627 interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse, 00628 argv[i]); 00629 if (interlace < 0) 00630 ThrowCompareException(OptionError,"UnrecognizedInterlaceType", 00631 argv[i]); 00632 break; 00633 } 00634 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00635 } 00636 case 'l': 00637 { 00638 if (LocaleCompare("limit",option+1) == 0) 00639 { 00640 char 00641 *p; 00642 00643 double 00644 value; 00645 00646 ssize_t 00647 resource; 00648 00649 if (*option == '+') 00650 break; 00651 i++; 00652 if (i == (ssize_t) argc) 00653 ThrowCompareException(OptionError,"MissingArgument",option); 00654 resource=ParseCommandOption(MagickResourceOptions,MagickFalse, 00655 argv[i]); 00656 if (resource < 0) 00657 ThrowCompareException(OptionError,"UnrecognizedResourceType", 00658 argv[i]); 00659 i++; 00660 if (i == (ssize_t) argc) 00661 ThrowCompareException(OptionError,"MissingArgument",option); 00662 value=StringToDouble(argv[i],&p); 00663 (void) value; 00664 if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0)) 00665 ThrowCompareInvalidArgumentException(option,argv[i]); 00666 break; 00667 } 00668 if (LocaleCompare("list",option+1) == 0) 00669 { 00670 ssize_t 00671 list; 00672 00673 if (*option == '+') 00674 break; 00675 i++; 00676 if (i == (ssize_t) argc) 00677 ThrowCompareException(OptionError,"MissingArgument",option); 00678 list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]); 00679 if (list < 0) 00680 ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]); 00681 status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **) 00682 argv+j,exception); 00683 DestroyCompare(); 00684 return(status != 0 ? MagickFalse : MagickTrue); 00685 } 00686 if (LocaleCompare("log",option+1) == 0) 00687 { 00688 if (*option == '+') 00689 break; 00690 i++; 00691 if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL)) 00692 ThrowCompareException(OptionError,"MissingArgument",option); 00693 break; 00694 } 00695 if (LocaleCompare("lowlight-color",option+1) == 0) 00696 { 00697 if (*option == '+') 00698 break; 00699 i++; 00700 if (i == (ssize_t) (argc-1)) 00701 ThrowCompareException(OptionError,"MissingArgument",option); 00702 break; 00703 } 00704 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00705 } 00706 case 'm': 00707 { 00708 if (LocaleCompare("matte",option+1) == 0) 00709 break; 00710 if (LocaleCompare("metric",option+1) == 0) 00711 { 00712 ssize_t 00713 type; 00714 00715 if (*option == '+') 00716 break; 00717 i++; 00718 if (i == (ssize_t) argc) 00719 ThrowCompareException(OptionError,"MissingArgument",option); 00720 type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]); 00721 if (type < 0) 00722 ThrowCompareException(OptionError,"UnrecognizedMetricType", 00723 argv[i]); 00724 metric=(MetricType) type; 00725 break; 00726 } 00727 if (LocaleCompare("monitor",option+1) == 0) 00728 break; 00729 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00730 } 00731 case 'p': 00732 { 00733 if (LocaleCompare("passphrase",option+1) == 0) 00734 { 00735 if (*option == '+') 00736 break; 00737 i++; 00738 if (i == (ssize_t) argc) 00739 ThrowCompareException(OptionError,"MissingArgument",option); 00740 break; 00741 } 00742 if (LocaleCompare("profile",option+1) == 0) 00743 { 00744 i++; 00745 if (i == (ssize_t) (argc-1)) 00746 ThrowCompareException(OptionError,"MissingArgument",option); 00747 break; 00748 } 00749 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00750 } 00751 case 'q': 00752 { 00753 if (LocaleCompare("quality",option+1) == 0) 00754 { 00755 if (*option == '+') 00756 break; 00757 i++; 00758 if (i == (ssize_t) (argc-1)) 00759 ThrowCompareException(OptionError,"MissingArgument",option); 00760 if (IsGeometry(argv[i]) == MagickFalse) 00761 ThrowCompareInvalidArgumentException(option,argv[i]); 00762 break; 00763 } 00764 if (LocaleCompare("quantize",option+1) == 0) 00765 { 00766 ssize_t 00767 colorspace; 00768 00769 if (*option == '+') 00770 break; 00771 i++; 00772 if (i == (ssize_t) (argc-1)) 00773 ThrowCompareException(OptionError,"MissingArgument",option); 00774 colorspace=ParseCommandOption(MagickColorspaceOptions, 00775 MagickFalse,argv[i]); 00776 if (colorspace < 0) 00777 ThrowCompareException(OptionError,"UnrecognizedColorspace", 00778 argv[i]); 00779 break; 00780 } 00781 if (LocaleCompare("quiet",option+1) == 0) 00782 break; 00783 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00784 } 00785 case 'r': 00786 { 00787 if (LocaleCompare("regard-warnings",option+1) == 0) 00788 break; 00789 if (LocaleNCompare("respect-parentheses",option+1,17) == 0) 00790 { 00791 respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse; 00792 break; 00793 } 00794 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00795 } 00796 case 's': 00797 { 00798 if (LocaleCompare("sampling-factor",option+1) == 0) 00799 { 00800 if (*option == '+') 00801 break; 00802 i++; 00803 if (i == (ssize_t) argc) 00804 ThrowCompareException(OptionError,"MissingArgument",option); 00805 if (IsGeometry(argv[i]) == MagickFalse) 00806 ThrowCompareInvalidArgumentException(option,argv[i]); 00807 break; 00808 } 00809 if (LocaleCompare("seed",option+1) == 0) 00810 { 00811 if (*option == '+') 00812 break; 00813 i++; 00814 if (i == (ssize_t) (argc-1)) 00815 ThrowCompareException(OptionError,"MissingArgument",option); 00816 if (IsGeometry(argv[i]) == MagickFalse) 00817 ThrowCompareInvalidArgumentException(option,argv[i]); 00818 break; 00819 } 00820 if (LocaleCompare("set",option+1) == 0) 00821 { 00822 i++; 00823 if (i == (ssize_t) argc) 00824 ThrowCompareException(OptionError,"MissingArgument",option); 00825 if (*option == '+') 00826 break; 00827 i++; 00828 if (i == (ssize_t) argc) 00829 ThrowCompareException(OptionError,"MissingArgument",option); 00830 break; 00831 } 00832 if (LocaleCompare("size",option+1) == 0) 00833 { 00834 if (*option == '+') 00835 break; 00836 i++; 00837 if (i == (ssize_t) argc) 00838 ThrowCompareException(OptionError,"MissingArgument",option); 00839 if (IsGeometry(argv[i]) == MagickFalse) 00840 ThrowCompareInvalidArgumentException(option,argv[i]); 00841 break; 00842 } 00843 if (LocaleCompare("subimage-search",option+1) == 0) 00844 { 00845 if (*option == '+') 00846 { 00847 subimage_search=MagickFalse; 00848 break; 00849 } 00850 subimage_search=MagickTrue; 00851 break; 00852 } 00853 if (LocaleCompare("synchronize",option+1) == 0) 00854 break; 00855 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00856 } 00857 case 't': 00858 { 00859 if (LocaleCompare("taint",option+1) == 0) 00860 break; 00861 if (LocaleCompare("transparent-color",option+1) == 0) 00862 { 00863 if (*option == '+') 00864 break; 00865 i++; 00866 if (i == (ssize_t) (argc-1)) 00867 ThrowCompareException(OptionError,"MissingArgument",option); 00868 break; 00869 } 00870 if (LocaleCompare("type",option+1) == 0) 00871 { 00872 ssize_t 00873 type; 00874 00875 if (*option == '+') 00876 break; 00877 i++; 00878 if (i == (ssize_t) argc) 00879 ThrowCompareException(OptionError,"MissingArgument",option); 00880 type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]); 00881 if (type < 0) 00882 ThrowCompareException(OptionError,"UnrecognizedImageType", 00883 argv[i]); 00884 break; 00885 } 00886 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00887 } 00888 case 'v': 00889 { 00890 if (LocaleCompare("verbose",option+1) == 0) 00891 break; 00892 if ((LocaleCompare("version",option+1) == 0) || 00893 (LocaleCompare("-version",option+1) == 0)) 00894 { 00895 (void) FormatLocaleFile(stdout,"Version: %s\n", 00896 GetMagickVersion((size_t *) NULL)); 00897 (void) FormatLocaleFile(stdout,"Copyright: %s\n", 00898 GetMagickCopyright()); 00899 (void) FormatLocaleFile(stdout,"Features: %s\n\n", 00900 GetMagickFeatures()); 00901 break; 00902 } 00903 if (LocaleCompare("virtual-pixel",option+1) == 0) 00904 { 00905 ssize_t 00906 method; 00907 00908 if (*option == '+') 00909 break; 00910 i++; 00911 if (i == (ssize_t) (argc-1)) 00912 ThrowCompareException(OptionError,"MissingArgument",option); 00913 method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse, 00914 argv[i]); 00915 if (method < 0) 00916 ThrowCompareException(OptionError, 00917 "UnrecognizedVirtualPixelMethod",argv[i]); 00918 break; 00919 } 00920 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00921 } 00922 case '?': 00923 break; 00924 default: 00925 ThrowCompareException(OptionError,"UnrecognizedOption",option) 00926 } 00927 fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) & 00928 FireOptionFlag) == 0 ? MagickFalse : MagickTrue; 00929 if (fire != MagickFalse) 00930 FireImageStack(MagickTrue,MagickTrue,MagickTrue); 00931 } 00932 if (k != 0) 00933 ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]); 00934 if (i-- != (ssize_t) (argc-1)) 00935 ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]); 00936 if ((image == (Image *) NULL) || (GetImageListLength(image) < 2)) 00937 ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]); 00938 FinalizeImageSettings(image_info,image,MagickTrue); 00939 if ((image == (Image *) NULL) || (GetImageListLength(image) < 2)) 00940 ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]); 00941 image=GetImageFromList(image,0); 00942 reconstruct_image=GetImageFromList(image,1); 00943 if (subimage_search != MagickFalse) 00944 { 00945 similarity_image=SimilarityImage(image,reconstruct_image,metric,&offset, 00946 &similarity_metric,exception); 00947 if (similarity_metric > dissimilarity_threshold) 00948 ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename); 00949 } 00950 if ((reconstruct_image->columns == image->columns) && 00951 (reconstruct_image->rows == image->rows)) 00952 difference_image=CompareImages(image,reconstruct_image,metric,&distortion, 00953 exception); 00954 else 00955 if (similarity_image == (Image *) NULL) 00956 ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer", 00957 image->filename) 00958 else 00959 { 00960 Image 00961 *composite_image; 00962 00963 /* 00964 Determine if reconstructed image is a subimage of the image. 00965 */ 00966 composite_image=CloneImage(image,0,0,MagickTrue,exception); 00967 if (composite_image == (Image *) NULL) 00968 difference_image=CompareImages(image,reconstruct_image,metric, 00969 &distortion,exception); 00970 else 00971 { 00972 (void) CompositeImage(composite_image,CopyCompositeOp, 00973 reconstruct_image,offset.x,offset.y,exception); 00974 difference_image=CompareImages(image,composite_image,metric, 00975 &distortion,exception); 00976 if (difference_image != (Image *) NULL) 00977 { 00978 difference_image->page.x=offset.x; 00979 difference_image->page.y=offset.y; 00980 } 00981 composite_image=DestroyImage(composite_image); 00982 } 00983 if (difference_image != (Image *) NULL) 00984 { 00985 AppendImageToList(&difference_image,similarity_image); 00986 similarity_image=(Image *) NULL; 00987 } 00988 } 00989 if (difference_image == (Image *) NULL) 00990 status=0; 00991 else 00992 { 00993 if (image_info->verbose != MagickFalse) 00994 (void) IsImagesEqual(image,reconstruct_image,exception); 00995 if (*difference_image->magick == '\0') 00996 (void) CopyMagickString(difference_image->magick,image->magick, 00997 MaxTextExtent); 00998 if (image_info->verbose == MagickFalse) 00999 { 01000 switch (metric) 01001 { 01002 case FuzzErrorMetric: 01003 case MeanAbsoluteErrorMetric: 01004 case MeanSquaredErrorMetric: 01005 case RootMeanSquaredErrorMetric: 01006 case PeakAbsoluteErrorMetric: 01007 { 01008 (void) FormatLocaleFile(stderr,"%g (%g)",QuantumRange*distortion, 01009 (double) distortion); 01010 if ((reconstruct_image->columns != image->columns) || 01011 (reconstruct_image->rows != image->rows)) 01012 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double) 01013 difference_image->page.x,(double) difference_image->page.y); 01014 (void) FormatLocaleFile(stderr,"\n"); 01015 break; 01016 } 01017 case AbsoluteErrorMetric: 01018 case NormalizedCrossCorrelationErrorMetric: 01019 case PeakSignalToNoiseRatioMetric: 01020 { 01021 (void) FormatLocaleFile(stderr,"%g",distortion); 01022 if ((reconstruct_image->columns != image->columns) || 01023 (reconstruct_image->rows != image->rows)) 01024 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double) 01025 difference_image->page.x,(double) difference_image->page.y); 01026 (void) FormatLocaleFile(stderr,"\n"); 01027 break; 01028 } 01029 case MeanErrorPerPixelMetric: 01030 { 01031 (void) FormatLocaleFile(stderr,"%g (%g, %g)",distortion, 01032 image->error.normalized_mean_error, 01033 image->error.normalized_maximum_error); 01034 if ((reconstruct_image->columns != image->columns) || 01035 (reconstruct_image->rows != image->rows)) 01036 (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double) 01037 difference_image->page.x,(double) difference_image->page.y); 01038 (void) FormatLocaleFile(stderr,"\n"); 01039 break; 01040 } 01041 case UndefinedMetric: 01042 break; 01043 } 01044 } 01045 else 01046 { 01047 double 01048 *channel_distortion; 01049 01050 channel_distortion=GetImageDistortions(image,reconstruct_image, 01051 metric,exception); 01052 (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename); 01053 if ((reconstruct_image->columns != image->columns) || 01054 (reconstruct_image->rows != image->rows)) 01055 (void) FormatLocaleFile(stderr,"Offset: %.20g,%.20g\n",(double) 01056 difference_image->page.x,(double) difference_image->page.y); 01057 (void) FormatLocaleFile(stderr," Channel distortion: %s\n", 01058 CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric)); 01059 switch (metric) 01060 { 01061 case FuzzErrorMetric: 01062 case MeanAbsoluteErrorMetric: 01063 case MeanSquaredErrorMetric: 01064 case RootMeanSquaredErrorMetric: 01065 case PeakAbsoluteErrorMetric: 01066 { 01067 switch (image->colorspace) 01068 { 01069 case RGBColorspace: 01070 default: 01071 { 01072 (void) FormatLocaleFile(stderr," red: %g (%g)\n", 01073 QuantumRange*channel_distortion[RedPixelChannel], 01074 channel_distortion[RedPixelChannel]); 01075 (void) FormatLocaleFile(stderr," green: %g (%g)\n", 01076 QuantumRange*channel_distortion[GreenPixelChannel], 01077 channel_distortion[GreenPixelChannel]); 01078 (void) FormatLocaleFile(stderr," blue: %g (%g)\n", 01079 QuantumRange*channel_distortion[BluePixelChannel], 01080 channel_distortion[BluePixelChannel]); 01081 if (image->matte != MagickFalse) 01082 (void) FormatLocaleFile(stderr," alpha: %g (%g)\n", 01083 QuantumRange*channel_distortion[AlphaPixelChannel], 01084 channel_distortion[AlphaPixelChannel]); 01085 break; 01086 } 01087 case CMYKColorspace: 01088 { 01089 (void) FormatLocaleFile(stderr," cyan: %g (%g)\n", 01090 QuantumRange*channel_distortion[CyanPixelChannel], 01091 channel_distortion[CyanPixelChannel]); 01092 (void) FormatLocaleFile(stderr," magenta: %g (%g)\n", 01093 QuantumRange*channel_distortion[MagentaPixelChannel], 01094 channel_distortion[MagentaPixelChannel]); 01095 (void) FormatLocaleFile(stderr," yellow: %g (%g)\n", 01096 QuantumRange*channel_distortion[YellowPixelChannel], 01097 channel_distortion[YellowPixelChannel]); 01098 (void) FormatLocaleFile(stderr," black: %g (%g)\n", 01099 QuantumRange*channel_distortion[BlackPixelChannel], 01100 channel_distortion[BlackPixelChannel]); 01101 if (image->matte != MagickFalse) 01102 (void) FormatLocaleFile(stderr," alpha: %g (%g)\n", 01103 QuantumRange*channel_distortion[AlphaPixelChannel], 01104 channel_distortion[AlphaPixelChannel]); 01105 break; 01106 } 01107 case GRAYColorspace: 01108 { 01109 (void) FormatLocaleFile(stderr," gray: %g (%g)\n", 01110 QuantumRange*channel_distortion[GrayPixelChannel], 01111 channel_distortion[GrayPixelChannel]); 01112 if (image->matte != MagickFalse) 01113 (void) FormatLocaleFile(stderr," alpha: %g (%g)\n", 01114 QuantumRange*channel_distortion[AlphaPixelChannel], 01115 channel_distortion[AlphaPixelChannel]); 01116 break; 01117 } 01118 } 01119 (void) FormatLocaleFile(stderr," all: %g (%g)\n", 01120 QuantumRange*channel_distortion[MaxPixelChannels], 01121 channel_distortion[MaxPixelChannels]); 01122 break; 01123 } 01124 case AbsoluteErrorMetric: 01125 case NormalizedCrossCorrelationErrorMetric: 01126 case PeakSignalToNoiseRatioMetric: 01127 { 01128 switch (image->colorspace) 01129 { 01130 case RGBColorspace: 01131 default: 01132 { 01133 (void) FormatLocaleFile(stderr," red: %g\n", 01134 channel_distortion[RedPixelChannel]); 01135 (void) FormatLocaleFile(stderr," green: %g\n", 01136 channel_distortion[GreenPixelChannel]); 01137 (void) FormatLocaleFile(stderr," blue: %g\n", 01138 channel_distortion[BluePixelChannel]); 01139 if (image->matte != MagickFalse) 01140 (void) FormatLocaleFile(stderr," alpha: %g\n", 01141 channel_distortion[AlphaPixelChannel]); 01142 break; 01143 } 01144 case CMYKColorspace: 01145 { 01146 (void) FormatLocaleFile(stderr," cyan: %g\n", 01147 channel_distortion[CyanPixelChannel]); 01148 (void) FormatLocaleFile(stderr," magenta: %g\n", 01149 channel_distortion[MagentaPixelChannel]); 01150 (void) FormatLocaleFile(stderr," yellow: %g\n", 01151 channel_distortion[YellowPixelChannel]); 01152 (void) FormatLocaleFile(stderr," black: %g\n", 01153 channel_distortion[BlackPixelChannel]); 01154 if (image->matte != MagickFalse) 01155 (void) FormatLocaleFile(stderr," alpha: %g\n", 01156 channel_distortion[AlphaPixelChannel]); 01157 break; 01158 } 01159 case GRAYColorspace: 01160 { 01161 (void) FormatLocaleFile(stderr," gray: %g\n", 01162 channel_distortion[GrayPixelChannel]); 01163 if (image->matte != MagickFalse) 01164 (void) FormatLocaleFile(stderr," alpha: %g\n", 01165 channel_distortion[AlphaPixelChannel]); 01166 break; 01167 } 01168 } 01169 (void) FormatLocaleFile(stderr," all: %g\n", 01170 channel_distortion[MaxPixelChannels]); 01171 break; 01172 } 01173 case MeanErrorPerPixelMetric: 01174 { 01175 (void) FormatLocaleFile(stderr," %g (%g, %g)\n", 01176 channel_distortion[MaxPixelChannels], 01177 image->error.normalized_mean_error, 01178 image->error.normalized_maximum_error); 01179 break; 01180 } 01181 case UndefinedMetric: 01182 break; 01183 } 01184 channel_distortion=(double *) RelinquishMagickMemory( 01185 channel_distortion); 01186 } 01187 status&=WriteImages(image_info,difference_image,argv[argc-1],exception); 01188 if ((metadata != (char **) NULL) && (format != (char *) NULL)) 01189 { 01190 char 01191 *text; 01192 01193 text=InterpretImageProperties(image_info,difference_image,format, 01194 exception); 01195 if (text == (char *) NULL) 01196 ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed", 01197 GetExceptionMessage(errno)); 01198 (void) ConcatenateString(&(*metadata),text); 01199 (void) ConcatenateString(&(*metadata),"\n"); 01200 text=DestroyString(text); 01201 } 01202 difference_image=DestroyImageList(difference_image); 01203 } 01204 DestroyCompare(); 01205 return(status != 0 ? MagickTrue : MagickFalse); 01206 }