1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // WARNING
4 //
5 // THIS DOES NOT DEAL WITH VERTICALLY FLIPPED DATA CORRECTLY
6 //
7 ////////////////////////////////////////////////////////////////////////////////
8 
9 /* This file is derived from (actually an earlier version of)... */
10 
11 /* The GIMP -- an image manipulation program
12  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
13  *
14  * $Id: tga.cpp,v 1.1.2.5 2007-05-10 02:10:07 elif Exp $
15  * TrueVision Targa loading and saving file filter for the Gimp.
16  * Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit
17  *
18  * The Targa reading and writing code was written from scratch by
19  * Raphael FRANCOIS <fraph@ibm.net> and Gordon Matzigkeit
20  * <gord@gnu.ai.mit.edu> based on the TrueVision TGA File Format
21  * Specification, Version 2.0:
22  *
23  *   <URL:ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/>
24  *
25  * It does not contain any code written for other TGA file loaders.
26  * Not even the RLE handling. ;)
27  *
28  * This program is free software; you can redistribute it and/or modify
29  * it under the terms of the GNU General Public License as published by
30  * the Free Software Foundation; either version 2 of the License, or
31  * (at your option) any later version.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41  */
42 
43 #include "tga.h"
44 #include "../../opengl2/glext.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <assert.h>
49 
50 static char error[256];
51 static unsigned int _verbose = 0;
52 static int totbytes = 0;
53 
54 typedef struct {
55   unsigned char *statebuf;
56   int statelen;
57   int laststate;
58 } RLEstate;
59 
60 IGL_INLINE static int
std_fread(RLEstate *,unsigned char * buf,size_t datasize,size_t nelems,FILE * fp)61 std_fread(RLEstate * /*rleInfo*/, unsigned char *buf, size_t datasize, size_t nelems, FILE *fp)
62 {
63   if (_verbose > 1) {
64     totbytes += nelems * datasize;
65     printf("TGA: std_fread %d (total %d)\n",
66       (int)(nelems * datasize), totbytes);
67   }
68   return fread(buf, datasize, nelems, fp);
69 }
70 
71 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
72 
73 #define RLE_PACKETSIZE 0x80
74 
75 /* Decode a bufferful of file. */
76 IGL_INLINE static int
rle_fread(RLEstate * rleInfo,unsigned char * vbuf,size_t datasize,size_t nelems,FILE * fp)77 rle_fread(RLEstate *rleInfo, unsigned char *vbuf, size_t datasize, size_t nelems, FILE *fp)
78 {
79 
80   unsigned char *buf = vbuf;
81   int j, k;
82   int buflen, count, bytes, curbytes;
83   unsigned char *p;
84 
85   /* Scale the buffer length. */
86   buflen = nelems * datasize;
87 
88   j = 0;
89   curbytes = totbytes;
90   while (j < buflen) {
91     if (rleInfo->laststate < rleInfo->statelen) {
92       /* Copy bytes from our previously decoded buffer. */
93       bytes = MIN(buflen - j, rleInfo->statelen - rleInfo->laststate);
94       memcpy(buf + j, rleInfo->statebuf + rleInfo->laststate, bytes);
95       j += bytes;
96       rleInfo->laststate += bytes;
97 
98       /* If we used up all of our state bytes, then reset them. */
99       if (rleInfo->laststate >= rleInfo->statelen) {
100         rleInfo->laststate = 0;
101         rleInfo->statelen = 0;
102       }
103 
104       /* If we filled the buffer, then exit the loop. */
105       if (j >= buflen) break;
106     }
107 
108     /* Decode the next packet. */
109     count = fgetc(fp);
110     if (count == EOF) {
111       if (_verbose) printf("TGA: hit EOF while looking for count\n");
112       return j / datasize;
113     }
114 
115     /* Scale the byte length to the size of the data. */
116     bytes = ((count & ~RLE_PACKETSIZE) + 1) * datasize;
117 
118     if (j + bytes <= buflen) {
119       /* We can copy directly into the image buffer. */
120       p = buf + j;
121     } else {
122 #ifdef PROFILE
123       printf("TGA: needed to use statebuf for %d bytes\n", buflen - j);
124 #endif
125       /* Allocate the state buffer if we haven't already. */
126       if (!rleInfo->statebuf) {
127         rleInfo->statebuf = (unsigned char *) malloc(RLE_PACKETSIZE * datasize);
128       }
129       p = rleInfo->statebuf;
130     }
131 
132     if (count & RLE_PACKETSIZE) {
133       /* Fill the buffer with the next value. */
134       if (fread(p, datasize, 1, fp) != 1) {
135         if (_verbose) {
136           printf("TGA: EOF while reading %d/%d element RLE packet\n",
137             bytes, (int)datasize);
138         }
139         return j / datasize;
140       }
141 
142       /* Optimized case for single-byte encoded data. */
143       if (datasize == 1) {
144         memset(p + 1, *p, bytes - 1);
145       } else {
146         for (k = datasize; k < bytes; k += datasize) {
147           memcpy(p + k, p, datasize);
148         }
149       }
150     } else {
151       /* Read in the buffer. */
152       if (fread(p, bytes, 1, fp) != 1) {
153         if (_verbose) {
154           printf("TGA: EOF while reading %d/%d element raw packet\n",
155             bytes, (int)datasize);
156         }
157         return j / datasize;
158       }
159     }
160 
161     if (_verbose > 1) {
162       totbytes += bytes;
163       if (_verbose > 2) {
164         printf("TGA: %s packet %d/%d\n",
165           (count & RLE_PACKETSIZE) ? "RLE" : "raw",
166           bytes, totbytes);
167       }
168     }
169 
170     /* We may need to copy bytes from the state buffer. */
171     if (p == rleInfo->statebuf) {
172       rleInfo->statelen = bytes;
173     } else {
174       j += bytes;
175     }
176   }
177 
178   if (_verbose > 1) {
179     printf("TGA: rle_fread %d/%d (total %d)\n",
180     (int) ( nelems * datasize), totbytes - curbytes, totbytes);
181   }
182   return nelems;
183 }
184 
185 IGL_INLINE igl::opengl::gliGenericImage *
gliReadTGA(FILE * fp,char * name,int,int vflip)186 igl::opengl::gliReadTGA(FILE *fp, char *name, int /*hflip*/, int vflip)
187 {
188   igl::opengl::TgaHeader tgaHeader;
189   igl::opengl::TgaFooter tgaFooter;
190   char horzrev, vertrev;
191   int width, height, bpp;
192   int start, end, dir;
193   int i, j, k;
194   int pelbytes, wbytes;
195   GLenum format;
196   int components;
197   RLEstate rleRec;
198   RLEstate *rleInfo;
199   int rle;
200   int index, colors, length;
201   GLubyte *cmap, *pixels, *data;
202   int (*myfread)(RLEstate *rleInfo, unsigned char*, size_t, size_t, FILE*);
203   igl::opengl::gliGenericImage *genericImage;
204 
205   /* Check the footer. */
206   if (fseek(fp, 0L - sizeof(tgaFooter), SEEK_END)
207       || fread(&tgaFooter, sizeof(tgaFooter), 1, fp) != 1) {
208     sprintf(error, "TGA: Cannot read footer from \"%s\"", name);
209     if (_verbose) printf("%s\n", error);
210     return NULL;
211   }
212 
213   /* Check the signature. */
214   if (memcmp(tgaFooter.signature, TGA_SIGNATURE,
215              sizeof(tgaFooter.signature)) == 0) {
216     if (_verbose) printf("TGA: found New TGA\n");
217   } else {
218     if (_verbose) printf("TGA: found Original TGA\n");
219   }
220 
221   if (fseek(fp, 0, SEEK_SET) ||
222       fread(&tgaHeader, sizeof(tgaHeader), 1, fp) != 1) {
223     sprintf(error, "TGA: Cannot read header from \"%s\"", name);
224     if (_verbose) printf("%s\n", error);
225     return NULL;
226   }
227 
228   if (_verbose && tgaHeader.idLength) {
229     char *idString = (char*) malloc(tgaHeader.idLength);
230 
231     if (fread(idString, tgaHeader.idLength, 1, fp) != 1) {
232       sprintf(error, "TGA: Cannot read ID field in \"%s\"", name);
233       printf("%s\n", error);
234     } else {
235       printf("TGA: ID field: \"%*s\"\n", tgaHeader.idLength, idString);
236     }
237     free(idString);
238   } else {
239     /* Skip the image ID field. */
240     if (tgaHeader.idLength && fseek(fp, tgaHeader.idLength, SEEK_CUR)) {
241       sprintf(error, "TGA: Cannot skip ID field in \"%s\"", name);
242       if (_verbose) printf("%s\n", error);
243       return NULL;
244     }
245   }
246 
247   /* Reassemble the multi-byte values correctly, regardless of
248      host endianness. */
249   width = (tgaHeader.widthHi << 8) | tgaHeader.widthLo;
250   height = (tgaHeader.heightHi << 8) | tgaHeader.heightLo;
251   bpp = tgaHeader.bpp;
252   if (_verbose) {
253     printf("TGA: width=%d, height=%d, bpp=%d\n", width, height, bpp);
254   }
255 
256   horzrev = tgaHeader.descriptor & TGA_DESC_HORIZONTAL;
257   vertrev = tgaHeader.descriptor & TGA_DESC_VERTICAL;
258   //vertrev=0;
259 
260 //   // JASON - we can force this stuff if we want
261 //   if( hflip )
262 //       horzrev = 1;
263   if( vflip )
264       vertrev = 1;
265 
266   if (_verbose && horzrev) printf("TGA: horizontal reversed\n");
267   if (_verbose && vertrev) printf("TGA: vertical reversed\n");
268 
269   rle = 0;
270   switch (tgaHeader.imageType) {
271   case TGA_TYPE_MAPPED_RLE:
272     rle = 1;
273     if (_verbose) printf("TGA: run-length encoded\n");
274   case TGA_TYPE_MAPPED:
275     /* Test for alpha channel. */
276     format = GL_COLOR_INDEX;
277     components = 1;
278     if (_verbose) {
279       printf("TGA: %d bit indexed image (%d bit palette)\n",
280         tgaHeader.colorMapSize, bpp);
281     }
282     break;
283 
284   case TGA_TYPE_GRAY_RLE:
285     rle = 1;
286     if (_verbose) printf("TGA: run-length encoded\n");
287   case TGA_TYPE_GRAY:
288     format = GL_LUMINANCE;
289     components = 1;
290     if (_verbose) printf("TGA: %d bit grayscale image\n", bpp);
291     break;
292 
293   case TGA_TYPE_COLOR_RLE:
294     rle = 1;
295     if (_verbose) printf("TGA: run-length encoded\n");
296   case TGA_TYPE_COLOR:
297     /* Test for alpha channel. */
298     if (bpp == 32) {
299       format = GL_BGRA_EXT;
300       components = 4;
301       if (_verbose) {
302         printf("TGA: %d bit color image with alpha channel\n", bpp);
303       }
304     } else {
305       format = GL_BGR_EXT;
306       components = 3;
307       if (_verbose) printf("TGA: %d bit color image\n", bpp);
308     }
309     break;
310 
311   default:
312     sprintf(error,
313       "TGA: unrecognized image type %d\n", tgaHeader.imageType);
314     if (_verbose) printf("%s\n", error);
315     return NULL;
316   }
317 
318   if ((format == GL_BGRA_EXT && bpp != 32) ||
319       (format == GL_BGR_EXT && bpp != 24) ||
320       ((format == GL_LUMINANCE || format == GL_COLOR_INDEX) && bpp != 8)) {
321     /* FIXME: We haven't implemented bit-packed fields yet. */
322     fprintf(stderr, "bpp %d, format %x\n", bpp, (unsigned int)format);
323     sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
324     if (_verbose) printf("%s\n", error);
325     return NULL;
326   }
327 
328   /* Check that we have a color map only when we need it. */
329   if (format == GL_COLOR_INDEX) {
330     if (tgaHeader.colorMapType != 1) {
331       sprintf(error, "TGA: indexed image has invalid color map type %d\n",
332         tgaHeader.colorMapType);
333       if (_verbose) printf("%s\n", error);
334       return NULL;
335     }
336   } else if (tgaHeader.colorMapType != 0) {
337     sprintf(error, "TGA: non-indexed image has invalid color map type %d\n",
338       tgaHeader.colorMapType);
339     if (_verbose) printf("%s\n", error);
340     return NULL;
341   }
342 
343   if (tgaHeader.colorMapType == 1) {
344     /* We need to read in the colormap. */
345     index = (tgaHeader.colorMapIndexHi << 8) | tgaHeader.colorMapIndexLo;
346     length = (tgaHeader.colorMapLengthHi << 8) | tgaHeader.colorMapLengthLo;
347 
348     if (_verbose) {
349       printf("TGA: reading color map (%d + %d) * (%d / 8)\n",
350         index, length, tgaHeader.colorMapSize);
351     }
352     if (length == 0) {
353       sprintf(error, "TGA: invalid color map length %d", length);
354       if (_verbose) printf("%s\n", error);
355       return NULL;
356     }
357     if (tgaHeader.colorMapSize != 24) {
358       /* We haven't implemented bit-packed fields yet. */
359       sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
360       if (_verbose) printf("%s\n", error);
361       return NULL;
362     }
363 
364     pelbytes = tgaHeader.colorMapSize / 8;
365     colors = length + index;
366     cmap = (GLubyte*)malloc (colors * pelbytes);
367 
368     /* Zero the entries up to the beginning of the map. */
369     memset(cmap, 0, index * pelbytes);
370 
371     /* Read in the rest of the colormap. */
372     if (fread(cmap, pelbytes, length, fp) != (size_t) length) {
373       sprintf(error, "TGA: error reading colormap (ftell == %ld)\n",
374         ftell (fp));
375       if (_verbose) printf("%s\n", error);
376       return NULL;
377     }
378 
379     if (pelbytes >= 3) {
380       /* Rearrange the colors from BGR to RGB. */
381       int tmp;
382       for (j = index; j < length * pelbytes; j += pelbytes) {
383         tmp = cmap[j];
384         cmap[j] = cmap[j + 2];
385         cmap[j + 2] = tmp;
386       }
387     }
388   } else {
389     colors = 0;
390     cmap = NULL;
391   }
392 
393   /* Allocate the data. */
394   pelbytes = bpp / 8;
395   pixels = (unsigned char *) malloc (width * height * pelbytes);
396 
397   if (rle) {
398     rleRec.statebuf = 0;
399     rleRec.statelen = 0;
400     rleRec.laststate = 0;
401     rleInfo = &rleRec;
402     myfread = rle_fread;
403   } else {
404     rleInfo = NULL;
405     myfread = std_fread;
406   }
407 
408   wbytes = width * pelbytes;
409 
410   if (vertrev) {
411     start = 0;
412     end = height;
413     dir = 1;
414   } else {
415     /* We need to reverse loading order of rows. */
416     start = height-1;
417     end = -1;
418     dir = -1;
419   }
420 
421   for (i = start; i != end; i += dir) {
422     data = pixels + i*wbytes;
423 
424     /* Suck in the data one row at a time. */
425     if (myfread(rleInfo, data, pelbytes, width, fp) != width) {
426       /* Probably premature end of file. */
427       if (_verbose) {
428         printf ("TGA: error reading (ftell == %ld, width=%d)\n",
429           ftell(fp), width);
430       }
431       return NULL;
432     }
433 
434     if (horzrev) {
435       /* We need to mirror row horizontally. */
436       for (j = 0; j < width/2; j++) {
437         GLubyte tmp;
438 
439         for (k = 0; k < pelbytes; k++) {
440           tmp = data[j*pelbytes+k];
441           data[j*pelbytes+k] = data[(width-j-1)*pelbytes+k];
442           data[(width-j-1)*pelbytes+k] = tmp;
443         }
444       }
445     }
446   }
447 
448   if (rle) {
449     free(rleInfo->statebuf);
450   }
451 
452   if (fgetc (fp) != EOF) {
453     if (_verbose) printf ("TGA: too much input data, ignoring extra...\n");
454   }
455 
456   genericImage = (igl::opengl::gliGenericImage*) malloc(sizeof(igl::opengl::gliGenericImage));
457   genericImage->width = width;
458   genericImage->height = height;
459   genericImage->format = format;
460   genericImage->components = components;
461   genericImage->cmapEntries = colors;
462   genericImage->cmapFormat = GL_BGR_EXT;  // XXX fix me
463   genericImage->cmap = cmap;
464   genericImage->pixels = pixels;
465 
466   return genericImage;
467 }
468 
gli_verbose(int new_verbose)469 IGL_INLINE int igl::opengl::gli_verbose(int new_verbose)
470 {
471   _verbose = new_verbose;
472   return _verbose;
473 }
474 
475 
476 
477 // added 10/2005, Denis Zorin
478 // a very simple TGA output, supporting
479 // uncompressed luminance RGB and RGBA
480 // G22.2270 students: this is C (no C++)
481 // so this is not the style I would encourage
482 // you to use; I used it for consistency
483 // with the rest of the code in this file
484 
485 
486 // fixed header values for the subset of TGA we use for writing
487 unsigned char TGAHeaderColor[12] =
488   { 0,// 0 ID length = no id
489     0,// 1 color map type = no color map
490     2,// 2 image type = uncompressed true color
491     0, 0, 0, 0, 0,// color map spec = empty
492     0, 0,  // x origin of image
493     0, 0   // y origin of image
494   };
495 
496 unsigned char TGAHeaderBW[12] =
497   { 0,// 0 ID length = no id
498     0,// 1 color map type = no color map
499     3,// 3 image type = uncompressed black and white
500     0, 0, 0, 0, 0,// color map spec = empty
501     0, 0,  // x origin of image
502     0, 0   // y origin of image
503   };
504 
505 // this makes sure that
506 // image size is written in correct format
507 // and byte order (least first)
write16bit(int n,FILE * fp)508 IGL_INLINE void write16bit(int n, FILE* fp) {
509   unsigned char bytes[] = { static_cast<unsigned char>(n % 256), static_cast<unsigned char>(n / 256) };
510   fwrite(bytes, 2, sizeof(unsigned char),fp);
511 }
512 
513 
514 
writeTGA(igl::opengl::gliGenericImage * image,FILE * fp)515 IGL_INLINE void igl::opengl::writeTGA( igl::opengl::gliGenericImage* image, FILE *fp) {
516 
517   assert(!image->cmap); // we do not deal with color map images
518 
519   if(image->components == 3 || image->components == 4)
520     fwrite(TGAHeaderColor, 12, sizeof(unsigned char),fp);
521   else {
522     if(image->components == 1 )
523       fwrite(TGAHeaderBW, 12, sizeof(unsigned char),fp);
524     else { fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); }
525   }
526 
527   write16bit(image->width,fp);
528   write16bit(image->height,fp);
529   switch (image->components ) {
530   case 1:
531     putc(8,fp);
532     break;
533   case 3:
534     putc(24,fp);
535     break;
536   case 4:
537     putc(32,fp);
538     break;
539   default: fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1);
540   };
541 
542   if(image-> components == 4)
543     putc(0x04,fp); // bottom left image (0x00) + 8 bit alpha (0x4)
544   else
545     putc(0x00,fp);
546 
547   fwrite(image->pixels, image->height*image->width*image->components, sizeof(char),fp);
548 }
549 
550