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"
45 extern int getopt(int, char**, char*);
48 static int stopondiff
= 1;
49 static int stoponfirsttag
= 1;
50 static uint16 bitspersample
= 1;
51 static uint16 samplesperpixel
= 1;
52 static uint16 sampleformat
= SAMPLEFORMAT_UINT
;
53 static uint32 imagewidth
;
54 static uint32 imagelength
;
56 static void usage(void);
57 static int tiffcmp(TIFF
*, TIFF
*);
58 static int cmptags(TIFF
*, TIFF
*);
59 static int ContigCompare(int, uint32
, unsigned char*, unsigned char*, tsize_t
);
60 static int SeparateCompare(int, int, uint32
, unsigned char*, unsigned char*);
61 static void PrintIntDiff(uint32
, int, uint32
, uint32
, uint32
);
62 static void PrintFloatDiff(uint32
, int, uint32
, double, double);
64 static void leof(const char*, uint32
, int);
67 main(int argc
, char* argv
[])
74 while ((c
= getopt(argc
, argv
, "ltz:")) != -1)
80 stopondiff
= atoi(optarg
);
89 if (argc
- optind
< 2)
91 tif1
= TIFFOpen(argv
[optind
], "r");
94 tif2
= TIFFOpen(argv
[optind
+1], "r");
98 while (tiffcmp(tif1
, tif2
)) {
99 if (!TIFFReadDirectory(tif1
)) {
100 if (!TIFFReadDirectory(tif2
))
102 printf("No more directories for %s\n",
105 } else if (!TIFFReadDirectory(tif2
)) {
106 printf("No more directories for %s\n",
110 printf("Directory %d:\n", ++dirnum
);
119 "usage: tiffcmp [options] file1 file2",
120 "where options are:",
121 " -l list each byte of image data that differs between the files",
122 " -z # list specified number of bytes that differs between the files",
123 " -t ignore any differences in directory tags",
134 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
135 for (i
= 0; stuff
[i
] != NULL
; i
++)
136 fprintf(stderr
, "%s\n", stuff
[i
]);
140 #define checkEOF(tif, row, sample) { \
141 leof(TIFFFileName(tif), row, sample); \
145 static int CheckShortTag(TIFF
*, TIFF
*, int, char*);
146 static int CheckShort2Tag(TIFF
*, TIFF
*, int, char*);
147 static int CheckShortArrayTag(TIFF
*, TIFF
*, int, char*);
148 static int CheckLongTag(TIFF
*, TIFF
*, int, char*);
149 static int CheckFloatTag(TIFF
*, TIFF
*, int, char*);
150 static int CheckStringTag(TIFF
*, TIFF
*, int, char*);
153 tiffcmp(TIFF
* tif1
, TIFF
* tif2
)
155 uint16 config1
, config2
;
159 unsigned char *buf1
, *buf2
;
161 if (!CheckShortTag(tif1
, tif2
, TIFFTAG_BITSPERSAMPLE
, "BitsPerSample"))
163 if (!CheckShortTag(tif1
, tif2
, TIFFTAG_SAMPLESPERPIXEL
, "SamplesPerPixel"))
165 if (!CheckLongTag(tif1
, tif2
, TIFFTAG_IMAGEWIDTH
, "ImageWidth"))
167 if (!cmptags(tif1
, tif2
))
169 (void) TIFFGetField(tif1
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
);
170 (void) TIFFGetField(tif1
, TIFFTAG_SAMPLESPERPIXEL
, &samplesperpixel
);
171 (void) TIFFGetField(tif1
, TIFFTAG_SAMPLEFORMAT
, &sampleformat
);
172 (void) TIFFGetField(tif1
, TIFFTAG_IMAGEWIDTH
, &imagewidth
);
173 (void) TIFFGetField(tif1
, TIFFTAG_IMAGELENGTH
, &imagelength
);
174 (void) TIFFGetField(tif1
, TIFFTAG_PLANARCONFIG
, &config1
);
175 (void) TIFFGetField(tif2
, TIFFTAG_PLANARCONFIG
, &config2
);
176 buf1
= (unsigned char *)_TIFFmalloc(size1
= TIFFScanlineSize(tif1
));
177 buf2
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2
));
178 if (buf1
== NULL
|| buf2
== NULL
) {
179 fprintf(stderr
, "No space for scanline buffers\n");
182 if (config1
!= config2
&& bitspersample
!= 8 && samplesperpixel
> 1) {
184 "Can't handle different planar configuration w/ different bits/sample\n");
187 #define pack(a,b) ((a)<<8)|(b)
188 switch (pack(config1
, config2
)) {
189 case pack(PLANARCONFIG_SEPARATE
, PLANARCONFIG_CONTIG
):
190 for (row
= 0; row
< imagelength
; row
++) {
191 if (TIFFReadScanline(tif2
, buf2
, row
, 0) < 0)
192 checkEOF(tif2
, row
, -1)
193 for (s
= 0; s
< samplesperpixel
; s
++) {
194 if (TIFFReadScanline(tif1
, buf1
, row
, s
) < 0)
195 checkEOF(tif1
, row
, s
)
196 if (SeparateCompare(1, s
, row
, buf2
, buf1
) < 0)
201 case pack(PLANARCONFIG_CONTIG
, PLANARCONFIG_SEPARATE
):
202 for (row
= 0; row
< imagelength
; row
++) {
203 if (TIFFReadScanline(tif1
, buf1
, row
, 0) < 0)
204 checkEOF(tif1
, row
, -1)
205 for (s
= 0; s
< samplesperpixel
; s
++) {
206 if (TIFFReadScanline(tif2
, buf2
, row
, s
) < 0)
207 checkEOF(tif2
, row
, s
)
208 if (SeparateCompare(0, s
, row
, buf1
, buf2
) < 0)
213 case pack(PLANARCONFIG_SEPARATE
, PLANARCONFIG_SEPARATE
):
214 for (s
= 0; s
< samplesperpixel
; s
++)
215 for (row
= 0; row
< imagelength
; row
++) {
216 if (TIFFReadScanline(tif1
, buf1
, row
, s
) < 0)
217 checkEOF(tif1
, row
, s
)
218 if (TIFFReadScanline(tif2
, buf2
, row
, s
) < 0)
219 checkEOF(tif2
, row
, s
)
220 if (ContigCompare(s
, row
, buf1
, buf2
, size1
) < 0)
224 case pack(PLANARCONFIG_CONTIG
, PLANARCONFIG_CONTIG
):
225 for (row
= 0; row
< imagelength
; row
++) {
226 if (TIFFReadScanline(tif1
, buf1
, row
, 0) < 0)
227 checkEOF(tif1
, row
, -1)
228 if (TIFFReadScanline(tif2
, buf2
, row
, 0) < 0)
229 checkEOF(tif2
, row
, -1)
230 if (ContigCompare(-1, row
, buf1
, buf2
, size1
) < 0)
235 if (buf1
) _TIFFfree(buf1
);
236 if (buf2
) _TIFFfree(buf2
);
242 if (buf1
) _TIFFfree(buf1
);
243 if (buf2
) _TIFFfree(buf2
);
247 #define CmpShortField(tag, name) \
248 if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
249 #define CmpShortField2(tag, name) \
250 if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
251 #define CmpLongField(tag, name) \
252 if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
253 #define CmpFloatField(tag, name) \
254 if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
255 #define CmpStringField(tag, name) \
256 if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
257 #define CmpShortArrayField(tag, name) \
258 if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
261 cmptags(TIFF
* tif1
, TIFF
* tif2
)
263 CmpLongField(TIFFTAG_SUBFILETYPE
, "SubFileType");
264 CmpLongField(TIFFTAG_IMAGEWIDTH
, "ImageWidth");
265 CmpLongField(TIFFTAG_IMAGELENGTH
, "ImageLength");
266 CmpShortField(TIFFTAG_BITSPERSAMPLE
, "BitsPerSample");
267 CmpShortField(TIFFTAG_COMPRESSION
, "Compression");
268 CmpShortField(TIFFTAG_PREDICTOR
, "Predictor");
269 CmpShortField(TIFFTAG_PHOTOMETRIC
, "PhotometricInterpretation");
270 CmpShortField(TIFFTAG_THRESHHOLDING
, "Thresholding");
271 CmpShortField(TIFFTAG_FILLORDER
, "FillOrder");
272 CmpShortField(TIFFTAG_ORIENTATION
, "Orientation");
273 CmpShortField(TIFFTAG_SAMPLESPERPIXEL
, "SamplesPerPixel");
274 CmpShortField(TIFFTAG_MINSAMPLEVALUE
, "MinSampleValue");
275 CmpShortField(TIFFTAG_MAXSAMPLEVALUE
, "MaxSampleValue");
276 CmpShortField(TIFFTAG_SAMPLEFORMAT
, "SampleFormat");
277 CmpFloatField(TIFFTAG_XRESOLUTION
, "XResolution");
278 CmpFloatField(TIFFTAG_YRESOLUTION
, "YResolution");
279 CmpLongField(TIFFTAG_GROUP3OPTIONS
, "Group3Options");
280 CmpLongField(TIFFTAG_GROUP4OPTIONS
, "Group4Options");
281 CmpShortField(TIFFTAG_RESOLUTIONUNIT
, "ResolutionUnit");
282 CmpShortField(TIFFTAG_PLANARCONFIG
, "PlanarConfiguration");
283 CmpLongField(TIFFTAG_ROWSPERSTRIP
, "RowsPerStrip");
284 CmpFloatField(TIFFTAG_XPOSITION
, "XPosition");
285 CmpFloatField(TIFFTAG_YPOSITION
, "YPosition");
286 CmpShortField(TIFFTAG_GRAYRESPONSEUNIT
, "GrayResponseUnit");
287 CmpShortField(TIFFTAG_COLORRESPONSEUNIT
, "ColorResponseUnit");
290 CmpField(TIFFTAG_GRAYRESPONSECURVE
, graycurve
);
292 { uint16
*red
, *green
, *blue
;
293 CmpField3(TIFFTAG_COLORRESPONSECURVE
, red
, green
, blue
);
295 { uint16
*red
, *green
, *blue
;
296 CmpField3(TIFFTAG_COLORMAP
, red
, green
, blue
);
299 CmpShortField2(TIFFTAG_PAGENUMBER
, "PageNumber");
300 CmpStringField(TIFFTAG_ARTIST
, "Artist");
301 CmpStringField(TIFFTAG_IMAGEDESCRIPTION
,"ImageDescription");
302 CmpStringField(TIFFTAG_MAKE
, "Make");
303 CmpStringField(TIFFTAG_MODEL
, "Model");
304 CmpStringField(TIFFTAG_SOFTWARE
, "Software");
305 CmpStringField(TIFFTAG_DATETIME
, "DateTime");
306 CmpStringField(TIFFTAG_HOSTCOMPUTER
, "HostComputer");
307 CmpStringField(TIFFTAG_PAGENAME
, "PageName");
308 CmpStringField(TIFFTAG_DOCUMENTNAME
, "DocumentName");
309 CmpShortField(TIFFTAG_MATTEING
, "Matteing");
310 CmpShortArrayField(TIFFTAG_EXTRASAMPLES
,"ExtraSamples");
315 ContigCompare(int sample
, uint32 row
,
316 unsigned char* p1
, unsigned char* p2
, tsize_t size
)
319 int ppb
= 8 / bitspersample
;
322 if (memcmp(p1
, p2
, size
) == 0)
325 samples_to_test
= (sample
== -1) ? samplesperpixel
: 1;
327 switch (bitspersample
) {
328 case 1: case 2: case 4: case 8:
330 unsigned char *pix1
= p1
, *pix2
= p2
;
332 for (pix
= 0; pix
< imagewidth
; pix
+= ppb
) {
335 for(s
= 0; s
< samples_to_test
; s
++) {
336 if (*pix1
!= *pix2
) {
338 PrintIntDiff(row
, s
, pix
, *pix1
, *pix2
);
340 PrintIntDiff(row
, sample
, pix
, *pix1
, *pix2
);
351 uint16
*pix1
= (uint16
*)p1
, *pix2
= (uint16
*)p2
;
353 for (pix
= 0; pix
< imagewidth
; pix
++) {
356 for(s
= 0; s
< samples_to_test
; s
++) {
358 PrintIntDiff(row
, sample
, pix
, *pix1
, *pix2
);
367 if (sampleformat
== SAMPLEFORMAT_UINT
368 || sampleformat
== SAMPLEFORMAT_INT
) {
369 uint32
*pix1
= (uint32
*)p1
, *pix2
= (uint32
*)p2
;
371 for (pix
= 0; pix
< imagewidth
; pix
++) {
374 for(s
= 0; s
< samples_to_test
; s
++) {
375 if (*pix1
!= *pix2
) {
376 PrintIntDiff(row
, sample
, pix
,
384 } else if (sampleformat
== SAMPLEFORMAT_IEEEFP
) {
385 float *pix1
= (float *)p1
, *pix2
= (float *)p2
;
387 for (pix
= 0; pix
< imagewidth
; pix
++) {
390 for(s
= 0; s
< samples_to_test
; s
++) {
391 if (fabs(*pix1
- *pix2
) < 0.000000000001) {
392 PrintFloatDiff(row
, sample
, pix
,
401 fprintf(stderr
, "Sample format %d is not supported.\n",
407 fprintf(stderr
, "Bit depth %d is not supported.\n", bitspersample
);
415 PrintIntDiff(uint32 row
, int sample
, uint32 pix
, uint32 w1
, uint32 w2
)
419 switch (bitspersample
) {
424 int32 mask1
, mask2
, s
;
426 mask1
= ~((-1) << bitspersample
);
427 s
= (8 - bitspersample
);
429 for (; mask2
&& pix
< imagewidth
;
430 mask2
>>= bitspersample
, s
-= bitspersample
, pix
++) {
431 if ((w1
& mask2
) ^ (w2
& mask2
)) {
433 "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
437 (unsigned int)((w1
>> s
) & mask1
),
438 (unsigned int)((w2
>> s
) & mask1
));
439 if (--stopondiff
== 0)
446 printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
447 (unsigned long) row
, (unsigned long) pix
, sample
,
448 (unsigned int) w1
, (unsigned int) w2
);
449 if (--stopondiff
== 0)
453 printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
454 (unsigned long) row
, (unsigned long) pix
, sample
,
455 (unsigned int) w1
, (unsigned int) w2
);
456 if (--stopondiff
== 0)
460 printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
461 (unsigned long) row
, (unsigned long) pix
, sample
,
462 (unsigned int) w1
, (unsigned int) w2
);
463 if (--stopondiff
== 0)
472 PrintFloatDiff(uint32 row
, int sample
, uint32 pix
, double w1
, double w2
)
476 switch (bitspersample
) {
478 printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
479 (long) row
, (long) pix
, sample
, w1
, w2
);
480 if (--stopondiff
== 0)
489 SeparateCompare(int reversed
, int sample
, uint32 row
,
490 unsigned char* cp1
, unsigned char* p2
)
492 uint32 npixels
= imagewidth
;
496 for (pixel
= 0; npixels
-- > 0; pixel
++, cp1
+= samplesperpixel
, p2
++) {
498 printf("Scanline %lu, pixel %lu, sample %ld: ",
499 (long) row
, (long) pixel
, (long) sample
);
501 printf("%02x %02x\n", *p2
, *cp1
);
503 printf("%02x %02x\n", *cp1
, *p2
);
504 if (--stopondiff
== 0)
513 checkTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
, void* p1
, void* p2
)
516 if (TIFFGetField(tif1
, tag
, p1
)) {
517 if (!TIFFGetField(tif2
, tag
, p2
)) {
518 printf("%s tag appears only in %s\n",
519 name
, TIFFFileName(tif1
));
523 } else if (TIFFGetField(tif2
, tag
, p2
)) {
524 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
530 #define CHECK(cmp, fmt) { \
531 switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \
533 case -1: return (1); \
534 printf(fmt, name, v1, v2); \
540 CheckShortTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
543 CHECK(v1
== v2
, "%s: %u %u\n");
547 CheckShort2Tag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
549 uint16 v11
, v12
, v21
, v22
;
551 if (TIFFGetField(tif1
, tag
, &v11
, &v12
)) {
552 if (!TIFFGetField(tif2
, tag
, &v21
, &v22
)) {
553 printf("%s tag appears only in %s\n",
554 name
, TIFFFileName(tif1
));
557 if (v11
== v21
&& v12
== v22
)
559 printf("%s: <%u,%u> <%u,%u>\n", name
, v11
, v12
, v21
, v22
);
560 } else if (TIFFGetField(tif2
, tag
, &v21
, &v22
))
561 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
568 CheckShortArrayTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
573 if (TIFFGetField(tif1
, tag
, &n1
, &a1
)) {
574 if (!TIFFGetField(tif2
, tag
, &n2
, &a2
)) {
575 printf("%s tag appears only in %s\n",
576 name
, TIFFFileName(tif1
));
583 if (memcmp(a1
, a2
, n1
* sizeof(uint16
)) == 0)
585 printf("%s: value mismatch, <%u:", name
, n1
);
587 for (i
= 0; i
< n1
; i
++)
588 printf("%s%u", sep
, a1
[i
]), sep
= ",";
589 printf("> and <%u: ", n2
);
591 for (i
= 0; i
< n2
; i
++)
592 printf("%s%u", sep
, a2
[i
]), sep
= ",";
595 printf("%s: %u items in %s, %u items in %s", name
,
596 n1
, TIFFFileName(tif1
),
597 n2
, TIFFFileName(tif2
)
599 } else if (TIFFGetField(tif2
, tag
, &n2
, &a2
))
600 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
607 CheckLongTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
610 CHECK(v1
== v2
, "%s: %u %u\n");
614 CheckFloatTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
617 CHECK(v1
== v2
, "%s: %g %g\n");
621 CheckStringTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
624 CHECK(strcmp(v1
, v2
) == 0, "%s: \"%s\" \"%s\"\n");
628 leof(const char* name
, uint32 row
, int s
)
631 printf("%s: EOF at scanline %lu", name
, (unsigned long)row
);
633 printf(", sample %d", s
);
637 /* vim: set ts=8 sts=8 sw=8 noet: */