PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/scripts/ImageMagick-6.6.2-6/wand/compare.c

https://bitbucket.org/JasonGross/alphabets
C | 1177 lines | 1053 code | 37 blank | 87 comment | 397 complexity | d087801ddb61a68430cdc22a9c46285d MD5 | raw file
Possible License(s): BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, MPL-2.0-no-copyleft-exception
  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % %
  4. % %
  5. % %
  6. % CCCC OOO M M PPPP AAA RRRR EEEEE %
  7. % C O O MM MM P P A A R R E %
  8. % C O O M M M PPPP AAAAA RRRR EEE %
  9. % C O O M M P A A R R E %
  10. % CCCC OOO M M P A A R R EEEEE %
  11. % %
  12. % %
  13. % Image Comparison Methods %
  14. % %
  15. % Software Design %
  16. % John Cristy %
  17. % December 2003 %
  18. % %
  19. % %
  20. % Copyright 1999-2010 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. % Use the compare program to mathematically and visually annotate the
  37. % difference between an image and its reconstruction.
  38. %
  39. */
  40. /*
  41. Include declarations.
  42. */
  43. #include "wand/studio.h"
  44. #include "wand/MagickWand.h"
  45. #include "wand/mogrify-private.h"
  46. #include "magick/string-private.h"
  47. /*
  48. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  49. % %
  50. % %
  51. % %
  52. % C o m p a r e I m a g e C o m m a n d %
  53. % %
  54. % %
  55. % %
  56. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  57. %
  58. % CompareImageCommand() compares two images and returns the difference between
  59. % them as a distortion metric and as a new image visually annotating their
  60. % differences.
  61. %
  62. % The format of the CompareImageCommand method is:
  63. %
  64. % MagickBooleanType CompareImageCommand(ImageInfo *image_info,int argc,
  65. % char **argv,char **metadata,ExceptionInfo *exception)
  66. %
  67. % A description of each parameter follows:
  68. %
  69. % o image_info: the image info.
  70. %
  71. % o argc: the number of elements in the argument vector.
  72. %
  73. % o argv: A text array containing the command line arguments.
  74. %
  75. % o metadata: any metadata is returned here.
  76. %
  77. % o exception: return any errors or warnings in this structure.
  78. %
  79. */
  80. static MagickBooleanType CompareUsage(void)
  81. {
  82. const char
  83. **p;
  84. static const char
  85. *miscellaneous[]=
  86. {
  87. "-debug events display copious debugging information",
  88. "-help print program options",
  89. "-list type print a list of supported option arguments",
  90. "-log format format of debugging information",
  91. (char *) NULL
  92. },
  93. *settings[]=
  94. {
  95. "-alpha option on, activate, off, deactivate, set, opaque, copy",
  96. " transparent, extract, background, or shape",
  97. "-authenticate password",
  98. " decipher image with this password",
  99. "-channel type apply option to select image channels",
  100. "-colorspace type alternate image colorspace",
  101. "-compose operator set image composite operator",
  102. "-compress type type of pixel compression when writing the image",
  103. "-decipher filename convert cipher pixels to plain pixels",
  104. "-define format:option",
  105. " define one or more image format options",
  106. "-density geometry horizontal and vertical density of the image",
  107. "-depth value image depth",
  108. "-dissimilarity-threshold value",
  109. " maximum RMSE for (sub)image match",
  110. "-encipher filename convert plain pixels to cipher pixels",
  111. "-extract geometry extract area from image",
  112. "-format \"string\" output formatted image characteristics",
  113. "-fuzz distance colors within this distance are considered equal",
  114. "-highlight-color color",
  115. " empasize pixel differences with this color",
  116. "-identify identify the format and characteristics of the image",
  117. "-interlace type type of image interlacing scheme",
  118. "-limit type value pixel cache resource limit",
  119. "-lowlight-color color",
  120. " de-emphasize pixel differences with this color",
  121. "-metric type measure differences between images with this metric",
  122. "-monitor monitor progress",
  123. "-passphrase filename get the passphrase from this file",
  124. "-profile filename add, delete, or apply an image profile",
  125. "-quality value JPEG/MIFF/PNG compression level",
  126. "-quiet suppress all warning messages",
  127. "-quantize colorspace reduce colors in this colorspace",
  128. "-regard-warnings pay attention to warning messages",
  129. "-respect-parentheses settings remain in effect until parenthesis boundary",
  130. "-sampling-factor geometry",
  131. " horizontal and vertical sampling factor",
  132. "-seed value seed a new sequence of pseudo-random numbers",
  133. "-set attribute value set an image attribute",
  134. "-quality value JPEG/MIFF/PNG compression level",
  135. "-size geometry width and height of image",
  136. "-transparent-color color",
  137. " transparent color",
  138. "-type type image type",
  139. "-verbose print detailed information about the image",
  140. "-version print version information",
  141. "-virtual-pixel method",
  142. " virtual pixel access method",
  143. (char *) NULL
  144. };
  145. (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
  146. (void) printf("Copyright: %s\n",GetMagickCopyright());
  147. (void) printf("Features: %s\n\n",GetMagickFeatures());
  148. (void) printf("Usage: %s [options ...] image reconstruct difference\n",
  149. GetClientName());
  150. (void) printf("\nImage Settings:\n");
  151. for (p=settings; *p != (char *) NULL; p++)
  152. (void) printf(" %s\n",*p);
  153. (void) printf("\nMiscellaneous Options:\n");
  154. for (p=miscellaneous; *p != (char *) NULL; p++)
  155. (void) printf(" %s\n",*p);
  156. (void) printf(
  157. "\nBy default, the image format of `file' is determined by its magic\n");
  158. (void) printf(
  159. "number. To specify a particular image format, precede the filename\n");
  160. (void) printf(
  161. "with an image format name and a colon (i.e. ps:image) or specify the\n");
  162. (void) printf(
  163. "image type as the filename suffix (i.e. image.ps). Specify 'file' as\n");
  164. (void) printf("'-' for standard input or output.\n");
  165. return(MagickFalse);
  166. }
  167. WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
  168. int argc,char **argv,char **metadata,ExceptionInfo *exception)
  169. {
  170. #define DefaultDissimilarityThreshold 0.31830988618379067154
  171. #define DestroyCompare() \
  172. { \
  173. if (similarity_image != (Image *) NULL) \
  174. similarity_image=DestroyImageList(similarity_image); \
  175. if (difference_image != (Image *) NULL) \
  176. difference_image=DestroyImageList(difference_image); \
  177. DestroyImageStack(); \
  178. for (i=0; i < (ssize_t) argc; i++) \
  179. argv[i]=DestroyString(argv[i]); \
  180. argv=(char **) RelinquishMagickMemory(argv); \
  181. }
  182. #define ThrowCompareException(asperity,tag,option) \
  183. { \
  184. if (exception->severity < (asperity)) \
  185. (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
  186. "`%s'",option); \
  187. DestroyCompare(); \
  188. return(MagickFalse); \
  189. }
  190. #define ThrowCompareInvalidArgumentException(option,argument) \
  191. { \
  192. (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
  193. "InvalidArgument","`%s': %s",option,argument); \
  194. DestroyCompare(); \
  195. return(MagickFalse); \
  196. }
  197. char
  198. *filename,
  199. *option;
  200. const char
  201. *format;
  202. ChannelType
  203. channels;
  204. double
  205. dissimilarity_threshold,
  206. distortion,
  207. similarity_metric;
  208. Image
  209. *difference_image,
  210. *image,
  211. *reconstruct_image,
  212. *similarity_image;
  213. ImageStack
  214. image_stack[MaxImageStackDepth+1];
  215. ssize_t
  216. j,
  217. k;
  218. MagickBooleanType
  219. fire,
  220. pend;
  221. MagickStatusType
  222. status;
  223. MetricType
  224. metric;
  225. RectangleInfo
  226. offset;
  227. register ssize_t
  228. i;
  229. /*
  230. Set defaults.
  231. */
  232. assert(image_info != (ImageInfo *) NULL);
  233. assert(image_info->signature == MagickSignature);
  234. if (image_info->debug != MagickFalse)
  235. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  236. assert(exception != (ExceptionInfo *) NULL);
  237. if (argc == 2)
  238. {
  239. option=argv[1];
  240. if ((LocaleCompare("version",option+1) == 0) ||
  241. (LocaleCompare("-version",option+1) == 0))
  242. {
  243. (void) fprintf(stdout,"Version: %s\n",
  244. GetMagickVersion((size_t *) NULL));
  245. (void) fprintf(stdout,"Copyright: %s\n",GetMagickCopyright());
  246. (void) fprintf(stdout,"Features: %s\n\n",GetMagickFeatures());
  247. return(MagickFalse);
  248. }
  249. }
  250. if (argc < 3)
  251. return(CompareUsage());
  252. channels=AllChannels;
  253. difference_image=NewImageList();
  254. similarity_image=NewImageList();
  255. dissimilarity_threshold=DefaultDissimilarityThreshold;
  256. distortion=0.0;
  257. format=(char *) NULL;
  258. j=1;
  259. k=0;
  260. metric=UndefinedMetric;
  261. NewImageStack();
  262. option=(char *) NULL;
  263. pend=MagickFalse;
  264. reconstruct_image=NewImageList();
  265. status=MagickTrue;
  266. /*
  267. Compare an image.
  268. */
  269. ReadCommandlLine(argc,&argv);
  270. status=ExpandFilenames(&argc,&argv);
  271. if (status == MagickFalse)
  272. ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
  273. GetExceptionMessage(errno));
  274. for (i=1; i < (ssize_t) (argc-1); i++)
  275. {
  276. option=argv[i];
  277. if (LocaleCompare(option,"(") == 0)
  278. {
  279. FireImageStack(MagickTrue,MagickTrue,pend);
  280. if (k == MaxImageStackDepth)
  281. ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
  282. option);
  283. PushImageStack();
  284. continue;
  285. }
  286. if (LocaleCompare(option,")") == 0)
  287. {
  288. FireImageStack(MagickTrue,MagickTrue,MagickTrue);
  289. if (k == 0)
  290. ThrowCompareException(OptionError,"UnableToParseExpression",option);
  291. PopImageStack();
  292. continue;
  293. }
  294. if (IsMagickOption(option) == MagickFalse)
  295. {
  296. Image
  297. *images;
  298. /*
  299. Read input image.
  300. */
  301. FireImageStack(MagickFalse,MagickFalse,pend);
  302. filename=argv[i];
  303. if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1)))
  304. filename=argv[++i];
  305. (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
  306. images=ReadImages(image_info,exception);
  307. status&=(images != (Image *) NULL) &&
  308. (exception->severity < ErrorException);
  309. if (images == (Image *) NULL)
  310. continue;
  311. AppendImageStack(images);
  312. continue;
  313. }
  314. pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
  315. switch (*(option+1))
  316. {
  317. case 'a':
  318. {
  319. if (LocaleCompare("alpha",option+1) == 0)
  320. {
  321. ssize_t
  322. type;
  323. if (*option == '+')
  324. break;
  325. i++;
  326. if (i == (ssize_t) argc)
  327. ThrowCompareException(OptionError,"MissingArgument",option);
  328. type=ParseMagickOption(MagickAlphaOptions,MagickFalse,argv[i]);
  329. if (type < 0)
  330. ThrowCompareException(OptionError,"UnrecognizedAlphaChannelType",
  331. argv[i]);
  332. break;
  333. }
  334. if (LocaleCompare("authenticate",option+1) == 0)
  335. {
  336. if (*option == '+')
  337. break;
  338. i++;
  339. if (i == (ssize_t) argc)
  340. ThrowCompareException(OptionError,"MissingArgument",option);
  341. break;
  342. }
  343. ThrowCompareException(OptionError,"UnrecognizedOption",option);
  344. }
  345. case 'c':
  346. {
  347. if (LocaleCompare("cache",option+1) == 0)
  348. {
  349. if (*option == '+')
  350. break;
  351. i++;
  352. if (i == (ssize_t) argc)
  353. ThrowCompareException(OptionError,"MissingArgument",option);
  354. if (IsGeometry(argv[i]) == MagickFalse)
  355. ThrowCompareInvalidArgumentException(option,argv[i]);
  356. break;
  357. }
  358. if (LocaleCompare("channel",option+1) == 0)
  359. {
  360. ssize_t
  361. channel;
  362. if (*option == '+')
  363. break;
  364. i++;
  365. if (i == (ssize_t) (argc-1))
  366. ThrowCompareException(OptionError,"MissingArgument",option);
  367. channel=ParseChannelOption(argv[i]);
  368. if (channel < 0)
  369. ThrowCompareException(OptionError,"UnrecognizedChannelType",
  370. argv[i]);
  371. channels=(ChannelType) channel;
  372. break;
  373. }
  374. if (LocaleCompare("colorspace",option+1) == 0)
  375. {
  376. ssize_t
  377. colorspace;
  378. if (*option == '+')
  379. break;
  380. i++;
  381. if (i == (ssize_t) (argc-1))
  382. ThrowCompareException(OptionError,"MissingArgument",option);
  383. colorspace=ParseMagickOption(MagickColorspaceOptions,MagickFalse,
  384. argv[i]);
  385. if (colorspace < 0)
  386. ThrowCompareException(OptionError,"UnrecognizedColorspace",
  387. argv[i]);
  388. break;
  389. }
  390. if (LocaleCompare("compose",option+1) == 0)
  391. {
  392. ssize_t
  393. compose;
  394. if (*option == '+')
  395. break;
  396. i++;
  397. if (i == (ssize_t) argc)
  398. ThrowCompareException(OptionError,"MissingArgument",option);
  399. compose=ParseMagickOption(MagickComposeOptions,MagickFalse,
  400. argv[i]);
  401. if (compose < 0)
  402. ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
  403. argv[i]);
  404. break;
  405. }
  406. if (LocaleCompare("compress",option+1) == 0)
  407. {
  408. ssize_t
  409. compress;
  410. if (*option == '+')
  411. break;
  412. i++;
  413. if (i == (ssize_t) (argc-1))
  414. ThrowCompareException(OptionError,"MissingArgument",option);
  415. compress=ParseMagickOption(MagickCompressOptions,MagickFalse,
  416. argv[i]);
  417. if (compress < 0)
  418. ThrowCompareException(OptionError,"UnrecognizedImageCompression",
  419. argv[i]);
  420. break;
  421. }
  422. if (LocaleCompare("concurrent",option+1) == 0)
  423. break;
  424. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  425. }
  426. case 'd':
  427. {
  428. if (LocaleCompare("debug",option+1) == 0)
  429. {
  430. LogEventType
  431. event_mask;
  432. if (*option == '+')
  433. break;
  434. i++;
  435. if (i == (ssize_t) argc)
  436. ThrowCompareException(OptionError,"MissingArgument",option);
  437. event_mask=SetLogEventMask(argv[i]);
  438. if (event_mask == UndefinedEvents)
  439. ThrowCompareException(OptionError,"UnrecognizedEventType",
  440. argv[i]);
  441. break;
  442. }
  443. if (LocaleCompare("decipher",option+1) == 0)
  444. {
  445. if (*option == '+')
  446. break;
  447. i++;
  448. if (i == (ssize_t) (argc-1))
  449. ThrowCompareException(OptionError,"MissingArgument",option);
  450. break;
  451. }
  452. if (LocaleCompare("define",option+1) == 0)
  453. {
  454. i++;
  455. if (i == (ssize_t) argc)
  456. ThrowCompareException(OptionError,"MissingArgument",option);
  457. if (*option == '+')
  458. {
  459. const char
  460. *define;
  461. define=GetImageOption(image_info,argv[i]);
  462. if (define == (const char *) NULL)
  463. ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
  464. break;
  465. }
  466. break;
  467. }
  468. if (LocaleCompare("density",option+1) == 0)
  469. {
  470. if (*option == '+')
  471. break;
  472. i++;
  473. if (i == (ssize_t) argc)
  474. ThrowCompareException(OptionError,"MissingArgument",option);
  475. if (IsGeometry(argv[i]) == MagickFalse)
  476. ThrowCompareInvalidArgumentException(option,argv[i]);
  477. break;
  478. }
  479. if (LocaleCompare("depth",option+1) == 0)
  480. {
  481. if (*option == '+')
  482. break;
  483. i++;
  484. if (i == (ssize_t) argc)
  485. ThrowCompareException(OptionError,"MissingArgument",option);
  486. if (IsGeometry(argv[i]) == MagickFalse)
  487. ThrowCompareInvalidArgumentException(option,argv[i]);
  488. break;
  489. }
  490. if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
  491. {
  492. if (*option == '+')
  493. break;
  494. i++;
  495. if (i == (ssize_t) argc)
  496. ThrowCompareException(OptionError,"MissingArgument",option);
  497. if (IsGeometry(argv[i]) == MagickFalse)
  498. ThrowCompareInvalidArgumentException(option,argv[i]);
  499. if (*option == '+')
  500. dissimilarity_threshold=DefaultDissimilarityThreshold;
  501. else
  502. dissimilarity_threshold=StringToDouble(argv[i]);
  503. break;
  504. }
  505. if (LocaleCompare("duration",option+1) == 0)
  506. {
  507. if (*option == '+')
  508. break;
  509. i++;
  510. if (i == (ssize_t) (argc-1))
  511. ThrowCompareException(OptionError,"MissingArgument",option);
  512. if (IsGeometry(argv[i]) == MagickFalse)
  513. ThrowCompareInvalidArgumentException(option,argv[i]);
  514. break;
  515. }
  516. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  517. }
  518. case 'e':
  519. {
  520. if (LocaleCompare("encipher",option+1) == 0)
  521. {
  522. if (*option == '+')
  523. break;
  524. i++;
  525. if (i == (ssize_t) (argc-1))
  526. ThrowCompareException(OptionError,"MissingArgument",option);
  527. break;
  528. }
  529. if (LocaleCompare("extract",option+1) == 0)
  530. {
  531. if (*option == '+')
  532. break;
  533. i++;
  534. if (i == (ssize_t) (argc-1))
  535. ThrowCompareException(OptionError,"MissingArgument",option);
  536. if (IsGeometry(argv[i]) == MagickFalse)
  537. ThrowCompareInvalidArgumentException(option,argv[i]);
  538. break;
  539. }
  540. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  541. }
  542. case 'f':
  543. {
  544. if (LocaleCompare("format",option+1) == 0)
  545. {
  546. if (*option == '+')
  547. break;
  548. i++;
  549. if (i == (ssize_t) argc)
  550. ThrowCompareException(OptionError,"MissingArgument",option);
  551. format=argv[i];
  552. break;
  553. }
  554. if (LocaleCompare("fuzz",option+1) == 0)
  555. {
  556. if (*option == '+')
  557. break;
  558. i++;
  559. if (i == (ssize_t) (argc-1))
  560. ThrowCompareException(OptionError,"MissingArgument",option);
  561. if (IsGeometry(argv[i]) == MagickFalse)
  562. ThrowCompareInvalidArgumentException(option,argv[i]);
  563. break;
  564. }
  565. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  566. }
  567. case 'h':
  568. {
  569. if ((LocaleCompare("help",option+1) == 0) ||
  570. (LocaleCompare("-help",option+1) == 0))
  571. return(CompareUsage());
  572. if (LocaleCompare("highlight-color",option+1) == 0)
  573. {
  574. if (*option == '+')
  575. break;
  576. i++;
  577. if (i == (ssize_t) (argc-1))
  578. ThrowCompareException(OptionError,"MissingArgument",option);
  579. break;
  580. }
  581. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  582. }
  583. case 'i':
  584. {
  585. if (LocaleCompare("identify",option+1) == 0)
  586. break;
  587. if (LocaleCompare("interlace",option+1) == 0)
  588. {
  589. ssize_t
  590. interlace;
  591. if (*option == '+')
  592. break;
  593. i++;
  594. if (i == (ssize_t) argc)
  595. ThrowCompareException(OptionError,"MissingArgument",option);
  596. interlace=ParseMagickOption(MagickInterlaceOptions,MagickFalse,
  597. argv[i]);
  598. if (interlace < 0)
  599. ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
  600. argv[i]);
  601. break;
  602. }
  603. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  604. }
  605. case 'l':
  606. {
  607. if (LocaleCompare("limit",option+1) == 0)
  608. {
  609. char
  610. *p;
  611. double
  612. value;
  613. ssize_t
  614. resource;
  615. if (*option == '+')
  616. break;
  617. i++;
  618. if (i == (ssize_t) argc)
  619. ThrowCompareException(OptionError,"MissingArgument",option);
  620. resource=ParseMagickOption(MagickResourceOptions,MagickFalse,
  621. argv[i]);
  622. if (resource < 0)
  623. ThrowCompareException(OptionError,"UnrecognizedResourceType",
  624. argv[i]);
  625. i++;
  626. if (i == (ssize_t) argc)
  627. ThrowCompareException(OptionError,"MissingArgument",option);
  628. value=strtod(argv[i],&p);
  629. if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
  630. ThrowCompareInvalidArgumentException(option,argv[i]);
  631. break;
  632. }
  633. if (LocaleCompare("list",option+1) == 0)
  634. {
  635. ssize_t
  636. list;
  637. if (*option == '+')
  638. break;
  639. i++;
  640. if (i == (ssize_t) argc)
  641. ThrowCompareException(OptionError,"MissingArgument",option);
  642. list=ParseMagickOption(MagickListOptions,MagickFalse,argv[i]);
  643. if (list < 0)
  644. ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]);
  645. status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **)
  646. argv+j,exception);
  647. DestroyCompare();
  648. return(status != 0 ? MagickFalse : MagickTrue);
  649. }
  650. if (LocaleCompare("log",option+1) == 0)
  651. {
  652. if (*option == '+')
  653. break;
  654. i++;
  655. if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL))
  656. ThrowCompareException(OptionError,"MissingArgument",option);
  657. break;
  658. }
  659. if (LocaleCompare("lowlight-color",option+1) == 0)
  660. {
  661. if (*option == '+')
  662. break;
  663. i++;
  664. if (i == (ssize_t) (argc-1))
  665. ThrowCompareException(OptionError,"MissingArgument",option);
  666. break;
  667. }
  668. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  669. }
  670. case 'm':
  671. {
  672. if (LocaleCompare("matte",option+1) == 0)
  673. break;
  674. if (LocaleCompare("metric",option+1) == 0)
  675. {
  676. ssize_t
  677. type;
  678. if (*option == '+')
  679. break;
  680. i++;
  681. if (i == (ssize_t) argc)
  682. ThrowCompareException(OptionError,"MissingArgument",option);
  683. type=ParseMagickOption(MagickMetricOptions,MagickTrue,argv[i]);
  684. if (type < 0)
  685. ThrowCompareException(OptionError,"UnrecognizedMetricType",
  686. argv[i]);
  687. metric=(MetricType) type;
  688. break;
  689. }
  690. if (LocaleCompare("monitor",option+1) == 0)
  691. break;
  692. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  693. }
  694. case 'p':
  695. {
  696. if (LocaleCompare("passphrase",option+1) == 0)
  697. {
  698. if (*option == '+')
  699. break;
  700. i++;
  701. if (i == (ssize_t) argc)
  702. ThrowCompareException(OptionError,"MissingArgument",option);
  703. break;
  704. }
  705. if (LocaleCompare("profile",option+1) == 0)
  706. {
  707. i++;
  708. if (i == (ssize_t) (argc-1))
  709. ThrowCompareException(OptionError,"MissingArgument",option);
  710. break;
  711. }
  712. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  713. }
  714. case 'q':
  715. {
  716. if (LocaleCompare("quality",option+1) == 0)
  717. {
  718. if (*option == '+')
  719. break;
  720. i++;
  721. if (i == (ssize_t) (argc-1))
  722. ThrowCompareException(OptionError,"MissingArgument",option);
  723. if (IsGeometry(argv[i]) == MagickFalse)
  724. ThrowCompareInvalidArgumentException(option,argv[i]);
  725. break;
  726. }
  727. if (LocaleCompare("quantize",option+1) == 0)
  728. {
  729. ssize_t
  730. colorspace;
  731. if (*option == '+')
  732. break;
  733. i++;
  734. if (i == (ssize_t) (argc-1))
  735. ThrowCompareException(OptionError,"MissingArgument",option);
  736. colorspace=ParseMagickOption(MagickColorspaceOptions,
  737. MagickFalse,argv[i]);
  738. if (colorspace < 0)
  739. ThrowCompareException(OptionError,"UnrecognizedColorspace",
  740. argv[i]);
  741. break;
  742. }
  743. if (LocaleCompare("quiet",option+1) == 0)
  744. break;
  745. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  746. }
  747. case 'r':
  748. {
  749. if (LocaleCompare("regard-warnings",option+1) == 0)
  750. break;
  751. if (LocaleNCompare("respect-parentheses",option+1,17) == 0)
  752. {
  753. respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
  754. break;
  755. }
  756. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  757. }
  758. case 's':
  759. {
  760. if (LocaleCompare("sampling-factor",option+1) == 0)
  761. {
  762. if (*option == '+')
  763. break;
  764. i++;
  765. if (i == (ssize_t) argc)
  766. ThrowCompareException(OptionError,"MissingArgument",option);
  767. if (IsGeometry(argv[i]) == MagickFalse)
  768. ThrowCompareInvalidArgumentException(option,argv[i]);
  769. break;
  770. }
  771. if (LocaleCompare("seed",option+1) == 0)
  772. {
  773. if (*option == '+')
  774. break;
  775. i++;
  776. if (i == (ssize_t) (argc-1))
  777. ThrowCompareException(OptionError,"MissingArgument",option);
  778. if (IsGeometry(argv[i]) == MagickFalse)
  779. ThrowCompareInvalidArgumentException(option,argv[i]);
  780. break;
  781. }
  782. if (LocaleCompare("set",option+1) == 0)
  783. {
  784. i++;
  785. if (i == (ssize_t) argc)
  786. ThrowCompareException(OptionError,"MissingArgument",option);
  787. if (*option == '+')
  788. break;
  789. i++;
  790. if (i == (ssize_t) argc)
  791. ThrowCompareException(OptionError,"MissingArgument",option);
  792. break;
  793. }
  794. if (LocaleCompare("size",option+1) == 0)
  795. {
  796. if (*option == '+')
  797. break;
  798. i++;
  799. if (i == (ssize_t) argc)
  800. ThrowCompareException(OptionError,"MissingArgument",option);
  801. if (IsGeometry(argv[i]) == MagickFalse)
  802. ThrowCompareInvalidArgumentException(option,argv[i]);
  803. break;
  804. }
  805. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  806. }
  807. case 't':
  808. {
  809. if (LocaleCompare("transparent-color",option+1) == 0)
  810. {
  811. if (*option == '+')
  812. break;
  813. i++;
  814. if (i == (ssize_t) (argc-1))
  815. ThrowCompareException(OptionError,"MissingArgument",option);
  816. break;
  817. }
  818. if (LocaleCompare("type",option+1) == 0)
  819. {
  820. ssize_t
  821. type;
  822. if (*option == '+')
  823. break;
  824. i++;
  825. if (i == (ssize_t) argc)
  826. ThrowCompareException(OptionError,"MissingArgument",option);
  827. type=ParseMagickOption(MagickTypeOptions,MagickFalse,argv[i]);
  828. if (type < 0)
  829. ThrowCompareException(OptionError,"UnrecognizedImageType",
  830. argv[i]);
  831. break;
  832. }
  833. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  834. }
  835. case 'v':
  836. {
  837. if (LocaleCompare("verbose",option+1) == 0)
  838. break;
  839. if ((LocaleCompare("version",option+1) == 0) ||
  840. (LocaleCompare("-version",option+1) == 0))
  841. {
  842. (void) fprintf(stdout,"Version: %s\n",
  843. GetMagickVersion((size_t *) NULL));
  844. (void) fprintf(stdout,"Copyright: %s\n",GetMagickCopyright());
  845. (void) fprintf(stdout,"Features: %s\n\n",GetMagickFeatures());
  846. break;
  847. }
  848. if (LocaleCompare("virtual-pixel",option+1) == 0)
  849. {
  850. ssize_t
  851. method;
  852. if (*option == '+')
  853. break;
  854. i++;
  855. if (i == (ssize_t) (argc-1))
  856. ThrowCompareException(OptionError,"MissingArgument",option);
  857. method=ParseMagickOption(MagickVirtualPixelOptions,MagickFalse,
  858. argv[i]);
  859. if (method < 0)
  860. ThrowCompareException(OptionError,
  861. "UnrecognizedVirtualPixelMethod",argv[i]);
  862. break;
  863. }
  864. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  865. }
  866. case '?':
  867. break;
  868. default:
  869. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  870. }
  871. fire=ParseMagickOption(MagickImageListOptions,MagickFalse,option+1) < 0 ?
  872. MagickFalse : MagickTrue;
  873. if (fire != MagickFalse)
  874. FireImageStack(MagickTrue,MagickTrue,MagickTrue);
  875. }
  876. if (k != 0)
  877. ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
  878. if (i-- != (ssize_t) (argc-1))
  879. ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  880. if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
  881. ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  882. FinalizeImageSettings(image_info,image,MagickTrue);
  883. if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
  884. ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  885. image=GetImageFromList(image,0);
  886. reconstruct_image=GetImageFromList(image,1);
  887. similarity_image=SimilarityImage(image,reconstruct_image,&offset,
  888. &similarity_metric,exception);
  889. if (similarity_metric > dissimilarity_threshold)
  890. ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
  891. if ((reconstruct_image->columns == image->columns) &&
  892. (reconstruct_image->rows == image->rows))
  893. difference_image=CompareImageChannels(image,reconstruct_image,channels,
  894. metric,&distortion,exception);
  895. else
  896. if (similarity_image != (Image *) NULL)
  897. {
  898. Image
  899. *composite_image;
  900. /*
  901. Determine if reconstructed image is a subimage of the image.
  902. */
  903. composite_image=CloneImage(image,0,0,MagickTrue,exception);
  904. if (composite_image == (Image *) NULL)
  905. difference_image=CompareImageChannels(image,reconstruct_image,
  906. channels,metric,&distortion,exception);
  907. else
  908. {
  909. (void) CompositeImage(composite_image,CopyCompositeOp,
  910. reconstruct_image,offset.x,offset.y);
  911. difference_image=CompareImageChannels(image,composite_image,
  912. channels,metric,&distortion,exception);
  913. if (difference_image != (Image *) NULL)
  914. {
  915. difference_image->page.x=offset.x;
  916. difference_image->page.y=offset.y;
  917. }
  918. composite_image=DestroyImage(composite_image);
  919. }
  920. if (difference_image == (Image *) NULL)
  921. similarity_image=DestroyImage(similarity_image);
  922. else
  923. {
  924. AppendImageToList(&difference_image,similarity_image);
  925. similarity_image=(Image *) NULL;
  926. }
  927. }
  928. if (difference_image == (Image *) NULL)
  929. status=0;
  930. else
  931. {
  932. if (image_info->verbose != MagickFalse)
  933. (void) IsImagesEqual(image,reconstruct_image);
  934. if (*difference_image->magick == '\0')
  935. (void) CopyMagickString(difference_image->magick,image->magick,
  936. MaxTextExtent);
  937. if (image_info->verbose == MagickFalse)
  938. {
  939. switch (metric)
  940. {
  941. case MeanAbsoluteErrorMetric:
  942. case MeanSquaredErrorMetric:
  943. case RootMeanSquaredErrorMetric:
  944. case PeakAbsoluteErrorMetric:
  945. {
  946. (void) fprintf(stderr,"%g (%g)",QuantumRange*distortion,
  947. (double) distortion);
  948. if ((reconstruct_image->columns != image->columns) ||
  949. (reconstruct_image->rows != image->rows))
  950. (void) fprintf(stderr," @ %.20g,%.20g",(double)
  951. difference_image->page.x,(double) difference_image->page.y);
  952. (void) fprintf(stderr,"\n");
  953. break;
  954. }
  955. case AbsoluteErrorMetric:
  956. case PeakSignalToNoiseRatioMetric:
  957. {
  958. (void) fprintf(stderr,"%g",distortion);
  959. if ((reconstruct_image->columns != image->columns) ||
  960. (reconstruct_image->rows != image->rows))
  961. (void) fprintf(stderr," @ %.20g,%.20g",(double)
  962. difference_image->page.x,(double) difference_image->page.y);
  963. (void) fprintf(stderr,"\n");
  964. break;
  965. }
  966. case MeanErrorPerPixelMetric:
  967. {
  968. (void) fprintf(stderr,"%g (%g, %g)",distortion,
  969. image->error.normalized_mean_error,
  970. image->error.normalized_maximum_error);
  971. if ((reconstruct_image->columns != image->columns) ||
  972. (reconstruct_image->rows != image->rows))
  973. (void) fprintf(stderr," @ %.20g,%.20g",(double)
  974. difference_image->page.x,(double) difference_image->page.y);
  975. (void) fprintf(stderr,"\n");
  976. break;
  977. }
  978. case UndefinedMetric:
  979. break;
  980. }
  981. }
  982. else
  983. {
  984. double
  985. *channel_distortion;
  986. channel_distortion=GetImageChannelDistortions(image,reconstruct_image,
  987. metric,&image->exception);
  988. (void) fprintf(stderr,"Image: %s\n",image->filename);
  989. if ((reconstruct_image->columns != image->columns) ||
  990. (reconstruct_image->rows != image->rows))
  991. (void) fprintf(stderr,"Offset: %.20g,%.20g\n",(double)
  992. difference_image->page.x,(double) difference_image->page.y);
  993. (void) fprintf(stderr," Channel distortion: %s\n",
  994. MagickOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
  995. switch (metric)
  996. {
  997. case MeanAbsoluteErrorMetric:
  998. case MeanSquaredErrorMetric:
  999. case RootMeanSquaredErrorMetric:
  1000. case PeakAbsoluteErrorMetric:
  1001. {
  1002. switch (image->colorspace)
  1003. {
  1004. case RGBColorspace:
  1005. default:
  1006. {
  1007. (void) fprintf(stderr," red: %g (%g)\n",
  1008. QuantumRange*channel_distortion[RedChannel],
  1009. channel_distortion[RedChannel]);
  1010. (void) fprintf(stderr," green: %g (%g)\n",
  1011. QuantumRange*channel_distortion[GreenChannel],
  1012. channel_distortion[GreenChannel]);
  1013. (void) fprintf(stderr," blue: %g (%g)\n",
  1014. QuantumRange*channel_distortion[BlueChannel],
  1015. channel_distortion[BlueChannel]);
  1016. if (image->matte != MagickFalse)
  1017. (void) fprintf(stderr," alpha: %g (%g)\n",
  1018. QuantumRange*channel_distortion[OpacityChannel],
  1019. channel_distortion[OpacityChannel]);
  1020. break;
  1021. }
  1022. case CMYKColorspace:
  1023. {
  1024. (void) fprintf(stderr," cyan: %g (%g)\n",
  1025. QuantumRange*channel_distortion[CyanChannel],
  1026. channel_distortion[CyanChannel]);
  1027. (void) fprintf(stderr," magenta: %g (%g)\n",
  1028. QuantumRange*channel_distortion[MagentaChannel],
  1029. channel_distortion[MagentaChannel]);
  1030. (void) fprintf(stderr," yellow: %g (%g)\n",
  1031. QuantumRange*channel_distortion[YellowChannel],
  1032. channel_distortion[YellowChannel]);
  1033. (void) fprintf(stderr," black: %g (%g)\n",
  1034. QuantumRange*channel_distortion[BlackChannel],
  1035. channel_distortion[BlackChannel]);
  1036. if (image->matte != MagickFalse)
  1037. (void) fprintf(stderr," alpha: %g (%g)\n",
  1038. QuantumRange*channel_distortion[OpacityChannel],
  1039. channel_distortion[OpacityChannel]);
  1040. break;
  1041. }
  1042. case GRAYColorspace:
  1043. {
  1044. (void) fprintf(stderr," gray: %g (%g)\n",
  1045. QuantumRange*channel_distortion[GrayChannel],
  1046. channel_distortion[GrayChannel]);
  1047. if (image->matte != MagickFalse)
  1048. (void) fprintf(stderr," alpha: %g (%g)\n",
  1049. QuantumRange*channel_distortion[OpacityChannel],
  1050. channel_distortion[OpacityChannel]);
  1051. break;
  1052. }
  1053. }
  1054. (void) fprintf(stderr," all: %g (%g)\n",
  1055. QuantumRange*channel_distortion[AllChannels],
  1056. channel_distortion[AllChannels]);
  1057. break;
  1058. }
  1059. case AbsoluteErrorMetric:
  1060. case PeakSignalToNoiseRatioMetric:
  1061. {
  1062. switch (image->colorspace)
  1063. {
  1064. case RGBColorspace:
  1065. default:
  1066. {
  1067. (void) fprintf(stderr," red: %g\n",
  1068. channel_distortion[RedChannel]);
  1069. (void) fprintf(stderr," green: %g\n",
  1070. channel_distortion[GreenChannel]);
  1071. (void) fprintf(stderr," blue: %g\n",
  1072. channel_distortion[BlueChannel]);
  1073. if (image->matte != MagickFalse)
  1074. (void) fprintf(stderr," alpha: %g\n",
  1075. channel_distortion[OpacityChannel]);
  1076. break;
  1077. }
  1078. case CMYKColorspace:
  1079. {
  1080. (void) fprintf(stderr," cyan: %g\n",
  1081. channel_distortion[CyanChannel]);
  1082. (void) fprintf(stderr," magenta: %g\n",
  1083. channel_distortion[MagentaChannel]);
  1084. (void) fprintf(stderr," yellow: %g\n",
  1085. channel_distortion[YellowChannel]);
  1086. (void) fprintf(stderr," black: %g\n",
  1087. channel_distortion[BlackChannel]);
  1088. if (image->matte != MagickFalse)
  1089. (void) fprintf(stderr," alpha: %g\n",
  1090. channel_distortion[OpacityChannel]);
  1091. break;
  1092. }
  1093. case GRAYColorspace:
  1094. {
  1095. (void) fprintf(stderr," gray: %g\n",
  1096. channel_distortion[GrayChannel]);
  1097. if (image->matte != MagickFalse)
  1098. (void) fprintf(stderr," alpha: %g\n",
  1099. channel_distortion[OpacityChannel]);
  1100. break;
  1101. }
  1102. }
  1103. (void) fprintf(stderr," all: %g\n",
  1104. channel_distortion[AllChannels]);
  1105. break;
  1106. }
  1107. case MeanErrorPerPixelMetric:
  1108. {
  1109. (void) fprintf(stderr," %g (%g, %g)\n",
  1110. channel_distortion[AllChannels],
  1111. image->error.normalized_mean_error,
  1112. image->error.normalized_maximum_error);
  1113. break;
  1114. }
  1115. case UndefinedMetric:
  1116. break;
  1117. }
  1118. channel_distortion=(double *) RelinquishMagickMemory(
  1119. channel_distortion);
  1120. }
  1121. status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
  1122. if ((metadata != (char **) NULL) && (format != (char *) NULL))
  1123. {
  1124. char
  1125. *text;
  1126. text=InterpretImageProperties(image_info,difference_image,format);
  1127. if (text == (char *) NULL)
  1128. ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
  1129. GetExceptionMessage(errno));
  1130. (void) ConcatenateString(&(*metadata),text);
  1131. (void) ConcatenateString(&(*metadata),"\n");
  1132. text=DestroyString(text);
  1133. }
  1134. difference_image=DestroyImageList(difference_image);
  1135. }
  1136. DestroyCompare();
  1137. return(status != 0 ? MagickTrue : MagickFalse);
  1138. }