/[LeafOK_CVS]/pvpgn-1.7.4/src/bniutils/tga.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bniutils/tga.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 Copyright (C) 2000 Marco Ziech (mmz@gmx.net)
3 Copyright (C) 2000 Ross Combs (rocombs@cs.nmsu.edu)
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "common/setup_before.h"
20 #include <stdio.h>
21 #ifdef STDC_HEADERS
22 # include <stdlib.h>
23 #else
24 # ifdef HAVE_MALLOC_H
25 # include <malloc.h>
26 # endif
27 #endif
28 #ifdef HAVE_STRING_H
29 # include <string.h>
30 #else
31 # ifdef HAVE_STRINGS_H
32 # include <strings.h>
33 # endif
34 #endif
35 #include <errno.h>
36 #include "compat/strerror.h"
37 #include "fileio.h"
38 #include "tga.h"
39 #include "common/setup_after.h"
40
41
42 static int rotate_updown(t_tgaimg *img);
43 static int rotate_leftright(t_tgaimg *img);
44 static int RLE_decompress(FILE *f, void *buf, int bufsize, int pixelsize);
45 static void RLE_write_pkt(FILE *f, t_tgapkttype pkttype, int len, void *data, int pixelsize);
46 static int RLE_compress(FILE *f, t_tgaimg const *img);
47
48
49 static int rotate_updown(t_tgaimg *img) {
50 unsigned char *ndata;
51 int pixelsize;
52 int y;
53 if (img == NULL) return -1;
54 if (img->data == NULL) return -1;
55 pixelsize = getpixelsize(img);
56 if (pixelsize == 0) return -1;
57 ndata = malloc(img->width*img->height*pixelsize);
58 for (y = 0; y < img->height; y++) {
59 memcpy(ndata + (y*img->width*pixelsize),
60 img->data + ((img->width*img->height*pixelsize)-((y+1)*img->width*pixelsize)),
61 img->width*pixelsize);
62 }
63 free(img->data);
64 img->data = ndata;
65 return 0;
66 }
67
68 static int rotate_leftright(t_tgaimg *img) {
69 unsigned char *ndata, *datap;
70 int pixelsize;
71 int y,x;
72 fprintf(stderr,"WARNING: rotate_leftright: this function is untested!\n");
73 if (img == NULL) return -1;
74 if (img->data == NULL) return -1;
75 pixelsize = getpixelsize(img);
76 if (pixelsize == 0) return -1;
77 ndata = malloc(img->width*img->height*pixelsize);
78 datap = img->data;
79 for (y = 0; y < img->height; y++) {
80 unsigned char *linep = (ndata + (((y+1)*img->width*pixelsize)-pixelsize));
81 for (x = 0; x < img->width; x++) {
82 memcpy(linep,datap,pixelsize);
83 linep -= pixelsize;
84 datap += pixelsize;
85 }
86 }
87 free(img->data);
88 img->data = ndata;
89
90 return 0;
91 }
92
93 extern int getpixelsize(t_tgaimg const *img) {
94 switch (img->bpp) {
95 case 8:
96 return 1;
97 case 15:
98 case 16:
99 return 2;
100 case 24:
101 return 3;
102 case 32:
103 return 4;
104 default:
105 fprintf(stderr,"load_tga: color depth %u is not supported!\n",img->bpp);
106 return 0;
107 }
108 }
109
110
111 extern t_tgaimg * new_tgaimg(unsigned int width, unsigned int height, unsigned int bpp, t_tgaimgtype imgtype) {
112 t_tgaimg *img;
113
114 img = malloc(sizeof(t_tgaimg));
115 img->idlen = 0;
116 img->cmaptype = tgacmap_none;
117 img->imgtype = imgtype;
118 img->cmapfirst = 0;
119 img->cmaplen = 0;
120 img->cmapes = 0;
121 img->xorigin = 0;
122 img->yorigin = 0;
123 img->width = width;
124 img->height = height;
125 img->bpp = bpp;
126 img->desc = 0; /* no attribute bits, top, left, and zero reserved */
127 img->data = NULL;
128 img->extareaoff = 0;
129 img->devareaoff = 0;
130
131 return img;
132 }
133
134 extern t_tgaimg * load_tgaheader(void) {
135 t_tgaimg *img;
136
137 img = malloc(sizeof(t_tgaimg));
138 img->idlen = file_readb();
139 img->cmaptype = file_readb();
140 img->imgtype = file_readb();
141 img->cmapfirst = file_readw_le();
142 img->cmaplen = file_readw_le();
143 img->cmapes = file_readb();
144 img->xorigin = file_readw_le();
145 img->yorigin = file_readw_le();
146 img->width = file_readw_le();
147 img->height = file_readw_le();
148 img->bpp = file_readb();
149 img->desc = file_readb();
150 img->data = NULL;
151 img->extareaoff = 0; /* ignored when reading */
152 img->devareaoff = 0; /* ignored when reading */
153
154 return img;
155 }
156
157 extern t_tgaimg * load_tga(FILE *f) {
158 t_tgaimg *img;
159 int pixelsize;
160
161 file_rpush(f);
162 img = load_tgaheader();
163
164 /* make sure we understand the header fields */
165 if (img->cmaptype != tgacmap_none) {
166 fprintf(stderr,"load_tga: Color-mapped images are not (yet?) supported!\n");
167 free(img);
168 return NULL;
169 }
170 if (img->imgtype!=tgaimgtype_uncompressed_truecolor && img->imgtype!=tgaimgtype_rlecompressed_truecolor) {
171 fprintf(stderr,"load_tga: imagetype %u is not supported. (only 2 and 10 are supported)\n",img->imgtype);
172 free(img);
173 return NULL;
174 }
175
176 pixelsize = getpixelsize(img);
177 if (pixelsize == 0) {
178 free(img);
179 return NULL;
180 }
181 /* Skip the ID if there is one */
182 if (img->idlen > 0) {
183 fprintf(stderr,"load_tga: ID present, skipping %d bytes\n",img->idlen);
184 if (fseek(f,img->idlen,SEEK_CUR)<0)
185 fprintf(stderr,"load_tga: could not seek %u bytes forward (fseek: %s)\n",img->idlen,pstrerror(errno));
186 }
187
188 /* Now, we can alloc img->data */
189 img->data = malloc(img->width*img->height*pixelsize);
190 if (img->imgtype == tgaimgtype_uncompressed_truecolor) {
191 if (fread(img->data,pixelsize,img->width*img->height,f)<(unsigned)(img->width*img->height)) {
192 fprintf(stderr,"load_tga: error while reading data!\n");
193 free(img->data);
194 free(img);
195 return NULL;
196 }
197 }
198 else { /* == tgaimgtype_rlecompressed_truecolor */
199 if (RLE_decompress(f,img->data,img->width*img->height*pixelsize,pixelsize) < 0) {
200 fprintf(stderr,"load_tga: error while decompressing data!\n");
201 free(img->data);
202 free(img);
203 return NULL;
204 }
205 }
206 file_rpop();
207 if ((img->desc & tgadesc_horz) == 1) { /* right, want left */
208 if (rotate_leftright(img)<0) {
209 fprintf(stderr,"ERROR: rotate_leftright failed!\n");
210 }
211 }
212 if ((img->desc & tgadesc_vert) == 0) { /* bottom, want top */
213 if (rotate_updown(img)<0) {
214 fprintf(stderr,"ERROR: rotate_updown failed!\n");
215 }
216 }
217 return img;
218 }
219
220 extern int write_tga(FILE *f, t_tgaimg *img) {
221 if (f == NULL) return -1;
222 if (img == NULL) return -1;
223 if (img->data == NULL) return -1;
224 if (img->idlen!=0) return -1;
225 if (img->cmaptype!=tgacmap_none) return -1;
226 if (img->imgtype!=tgaimgtype_uncompressed_truecolor && img->imgtype!=tgaimgtype_rlecompressed_truecolor) return -1;
227 file_wpush(f);
228
229 file_writeb(img->idlen);
230 file_writeb(img->cmaptype);
231 file_writeb(img->imgtype);
232 file_writew_le(img->cmapfirst);
233 file_writew_le(img->cmaplen);
234 file_writeb(img->cmapes);
235 file_writew_le(img->xorigin);
236 file_writew_le(img->yorigin);
237 file_writew_le(img->width);
238 file_writew_le(img->height);
239 file_writeb(img->bpp);
240 file_writeb(img->desc);
241
242 if ((img->desc&tgadesc_horz)==1) { /* right, want left */
243 fprintf(stderr,"write_tga: flipping horizontally\n");
244 if (rotate_leftright(img)<0) {
245 fprintf(stderr,"ERROR: rotate_updown failed!\n");
246 }
247 }
248 if ((img->desc&tgadesc_vert)==0) { /* bottom, want top */
249 fprintf(stderr,"write_tga: flipping vertically\n");
250 if (rotate_updown(img)<0) {
251 fprintf(stderr,"ERROR: rotate_updown failed!\n");
252 }
253 }
254 if (img->imgtype==tgaimgtype_uncompressed_truecolor) {
255 int pixelsize;
256
257 pixelsize = getpixelsize(img);
258 if (pixelsize == 0) return -1;
259 if (fwrite(img->data,pixelsize,img->width*img->height,f)<(unsigned)(img->width*img->height)) {
260 fprintf(stderr,"write_tga: could not write %d pixels (fwrite: %s)\n",img->width*img->height,pstrerror(errno));
261 file_wpop();
262 return -1;
263 }
264 } else if (img->imgtype==tgaimgtype_rlecompressed_truecolor) {
265 fprintf(stderr,"write_tga: using RLE compression\n");
266 if (RLE_compress(f,img)<0) {
267 fprintf(stderr,"write_tga: RLE compression failed.\n");
268 }
269 }
270 /* Write the file-footer */
271 file_writed_le(img->extareaoff);
272 file_writed_le(img->devareaoff);
273 if (fwrite(TGAMAGIC,strlen(TGAMAGIC)+1,1,f)<1)
274 fprintf(stderr,"write_tga: could not write TGA footer magic (fwrite: %s)\n",pstrerror(errno));
275 /* Ready */
276 file_wpop();
277 return 0;
278 }
279
280 static int RLE_decompress(FILE *f, void *buf, int bufsize, int pixelsize) {
281 unsigned char pt;
282 unsigned char *bufp;
283 unsigned char temp[8]; /* MAXPIXELSIZE */
284 int bufi;
285 int count;
286
287 file_rpush(f);
288 bufp = buf;
289 for (bufi=0; bufi<bufsize; ) {
290 pt = file_readb();
291 if (feof(f)) {
292 fprintf(stderr,"RLE_decompress: after final packet only got %d of %d bytes\n",bufi,bufsize);
293 file_rpop();
294 return -1;
295 }
296 count = (pt & 0x7f)+1;
297 if (bufi+count*pixelsize>bufsize) {
298 fprintf(stderr,"RLE_decompress: buffer too short for next packet (need %d bytes, have %d)\n",bufi+count*pixelsize,bufsize);
299 file_rpop();
300 return -1;
301 }
302 if ((pt & 0x80) == 0) { /* RAW PACKET */
303 if (fread(bufp,pixelsize,count,f)<(unsigned)count) {
304 if (feof(f))
305 fprintf(stderr,"RLE_decompress: short RAW packet (expected %d bytes) (EOF)\n",pixelsize*count);
306 else
307 fprintf(stderr,"RLE_decompress: short RAW packet (expected %d bytes) (fread: %s)\n",pixelsize*count,pstrerror(errno));
308 #if 0
309 file_rpop();
310 return -1;
311 #endif
312 }
313 bufp += count*pixelsize;
314 bufi += count*pixelsize;
315 } else { /* RLE PACKET */
316 if (fread(temp,pixelsize,1,f) < 1) {
317 if (feof(f))
318 fprintf(stderr,"RLE_decompress: short RLE packet (expected %d bytes) (EOF)\n",pixelsize);
319 else
320 fprintf(stderr,"RLE_decompress: short RLE packet (expected %d bytes) (fread: %s)\n",pixelsize,pstrerror(errno));
321 #if 0
322 file_rpop();
323 return -1;
324 #endif
325 }
326 if (count<2) {
327 fprintf(stderr,"RLE_decompress: suspicious RLE repetition count %d\n",count);
328 }
329 for (;count > 0; count--) {
330 memcpy(bufp,temp,pixelsize);
331 bufp += pixelsize;
332 bufi += pixelsize;
333 }
334 }
335 }
336 file_rpop();
337 return 0;
338 }
339
340 static void RLE_write_pkt(FILE *f, t_tgapkttype pkttype, int len, void *data, int pixelsize) {
341 unsigned char count;
342
343 if (len<1 || len>128) {
344 fprintf(stderr,"RLE_write_pkt: packet has bad length (%d bytes)\n",len);
345 return;
346 }
347 if (pkttype==RLE) {
348 if (len<2) {
349 fprintf(stderr,"RLE_write_pkt: RLE packet has bad length (%d bytes)\n",len);
350 return;
351 }
352 count = (unsigned char)(0x80 | (len-1));
353 if (fwrite(&count, 1, 1, f)<1)
354 fprintf(stderr,"RLE_write_pkt: could not write RLE pixel count (fwrite: %s)\n",pstrerror(errno));
355 if (fwrite(data, pixelsize, 1, f)<1)
356 fprintf(stderr,"RLE_write_pkt: could not write RLE pixel value (fwrite: %s)\n",pstrerror(errno));
357 } else {
358 count = (unsigned char) (len-1);
359 if (fwrite(&count, 1, 1, f)<1)
360 fprintf(stderr,"RLE_write_pkt: could not write RAW pixel count (fwrite: %s)\n",pstrerror(errno));
361 if (fwrite(data,pixelsize,len,f)<(unsigned)len)
362 fprintf(stderr,"RLE_write_pkt: could not write %d RAW pixels (fwrite: %s)\n",len,pstrerror(errno));
363 }
364 }
365
366
367 static int RLE_compress(FILE *f, t_tgaimg const *img) {
368 int pixelsize;
369 unsigned char const *datap;
370 unsigned char *pktdata;
371 unsigned int pktlen;
372 t_tgapkttype pkttype;
373 unsigned char *pktdatap;
374 unsigned int actual=0,perceived=0;
375 int i;
376
377 pkttype = RAW;
378 pktdatap = NULL;
379
380 if (img == NULL) return -1;
381 if (img->data == NULL) return -1;
382 pixelsize = getpixelsize(img);
383 if (pixelsize == 0) return -1;
384
385 datap = img->data;
386 pktdata = malloc(img->width*img->height*pixelsize);
387 pktlen = 0;
388
389 for (i=0; i<img->width*img->height; ) {
390 if (pktlen == 0) {
391 pktdatap = pktdata;
392 memcpy(pktdatap,datap,pixelsize);
393 pktlen++;
394 i++;
395 pktdatap += pixelsize;
396 datap += pixelsize;
397 pkttype = RAW;
398 continue;
399 }
400 if (pktlen == 1) {
401 if (memcmp(datap-pixelsize,datap,pixelsize)==0) {
402 pkttype = RLE;
403 }
404 }
405 if (pkttype == RLE) {
406 if (memcmp(datap-pixelsize,datap,pixelsize)!=0 || pktlen>=128) {
407 RLE_write_pkt(f,pkttype,pktlen,pktdata,pixelsize);
408 actual += 1+pixelsize;
409 perceived += pixelsize*pktlen;
410 pktlen = 0;
411 } else {
412 pktlen++;
413 i++;
414 datap += pixelsize;
415 }
416 } else {
417 if (memcmp(datap-pixelsize,datap,pixelsize)==0 || pktlen>=129) {
418 datap -= pixelsize; /* push back last pixel */
419 i--;
420 if (i<0) fprintf(stderr,"BUG!\n");
421 pktlen--;
422 RLE_write_pkt(f,pkttype,pktlen,pktdata,pixelsize);
423 actual += 1+pixelsize*pktlen;
424 perceived += pixelsize*pktlen;
425 pktlen = 0;
426 } else {
427 memcpy(pktdatap,datap,pixelsize);
428 pktlen++;
429 i++;
430 pktdatap += pixelsize;
431 datap += pixelsize;
432 }
433 }
434 }
435 if (pktlen) {
436 RLE_write_pkt(f,pkttype,pktlen,pktdata,pixelsize);
437 if (pkttype==RLE) {
438 actual += 1+pixelsize;
439 perceived += pixelsize*pktlen;
440 } else {
441 actual += 1+pixelsize*pktlen;
442 perceived += pixelsize*pktlen;
443 }
444 pktlen = 0;
445 }
446 fprintf(stderr,"RLE_compress: wrote %u bytes (%u uncompressed)\n",actual,perceived);
447 return 0;
448 }
449
450 extern void destroy_img(t_tgaimg * img) {
451 if (img == NULL) return;
452
453 if (img->data)
454 free(img->data);
455 free(img);
456 }
457
458 extern void print_tga_info(t_tgaimg const * img, FILE * fp) {
459 unsigned int interleave;
460 unsigned int attrbits;
461 char const * typestr;
462 char const * cmapstr;
463 char const * horzstr;
464 char const * vertstr;
465 char const * intlstr;
466
467 if (!img || !fp)
468 return;
469
470 interleave = ((img->desc&tgadesc_interleave1)!=0)*2+((img->desc&tgadesc_interleave2)!=0);
471 attrbits = img->desc&(tgadesc_attrbits0|tgadesc_attrbits1|tgadesc_attrbits2|tgadesc_attrbits3);
472 switch (img->imgtype) {
473 case tgaimgtype_empty:
474 typestr = "No Image Data Included";
475 break;
476 case tgaimgtype_uncompressed_mapped:
477 typestr = "Uncompressed, Color-mapped Image";
478 break;
479 case tgaimgtype_uncompressed_truecolor:
480 typestr = "Uncompressed, True-color Image";
481 break;
482 case tgaimgtype_uncompressed_monochrome:
483 typestr = "Uncompressed, Black-and-white image";
484 break;
485 case tgaimgtype_rlecompressed_mapped:
486 typestr = "Run-length encoded, Color-mapped Image";
487 break;
488 case tgaimgtype_rlecompressed_truecolor:
489 typestr = "Run-length encoded, True-color Image";
490 break;
491 case tgaimgtype_rlecompressed_monochrome:
492 typestr = "Run-length encoded, Black-and-white image";
493 break;
494 case tgaimgtype_huffman_mapped:
495 typestr = "Huffman encoded, Color-mapped image";
496 break;
497 case tgaimgtype_huffman_4pass_mapped:
498 typestr = "Four-pass Huffman encoded, Color-mapped image";
499 break;
500 default:
501 typestr = "unknown";
502 }
503 switch (img->cmaptype) {
504 case tgacmap_none:
505 cmapstr = "None";
506 break;
507 case tgacmap_included:
508 cmapstr = "Included";
509 break;
510 default:
511 cmapstr = "Unknown";
512 }
513 if ((img->desc&tgadesc_horz)==0) {
514 horzstr = "left";
515 } else {
516 horzstr = "right";
517 }
518 if ((img->desc&tgadesc_vert)==0) {
519 vertstr = "bottom";
520 } else {
521 vertstr = "top";
522 }
523 switch (interleave) {
524 case 0:
525 intlstr = "none";
526 break;
527 case 2:
528 intlstr = "two way";
529 break;
530 case 3:
531 intlstr = "four way";
532 break;
533 case 4:
534 default:
535 intlstr = "unknown";
536 break;
537 }
538
539 fprintf(fp,"TGAHeader: IDLength=%u ColorMapType=%u(%s)\n",img->idlen,img->cmaptype,cmapstr);
540 fprintf(fp,"TGAHeader: ImageType=%u(%s)\n",img->imgtype,typestr);
541 fprintf(fp,"TGAHeader: ColorMap: FirstEntryIndex=%u ColorMapLength=%u\n",img->cmapfirst,img->cmaplen);
542 fprintf(fp,"TGAHeader: ColorMap: ColorMapEntrySize=%ubits\n",img->cmapes);
543 fprintf(fp,"TGAHeader: X-origin=%u Y-origin=%u Width=%u(0x%x) Height=%u(0x%x)\n",img->xorigin,img->yorigin,img->width,img->width,img->height,img->height);
544 fprintf(fp,"TGAHeader: PixelDepth=%ubits ImageDescriptor=0x%02x(%u attribute bits, origin is %s %s, interleave=%s)\n",img->bpp,img->desc,attrbits,vertstr,horzstr,intlstr);
545 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1