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