1/* This code is ripped from Autotrace-0.29. Small modifications by pts. */ 2 3/* input-tga.ci reads tga files */ 4 5#ifdef __GNUC__ 6#ifndef __clang__ 7#pragma implementation 8#endif 9#endif 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14/* #include <unistd.h> */ 15 16#include "at_bitmap.h" 17/* #include "message.h" */ 18/* #include "xstd.h" */ 19/* #include "input-tga.h" */ /* BUGFIX by pts: bmp -> tga */ 20 21/* TODO: 22 - Handle loading images that aren't 8 bits per channel. 23*/ 24 25/* Round up a division to the nearest integer. */ 26#define ROUNDUP_DIVIDE(n,d) (((n) + (d - 1)) / (d)) 27 28#define MAX(a,b) ((a) > (b) ? (a) : (b)) 29#define MIN(a,b) ((a) < (b) ? (a) : (b)) 30 31#define INDEXED 1 32#define INDEXEDA 2 33#define GRAY 3 34#define TGA_RGB 5 35#define INDEXED_IMAGE 1 36#define INDEXEDA_IMAGE 2 37#define GRAY_IMAGE 3 38#define GRAYA_IMAGE 4 39#define TGA_RGB_IMAGE 5 40#define TGA_RGBA_IMAGE 6 41 42typedef struct _TgaSaveVals 43{ 44 int rle; 45} TgaSaveVals; 46 47typedef struct _TgaSaveInterface 48{ 49 int run; 50} TgaSaveInterface; 51 52struct tga_header 53{ 54 unsigned char idLength; 55 unsigned char colorMapType; 56 57 /* The image type. */ 58#define TGA_TYPE_MAPPED 1 59#define TGA_TYPE_COLOR 2 60#define TGA_TYPE_GRAY 3 61#define TGA_TYPE_MAPPED_RLE 9 62#define TGA_TYPE_COLOR_RLE 10 63#define TGA_TYPE_GRAY_RLE 11 64 unsigned char imageType; 65 66 /* Color Map Specification. */ 67 /* We need to separately specify high and low bytes to avoid endianness 68 and alignment problems. */ 69 unsigned char colorMapIndexLo, colorMapIndexHi; 70 unsigned char colorMapLengthLo, colorMapLengthHi; 71 unsigned char colorMapSize; 72 73 /* Image Specification. */ 74 unsigned char xOriginLo, xOriginHi; 75 unsigned char yOriginLo, yOriginHi; 76 77 unsigned char widthLo, widthHi; 78 unsigned char heightLo, heightHi; 79 80 unsigned char bpp; 81 82 /* Image descriptor. 83 3-0: attribute bpp 84 4: left-to-right ordering 85 5: top-to-bottom ordering 86 7-6: zero 87 */ 88#define TGA_DESC_ABITS 0x0f 89#define TGA_DESC_HORIZONTAL 0x10 90#define TGA_DESC_VERTICAL 0x20 91 unsigned char descriptor; 92}; 93 94#if 0 95static struct 96{ 97 unsigned int extensionAreaOffset; 98 unsigned int developerDirectoryOffset; 99#define TGA_SIGNATURE "TRUEVISION-XFILE" 100 char signature[16]; 101 char dot; 102 char null; 103} tga_footer; 104#endif 105 106 107static bitmap_type ReadImage (FILE *fp, 108 struct tga_header *hdr); 109#if PTS_SAM2P /**** pts ****/ 110bitmap_type tga_load_image (FILE* filename) 111#else 112bitmap_type tga_load_image (at_string filename) 113#endif 114{ 115 FILE *fp; 116 struct tga_header hdr; 117 118 bitmap_type image; 119 120 image.bitmap = NULL; 121 122 #if PTS_SAM2P /**** pts ****/ 123 fp=filename; 124 #else 125 fp = fopen (filename, "rb"); 126 if (!fp) 127 FATAL1 ("TGA: can't open \"%s\"\n", filename); 128 #endif 129 130 memset(&hdr, '\0', sizeof(hdr)); 131 132#if 0 133 /* Check the footer. */ 134 if (fseek (fp, 0L - (sizeof (tga_footer)), SEEK_END) 135 || fread (&tga_footer, sizeof (tga_footer), 1, fp) != 1) 136#if PTS_SAM2P 137 FATALP("TGA: Cannot read footer"); 138#else 139 FATAL1 ("TGA: Cannot read footer from \"%s\"\n", filename); 140#endif 141 /* Check the signature. */ 142 if (fseek (fp, 0, SEEK_SET) || 143#else 144 if (0 || 145#endif 146 fread (&hdr, sizeof (hdr), 1, fp) != 1) 147#if PTS_SAM2P 148 FATALP("TGA: Cannot read header"); 149#else 150 FATAL1 ("TGA: Cannot read header from \"%s\"\n", filename); 151#endif 152 153 /* Skip the image ID field. */ 154 { 155#if 0 156 if (hdr.idLength && fseek (fp, hdr.idLength, SEEK_CUR)) 157#else 158 char buf[256]; 159 if (hdr.idLength!=fread(buf, 1, hdr.idLength, fp)) 160#endif 161#if PTS_SAM2P 162 FATALP("TGA: Cannot skip ID field"); 163#else 164 FATAL1 ("TGA: Cannot skip ID field in \"%s\"\n", filename); 165#endif 166 } 167 168 image = ReadImage (fp, &hdr); 169 /* fclose (fp); */ 170 return image; 171} 172 173 174static int 175std_fread (unsigned char *buf, 176 int datasize, 177 int nelems, 178 FILE *fp) 179{ 180 181 return fread (buf, datasize, nelems, fp); 182} 183 184#define RLE_PACKETSIZE 0x80 185 186/* Decode a bufferful of file. */ 187static int 188rle_fread (unsigned char *buf, 189 int datasize, 190 int nelems, 191 FILE *fp) 192{ 193 static unsigned char *statebuf = 0; 194 static int statelen = 0; 195 static int laststate = 0; 196 197 int j, k; 198 int buflen, count, bytes; 199 unsigned char *p; 200 201 /* Scale the buffer length. */ 202 buflen = nelems * datasize; 203 204 j = 0; 205 while (j < buflen) 206 { 207 if (laststate < statelen) 208 { 209 /* Copy bytes from our previously decoded buffer. */ 210 bytes = MIN (buflen - j, statelen - laststate); 211 memcpy (buf + j, statebuf + laststate, bytes); 212 j += bytes; 213 laststate += bytes; 214 215 /* If we used up all of our state bytes, then reset them. */ 216 if (laststate >= statelen) 217 { 218 laststate = 0; 219 statelen = 0; 220 } 221 222 /* If we filled the buffer, then exit the loop. */ 223 if (j >= buflen) 224 break; 225 } 226 227 /* Decode the next packet. */ 228 count = fgetc (fp); 229 if (count == EOF) 230 { 231 return j / datasize; 232 } 233 234 /* Scale the byte length to the size of the data. */ 235 bytes = ((count & ~RLE_PACKETSIZE) + 1) * datasize; 236 237 if (j + bytes <= buflen) 238 { 239 /* We can copy directly into the image buffer. */ 240 p = buf + j; 241 } 242 else { 243 /* Allocate the state buffer if we haven't already. */ 244 if (!statebuf) 245 statebuf = (unsigned char *) malloc (RLE_PACKETSIZE * datasize); 246 p = statebuf; 247 } 248 249 if (count & RLE_PACKETSIZE) 250 { 251 /* Fill the buffer with the next value. */ 252 if (fread (p, datasize, 1, fp) != 1) 253 { 254 return j / datasize; 255 } 256 257 /* Optimized case for single-byte encoded data. */ 258 if (datasize == 1) 259 memset (p + 1, *p, bytes - 1); 260 else 261 for (k = datasize; k < bytes; k += datasize) 262 memcpy (p + k, p, datasize); 263 } 264 else 265 { 266 /* Read in the buffer. */ 267 if (fread (p, bytes, 1, fp) != 1) 268 { 269 return j / datasize; 270 } 271 } 272 273 /* We may need to copy bytes from the state buffer. */ 274 if (p == statebuf) 275 statelen = bytes; 276 else 277 j += bytes; 278 } 279 280return nelems; 281} 282 283static bitmap_type 284ReadImage (FILE *fp, 285 struct tga_header *hdr) 286{ 287 bitmap_type image; 288 unsigned char *buffer; 289 unsigned char *alphas; 290 291 int width, height, bpp, abpp, pbpp, nalphas; 292 int j, k; 293 int pelbytes, wbytes, bsize, npels, pels; 294 int rle, badread; 295 int itype=0; 296 unsigned char *cmap = NULL; 297 int (*myfread)(unsigned char *, int, int, FILE *); 298 299 /* Find out whether the image is horizontally or vertically reversed. */ 300 char horzrev = (char) (hdr->descriptor & TGA_DESC_HORIZONTAL); 301 char vertrev = (char) (!(hdr->descriptor & TGA_DESC_VERTICAL)); 302 303 image.bitmap = NULL; 304 305 /* Reassemble the multi-byte values correctly, regardless of 306 host endianness. */ 307 width = (hdr->widthHi << 8) | hdr->widthLo; 308 height = (hdr->heightHi << 8) | hdr->heightLo; 309 310 bpp = hdr->bpp; 311 abpp = hdr->descriptor & TGA_DESC_ABITS; 312 313 if (hdr->imageType == TGA_TYPE_COLOR || 314 hdr->imageType == TGA_TYPE_COLOR_RLE) 315 pbpp = MIN (bpp / 3, 8) * 3; 316 else if (abpp < bpp) 317 pbpp = bpp - abpp; 318 else 319 pbpp = bpp; 320 321 if (abpp + pbpp > bpp) 322 { 323 WARNINGP3 ("TGA: ",pbpp," bit image, ",abpp," bit alpha is greater than ",bpp," total bits per pixel"); 324 325 /* Assume that alpha bits were set incorrectly. */ 326 abpp = bpp - pbpp; 327 WARNINGP1 ("TGA: reducing to * bit alpha: ", abpp); 328 } 329 else if (abpp + pbpp < bpp) 330 { 331 WARNINGP3 ("TGA: ",pbpp," bit image, ",abpp," bit alpha is less than ",bpp," total bits per pixel"); 332 333 /* Again, assume that alpha bits were set incorrectly. */ 334 abpp = bpp - pbpp; 335 WARNINGP1 ("TGA: increasing to * bit alpha: ", abpp); 336 } 337 338 rle = 0; 339 switch (hdr->imageType) 340 { 341 case TGA_TYPE_MAPPED_RLE: 342 rle = 1; 343 case TGA_TYPE_MAPPED: 344 itype = INDEXED; 345 346 /* Find the size of palette elements. */ 347 pbpp = MIN (hdr->colorMapSize / 3, 8) * 3; 348 if (pbpp < hdr->colorMapSize) 349 abpp = hdr->colorMapSize - pbpp; 350 else 351 abpp = 0; 352 353 354 if (bpp != 8) 355 /* We can only cope with 8-bit indices. */ 356 FATALP ("TGA: index sizes other than 8 bits are unimplemented"); 357 break; 358 359 case TGA_TYPE_GRAY_RLE: 360 rle = 1; 361 case TGA_TYPE_GRAY: 362 itype = GRAY; 363 break; 364 365 case TGA_TYPE_COLOR_RLE: 366 rle = 1; 367 case TGA_TYPE_COLOR: 368 itype = TGA_RGB; 369 break; 370 371 default: 372 FATALP1 ("TGA: unrecognized image type ", (unsigned)hdr->imageType); 373} 374 375 if ((abpp && abpp != 8) || 376 ((itype == TGA_RGB || itype == INDEXED) && pbpp != 24) || 377 (itype == GRAY && pbpp != 8)) 378 /* FIXME: We haven't implemented bit-packed fields yet. */ 379 FATALP ("TGA: channel sizes other than 8 bits are unimplemented"); 380 381 /* Check that we have a color map only when we need it. */ 382 if (itype == INDEXED) 383 { 384 if (hdr->colorMapType != 1) 385 FATALP1 ("TGA: indexed image has invalid color map type ", 386 (unsigned)hdr->colorMapType); 387 } 388 else if (hdr->colorMapType != 0) 389 FATALP1 ("TGA: non-indexed image has invalid color map type ", 390 (unsigned)hdr->colorMapType); 391 392 alphas = 0; 393 nalphas = 0; 394 if (hdr->colorMapType == 1) 395 { 396 /* We need to read in the colormap. */ 397 int index, colors; 398 unsigned int length; 399 400 index = (hdr->colorMapIndexHi << 8) | hdr->colorMapIndexLo; 401 length = (hdr->colorMapLengthHi << 8) | hdr->colorMapLengthLo; 402 403 if (length == 0) 404 FATALP1 ("TGA: invalid color map length ", length); 405 406 pelbytes = ROUNDUP_DIVIDE (hdr->colorMapSize, 8); 407 colors = length + index; 408 cmap = (unsigned char *) malloc (colors * pelbytes); 409 410 /* Zero the entries up to the beginning of the map. */ 411 memset (cmap, 0, index * pelbytes); 412 413 /* Read in the rest of the colormap. */ 414 if (fread (cmap + (index * pelbytes), pelbytes, length, fp) != length) 415 FATALP1 ("TGA: error reading colormap; ftell == ", ftell (fp)); 416 417 /* If we have an alpha channel, then create a mapping to the alpha 418 values. */ 419 if (pelbytes > 3) 420 alphas = (unsigned char *) malloc (colors); 421 422 k = 0; 423 for (j = 0; j < colors * pelbytes; j += pelbytes) 424 { 425 /* Swap from BGR to TGA_RGB. */ 426 unsigned char tmp = cmap[j]; 427 cmap[k ++] = cmap[j + 2]; 428 cmap[k ++] = cmap[j + 1]; 429 cmap[k ++] = tmp; 430 431 /* Take the alpha values out of the colormap. */ 432 if (alphas) 433 alphas[nalphas ++] = cmap[j + 3]; 434 } 435 436 /* If the last color was transparent, then omit it from the 437 mapping. */ 438 if (nalphas && alphas[nalphas - 1] == 0) 439 colors --; 440 441 /* Now pretend as if we only have 8 bpp. */ 442 abpp = 0; 443 pbpp = 8; 444 pelbytes = 1; 445 } 446 else 447 pelbytes = 3; 448 449 image.bitmap = (unsigned char *) malloc (width * height * 3 * sizeof(unsigned char)); 450 BITMAP_WIDTH (image) = (unsigned short) width; 451 BITMAP_HEIGHT (image) = (unsigned short) height; 452 BITMAP_PLANES (image) = (unsigned short) 3; 453 454 /* Calculate TGA bytes per pixel. */ 455 bpp = ROUNDUP_DIVIDE (pbpp + abpp, 8); 456 457 /* Maybe we need to reverse the data. */ 458 buffer = NULL; 459 if (horzrev || vertrev) 460 buffer = (unsigned char *) malloc (width * height * pelbytes * sizeof (unsigned char)); 461 if (rle) 462 myfread = rle_fread; 463 else 464 myfread = std_fread; 465 466 wbytes = width * pelbytes; 467 badread = 0; 468 469 npels = width * height; 470 bsize = wbytes * height; 471 472 /* Suck in the data one height at a time. */ 473 if (badread) 474 pels = 0; 475 else 476 pels = (*myfread) (image.bitmap, bpp, npels, fp); 477 478 if (pels != npels) 479 { 480 if (!badread) 481 { 482 /* Probably premature end of file. */ 483 WARNINGP1 ("TGA: error reading; ftell == ", ftell (fp)); 484 badread = 1; 485 } 486 487 488 /* Fill the rest of this tile with zeros. */ 489 memset (image.bitmap + (pels * bpp), 0, ((npels - pels) * bpp)); 490 } 491 /* If we have indexed alphas, then set them. */ 492 if (nalphas) 493 { 494 /* Start at the end of the buffer, and work backwards. */ 495 k = (npels - 1) * bpp; 496 for (j = bsize - pelbytes; j >= 0; j -= pelbytes) 497 { 498 /* Find the alpha for this index. */ 499 image.bitmap[j + 1] = alphas[image.bitmap[k]]; 500 image.bitmap[j] = image.bitmap[k --]; 501 } 502 } 503 504 if (itype == GRAY) 505 for (j = bsize/3 - 1; j >= 0; j -= 1) 506 { 507 /* Find the alpha for this index. */ 508 image.bitmap[3*j] = image.bitmap[j]; 509 image.bitmap[3*j+1] = image.bitmap[j]; 510 image.bitmap[3*j+2] = image.bitmap[j]; 511 } 512 513 514 if (pelbytes >= 3) 515 { 516 /* Rearrange the colors from BGR to TGA_RGB. */ 517 for (j = 0; j < bsize; j += pelbytes) 518 { 519 unsigned char tmp = image.bitmap[j]; 520 image.bitmap[j] = image.bitmap[j + 2]; 521 image.bitmap[j + 2] = tmp; 522 } 523 } 524 525 526 527 if (horzrev || vertrev) 528 { 529 unsigned char *tmp; 530 if (vertrev) 531 { 532 /* We need to mirror only vertically. */ 533 for (j = 0; j < bsize; j += wbytes) 534 memcpy (buffer + j, 535 image.bitmap + bsize - (j + wbytes), wbytes); 536 } 537 else if (horzrev) 538 { 539 /* We need to mirror only horizontally. */ 540 for (j = 0; j < bsize; j += wbytes) 541 for (k = 0; k < wbytes; k += pelbytes) 542 memcpy (buffer + k + j, 543 image.bitmap + (j + wbytes) - (k + pelbytes), pelbytes); 544 } 545 else 546 { 547 /* Completely reverse the pixels in the buffer. */ 548 for (j = 0; j < bsize; j += pelbytes) 549 memcpy (buffer + j, 550 image.bitmap + bsize - (j + pelbytes), pelbytes); 551 } 552 553 /* Swap the buffers because we modified them. */ 554 tmp = buffer; 555 buffer = image.bitmap; 556 image.bitmap = tmp; 557 } 558 559 if (fgetc (fp) != EOF) 560 WARNINGP ("TGA: too much input data, ignoring extra..."); 561 562 free (buffer); 563 564 if (hdr->colorMapType == 1) 565 { 566 unsigned char *temp, *temp2, *temp3; 567 unsigned char index; 568 int xpos, ypos; 569 570 temp2 = temp = image.bitmap; 571 image.bitmap = temp3 = (unsigned char *) malloc (width * height * 3 * sizeof (unsigned char)); 572 573 for (ypos = 0; ypos < height; ypos++) 574 { 575 for (xpos = 0; xpos < width; xpos++) 576 { 577 index = *temp2++; 578 *temp3++ = cmap[3*index+0]; 579 *temp3++ = cmap[3*index+1]; 580 *temp3++ = cmap[3*index+2]; 581 } 582 } 583 free (temp); 584 free (cmap); 585 } 586 587 if (alphas) 588 free (alphas); 589 590 return image; 591} /* read_image */ 592