1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <draw.h>
5 #include "imagefile.h"
6
7 typedef struct Entry Entry;
8 typedef struct Header Header;
9
10 struct Entry{
11 int prefix;
12 int exten;
13 };
14
15
16 struct Header{
17 Biobuf *fd;
18 char err[256];
19 jmp_buf errlab;
20 uchar buf[3*256];
21 char vers[8];
22 uchar *globalcmap;
23 int screenw;
24 int screenh;
25 int fields;
26 int bgrnd;
27 int aspect;
28 int flags;
29 int delay;
30 int trindex;
31 int loopcount;
32 Entry tbl[4096];
33 Rawimage **array;
34 Rawimage *new;
35
36 uchar *pic;
37 };
38
39 static char readerr[] = "ReadGIF: read error: %r";
40 static char extreaderr[] = "ReadGIF: can't read extension: %r";
41 static char memerr[] = "ReadGIF: malloc failed: %r";
42
43 static Rawimage** readarray(Header*);
44 static Rawimage* readone(Header*);
45 static void readheader(Header*);
46 static void skipextension(Header*);
47 static uchar* readcmap(Header*, int);
48 static uchar* decode(Header*, Rawimage*, Entry*);
49 static void interlace(Header*, Rawimage*);
50
51 static
52 void
clear(void ** p)53 clear(void **p)
54 {
55 if(*p){
56 free(*p);
57 *p = nil;
58 }
59 }
60
61 static
62 void
giffreeall(Header * h,int freeimage)63 giffreeall(Header *h, int freeimage)
64 {
65 int i;
66
67 if(h->fd){
68 Bterm(h->fd);
69 h->fd = nil;
70 }
71 clear(&h->pic);
72 if(h->new){
73 clear(&h->new->cmap);
74 clear(&h->new->chans[0]);
75 clear(&h->new);
76 }
77 clear(&h->globalcmap);
78 if(freeimage && h->array!=nil){
79 for(i=0; h->array[i]; i++){
80 clear(&h->array[i]->cmap);
81 clear(&h->array[i]->chans[0]);
82 }
83 clear(&h->array);
84 }
85 }
86
87 static
88 void
giferror(Header * h,char * fmt,...)89 giferror(Header *h, char *fmt, ...)
90 {
91 va_list arg;
92
93 va_start(arg, fmt);
94 vseprint(h->err, h->err+sizeof h->err, fmt, arg);
95 va_end(arg);
96
97 werrstr(h->err);
98 giffreeall(h, 1);
99 longjmp(h->errlab, 1);
100 }
101
102
103 Rawimage**
readgif(int fd,int colorspace)104 readgif(int fd, int colorspace)
105 {
106 Rawimage **a;
107 Biobuf b;
108 Header *h;
109 char buf[ERRMAX];
110
111 buf[0] = '\0';
112 USED(colorspace);
113 if(Binit(&b, fd, OREAD) < 0)
114 return nil;
115 h = malloc(sizeof(Header));
116 if(h == nil){
117 Bterm(&b);
118 return nil;
119 }
120 memset(h, 0, sizeof(Header));
121 h->fd = &b;
122 errstr(buf, sizeof buf); /* throw it away */
123 if(setjmp(h->errlab))
124 a = nil;
125 else
126 a = readarray(h);
127 giffreeall(h, 0);
128 free(h);
129 return a;
130 }
131
132 static
133 void
inittbl(Header * h)134 inittbl(Header *h)
135 {
136 int i;
137 Entry *tbl;
138
139 tbl = h->tbl;
140 for(i=0; i<258; i++) {
141 tbl[i].prefix = -1;
142 tbl[i].exten = i;
143 }
144 }
145
146 static
147 Rawimage**
readarray(Header * h)148 readarray(Header *h)
149 {
150 Entry *tbl;
151 Rawimage *new, **array;
152 int c, nimages;
153
154 tbl = h->tbl;
155
156 readheader(h);
157
158 if(h->fields & 0x80)
159 h->globalcmap = readcmap(h, (h->fields&7)+1);
160
161 array = malloc(sizeof(Rawimage**));
162 if(array == nil)
163 giferror(h, memerr);
164 nimages = 0;
165 array[0] = nil;
166 h->array = array;
167
168 for(;;){
169 switch(c = Bgetc(h->fd)){
170 case Beof:
171 goto Return;
172
173 case 0x21: /* Extension (ignored) */
174 skipextension(h);
175 break;
176
177 case 0x2C: /* Image Descriptor */
178 inittbl(h);
179 new = readone(h);
180 if(new->fields & 0x80){
181 new->cmaplen = 3*(1<<((new->fields&7)+1));
182 new->cmap = readcmap(h, (new->fields&7)+1);
183 }else{
184 new->cmaplen = 3*(1<<((h->fields&7)+1));
185 new->cmap = malloc(new->cmaplen);
186 memmove(new->cmap, h->globalcmap, new->cmaplen);
187 }
188 h->new = new;
189 new->chans[0] = decode(h, new, tbl);
190 if(new->fields & 0x40)
191 interlace(h, new);
192 new->gifflags = h->flags;
193 new->gifdelay = h->delay;
194 new->giftrindex = h->trindex;
195 new->gifloopcount = h->loopcount;
196 array = realloc(h->array, (nimages+2)*sizeof(Rawimage*));
197 if(array == nil)
198 giferror(h, memerr);
199 array[nimages++] = new;
200 array[nimages] = nil;
201 h->array = array;
202 h->new = nil;
203 break;
204
205 case 0x3B: /* Trailer */
206 goto Return;
207
208 default:
209 fprint(2, "ReadGIF: unknown block type: 0x%.2x\n", c);
210 goto Return;
211 }
212 }
213
214 Return:
215 if(array[0]==nil || array[0]->chans[0] == nil)
216 giferror(h, "ReadGIF: no picture in file");
217
218 return array;
219 }
220
221 static
222 void
readheader(Header * h)223 readheader(Header *h)
224 {
225 if(Bread(h->fd, h->buf, 13) != 13)
226 giferror(h, "ReadGIF: can't read header: %r");
227 memmove(h->vers, h->buf, 6);
228 if(strcmp(h->vers, "GIF87a")!=0 && strcmp(h->vers, "GIF89a")!=0)
229 giferror(h, "ReadGIF: can't recognize format %s", h->vers);
230 h->screenw = h->buf[6]+(h->buf[7]<<8);
231 h->screenh = h->buf[8]+(h->buf[9]<<8);
232 h->fields = h->buf[10];
233 h->bgrnd = h->buf[11];
234 h->aspect = h->buf[12];
235 h->flags = 0;
236 h->delay = 0;
237 h->trindex = 0;
238 h->loopcount = -1;
239 }
240
241 static
242 uchar*
readcmap(Header * h,int size)243 readcmap(Header *h, int size)
244 {
245 uchar *map;
246
247 if(size > 8)
248 giferror(h, "ReadGIF: can't handles %d bits per pixel", size);
249 size = 3*(1<<size);
250 if(Bread(h->fd, h->buf, size) != size)
251 giferror(h, "ReadGIF: short read on color map");
252 map = malloc(size);
253 if(map == nil)
254 giferror(h, memerr);
255 memmove(map, h->buf, size);
256 return map;
257 }
258
259 static
260 Rawimage*
readone(Header * h)261 readone(Header *h)
262 {
263 Rawimage *i;
264 int left, top, width, height;
265
266 if(Bread(h->fd, h->buf, 9) != 9)
267 giferror(h, "ReadGIF: can't read image descriptor: %r");
268 i = malloc(sizeof(Rawimage));
269 if(i == nil)
270 giferror(h, memerr);
271 left = h->buf[0]+(h->buf[1]<<8);
272 top = h->buf[2]+(h->buf[3]<<8);
273 width = h->buf[4]+(h->buf[5]<<8);
274 height = h->buf[6]+(h->buf[7]<<8);
275 i->fields = h->buf[8];
276 i->r.min.x = left;
277 i->r.min.y = top;
278 i->r.max.x = left+width;
279 i->r.max.y = top+height;
280 i->nchans = 1;
281 i->chandesc = CRGB1;
282 memset(i->chans, 0, sizeof(i->chans));
283 return i;
284 }
285
286
287 static
288 int
readdata(Header * h,uchar * data)289 readdata(Header *h, uchar *data)
290 {
291 int nbytes, n;
292
293 nbytes = Bgetc(h->fd);
294 if(nbytes < 0)
295 giferror(h, "ReadGIF: can't read data: %r");
296 if(nbytes == 0)
297 return 0;
298 n = Bread(h->fd, data, nbytes);
299 if(n < 0)
300 giferror(h, "ReadGIF: can't read data: %r");
301 if(n != nbytes)
302 fprint(2, "ReadGIF: short data subblock\n");
303 return n;
304 }
305
306 static
307 void
graphiccontrol(Header * h)308 graphiccontrol(Header *h)
309 {
310 if(Bread(h->fd, h->buf, 5+1) != 5+1)
311 giferror(h, readerr);
312 h->flags = h->buf[1];
313 h->delay = h->buf[2]+(h->buf[3]<<8);
314 h->trindex = h->buf[4];
315 }
316
317 static
318 void
skipextension(Header * h)319 skipextension(Header *h)
320 {
321 int type, hsize, hasdata, n;
322 uchar data[256];
323
324 hsize = 0;
325 hasdata = 0;
326
327 type = Bgetc(h->fd);
328 switch(type){
329 case Beof:
330 giferror(h, extreaderr);
331 break;
332 case 0x01: /* Plain Text Extension */
333 hsize = 13;
334 hasdata = 1;
335 break;
336 case 0xF9: /* Graphic Control Extension */
337 graphiccontrol(h);
338 return;
339 case 0xFE: /* Comment Extension */
340 hasdata = 1;
341 break;
342 case 0xFF: /* Application Extension */
343 hsize = Bgetc(h->fd);
344 /* standard says this must be 11, but Adobe likes to put out 10-byte ones,
345 * so we pay attention to the field. */
346 hasdata = 1;
347 break;
348 default:
349 giferror(h, "ReadGIF: unknown extension");
350 }
351 if(hsize>0 && Bread(h->fd, h->buf, hsize) != hsize)
352 giferror(h, extreaderr);
353 if(!hasdata){
354 /*
355 * This code used to check h->buf[hsize-1] != 0
356 * and giferror if so, but if !hasdata, hsize == 0.
357 */
358 return;
359 }
360
361 /* loop counter: Application Extension with NETSCAPE2.0 as string and 1 <loop.count> in data */
362 if(type == 0xFF && hsize==11 && memcmp(h->buf, "NETSCAPE2.0", 11)==0){
363 n = readdata(h, data);
364 if(n == 0)
365 return;
366 if(n==3 && data[0]==1)
367 h->loopcount = data[1] | (data[2]<<8);
368 }
369 while(readdata(h, data) != 0)
370 ;
371 }
372
373 static
374 uchar*
decode(Header * h,Rawimage * i,Entry * tbl)375 decode(Header *h, Rawimage *i, Entry *tbl)
376 {
377 int c, doclip, incode, codesize, CTM, EOD, pici, datai, stacki, nbits, sreg, fc, code, piclen;
378 int csize, nentry, maxentry, first, ocode, ndata, nb;
379 uchar clip, *p, *pic;
380 uchar stack[4096], data[256];
381
382 if(Bread(h->fd, h->buf, 1) != 1)
383 giferror(h, "ReadGIF: can't read data: %r");
384 codesize = h->buf[0];
385 if(codesize>8 || 0>codesize)
386 giferror(h, "ReadGIF: can't handle codesize %d", codesize);
387 doclip = 0;
388 if(i->cmap!=nil && i->cmaplen!=3*(1<<codesize)
389 && (codesize!=2 || i->cmaplen!=3*2)) /* peculiar GIF bitmap files... */
390 doclip = 1;
391
392 CTM =1<<codesize;
393 EOD = CTM+1;
394
395 piclen = (i->r.max.x-i->r.min.x)*(i->r.max.y-i->r.min.y);
396 i->chanlen = piclen;
397 pic = malloc(piclen);
398 if(pic == nil)
399 giferror(h, memerr);
400 h->pic = pic;
401 pici = 0;
402 ndata = 0;
403 datai = 0;
404 nbits = 0;
405 sreg = 0;
406 fc = 0;
407
408 Loop:
409 for(;;){
410 csize = codesize+1;
411 nentry = EOD+1;
412 maxentry = (1<<csize)-1;
413 first = 1;
414 ocode = -1;
415
416 for(;; ocode = incode) {
417 while(nbits < csize) {
418 if(datai == ndata){
419 ndata = readdata(h, data);
420 if(ndata == 0)
421 goto Return;
422 datai = 0;
423 }
424 c = data[datai++];
425 sreg |= c<<nbits;
426 nbits += 8;
427 }
428 code = sreg & ((1<<csize) - 1);
429 sreg >>= csize;
430 nbits -= csize;
431
432 if(code == EOD){
433 ndata = readdata(h, data);
434 if(ndata != 0)
435 fprint(2, "ReadGIF: unexpected data past EOD\n");
436 goto Return;
437 }
438
439 if(code == CTM)
440 goto Loop;
441
442 stacki = (sizeof stack)-1;
443
444 incode = code;
445
446 /* special case for KwKwK */
447 if(code == nentry) {
448 stack[stacki--] = fc;
449 code = ocode;
450 }
451
452 if(code > nentry){
453 fprint(2, "ReadGIF: GIF invalid, code out of range, %x > %x\n", code, nentry);
454 code = nentry;
455 }
456 for(c=code; stacki>0 && c>=0; c=tbl[c].prefix)
457 stack[stacki--] = tbl[c].exten;
458
459 nb = (sizeof stack)-(stacki+1);
460 if(pici+nb > piclen){
461 /* this common error is harmless
462 * we have to keep reading to keep the blocks in sync */
463 ;
464 }else{
465 memmove(pic+pici, stack+stacki+1, sizeof stack - (stacki+1));
466 pici += nb;
467 }
468
469 fc = stack[stacki+1];
470
471 if(first){
472 first = 0;
473 continue;
474 }
475 #define early 0 /* peculiar tiff feature here for reference */
476 if(nentry == maxentry-early) {
477 if(csize >= 12)
478 continue;
479 csize++;
480 maxentry = (1<<csize);
481 if(csize < 12)
482 maxentry--;
483 }
484 tbl[nentry].prefix = ocode;
485 tbl[nentry].exten = fc;
486 nentry++;
487 }
488 }
489
490 Return:
491 if(doclip){
492 clip = i->cmaplen/3;
493 for(p = pic; p < pic+piclen; p++)
494 if(*p >= clip)
495 *p = clip;
496 }
497 h->pic = nil;
498 return pic;
499 }
500
501 static
502 void
interlace(Header * h,Rawimage * image)503 interlace(Header *h, Rawimage *image)
504 {
505 uchar *pic;
506 Rectangle r;
507 int dx, yy, y;
508 uchar *ipic;
509
510 pic = image->chans[0];
511 r = image->r;
512 dx = r.max.x-r.min.x;
513 ipic = malloc(dx*(r.max.y-r.min.y));
514 if(ipic == nil)
515 giferror(h, nil);
516
517 /* Group 1: every 8th row, starting with row 0 */
518 yy = 0;
519 for(y=r.min.y; y<r.max.y; y+=8){
520 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
521 yy++;
522 }
523
524 /* Group 2: every 8th row, starting with row 4 */
525 for(y=r.min.y+4; y<r.max.y; y+=8){
526 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
527 yy++;
528 }
529
530 /* Group 3: every 4th row, starting with row 2 */
531 for(y=r.min.y+2; y<r.max.y; y+=4){
532 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
533 yy++;
534 }
535
536 /* Group 4: every 2nd row, starting with row 1 */
537 for(y=r.min.y+1; y<r.max.y; y+=2){
538 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx);
539 yy++;
540 }
541
542 free(image->chans[0]);
543 image->chans[0] = ipic;
544 }
545