1 /* zgv 5.5 - GIF, JPEG and PBM/PGM/PPM viewer, for VGA PCs running Linux.
2 * Copyright (C) 1993-2001 Russell Marks. See README for license details.
3 *
4 * readtga.c - loads TGA files (based on readpnm.c).
5 *
6 * only supports file types 1, 2, 9 and 10, since that's all I've
7 * got documentation for. If you want support for the others,
8 * write it yourself. ;-)
9 */
10
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16 #include "zgv.h"
17 #include "readtga.h"
18 #include "readpnm.h" /* for dithering routines */
19 #include "rcfile.h"
20 #include "rc_config.h"
21
22
23 /* for aborted_file_tga_cleanup() */
24 static unsigned char *work_bmap,*work_pal;
25 static FILE *work_in;
26
27 int tga_need_flip;
28
29
30 /* prototypes */
31 /* (none needed) */
32
33
34 /* convert 16-bit at ptr to 24-bit. */
fix16bit(unsigned char * ptr,int width)35 static void fix16bit(unsigned char *ptr,int width)
36 {
37 static unsigned char scaleup[32];
38 static int first=1;
39 unsigned char *src,*dst;
40
41 if(first)
42 {
43 int f;
44
45 first=0;
46 for(f=0;f<32;f++)
47 scaleup[f]=(f*255)/31;
48 }
49
50 /* does it right-to-left to avoid needing temporary buffer */
51 dst=ptr+width*3;
52 for(src=ptr+width*2;src>ptr;src-=2)
53 {
54 *--dst=scaleup[(src[-1]>>2)&31];
55 *--dst=scaleup[src[-2]>>5 | (src[-1]&3)<<3];
56 *--dst=scaleup[src[-2]&31];
57 }
58 }
59
60
read_tga_file(char * filename,hffunc howfarfunc,unsigned char ** bmap,unsigned char ** pal,int * output_type,PICINFO * pp)61 int read_tga_file(char *filename,hffunc howfarfunc,unsigned char **bmap,
62 unsigned char **pal,int *output_type,PICINFO *pp)
63 {
64 FILE *in;
65 struct tgahed hed;
66 int c,w,h,bytepp,x,y,i,cmapstart,cmaplen;
67 int rle_left=0,rle_pkt=0;
68 unsigned char rle_byte[3],*rle_ptr=NULL;
69 unsigned char *ptr;
70 int filebytepp=1;
71
72 *bmap=NULL;
73 *pal=NULL;
74
75 if((in=fopen(filename,"rb"))==NULL)
76 return(_PICERR_NOFILE);
77
78 if(fread(&hed,sizeof(hed),1,in)!=1)
79 CLOSE_AND_RET(_PICERR_BADMAGIC);
80
81 cmapstart=(hed.cmapstart_hi<<8)+hed.cmapstart_lo;
82 cmaplen =(hed.cmaplen_hi<<8) +hed.cmaplen_lo;
83
84 switch(hed.type)
85 {
86 case 1:
87 case 9:
88 bytepp=1;
89 break;
90 case 2:
91 case 10:
92 bytepp=3;
93 filebytepp=hed.bpp/8;
94 if(filebytepp<1 || filebytepp>3)
95 filebytepp=3;
96 break;
97 default:
98 CLOSE_AND_RET(_PICERR_BADMAGIC);
99 }
100
101 /* skip any id field */
102 for(i=0;i<hed.idfieldlen;i++) fgetc(in);
103
104 if((*pal=calloc(768,1))==NULL)
105 CLOSE_AND_RET(_PICERR_NOMEM);
106 else
107 {
108 int r,g,b;
109 ptr=*pal;
110
111 /* only actually used if using 8-bit display, but defined always */
112 for(r=0;r<8;r++)
113 for(g=0;g<8;g++) /* colours are 3:3:2 */
114 for(b=0;b<4;b++)
115 {
116 *ptr=r*255/7; ptr[256]=g*255/7; ptr[512]=b*255/3;
117 ptr++;
118 }
119 }
120
121 /* read colour map if there is one - note we actually skip it entirely
122 * if some hoser put a colourmap on a 24-bit file (which is possible
123 * with TGA apparently; duh, I'll have the 16 meg palette please Bob).
124 */
125 if(hed.hascmap)
126 {
127 int bytecmapd;
128 unsigned char tmp[4];
129
130 if(cmapstart+cmaplen>256)
131 CLOSE_AND_RET(_PICERR_CORRUPT); /* just in case... */
132 if(hed.cmapdepth!=16 && hed.cmapdepth!=24 && hed.cmapdepth!=32)
133 CLOSE_AND_RET(_PICERR_CORRUPT);
134
135 bytecmapd=hed.cmapdepth/8;
136 if(hed.type==2 || hed.type==10) /* supported RGB types */
137 {
138 /* skip colourmap */
139 for(i=0;i<cmaplen;i++) fread(tmp,bytecmapd,1,in);
140 }
141 else
142 {
143 /* read colourmap */
144 ptr=*pal;
145 for(i=0;i<cmaplen;i++)
146 {
147 fread(tmp,bytecmapd,1,in);
148 switch(hed.cmapdepth)
149 {
150 case 16:
151 c=((tmp[1]<<8)|tmp[0]);
152 ptr[ cmapstart+i]=(( c &31)*255)/31;
153 ptr[256+cmapstart+i]=(((c>> 5)&31)*255)/31;
154 ptr[512+cmapstart+i]=(((c>>10)&31)*255)/31;
155 case 24: case 32:
156 ptr[ cmapstart+i]=tmp[2];
157 ptr[256+cmapstart+i]=tmp[1];
158 ptr[512+cmapstart+i]=tmp[0];
159 }
160 }
161 }
162 }
163
164 w=(hed.width_hi<<8) +hed.width_lo;
165 h=(hed.height_hi<<8)+hed.height_lo;
166
167 if(w==0 || h==0)
168 CLOSE_AND_RET(_PICERR_CORRUPT);
169
170 if(bytepp==3 && (*output_type==1 || cfg.jpeg24bit==0)) /* dither? */
171 {
172 bytepp=1;
173 if(ditherinit(w)==0)
174 CLOSE_AND_RET(_PICERR_NOMEM);
175 }
176
177 /* we allocate two blank lines at the end. reason is the dithering
178 * of PPM files to 8-bit works a line at a time, and we need
179 * 3 times as much for each line, which works out only meaning
180 * 3x as much for the last line. If you see what I mean. (!?)
181 */
182 if(WH_BAD(w,h) || (*bmap=malloc(w*(h+2)*bytepp))==NULL)
183 CLOSE_AND_RET(_PICERR_NOMEM);
184
185
186 ptr=*bmap;
187
188 /* save stuff in case of abort */
189 work_in=in; work_bmap=ptr; work_pal=*pal;
190
191 tga_need_flip=(hed.desc&32)?0:1;
192
193 /* read in the image
194 * no errors are detected once we start reading.
195 * now, of course, TGA files are stored backwards. rather than
196 * try to cope with this, I *completely* ignore it until the whole
197 * image is read in, then I flip the image. :-)
198 */
199 switch(hed.type)
200 {
201 case 1: case 2:
202 /* uncompressed */
203 for(y=0;y<h;y++)
204 {
205 fread(ptr,filebytepp,w,in);
206
207 if(filebytepp==2)
208 fix16bit(ptr,w);
209
210 /* dither if required */
211 if(hed.type==2 && bytepp==1)
212 ditherline(ptr,y,w);
213
214 ptr+=bytepp*w;
215 if(howfarfunc!=NULL) howfarfunc(y,h);
216 }
217 break;
218
219 case 9: case 10:
220 /* RLE compressed */
221 rle_left=0;
222 for(y=0;y<h;y++)
223 {
224 static unsigned char buf[128*3];
225
226 for(x=0;x<w;x++)
227 {
228 if(rle_left==0)
229 {
230 c=fgetc(in);
231 rle_pkt=(c&128)?1:0;
232 rle_left=(c&127)+1;
233 if(rle_pkt)
234 fread(rle_ptr=rle_byte,filebytepp,1,in);
235 else
236 fread(rle_ptr=buf ,filebytepp,rle_left,in);
237 }
238
239 memcpy(ptr,rle_ptr,filebytepp);
240 if(!rle_pkt) rle_ptr+=filebytepp;
241 rle_left--;
242 ptr+=filebytepp;
243 }
244
245 if(filebytepp==2)
246 fix16bit(ptr-filebytepp*w,w);
247
248 /* dither if required */
249 if(hed.type==10 && bytepp==1)
250 {
251 ptr-=3*w;
252 ditherline(ptr,y,w);
253 ptr+=w;
254 }
255
256 if(howfarfunc!=NULL) howfarfunc(y,h);
257 }
258 break;
259 }
260
261 pp->width=w;
262 pp->height=h;
263 pp->numcols=256;
264
265 *output_type=bytepp;
266
267 if((hed.type==2 || hed.type==10) && bytepp==1)
268 ditherfinish();
269
270 fclose(in);
271
272 /* the image is actually flipped in vgadisp.c */
273
274 return(_PIC_OK);
275 }
276
277
aborted_file_tga_cleanup()278 void aborted_file_tga_cleanup()
279 {
280 free(work_bmap);
281 free(work_pal);
282 fclose(work_in);
283 }
284