]>
Commit | Line | Data |
---|---|---|
1 | ||
2 | /* | |
3 | * Copyright (c) 1988-1997 Sam Leffler | |
4 | * Copyright (c) 1991-1997 Silicon Graphics, Inc. | |
5 | * | |
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. | |
13 | * | |
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. | |
17 | * | |
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 | |
23 | * OF THIS SOFTWARE. | |
24 | */ | |
25 | ||
26 | #include "tif_config.h" | |
27 | ||
28 | #include <stdio.h> | |
29 | #include <stdlib.h> | |
30 | #include <string.h> | |
31 | #include <math.h> | |
32 | ||
33 | #ifdef HAVE_UNISTD_H | |
34 | # include <unistd.h> | |
35 | #endif | |
36 | ||
37 | #ifdef NEED_LIBPORT | |
38 | # include "libport.h" | |
39 | #endif | |
40 | ||
41 | #include "tiffio.h" | |
42 | ||
43 | #ifndef HAVE_GETOPT | |
44 | extern int getopt(int, char**, char*); | |
45 | #endif | |
46 | ||
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; | |
54 | ||
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); | |
62 | ||
63 | static void leof(const char*, uint32, int); | |
64 | ||
65 | int | |
66 | main(int argc, char* argv[]) | |
67 | { | |
68 | TIFF *tif1, *tif2; | |
69 | int c, dirnum; | |
70 | extern int optind; | |
71 | extern char* optarg; | |
72 | ||
73 | while ((c = getopt(argc, argv, "ltz:")) != -1) | |
74 | switch (c) { | |
75 | case 'l': | |
76 | stopondiff = 0; | |
77 | break; | |
78 | case 'z': | |
79 | stopondiff = atoi(optarg); | |
80 | break; | |
81 | case 't': | |
82 | stoponfirsttag = 0; | |
83 | break; | |
84 | case '?': | |
85 | usage(); | |
86 | /*NOTREACHED*/ | |
87 | } | |
88 | if (argc - optind < 2) | |
89 | usage(); | |
90 | tif1 = TIFFOpen(argv[optind], "r"); | |
91 | if (tif1 == NULL) | |
92 | return (-1); | |
93 | tif2 = TIFFOpen(argv[optind+1], "r"); | |
94 | if (tif2 == NULL) | |
95 | return (-2); | |
96 | dirnum = 0; | |
97 | while (tiffcmp(tif1, tif2)) { | |
98 | if (!TIFFReadDirectory(tif1)) { | |
99 | if (!TIFFReadDirectory(tif2)) | |
100 | break; | |
101 | printf("No more directories for %s\n", | |
102 | TIFFFileName(tif1)); | |
103 | return (1); | |
104 | } else if (!TIFFReadDirectory(tif2)) { | |
105 | printf("No more directories for %s\n", | |
106 | TIFFFileName(tif2)); | |
107 | return (1); | |
108 | } | |
109 | printf("Directory %d:\n", ++dirnum); | |
110 | } | |
111 | ||
112 | TIFFClose(tif1); | |
113 | TIFFClose(tif2); | |
114 | return (0); | |
115 | } | |
116 | ||
117 | char* stuff[] = { | |
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", | |
123 | NULL | |
124 | }; | |
125 | ||
126 | static void | |
127 | usage(void) | |
128 | { | |
129 | char buf[BUFSIZ]; | |
130 | int i; | |
131 | ||
132 | setbuf(stderr, buf); | |
133 | fprintf(stderr, "%s\n\n", TIFFGetVersion()); | |
134 | for (i = 0; stuff[i] != NULL; i++) | |
135 | fprintf(stderr, "%s\n", stuff[i]); | |
136 | exit(-1); | |
137 | } | |
138 | ||
139 | #define checkEOF(tif, row, sample) { \ | |
140 | leof(TIFFFileName(tif), row, sample); \ | |
141 | goto bad; \ | |
142 | } | |
143 | ||
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*); | |
150 | ||
151 | static int | |
152 | tiffcmp(TIFF* tif1, TIFF* tif2) | |
153 | { | |
154 | uint16 config1, config2; | |
155 | tsize_t size1; | |
156 | uint32 row; | |
157 | tsample_t s; | |
158 | unsigned char *buf1, *buf2; | |
159 | ||
160 | if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample")) | |
161 | return (0); | |
162 | if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel")) | |
163 | return (0); | |
164 | if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth")) | |
165 | return (0); | |
166 | if (!cmptags(tif1, tif2)) | |
167 | return (1); | |
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"); | |
179 | exit(-1); | |
180 | } | |
181 | if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) { | |
182 | fprintf(stderr, | |
183 | "Can't handle different planar configuration w/ different bits/sample\n"); | |
184 | goto bad; | |
185 | } | |
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) | |
196 | goto bad1; | |
197 | } | |
198 | } | |
199 | break; | |
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) | |
208 | goto bad1; | |
209 | } | |
210 | } | |
211 | break; | |
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) | |
220 | goto bad1; | |
221 | } | |
222 | break; | |
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) | |
230 | goto bad1; | |
231 | } | |
232 | break; | |
233 | } | |
234 | if (buf1) _TIFFfree(buf1); | |
235 | if (buf2) _TIFFfree(buf2); | |
236 | return (1); | |
237 | bad: | |
238 | if (stopondiff) | |
239 | exit(1); | |
240 | bad1: | |
241 | if (buf1) _TIFFfree(buf1); | |
242 | if (buf2) _TIFFfree(buf2); | |
243 | return (0); | |
244 | } | |
245 | ||
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) | |
258 | ||
259 | static int | |
260 | cmptags(TIFF* tif1, TIFF* tif2) | |
261 | { | |
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"); | |
287 | #ifdef notdef | |
288 | { uint16 *graycurve; | |
289 | CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve); | |
290 | } | |
291 | { uint16 *red, *green, *blue; | |
292 | CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue); | |
293 | } | |
294 | { uint16 *red, *green, *blue; | |
295 | CmpField3(TIFFTAG_COLORMAP, red, green, blue); | |
296 | } | |
297 | #endif | |
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"); | |
310 | return (1); | |
311 | } | |
312 | ||
313 | static int | |
314 | ContigCompare(int sample, uint32 row, | |
315 | unsigned char* p1, unsigned char* p2, tsize_t size) | |
316 | { | |
317 | uint32 pix; | |
318 | int ppb = 8 / bitspersample; | |
319 | int samples_to_test; | |
320 | ||
321 | if (memcmp(p1, p2, size) == 0) | |
322 | return 0; | |
323 | ||
324 | samples_to_test = (sample == -1) ? samplesperpixel : 1; | |
325 | ||
326 | switch (bitspersample) { | |
327 | case 1: case 2: case 4: case 8: | |
328 | { | |
329 | unsigned char *pix1 = p1, *pix2 = p2; | |
330 | ||
331 | for (pix = 0; pix < imagewidth; pix += ppb) { | |
332 | int s; | |
333 | ||
334 | for(s = 0; s < samples_to_test; s++) { | |
335 | if (*pix1 != *pix2) { | |
336 | if( sample == -1 ) | |
337 | PrintIntDiff(row, s, pix, *pix1, *pix2); | |
338 | else | |
339 | PrintIntDiff(row, sample, pix, *pix1, *pix2); | |
340 | } | |
341 | ||
342 | pix1++; | |
343 | pix2++; | |
344 | } | |
345 | } | |
346 | break; | |
347 | } | |
348 | case 16: | |
349 | { | |
350 | uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2; | |
351 | ||
352 | for (pix = 0; pix < imagewidth; pix++) { | |
353 | int s; | |
354 | ||
355 | for(s = 0; s < samples_to_test; s++) { | |
356 | if (*pix1 != *pix2) | |
357 | PrintIntDiff(row, sample, pix, *pix1, *pix2); | |
358 | ||
359 | pix1++; | |
360 | pix2++; | |
361 | } | |
362 | } | |
363 | break; | |
364 | } | |
365 | case 32: | |
366 | if (sampleformat == SAMPLEFORMAT_UINT | |
367 | || sampleformat == SAMPLEFORMAT_INT) { | |
368 | uint32 *pix1 = (uint32 *)p1, *pix2 = (uint32 *)p2; | |
369 | ||
370 | for (pix = 0; pix < imagewidth; pix++) { | |
371 | int s; | |
372 | ||
373 | for(s = 0; s < samples_to_test; s++) { | |
374 | if (*pix1 != *pix2) { | |
375 | PrintIntDiff(row, sample, pix, | |
376 | *pix1, *pix2); | |
377 | } | |
378 | ||
379 | pix1++; | |
380 | pix2++; | |
381 | } | |
382 | } | |
383 | } else if (sampleformat == SAMPLEFORMAT_IEEEFP) { | |
384 | float *pix1 = (float *)p1, *pix2 = (float *)p2; | |
385 | ||
386 | for (pix = 0; pix < imagewidth; pix++) { | |
387 | int s; | |
388 | ||
389 | for(s = 0; s < samples_to_test; s++) { | |
390 | if (fabs(*pix1 - *pix2) < 0.000000000001) { | |
391 | PrintFloatDiff(row, sample, pix, | |
392 | *pix1, *pix2); | |
393 | } | |
394 | ||
395 | pix1++; | |
396 | pix2++; | |
397 | } | |
398 | } | |
399 | } else { | |
400 | fprintf(stderr, "Sample format %d is not supported.\n", | |
401 | sampleformat); | |
402 | return -1; | |
403 | } | |
404 | break; | |
405 | default: | |
406 | fprintf(stderr, "Bit depth %d is not supported.\n", bitspersample); | |
407 | return -1; | |
408 | } | |
409 | ||
410 | return 0; | |
411 | } | |
412 | ||
413 | static void | |
414 | PrintIntDiff(uint32 row, int sample, uint32 pix, uint32 w1, uint32 w2) | |
415 | { | |
416 | if (sample < 0) | |
417 | sample = 0; | |
418 | switch (bitspersample) { | |
419 | case 1: | |
420 | case 2: | |
421 | case 4: | |
422 | { | |
423 | int32 mask1, mask2, s; | |
424 | ||
425 | mask1 = ~((-1) << bitspersample); | |
426 | s = (8 - bitspersample); | |
427 | mask2 = mask1 << s; | |
428 | for (; mask2 && pix < imagewidth; | |
429 | mask2 >>= bitspersample, s -= bitspersample, pix++) { | |
430 | if ((w1 & mask2) ^ (w2 & mask2)) { | |
431 | printf( | |
432 | "Scanline %lu, pixel %lu, sample %d: %01x %01x\n", | |
433 | (unsigned long) row, | |
434 | (unsigned long) pix, | |
435 | sample, | |
436 | (unsigned int)((w1 >> s) & mask1), | |
437 | (unsigned int)((w2 >> s) & mask1)); | |
438 | if (--stopondiff == 0) | |
439 | exit(1); | |
440 | } | |
441 | } | |
442 | break; | |
443 | } | |
444 | case 8: | |
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) | |
449 | exit(1); | |
450 | break; | |
451 | case 16: | |
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) | |
456 | exit(1); | |
457 | break; | |
458 | case 32: | |
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) | |
463 | exit(1); | |
464 | break; | |
465 | default: | |
466 | break; | |
467 | } | |
468 | } | |
469 | ||
470 | static void | |
471 | PrintFloatDiff(uint32 row, int sample, uint32 pix, double w1, double w2) | |
472 | { | |
473 | if (sample < 0) | |
474 | sample = 0; | |
475 | switch (bitspersample) { | |
476 | case 32: | |
477 | printf("Scanline %lu, pixel %lu, sample %d: %g %g\n", | |
478 | (long) row, (long) pix, sample, w1, w2); | |
479 | if (--stopondiff == 0) | |
480 | exit(1); | |
481 | break; | |
482 | default: | |
483 | break; | |
484 | } | |
485 | } | |
486 | ||
487 | static int | |
488 | SeparateCompare(int reversed, int sample, uint32 row, | |
489 | unsigned char* cp1, unsigned char* p2) | |
490 | { | |
491 | uint32 npixels = imagewidth; | |
492 | int pixel; | |
493 | ||
494 | cp1 += sample; | |
495 | for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++) { | |
496 | if (*cp1 != *p2) { | |
497 | printf("Scanline %lu, pixel %lu, sample %ld: ", | |
498 | (long) row, (long) pixel, (long) sample); | |
499 | if (reversed) | |
500 | printf("%02x %02x\n", *p2, *cp1); | |
501 | else | |
502 | printf("%02x %02x\n", *cp1, *p2); | |
503 | if (--stopondiff == 0) | |
504 | exit(1); | |
505 | } | |
506 | } | |
507 | ||
508 | return 0; | |
509 | } | |
510 | ||
511 | static int | |
512 | checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2) | |
513 | { | |
514 | ||
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)); | |
519 | return (0); | |
520 | } | |
521 | return (1); | |
522 | } else if (TIFFGetField(tif2, tag, p2)) { | |
523 | printf("%s tag appears only in %s\n", name, TIFFFileName(tif2)); | |
524 | return (0); | |
525 | } | |
526 | return (-1); | |
527 | } | |
528 | ||
529 | #define CHECK(cmp, fmt) { \ | |
530 | switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \ | |
531 | case 1: if (cmp) \ | |
532 | case -1: return (1); \ | |
533 | printf(fmt, name, v1, v2); \ | |
534 | } \ | |
535 | return (0); \ | |
536 | } | |
537 | ||
538 | static int | |
539 | CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
540 | { | |
541 | uint16 v1, v2; | |
542 | CHECK(v1 == v2, "%s: %u %u\n"); | |
543 | } | |
544 | ||
545 | static int | |
546 | CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
547 | { | |
548 | uint16 v11, v12, v21, v22; | |
549 | ||
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)); | |
554 | return (0); | |
555 | } | |
556 | if (v11 == v21 && v12 == v22) | |
557 | return (1); | |
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)); | |
561 | else | |
562 | return (1); | |
563 | return (0); | |
564 | } | |
565 | ||
566 | static int | |
567 | CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
568 | { | |
569 | uint16 n1, *a1; | |
570 | uint16 n2, *a2; | |
571 | ||
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)); | |
576 | return (0); | |
577 | } | |
578 | if (n1 == n2) { | |
579 | char* sep; | |
580 | uint16 i; | |
581 | ||
582 | if (memcmp(a1, a2, n1 * sizeof(uint16)) == 0) | |
583 | return (1); | |
584 | printf("%s: value mismatch, <%u:", name, n1); | |
585 | sep = ""; | |
586 | for (i = 0; i < n1; i++) | |
587 | printf("%s%u", sep, a1[i]), sep = ","; | |
588 | printf("> and <%u: ", n2); | |
589 | sep = ""; | |
590 | for (i = 0; i < n2; i++) | |
591 | printf("%s%u", sep, a2[i]), sep = ","; | |
592 | printf(">\n"); | |
593 | } else | |
594 | printf("%s: %u items in %s, %u items in %s", name, | |
595 | n1, TIFFFileName(tif1), | |
596 | n2, TIFFFileName(tif2) | |
597 | ); | |
598 | } else if (TIFFGetField(tif2, tag, &n2, &a2)) | |
599 | printf("%s tag appears only in %s\n", name, TIFFFileName(tif2)); | |
600 | else | |
601 | return (1); | |
602 | return (0); | |
603 | } | |
604 | ||
605 | static int | |
606 | CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
607 | { | |
608 | uint32 v1, v2; | |
609 | CHECK(v1 == v2, "%s: %u %u\n"); | |
610 | } | |
611 | ||
612 | static int | |
613 | CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
614 | { | |
615 | float v1, v2; | |
616 | CHECK(v1 == v2, "%s: %g %g\n"); | |
617 | } | |
618 | ||
619 | static int | |
620 | CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
621 | { | |
622 | char *v1, *v2; | |
623 | CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n"); | |
624 | } | |
625 | ||
626 | static void | |
627 | leof(const char* name, uint32 row, int s) | |
628 | { | |
629 | ||
630 | printf("%s: EOF at scanline %lu", name, (unsigned long)row); | |
631 | if (s >= 0) | |
632 | printf(", sample %d", s); | |
633 | printf("\n"); | |
634 | } | |
635 | ||
636 | /* vim: set ts=8 sts=8 sw=8 noet: */ | |
637 | /* | |
638 | * Local Variables: | |
639 | * mode: c | |
640 | * c-basic-offset: 8 | |
641 | * fill-column: 78 | |
642 | * End: | |
643 | */ |