Blob


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