xref: /haiku/src/tools/translation/tgainfo/tgainfo.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*****************************************************************************/
2 // tgainfo
3 // Written by Michael Wilber, Haiku 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 Haiku 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 <Catalog.h>
40 #include <File.h>
41 #include <TranslatorFormats.h>
42 #include <StorageDefs.h>
43 
44 #undef B_TRANSLATION_CONTEXT
45 #define B_TRANSLATION_CONTEXT "tgainfo"
46 
47 #define max(x,y) ((x > y) ? x : y)
48 #define DATA_BUFFER_SIZE 64
49 
50 struct TGAFileHeader {
51 	uint8 idlength;
52 		// Number of bytes in the Image ID field
53 	uint8 colormaptype;
54 	uint8 imagetype;
55 };
56 
57 #define TGA_NO_COLORMAP			0
58 #define TGA_COLORMAP			1
59 
60 #define TGA_NO_IMAGE_DATA		0
61 
62 #define TGA_NOCOMP_COLORMAP		1
63 #define TGA_NOCOMP_TRUECOLOR	2
64 #define TGA_NOCOMP_BW			3
65 #define TGA_RLE_COLORMAP		9
66 #define TGA_RLE_TRUECOLOR		10
67 #define TGA_RLE_BW				11
68 
69 // Information about the color map (palette). These bytes are
70 // always present, but are zero if no color map is present
71 struct TGAColorMapSpec {
72 	uint16 firstentry;		// first useful entry in the color map
73 	uint16 length;			// number of color map entries
74 	uint8 entrysize;		// number of bits per entry
75 };
76 
77 struct TGAImageSpec {
78 	uint16 xorigin;
79 	uint16 yorigin;
80 	uint16 width;
81 	uint16 height;
82 	uint8 depth;
83 	uint8 descriptor;
84 };
85 
86 #define TGA_ORIGIN_VERT_BIT	0x20
87 #define TGA_ORIGIN_BOTTOM	0
88 #define TGA_ORIGIN_TOP		1
89 
90 #define TGA_ORIGIN_HORZ_BIT	0x10
91 #define TGA_ORIGIN_LEFT		0
92 #define TGA_ORIGIN_RIGHT	1
93 
94 #define TGA_DESC_BITS76		0xc0
95 #define TGA_DESC_ALPHABITS	0x0f
96 
97 #define TGA_HEADERS_SIZE 18
98 #define TGA_FTR_LEN 26
99 #define TGA_EXT_LEN 495
100 #define LINE_LEN 82
101 
102 const char *
103 colormaptype(uint8 n)
104 {
105 	switch (n) {
106 		case 0: return B_TRANSLATE("No colormap");
107 		case 1: return B_TRANSLATE("colormap");
108 	}
109 	return "unknown";
110 }
111 
112 const char *
113 imagetype(uint8 n)
114 {
115 	switch (n) {
116 		case 0:  return B_TRANSLATE("No Image Data");
117 		case 1:  return B_TRANSLATE("colormap");
118 		case 2:  return B_TRANSLATE("true color");
119 		case 3:  return B_TRANSLATE("grayscale");
120 		case 9:  return B_TRANSLATE("RLE colormap");
121 		case 10: return B_TRANSLATE("RLE true color");
122 		case 11: return B_TRANSLATE("RLE grayscale");
123 		default: break;
124 	}
125 	return B_TRANSLATE("unknown");
126 }
127 
128 uint16
129 tga_uint16(char *buffer, int32 offset)
130 {
131 	return B_LENDIAN_TO_HOST_INT16(*(reinterpret_cast<uint16 *>(buffer + offset)));
132 }
133 
134 uint32
135 tga_uint32(char *buffer, int32 offset)
136 {
137 	return B_LENDIAN_TO_HOST_INT32(*(reinterpret_cast<uint32 *>(buffer + offset)));
138 }
139 
140 void
141 print_tga_info(BFile &file)
142 {
143 	uint8 buf[TGA_HEADERS_SIZE];
144 
145 	// read in TGA headers
146 	ssize_t size = TGA_HEADERS_SIZE;
147 	if (size > 0 && file.Read(buf, size) != size) {
148 		printf(B_TRANSLATE("Error: unable to read all TGA headers\n"));
149 		return;
150 	}
151 
152 	// TGA file header
153 	TGAFileHeader fh;
154 	fh.idlength = buf[0];
155 	fh.colormaptype = buf[1];
156 	fh.imagetype = buf[2];
157 
158 	printf(B_TRANSLATE("\nFile Header:\n"));
159 	printf(B_TRANSLATE("    id length: %d\n"), static_cast<int>(fh.idlength));
160 
161 	printf(B_TRANSLATE("colormap type: %d (%s)\n"),
162 		static_cast<int>(fh.colormaptype),
163 		static_cast<const char *>(colormaptype(fh.colormaptype)));
164 	printf(B_TRANSLATE("   image type: %d (%s)\n"),
165 		static_cast<int>(fh.imagetype),
166 		static_cast<const char *>(imagetype(fh.imagetype)));
167 
168 
169 	// TGA color map spec
170 	TGAColorMapSpec mapspec;
171 	mapspec.firstentry = tga_uint16(reinterpret_cast<char *>(buf), 3);
172 	mapspec.length = tga_uint16(reinterpret_cast<char *>(buf), 5);
173 	mapspec.entrysize = buf[7];
174 
175 	printf(B_TRANSLATE("\nColormap Spec:\n"));
176 	printf(B_TRANSLATE("first entry: %d\n"),
177 		static_cast<int>(mapspec.firstentry));
178 	printf(B_TRANSLATE("     length: %d\n"),
179 		static_cast<int>(mapspec.length));
180 	printf(B_TRANSLATE(" entry size: %d\n"),
181 		static_cast<int>(mapspec.entrysize));
182 
183 
184 	// TGA image spec
185 	TGAImageSpec imagespec;
186 	imagespec.xorigin = tga_uint16(reinterpret_cast<char *>(buf), 8);
187 	imagespec.yorigin = tga_uint16(reinterpret_cast<char *>(buf), 10);
188 	imagespec.width = tga_uint16(reinterpret_cast<char *>(buf), 12);
189 	imagespec.height = tga_uint16(reinterpret_cast<char *>(buf), 14);
190 	imagespec.depth = buf[16];
191 	imagespec.descriptor = buf[17];
192 
193 	printf(B_TRANSLATE("\nImage Spec:\n"));
194 	printf(B_TRANSLATE("  x origin: %d\n"),
195 		static_cast<int>(imagespec.xorigin));
196 	printf(B_TRANSLATE("  y origin: %d\n"),
197 		static_cast<int>(imagespec.yorigin));
198 	printf(B_TRANSLATE("     width: %d\n"),
199 		static_cast<int>(imagespec.width));
200 	printf(B_TRANSLATE("    height: %d\n"),
201 		static_cast<int>(imagespec.height));
202 	printf(B_TRANSLATE("     depth: %d\n"),
203 		static_cast<int>(imagespec.depth));
204 	printf(B_TRANSLATE("descriptor: 0x%.2x\n"),
205 		static_cast<int>(imagespec.descriptor));
206 	printf(B_TRANSLATE("\talpha (attr): %d\n"),
207 		static_cast<int>(imagespec.descriptor & TGA_DESC_ALPHABITS));
208 	if (imagespec.descriptor & TGA_ORIGIN_VERT_BIT)
209 		if (imagespec.descriptor & TGA_ORIGIN_HORZ_BIT)
210 			printf(B_TRANSLATE("\t      origin: %d (%s %s)\n"),
211 				static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
212 				| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("top"),
213 				static_cast<const char *>("right"));
214 		else
215 			printf(B_TRANSLATE("\t      origin: %d (%s %s)\n"),
216 			static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
217 				| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("top"),
218 				static_cast<const char *>("left"));
219 	else
220 		if (imagespec.descriptor & TGA_ORIGIN_HORZ_BIT)
221 			printf(B_TRANSLATE("\t      origin: %d (%s %s)\n"),
222 				static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
223 				| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("bottom"),
224 				static_cast<const char *>("right"));
225 		else
226 			printf(B_TRANSLATE("\t      origin: %d (%s %s)\n"),
227 			static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
228 				| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("bottom"),
229 				static_cast<const char *>("left"));
230 
231 
232 	printf(B_TRANSLATE("\t  bits 7 & 6: %d\n"),
233 		static_cast<int>(imagespec.descriptor & TGA_DESC_BITS76));
234 
235 
236 	// Optional TGA Footer
237 	off_t filesize = 0;
238 	if (file.GetSize(&filesize) == B_OK) {
239 
240 		char tgafooter[TGA_FTR_LEN + 1] = { 0 };
241 		if (file.ReadAt(filesize - TGA_FTR_LEN, tgafooter, TGA_FTR_LEN) == TGA_FTR_LEN) {
242 
243 			if (strcmp(tgafooter + 8, "TRUEVISION-XFILE.") == 0) {
244 
245 				uint32 extoffset = 0, devoffset = 0;
246 				extoffset = tga_uint32(tgafooter, 0);
247 				devoffset = tga_uint32(tgafooter, 4);
248 
249 				printf(B_TRANSLATE("\nTGA Footer:\n"));
250 				printf(B_TRANSLATE("extension offset: 0x%.8lx (%ld)\n"),
251 					static_cast<long int>(extoffset),
252 					static_cast<long int>(extoffset));
253 				printf(B_TRANSLATE("developer offset: 0x%.8lx (%ld)\n"),
254 					static_cast<long int>(devoffset),
255 					static_cast<long int>(devoffset));
256 				printf(B_TRANSLATE("signature: %s\n"), tgafooter + 8);
257 
258 				if (extoffset) {
259 					char extbuf[TGA_EXT_LEN];
260 					if (file.ReadAt(extoffset, extbuf, TGA_EXT_LEN) == TGA_EXT_LEN) {
261 
262 						printf(B_TRANSLATE("\nExtension Area:\n"));
263 
264 						char strbuffer[LINE_LEN];
265 
266 						uint16 extsize = tga_uint16(extbuf, 0);
267 						if (extsize < TGA_EXT_LEN) {
268 							printf(B_TRANSLATE("\nError: extension "
269 								"area is too small (%d)\n"), extsize);
270 							return;
271 						}
272 						printf(B_TRANSLATE("size: %d\n"), extsize);
273 
274 						memset(strbuffer, 0, LINE_LEN);
275 						strncpy(strbuffer, extbuf + 2, 41);
276 						printf("author: \"%s\"\n", strbuffer);
277 
278 						printf(B_TRANSLATE("comments:\n"));
279 						for (int32 i = 0; i < 4; i++) {
280 							memset(strbuffer, 0, LINE_LEN);
281 							strcpy(strbuffer, extbuf + 43 + (i * 81));
282 							printf(B_TRANSLATE("\tline %ld: \"%s\"\n"),
283 								static_cast<long int>(i + 1),
284 								static_cast<const char *>(strbuffer));
285 						}
286 
287 						printf(B_TRANSLATE("date/time (yyyy-mm-dd hh:mm:ss): "
288 							"%.4d-%.2d-%.2d %.2d:%.2d:%.2d\n"),
289 							tga_uint16(extbuf, 367), tga_uint16(extbuf, 369),
290 							tga_uint16(extbuf, 371), tga_uint16(extbuf, 373),
291 							tga_uint16(extbuf, 375), tga_uint16(extbuf, 377));
292 
293 						memset(strbuffer, 0, LINE_LEN);
294 						strncpy(strbuffer, extbuf + 379, 41);
295 						printf(B_TRANSLATE("job name: \"%s\"\n"), strbuffer);
296 
297 						printf(B_TRANSLATE("job time (hh:mm:ss): "
298 							"%.2d:%.2d:%.2d\n"), tga_uint16(extbuf, 420),
299 							tga_uint16(extbuf, 422), tga_uint16(extbuf, 424));
300 
301 						memset(strbuffer, 0, LINE_LEN);
302 						strncpy(strbuffer, extbuf + 426, 41);
303 						printf(B_TRANSLATE("software id: \"%s\"\n"),
304 							strbuffer);
305 
306 						char strver[] = "[null]";
307 						if (extbuf[469] != '\0') {
308 							strver[0] = extbuf[469];
309 							strver[1] = '\0';
310 						}
311 						printf(B_TRANSLATE("software version, letter: %d, "
312 							"%s\n"), tga_uint16(extbuf, 467), strver);
313 
314 						printf(B_TRANSLATE("key color (A,R,G,B): %d, %d, %d, "
315 							"%d\n"), extbuf[470], extbuf[471], extbuf[472],
316 							extbuf[473]);
317 
318 						printf(B_TRANSLATE("pixel aspect ratio: %d / %d\n"),
319 							tga_uint16(extbuf, 474), tga_uint16(extbuf, 476));
320 
321 						printf(B_TRANSLATE("gamma value: %d / %d\n"),
322 							tga_uint16(extbuf, 478), tga_uint16(extbuf, 480));
323 
324 						printf(B_TRANSLATE("color correction offset: 0x%.8lx "
325 							"(%ld)\n"),	tga_uint32(extbuf, 482),
326 							tga_uint32(extbuf, 482));
327 						printf(B_TRANSLATE("postage stamp offset: 0x%.8lx "
328 							"(%ld)\n"),	tga_uint32(extbuf, 486),
329 							tga_uint32(extbuf, 486));
330 						printf(B_TRANSLATE("scan line offset: 0x%.8lx "
331 							"(%ld)\n"), tga_uint32(extbuf, 490),
332 							tga_uint32(extbuf, 490));
333 
334 						const char *strattrtype = NULL;
335 						uint8 attrtype = extbuf[494];
336 						switch (attrtype) {
337 							case 0: strattrtype
338 								= B_TRANSLATE("no alpha"); break;
339 							case 1: strattrtype
340 								= B_TRANSLATE("undefined, ignore"); break;
341 							case 2: strattrtype
342 								= B_TRANSLATE("undefined, retain"); break;
343 							case 3: strattrtype
344 								= B_TRANSLATE("alpha"); break;
345 							case 4: strattrtype
346 								= B_TRANSLATE("pre-multiplied alpha"); break;
347 							default:
348 								if (attrtype > 4 && attrtype < 128)
349 									strattrtype = B_TRANSLATE("reserved");
350 								else
351 									strattrtype = B_TRANSLATE("unassigned");
352 								break;
353 						}
354 						printf(B_TRANSLATE("attributes type: %d (%s)\n"),
355 							attrtype, strattrtype);
356 
357 					} else
358 						printf(B_TRANSLATE("\nError: Unable to read entire "
359 							"extension area\n"));
360 				}
361 
362 			} else
363 				printf(B_TRANSLATE("\nTGA footer not found\n"));
364 
365 		} else
366 			printf(B_TRANSLATE("\nError: Unable to read TGA footer "
367 				"section\n"));
368 
369 	} else
370 		printf(B_TRANSLATE("\nError: Unable to get file size\n"));
371 }
372 
373 int
374 main(int argc, char **argv)
375 {
376 	printf("\n");
377 
378 	if (argc == 1) {
379 		printf(B_TRANSLATE("tgainfo - reports information about a TGA image file\n"));
380 		printf(B_TRANSLATE("\nUsage:\n"));
381 		printf(B_TRANSLATE("tgainfo filename.tga\n"));
382 	}
383 	else {
384 		BFile file;
385 
386 		for (int32 i = 1; i < argc; i++) {
387 			if (file.SetTo(argv[i], B_READ_ONLY) != B_OK)
388 				printf(B_TRANSLATE("\nError opening %s\n"), argv[i]);
389 			else {
390 				printf(B_TRANSLATE("\nTGA image information for: %s\n"), argv[i]);
391 				print_tga_info(file);
392 			}
393 		}
394 
395 	}
396 
397 	printf("\n");
398 
399 	return 0;
400 }
401 
402