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 <Catalog.h> 40 #include <File.h> 41 #include <TranslatorFormats.h> 42 #include <StorageDefs.h> 43 44 #undef B_TRANSLATE_CONTEXT 45 #define B_TRANSLATE_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