xref: /plan9/sys/src/cmd/jpg/readgif.c (revision 9f2726c34299ea5a81cda1b22133dd5a4b421e04)
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