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