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 free(cmap);
377 return NULL;
378 }
379
380 if (pelbytes >= 3) {
381 /* Rearrange the colors from BGR to RGB. */
382 int tmp;
383 for (j = index; j < length * pelbytes; j += pelbytes) {
384 tmp = cmap[j];
385 cmap[j] = cmap[j + 2];
386 cmap[j + 2] = tmp;
387 }
388 }
389 } else {
390 colors = 0;
391 cmap = NULL;
392 }
393
394 /* Allocate the data. */
395 pelbytes = bpp / 8;
396 pixels = (unsigned char *) malloc (width * height * pelbytes);
397
398 if (rle) {
399 rleRec.statebuf = 0;
400 rleRec.statelen = 0;
401 rleRec.laststate = 0;
402 rleInfo = &rleRec;
403 myfread = rle_fread;
404 } else {
405 rleInfo = NULL;
406 myfread = std_fread;
407 }
408
409 wbytes = width * pelbytes;
410
411 if (vertrev) {
412 start = 0;
413 end = height;
414 dir = 1;
415 } else {
416 /* We need to reverse loading order of rows. */
417 start = height-1;
418 end = -1;
419 dir = -1;
420 }
421
422 for (i = start; i != end; i += dir) {
423 data = pixels + i*wbytes;
424
425 /* Suck in the data one row at a time. */
426 if (myfread(rleInfo, data, pelbytes, width, fp) != width) {
427 /* Probably premature end of file. */
428 if (_verbose) {
429 printf ("TGA: error reading (ftell == %ld, width=%d)\n",
430 ftell(fp), width);
431 }
432 return NULL;
433 }
434
435 if (horzrev) {
436 /* We need to mirror row horizontally. */
437 for (j = 0; j < width/2; j++) {
438 GLubyte tmp;
439
440 for (k = 0; k < pelbytes; k++) {
441 tmp = data[j*pelbytes+k];
442 data[j*pelbytes+k] = data[(width-j-1)*pelbytes+k];
443 data[(width-j-1)*pelbytes+k] = tmp;
444 }
445 }
446 }
447 }
448
449 if (rle) {
450 free(rleInfo->statebuf);
451 }
452
453 if (fgetc (fp) != EOF) {
454 if (_verbose) printf ("TGA: too much input data, ignoring extra...\n");
455 }
456
457 genericImage = (igl::opengl::gliGenericImage*) malloc(sizeof(igl::opengl::gliGenericImage));
458 genericImage->width = width;
459 genericImage->height = height;
460 genericImage->format = format;
461 genericImage->components = components;
462 genericImage->cmapEntries = colors;
463 genericImage->cmapFormat = GL_BGR_EXT; // XXX fix me
464 genericImage->cmap = cmap;
465 genericImage->pixels = pixels;
466
467 return genericImage;
468 }
469
gli_verbose(int new_verbose)470 IGL_INLINE int igl::opengl::gli_verbose(int new_verbose)
471 {
472 _verbose = new_verbose;
473 return _verbose;
474 }
475
476
477
478 // added 10/2005, Denis Zorin
479 // a very simple TGA output, supporting
480 // uncompressed luminance RGB and RGBA
481 // G22.2270 students: this is C (no C++)
482 // so this is not the style I would encourage
483 // you to use; I used it for consistency
484 // with the rest of the code in this file
485
486
487 // fixed header values for the subset of TGA we use for writing
488 unsigned char TGAHeaderColor[12] =
489 { 0,// 0 ID length = no id
490 0,// 1 color map type = no color map
491 2,// 2 image type = uncompressed true color
492 0, 0, 0, 0, 0,// color map spec = empty
493 0, 0, // x origin of image
494 0, 0 // y origin of image
495 };
496
497 unsigned char TGAHeaderBW[12] =
498 { 0,// 0 ID length = no id
499 0,// 1 color map type = no color map
500 3,// 3 image type = uncompressed black and white
501 0, 0, 0, 0, 0,// color map spec = empty
502 0, 0, // x origin of image
503 0, 0 // y origin of image
504 };
505
506 // this makes sure that
507 // image size is written in correct format
508 // and byte order (least first)
write16bit(int n,FILE * fp)509 IGL_INLINE void write16bit(int n, FILE* fp) {
510 unsigned char bytes[] = { static_cast<unsigned char>(n % 256), static_cast<unsigned char>(n / 256) };
511 fwrite(bytes, 2, sizeof(unsigned char),fp);
512 }
513
514
515
writeTGA(igl::opengl::gliGenericImage * image,FILE * fp)516 IGL_INLINE void igl::opengl::writeTGA( igl::opengl::gliGenericImage* image, FILE *fp) {
517
518 assert(!image->cmap); // we do not deal with color map images
519
520 if(image->components == 3 || image->components == 4)
521 fwrite(TGAHeaderColor, 12, sizeof(unsigned char),fp);
522 else {
523 if(image->components == 1 )
524 fwrite(TGAHeaderBW, 12, sizeof(unsigned char),fp);
525 else { fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); }
526 }
527
528 write16bit(image->width,fp);
529 write16bit(image->height,fp);
530 switch (image->components ) {
531 case 1:
532 putc(8,fp);
533 break;
534 case 3:
535 putc(24,fp);
536 break;
537 case 4:
538 putc(32,fp);
539 break;
540 default: fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1);
541 };
542
543 if(image-> components == 4)
544 putc(0x04,fp); // bottom left image (0x00) + 8 bit alpha (0x4)
545 else
546 putc(0x00,fp);
547
548 fwrite(image->pixels, image->height*image->width*image->components, sizeof(char),fp);
549 }
550
551