1
2 /* gif.c Decodes gif images. */
3
4 #include <stdio.h>
5 #include <stdlib.h>
6
7 #include "modules.h"
8 #include "gif.h"
9
10 #define M_TRAILER 0x3B
11 #define M_IMAGE 0x2C
12 #define M_EXTENSION 0x21
13
14 static int gif_width,gif_height;
15 static FILE *giffile;
16 static long int gif_filesize;
17 static const char *gifmarker="GIF";
18 static int gif_gctdef=0;
19 static int gif_resolution=0;
20 static int gif_colors=0;
21 static int gif_background=0;
22 static int gif_aspectratio=0;
23 static int *gif_pal;
24 static int gif_palmask;
25 static unsigned char *gif_data,*data;
26 static int gif_interlaced=0;
27 static int bitpos,maxbits;
28 static unsigned char bitbuf[256];
29 static int initcodesize,codesize,codemask,gif_ipixel,gif_iindex,
30 gif_ipassnr,gif_ipassinc;
31
32 /* prototypes */
33 void readColormap(int);
34
35
gif_readword(void)36 static int gif_readword(void)
37 {
38 return (fgetc(giffile)|(fgetc(giffile)<<8))&0xFFFF;
39 }
40
readColormap(int colors)41 void readColormap(int colors)
42 {
43 int i;
44
45 for (i=0;i<colors;i++)
46 gif_pal[i]=gif_readword()|(fgetc(giffile)<<16);
47 }
48
readCode(void)49 static int readCode(void)
50 {
51 int bits,size;
52
53 bits=size=0;
54
55 while (size<codesize) {
56 if (bitpos>=maxbits) {
57 if ((maxbits=fgetc(giffile))==EOF) return -1;
58 maxbits<<=3;
59 fread(bitbuf,1,(size_t)(maxbits>>3),giffile);
60 bitpos=0;
61 }
62 bits=bits|(((bitbuf[bitpos>>3]>>(bitpos&7))&1)<<size);
63 bitpos++;size++;
64 }
65
66 return bits & codemask;
67 }
68
saveColor(int nr)69 static void saveColor(int nr)
70 {
71 if (data-gif_data>=gif_width*gif_height) {
72 /* printf("Error: data overflow.\n"); */
73 return;
74 }
75 *data++=nr;
76
77 if (gif_interlaced) {
78 if ((++gif_ipixel)>=gif_width) {
79 gif_ipixel=0;
80 gif_iindex+=gif_ipassinc;
81 if (gif_iindex>=gif_height) {
82 switch (++gif_ipassnr) {
83 case 1:
84 gif_ipassinc=8;
85 gif_iindex=4;
86 break;
87 case 2:
88 gif_ipassinc=4;
89 gif_iindex=2;
90 break;
91 case 3:
92 gif_ipassinc=2;
93 gif_iindex=1;
94 break;
95 }
96 }
97 data=gif_data+gif_iindex*gif_width;
98 }
99 }
100 }
101
readImage(void)102 static int readImage(void)
103 {
104 int leftoffs,topoffs,info,CC,EOFC,savecode,
105 code,lastcode=0,lastchar=0,curcode,freecode,initfreecode,outcodenr;
106 int prefix[4096];
107 unsigned char suffix[4096],output[4096];
108
109 leftoffs=gif_readword();topoffs=gif_readword();
110 gif_width=gif_readword();gif_height=gif_readword();
111
112 gif_data=(unsigned char *)malloc((size_t)(gif_width*gif_height));
113
114 if (!gif_data) {
115 printf("Out of memory.\n");
116 fclose(giffile);giffile=NULL;
117 return 1;
118 }
119
120 info=fgetc(giffile);
121 gif_interlaced=info&0x40;
122 if (info&0x80) readColormap((int)1 <<((info&7)+1));
123
124 /* if (leftoffs||topoffs) {
125 printf("Warning: image offset (%i, %i)\n",leftoffs,topoffs);
126 return 1;
127 }*/
128
129 data=gif_data;
130 initcodesize=fgetc(giffile);
131 bitpos=maxbits=0;
132 CC=1<<initcodesize;
133 EOFC=CC+1;
134 freecode=initfreecode=CC+2;
135 codesize=++initcodesize;
136 codemask=(1<<codesize)-1;
137 gif_iindex=gif_ipassnr=0;
138 gif_ipassinc=8;
139 gif_ipixel=0;
140
141 if ((code=readCode())>=0)
142 while (code!=EOFC) {
143 if (code==CC) {
144 codesize=initcodesize;
145 codemask=(1<<codesize)-1;
146 freecode=initfreecode;
147 lastcode=lastchar=code=readCode();
148 if (code<0) break;
149 saveColor(code);
150 } else {
151 outcodenr=0;savecode=code;
152 if (code>=freecode) {
153 if (code>freecode) break;
154 output[(outcodenr++) & 0xFFF]=lastchar;
155 code=lastcode;
156 }
157 curcode=code;
158
159 while (curcode>gif_palmask) {
160 if (outcodenr>4095) break;
161 output[(outcodenr++)&0xFFF]=suffix[curcode];
162 curcode=prefix[curcode];
163 }
164
165 output[(outcodenr++)&0xFFF]=lastchar=curcode;
166
167 while (outcodenr>0)
168 saveColor(output[--outcodenr]);
169
170 prefix[freecode]=lastcode;
171 suffix[freecode++]=lastchar;
172 lastcode=savecode;
173
174 if (freecode>codemask) {
175 if (codesize<12) {
176 codesize++;
177 codemask=(codemask<<1)|1;
178 }
179 }
180 }
181 if ((code=readCode())<0) break;
182 }
183 return 0;
184 }
185
186 /* output size will be ignored */
GIF_OpenFile(const char * filename,const char * imgdir,unsigned int owidth,unsigned int oheight)187 int GIF_OpenFile(const char *filename,const char *imgdir,
188 unsigned int owidth, unsigned int oheight)
189 {
190 int i,marker;
191
192 UNUSED(imgdir); UNUSED(owidth); UNUSED(oheight);
193
194 gif_data=NULL;
195 gif_pal=NULL;
196 gif_width=gif_height=0;
197
198 giffile=NULL;
199 giffile=fopen(filename,"rb");
200 if (!giffile) return 0;
201
202 fseek(giffile,0,SEEK_END);
203 gif_filesize=ftell(giffile);
204 rewind(giffile);
205
206 if (gif_filesize<13) {
207 fclose(giffile);giffile=NULL;
208 return 0;
209 }
210
211 for (i=0;i<3;i++)
212 if (fgetc(giffile)!=gifmarker[i]) {
213 fclose(giffile);giffile=NULL;
214 return 0;
215 }
216
217 /* skip version info for now */
218 for (i=0;i<3;i++)
219 fgetc(giffile);
220
221 gif_width=gif_readword();
222 gif_height=gif_readword();
223
224 i=fgetc(giffile);
225 gif_gctdef=i&0x80;
226 gif_resolution=((i>>4)&7)+1;
227 gif_colors=(int)1 << ((i&7)+1);
228 gif_palmask=gif_colors-1;
229
230 gif_background=fgetc(giffile);
231 gif_aspectratio=fgetc(giffile);
232
233 if (gif_aspectratio) {
234 printf("Hmm: ASPECT RATIO given ! What to do ?\n");
235 fclose(giffile);giffile=NULL;
236 return 0;
237 }
238
239 gif_pal=malloc(256*sizeof(int));
240 if (gif_gctdef) readColormap(gif_colors);
241
242 do {
243 if ((marker=fgetc(giffile))==EOF) break;
244
245 switch (marker) {
246 case M_IMAGE:
247 readImage();fgetc(giffile);
248 break;
249 case M_EXTENSION:
250 fgetc(giffile);
251 i=fgetc(giffile);
252 while (i) {
253 while (i--) fgetc(giffile);
254 i=fgetc(giffile);
255 }
256 break;
257 case M_TRAILER:
258 break;
259 default:
260 i=fgetc(giffile);
261 while (i) {
262 while (i--) fgetc(giffile);
263 i=fgetc(giffile);
264 }
265 break;
266 }
267 } while (marker!=M_TRAILER);
268
269 fclose(giffile);giffile=NULL;
270 return 1;
271 }
272
GIF_CloseFile(void)273 void GIF_CloseFile(void)
274 {
275 if (gif_pal!=NULL) free(gif_pal);
276 if (gif_data!=NULL) free(gif_data);
277
278 if (giffile!=NULL) fclose(giffile);
279 giffile=NULL;
280 }
281
GIF_GetPixel(int x,int y,int col)282 unsigned int GIF_GetPixel(int x,int y,int col)
283 {
284 int color;
285
286 if ((x>=gif_width)||(y>=gif_height))
287 return 0x000000;
288
289 color=gif_pal[gif_data[y*gif_width+x]];
290
291 return col ? (color&0xFF00)|((color>>16)&0xFF)|((color&0xFF)<<16) :
292 (((color&0xFF)+((color>>8)&0xFF)+((color>>16)&0xFF))/3)*0x010101;
293 }
294
GIF_GetWidth(void)295 int GIF_GetWidth(void)
296 {
297 return gif_width;
298 }
299
GIF_GetHeight(void)300 int GIF_GetHeight(void)
301 {
302 return gif_height;
303 }
304