1/* $Id: tiffinfo.c 276 2010-06-30 12:18:30Z nijtmans $ */
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_STRINGS_H
34# include <strings.h>
35#endif
36
37#ifdef HAVE_UNISTD_H
38# include <unistd.h>
39#endif
40
41#include "tiffio.h"
42
43#define	streq(a,b)	(strcasecmp(a,b) == 0)
44
45int	showdata = 0;			/* show data */
46int	rawdata = 0;			/* show raw/decoded data */
47int	showwords = 0;			/* show data as bytes/words */
48int	readdata = 0;			/* read data in file */
49int	stoponerr = 1;			/* stop on first read error */
50
51static	void usage(void);
52static	void tiffinfo(TIFF*, uint16, long);
53
54int
55main(int argc, char* argv[])
56{
57	int dirnum = -1, multiplefiles, c;
58	uint16 order = 0;
59	TIFF* tif;
60	extern int optind;
61	extern char* optarg;
62	long flags = 0;
63	uint32 diroff = 0;
64	int chopstrips = 0;		/* disable strip chopping */
65
66	while ((c = getopt(argc, argv, "f:o:cdDSjilmrsvwz0123456789")) != -1)
67		switch (c) {
68		case '0': case '1': case '2': case '3':
69		case '4': case '5': case '6': case '7':
70		case '8': case '9':
71			dirnum = atoi(&argv[optind-1][1]);
72			break;
73		case 'd':
74			showdata++;
75			/* fall thru... */
76		case 'D':
77			readdata++;
78			break;
79		case 'c':
80			flags |= TIFFPRINT_COLORMAP | TIFFPRINT_CURVES;
81			break;
82		case 'f':		/* fill order */
83			if (streq(optarg, "lsb2msb"))
84				order = FILLORDER_LSB2MSB;
85			else if (streq(optarg, "msb2lsb"))
86				order = FILLORDER_MSB2LSB;
87			else
88				usage();
89			break;
90		case 'i':
91			stoponerr = 0;
92			break;
93		case 'o':
94			diroff = strtoul(optarg, NULL, 0);
95			break;
96		case 'j':
97			flags |= TIFFPRINT_JPEGQTABLES |
98				 TIFFPRINT_JPEGACTABLES |
99				 TIFFPRINT_JPEGDCTABLES;
100			break;
101		case 'r':
102			rawdata = 1;
103			break;
104		case 's':
105			flags |= TIFFPRINT_STRIPS;
106			break;
107		case 'w':
108			showwords = 1;
109			break;
110		case 'z':
111			chopstrips = 1;
112			break;
113		case '?':
114			usage();
115			/*NOTREACHED*/
116		}
117	if (optind >= argc)
118		usage();
119	multiplefiles = (argc - optind > 1);
120	for (; optind < argc; optind++) {
121		if (multiplefiles)
122			printf("%s:\n", argv[optind]);
123		tif = TIFFOpen(argv[optind], chopstrips ? "rC" : "rc");
124		if (tif != NULL) {
125			if (dirnum != -1) {
126				if (TIFFSetDirectory(tif, (tdir_t) dirnum))
127					tiffinfo(tif, order, flags);
128			} else if (diroff != 0) {
129				if (TIFFSetSubDirectory(tif, diroff))
130					tiffinfo(tif, order, flags);
131			} else {
132				do {
133					uint32 offset;
134
135					tiffinfo(tif, order, flags);
136					if (TIFFGetField(tif, TIFFTAG_EXIFIFD,
137							 &offset)) {
138						if (TIFFReadEXIFDirectory(tif, offset))
139							tiffinfo(tif, order, flags);
140					}
141				} while (TIFFReadDirectory(tif));
142			}
143			TIFFClose(tif);
144		}
145	}
146	return (0);
147}
148
149char* stuff[] = {
150"usage: tiffinfo [options] input...",
151"where options are:",
152" -D		read data",
153" -i		ignore read errors",
154" -c		display data for grey/color response curve or colormap",
155" -d		display raw/decoded image data",
156" -f lsb2msb	force lsb-to-msb FillOrder for input",
157" -f msb2lsb	force msb-to-lsb FillOrder for input",
158" -j		show JPEG tables",
159" -o offset	set initial directory offset",
160" -r		read/display raw image data instead of decoded data",
161" -s		display strip offsets and byte counts",
162" -w		display raw data in words rather than bytes",
163" -z		enable strip chopping",
164" -#		set initial directory (first directory is # 0)",
165NULL
166};
167
168static void
169usage(void)
170{
171	char buf[BUFSIZ];
172	int i;
173
174	setbuf(stderr, buf);
175        fprintf(stderr, "%s\n\n", TIFFGetVersion());
176	for (i = 0; stuff[i] != NULL; i++)
177		fprintf(stderr, "%s\n", stuff[i]);
178	exit(-1);
179}
180
181static void
182ShowStrip(tstrip_t strip, unsigned char* pp, uint32 nrow, tsize_t scanline)
183{
184	register tsize_t cc;
185
186	printf("Strip %lu:\n", (unsigned long) strip);
187	while (nrow-- > 0) {
188		for (cc = 0; cc < scanline; cc++) {
189			printf(" %02x", *pp++);
190			if (((cc+1) % 24) == 0)
191				putchar('\n');
192		}
193		putchar('\n');
194	}
195}
196
197void
198TIFFReadContigStripData(TIFF* tif)
199{
200	unsigned char *buf;
201	tsize_t scanline = TIFFScanlineSize(tif);
202
203	buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
204	if (buf) {
205		uint32 row, h;
206		uint32 rowsperstrip = (uint32)-1;
207
208		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
209		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
210		for (row = 0; row < h; row += rowsperstrip) {
211			uint32 nrow = (row+rowsperstrip > h ?
212			    h-row : rowsperstrip);
213			tstrip_t strip = TIFFComputeStrip(tif, row, 0);
214			if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
215				if (stoponerr)
216					break;
217			} else if (showdata)
218				ShowStrip(strip, buf, nrow, scanline);
219		}
220		_TIFFfree(buf);
221	}
222}
223
224void
225TIFFReadSeparateStripData(TIFF* tif)
226{
227	unsigned char *buf;
228	tsize_t scanline = TIFFScanlineSize(tif);
229
230	buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
231	if (buf) {
232		uint32 row, h;
233		uint32 rowsperstrip = (uint32)-1;
234		tsample_t s, samplesperpixel;
235
236		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
237		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
238		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
239		for (row = 0; row < h; row += rowsperstrip) {
240			for (s = 0; s < samplesperpixel; s++) {
241				uint32 nrow = (row+rowsperstrip > h ?
242				    h-row : rowsperstrip);
243				tstrip_t strip = TIFFComputeStrip(tif, row, s);
244				if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
245					if (stoponerr)
246						break;
247				} else if (showdata)
248					ShowStrip(strip, buf, nrow, scanline);
249			}
250		}
251		_TIFFfree(buf);
252	}
253}
254
255static void
256ShowTile(uint32 row, uint32 col, tsample_t sample,
257    unsigned char* pp, uint32 nrow, uint32 rowsize)
258{
259	uint32 cc;
260
261	printf("Tile (%lu,%lu", (unsigned long) row, (unsigned long) col);
262	if (sample != (tsample_t) -1)
263		printf(",%u", sample);
264	printf("):\n");
265	while (nrow-- > 0) {
266		for (cc = 0; cc < rowsize; cc++) {
267			printf(" %02x", *pp++);
268			if (((cc+1) % 24) == 0)
269				putchar('\n');
270		}
271		putchar('\n');
272	}
273}
274
275void
276TIFFReadContigTileData(TIFF* tif)
277{
278	unsigned char *buf;
279	tsize_t rowsize = TIFFTileRowSize(tif);
280
281	buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif));
282	if (buf) {
283		uint32 tw, th, w, h;
284		uint32 row, col;
285
286		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
287		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
288		TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
289		TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
290		for (row = 0; row < h; row += th) {
291			for (col = 0; col < w; col += tw) {
292				if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0) {
293					if (stoponerr)
294						break;
295				} else if (showdata)
296					ShowTile(row, col, (tsample_t) -1, buf, th, rowsize);
297			}
298		}
299		_TIFFfree(buf);
300	}
301}
302
303void
304TIFFReadSeparateTileData(TIFF* tif)
305{
306	unsigned char *buf;
307	tsize_t rowsize = TIFFTileRowSize(tif);
308
309	buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif));
310	if (buf) {
311		uint32 tw, th, w, h;
312		uint32 row, col;
313		tsample_t s, samplesperpixel;
314
315		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
316		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
317		TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
318		TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
319		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
320		for (row = 0; row < h; row += th) {
321			for (col = 0; col < w; col += tw) {
322				for (s = 0; s < samplesperpixel; s++) {
323					if (TIFFReadTile(tif, buf, col, row, 0, s) < 0) {
324						if (stoponerr)
325							break;
326					} else if (showdata)
327						ShowTile(row, col, s, buf, th, rowsize);
328				}
329			}
330		}
331		_TIFFfree(buf);
332	}
333}
334
335void
336TIFFReadData(TIFF* tif)
337{
338	uint16 config;
339
340	TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
341	if (TIFFIsTiled(tif)) {
342		if (config == PLANARCONFIG_CONTIG)
343			TIFFReadContigTileData(tif);
344		else
345			TIFFReadSeparateTileData(tif);
346	} else {
347		if (config == PLANARCONFIG_CONTIG)
348			TIFFReadContigStripData(tif);
349		else
350			TIFFReadSeparateStripData(tif);
351	}
352}
353
354static void
355ShowRawBytes(unsigned char* pp, uint32 n)
356{
357	uint32 i;
358
359	for (i = 0; i < n; i++) {
360		printf(" %02x", *pp++);
361		if (((i+1) % 24) == 0)
362			printf("\n ");
363	}
364	putchar('\n');
365}
366
367static void
368ShowRawWords(uint16* pp, uint32 n)
369{
370	uint32 i;
371
372	for (i = 0; i < n; i++) {
373		printf(" %04x", *pp++);
374		if (((i+1) % 15) == 0)
375			printf("\n ");
376	}
377	putchar('\n');
378}
379
380void
381TIFFReadRawData(TIFF* tif, int bitrev)
382{
383	tstrip_t nstrips = TIFFNumberOfStrips(tif);
384	const char* what = TIFFIsTiled(tif) ? "Tile" : "Strip";
385	uint32* stripbc;
386
387	TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbc);
388	if (nstrips > 0) {
389		uint32 bufsize = stripbc[0];
390		tdata_t buf = _TIFFmalloc(bufsize);
391		tstrip_t s;
392
393		for (s = 0; s < nstrips; s++) {
394			if (stripbc[s] > bufsize) {
395				buf = _TIFFrealloc(buf, stripbc[s]);
396				bufsize = stripbc[s];
397			}
398			if (buf == NULL) {
399				fprintf(stderr,
400				   "Cannot allocate buffer to read strip %lu\n",
401				    (unsigned long) s);
402				break;
403			}
404			if (TIFFReadRawStrip(tif, s, buf, stripbc[s]) < 0) {
405				fprintf(stderr, "Error reading strip %lu\n",
406				    (unsigned long) s);
407				if (stoponerr)
408					break;
409			} else if (showdata) {
410				if (bitrev) {
411					TIFFReverseBits(buf, stripbc[s]);
412					printf("%s %lu: (bit reversed)\n ",
413					    what, (unsigned long) s);
414				} else
415					printf("%s %lu:\n ", what,
416					    (unsigned long) s);
417				if (showwords)
418					ShowRawWords((uint16*) buf, stripbc[s]>>1);
419				else
420					ShowRawBytes((unsigned char*) buf, stripbc[s]);
421			}
422		}
423		if (buf != NULL)
424			_TIFFfree(buf);
425	}
426}
427
428static void
429tiffinfo(TIFF* tif, uint16 order, long flags)
430{
431	TIFFPrintDirectory(tif, stdout, flags);
432	if (!readdata)
433		return;
434	if (rawdata) {
435		if (order) {
436			uint16 o;
437			TIFFGetFieldDefaulted(tif,
438			    TIFFTAG_FILLORDER, &o);
439			TIFFReadRawData(tif, o != order);
440		} else
441			TIFFReadRawData(tif, 0);
442	} else {
443		if (order)
444			TIFFSetField(tif, TIFFTAG_FILLORDER, order);
445		TIFFReadData(tif);
446	}
447}
448
449/* vim: set ts=8 sts=8 sw=8 noet: */
450/*
451 * Local Variables:
452 * mode: c
453 * c-basic-offset: 8
454 * fill-column: 78
455 * End:
456 */
457