1
/* $Id: tiffcmp.c,v 1.13.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
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"
41
extern int getopt(int, char**, char*);
44
static int stopondiff = 1;
45
static int stoponfirsttag = 1;
46
static uint16 bitspersample = 1;
47
static uint16 samplesperpixel = 1;
48
static uint16 sampleformat = SAMPLEFORMAT_UINT;
49
static uint32 imagewidth;
50
static uint32 imagelength;
52
static void usage(void);
53
static int tiffcmp(TIFF*, TIFF*);
54
static int cmptags(TIFF*, TIFF*);
55
static int ContigCompare(int, uint32, unsigned char*, unsigned char*, int);
56
static int SeparateCompare(int, int, uint32, unsigned char*, unsigned char*);
57
static void PrintIntDiff(uint32, int, uint32, uint32, uint32);
58
static void PrintFloatDiff(uint32, int, uint32, double, double);
60
static void leof(const char*, uint32, int);
63
main(int argc, char* argv[])
70
while ((c = getopt(argc, argv, "ltz:")) != -1)
76
stopondiff = atoi(optarg);
85
if (argc - optind < 2)
87
tif1 = TIFFOpen(argv[optind], "r");
90
tif2 = TIFFOpen(argv[optind+1], "r");
94
while (tiffcmp(tif1, tif2)) {
95
if (!TIFFReadDirectory(tif1)) {
96
if (!TIFFReadDirectory(tif2))
98
printf("No more directories for %s\n",
101
} else if (!TIFFReadDirectory(tif2)) {
102
printf("No more directories for %s\n",
106
printf("Directory %d:\n", ++dirnum);
115
"usage: tiffcmp [options] file1 file2",
116
"where options are:",
117
" -l list each byte of image data that differs between the files",
118
" -z # list specified number of bytes that differs between the files",
119
" -t ignore any differences in directory tags",
130
fprintf(stderr, "%s\n\n", TIFFGetVersion());
131
for (i = 0; stuff[i] != NULL; i++)
132
fprintf(stderr, "%s\n", stuff[i]);
136
#define checkEOF(tif, row, sample) { \
137
leof(TIFFFileName(tif), row, sample); \
141
static int CheckShortTag(TIFF*, TIFF*, int, char*);
142
static int CheckShort2Tag(TIFF*, TIFF*, int, char*);
143
static int CheckShortArrayTag(TIFF*, TIFF*, int, char*);
144
static int CheckLongTag(TIFF*, TIFF*, int, char*);
145
static int CheckFloatTag(TIFF*, TIFF*, int, char*);
146
static int CheckStringTag(TIFF*, TIFF*, int, char*);
149
tiffcmp(TIFF* tif1, TIFF* tif2)
151
uint16 config1, config2;
155
unsigned char *buf1, *buf2;
157
if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample"))
159
if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"))
161
if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth"))
163
if (!cmptags(tif1, tif2))
165
(void) TIFFGetField(tif1, TIFFTAG_BITSPERSAMPLE, &bitspersample);
166
(void) TIFFGetField(tif1, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
167
(void) TIFFGetField(tif1, TIFFTAG_SAMPLEFORMAT, &sampleformat);
168
(void) TIFFGetField(tif1, TIFFTAG_IMAGEWIDTH, &imagewidth);
169
(void) TIFFGetField(tif1, TIFFTAG_IMAGELENGTH, &imagelength);
170
(void) TIFFGetField(tif1, TIFFTAG_PLANARCONFIG, &config1);
171
(void) TIFFGetField(tif2, TIFFTAG_PLANARCONFIG, &config2);
172
buf1 = (unsigned char *)_TIFFmalloc(size1 = TIFFScanlineSize(tif1));
173
buf2 = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2));
174
if (buf1 == NULL || buf2 == NULL) {
175
fprintf(stderr, "No space for scanline buffers\n");
178
if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) {
180
"Can't handle different planar configuration w/ different bits/sample\n");
183
#define pack(a,b) ((a)<<8)|(b)
184
switch (pack(config1, config2)) {
185
case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG):
186
for (row = 0; row < imagelength; row++) {
187
if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
188
checkEOF(tif2, row, -1)
189
for (s = 0; s < samplesperpixel; s++) {
190
if (TIFFReadScanline(tif1, buf1, row, s) < 0)
191
checkEOF(tif1, row, s)
192
if (SeparateCompare(1, s, row, buf2, buf1) < 0)
197
case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE):
198
for (row = 0; row < imagelength; row++) {
199
if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
200
checkEOF(tif1, row, -1)
201
for (s = 0; s < samplesperpixel; s++) {
202
if (TIFFReadScanline(tif2, buf2, row, s) < 0)
203
checkEOF(tif2, row, s)
204
if (SeparateCompare(0, s, row, buf1, buf2) < 0)
209
case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE):
210
for (s = 0; s < samplesperpixel; s++)
211
for (row = 0; row < imagelength; row++) {
212
if (TIFFReadScanline(tif1, buf1, row, s) < 0)
213
checkEOF(tif1, row, s)
214
if (TIFFReadScanline(tif2, buf2, row, s) < 0)
215
checkEOF(tif2, row, s)
216
if (ContigCompare(s, row, buf1, buf2, size1) < 0)
220
case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG):
221
for (row = 0; row < imagelength; row++) {
222
if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
223
checkEOF(tif1, row, -1)
224
if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
225
checkEOF(tif2, row, -1)
226
if (ContigCompare(-1, row, buf1, buf2, size1) < 0)
231
if (buf1) _TIFFfree(buf1);
232
if (buf2) _TIFFfree(buf2);
238
if (buf1) _TIFFfree(buf1);
239
if (buf2) _TIFFfree(buf2);
243
#define CmpShortField(tag, name) \
244
if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
245
#define CmpShortField2(tag, name) \
246
if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
247
#define CmpLongField(tag, name) \
248
if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
249
#define CmpFloatField(tag, name) \
250
if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
251
#define CmpStringField(tag, name) \
252
if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
253
#define CmpShortArrayField(tag, name) \
254
if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
257
cmptags(TIFF* tif1, TIFF* tif2)
259
CmpLongField(TIFFTAG_SUBFILETYPE, "SubFileType");
260
CmpLongField(TIFFTAG_IMAGEWIDTH, "ImageWidth");
261
CmpLongField(TIFFTAG_IMAGELENGTH, "ImageLength");
262
CmpShortField(TIFFTAG_BITSPERSAMPLE, "BitsPerSample");
263
CmpShortField(TIFFTAG_COMPRESSION, "Compression");
264
CmpShortField(TIFFTAG_PREDICTOR, "Predictor");
265
CmpShortField(TIFFTAG_PHOTOMETRIC, "PhotometricInterpretation");
266
CmpShortField(TIFFTAG_THRESHHOLDING, "Thresholding");
267
CmpShortField(TIFFTAG_FILLORDER, "FillOrder");
268
CmpShortField(TIFFTAG_ORIENTATION, "Orientation");
269
CmpShortField(TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel");
270
CmpShortField(TIFFTAG_MINSAMPLEVALUE, "MinSampleValue");
271
CmpShortField(TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue");
272
CmpShortField(TIFFTAG_SAMPLEFORMAT, "SampleFormat");
273
CmpFloatField(TIFFTAG_XRESOLUTION, "XResolution");
274
CmpFloatField(TIFFTAG_YRESOLUTION, "YResolution");
275
CmpLongField(TIFFTAG_GROUP3OPTIONS, "Group3Options");
276
CmpLongField(TIFFTAG_GROUP4OPTIONS, "Group4Options");
277
CmpShortField(TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit");
278
CmpShortField(TIFFTAG_PLANARCONFIG, "PlanarConfiguration");
279
CmpLongField(TIFFTAG_ROWSPERSTRIP, "RowsPerStrip");
280
CmpFloatField(TIFFTAG_XPOSITION, "XPosition");
281
CmpFloatField(TIFFTAG_YPOSITION, "YPosition");
282
CmpShortField(TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit");
283
CmpShortField(TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit");
286
CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve);
288
{ uint16 *red, *green, *blue;
289
CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue);
291
{ uint16 *red, *green, *blue;
292
CmpField3(TIFFTAG_COLORMAP, red, green, blue);
295
CmpShortField2(TIFFTAG_PAGENUMBER, "PageNumber");
296
CmpStringField(TIFFTAG_ARTIST, "Artist");
297
CmpStringField(TIFFTAG_IMAGEDESCRIPTION,"ImageDescription");
298
CmpStringField(TIFFTAG_MAKE, "Make");
299
CmpStringField(TIFFTAG_MODEL, "Model");
300
CmpStringField(TIFFTAG_SOFTWARE, "Software");
301
CmpStringField(TIFFTAG_DATETIME, "DateTime");
302
CmpStringField(TIFFTAG_HOSTCOMPUTER, "HostComputer");
303
CmpStringField(TIFFTAG_PAGENAME, "PageName");
304
CmpStringField(TIFFTAG_DOCUMENTNAME, "DocumentName");
305
CmpShortField(TIFFTAG_MATTEING, "Matteing");
306
CmpShortArrayField(TIFFTAG_EXTRASAMPLES,"ExtraSamples");
311
ContigCompare(int sample, uint32 row,
312
unsigned char* p1, unsigned char* p2, int size)
315
int ppb = 8 / bitspersample;
318
if (memcmp(p1, p2, size) == 0)
321
samples_to_test = (sample == -1) ? samplesperpixel : 1;
323
switch (bitspersample) {
324
case 1: case 2: case 4: case 8:
326
unsigned char *pix1 = p1, *pix2 = p2;
328
for (pix = 0; pix < imagewidth; pix += ppb) {
331
for(s = 0; s < samples_to_test; s++) {
332
if (*pix1 != *pix2) {
334
PrintIntDiff(row, s, pix, *pix1, *pix2);
336
PrintIntDiff(row, sample, pix, *pix1, *pix2);
347
uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2;
349
for (pix = 0; pix < imagewidth; pix++) {
352
for(s = 0; s < samples_to_test; s++) {
354
PrintIntDiff(row, sample, pix, *pix1, *pix2);
363
if (sampleformat == SAMPLEFORMAT_UINT
364
|| sampleformat == SAMPLEFORMAT_INT) {
365
uint32 *pix1 = (uint32 *)p1, *pix2 = (uint32 *)p2;
367
for (pix = 0; pix < imagewidth; pix++) {
370
for(s = 0; s < samples_to_test; s++) {
371
if (*pix1 != *pix2) {
372
PrintIntDiff(row, sample, pix,
380
} else if (sampleformat == SAMPLEFORMAT_IEEEFP) {
381
float *pix1 = (float *)p1, *pix2 = (float *)p2;
383
for (pix = 0; pix < imagewidth; pix++) {
386
for(s = 0; s < samples_to_test; s++) {
387
if (fabs(*pix1 - *pix2) < 0.000000000001) {
388
PrintFloatDiff(row, sample, pix,
397
fprintf(stderr, "Sample format %d is not supported.\n",
403
fprintf(stderr, "Bit depth %d is not supported.\n", bitspersample);
411
PrintIntDiff(uint32 row, int sample, uint32 pix, uint32 w1, uint32 w2)
415
switch (bitspersample) {
420
int32 mask1, mask2, s;
422
mask1 = ~((-1) << bitspersample);
423
s = (8 - bitspersample);
425
for (; mask2 && pix < imagewidth;
426
mask2 >>= bitspersample, s -= bitspersample, pix++) {
427
if ((w1 & mask2) ^ (w2 & mask2)) {
429
"Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
433
(unsigned int)((w1 >> s) & mask1),
434
(unsigned int)((w2 >> s) & mask1));
435
if (--stopondiff == 0)
442
printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
443
(unsigned long) row, (unsigned long) pix, sample,
444
(unsigned int) w1, (unsigned int) w2);
445
if (--stopondiff == 0)
449
printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
450
(unsigned long) row, (unsigned long) pix, sample,
451
(unsigned int) w1, (unsigned int) w2);
452
if (--stopondiff == 0)
456
printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
457
(unsigned long) row, (unsigned long) pix, sample,
458
(unsigned int) w1, (unsigned int) w2);
459
if (--stopondiff == 0)
468
PrintFloatDiff(uint32 row, int sample, uint32 pix, double w1, double w2)
472
switch (bitspersample) {
474
printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
475
(long) row, (long) pix, sample, w1, w2);
476
if (--stopondiff == 0)
485
SeparateCompare(int reversed, int sample, uint32 row,
486
unsigned char* cp1, unsigned char* p2)
488
uint32 npixels = imagewidth;
492
for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++) {
494
printf("Scanline %lu, pixel %lu, sample %ld: ",
495
(long) row, (long) pixel, (long) sample);
497
printf("%02x %02x\n", *p2, *cp1);
499
printf("%02x %02x\n", *cp1, *p2);
500
if (--stopondiff == 0)
509
checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2)
512
if (TIFFGetField(tif1, tag, p1)) {
513
if (!TIFFGetField(tif2, tag, p2)) {
514
printf("%s tag appears only in %s\n",
515
name, TIFFFileName(tif1));
519
} else if (TIFFGetField(tif2, tag, p2)) {
520
printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
526
#define CHECK(cmp, fmt) { \
527
switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \
529
case -1: return (1); \
530
printf(fmt, name, v1, v2); \
536
CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
539
CHECK(v1 == v2, "%s: %u %u\n");
543
CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name)
545
uint16 v11, v12, v21, v22;
547
if (TIFFGetField(tif1, tag, &v11, &v12)) {
548
if (!TIFFGetField(tif2, tag, &v21, &v22)) {
549
printf("%s tag appears only in %s\n",
550
name, TIFFFileName(tif1));
553
if (v11 == v21 && v12 == v22)
555
printf("%s: <%u,%u> <%u,%u>\n", name, v11, v12, v21, v22);
556
} else if (TIFFGetField(tif2, tag, &v21, &v22))
557
printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
564
CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
569
if (TIFFGetField(tif1, tag, &n1, &a1)) {
570
if (!TIFFGetField(tif2, tag, &n2, &a2)) {
571
printf("%s tag appears only in %s\n",
572
name, TIFFFileName(tif1));
579
if (memcmp(a1, a2, n1 * sizeof(uint16)) == 0)
581
printf("%s: value mismatch, <%u:", name, n1);
583
for (i = 0; i < n1; i++)
584
printf("%s%u", sep, a1[i]), sep = ",";
585
printf("> and <%u: ", n2);
587
for (i = 0; i < n2; i++)
588
printf("%s%u", sep, a2[i]), sep = ",";
591
printf("%s: %u items in %s, %u items in %s", name,
592
n1, TIFFFileName(tif1),
593
n2, TIFFFileName(tif2)
595
} else if (TIFFGetField(tif2, tag, &n2, &a2))
596
printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
603
CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
606
CHECK(v1 == v2, "%s: %u %u\n");
610
CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
613
CHECK(v1 == v2, "%s: %g %g\n");
617
CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
620
CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n");
624
leof(const char* name, uint32 row, int s)
627
printf("%s: EOF at scanline %lu", name, (unsigned long)row);
629
printf(", sample %d", s);
633
/* vim: set ts=8 sts=8 sw=8 noet: */