xref: /haiku/src/tools/translation/tgainfo/tgainfo.cpp (revision 9eb55bc1d104b8fda80898f8b25c94d8000c8255)
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 
46 struct 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
67 struct 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 
73 struct 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 
98 const char *
99 colormaptype(uint8 n)
100 {
101 	switch (n) {
102 		case 0: return "No colormap";
103 		case 1: return "colormap";
104 	}
105 	return "unknown";
106 }
107 
108 const char *
109 imagetype(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 
123 uint16
124 tga_uint16(char *buffer, int32 offset)
125 {
126 	return B_LENDIAN_TO_HOST_INT16(*(reinterpret_cast<uint16 *>(buffer + offset)));
127 }
128 
129 uint32
130 tga_uint32(char *buffer, int32 offset)
131 {
132 	return B_LENDIAN_TO_HOST_INT32(*(reinterpret_cast<uint32 *>(buffer + offset)));
133 }
134 
135 void
136 print_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%.2lx\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 (%d)\n", extoffset, extoffset);
213 				printf("developer offset: 0x%.8lx (%d)\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 %d: \"%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 (%d)\n",
277 							tga_uint32(extbuf, 482), tga_uint32(extbuf, 482));
278 						printf("postage stamp offset: 0x%.8lx (%d)\n",
279 							tga_uint32(extbuf, 486), tga_uint32(extbuf, 486));
280 						printf("scan line offset: 0x%.8lx (%d)\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 
314 int
315 main(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