4 * Copyright (c) 1988-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
27 #include "tif_config.h"
40 extern int getopt(int, char**, char*);
43 static int stopondiff
= 1;
44 static int stoponfirsttag
= 1;
45 static uint16 bitspersample
= 1;
46 static uint16 samplesperpixel
= 1;
47 static uint16 sampleformat
= SAMPLEFORMAT_UINT
;
48 static uint32 imagewidth
;
49 static uint32 imagelength
;
51 static void usage(void);
52 static int tiffcmp(TIFF
*, TIFF
*);
53 static int cmptags(TIFF
*, TIFF
*);
54 static int ContigCompare(int, uint32
, unsigned char*, unsigned char*, int);
55 static int SeparateCompare(int, int, uint32
, unsigned char*, unsigned char*);
56 static void PrintIntDiff(uint32
, int, uint32
, uint32
, uint32
);
57 static void PrintFloatDiff(uint32
, int, uint32
, double, double);
59 static void leof(const char*, uint32
, int);
62 main(int argc
, char* argv
[])
69 while ((c
= getopt(argc
, argv
, "ltz:")) != -1)
75 stopondiff
= atoi(optarg
);
84 if (argc
- optind
< 2)
86 tif1
= TIFFOpen(argv
[optind
], "r");
89 tif2
= TIFFOpen(argv
[optind
+1], "r");
93 while (tiffcmp(tif1
, tif2
)) {
94 if (!TIFFReadDirectory(tif1
)) {
95 if (!TIFFReadDirectory(tif2
))
97 printf("No more directories for %s\n",
100 } else if (!TIFFReadDirectory(tif2
)) {
101 printf("No more directories for %s\n",
105 printf("Directory %d:\n", ++dirnum
);
114 "usage: tiffcmp [options] file1 file2",
115 "where options are:",
116 " -l list each byte of image data that differs between the files",
117 " -z # list specified number of bytes that differs between the files",
118 " -t ignore any differences in directory tags",
129 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
130 for (i
= 0; stuff
[i
] != NULL
; i
++)
131 fprintf(stderr
, "%s\n", stuff
[i
]);
135 #define checkEOF(tif, row, sample) { \
136 leof(TIFFFileName(tif), row, sample); \
140 static int CheckShortTag(TIFF
*, TIFF
*, int, char*);
141 static int CheckShort2Tag(TIFF
*, TIFF
*, int, char*);
142 static int CheckShortArrayTag(TIFF
*, TIFF
*, int, char*);
143 static int CheckLongTag(TIFF
*, TIFF
*, int, char*);
144 static int CheckFloatTag(TIFF
*, TIFF
*, int, char*);
145 static int CheckStringTag(TIFF
*, TIFF
*, int, char*);
148 tiffcmp(TIFF
* tif1
, TIFF
* tif2
)
150 uint16 config1
, config2
;
154 unsigned char *buf1
, *buf2
;
156 if (!CheckShortTag(tif1
, tif2
, TIFFTAG_BITSPERSAMPLE
, "BitsPerSample"))
158 if (!CheckShortTag(tif1
, tif2
, TIFFTAG_SAMPLESPERPIXEL
, "SamplesPerPixel"))
160 if (!CheckLongTag(tif1
, tif2
, TIFFTAG_IMAGEWIDTH
, "ImageWidth"))
162 if (!cmptags(tif1
, tif2
))
164 (void) TIFFGetField(tif1
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
);
165 (void) TIFFGetField(tif1
, TIFFTAG_SAMPLESPERPIXEL
, &samplesperpixel
);
166 (void) TIFFGetField(tif1
, TIFFTAG_SAMPLEFORMAT
, &sampleformat
);
167 (void) TIFFGetField(tif1
, TIFFTAG_IMAGEWIDTH
, &imagewidth
);
168 (void) TIFFGetField(tif1
, TIFFTAG_IMAGELENGTH
, &imagelength
);
169 (void) TIFFGetField(tif1
, TIFFTAG_PLANARCONFIG
, &config1
);
170 (void) TIFFGetField(tif2
, TIFFTAG_PLANARCONFIG
, &config2
);
171 buf1
= (unsigned char *)_TIFFmalloc(size1
= TIFFScanlineSize(tif1
));
172 buf2
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2
));
173 if (buf1
== NULL
|| buf2
== NULL
) {
174 fprintf(stderr
, "No space for scanline buffers\n");
177 if (config1
!= config2
&& bitspersample
!= 8 && samplesperpixel
> 1) {
179 "Can't handle different planar configuration w/ different bits/sample\n");
182 #define pack(a,b) ((a)<<8)|(b)
183 switch (pack(config1
, config2
)) {
184 case pack(PLANARCONFIG_SEPARATE
, PLANARCONFIG_CONTIG
):
185 for (row
= 0; row
< imagelength
; row
++) {
186 if (TIFFReadScanline(tif2
, buf2
, row
, 0) < 0)
187 checkEOF(tif2
, row
, -1)
188 for (s
= 0; s
< samplesperpixel
; s
++) {
189 if (TIFFReadScanline(tif1
, buf1
, row
, s
) < 0)
190 checkEOF(tif1
, row
, s
)
191 if (SeparateCompare(1, s
, row
, buf2
, buf1
) < 0)
196 case pack(PLANARCONFIG_CONTIG
, PLANARCONFIG_SEPARATE
):
197 for (row
= 0; row
< imagelength
; row
++) {
198 if (TIFFReadScanline(tif1
, buf1
, row
, 0) < 0)
199 checkEOF(tif1
, row
, -1)
200 for (s
= 0; s
< samplesperpixel
; s
++) {
201 if (TIFFReadScanline(tif2
, buf2
, row
, s
) < 0)
202 checkEOF(tif2
, row
, s
)
203 if (SeparateCompare(0, s
, row
, buf1
, buf2
) < 0)
208 case pack(PLANARCONFIG_SEPARATE
, PLANARCONFIG_SEPARATE
):
209 for (s
= 0; s
< samplesperpixel
; s
++)
210 for (row
= 0; row
< imagelength
; row
++) {
211 if (TIFFReadScanline(tif1
, buf1
, row
, s
) < 0)
212 checkEOF(tif1
, row
, s
)
213 if (TIFFReadScanline(tif2
, buf2
, row
, s
) < 0)
214 checkEOF(tif2
, row
, s
)
215 if (ContigCompare(s
, row
, buf1
, buf2
, size1
) < 0)
219 case pack(PLANARCONFIG_CONTIG
, PLANARCONFIG_CONTIG
):
220 for (row
= 0; row
< imagelength
; row
++) {
221 if (TIFFReadScanline(tif1
, buf1
, row
, 0) < 0)
222 checkEOF(tif1
, row
, -1)
223 if (TIFFReadScanline(tif2
, buf2
, row
, 0) < 0)
224 checkEOF(tif2
, row
, -1)
225 if (ContigCompare(-1, row
, buf1
, buf2
, size1
) < 0)
230 if (buf1
) _TIFFfree(buf1
);
231 if (buf2
) _TIFFfree(buf2
);
237 if (buf1
) _TIFFfree(buf1
);
238 if (buf2
) _TIFFfree(buf2
);
242 #define CmpShortField(tag, name) \
243 if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
244 #define CmpShortField2(tag, name) \
245 if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
246 #define CmpLongField(tag, name) \
247 if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
248 #define CmpFloatField(tag, name) \
249 if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
250 #define CmpStringField(tag, name) \
251 if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
252 #define CmpShortArrayField(tag, name) \
253 if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
256 cmptags(TIFF
* tif1
, TIFF
* tif2
)
258 CmpLongField(TIFFTAG_SUBFILETYPE
, "SubFileType");
259 CmpLongField(TIFFTAG_IMAGEWIDTH
, "ImageWidth");
260 CmpLongField(TIFFTAG_IMAGELENGTH
, "ImageLength");
261 CmpShortField(TIFFTAG_BITSPERSAMPLE
, "BitsPerSample");
262 CmpShortField(TIFFTAG_COMPRESSION
, "Compression");
263 CmpShortField(TIFFTAG_PREDICTOR
, "Predictor");
264 CmpShortField(TIFFTAG_PHOTOMETRIC
, "PhotometricInterpretation");
265 CmpShortField(TIFFTAG_THRESHHOLDING
, "Thresholding");
266 CmpShortField(TIFFTAG_FILLORDER
, "FillOrder");
267 CmpShortField(TIFFTAG_ORIENTATION
, "Orientation");
268 CmpShortField(TIFFTAG_SAMPLESPERPIXEL
, "SamplesPerPixel");
269 CmpShortField(TIFFTAG_MINSAMPLEVALUE
, "MinSampleValue");
270 CmpShortField(TIFFTAG_MAXSAMPLEVALUE
, "MaxSampleValue");
271 CmpShortField(TIFFTAG_SAMPLEFORMAT
, "SampleFormat");
272 CmpFloatField(TIFFTAG_XRESOLUTION
, "XResolution");
273 CmpFloatField(TIFFTAG_YRESOLUTION
, "YResolution");
274 CmpLongField(TIFFTAG_GROUP3OPTIONS
, "Group3Options");
275 CmpLongField(TIFFTAG_GROUP4OPTIONS
, "Group4Options");
276 CmpShortField(TIFFTAG_RESOLUTIONUNIT
, "ResolutionUnit");
277 CmpShortField(TIFFTAG_PLANARCONFIG
, "PlanarConfiguration");
278 CmpLongField(TIFFTAG_ROWSPERSTRIP
, "RowsPerStrip");
279 CmpFloatField(TIFFTAG_XPOSITION
, "XPosition");
280 CmpFloatField(TIFFTAG_YPOSITION
, "YPosition");
281 CmpShortField(TIFFTAG_GRAYRESPONSEUNIT
, "GrayResponseUnit");
282 CmpShortField(TIFFTAG_COLORRESPONSEUNIT
, "ColorResponseUnit");
285 CmpField(TIFFTAG_GRAYRESPONSECURVE
, graycurve
);
287 { uint16
*red
, *green
, *blue
;
288 CmpField3(TIFFTAG_COLORRESPONSECURVE
, red
, green
, blue
);
290 { uint16
*red
, *green
, *blue
;
291 CmpField3(TIFFTAG_COLORMAP
, red
, green
, blue
);
294 CmpShortField2(TIFFTAG_PAGENUMBER
, "PageNumber");
295 CmpStringField(TIFFTAG_ARTIST
, "Artist");
296 CmpStringField(TIFFTAG_IMAGEDESCRIPTION
,"ImageDescription");
297 CmpStringField(TIFFTAG_MAKE
, "Make");
298 CmpStringField(TIFFTAG_MODEL
, "Model");
299 CmpStringField(TIFFTAG_SOFTWARE
, "Software");
300 CmpStringField(TIFFTAG_DATETIME
, "DateTime");
301 CmpStringField(TIFFTAG_HOSTCOMPUTER
, "HostComputer");
302 CmpStringField(TIFFTAG_PAGENAME
, "PageName");
303 CmpStringField(TIFFTAG_DOCUMENTNAME
, "DocumentName");
304 CmpShortField(TIFFTAG_MATTEING
, "Matteing");
305 CmpShortArrayField(TIFFTAG_EXTRASAMPLES
,"ExtraSamples");
310 ContigCompare(int sample
, uint32 row
,
311 unsigned char* p1
, unsigned char* p2
, int size
)
314 int ppb
= 8 / bitspersample
;
317 if (memcmp(p1
, p2
, size
) == 0)
320 samples_to_test
= (sample
== -1) ? samplesperpixel
: 1;
322 switch (bitspersample
) {
323 case 1: case 2: case 4: case 8:
325 unsigned char *pix1
= p1
, *pix2
= p2
;
327 for (pix
= 0; pix
< imagewidth
; pix
+= ppb
) {
330 for(s
= 0; s
< samples_to_test
; s
++) {
331 if (*pix1
!= *pix2
) {
333 PrintIntDiff(row
, s
, pix
, *pix1
, *pix2
);
335 PrintIntDiff(row
, sample
, pix
, *pix1
, *pix2
);
346 uint16
*pix1
= (uint16
*)p1
, *pix2
= (uint16
*)p2
;
348 for (pix
= 0; pix
< imagewidth
; pix
++) {
351 for(s
= 0; s
< samples_to_test
; s
++) {
353 PrintIntDiff(row
, sample
, pix
, *pix1
, *pix2
);
362 if (sampleformat
== SAMPLEFORMAT_UINT
363 || sampleformat
== SAMPLEFORMAT_INT
) {
364 uint32
*pix1
= (uint32
*)p1
, *pix2
= (uint32
*)p2
;
366 for (pix
= 0; pix
< imagewidth
; pix
++) {
369 for(s
= 0; s
< samples_to_test
; s
++) {
370 if (*pix1
!= *pix2
) {
371 PrintIntDiff(row
, sample
, pix
,
379 } else if (sampleformat
== SAMPLEFORMAT_IEEEFP
) {
380 float *pix1
= (float *)p1
, *pix2
= (float *)p2
;
382 for (pix
= 0; pix
< imagewidth
; pix
++) {
385 for(s
= 0; s
< samples_to_test
; s
++) {
386 if (*pix1
!= *pix2
) {
387 PrintFloatDiff(row
, sample
, pix
,
396 fprintf(stderr
, "Sample format %d is not supported.\n",
402 fprintf(stderr
, "Bit depth %d is not supported.\n", bitspersample
);
410 PrintIntDiff(uint32 row
, int sample
, uint32 pix
, uint32 w1
, uint32 w2
)
414 switch (bitspersample
) {
419 int32 mask1
, mask2
, s
;
421 mask1
= ~((-1) << bitspersample
);
422 s
= (8 - bitspersample
);
424 for (; mask2
&& pix
< imagewidth
;
425 mask2
>>= bitspersample
, s
-= bitspersample
, pix
++) {
426 if ((w1
& mask2
) ^ (w2
& mask2
)) {
428 "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
432 (unsigned int)((w1
>> s
) & mask1
),
433 (unsigned int)((w2
>> s
) & mask1
));
434 if (--stopondiff
== 0)
441 printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
442 (unsigned long) row
, (unsigned long) pix
, sample
,
443 (unsigned int) w1
, (unsigned int) w2
);
444 if (--stopondiff
== 0)
448 printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
449 (unsigned long) row
, (unsigned long) pix
, sample
,
450 (unsigned int) w1
, (unsigned int) w2
);
451 if (--stopondiff
== 0)
455 printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
456 (unsigned long) row
, (unsigned long) pix
, sample
,
457 (unsigned int) w1
, (unsigned int) w2
);
458 if (--stopondiff
== 0)
467 PrintFloatDiff(uint32 row
, int sample
, uint32 pix
, double w1
, double w2
)
471 switch (bitspersample
) {
473 printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
474 (long) row
, (long) pix
, sample
, w1
, w2
);
475 if (--stopondiff
== 0)
484 SeparateCompare(int reversed
, int sample
, uint32 row
,
485 unsigned char* cp1
, unsigned char* p2
)
487 uint32 npixels
= imagewidth
;
491 for (pixel
= 0; npixels
-- > 0; pixel
++, cp1
+= samplesperpixel
, p2
++) {
493 printf("Scanline %lu, pixel %lu, sample %ld: ",
494 (long) row
, (long) pixel
, (long) sample
);
496 printf("%02x %02x\n", *p2
, *cp1
);
498 printf("%02x %02x\n", *cp1
, *p2
);
499 if (--stopondiff
== 0)
508 checkTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
, void* p1
, void* p2
)
511 if (TIFFGetField(tif1
, tag
, p1
)) {
512 if (!TIFFGetField(tif2
, tag
, p2
)) {
513 printf("%s tag appears only in %s\n",
514 name
, TIFFFileName(tif1
));
518 } else if (TIFFGetField(tif2
, tag
, p2
)) {
519 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
525 #define CHECK(cmp, fmt) { \
526 switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \
528 case -1: return (1); \
529 printf(fmt, name, v1, v2); \
535 CheckShortTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
538 CHECK(v1
== v2
, "%s: %u %u\n");
542 CheckShort2Tag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
544 uint16 v11
, v12
, v21
, v22
;
546 if (TIFFGetField(tif1
, tag
, &v11
, &v12
)) {
547 if (!TIFFGetField(tif2
, tag
, &v21
, &v22
)) {
548 printf("%s tag appears only in %s\n",
549 name
, TIFFFileName(tif1
));
552 if (v11
== v21
&& v12
== v22
)
554 printf("%s: <%u,%u> <%u,%u>\n", name
, v11
, v12
, v21
, v22
);
555 } else if (TIFFGetField(tif2
, tag
, &v21
, &v22
))
556 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
563 CheckShortArrayTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
568 if (TIFFGetField(tif1
, tag
, &n1
, &a1
)) {
569 if (!TIFFGetField(tif2
, tag
, &n2
, &a2
)) {
570 printf("%s tag appears only in %s\n",
571 name
, TIFFFileName(tif1
));
578 if (memcmp(a1
, a2
, n1
* sizeof(uint16
)) == 0)
580 printf("%s: value mismatch, <%u:", name
, n1
);
582 for (i
= 0; i
< n1
; i
++)
583 printf("%s%u", sep
, a1
[i
]), sep
= ",";
584 printf("> and <%u: ", n2
);
586 for (i
= 0; i
< n2
; i
++)
587 printf("%s%u", sep
, a2
[i
]), sep
= ",";
590 printf("%s: %u items in %s, %u items in %s", name
,
591 n1
, TIFFFileName(tif1
),
592 n2
, TIFFFileName(tif2
)
594 } else if (TIFFGetField(tif2
, tag
, &n2
, &a2
))
595 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
602 CheckLongTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
605 CHECK(v1
== v2
, "%s: %u %u\n");
609 CheckFloatTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
612 CHECK(v1
== v2
, "%s: %g %g\n");
616 CheckStringTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
619 CHECK(strcmp(v1
, v2
) == 0, "%s: \"%s\" \"%s\"\n");
623 leof(const char* name
, uint32 row
, int s
)
626 printf("%s: EOF at scanline %lu", name
, (unsigned long)row
);
628 printf(", sample %d", s
);
632 /* vim: set ts=8 sts=8 sw=8 noet: */