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