home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / libtiff / lbtif3_3.tar / tools / tiffcmp.c < prev    next >
C/C++ Source or Header  |  1993-08-26  |  14KB  |  487 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Header: /usr/people/sam/tiff/tools/RCS/tiffcmp.c,v 1.17 93/08/26 15:11:24 sam Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Copyright (c) 1988, 1989, 1990, 1991, 1992 Sam Leffler
  7.  * Copyright (c) 1991, 1992 Silicon Graphics, Inc.
  8.  *
  9.  * Permission to use, copy, modify, distribute, and sell this software and 
  10.  * its documentation for any purpose is hereby granted without fee, provided
  11.  * that (i) the above copyright notices and this permission notice appear in
  12.  * all copies of the software and related documentation, and (ii) the names of
  13.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  14.  * publicity relating to the software without the specific, prior written
  15.  * permission of Sam Leffler and Silicon Graphics.
  16.  * 
  17.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  18.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  19.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  20.  * 
  21.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  22.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  23.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  24.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  25.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  26.  * OF THIS SOFTWARE.
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32.  
  33. #include "tiffio.h"
  34.  
  35. static    int stoponfirstdiff = 1;
  36. static    int stoponfirsttag = 1;
  37. static    uint16 bitspersample = 1;
  38. static    uint16 samplesperpixel = 1;
  39. static    uint32 imagewidth;
  40. static    uint32 imagelength;
  41.  
  42. static    int tiffcmp(TIFF*, TIFF*);
  43. static    int cmptags(TIFF*, TIFF*);
  44. static    void ContigCompare(int, uint32, unsigned char*, unsigned char*, int);
  45. static    void PrintDiff(uint32, int, uint32, int, int);
  46. static    void SeparateCompare(int, int, uint32, unsigned char*, unsigned char*);
  47. static    void eof(const char*, uint32, int);
  48.  
  49. static void
  50. usage(void)
  51. {
  52.     fprintf(stderr, "Usage: tiffcmp [-l] [-t] file1 file2\n");
  53.     exit(-3);
  54. }
  55.  
  56. void
  57. main(int argc, char* argv[])
  58. {
  59.     TIFF *tif1, *tif2;
  60.     int c, dirnum;
  61.     extern int optind;
  62.  
  63.     while ((c = getopt(argc, argv, "lt")) != -1)
  64.         switch (c) {
  65.         case 'l':
  66.             stoponfirstdiff = 0;
  67.             break;
  68.         case 't':
  69.             stoponfirsttag = 0;
  70.             break;
  71.         case '?':
  72.             usage();
  73.             /*NOTREACHED*/
  74.         }
  75.     if (argc - optind < 2)
  76.         usage();
  77.     tif1 = TIFFOpen(argv[optind], "r");
  78.     if (tif1 == NULL)
  79.         exit(-1);
  80.     tif2 = TIFFOpen(argv[optind+1], "r");
  81.     if (tif2 == NULL)
  82.         exit(-2);
  83.     dirnum = 0;
  84.     while (tiffcmp(tif1, tif2)) {
  85.         if (!TIFFReadDirectory(tif1)) {
  86.             if (!TIFFReadDirectory(tif2))
  87.                 break;
  88.             printf("No more directories for %s\n",
  89.                 TIFFFileName(tif1));
  90.             exit(1);
  91.         } else if (!TIFFReadDirectory(tif2)) {
  92.             printf("No more directories for %s\n",
  93.                 TIFFFileName(tif2));
  94.             exit(1);
  95.         }
  96.         printf("Directory %d:\n", ++dirnum);
  97.     }
  98.     exit(0);
  99. }
  100.  
  101. #ifdef EOF
  102. #undef EOF
  103. #endif
  104. #define    EOF(tif, row, sample) { \
  105.     eof(TIFFFileName(tif), row, sample); \
  106.     goto bad; \
  107. }
  108.  
  109. static    int CheckShortTag(TIFF*, TIFF*, int, char*);
  110. static    int CheckShort2Tag(TIFF*, TIFF*, int, char*);
  111. static    int CheckShortArrayTag(TIFF*, TIFF*, int, char*);
  112. static    int CheckLongTag(TIFF*, TIFF*, int, char*);
  113. static    int CheckFloatTag(TIFF*, TIFF*, int, char*);
  114. static    int CheckStringTag(TIFF*, TIFF*, int, char*);
  115.  
  116. static int
  117. tiffcmp(TIFF* tif1, TIFF* tif2)
  118. {
  119.     uint16 config1, config2;
  120.     int s, size1, size2;
  121.     uint32 row;
  122.     register unsigned char *p1, *p2;
  123.     unsigned char *buf1, *buf2;
  124.  
  125.     if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample"))
  126.         return (0);
  127.     if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"))
  128.         return (0);
  129.     if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth"))
  130.         return (0);
  131.     if (!cmptags(tif1, tif2))
  132.         return (1);
  133.     (void) TIFFGetField(tif1, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  134.     (void) TIFFGetField(tif1, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
  135.     (void) TIFFGetField(tif1, TIFFTAG_IMAGEWIDTH, &imagewidth);
  136.     (void) TIFFGetField(tif1, TIFFTAG_IMAGELENGTH, &imagelength);
  137.     (void) TIFFGetField(tif1, TIFFTAG_PLANARCONFIG, &config1);
  138.     (void) TIFFGetField(tif2, TIFFTAG_PLANARCONFIG, &config2);
  139.     buf1 = (unsigned char *)malloc(size1 = TIFFScanlineSize(tif1));
  140.     buf2 = (unsigned char *)malloc(size2 = TIFFScanlineSize(tif2));
  141.     if (buf1 == NULL || buf2 == NULL) {
  142.         fprintf(stderr, "No space for scanline buffers\n");
  143.         exit(-1);
  144.     }
  145.     if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) {
  146.         fprintf(stderr,
  147. "Can't handle different planar configuration w/ different bits/sample\n");
  148.         goto bad;
  149.     }
  150. #define    pack(a,b)    ((a)<<8)|(b)
  151.     switch (pack(config1, config2)) {
  152.     case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG):
  153.         for (row = 0; row < imagelength; row++) {
  154.             if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
  155.                 EOF(tif2, row, -1)
  156.             for (s = 0; s < samplesperpixel; s++) {
  157.                 if (TIFFReadScanline(tif1, buf1, row, s) < 0)
  158.                     EOF(tif1, row, s)
  159.                 SeparateCompare(1, s, row, buf2, buf1);
  160.             }
  161.         }
  162.         break;
  163.     case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE):
  164.         for (row = 0; row < imagelength; row++) {
  165.             if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
  166.                 EOF(tif1, row, -1)
  167.             for (s = 0; s < samplesperpixel; s++) {
  168.                 if (TIFFReadScanline(tif2, buf2, row, s) < 0)
  169.                     EOF(tif2, row, s)
  170.                 SeparateCompare(0, s, row, buf1, buf2);
  171.             }
  172.         }
  173.         break;
  174.     case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE):
  175.         for (s = 0; s < samplesperpixel; s++)
  176.             for (row = 0; row < imagelength; row++) {
  177.                 if (TIFFReadScanline(tif1, buf1, row, s) < 0)
  178.                     EOF(tif1, row, s)
  179.                 if (TIFFReadScanline(tif2, buf2, row, s) < 0)
  180.                     EOF(tif2, row, s)
  181.                 ContigCompare(s, row, buf1, buf2, size1);
  182.             }
  183.         break;
  184.     case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG):
  185.         for (row = 0; row < imagelength; row++) {
  186.             if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
  187.                 EOF(tif1, row, -1)
  188.             if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
  189.                 EOF(tif2, row, -1)
  190.             ContigCompare(-1, row, buf1, buf2, size1);
  191.         }
  192.         break;
  193.     }
  194. done:
  195.     if (buf1) free(buf1);
  196.     if (buf2) free(buf2);
  197.     return (1);
  198. bad:
  199.     if (stoponfirstdiff)
  200.         exit(1);
  201.     if (buf1) free(buf1);
  202.     if (buf2) free(buf2);
  203.     return (0);
  204. }
  205.  
  206. #define    CmpShortField(tag, name) \
  207.     if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  208. #define    CmpShortField2(tag, name) \
  209.     if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  210. #define    CmpLongField(tag, name) \
  211.     if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  212. #define    CmpFloatField(tag, name) \
  213.     if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  214. #define    CmpStringField(tag, name) \
  215.     if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  216. #define    CmpShortArrayField(tag, name) \
  217.     if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  218.  
  219. static int
  220. cmptags(TIFF* tif1, TIFF* tif2)
  221. {
  222.     CmpLongField(TIFFTAG_SUBFILETYPE,    "SubFileType");
  223.     CmpLongField(TIFFTAG_IMAGEWIDTH,    "ImageWidth");
  224.     CmpLongField(TIFFTAG_IMAGELENGTH,    "ImageLength");
  225.     CmpShortField(TIFFTAG_BITSPERSAMPLE,    "BitsPerSample");
  226.     CmpShortField(TIFFTAG_COMPRESSION,    "Compression");
  227.     CmpShortField(TIFFTAG_PREDICTOR,    "Predictor");
  228.     CmpShortField(TIFFTAG_PHOTOMETRIC,    "PhotometricInterpretation");
  229.     CmpShortField(TIFFTAG_THRESHHOLDING,    "Thresholding");
  230.     CmpShortField(TIFFTAG_FILLORDER,    "FillOrder");
  231.     CmpShortField(TIFFTAG_ORIENTATION,    "Orientation");
  232.     CmpShortField(TIFFTAG_SAMPLESPERPIXEL,    "SamplesPerPixel");
  233.     CmpShortField(TIFFTAG_MINSAMPLEVALUE,    "MinSampleValue");
  234.     CmpShortField(TIFFTAG_MAXSAMPLEVALUE,    "MaxSampleValue");
  235.     CmpFloatField(TIFFTAG_XRESOLUTION,    "XResolution");
  236.     CmpFloatField(TIFFTAG_YRESOLUTION,    "YResolution");
  237.     CmpLongField(TIFFTAG_GROUP3OPTIONS,    "Group3Options");
  238.     CmpLongField(TIFFTAG_GROUP4OPTIONS,    "Group4Options");
  239.     CmpShortField(TIFFTAG_RESOLUTIONUNIT,    "ResolutionUnit");
  240.     CmpShortField(TIFFTAG_PLANARCONFIG,    "PlanarConfiguration");
  241.     CmpLongField(TIFFTAG_ROWSPERSTRIP,    "RowsPerStrip");
  242.     CmpFloatField(TIFFTAG_XPOSITION,    "XPosition");
  243.     CmpFloatField(TIFFTAG_YPOSITION,    "YPosition");
  244.     CmpShortField(TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit");
  245.     CmpShortField(TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit");
  246. #ifdef notdef
  247.     { uint16 *graycurve;
  248.       CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve);
  249.     }
  250.     { uint16 *red, *green, *blue;
  251.       CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue);
  252.     }
  253.     { uint16 *red, *green, *blue;
  254.       CmpField3(TIFFTAG_COLORMAP, red, green, blue);
  255.     }
  256. #endif
  257.     CmpShortField2(TIFFTAG_PAGENUMBER,    "PageNumber");
  258.     CmpStringField(TIFFTAG_ARTIST,        "Artist");
  259.     CmpStringField(TIFFTAG_IMAGEDESCRIPTION,"ImageDescription");
  260.     CmpStringField(TIFFTAG_MAKE,        "Make");
  261.     CmpStringField(TIFFTAG_MODEL,        "Model");
  262.     CmpStringField(TIFFTAG_SOFTWARE,    "Software");
  263.     CmpStringField(TIFFTAG_DATETIME,    "DateTime");
  264.     CmpStringField(TIFFTAG_HOSTCOMPUTER,    "HostComputer");
  265.     CmpStringField(TIFFTAG_PAGENAME,    "PageName");
  266.     CmpStringField(TIFFTAG_DOCUMENTNAME,    "DocumentName");
  267.     CmpShortField(TIFFTAG_MATTEING,        "Matteing");
  268.     CmpShortArrayField(TIFFTAG_EXTRASAMPLES,"ExtraSamples");
  269.     return (1);
  270. }
  271.  
  272. static void
  273. ContigCompare(int sample, uint32 row, unsigned char* p1, unsigned char* p2, int size)
  274. {
  275.     register uint32 pix;
  276.     register int ppb = 8/bitspersample;
  277.  
  278.     if (memcmp(p1, p2, size) == 0)
  279.         return;
  280.     switch (bitspersample) {
  281.     case 1: case 2: case 4: case 8: {
  282.         register unsigned char *pix1 = p1, *pix2 = p2;
  283.  
  284.         for (pix = 0; pix < imagewidth; pix1++, pix2++, pix += ppb)
  285.             if (*pix1 != *pix2)
  286.                 PrintDiff(row, sample, pix,
  287.                     *pix1, *pix2);
  288.         break;
  289.     }
  290.     case 16: {
  291.         register uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2;
  292.  
  293.         for (pix = 0; pix < imagewidth; pix1++, pix2++, pix++)
  294.             if (*pix1 != *pix2)
  295.                 PrintDiff(row, sample, pix,
  296.                     *pix1, *pix2);
  297.         break;
  298.     }
  299.     }
  300. }
  301.  
  302. static void
  303. PrintDiff(uint32 row, int sample, uint32 pix, int w1, int w2)
  304. {
  305.     register int mask1, mask2, s, ppb, bps;
  306.  
  307.     if (sample < 0)
  308.         sample = 0;
  309.     bps = bitspersample;
  310.     switch (bps) {
  311.     case 1:
  312.     case 2:
  313.     case 4:
  314.         mask1 =  ~((-1)<<bps);
  315.         s = (8-bps);
  316.         mask2 = mask1<<s;
  317.         for (; mask2; mask2 >>= bps, s -= bps, pix++) {
  318.             if ((w1 & mask2) ^ (w2 & mask2)) {
  319.                 printf(
  320.             "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
  321.                         row, pix, sample, (w1 >> s) & mask1,
  322.                     (w2 >> s) & mask1 );
  323.                 if (stoponfirstdiff)
  324.                     exit(1);
  325.             }
  326.         }
  327.         break;
  328.     case 8: 
  329.         printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
  330.             row, pix, sample, w1, w2);
  331.         if (stoponfirstdiff)
  332.             exit(1);
  333.         break;
  334.     case 16:
  335.         printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
  336.             row, pix, sample, w1, w2);
  337.         if (stoponfirstdiff)
  338.             exit(1);
  339.         break;
  340.     }
  341. }
  342.  
  343. static void
  344. SeparateCompare(int reversed, int sample, uint32 row, unsigned char* cp1, unsigned char* p2)
  345. {
  346.     uint32 npixels = imagewidth;
  347.     register int pixel;
  348.  
  349.     cp1 += sample;
  350.     for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++)
  351.         if (*cp1 != *p2) {
  352.             printf("Scanline %lu, pixel %lu, sample %d: ",
  353.                 row, pixel, sample);
  354.             if (reversed)
  355.                 printf("%02x %02x\n", *p2, *cp1);
  356.             else
  357.                 printf("%02x %02x\n", *cp1, *p2);
  358.             if (stoponfirstdiff)
  359.                 exit(1);
  360.         }
  361. }
  362.  
  363. static int
  364. checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2)
  365. {
  366.  
  367.     if (TIFFGetField(tif1, tag, p1)) {
  368.         if (!TIFFGetField(tif2, tag, p2)) {
  369.             printf("%s tag appears only in %s\n",
  370.                 name, TIFFFileName(tif1));
  371.             return (0);
  372.         }
  373.         return (1);
  374.     } else if (TIFFGetField(tif2, tag, p2)) {
  375.         printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
  376.         return (0);
  377.     }
  378.     return (-1);
  379. }
  380.  
  381. #define    CHECK(cmp, fmt) {                \
  382.     switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) {    \
  383.     case 1:    if (cmp)                \
  384.     case -1:    return (1);            \
  385.         printf(fmt, name, v1, v2);        \
  386.     }                        \
  387.     return (0);                    \
  388. }
  389.  
  390. static int
  391. CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  392. {
  393.     uint16 v1, v2;
  394.     CHECK(v1 == v2, "%s: %u %u\n");
  395. }
  396.  
  397. static int
  398. CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  399. {
  400.     uint16 v11, v12, v21, v22;
  401.  
  402.     if (TIFFGetField(tif1, tag, &v11, &v12)) {
  403.         if (!TIFFGetField(tif2, tag, &v21, &v22)) {
  404.             printf("%s tag appears only in %s\n",
  405.                 name, TIFFFileName(tif1));
  406.             return (0);
  407.         }
  408.         if (v11 == v21 && v12 == v22)
  409.             return (1);
  410.         printf("%s: <%u,%u> <%u,%u>\n", name, v11, v12, v21, v22);
  411.     } else if (TIFFGetField(tif2, tag, &v21, &v22))
  412.         printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
  413.     else
  414.         return (1);
  415.     return (0);
  416. }
  417.  
  418. static int
  419. CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  420. {
  421.     uint16 n1, *a1;
  422.     uint16 n2, *a2;
  423.  
  424.     if (TIFFGetField(tif1, tag, &n1, &a1)) {
  425.         if (!TIFFGetField(tif2, tag, &n2, &a2)) {
  426.             printf("%s tag appears only in %s\n",
  427.                 name, TIFFFileName(tif1));
  428.             return (0);
  429.         }
  430.         if (n1 == n2) {
  431.             char* sep;
  432.             int i;
  433.  
  434.             if (memcmp(a1, a2, n1) == 0)
  435.                 return (1);
  436.             printf("%s: value mismatch, <%u:", name, n1);
  437.             sep = "";
  438.             for (i = 0; i < n1; i++)
  439.                 printf("%s%u", sep, a1[i]), sep = ",";
  440.             printf("> and <%u: ", n2);
  441.             sep = "";
  442.             for (i = 0; i < n2; i++)
  443.                 printf("%s%u", sep, a2[i]), sep = ",";
  444.             printf(">\n");
  445.         } else
  446.             printf("%s: %u items in %s, %u items in %s", name,
  447.                 n1, TIFFFileName(tif1),
  448.                 n2, TIFFFileName(tif2)
  449.             );
  450.     } else if (TIFFGetField(tif2, tag, &n2, &a2))
  451.         printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
  452.     else
  453.         return (1);
  454.     return (0);
  455. }
  456.  
  457. static int
  458. CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  459. {
  460.     uint32 v1, v2;
  461.     CHECK(v1 == v2, "%s: %lu %lu\n");
  462. }
  463.  
  464. static int
  465. CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  466. {
  467.     float v1, v2;
  468.     CHECK(v1 == v2, "%s: %g %g\n");
  469. }
  470.  
  471. static int
  472. CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  473. {
  474.     char *v1, *v2;
  475.     CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n");
  476. }
  477.  
  478. static void
  479. eof(const char* name, uint32 row, int s)
  480. {
  481.  
  482.     printf("%s: EOF at scanline %lu", name, row);
  483.     if (s >= 0)
  484.         printf(", sample %d", s);
  485.     printf("\n");
  486. }
  487.