]>
Commit | Line | Data |
---|---|---|
1 | /* $Id$ */ | |
2 | ||
3 | /* | |
4 | * Copyright (c) 1988-1997 Sam Leffler | |
5 | * Copyright (c) 1991-1997 Silicon Graphics, Inc. | |
6 | * | |
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. | |
14 | * | |
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. | |
18 | * | |
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 | |
24 | * OF THIS SOFTWARE. | |
25 | */ | |
26 | ||
27 | #include "tif_config.h" | |
28 | ||
29 | #include <stdio.h> | |
30 | #include <stdlib.h> | |
31 | #include <string.h> | |
32 | ||
33 | #ifdef HAVE_UNISTD_H | |
34 | # include <unistd.h> | |
35 | #endif | |
36 | ||
37 | #include "tiffio.h" | |
38 | ||
39 | #ifndef HAVE_GETOPT | |
40 | extern int getopt(int, char**, char*); | |
41 | #endif | |
42 | ||
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; | |
50 | ||
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); | |
58 | ||
59 | static void leof(const char*, uint32, int); | |
60 | ||
61 | int | |
62 | main(int argc, char* argv[]) | |
63 | { | |
64 | TIFF *tif1, *tif2; | |
65 | int c, dirnum; | |
66 | extern int optind; | |
67 | extern char* optarg; | |
68 | ||
69 | while ((c = getopt(argc, argv, "ltz:")) != -1) | |
70 | switch (c) { | |
71 | case 'l': | |
72 | stopondiff = 0; | |
73 | break; | |
74 | case 'z': | |
75 | stopondiff = atoi(optarg); | |
76 | break; | |
77 | case 't': | |
78 | stoponfirsttag = 0; | |
79 | break; | |
80 | case '?': | |
81 | usage(); | |
82 | /*NOTREACHED*/ | |
83 | } | |
84 | if (argc - optind < 2) | |
85 | usage(); | |
86 | tif1 = TIFFOpen(argv[optind], "r"); | |
87 | if (tif1 == NULL) | |
88 | return (-1); | |
89 | tif2 = TIFFOpen(argv[optind+1], "r"); | |
90 | if (tif2 == NULL) | |
91 | return (-2); | |
92 | dirnum = 0; | |
93 | while (tiffcmp(tif1, tif2)) { | |
94 | if (!TIFFReadDirectory(tif1)) { | |
95 | if (!TIFFReadDirectory(tif2)) | |
96 | break; | |
97 | printf("No more directories for %s\n", | |
98 | TIFFFileName(tif1)); | |
99 | return (1); | |
100 | } else if (!TIFFReadDirectory(tif2)) { | |
101 | printf("No more directories for %s\n", | |
102 | TIFFFileName(tif2)); | |
103 | return (1); | |
104 | } | |
105 | printf("Directory %d:\n", ++dirnum); | |
106 | } | |
107 | ||
108 | TIFFClose(tif1); | |
109 | TIFFClose(tif2); | |
110 | return (0); | |
111 | } | |
112 | ||
113 | char* stuff[] = { | |
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", | |
119 | NULL | |
120 | }; | |
121 | ||
122 | static void | |
123 | usage(void) | |
124 | { | |
125 | char buf[BUFSIZ]; | |
126 | int i; | |
127 | ||
128 | setbuf(stderr, buf); | |
129 | fprintf(stderr, "%s\n\n", TIFFGetVersion()); | |
130 | for (i = 0; stuff[i] != NULL; i++) | |
131 | fprintf(stderr, "%s\n", stuff[i]); | |
132 | exit(-1); | |
133 | } | |
134 | ||
135 | #define checkEOF(tif, row, sample) { \ | |
136 | leof(TIFFFileName(tif), row, sample); \ | |
137 | goto bad; \ | |
138 | } | |
139 | ||
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*); | |
146 | ||
147 | static int | |
148 | tiffcmp(TIFF* tif1, TIFF* tif2) | |
149 | { | |
150 | uint16 config1, config2; | |
151 | tsize_t size1; | |
152 | uint32 row; | |
153 | tsample_t s; | |
154 | unsigned char *buf1, *buf2; | |
155 | ||
156 | if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample")) | |
157 | return (0); | |
158 | if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel")) | |
159 | return (0); | |
160 | if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth")) | |
161 | return (0); | |
162 | if (!cmptags(tif1, tif2)) | |
163 | return (1); | |
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"); | |
175 | exit(-1); | |
176 | } | |
177 | if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) { | |
178 | fprintf(stderr, | |
179 | "Can't handle different planar configuration w/ different bits/sample\n"); | |
180 | goto bad; | |
181 | } | |
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) | |
192 | goto bad1; | |
193 | } | |
194 | } | |
195 | break; | |
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) | |
204 | goto bad1; | |
205 | } | |
206 | } | |
207 | break; | |
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) | |
216 | goto bad1; | |
217 | } | |
218 | break; | |
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) | |
226 | goto bad1; | |
227 | } | |
228 | break; | |
229 | } | |
230 | if (buf1) _TIFFfree(buf1); | |
231 | if (buf2) _TIFFfree(buf2); | |
232 | return (1); | |
233 | bad: | |
234 | if (stopondiff) | |
235 | exit(1); | |
236 | bad1: | |
237 | if (buf1) _TIFFfree(buf1); | |
238 | if (buf2) _TIFFfree(buf2); | |
239 | return (0); | |
240 | } | |
241 | ||
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) | |
254 | ||
255 | static int | |
256 | cmptags(TIFF* tif1, TIFF* tif2) | |
257 | { | |
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"); | |
283 | #ifdef notdef | |
284 | { uint16 *graycurve; | |
285 | CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve); | |
286 | } | |
287 | { uint16 *red, *green, *blue; | |
288 | CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue); | |
289 | } | |
290 | { uint16 *red, *green, *blue; | |
291 | CmpField3(TIFFTAG_COLORMAP, red, green, blue); | |
292 | } | |
293 | #endif | |
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"); | |
306 | return (1); | |
307 | } | |
308 | ||
309 | static int | |
310 | ContigCompare(int sample, uint32 row, | |
311 | unsigned char* p1, unsigned char* p2, int size) | |
312 | { | |
313 | uint32 pix; | |
314 | int ppb = 8 / bitspersample; | |
315 | int samples_to_test; | |
316 | ||
317 | if (memcmp(p1, p2, size) == 0) | |
318 | return 0; | |
319 | ||
320 | samples_to_test = (sample == -1) ? samplesperpixel : 1; | |
321 | ||
322 | switch (bitspersample) { | |
323 | case 1: case 2: case 4: case 8: | |
324 | { | |
325 | unsigned char *pix1 = p1, *pix2 = p2; | |
326 | ||
327 | for (pix = 0; pix < imagewidth; pix += ppb) { | |
328 | int s; | |
329 | ||
330 | for(s = 0; s < samples_to_test; s++) { | |
331 | if (*pix1 != *pix2) { | |
332 | if( sample == -1 ) | |
333 | PrintIntDiff(row, s, pix, *pix1, *pix2); | |
334 | else | |
335 | PrintIntDiff(row, sample, pix, *pix1, *pix2); | |
336 | } | |
337 | ||
338 | pix1++; | |
339 | pix2++; | |
340 | } | |
341 | } | |
342 | break; | |
343 | } | |
344 | case 16: | |
345 | { | |
346 | uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2; | |
347 | ||
348 | for (pix = 0; pix < imagewidth; pix++) { | |
349 | int s; | |
350 | ||
351 | for(s = 0; s < samples_to_test; s++) { | |
352 | if (*pix1 != *pix2) | |
353 | PrintIntDiff(row, sample, pix, *pix1, *pix2); | |
354 | ||
355 | pix1++; | |
356 | pix2++; | |
357 | } | |
358 | } | |
359 | break; | |
360 | } | |
361 | case 32: | |
362 | if (sampleformat == SAMPLEFORMAT_UINT | |
363 | || sampleformat == SAMPLEFORMAT_INT) { | |
364 | uint32 *pix1 = (uint32 *)p1, *pix2 = (uint32 *)p2; | |
365 | ||
366 | for (pix = 0; pix < imagewidth; pix++) { | |
367 | int s; | |
368 | ||
369 | for(s = 0; s < samples_to_test; s++) { | |
370 | if (*pix1 != *pix2) { | |
371 | PrintIntDiff(row, sample, pix, | |
372 | *pix1, *pix2); | |
373 | } | |
374 | ||
375 | pix1++; | |
376 | pix2++; | |
377 | } | |
378 | } | |
379 | } else if (sampleformat == SAMPLEFORMAT_IEEEFP) { | |
380 | float *pix1 = (float *)p1, *pix2 = (float *)p2; | |
381 | ||
382 | for (pix = 0; pix < imagewidth; pix++) { | |
383 | int s; | |
384 | ||
385 | for(s = 0; s < samples_to_test; s++) { | |
386 | if (*pix1 != *pix2) { | |
387 | PrintFloatDiff(row, sample, pix, | |
388 | *pix1, *pix2); | |
389 | } | |
390 | ||
391 | pix1++; | |
392 | pix2++; | |
393 | } | |
394 | } | |
395 | } else { | |
396 | fprintf(stderr, "Sample format %d is not supported.\n", | |
397 | sampleformat); | |
398 | return -1; | |
399 | } | |
400 | break; | |
401 | default: | |
402 | fprintf(stderr, "Bit depth %d is not supported.\n", bitspersample); | |
403 | return -1; | |
404 | } | |
405 | ||
406 | return 0; | |
407 | } | |
408 | ||
409 | static void | |
410 | PrintIntDiff(uint32 row, int sample, uint32 pix, uint32 w1, uint32 w2) | |
411 | { | |
412 | if (sample < 0) | |
413 | sample = 0; | |
414 | switch (bitspersample) { | |
415 | case 1: | |
416 | case 2: | |
417 | case 4: | |
418 | { | |
419 | int32 mask1, mask2, s; | |
420 | ||
421 | mask1 = ~((-1) << bitspersample); | |
422 | s = (8 - bitspersample); | |
423 | mask2 = mask1 << s; | |
424 | for (; mask2 && pix < imagewidth; | |
425 | mask2 >>= bitspersample, s -= bitspersample, pix++) { | |
426 | if ((w1 & mask2) ^ (w2 & mask2)) { | |
427 | printf( | |
428 | "Scanline %lu, pixel %lu, sample %d: %01x %01x\n", | |
429 | (unsigned long) row, | |
430 | (unsigned long) pix, | |
431 | sample, | |
432 | (unsigned int)((w1 >> s) & mask1), | |
433 | (unsigned int)((w2 >> s) & mask1)); | |
434 | if (--stopondiff == 0) | |
435 | exit(1); | |
436 | } | |
437 | } | |
438 | break; | |
439 | } | |
440 | case 8: | |
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) | |
445 | exit(1); | |
446 | break; | |
447 | case 16: | |
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) | |
452 | exit(1); | |
453 | break; | |
454 | case 32: | |
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) | |
459 | exit(1); | |
460 | break; | |
461 | default: | |
462 | break; | |
463 | } | |
464 | } | |
465 | ||
466 | static void | |
467 | PrintFloatDiff(uint32 row, int sample, uint32 pix, double w1, double w2) | |
468 | { | |
469 | if (sample < 0) | |
470 | sample = 0; | |
471 | switch (bitspersample) { | |
472 | case 32: | |
473 | printf("Scanline %lu, pixel %lu, sample %d: %g %g\n", | |
474 | (long) row, (long) pix, sample, w1, w2); | |
475 | if (--stopondiff == 0) | |
476 | exit(1); | |
477 | break; | |
478 | default: | |
479 | break; | |
480 | } | |
481 | } | |
482 | ||
483 | static int | |
484 | SeparateCompare(int reversed, int sample, uint32 row, | |
485 | unsigned char* cp1, unsigned char* p2) | |
486 | { | |
487 | uint32 npixels = imagewidth; | |
488 | int pixel; | |
489 | ||
490 | cp1 += sample; | |
491 | for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++) { | |
492 | if (*cp1 != *p2) { | |
493 | printf("Scanline %lu, pixel %lu, sample %ld: ", | |
494 | (long) row, (long) pixel, (long) sample); | |
495 | if (reversed) | |
496 | printf("%02x %02x\n", *p2, *cp1); | |
497 | else | |
498 | printf("%02x %02x\n", *cp1, *p2); | |
499 | if (--stopondiff == 0) | |
500 | exit(1); | |
501 | } | |
502 | } | |
503 | ||
504 | return 0; | |
505 | } | |
506 | ||
507 | static int | |
508 | checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2) | |
509 | { | |
510 | ||
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)); | |
515 | return (0); | |
516 | } | |
517 | return (1); | |
518 | } else if (TIFFGetField(tif2, tag, p2)) { | |
519 | printf("%s tag appears only in %s\n", name, TIFFFileName(tif2)); | |
520 | return (0); | |
521 | } | |
522 | return (-1); | |
523 | } | |
524 | ||
525 | #define CHECK(cmp, fmt) { \ | |
526 | switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \ | |
527 | case 1: if (cmp) \ | |
528 | case -1: return (1); \ | |
529 | printf(fmt, name, v1, v2); \ | |
530 | } \ | |
531 | return (0); \ | |
532 | } | |
533 | ||
534 | static int | |
535 | CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
536 | { | |
537 | uint16 v1, v2; | |
538 | CHECK(v1 == v2, "%s: %u %u\n"); | |
539 | } | |
540 | ||
541 | static int | |
542 | CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
543 | { | |
544 | uint16 v11, v12, v21, v22; | |
545 | ||
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)); | |
550 | return (0); | |
551 | } | |
552 | if (v11 == v21 && v12 == v22) | |
553 | return (1); | |
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)); | |
557 | else | |
558 | return (1); | |
559 | return (0); | |
560 | } | |
561 | ||
562 | static int | |
563 | CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
564 | { | |
565 | uint16 n1, *a1; | |
566 | uint16 n2, *a2; | |
567 | ||
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)); | |
572 | return (0); | |
573 | } | |
574 | if (n1 == n2) { | |
575 | char* sep; | |
576 | uint16 i; | |
577 | ||
578 | if (memcmp(a1, a2, n1 * sizeof(uint16)) == 0) | |
579 | return (1); | |
580 | printf("%s: value mismatch, <%u:", name, n1); | |
581 | sep = ""; | |
582 | for (i = 0; i < n1; i++) | |
583 | printf("%s%u", sep, a1[i]), sep = ","; | |
584 | printf("> and <%u: ", n2); | |
585 | sep = ""; | |
586 | for (i = 0; i < n2; i++) | |
587 | printf("%s%u", sep, a2[i]), sep = ","; | |
588 | printf(">\n"); | |
589 | } else | |
590 | printf("%s: %u items in %s, %u items in %s", name, | |
591 | n1, TIFFFileName(tif1), | |
592 | n2, TIFFFileName(tif2) | |
593 | ); | |
594 | } else if (TIFFGetField(tif2, tag, &n2, &a2)) | |
595 | printf("%s tag appears only in %s\n", name, TIFFFileName(tif2)); | |
596 | else | |
597 | return (1); | |
598 | return (0); | |
599 | } | |
600 | ||
601 | static int | |
602 | CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
603 | { | |
604 | uint32 v1, v2; | |
605 | CHECK(v1 == v2, "%s: %u %u\n"); | |
606 | } | |
607 | ||
608 | static int | |
609 | CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
610 | { | |
611 | float v1, v2; | |
612 | CHECK(v1 == v2, "%s: %g %g\n"); | |
613 | } | |
614 | ||
615 | static int | |
616 | CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name) | |
617 | { | |
618 | char *v1, *v2; | |
619 | CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n"); | |
620 | } | |
621 | ||
622 | static void | |
623 | leof(const char* name, uint32 row, int s) | |
624 | { | |
625 | ||
626 | printf("%s: EOF at scanline %lu", name, (unsigned long)row); | |
627 | if (s >= 0) | |
628 | printf(", sample %d", s); | |
629 | printf("\n"); | |
630 | } | |
631 | ||
632 | /* vim: set ts=8 sts=8 sw=8 noet: */ |