1/*****************************************************************************/
2// tgainfo
3// Written by Michael Wilber, OBOS Translation Kit Team
4//
5// Version:
6//
7// tgainfo is a command line program for displaying information about
8// TGA images.
9//
10//
11// This application and all source files used in its construction, except
12// where noted, are licensed under the MIT License, and have been written
13// and are:
14//
15// Copyright (c) 2003 OpenBeOS Project
16//
17// Permission is hereby granted, free of charge, to any person obtaining a
18// copy of this software and associated documentation files (the "Software"),
19// to deal in the Software without restriction, including without limitation
20// the rights to use, copy, modify, merge, publish, distribute, sublicense,
21// and/or sell copies of the Software, and to permit persons to whom the
22// Software is furnished to do so, subject to the following conditions:
23//
24// The above copyright notice and this permission notice shall be included
25// in all copies or substantial portions of the Software.
26//
27// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33// DEALINGS IN THE SOFTWARE.
34/*****************************************************************************/
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <ByteOrder.h>
39#include <File.h>
40#include <TranslatorFormats.h>
41#include <StorageDefs.h>
42
43#define max(x,y) ((x > y) ? x : y)
44#define DATA_BUFFER_SIZE 64
45
46struct TGAFileHeader {
47	uint8 idlength;
48		// Number of bytes in the Image ID field
49	uint8 colormaptype;
50	uint8 imagetype;
51};
52
53#define TGA_NO_COLORMAP			0
54#define TGA_COLORMAP			1
55
56#define TGA_NO_IMAGE_DATA		0
57
58#define TGA_NOCOMP_COLORMAP		1
59#define TGA_NOCOMP_TRUECOLOR	2
60#define TGA_NOCOMP_BW			3
61#define TGA_RLE_COLORMAP		9
62#define TGA_RLE_TRUECOLOR		10
63#define TGA_RLE_BW				11
64
65// Information about the color map (palette). These bytes are
66// always present, but are zero if no color map is present
67struct TGAColorMapSpec {
68	uint16 firstentry;		// first useful entry in the color map
69	uint16 length;			// number of color map entries
70	uint8 entrysize;		// number of bits per entry
71};
72
73struct TGAImageSpec {
74	uint16 xorigin;
75	uint16 yorigin;
76	uint16 width;
77	uint16 height;
78	uint8 depth;
79	uint8 descriptor;
80};
81
82#define TGA_ORIGIN_VERT_BIT	0x20
83#define TGA_ORIGIN_BOTTOM	0
84#define TGA_ORIGIN_TOP		1
85
86#define TGA_ORIGIN_HORZ_BIT	0x10
87#define TGA_ORIGIN_LEFT		0
88#define TGA_ORIGIN_RIGHT	1
89
90#define TGA_DESC_BITS76		0xc0
91#define TGA_DESC_ALPHABITS	0x0f
92
93#define TGA_HEADERS_SIZE 18
94#define TGA_FTR_LEN 26
95#define TGA_EXT_LEN 495
96#define LINE_LEN 82
97
98const char *
99colormaptype(uint8 n)
100{
101	switch (n) {
102		case 0: return "No colormap";
103		case 1: return "colormap";
104	}
105	return "unknown";
106}
107
108const char *
109imagetype(uint8 n)
110{
111	switch (n) {
112		case 0:  return "No Image Data";
113		case 1:  return "colormap";
114		case 2:  return "true color";
115		case 3:  return "grayscale";
116		case 9:  return "RLE colormap";
117		case 10: return "RLE true color";
118		case 11: return "RLE grayscale";
119	}
120	return "unknown";
121}
122
123uint16
124tga_uint16(char *buffer, int32 offset)
125{
126	return B_LENDIAN_TO_HOST_INT16(*(reinterpret_cast<uint16 *>(buffer + offset)));
127}
128
129uint32
130tga_uint32(char *buffer, int32 offset)
131{
132	return B_LENDIAN_TO_HOST_INT32(*(reinterpret_cast<uint32 *>(buffer + offset)));
133}
134
135void
136print_tga_info(BFile &file)
137{
138	uint8 buf[TGA_HEADERS_SIZE];
139
140	// read in TGA headers
141	ssize_t size = TGA_HEADERS_SIZE;
142	if (size > 0 && file.Read(buf, size) != size) {
143		printf("Error: unable to read all TGA headers\n");
144		return;
145	}
146
147	// TGA file header
148	TGAFileHeader fh;
149	fh.idlength = buf[0];
150	fh.colormaptype = buf[1];
151	fh.imagetype = buf[2];
152
153	printf("\nFile Header:\n");
154	printf("    id length: %d\n", fh.idlength);
155
156	printf("colormap type: %d (%s)\n", fh.colormaptype,
157		colormaptype(fh.colormaptype));
158	printf("   image type: %d (%s)\n", fh.imagetype, imagetype(fh.imagetype));
159
160
161	// TGA color map spec
162	TGAColorMapSpec mapspec;
163	mapspec.firstentry = tga_uint16(reinterpret_cast<char *>(buf), 3);
164	mapspec.length = tga_uint16(reinterpret_cast<char *>(buf), 5);
165	mapspec.entrysize = buf[7];
166
167	printf("\nColormap Spec:\n");
168	printf("first entry: %d\n", mapspec.firstentry);
169	printf("     length: %d\n", mapspec.length);
170	printf(" entry size: %d\n", mapspec.entrysize);
171
172
173	// TGA image spec
174	TGAImageSpec imagespec;
175	imagespec.xorigin = tga_uint16(reinterpret_cast<char *>(buf), 8);
176	imagespec.yorigin = tga_uint16(reinterpret_cast<char *>(buf), 10);
177	imagespec.width = tga_uint16(reinterpret_cast<char *>(buf), 12);
178	imagespec.height = tga_uint16(reinterpret_cast<char *>(buf), 14);
179	imagespec.depth = buf[16];
180	imagespec.descriptor = buf[17];
181
182	printf("\nImage Spec:\n");
183	printf("  x origin: %d\n", imagespec.xorigin);
184	printf("  y origin: %d\n", imagespec.yorigin);
185	printf("     width: %d\n", imagespec.width);
186	printf("    height: %d\n", imagespec.height);
187	printf("     depth: %d\n", imagespec.depth);
188	printf("descriptor: 0x%.2x\n", imagespec.descriptor);
189		printf("\talpha (attr): %d\n",
190			imagespec.descriptor & TGA_DESC_ALPHABITS);
191		printf("\t      origin: %d (%s %s)\n",
192			imagespec.descriptor & (TGA_ORIGIN_VERT_BIT | TGA_ORIGIN_HORZ_BIT),
193			((imagespec.descriptor & TGA_ORIGIN_VERT_BIT) ? "top" : "bottom"),
194			((imagespec.descriptor & TGA_ORIGIN_HORZ_BIT) ? "right" : "left"));
195		printf("\t  bits 7 & 6: %d\n", imagespec.descriptor & TGA_DESC_BITS76);
196
197
198	// Optional TGA Footer
199	off_t filesize = 0;
200	if (file.GetSize(&filesize) == B_OK) {
201
202		char tgafooter[TGA_FTR_LEN + 1] = { 0 };
203		if (file.ReadAt(filesize - TGA_FTR_LEN, tgafooter, TGA_FTR_LEN) == TGA_FTR_LEN) {
204
205			if (strcmp(tgafooter + 8, "TRUEVISION-XFILE.") == 0) {
206
207				uint32 extoffset = 0, devoffset = 0;
208				extoffset = tga_uint32(tgafooter, 0);
209				devoffset = tga_uint32(tgafooter, 4);
210
211				printf("\nTGA Footer:\n");
212				printf("extension offset: 0x%.8lx (%ld)\n", extoffset, extoffset);
213				printf("developer offset: 0x%.8lx (%ld)\n", devoffset, devoffset);
214				printf("signature: %s\n", tgafooter + 8);
215
216				if (extoffset) {
217					char extbuf[TGA_EXT_LEN];
218					if (file.ReadAt(extoffset, extbuf, TGA_EXT_LEN) == TGA_EXT_LEN) {
219
220						printf("\nExtension Area:\n");
221
222						char strbuffer[LINE_LEN];
223
224						uint16 extsize = tga_uint16(extbuf, 0);
225						if (extsize < TGA_EXT_LEN) {
226							printf("\nError: extension area is too small (%d)\n", extsize);
227							return;
228						}
229						printf("size: %d\n", extsize);
230
231						memset(strbuffer, 0, LINE_LEN);
232						strncpy(strbuffer, extbuf + 2, 41);
233						printf("author: \"%s\"\n", strbuffer);
234
235						printf("comments:\n");
236						for (int32 i = 0; i < 4; i++) {
237							memset(strbuffer, 0, LINE_LEN);
238							strcpy(strbuffer, extbuf + 43 + (i * 81));
239							printf("\tline %ld: \"%s\"\n", i + 1, strbuffer);
240						}
241
242						printf("date/time (yyyy-mm-dd hh:mm:ss): %.4d-%.2d-%.2d %.2d:%.2d:%.2d\n",
243							tga_uint16(extbuf, 367), tga_uint16(extbuf, 369),
244							tga_uint16(extbuf, 371), tga_uint16(extbuf, 373),
245							tga_uint16(extbuf, 375), tga_uint16(extbuf, 377));
246
247						memset(strbuffer, 0, LINE_LEN);
248						strncpy(strbuffer, extbuf + 379, 41);
249						printf("job name: \"%s\"\n", strbuffer);
250
251						printf("job time (hh:mm:ss): %.2d:%.2d:%.2d\n",
252							tga_uint16(extbuf, 420), tga_uint16(extbuf, 422),
253							tga_uint16(extbuf, 424));
254
255						memset(strbuffer, 0, LINE_LEN);
256						strncpy(strbuffer, extbuf + 426, 41);
257						printf("software id: \"%s\"\n", strbuffer);
258
259						char strver[] = "[null]";
260						if (extbuf[469] != '\0') {
261							strver[0] = extbuf[469];
262							strver[1] = '\0';
263						}
264						printf("software version, letter: %d, %s\n",
265							tga_uint16(extbuf, 467), strver);
266
267						printf("key color (A,R,G,B): %d, %d, %d, %d\n",
268							extbuf[470], extbuf[471], extbuf[472], extbuf[473]);
269
270						printf("pixel aspect ratio: %d / %d\n",
271							tga_uint16(extbuf, 474), tga_uint16(extbuf, 476));
272
273						printf("gamma value: %d / %d\n",
274							tga_uint16(extbuf, 478), tga_uint16(extbuf, 480));
275
276						printf("color correction offset: 0x%.8lx (%ld)\n",
277							tga_uint32(extbuf, 482), tga_uint32(extbuf, 482));
278						printf("postage stamp offset: 0x%.8lx (%ld)\n",
279							tga_uint32(extbuf, 486), tga_uint32(extbuf, 486));
280						printf("scan line offset: 0x%.8lx (%ld)\n",
281							tga_uint32(extbuf, 490), tga_uint32(extbuf, 490));
282
283						const char *strattrtype = NULL;
284						uint8 attrtype = extbuf[494];
285						switch (attrtype) {
286							case 0: strattrtype = "no alpha"; break;
287							case 1: strattrtype = "undefined, ignore"; break;
288							case 2: strattrtype = "undefined, retain"; break;
289							case 3: strattrtype = "alpha"; break;
290							case 4: strattrtype = "pre-multiplied alpha"; break;
291							default:
292								if (attrtype > 4 && attrtype < 128)
293									strattrtype = "reserved";
294								else
295									strattrtype = "unassigned";
296								break;
297						}
298						printf("attributes type: %d (%s)\n", attrtype, strattrtype);
299
300					} else
301						printf("\nError: Unable to read entire extension area\n");
302				}
303
304			} else
305				printf("\nTGA footer not found\n");
306
307		} else
308			printf("\nError: Unable to read TGA footer section\n");
309
310	} else
311		printf("\nError: Unable to get file size\n");
312}
313
314int
315main(int argc, char **argv)
316{
317	printf("\n");
318
319	if (argc == 1) {
320		printf("tgainfo - reports information about a TGA image file\n");
321		printf("\nUsage:\n");
322		printf("tgainfo filename.tga\n");
323	}
324	else {
325		BFile file;
326
327		for (int32 i = 1; i < argc; i++) {
328			if (file.SetTo(argv[i], B_READ_ONLY) != B_OK)
329				printf("\nError opening %s\n", argv[i]);
330			else {
331				printf("\nTGA image information for: %s\n", argv[i]);
332				print_tga_info(file);
333			}
334		}
335
336	}
337
338	printf("\n");
339
340	return 0;
341}
342
343