plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

readgif.c (10249B)


      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
     53 clear(void *pp)
     54 {
     55 	void **p = (void**)pp;
     56 
     57 	if(*p){
     58 		free(*p);
     59 		*p = nil;
     60 	}
     61 }
     62 
     63 static
     64 void
     65 giffreeall(Header *h, int freeimage)
     66 {
     67 	int i;
     68 
     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 }
     88 
     89 static
     90 void
     91 giferror(Header *h, char *fmt, ...)
     92 {
     93 	va_list arg;
     94 
     95 	va_start(arg, fmt);
     96 	vseprint(h->err, h->err+sizeof h->err, fmt, arg);
     97 	va_end(arg);
     98 
     99 	werrstr(h->err);
    100 	giffreeall(h, 1);
    101 	longjmp(h->errlab, 1);
    102 }
    103 
    104 
    105 Rawimage**
    106 readgif(int fd, int colorspace)
    107 {
    108 	Rawimage **a;
    109 	Biobuf b;
    110 	Header *h;
    111 	char buf[ERRMAX];
    112 
    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;
    121 	}
    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;
    132 }
    133 
    134 static
    135 void
    136 inittbl(Header *h)
    137 {
    138 	int i;
    139 	Entry *tbl;
    140 
    141 	tbl = h->tbl;
    142 	for(i=0; i<258; i++) {
    143 		tbl[i].prefix = -1;
    144 		tbl[i].exten = i;
    145 	}
    146 }
    147 
    148 static
    149 Rawimage**
    150 readarray(Header *h)
    151 {
    152 	Entry *tbl;
    153 	Rawimage *new, **array;
    154 	int c, nimages;
    155 
    156 	tbl = h->tbl;
    157 
    158 	readheader(h);
    159 
    160 	if(h->fields & 0x80)
    161 		h->globalcmap = readcmap(h, (h->fields&7)+1);
    162 
    163 	array = malloc(sizeof(Rawimage**));
    164 	if(array == nil)
    165 		giferror(h, memerr);
    166 	nimages = 0;
    167 	array[0] = nil;
    168 	h->array = array;
    169 
    170 	for(;;){
    171 		switch(c = Bgetc(h->fd)){
    172 		case Beof:
    173 			goto Return;
    174 
    175 		case 0x21:	/* Extension (ignored) */
    176 			skipextension(h);
    177 			break;
    178 
    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);
    189 			}
    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;
    206 
    207 		case 0x3B:	/* Trailer */
    208 			goto Return;
    209 
    210 		default:
    211 			fprint(2, "ReadGIF: unknown block type: 0x%.2x\n", c);
    212 			goto Return;
    213 		}
    214 	}
    215 
    216    Return:
    217 	if(array[0]==nil || array[0]->chans[0] == nil)
    218 		giferror(h, "ReadGIF: no picture in file");
    219 
    220 	return array;
    221 }
    222 
    223 static
    224 void
    225 readheader(Header *h)
    226 {
    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;
    241 }
    242 
    243 static
    244 uchar*
    245 readcmap(Header *h, int size)
    246 {
    247 	uchar *map;
    248 
    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;
    259 }
    260 
    261 static
    262 Rawimage*
    263 readone(Header *h)
    264 {
    265 	Rawimage *i;
    266 	int left, top, width, height;
    267 
    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;
    285 }
    286 
    287 
    288 static
    289 int
    290 readdata(Header *h, uchar *data)
    291 {
    292 	int nbytes, n;
    293 
    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;
    305 }
    306 
    307 static
    308 void
    309 graphiccontrol(Header *h)
    310 {
    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];
    316 }
    317 
    318 static
    319 void
    320 skipextension(Header *h)
    321 {
    322 	int type, hsize, hasdata, n;
    323 	uchar data[256];
    324 
    325 	hsize = 0;
    326 	hasdata = 0;
    327 
    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");
    351 	}
    352 	if(hsize>0 && Bread(h->fd, h->buf, hsize) != hsize)
    353 		giferror(h, extreaderr);
    354 	if(!hasdata)
    355 		return;
    356 
    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);
    364 	}
    365 	while(readdata(h, data) != 0)
    366 		;
    367 }
    368 
    369 static
    370 uchar*
    371 decode(Header *h, Rawimage *i, Entry *tbl)
    372 {
    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];
    377 
    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);
    386 
    387 	CTM =1<<codesize;
    388 	EOD = CTM+1;
    389 
    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;
    402 
    403     Loop:
    404 	for(;;){
    405 		csize = codesize+1;
    406 		nentry = EOD+1;
    407 		maxentry = (1<<csize)-1;
    408 		first = 1;
    409 		ocode = -1;
    410 
    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;
    418 				}
    419 				c = data[datai++];
    420 				sreg |= c<<nbits;
    421 				nbits += 8;
    422 			}
    423 			code = sreg & ((1<<csize) - 1);
    424 			sreg >>= csize;
    425 			nbits -= csize;
    426 
    427 			if(code == EOD){
    428 				ndata = readdata(h, data);
    429 				if(ndata != 0)
    430 					fprint(2, "ReadGIF: unexpected data past EOD");
    431 				goto Return;
    432 			}
    433 
    434 			if(code == CTM)
    435 				goto Loop;
    436 
    437 			stacki = (sizeof stack)-1;
    438 
    439 			incode = code;
    440 
    441 			/* special case for KwKwK */
    442 			if(code == nentry) {
    443 				stack[stacki--] = fc;
    444 				code = ocode;
    445 			}
    446 
    447 			if(code > nentry)
    448 				giferror(h, "ReadGIF: bad code %x %x", code, nentry);
    449 
    450 			for(c=code; c>=0; c=tbl[c].prefix)
    451 				stack[stacki--] = tbl[c].exten;
    452 
    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 */
    457 				;
    458 			}else{
    459 				memmove(pic+pici, stack+stacki+1, sizeof stack - (stacki+1));
    460 				pici += nb;
    461 			}
    462 
    463 			fc = stack[stacki+1];
    464 
    465 			if(first){
    466 				first = 0;
    467 				continue;
    468 			}
    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--;
    477 			}
    478 			tbl[nentry].prefix = ocode;
    479 			tbl[nentry].exten = fc;
    480 			nentry++;
    481 		}
    482 	}
    483 
    484 Return:
    485 	h->pic = nil;
    486 	return pic;
    487 }
    488 
    489 static
    490 void
    491 interlace(Header *h, Rawimage *image)
    492 {
    493 	uchar *pic;
    494 	Rectangle r;
    495 	int dx, yy, y;
    496 	uchar *ipic;
    497 
    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);
    504 
    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++;
    510 	}
    511 
    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++;
    516 	}
    517 
    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++;
    522 	}
    523 
    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++;
    528 	}
    529 
    530 	free(image->chans[0]);
    531 	image->chans[0] = ipic;
    532 }