Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 **p)
54
{
55
	if(*p){
56
		free(*p);
57
		*p = nil;
58
	}
59
}
60
 
61
static
62
void
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
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**
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
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**
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
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*
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*
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
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
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
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*
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
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
}