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