PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/ImageMagick-6.3.2/wand/compare.c

https://bitbucket.org/sisko/operation-caribou
C | 742 lines | 630 code | 28 blank | 84 comment | 251 complexity | 28a439a5b5ef9916649eb809473effcf MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1
  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-2006 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. %
  37. %
  38. */
  39. /*
  40. Include declarations.
  41. */
  42. #include "wand/studio.h"
  43. #include "wand/MagickWand.h"
  44. #include "wand/mogrify-private.h"
  45. /*
  46. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  47. % %
  48. % %
  49. % %
  50. % C o m p a r e I m a g e C o m m a n d %
  51. % %
  52. % %
  53. % %
  54. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  55. %
  56. % CompareImageCommand() compares two images and returns the difference between
  57. % them as a distortion metric and as a new image visually annotating their
  58. % differences.
  59. %
  60. % The format of the CompareImageCommand method is:
  61. %
  62. % MagickBooleanType CompareImageCommand(ImageInfo *image_info,int argc,
  63. % char **argv,char **metadata,ExceptionInfo *exception)
  64. %
  65. % A description of each parameter follows:
  66. %
  67. % o image_info: The image info.
  68. %
  69. % o argc: The number of elements in the argument vector.
  70. %
  71. % o argv: A text array containing the command line arguments.
  72. %
  73. % o metadata: any metadata is returned here.
  74. %
  75. % o exception: Return any errors or warnings in this structure.
  76. %
  77. %
  78. */
  79. static void CompareUsage(void)
  80. {
  81. const char
  82. **p;
  83. static const char
  84. *settings[]=
  85. {
  86. "-authenticate value decrypt image with this password",
  87. "-channel type apply option to select image channels",
  88. "-colorspace type alternate image colorspace",
  89. "-compress type type of pixel compression when writing the image",
  90. "-debug events display copious debugging information",
  91. "-define format:option",
  92. " define one or more image format options",
  93. "-density geometry horizontal and vertical density of the image",
  94. "-depth value image depth",
  95. "-extract geometry extract area from image",
  96. "-format \"string\" output formatted image characteristics",
  97. "-fuzz distance colors within this distance are considered equal",
  98. "-help print program options",
  99. "-identify identify the format and characteristics of the image",
  100. "-interlace type type of image interlacing scheme",
  101. "-limit type value pixel cache resource limit",
  102. "-log format format of debugging information",
  103. "-metric type measure differences between images with this metric",
  104. "-monitor monitor progress",
  105. "-profile filename add, delete, or apply an image profile",
  106. "-quality value JPEG/MIFF/PNG compression level",
  107. "-quiet suppress all error or warning messages",
  108. "-quantize colorspace reduce colors in this colorspace",
  109. "-regard-warnings pay attention to warning messages",
  110. "-sampling-factor geometry",
  111. " horizontal and vertical sampling factor",
  112. "-set attribute value set an image attribute",
  113. "-size geometry width and height of image",
  114. "-transparent-color color",
  115. " transparent color",
  116. "-type type image type",
  117. "-verbose print detailed information about the image",
  118. "-version print version information",
  119. "-virtual-pixel method",
  120. " virtual pixel access method",
  121. (char *) NULL
  122. };
  123. (void) printf("Version: %s\n",GetMagickVersion((unsigned long *) NULL));
  124. (void) printf("Copyright: %s\n\n",GetMagickCopyright());
  125. (void) printf("Usage: %s [options ...] image reconstruct difference\n",
  126. GetClientName());
  127. (void) printf("\nImage Settings:\n");
  128. for (p=settings; *p != (char *) NULL; p++)
  129. (void) printf(" %s\n",*p);
  130. (void) printf(
  131. "\nBy default, the image format of `file' is determined by its magic\n");
  132. (void) printf(
  133. "number. To specify a particular image format, precede the filename\n");
  134. (void) printf(
  135. "with an image format name and a colon (i.e. ps:image) or specify the\n");
  136. (void) printf(
  137. "image type as the filename suffix (i.e. image.ps). Specify 'file' as\n");
  138. (void) printf("'-' for standard input or output.\n");
  139. exit(0);
  140. }
  141. WandExport MagickBooleanType CompareImageCommand(ImageInfo *image_info,
  142. int argc,char **argv,char **metadata,ExceptionInfo *exception)
  143. {
  144. #define DestroyCompare() \
  145. { \
  146. for ( ; k >= 0; k--) \
  147. image_stack[k]=DestroyImageList(image_stack[k]); \
  148. for (i=0; i < (long) argc; i++) \
  149. argv[i]=(char *) RelinquishMagickMemory(argv[i]); \
  150. argv=(char **) RelinquishMagickMemory(argv); \
  151. }
  152. #define ThrowCompareException(asperity,tag,option) \
  153. { \
  154. if (exception->severity < (asperity)) \
  155. (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
  156. "`%s'",option); \
  157. DestroyCompare(); \
  158. return(MagickFalse); \
  159. }
  160. #define ThrowCompareInvalidArgumentException(option,argument) \
  161. { \
  162. (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
  163. "InvalidArgument","`%s': %s",argument,option); \
  164. DestroyCompare(); \
  165. return(MagickFalse); \
  166. }
  167. char
  168. *filename,
  169. *option;
  170. const char
  171. *format;
  172. ChannelType
  173. channel;
  174. double
  175. distortion;
  176. Image
  177. *difference_image,
  178. *image,
  179. *image_stack[MaxImageStackDepth+1],
  180. *reconstruct_image;
  181. long
  182. j,
  183. k;
  184. MagickBooleanType
  185. fire,
  186. pend;
  187. MagickStatusType
  188. status;
  189. MetricType
  190. metric;
  191. register long
  192. i;
  193. /*
  194. Set defaults.
  195. */
  196. assert(image_info != (ImageInfo *) NULL);
  197. assert(image_info->signature == MagickSignature);
  198. if (image_info->debug != MagickFalse)
  199. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  200. assert(exception != (ExceptionInfo *) NULL);
  201. if (argc < 3)
  202. CompareUsage();
  203. channel=AllChannels;
  204. difference_image=NewImageList();
  205. distortion=0.0;
  206. format=(char *) NULL;
  207. j=1;
  208. k=0;
  209. image_stack[k]=NewImageList();
  210. metric=UndefinedMetric;
  211. option=(char *) NULL;
  212. pend=MagickFalse;
  213. reconstruct_image=NewImageList();
  214. status=MagickTrue;
  215. /*
  216. Compare an image.
  217. */
  218. ReadCommandlLine(argc,&argv);
  219. status=ExpandFilenames(&argc,&argv);
  220. if (status == MagickFalse)
  221. {
  222. char
  223. *message;
  224. message=GetExceptionMessage(errno);
  225. ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
  226. message);
  227. message=(char *) RelinquishMagickMemory(message);
  228. }
  229. for (i=1; i < (long) (argc-1); i++)
  230. {
  231. option=argv[i];
  232. if (LocaleCompare(option,"(") == 0)
  233. {
  234. if (k == MaxImageStackDepth)
  235. ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
  236. option);
  237. MogrifyImageStack(image_stack[k],MagickTrue,pend);
  238. k++;
  239. image_stack[k]=NewImageList();
  240. continue;
  241. }
  242. if (LocaleCompare(option,")") == 0)
  243. {
  244. if (k == 0)
  245. ThrowCompareException(OptionError,"UnableToParseExpression",option);
  246. if (image_stack[k] != (Image *) NULL)
  247. {
  248. MogrifyImageStack(image_stack[k],MagickTrue,MagickTrue);
  249. AppendImageToList(&image_stack[k-1],image_stack[k]);
  250. }
  251. k--;
  252. continue;
  253. }
  254. if (IsMagickOption(option) == MagickFalse)
  255. {
  256. /*
  257. Read input image.
  258. */
  259. MogrifyImageStack(image_stack[k],MagickTrue,pend);
  260. filename=argv[i];
  261. if ((LocaleCompare(filename,"--") == 0) && (i < (argc-1)))
  262. filename=argv[++i];
  263. (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
  264. image=ReadImage(image_info,exception);
  265. status&=(image != (Image *) NULL) &&
  266. (exception->severity < ErrorException);
  267. if (image == (Image *) NULL)
  268. continue;
  269. AppendImageToList(&image_stack[k],image);
  270. continue;
  271. }
  272. pend=image_stack[k] != (Image *) NULL ? MagickTrue : MagickFalse;
  273. switch (*(option+1))
  274. {
  275. case 'c':
  276. {
  277. if (LocaleCompare("cache",option+1) == 0)
  278. {
  279. if (*option == '+')
  280. break;
  281. i++;
  282. if (i == (long) argc)
  283. ThrowCompareException(OptionError,"MissingArgument",option);
  284. if (IsGeometry(argv[i]) == MagickFalse)
  285. ThrowCompareInvalidArgumentException(option,argv[i]);
  286. break;
  287. }
  288. if (LocaleCompare("channel",option+1) == 0)
  289. {
  290. long
  291. channel;
  292. if (*option == '+')
  293. break;
  294. i++;
  295. if (i == (long) (argc-1))
  296. ThrowCompareException(OptionError,"MissingArgument",option);
  297. channel=ParseChannelOption(argv[i]);
  298. if (channel < 0)
  299. ThrowCompareException(OptionError,"UnrecognizedChannelType",
  300. argv[i]);
  301. break;
  302. }
  303. if (LocaleCompare("colorspace",option+1) == 0)
  304. {
  305. long
  306. colorspace;
  307. if (*option == '+')
  308. break;
  309. i++;
  310. if (i == (long) (argc-1))
  311. ThrowCompareException(OptionError,"MissingArgument",option);
  312. colorspace=ParseMagickOption(MagickColorspaceOptions,MagickFalse,
  313. argv[i]);
  314. if (colorspace < 0)
  315. ThrowCompareException(OptionError,"UnrecognizedColorspace",
  316. argv[i]);
  317. break;
  318. }
  319. if (LocaleCompare("compress",option+1) == 0)
  320. {
  321. long
  322. compression;
  323. if (*option == '+')
  324. break;
  325. i++;
  326. if (i == (long) (argc-1))
  327. ThrowCompareException(OptionError,"MissingArgument",option);
  328. compression=ParseMagickOption(MagickCompressionOptions,
  329. MagickFalse,argv[i]);
  330. if (compression < 0)
  331. ThrowCompareException(OptionError,
  332. "UnrecognizedImageCompression",argv[i]);
  333. break;
  334. }
  335. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  336. }
  337. case 'd':
  338. {
  339. if (LocaleCompare("debug",option+1) == 0)
  340. {
  341. LogEventType
  342. event_mask;
  343. if (*option == '+')
  344. break;
  345. i++;
  346. if (i == (long) argc)
  347. ThrowCompareException(OptionError,"MissingArgument",option);
  348. event_mask=SetLogEventMask(argv[i]);
  349. if (event_mask == UndefinedEvents)
  350. ThrowCompareException(OptionError,"UnrecognizedEventType",
  351. argv[i]);
  352. break;
  353. }
  354. if (LocaleCompare("define",option+1) == 0)
  355. {
  356. i++;
  357. if (i == (long) argc)
  358. ThrowCompareException(OptionError,"MissingArgument",option);
  359. if (*option == '+')
  360. {
  361. const char
  362. *define;
  363. define=GetImageOption(image_info,argv[i]);
  364. if (define == (const char *) NULL)
  365. ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
  366. break;
  367. }
  368. break;
  369. }
  370. if (LocaleCompare("density",option+1) == 0)
  371. {
  372. if (*option == '+')
  373. break;
  374. i++;
  375. if (i == (long) argc)
  376. ThrowCompareException(OptionError,"MissingArgument",option);
  377. if (IsGeometry(argv[i]) == MagickFalse)
  378. ThrowCompareInvalidArgumentException(option,argv[i]);
  379. break;
  380. }
  381. if (LocaleCompare("depth",option+1) == 0)
  382. {
  383. if (*option == '+')
  384. break;
  385. i++;
  386. if (i == (long) argc)
  387. ThrowCompareException(OptionError,"MissingArgument",option);
  388. if (IsGeometry(argv[i]) == MagickFalse)
  389. ThrowCompareInvalidArgumentException(option,argv[i]);
  390. break;
  391. }
  392. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  393. }
  394. case 'e':
  395. {
  396. if (LocaleCompare("extract",option+1) == 0)
  397. {
  398. if (*option == '+')
  399. break;
  400. i++;
  401. if (i == (long) (argc-1))
  402. ThrowCompareException(OptionError,"MissingArgument",option);
  403. if (IsGeometry(argv[i]) == MagickFalse)
  404. ThrowCompareInvalidArgumentException(option,argv[i]);
  405. break;
  406. }
  407. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  408. }
  409. case 'f':
  410. {
  411. if (LocaleCompare("format",option+1) == 0)
  412. {
  413. if (*option == '+')
  414. break;
  415. i++;
  416. if (i == (long) argc)
  417. ThrowCompareException(OptionError,"MissingArgument",option);
  418. format=argv[i];
  419. break;
  420. }
  421. if (LocaleCompare("fuzz",option+1) == 0)
  422. {
  423. if (*option == '+')
  424. break;
  425. i++;
  426. if (i == (long) (argc-1))
  427. ThrowCompareException(OptionError,"MissingArgument",option);
  428. if (IsGeometry(argv[i]) == MagickFalse)
  429. ThrowCompareInvalidArgumentException(option,argv[i]);
  430. break;
  431. }
  432. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  433. }
  434. case 'h':
  435. {
  436. if ((LocaleCompare("help",option+1) == 0) ||
  437. (LocaleCompare("-help",option+1) == 0))
  438. CompareUsage();
  439. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  440. }
  441. case 'i':
  442. {
  443. if (LocaleCompare("identify",option+1) == 0)
  444. break;
  445. if (LocaleCompare("interlace",option+1) == 0)
  446. {
  447. long
  448. interlace;
  449. if (*option == '+')
  450. break;
  451. i++;
  452. if (i == (long) argc)
  453. ThrowCompareException(OptionError,"MissingArgument",option);
  454. interlace=ParseMagickOption(MagickInterlaceOptions,MagickFalse,
  455. argv[i]);
  456. if (interlace < 0)
  457. ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
  458. argv[i]);
  459. break;
  460. }
  461. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  462. }
  463. case 'l':
  464. {
  465. if (LocaleCompare("limit",option+1) == 0)
  466. {
  467. long
  468. resource;
  469. if (*option == '+')
  470. break;
  471. i++;
  472. if (i == (long) argc)
  473. ThrowCompareException(OptionError,"MissingArgument",option);
  474. resource=ParseMagickOption(MagickResourceOptions,MagickFalse,
  475. argv[i]);
  476. if (resource < 0)
  477. ThrowCompareException(OptionError,"UnrecognizedResourceType",
  478. argv[i]);
  479. i++;
  480. if (i == (long) argc)
  481. ThrowCompareException(OptionError,"MissingArgument",option);
  482. if ((LocaleCompare("unlimited",argv[i]) != 0) &&
  483. (IsGeometry(argv[i]) == MagickFalse))
  484. ThrowCompareInvalidArgumentException(option,argv[i]);
  485. break;
  486. }
  487. if (LocaleCompare("log",option+1) == 0)
  488. {
  489. if (*option == '+')
  490. break;
  491. i++;
  492. if ((i == (long) argc) || (strchr(argv[i],'%') == (char *) NULL))
  493. ThrowCompareException(OptionError,"MissingArgument",option);
  494. break;
  495. }
  496. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  497. }
  498. case 'm':
  499. {
  500. if (LocaleCompare("metric",option+1) == 0)
  501. {
  502. if (*option == '+')
  503. break;
  504. i++;
  505. if (i == (long) argc)
  506. ThrowCompareException(OptionError,"MissingArgument",option);
  507. metric=(MetricType) ParseMagickOption(MagickMetricOptions,
  508. MagickTrue,argv[i]);
  509. if (metric <= UndefinedMetric)
  510. ThrowCompareException(OptionError,"UnrecognizedMetricType",
  511. argv[i]);
  512. break;
  513. }
  514. if (LocaleCompare("monitor",option+1) == 0)
  515. break;
  516. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  517. }
  518. case 'p':
  519. {
  520. if (LocaleCompare("profile",option+1) == 0)
  521. {
  522. i++;
  523. if (i == (long) (argc-1))
  524. ThrowCompareException(OptionError,"MissingArgument",option);
  525. break;
  526. }
  527. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  528. }
  529. case 'q':
  530. {
  531. if (LocaleCompare("quality",option+1) == 0)
  532. {
  533. if (*option == '+')
  534. break;
  535. i++;
  536. if (i == (long) (argc-1))
  537. ThrowCompareException(OptionError,"MissingArgument",option);
  538. if (IsGeometry(argv[i]) == MagickFalse)
  539. ThrowCompareInvalidArgumentException(option,argv[i]);
  540. break;
  541. }
  542. if (LocaleCompare("quantize",option+1) == 0)
  543. {
  544. long
  545. colorspace;
  546. if (*option == '+')
  547. break;
  548. i++;
  549. if (i == (long) (argc-1))
  550. ThrowCompareException(OptionError,"MissingArgument",option);
  551. colorspace=ParseMagickOption(MagickColorspaceOptions,
  552. MagickFalse,argv[i]);
  553. if (colorspace < 0)
  554. ThrowCompareException(OptionError,"UnrecognizedColorspace",
  555. argv[i]);
  556. break;
  557. }
  558. if (LocaleCompare("quiet",option+1) == 0)
  559. break;
  560. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  561. }
  562. case 'r':
  563. {
  564. if (LocaleCompare("regard-warnings",option+1) == 0)
  565. break;
  566. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  567. }
  568. case 's':
  569. {
  570. if (LocaleCompare("sampling-factor",option+1) == 0)
  571. {
  572. if (*option == '+')
  573. break;
  574. i++;
  575. if (i == (long) argc)
  576. ThrowCompareException(OptionError,"MissingArgument",option);
  577. if (IsGeometry(argv[i]) == MagickFalse)
  578. ThrowCompareInvalidArgumentException(option,argv[i]);
  579. break;
  580. }
  581. if (LocaleCompare("set",option+1) == 0)
  582. {
  583. i++;
  584. if (i == (long) argc)
  585. ThrowCompareException(OptionError,"MissingArgument",option);
  586. if (*option == '+')
  587. break;
  588. i++;
  589. if (i == (long) argc)
  590. ThrowCompareException(OptionError,"MissingArgument",option);
  591. break;
  592. }
  593. if (LocaleCompare("size",option+1) == 0)
  594. {
  595. if (*option == '+')
  596. break;
  597. i++;
  598. if (i == (long) argc)
  599. ThrowCompareException(OptionError,"MissingArgument",option);
  600. if (IsGeometry(argv[i]) == MagickFalse)
  601. ThrowCompareInvalidArgumentException(option,argv[i]);
  602. break;
  603. }
  604. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  605. }
  606. case 't':
  607. {
  608. if (LocaleCompare("transparent-color",option+1) == 0)
  609. {
  610. if (*option == '+')
  611. break;
  612. i++;
  613. if (i == (long) (argc-1))
  614. ThrowCompareException(OptionError,"MissingArgument",option);
  615. break;
  616. }
  617. if (LocaleCompare("type",option+1) == 0)
  618. {
  619. long
  620. type;
  621. if (*option == '+')
  622. break;
  623. i++;
  624. if (i == (long) argc)
  625. ThrowCompareException(OptionError,"MissingArgument",option);
  626. type=ParseMagickOption(MagickImageOptions,MagickFalse,argv[i]);
  627. if (type < 0)
  628. ThrowCompareException(OptionError,"UnrecognizedImageType",
  629. argv[i]);
  630. break;
  631. }
  632. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  633. }
  634. case 'v':
  635. {
  636. if (LocaleCompare("verbose",option+1) == 0)
  637. break;
  638. if ((LocaleCompare("version",option+1) == 0) ||
  639. (LocaleCompare("-version",option+1) == 0))
  640. break;
  641. if (LocaleCompare("virtual-pixel",option+1) == 0)
  642. {
  643. long
  644. method;
  645. if (*option == '+')
  646. break;
  647. i++;
  648. if (i == (long) (argc-1))
  649. ThrowCompareException(OptionError,"MissingArgument",option);
  650. method=ParseMagickOption(MagickVirtualPixelOptions,MagickFalse,
  651. argv[i]);
  652. if (method < 0)
  653. ThrowCompareException(OptionError,
  654. "UnrecognizedVirtualPixelMethod",argv[i]);
  655. break;
  656. }
  657. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  658. }
  659. case '?':
  660. break;
  661. default:
  662. ThrowCompareException(OptionError,"UnrecognizedOption",option)
  663. }
  664. fire=(MagickBooleanType) ParseMagickOption(MagickMogrifyOptions,
  665. MagickFalse,option+1);
  666. if (fire == MagickTrue)
  667. MogrifyImageStack(image_stack[k],MagickTrue,MagickTrue);
  668. }
  669. if (k != 0)
  670. ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
  671. if (i-- != (long) (argc-1))
  672. ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  673. if ((image_stack[k] == (Image *) NULL) ||
  674. (GetImageListLength(image_stack[k]) < 2))
  675. ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  676. MogrifyImageStack(image_stack[k],MagickTrue,MagickTrue);
  677. image=GetImageFromList(image_stack[k],0);
  678. reconstruct_image=GetImageFromList(image_stack[k],1);
  679. difference_image=CompareImageChannels(image,reconstruct_image,channel,
  680. metric,&distortion,exception);
  681. if (difference_image == (Image *) NULL)
  682. status=0;
  683. else
  684. {
  685. if (image_info->verbose != MagickFalse)
  686. (void) IsImagesEqual(image,reconstruct_image);
  687. status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
  688. if ((metadata != (char **) NULL) && (format != (char *) NULL))
  689. {
  690. char
  691. *text;
  692. text=InterpretImageProperties(image_info,difference_image,format);
  693. if (text == (char *) NULL)
  694. {
  695. char
  696. *message;
  697. message=GetExceptionMessage(errno);
  698. ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
  699. message);
  700. message=(char *) RelinquishMagickMemory(message);
  701. }
  702. (void) ConcatenateString(&(*metadata),text);
  703. (void) ConcatenateString(&(*metadata),"\n");
  704. text=(char *) RelinquishMagickMemory(text);
  705. }
  706. difference_image=DestroyImageList(difference_image);
  707. if (metric != UndefinedMetric)
  708. (void) fprintf(stdout,"%g\n",distortion);
  709. }
  710. DestroyCompare();
  711. return(status != 0 ? MagickTrue : MagickFalse);
  712. }