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 50struct 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 71struct 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 77struct 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 102const char * 103colormaptype(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 112const char * 113imagetype(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 128uint16 129tga_uint16(char *buffer, int32 offset) 130{ 131 return B_LENDIAN_TO_HOST_INT16(*(reinterpret_cast<uint16 *>(buffer + offset))); 132} 133 134uint32 135tga_uint32(char *buffer, int32 offset) 136{ 137 return B_LENDIAN_TO_HOST_INT32(*(reinterpret_cast<uint32 *>(buffer + offset))); 138} 139 140void 141print_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 373int 374main(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