3 * Copyright (c) 1988-1997 Sam Leffler
4 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 * Permission to use, copy, modify, distribute, and sell this software and
7 * its documentation for any purpose is hereby granted without fee, provided
8 * that (i) the above copyright notices and this permission notice appear in
9 * all copies of the software and related documentation, and (ii) the names of
10 * Sam Leffler and Silicon Graphics may not be used in any advertising or
11 * publicity relating to the software without the specific, prior written
12 * permission of Sam Leffler and Silicon Graphics.
14 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
19 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
20 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
22 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
26 #include "tif_config.h"
44 extern int getopt(int, char**, char*);
47 static int stopondiff
= 1;
48 static int stoponfirsttag
= 1;
49 static uint16 bitspersample
= 1;
50 static uint16 samplesperpixel
= 1;
51 static uint16 sampleformat
= SAMPLEFORMAT_UINT
;
52 static uint32 imagewidth
;
53 static uint32 imagelength
;
55 static void usage(void);
56 static int tiffcmp(TIFF
*, TIFF
*);
57 static int cmptags(TIFF
*, TIFF
*);
58 static int ContigCompare(int, uint32
, unsigned char*, unsigned char*, tsize_t
);
59 static int SeparateCompare(int, int, uint32
, unsigned char*, unsigned char*);
60 static void PrintIntDiff(uint32
, int, uint32
, uint32
, uint32
);
61 static void PrintFloatDiff(uint32
, int, uint32
, double, double);
63 static void leof(const char*, uint32
, int);
66 main(int argc
, char* argv
[])
73 while ((c
= getopt(argc
, argv
, "ltz:")) != -1)
79 stopondiff
= atoi(optarg
);
88 if (argc
- optind
< 2)
90 tif1
= TIFFOpen(argv
[optind
], "r");
93 tif2
= TIFFOpen(argv
[optind
+1], "r");
97 while (tiffcmp(tif1
, tif2
)) {
98 if (!TIFFReadDirectory(tif1
)) {
99 if (!TIFFReadDirectory(tif2
))
101 printf("No more directories for %s\n",
104 } else if (!TIFFReadDirectory(tif2
)) {
105 printf("No more directories for %s\n",
109 printf("Directory %d:\n", ++dirnum
);
118 "usage: tiffcmp [options] file1 file2",
119 "where options are:",
120 " -l list each byte of image data that differs between the files",
121 " -z # list specified number of bytes that differs between the files",
122 " -t ignore any differences in directory tags",
133 fprintf(stderr
, "%s\n\n", TIFFGetVersion());
134 for (i
= 0; stuff
[i
] != NULL
; i
++)
135 fprintf(stderr
, "%s\n", stuff
[i
]);
139 #define checkEOF(tif, row, sample) { \
140 leof(TIFFFileName(tif), row, sample); \
144 static int CheckShortTag(TIFF
*, TIFF
*, int, char*);
145 static int CheckShort2Tag(TIFF
*, TIFF
*, int, char*);
146 static int CheckShortArrayTag(TIFF
*, TIFF
*, int, char*);
147 static int CheckLongTag(TIFF
*, TIFF
*, int, char*);
148 static int CheckFloatTag(TIFF
*, TIFF
*, int, char*);
149 static int CheckStringTag(TIFF
*, TIFF
*, int, char*);
152 tiffcmp(TIFF
* tif1
, TIFF
* tif2
)
154 uint16 config1
, config2
;
158 unsigned char *buf1
, *buf2
;
160 if (!CheckShortTag(tif1
, tif2
, TIFFTAG_BITSPERSAMPLE
, "BitsPerSample"))
162 if (!CheckShortTag(tif1
, tif2
, TIFFTAG_SAMPLESPERPIXEL
, "SamplesPerPixel"))
164 if (!CheckLongTag(tif1
, tif2
, TIFFTAG_IMAGEWIDTH
, "ImageWidth"))
166 if (!cmptags(tif1
, tif2
))
168 (void) TIFFGetField(tif1
, TIFFTAG_BITSPERSAMPLE
, &bitspersample
);
169 (void) TIFFGetField(tif1
, TIFFTAG_SAMPLESPERPIXEL
, &samplesperpixel
);
170 (void) TIFFGetField(tif1
, TIFFTAG_SAMPLEFORMAT
, &sampleformat
);
171 (void) TIFFGetField(tif1
, TIFFTAG_IMAGEWIDTH
, &imagewidth
);
172 (void) TIFFGetField(tif1
, TIFFTAG_IMAGELENGTH
, &imagelength
);
173 (void) TIFFGetField(tif1
, TIFFTAG_PLANARCONFIG
, &config1
);
174 (void) TIFFGetField(tif2
, TIFFTAG_PLANARCONFIG
, &config2
);
175 buf1
= (unsigned char *)_TIFFmalloc(size1
= TIFFScanlineSize(tif1
));
176 buf2
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2
));
177 if (buf1
== NULL
|| buf2
== NULL
) {
178 fprintf(stderr
, "No space for scanline buffers\n");
181 if (config1
!= config2
&& bitspersample
!= 8 && samplesperpixel
> 1) {
183 "Can't handle different planar configuration w/ different bits/sample\n");
186 #define pack(a,b) ((a)<<8)|(b)
187 switch (pack(config1
, config2
)) {
188 case pack(PLANARCONFIG_SEPARATE
, PLANARCONFIG_CONTIG
):
189 for (row
= 0; row
< imagelength
; row
++) {
190 if (TIFFReadScanline(tif2
, buf2
, row
, 0) < 0)
191 checkEOF(tif2
, row
, -1)
192 for (s
= 0; s
< samplesperpixel
; s
++) {
193 if (TIFFReadScanline(tif1
, buf1
, row
, s
) < 0)
194 checkEOF(tif1
, row
, s
)
195 if (SeparateCompare(1, s
, row
, buf2
, buf1
) < 0)
200 case pack(PLANARCONFIG_CONTIG
, PLANARCONFIG_SEPARATE
):
201 for (row
= 0; row
< imagelength
; row
++) {
202 if (TIFFReadScanline(tif1
, buf1
, row
, 0) < 0)
203 checkEOF(tif1
, row
, -1)
204 for (s
= 0; s
< samplesperpixel
; s
++) {
205 if (TIFFReadScanline(tif2
, buf2
, row
, s
) < 0)
206 checkEOF(tif2
, row
, s
)
207 if (SeparateCompare(0, s
, row
, buf1
, buf2
) < 0)
212 case pack(PLANARCONFIG_SEPARATE
, PLANARCONFIG_SEPARATE
):
213 for (s
= 0; s
< samplesperpixel
; s
++)
214 for (row
= 0; row
< imagelength
; row
++) {
215 if (TIFFReadScanline(tif1
, buf1
, row
, s
) < 0)
216 checkEOF(tif1
, row
, s
)
217 if (TIFFReadScanline(tif2
, buf2
, row
, s
) < 0)
218 checkEOF(tif2
, row
, s
)
219 if (ContigCompare(s
, row
, buf1
, buf2
, size1
) < 0)
223 case pack(PLANARCONFIG_CONTIG
, PLANARCONFIG_CONTIG
):
224 for (row
= 0; row
< imagelength
; row
++) {
225 if (TIFFReadScanline(tif1
, buf1
, row
, 0) < 0)
226 checkEOF(tif1
, row
, -1)
227 if (TIFFReadScanline(tif2
, buf2
, row
, 0) < 0)
228 checkEOF(tif2
, row
, -1)
229 if (ContigCompare(-1, row
, buf1
, buf2
, size1
) < 0)
234 if (buf1
) _TIFFfree(buf1
);
235 if (buf2
) _TIFFfree(buf2
);
241 if (buf1
) _TIFFfree(buf1
);
242 if (buf2
) _TIFFfree(buf2
);
246 #define CmpShortField(tag, name) \
247 if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
248 #define CmpShortField2(tag, name) \
249 if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
250 #define CmpLongField(tag, name) \
251 if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
252 #define CmpFloatField(tag, name) \
253 if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
254 #define CmpStringField(tag, name) \
255 if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
256 #define CmpShortArrayField(tag, name) \
257 if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
260 cmptags(TIFF
* tif1
, TIFF
* tif2
)
262 CmpLongField(TIFFTAG_SUBFILETYPE
, "SubFileType");
263 CmpLongField(TIFFTAG_IMAGEWIDTH
, "ImageWidth");
264 CmpLongField(TIFFTAG_IMAGELENGTH
, "ImageLength");
265 CmpShortField(TIFFTAG_BITSPERSAMPLE
, "BitsPerSample");
266 CmpShortField(TIFFTAG_COMPRESSION
, "Compression");
267 CmpShortField(TIFFTAG_PREDICTOR
, "Predictor");
268 CmpShortField(TIFFTAG_PHOTOMETRIC
, "PhotometricInterpretation");
269 CmpShortField(TIFFTAG_THRESHHOLDING
, "Thresholding");
270 CmpShortField(TIFFTAG_FILLORDER
, "FillOrder");
271 CmpShortField(TIFFTAG_ORIENTATION
, "Orientation");
272 CmpShortField(TIFFTAG_SAMPLESPERPIXEL
, "SamplesPerPixel");
273 CmpShortField(TIFFTAG_MINSAMPLEVALUE
, "MinSampleValue");
274 CmpShortField(TIFFTAG_MAXSAMPLEVALUE
, "MaxSampleValue");
275 CmpShortField(TIFFTAG_SAMPLEFORMAT
, "SampleFormat");
276 CmpFloatField(TIFFTAG_XRESOLUTION
, "XResolution");
277 CmpFloatField(TIFFTAG_YRESOLUTION
, "YResolution");
278 CmpLongField(TIFFTAG_GROUP3OPTIONS
, "Group3Options");
279 CmpLongField(TIFFTAG_GROUP4OPTIONS
, "Group4Options");
280 CmpShortField(TIFFTAG_RESOLUTIONUNIT
, "ResolutionUnit");
281 CmpShortField(TIFFTAG_PLANARCONFIG
, "PlanarConfiguration");
282 CmpLongField(TIFFTAG_ROWSPERSTRIP
, "RowsPerStrip");
283 CmpFloatField(TIFFTAG_XPOSITION
, "XPosition");
284 CmpFloatField(TIFFTAG_YPOSITION
, "YPosition");
285 CmpShortField(TIFFTAG_GRAYRESPONSEUNIT
, "GrayResponseUnit");
286 CmpShortField(TIFFTAG_COLORRESPONSEUNIT
, "ColorResponseUnit");
289 CmpField(TIFFTAG_GRAYRESPONSECURVE
, graycurve
);
291 { uint16
*red
, *green
, *blue
;
292 CmpField3(TIFFTAG_COLORRESPONSECURVE
, red
, green
, blue
);
294 { uint16
*red
, *green
, *blue
;
295 CmpField3(TIFFTAG_COLORMAP
, red
, green
, blue
);
298 CmpShortField2(TIFFTAG_PAGENUMBER
, "PageNumber");
299 CmpStringField(TIFFTAG_ARTIST
, "Artist");
300 CmpStringField(TIFFTAG_IMAGEDESCRIPTION
,"ImageDescription");
301 CmpStringField(TIFFTAG_MAKE
, "Make");
302 CmpStringField(TIFFTAG_MODEL
, "Model");
303 CmpStringField(TIFFTAG_SOFTWARE
, "Software");
304 CmpStringField(TIFFTAG_DATETIME
, "DateTime");
305 CmpStringField(TIFFTAG_HOSTCOMPUTER
, "HostComputer");
306 CmpStringField(TIFFTAG_PAGENAME
, "PageName");
307 CmpStringField(TIFFTAG_DOCUMENTNAME
, "DocumentName");
308 CmpShortField(TIFFTAG_MATTEING
, "Matteing");
309 CmpShortArrayField(TIFFTAG_EXTRASAMPLES
,"ExtraSamples");
314 ContigCompare(int sample
, uint32 row
,
315 unsigned char* p1
, unsigned char* p2
, tsize_t size
)
318 int ppb
= 8 / bitspersample
;
321 if (memcmp(p1
, p2
, size
) == 0)
324 samples_to_test
= (sample
== -1) ? samplesperpixel
: 1;
326 switch (bitspersample
) {
327 case 1: case 2: case 4: case 8:
329 unsigned char *pix1
= p1
, *pix2
= p2
;
331 for (pix
= 0; pix
< imagewidth
; pix
+= ppb
) {
334 for(s
= 0; s
< samples_to_test
; s
++) {
335 if (*pix1
!= *pix2
) {
337 PrintIntDiff(row
, s
, pix
, *pix1
, *pix2
);
339 PrintIntDiff(row
, sample
, pix
, *pix1
, *pix2
);
350 uint16
*pix1
= (uint16
*)p1
, *pix2
= (uint16
*)p2
;
352 for (pix
= 0; pix
< imagewidth
; pix
++) {
355 for(s
= 0; s
< samples_to_test
; s
++) {
357 PrintIntDiff(row
, sample
, pix
, *pix1
, *pix2
);
366 if (sampleformat
== SAMPLEFORMAT_UINT
367 || sampleformat
== SAMPLEFORMAT_INT
) {
368 uint32
*pix1
= (uint32
*)p1
, *pix2
= (uint32
*)p2
;
370 for (pix
= 0; pix
< imagewidth
; pix
++) {
373 for(s
= 0; s
< samples_to_test
; s
++) {
374 if (*pix1
!= *pix2
) {
375 PrintIntDiff(row
, sample
, pix
,
383 } else if (sampleformat
== SAMPLEFORMAT_IEEEFP
) {
384 float *pix1
= (float *)p1
, *pix2
= (float *)p2
;
386 for (pix
= 0; pix
< imagewidth
; pix
++) {
389 for(s
= 0; s
< samples_to_test
; s
++) {
390 if (fabs(*pix1
- *pix2
) < 0.000000000001) {
391 PrintFloatDiff(row
, sample
, pix
,
400 fprintf(stderr
, "Sample format %d is not supported.\n",
406 fprintf(stderr
, "Bit depth %d is not supported.\n", bitspersample
);
414 PrintIntDiff(uint32 row
, int sample
, uint32 pix
, uint32 w1
, uint32 w2
)
418 switch (bitspersample
) {
423 int32 mask1
, mask2
, s
;
425 mask1
= ~((-1) << bitspersample
);
426 s
= (8 - bitspersample
);
428 for (; mask2
&& pix
< imagewidth
;
429 mask2
>>= bitspersample
, s
-= bitspersample
, pix
++) {
430 if ((w1
& mask2
) ^ (w2
& mask2
)) {
432 "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
436 (unsigned int)((w1
>> s
) & mask1
),
437 (unsigned int)((w2
>> s
) & mask1
));
438 if (--stopondiff
== 0)
445 printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
446 (unsigned long) row
, (unsigned long) pix
, sample
,
447 (unsigned int) w1
, (unsigned int) w2
);
448 if (--stopondiff
== 0)
452 printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
453 (unsigned long) row
, (unsigned long) pix
, sample
,
454 (unsigned int) w1
, (unsigned int) w2
);
455 if (--stopondiff
== 0)
459 printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
460 (unsigned long) row
, (unsigned long) pix
, sample
,
461 (unsigned int) w1
, (unsigned int) w2
);
462 if (--stopondiff
== 0)
471 PrintFloatDiff(uint32 row
, int sample
, uint32 pix
, double w1
, double w2
)
475 switch (bitspersample
) {
477 printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
478 (long) row
, (long) pix
, sample
, w1
, w2
);
479 if (--stopondiff
== 0)
488 SeparateCompare(int reversed
, int sample
, uint32 row
,
489 unsigned char* cp1
, unsigned char* p2
)
491 uint32 npixels
= imagewidth
;
495 for (pixel
= 0; npixels
-- > 0; pixel
++, cp1
+= samplesperpixel
, p2
++) {
497 printf("Scanline %lu, pixel %lu, sample %ld: ",
498 (long) row
, (long) pixel
, (long) sample
);
500 printf("%02x %02x\n", *p2
, *cp1
);
502 printf("%02x %02x\n", *cp1
, *p2
);
503 if (--stopondiff
== 0)
512 checkTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
, void* p1
, void* p2
)
515 if (TIFFGetField(tif1
, tag
, p1
)) {
516 if (!TIFFGetField(tif2
, tag
, p2
)) {
517 printf("%s tag appears only in %s\n",
518 name
, TIFFFileName(tif1
));
522 } else if (TIFFGetField(tif2
, tag
, p2
)) {
523 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
529 #define CHECK(cmp, fmt) { \
530 switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \
532 case -1: return (1); \
533 printf(fmt, name, v1, v2); \
539 CheckShortTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
542 CHECK(v1
== v2
, "%s: %u %u\n");
546 CheckShort2Tag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
548 uint16 v11
, v12
, v21
, v22
;
550 if (TIFFGetField(tif1
, tag
, &v11
, &v12
)) {
551 if (!TIFFGetField(tif2
, tag
, &v21
, &v22
)) {
552 printf("%s tag appears only in %s\n",
553 name
, TIFFFileName(tif1
));
556 if (v11
== v21
&& v12
== v22
)
558 printf("%s: <%u,%u> <%u,%u>\n", name
, v11
, v12
, v21
, v22
);
559 } else if (TIFFGetField(tif2
, tag
, &v21
, &v22
))
560 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
567 CheckShortArrayTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
572 if (TIFFGetField(tif1
, tag
, &n1
, &a1
)) {
573 if (!TIFFGetField(tif2
, tag
, &n2
, &a2
)) {
574 printf("%s tag appears only in %s\n",
575 name
, TIFFFileName(tif1
));
582 if (memcmp(a1
, a2
, n1
* sizeof(uint16
)) == 0)
584 printf("%s: value mismatch, <%u:", name
, n1
);
586 for (i
= 0; i
< n1
; i
++)
587 printf("%s%u", sep
, a1
[i
]), sep
= ",";
588 printf("> and <%u: ", n2
);
590 for (i
= 0; i
< n2
; i
++)
591 printf("%s%u", sep
, a2
[i
]), sep
= ",";
594 printf("%s: %u items in %s, %u items in %s", name
,
595 n1
, TIFFFileName(tif1
),
596 n2
, TIFFFileName(tif2
)
598 } else if (TIFFGetField(tif2
, tag
, &n2
, &a2
))
599 printf("%s tag appears only in %s\n", name
, TIFFFileName(tif2
));
606 CheckLongTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
609 CHECK(v1
== v2
, "%s: %u %u\n");
613 CheckFloatTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
616 CHECK(v1
== v2
, "%s: %g %g\n");
620 CheckStringTag(TIFF
* tif1
, TIFF
* tif2
, int tag
, char* name
)
623 CHECK(strcmp(v1
, v2
) == 0, "%s: \"%s\" \"%s\"\n");
627 leof(const char* name
, uint32 row
, int s
)
630 printf("%s: EOF at scanline %lu", name
, (unsigned long)row
);
632 printf(", sample %d", s
);
636 /* vim: set ts=8 sts=8 sw=8 noet: */