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