| #include <u.h> | 
 | #include <libc.h> | 
 | #include <bio.h> | 
 | #include <draw.h> | 
 | #include "imagefile.h" | 
 |  | 
 | enum { | 
 | 	/* Constants, all preceded by byte 0xFF */ | 
 | 	SOF	=0xC0,	/* Start of Frame */ | 
 | 	SOF2=0xC2,	/* Start of Frame; progressive Huffman */ | 
 | 	JPG	=0xC8,	/* Reserved for JPEG extensions */ | 
 | 	DHT	=0xC4,	/* Define Huffman Tables */ | 
 | 	DAC	=0xCC,	/* Arithmetic coding conditioning */ | 
 | 	RST	=0xD0,	/* Restart interval termination */ | 
 | 	RST7	=0xD7,	/* Restart interval termination (highest value) */ | 
 | 	SOI	=0xD8,	/* Start of Image */ | 
 | 	EOI	=0xD9,	/* End of Image */ | 
 | 	SOS	=0xDA,	/* Start of Scan */ | 
 | 	DQT	=0xDB,	/* Define quantization tables */ | 
 | 	DNL	=0xDC,	/* Define number of lines */ | 
 | 	DRI	=0xDD,	/* Define restart interval */ | 
 | 	DHP	=0xDE,	/* Define hierarchical progression */ | 
 | 	EXP	=0xDF,	/* Expand reference components */ | 
 | 	APPn	=0xE0,	/* Reserved for application segments */ | 
 | 	JPGn	=0xF0,	/* Reserved for JPEG extensions */ | 
 | 	COM	=0xFE,	/* Comment */ | 
 |  | 
 | 	CLAMPOFF	= 300, | 
 | 	NCLAMP		= CLAMPOFF+700 | 
 | }; | 
 |  | 
 | typedef struct Framecomp Framecomp; | 
 | typedef struct Header Header; | 
 | typedef struct Huffman Huffman; | 
 |  | 
 | struct Framecomp	/* Frame component specifier from SOF marker */ | 
 | { | 
 | 	int	C; | 
 | 	int	H; | 
 | 	int	V; | 
 | 	int	Tq; | 
 | }; | 
 |  | 
 | struct Huffman | 
 | { | 
 | 	int	*size;	/* malloc'ed */ | 
 | 	int	*code;	/* malloc'ed */ | 
 | 	int	*val;		/* malloc'ed */ | 
 | 	int	mincode[17]; | 
 | 	int	maxcode[17]; | 
 | 	int	valptr[17]; | 
 | 	/* fast lookup */ | 
 | 	int	value[256]; | 
 | 	int	shift[256]; | 
 | }; | 
 |  | 
 |  | 
 | struct Header | 
 | { | 
 | 	Biobuf	*fd; | 
 | 	char		err[256]; | 
 | 	jmp_buf	errlab; | 
 | 	/* variables in i/o routines */ | 
 | 	int		sr;	/* shift register, right aligned */ | 
 | 	int		cnt;	/* # bits in right part of sr */ | 
 | 	uchar	*buf; | 
 | 	int		nbuf; | 
 | 	int		peek; | 
 |  | 
 | 	int		Nf; | 
 |  | 
 | 	Framecomp	comp[3]; | 
 | 	uchar	mode; | 
 | 	int		X; | 
 | 	int		Y; | 
 | 	int		qt[4][64];		/* quantization tables */ | 
 | 	Huffman	dcht[4]; | 
 | 	Huffman	acht[4]; | 
 | 	int		**data[3]; | 
 | 	int		ndata[3]; | 
 | 	 | 
 | 	uchar	*sf;	/* start of frame; do better later */ | 
 | 	uchar	*ss;	/* start of scan; do better later */ | 
 | 	int		ri;	/* restart interval */ | 
 |  | 
 | 	/* progressive scan */ | 
 | 	Rawimage *image; | 
 | 	Rawimage **array; | 
 | 	int		*dccoeff[3]; | 
 | 	int		**accoeff[3];	/* only need 8 bits plus quantization */ | 
 | 	int		naccoeff[3]; | 
 | 	int		nblock[3]; | 
 | 	int		nacross; | 
 | 	int		ndown; | 
 | 	int		Hmax; | 
 | 	int		Vmax; | 
 | }; | 
 |  | 
 | static	uchar	clamp[NCLAMP]; | 
 |  | 
 | static	Rawimage	*readslave(Header*, int); | 
 | static	int			readsegment(Header*, int*); | 
 | static	void			quanttables(Header*, uchar*, int); | 
 | static	void			huffmantables(Header*, uchar*, int); | 
 | static	void			soiheader(Header*); | 
 | static	int			nextbyte(Header*, int); | 
 | static	int			int2(uchar*, int); | 
 | static	void			nibbles(int, int*, int*); | 
 | static	int			receive(Header*, int); | 
 | static	int			receiveEOB(Header*, int); | 
 | static	int			receivebit(Header*); | 
 | static	void			restart(Header*, int); | 
 | static	int			decode(Header*, Huffman*); | 
 | static	Rawimage*	baselinescan(Header*, int); | 
 | static	void			progressivescan(Header*, int); | 
 | static	Rawimage*	progressiveIDCT(Header*, int); | 
 | static	void			idct(int*); | 
 | static	void			colormap1(Header*, int, Rawimage*, int*, int, int); | 
 | static	void			colormapall1(Header*, int, Rawimage*, int*, int*, int*, int, int); | 
 | static	void			colormap(Header*, int, Rawimage*, int**, int**, int**, int, int, int, int, int*, int*); | 
 | static	void			jpgerror(Header*, char*, ...); | 
 |  | 
 | static	char		readerr[] = "ReadJPG: read error: %r"; | 
 | static	char		memerr[] = "ReadJPG: malloc failed: %r"; | 
 |  | 
 | static	int zig[64] = { | 
 | 	0, 1, 8, 16, 9, 2, 3, 10, 17, /* 0-7 */ | 
 | 	24, 32, 25, 18, 11, 4, 5, /* 8-15 */ | 
 | 	12, 19, 26, 33, 40, 48, 41, 34, /* 16-23 */ | 
 | 	27, 20, 13, 6, 7, 14, 21, 28, /* 24-31 */ | 
 | 	35, 42, 49, 56, 57, 50, 43, 36, /* 32-39 */ | 
 | 	29, 22, 15, 23, 30, 37, 44, 51, /* 40-47 */ | 
 | 	58, 59, 52, 45, 38, 31, 39, 46, /* 48-55 */ | 
 | 	53, 60, 61, 54, 47, 55, 62, 63 /* 56-63 */ | 
 | }; | 
 |  | 
 | static | 
 | void | 
 | jpginit(void) | 
 | { | 
 | 	int k; | 
 | 	static int inited; | 
 |  | 
 | 	if(inited) | 
 | 		return; | 
 | 	inited = 1; | 
 | 	for(k=0; k<CLAMPOFF; k++) | 
 | 		clamp[k] = 0; | 
 | 	for(; k<CLAMPOFF+256; k++) | 
 | 		clamp[k] = k-CLAMPOFF; | 
 | 	for(; k<NCLAMP; k++) | 
 | 		clamp[k] = 255; | 
 | } | 
 |  | 
 | static | 
 | void* | 
 | jpgmalloc(Header *h, int n, int clear) | 
 | { | 
 | 	void *p; | 
 |  | 
 | 	p = malloc(n); | 
 | 	if(p == nil) | 
 | 		jpgerror(h, memerr); | 
 | 	if(clear) | 
 | 		memset(p, 0, n); | 
 | 	return p; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | clear(void *pp) | 
 | { | 
 | 	void **p = (void**)pp; | 
 |  | 
 | 	if(*p){ | 
 | 		free(*p); | 
 | 		*p = nil; | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | jpgfreeall(Header *h, int freeimage) | 
 | { | 
 | 	int i, j; | 
 |  | 
 | 	clear(&h->buf); | 
 | 	if(h->dccoeff[0]) | 
 | 		for(i=0; i<3; i++) | 
 | 			clear(&h->dccoeff[i]); | 
 | 	if(h->accoeff[0]) | 
 | 		for(i=0; i<3; i++){ | 
 | 			if(h->accoeff[i]) | 
 | 				for(j=0; j<h->naccoeff[i]; j++) | 
 | 					clear(&h->accoeff[i][j]); | 
 | 			clear(&h->accoeff[i]); | 
 | 		} | 
 | 	for(i=0; i<4; i++){ | 
 | 		clear(&h->dcht[i].size); | 
 | 		clear(&h->acht[i].size); | 
 | 		clear(&h->dcht[i].code); | 
 | 		clear(&h->acht[i].code); | 
 | 		clear(&h->dcht[i].val); | 
 | 		clear(&h->acht[i].val); | 
 | 	} | 
 | 	if(h->data[0]) | 
 | 		for(i=0; i<3; i++){ | 
 | 			if(h->data[i]) | 
 | 				for(j=0; j<h->ndata[i]; j++) | 
 | 					clear(&h->data[i][j]); | 
 | 			clear(&h->data[i]); | 
 | 		} | 
 | 	if(freeimage && h->image!=nil){ | 
 | 		clear(&h->array); | 
 | 		clear(&h->image->cmap); | 
 | 		for(i=0; i<3; i++) | 
 | 			clear(&h->image->chans[i]); | 
 | 		clear(&h->image); | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | jpgerror(Header *h, char *fmt, ...) | 
 | { | 
 | 	va_list arg; | 
 |  | 
 | 	va_start(arg, fmt); | 
 | 	vseprint(h->err, h->err+sizeof h->err, fmt, arg); | 
 | 	va_end(arg); | 
 |  | 
 | 	werrstr(h->err); | 
 | 	jpgfreeall(h, 1); | 
 | 	longjmp(h->errlab, 1); | 
 | } | 
 |  | 
 | Rawimage** | 
 | Breadjpg(Biobuf *b, int colorspace) | 
 | { | 
 | 	Rawimage *r, **array; | 
 | 	Header *h; | 
 | 	char buf[ERRMAX]; | 
 |  | 
 | 	buf[0] = '\0'; | 
 | 	if(colorspace!=CYCbCr && colorspace!=CRGB){ | 
 | 		errstr(buf, sizeof buf);	/* throw it away */ | 
 | 		werrstr("ReadJPG: unknown color space"); | 
 | 		return nil; | 
 | 	} | 
 | 	jpginit(); | 
 | 	h = malloc(sizeof(Header)); | 
 | 	array = malloc(sizeof(Header)); | 
 | 	if(h==nil || array==nil){ | 
 | 		free(h); | 
 | 		free(array); | 
 | 		return nil; | 
 | 	} | 
 | 	h->array = array; | 
 | 	memset(h, 0, sizeof(Header)); | 
 | 	h->fd = b; | 
 | 	errstr(buf, sizeof buf);	/* throw it away */ | 
 | 	if(setjmp(h->errlab)) | 
 | 		r = nil; | 
 | 	else | 
 | 		r = readslave(h, colorspace); | 
 | 	jpgfreeall(h, 0); | 
 | 	free(h); | 
 | 	array[0] = r; | 
 | 	array[1] = nil; | 
 | 	return array; | 
 | } | 
 |  | 
 | Rawimage** | 
 | readjpg(int fd, int colorspace) | 
 | { | 
 | 	Rawimage** a; | 
 | 	Biobuf b; | 
 |  | 
 | 	if(Binit(&b, fd, OREAD) < 0) | 
 | 		return nil; | 
 | 	a = Breadjpg(&b, colorspace); | 
 | 	Bterm(&b); | 
 | 	return a; | 
 | } | 
 |  | 
 | static | 
 | Rawimage* | 
 | readslave(Header *header, int colorspace) | 
 | { | 
 | 	Rawimage *image; | 
 | 	int nseg, i, H, V, m, n; | 
 | 	uchar *b; | 
 |  | 
 | 	soiheader(header); | 
 | 	nseg = 0; | 
 | 	image = nil; | 
 |  | 
 | 	header->buf = jpgmalloc(header, 4096, 0); | 
 | 	header->nbuf = 4096; | 
 | 	while(header->err[0] == '\0'){ | 
 | 		nseg++; | 
 | 		n = readsegment(header, &m); | 
 | 		b = header->buf; | 
 | 		switch(m){ | 
 | 		case -1: | 
 | 			return image; | 
 |  | 
 | 		case APPn+0: | 
 | 			if(nseg==1 && strncmp((char*)b, "JFIF", 4)==0)  /* JFIF header; check version */ | 
 | 				if(b[5]>1 || b[6]>2) | 
 | 					sprint(header->err, "ReadJPG: can't handle JFIF version %d.%2d", b[5], b[6]); | 
 | 			break; | 
 |  | 
 | 		case APPn+1: case APPn+2: case APPn+3: case APPn+4: case APPn+5: | 
 | 		case APPn+6: case APPn+7: case APPn+8: case APPn+9: case APPn+10: | 
 | 		case APPn+11: case APPn+12: case APPn+13: case APPn+14: case APPn+15: | 
 | 			break; | 
 |  | 
 | 		case DQT: | 
 | 			quanttables(header, b, n); | 
 | 			break; | 
 |  | 
 | 		case SOF: | 
 | 		case SOF2: | 
 | 			header->Y = int2(b, 1); | 
 | 			header->X = int2(b, 3); | 
 | 			header->Nf =b[5]; | 
 | 			for(i=0; i<header->Nf; i++){ | 
 | 				header->comp[i].C = b[6+3*i+0]; | 
 | 				nibbles(b[6+3*i+1], &H, &V); | 
 | 				if(H<=0 || V<=0) | 
 | 					jpgerror(header, "non-positive sampling factor (Hsamp or Vsamp)"); | 
 | 				header->comp[i].H = H; | 
 | 				header->comp[i].V = V; | 
 | 				header->comp[i].Tq = b[6+3*i+2]; | 
 | 			} | 
 | 			header->mode = m; | 
 | 			header->sf = b; | 
 | 			break; | 
 |  | 
 | 		case  SOS: | 
 | 			header->ss = b; | 
 | 			switch(header->mode){ | 
 | 			case SOF: | 
 | 				image = baselinescan(header, colorspace); | 
 | 				break; | 
 | 			case SOF2: | 
 | 				progressivescan(header, colorspace); | 
 | 				break; | 
 | 			default: | 
 | 				sprint(header->err, "unrecognized or unspecified encoding %d", header->mode); | 
 | 				break; | 
 | 			} | 
 | 			break; | 
 |  | 
 | 		case  DHT: | 
 | 			huffmantables(header, b, n); | 
 | 			break; | 
 |  | 
 | 		case  DRI: | 
 | 			header->ri = int2(b, 0); | 
 | 			break; | 
 |  | 
 | 		case  COM: | 
 | 			break; | 
 |  | 
 | 		case EOI: | 
 | 			if(header->mode == SOF2) | 
 | 				image = progressiveIDCT(header, colorspace); | 
 | 			return image; | 
 |  | 
 | 		default: | 
 | 			sprint(header->err, "ReadJPG: unknown marker %.2x", m); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | 	return image; | 
 | } | 
 |  | 
 | /* readsegment is called after reading scan, which can have */ | 
 | /* read ahead a byte.  so we must check peek here */ | 
 | static | 
 | int | 
 | readbyte(Header *h) | 
 | { | 
 | 	uchar x; | 
 |  | 
 | 	if(h->peek >= 0){ | 
 | 		x = h->peek; | 
 | 		h->peek = -1; | 
 | 	}else if(Bread(h->fd, &x, 1) != 1) | 
 | 		jpgerror(h, readerr); | 
 | 	return x; | 
 | } | 
 |  | 
 | static | 
 | int | 
 | marker(Header *h) | 
 | { | 
 | 	int c; | 
 |  | 
 | 	while((c=readbyte(h)) == 0) | 
 | 		fprint(2, "ReadJPG: skipping zero byte at offset %lld\n", Boffset(h->fd)); | 
 | 	if(c != 0xFF) | 
 | 		jpgerror(h, "ReadJPG: expecting marker; found 0x%x at offset %lld\n", c, Boffset(h->fd)); | 
 | 	while(c == 0xFF) | 
 | 		c = readbyte(h); | 
 | 	return c; | 
 | } | 
 |  | 
 | static | 
 | int | 
 | int2(uchar *buf, int n) | 
 | { | 
 | 	return (buf[n]<<8) + buf[n+1]; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | nibbles(int b, int *p0, int *p1) | 
 | { | 
 | 	*p0 = (b>>4) & 0xF; | 
 | 	*p1 = b & 0xF; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | soiheader(Header *h) | 
 | { | 
 | 	h->peek = -1; | 
 | 	if(marker(h) != SOI) | 
 | 		jpgerror(h, "ReadJPG: unrecognized marker in header"); | 
 | 	h->err[0] = '\0'; | 
 | 	h->mode = 0; | 
 | 	h->ri = 0; | 
 | } | 
 |  | 
 | static | 
 | int | 
 | readsegment(Header *h, int *markerp) | 
 | { | 
 | 	int m, n; | 
 | 	uchar tmp[2]; | 
 |  | 
 | 	m = marker(h); | 
 | 	switch(m){ | 
 | 	case EOI: | 
 | 		*markerp = m; | 
 | 		return 0; | 
 | 	case 0: | 
 | 		jpgerror(h, "ReadJPG: expecting marker; saw %.2x at offset %lld", m, Boffset(h->fd)); | 
 | 	} | 
 | 	if(Bread(h->fd, tmp, 2) != 2) | 
 |     Readerr: | 
 | 		jpgerror(h, readerr); | 
 | 	n = int2(tmp, 0); | 
 | 	if(n < 2) | 
 | 		goto Readerr; | 
 | 	n -= 2; | 
 | 	if(n > h->nbuf){ | 
 | 		free(h->buf); | 
 | 		h->buf = jpgmalloc(h, n+1, 0); /* +1 for sentinel */ | 
 | 		h->nbuf = n; | 
 | 	} | 
 | 	if(Bread(h->fd, h->buf, n) != n) | 
 | 		goto Readerr; | 
 | 	*markerp = m; | 
 | 	return n; | 
 | } | 
 |  | 
 | static | 
 | int | 
 | huffmantable(Header *h, uchar *b) | 
 | { | 
 | 	Huffman *t; | 
 | 	int Tc, th, n, nsize, i, j, k, v, cnt, code, si, sr, m; | 
 | 	int *maxcode; | 
 |  | 
 | 	nibbles(b[0], &Tc, &th); | 
 | 	if(Tc > 1) | 
 | 		jpgerror(h, "ReadJPG: unknown Huffman table class %d", Tc); | 
 | 	if(th>3 || (h->mode==SOF && th>1)) | 
 | 		jpgerror(h, "ReadJPG: unknown Huffman table index %d", th); | 
 | 	if(Tc == 0) | 
 | 		t = &h->dcht[th]; | 
 | 	else | 
 | 		t = &h->acht[th]; | 
 |  | 
 | 	/* flow chart C-2 */ | 
 | 	nsize = 0; | 
 | 	for(i=0; i<16; i++) | 
 | 		nsize += b[1+i]; | 
 | 	t->size = jpgmalloc(h, (nsize+1)*sizeof(int), 1); | 
 | 	k = 0; | 
 | 	for(i=1; i<=16; i++){ | 
 | 		n = b[i]; | 
 | 		for(j=0; j<n; j++) | 
 | 			t->size[k++] = i; | 
 | 	} | 
 | 	t->size[k] = 0; | 
 |  | 
 | 	/* initialize HUFFVAL */ | 
 | 	t->val = jpgmalloc(h, nsize*sizeof(int), 1); | 
 | 	for(i=0; i<nsize; i++) | 
 | 		t->val[i] = b[17+i]; | 
 |  | 
 | 	/* flow chart C-3 */ | 
 | 	t->code = jpgmalloc(h, (nsize+1)*sizeof(int), 1); | 
 | 	k = 0; | 
 | 	code = 0; | 
 | 	si = t->size[0]; | 
 | 	for(;;){ | 
 | 		do | 
 | 			t->code[k++] = code++; | 
 | 		while(t->size[k] == si); | 
 | 		if(t->size[k] == 0) | 
 | 			break; | 
 | 		do{ | 
 | 			code <<= 1; | 
 | 			si++; | 
 | 		}while(t->size[k] != si); | 
 | 	} | 
 |  | 
 | 	/* flow chart F-25 */ | 
 | 	i = 0; | 
 | 	j = 0; | 
 | 	for(;;){ | 
 | 		for(;;){ | 
 | 			i++; | 
 | 			if(i > 16) | 
 | 				goto outF25; | 
 | 			if(b[i] != 0) | 
 | 				break; | 
 | 			t->maxcode[i] = -1; | 
 | 		} | 
 | 		t->valptr[i] = j; | 
 | 		t->mincode[i] = t->code[j]; | 
 | 		j += b[i]-1; | 
 | 		t->maxcode[i] = t->code[j]; | 
 | 		j++; | 
 | 	} | 
 | outF25: | 
 |  | 
 | 	/* create byte-indexed fast path tables */ | 
 | 	maxcode = t->maxcode; | 
 | 	/* stupid startup algorithm: just run machine for each byte value */ | 
 | 	for(v=0; v<256; ){ | 
 | 		cnt = 7; | 
 | 		m = 1<<7; | 
 | 		code = 0; | 
 | 		sr = v; | 
 | 		i = 1; | 
 | 		for(;;i++){ | 
 | 			if(sr & m) | 
 | 				code |= 1; | 
 | 			if(code <= maxcode[i]) | 
 | 				break; | 
 | 			code <<= 1; | 
 | 			m >>= 1; | 
 | 			if(m == 0){ | 
 | 				t->shift[v] = 0; | 
 | 				t->value[v] = -1; | 
 | 				goto continueBytes; | 
 | 			} | 
 | 			cnt--; | 
 | 		} | 
 | 		t->shift[v] = 8-cnt; | 
 | 		t->value[v] = t->val[t->valptr[i]+(code-t->mincode[i])]; | 
 |  | 
 |     continueBytes: | 
 | 		v++; | 
 | 	} | 
 |  | 
 | 	return nsize; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | huffmantables(Header *h, uchar *b, int n) | 
 | { | 
 | 	int l, mt; | 
 |  | 
 | 	for(l=0; l<n; l+=17+mt) | 
 | 		mt = huffmantable(h, &b[l]); | 
 | } | 
 |  | 
 | static | 
 | int | 
 | quanttable(Header *h, uchar *b) | 
 | { | 
 | 	int i, pq, tq, *q; | 
 |  | 
 | 	nibbles(b[0], &pq, &tq); | 
 | 	if(pq > 1) | 
 | 		jpgerror(h, "ReadJPG: unknown quantization table class %d", pq); | 
 | 	if(tq > 3) | 
 | 		jpgerror(h, "ReadJPG: unknown quantization table index %d", tq); | 
 | 	q = h->qt[tq]; | 
 | 	for(i=0; i<64; i++){ | 
 | 		if(pq == 0) | 
 | 			q[i] = b[1+i]; | 
 | 		else | 
 | 			q[i] = int2(b, 1+2*i); | 
 | 	} | 
 | 	return 64*(1+pq); | 
 | } | 
 |  | 
 | static | 
 | void | 
 | quanttables(Header *h, uchar *b, int n) | 
 | { | 
 | 	int l, m; | 
 |  | 
 | 	for(l=0; l<n; l+=1+m) | 
 | 		m = quanttable(h, &b[l]); | 
 | } | 
 |  | 
 | static | 
 | Rawimage* | 
 | baselinescan(Header *h, int colorspace) | 
 | { | 
 | 	int Ns, z, k, m, Hmax, Vmax, comp; | 
 | 	int allHV1, nblock, ri, mcu, nacross, nmcu; | 
 | 	Huffman *dcht, *acht; | 
 | 	int block, t, diff, *qt; | 
 | 	uchar *ss; | 
 | 	Rawimage *image; | 
 | 	int Td[3], Ta[3], H[3], V[3], DC[3]; | 
 | 	int ***data, *zz; | 
 |  | 
 | 	ss = h->ss; | 
 | 	Ns = ss[0]; | 
 | 	if((Ns!=3 && Ns!=1) || Ns!=h->Nf) | 
 | 		jpgerror(h, "ReadJPG: can't handle scan not 3 components"); | 
 |  | 
 | 	image = jpgmalloc(h, sizeof(Rawimage), 1); | 
 | 	h->image = image; | 
 | 	image->r = Rect(0, 0, h->X, h->Y); | 
 | 	image->cmap = nil; | 
 | 	image->cmaplen = 0; | 
 | 	image->chanlen = h->X*h->Y; | 
 | 	image->fields = 0; | 
 | 	image->gifflags = 0; | 
 | 	image->gifdelay = 0; | 
 | 	image->giftrindex = 0; | 
 | 	if(Ns == 3) | 
 | 		image->chandesc = colorspace; | 
 | 	else | 
 | 		image->chandesc = CY; | 
 | 	image->nchans = h->Nf; | 
 | 	for(k=0; k<h->Nf; k++) | 
 | 		image->chans[k] = jpgmalloc(h, h->X*h->Y, 0); | 
 |  | 
 | 	/* compute maximum H and V */ | 
 | 	Hmax = 0; | 
 | 	Vmax = 0; | 
 | 	for(comp=0; comp<Ns; comp++){ | 
 | 		if(h->comp[comp].H > Hmax) | 
 | 			Hmax = h->comp[comp].H; | 
 | 		if(h->comp[comp].V > Vmax) | 
 | 			Vmax = h->comp[comp].V; | 
 | 	} | 
 |  | 
 | 	/* initialize data structures */ | 
 | 	allHV1 = 1; | 
 | 	data = h->data; | 
 | 	for(comp=0; comp<Ns; comp++){ | 
 | 		/* JPEG requires scan components to be in same order as in frame, */ | 
 | 		/* so if both have 3 we know scan is Y Cb Cr and there's no need to */ | 
 | 		/* reorder */ | 
 | 		nibbles(ss[2+2*comp], &Td[comp], &Ta[comp]); | 
 | 		H[comp] = h->comp[comp].H; | 
 | 		V[comp] = h->comp[comp].V; | 
 | 		nblock = H[comp]*V[comp]; | 
 | 		if(nblock != 1) | 
 | 			allHV1 = 0; | 
 | 		data[comp] = jpgmalloc(h, nblock*sizeof(int*), 0); | 
 | 		h->ndata[comp] = nblock; | 
 | 		DC[comp] = 0; | 
 | 		for(m=0; m<nblock; m++) | 
 | 			data[comp][m] = jpgmalloc(h, 8*8*sizeof(int), 0); | 
 | 	} | 
 |  | 
 | 	ri = h->ri; | 
 |  | 
 | 	h->cnt = 0; | 
 | 	h->sr = 0; | 
 | 	h->peek = -1; | 
 | 	nacross = ((h->X+(8*Hmax-1))/(8*Hmax)); | 
 | 	nmcu = ((h->Y+(8*Vmax-1))/(8*Vmax))*nacross; | 
 | 	for(mcu=0; mcu<nmcu; ){ | 
 | 		for(comp=0; comp<Ns; comp++){ | 
 | 			dcht = &h->dcht[Td[comp]]; | 
 | 			acht = &h->acht[Ta[comp]]; | 
 | 			qt = h->qt[h->comp[comp].Tq]; | 
 |  | 
 | 			for(block=0; block<H[comp]*V[comp]; block++){ | 
 | 				/* F-22 */ | 
 | 				t = decode(h, dcht); | 
 | 				diff = receive(h, t); | 
 | 				DC[comp] += diff; | 
 |  | 
 | 				/* F-23 */ | 
 | 				zz = data[comp][block]; | 
 | 				memset(zz, 0, 8*8*sizeof(int)); | 
 | 				zz[0] = qt[0]*DC[comp]; | 
 | 				k = 1; | 
 |  | 
 | 				for(;;){ | 
 | 					t = decode(h, acht); | 
 | 					if((t&0x0F) == 0){ | 
 | 						if((t&0xF0) != 0xF0) | 
 | 							break; | 
 | 						k += 16; | 
 | 					}else{ | 
 | 						k += t>>4; | 
 | 						z = receive(h, t&0xF); | 
 | 						zz[zig[k]] = z*qt[k]; | 
 | 						if(k == 63) | 
 | 							break; | 
 | 						k++; | 
 | 					} | 
 | 				} | 
 |  | 
 | 				idct(zz); | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* rotate colors to RGB and assign to bytes */ | 
 | 		if(Ns == 1) /* very easy */ | 
 | 			colormap1(h, colorspace, image, data[0][0], mcu, nacross); | 
 | 		else if(allHV1) /* fairly easy */ | 
 | 			colormapall1(h, colorspace, image, data[0][0], data[1][0], data[2][0], mcu, nacross); | 
 | 		else /* miserable general case */ | 
 | 			colormap(h, colorspace, image, data[0], data[1], data[2], mcu, nacross, Hmax, Vmax, H, V); | 
 | 		/* process restart marker, if present */ | 
 | 		mcu++; | 
 | 		if(ri>0 && mcu<nmcu && mcu%ri==0){ | 
 | 			restart(h, mcu); | 
 | 			for(comp=0; comp<Ns; comp++) | 
 | 				DC[comp] = 0; | 
 | 		} | 
 | 	} | 
 | 	return image; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | restart(Header *h, int mcu) | 
 | { | 
 | 	int rest, rst, nskip; | 
 |  | 
 | 	rest = mcu/h->ri-1; | 
 | 	nskip = 0; | 
 | 	do{ | 
 | 		do{ | 
 | 			rst = nextbyte(h, 1); | 
 | 			nskip++; | 
 | 		}while(rst>=0 && rst!=0xFF); | 
 | 		if(rst == 0xFF){ | 
 | 			rst = nextbyte(h, 1); | 
 | 			nskip++; | 
 | 		} | 
 | 	}while(rst>=0 && (rst&~7)!=RST); | 
 | 	if(nskip != 2) | 
 | 		sprint(h->err, "ReadJPG: skipped %d bytes at restart %d\n", nskip-2, rest); | 
 | 	if(rst < 0) | 
 | 		jpgerror(h, readerr); | 
 | 	if((rst&7) != (rest&7)) | 
 | 		jpgerror(h, "ReadJPG: expected RST%d got %d", rest&7, rst&7); | 
 | 	h->cnt = 0; | 
 | 	h->sr = 0; | 
 | } | 
 |  | 
 | static | 
 | Rawimage* | 
 | progressiveIDCT(Header *h, int colorspace) | 
 | { | 
 | 	int k, m, comp, block, Nf, bn; | 
 | 	int allHV1, nblock, mcu, nmcu; | 
 | 	int H[3], V[3], blockno[3]; | 
 | 	int *dccoeff, **accoeff; | 
 | 	int ***data, *zz; | 
 |  | 
 | 	Nf = h->Nf; | 
 | 	allHV1 = 1; | 
 | 	data = h->data; | 
 |  | 
 | 	for(comp=0; comp<Nf; comp++){ | 
 | 		H[comp] = h->comp[comp].H; | 
 | 		V[comp] = h->comp[comp].V; | 
 | 		nblock = h->nblock[comp]; | 
 | 		if(nblock != 1) | 
 | 			allHV1 = 0; | 
 | 		h->ndata[comp] = nblock; | 
 | 		data[comp] = jpgmalloc(h, nblock*sizeof(int*), 0); | 
 | 		for(m=0; m<nblock; m++) | 
 | 			data[comp][m] = jpgmalloc(h, 8*8*sizeof(int), 0); | 
 | 	} | 
 |  | 
 | 	memset(blockno, 0, sizeof blockno); | 
 | 	nmcu = h->nacross*h->ndown; | 
 | 	for(mcu=0; mcu<nmcu; mcu++){ | 
 | 		for(comp=0; comp<Nf; comp++){ | 
 | 			dccoeff = h->dccoeff[comp]; | 
 | 			accoeff = h->accoeff[comp]; | 
 | 			bn = blockno[comp]; | 
 | 			for(block=0; block<h->nblock[comp]; block++){ | 
 | 				zz = data[comp][block]; | 
 | 				memset(zz, 0, 8*8*sizeof(int)); | 
 | 				zz[0] = dccoeff[bn]; | 
 |  | 
 | 				for(k=1; k<64; k++) | 
 | 					zz[zig[k]] = accoeff[bn][k]; | 
 |  | 
 | 				idct(zz); | 
 | 				bn++; | 
 | 			} | 
 | 			blockno[comp] = bn; | 
 | 		} | 
 |  | 
 | 		/* rotate colors to RGB and assign to bytes */ | 
 | 		if(Nf == 1) /* very easy */ | 
 | 			colormap1(h, colorspace, h->image, data[0][0], mcu, h->nacross); | 
 | 		else if(allHV1) /* fairly easy */ | 
 | 			colormapall1(h, colorspace, h->image, data[0][0], data[1][0], data[2][0], mcu, h->nacross); | 
 | 		else /* miserable general case */ | 
 | 			colormap(h, colorspace, h->image, data[0], data[1], data[2], mcu, h->nacross, h->Hmax, h->Vmax, H, V); | 
 | 	} | 
 |  | 
 | 	return h->image; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | progressiveinit(Header *h, int colorspace) | 
 | { | 
 | 	int Nf, Ns, j, k, nmcu, comp; | 
 | 	uchar *ss; | 
 | 	Rawimage *image; | 
 |  | 
 | 	ss = h->ss; | 
 | 	Ns = ss[0]; | 
 | 	Nf = h->Nf; | 
 | 	if((Ns!=3 && Ns!=1) || Ns!=Nf) | 
 | 		jpgerror(h, "ReadJPG: image must have 1 or 3 components"); | 
 |  | 
 | 	image = jpgmalloc(h, sizeof(Rawimage), 1); | 
 | 	h->image = image; | 
 | 	image->r = Rect(0, 0, h->X, h->Y); | 
 | 	image->cmap = nil; | 
 | 	image->cmaplen = 0; | 
 | 	image->chanlen = h->X*h->Y; | 
 | 	image->fields = 0; | 
 | 	image->gifflags = 0; | 
 | 	image->gifdelay = 0; | 
 | 	image->giftrindex = 0; | 
 | 	if(Nf == 3) | 
 | 		image->chandesc = colorspace; | 
 | 	else | 
 | 		image->chandesc = CY; | 
 | 	image->nchans = h->Nf; | 
 | 	for(k=0; k<Nf; k++){ | 
 | 		image->chans[k] = jpgmalloc(h, h->X*h->Y, 0); | 
 | 		h->nblock[k] = h->comp[k].H*h->comp[k].V; | 
 | 	} | 
 |  | 
 | 	/* compute maximum H and V */ | 
 | 	h->Hmax = 0; | 
 | 	h->Vmax = 0; | 
 | 	for(comp=0; comp<Nf; comp++){ | 
 | 		if(h->comp[comp].H > h->Hmax) | 
 | 			h->Hmax = h->comp[comp].H; | 
 | 		if(h->comp[comp].V > h->Vmax) | 
 | 			h->Vmax = h->comp[comp].V; | 
 | 	} | 
 | 	h->nacross = ((h->X+(8*h->Hmax-1))/(8*h->Hmax)); | 
 | 	h->ndown = ((h->Y+(8*h->Vmax-1))/(8*h->Vmax)); | 
 | 	nmcu = h->nacross*h->ndown; | 
 |  | 
 | 	for(k=0; k<Nf; k++){ | 
 | 		h->dccoeff[k] = jpgmalloc(h, h->nblock[k]*nmcu * sizeof(int), 1); | 
 | 		h->accoeff[k] = jpgmalloc(h, h->nblock[k]*nmcu * sizeof(int*), 1); | 
 | 		h->naccoeff[k] = h->nblock[k]*nmcu; | 
 | 		for(j=0; j<h->nblock[k]*nmcu; j++) | 
 | 			h->accoeff[k][j] = jpgmalloc(h, 64*sizeof(int), 1); | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | static | 
 | void | 
 | progressivedc(Header *h, int comp, int Ah, int Al) | 
 | { | 
 | 	int Ns, z, ri, mcu,  nmcu; | 
 | 	int block, t, diff, qt, *dc, bn; | 
 | 	Huffman *dcht; | 
 | 	uchar *ss; | 
 | 	int Td[3], DC[3], blockno[3]; | 
 |  | 
 | 	ss= h->ss; | 
 | 	Ns = ss[0]; | 
 | 	if(Ns!=h->Nf) | 
 | 		jpgerror(h, "ReadJPG: can't handle progressive with Nf!=Ns in DC scan"); | 
 |  | 
 | 	/* initialize data structures */ | 
 | 	h->cnt = 0; | 
 | 	h->sr = 0; | 
 | 	h->peek = -1; | 
 | 	for(comp=0; comp<Ns; comp++){ | 
 | 		/* | 
 | 		 * JPEG requires scan components to be in same order as in frame, | 
 | 		 * so if both have 3 we know scan is Y Cb Cr and there's no need to | 
 | 		 * reorder | 
 | 		 */ | 
 | 		nibbles(ss[2+2*comp], &Td[comp], &z);	/* z is ignored */ | 
 | 		DC[comp] = 0; | 
 | 	} | 
 |  | 
 | 	ri = h->ri; | 
 |  | 
 | 	nmcu = h->nacross*h->ndown; | 
 | 	memset(blockno, 0, sizeof blockno); | 
 | 	for(mcu=0; mcu<nmcu; ){ | 
 | 		for(comp=0; comp<Ns; comp++){ | 
 | 			dcht = &h->dcht[Td[comp]]; | 
 | 			qt = h->qt[h->comp[comp].Tq][0]; | 
 | 			dc = h->dccoeff[comp]; | 
 | 			bn = blockno[comp]; | 
 |  | 
 | 			for(block=0; block<h->nblock[comp]; block++){ | 
 | 				if(Ah == 0){ | 
 | 					t = decode(h, dcht); | 
 | 					diff = receive(h, t); | 
 | 					DC[comp] += diff; | 
 | 					dc[bn] = qt*DC[comp]<<Al; | 
 | 				}else | 
 | 					dc[bn] |= qt*receivebit(h)<<Al; | 
 | 				bn++; | 
 | 			} | 
 | 			blockno[comp] = bn; | 
 | 		} | 
 |  | 
 | 		/* process restart marker, if present */ | 
 | 		mcu++; | 
 | 		if(ri>0 && mcu<nmcu && mcu%ri==0){ | 
 | 			restart(h, mcu); | 
 | 			for(comp=0; comp<Ns; comp++) | 
 | 				DC[comp] = 0; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | progressiveac(Header *h, int comp, int Al) | 
 | { | 
 | 	int Ns, Ss, Se, z, k, eobrun, x, y, nver, tmcu, blockno, *acc, rs; | 
 | 	int ri, mcu, nacross, ndown, nmcu, nhor; | 
 | 	Huffman *acht; | 
 | 	int *qt, rrrr, ssss, q; | 
 | 	uchar *ss; | 
 | 	int Ta, H, V; | 
 |  | 
 | 	ss = h->ss; | 
 | 	Ns = ss[0]; | 
 | 	if(Ns != 1) | 
 | 		jpgerror(h, "ReadJPG: illegal Ns>1 in progressive AC scan"); | 
 | 	Ss = ss[1+2]; | 
 | 	Se = ss[2+2]; | 
 | 	H = h->comp[comp].H; | 
 | 	V = h->comp[comp].V; | 
 |  | 
 | 	nacross = h->nacross*H; | 
 | 	ndown = h->ndown*V; | 
 | 	q = 8*h->Hmax/H; | 
 | 	nhor = (h->X+q-1)/q; | 
 | 	q = 8*h->Vmax/V; | 
 | 	nver = (h->Y+q-1)/q; | 
 |  | 
 | 	/* initialize data structures */ | 
 | 	h->cnt = 0; | 
 | 	h->sr = 0; | 
 | 	h->peek = -1; | 
 | 	nibbles(ss[1+1], &z, &Ta);	/* z is thrown away */ | 
 |  | 
 | 	ri = h->ri; | 
 |  | 
 | 	eobrun = 0; | 
 | 	acht = &h->acht[Ta]; | 
 | 	qt = h->qt[h->comp[comp].Tq]; | 
 | 	nmcu = nacross*ndown; | 
 | 	mcu = 0; | 
 | 	for(y=0; y<nver; y++){ | 
 | 		for(x=0; x<nhor; x++){ | 
 | 			/* Figure G-3  */ | 
 | 			if(eobrun > 0){ | 
 | 				--eobrun; | 
 | 				continue; | 
 | 			} | 
 |  | 
 | 			/* arrange blockno to be in same sequence as original scan calculation. */ | 
 | 			tmcu = x/H + (nacross/H)*(y/V); | 
 | 			blockno = tmcu*H*V + H*(y%V) + x%H; | 
 | 			acc = h->accoeff[comp][blockno]; | 
 | 			k = Ss; | 
 | 			for(;;){ | 
 | 				rs = decode(h, acht); | 
 | 				/* XXX remove rrrr ssss as in baselinescan */ | 
 | 				nibbles(rs, &rrrr, &ssss); | 
 | 				if(ssss == 0){ | 
 | 					if(rrrr < 15){ | 
 | 						eobrun = 0; | 
 | 						if(rrrr > 0) | 
 | 							eobrun = receiveEOB(h, rrrr)-1; | 
 | 						break; | 
 | 					} | 
 | 					k += 16; | 
 | 				}else{ | 
 | 					k += rrrr; | 
 | 					z = receive(h, ssss); | 
 | 					acc[k] = z*qt[k]<<Al; | 
 | 					if(k == Se) | 
 | 						break; | 
 | 					k++; | 
 | 				} | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* process restart marker, if present */ | 
 | 		mcu++; | 
 | 		if(ri>0 && mcu<nmcu && mcu%ri==0){ | 
 | 			restart(h, mcu); | 
 | 			eobrun = 0; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | increment(Header *h, int acc[], int k, int Pt) | 
 | { | 
 | 	if(acc[k] == 0) | 
 | 		return; | 
 | 	if(receivebit(h) != 0) | 
 | 		if(acc[k] < 0) | 
 | 			acc[k] -= Pt; | 
 | 		else | 
 | 			acc[k] += Pt; | 
 | } | 
 |  | 
 | static | 
 | void | 
 | progressiveacinc(Header *h, int comp, int Al) | 
 | { | 
 | 	int Ns, i, z, k, Ss, Se, Ta, **ac, H, V; | 
 | 	int ri, mcu, nacross, ndown, nhor, nver, eobrun, nzeros, pending, x, y, tmcu, blockno, q, nmcu; | 
 | 	Huffman *acht; | 
 | 	int *qt, rrrr, ssss, *acc, rs; | 
 | 	uchar *ss; | 
 |  | 
 | 	ss = h->ss; | 
 | 	Ns = ss[0]; | 
 | 	if(Ns != 1) | 
 | 		jpgerror(h, "ReadJPG: illegal Ns>1 in progressive AC scan"); | 
 | 	Ss = ss[1+2]; | 
 | 	Se = ss[2+2]; | 
 | 	H = h->comp[comp].H; | 
 | 	V = h->comp[comp].V; | 
 |  | 
 | 	nacross = h->nacross*H; | 
 | 	ndown = h->ndown*V; | 
 | 	q = 8*h->Hmax/H; | 
 | 	nhor = (h->X+q-1)/q; | 
 | 	q = 8*h->Vmax/V; | 
 | 	nver = (h->Y+q-1)/q; | 
 |  | 
 | 	/* initialize data structures */ | 
 | 	h->cnt = 0; | 
 | 	h->sr = 0; | 
 | 	h->peek = -1; | 
 | 	nibbles(ss[1+1], &z, &Ta);	/* z is thrown away */ | 
 | 	ri = h->ri; | 
 |  | 
 | 	eobrun = 0; | 
 | 	ac = h->accoeff[comp]; | 
 | 	acht = &h->acht[Ta]; | 
 | 	qt = h->qt[h->comp[comp].Tq]; | 
 | 	nmcu = nacross*ndown; | 
 | 	mcu = 0; | 
 | 	pending = 0; | 
 | 	nzeros = -1; | 
 | 	for(y=0; y<nver; y++){ | 
 | 		for(x=0; x<nhor; x++){ | 
 | 			/* Figure G-7 */ | 
 |  | 
 | 			/*  arrange blockno to be in same sequence as original scan calculation. */ | 
 | 			tmcu = x/H + (nacross/H)*(y/V); | 
 | 			blockno = tmcu*H*V + H*(y%V) + x%H; | 
 | 			acc = ac[blockno]; | 
 | 			if(eobrun > 0){ | 
 | 				if(nzeros > 0) | 
 | 					jpgerror(h, "ReadJPG: zeros pending at block start"); | 
 | 				for(k=Ss; k<=Se; k++) | 
 | 					increment(h, acc, k, qt[k]<<Al); | 
 | 				--eobrun; | 
 | 				continue; | 
 | 			} | 
 |  | 
 | 			for(k=Ss; k<=Se; ){ | 
 | 				if(nzeros >= 0){ | 
 | 					if(acc[k] != 0) | 
 | 						increment(h, acc, k, qt[k]<<Al); | 
 | 					else if(nzeros-- == 0) | 
 | 						acc[k] = pending; | 
 | 					k++; | 
 | 					continue; | 
 | 				} | 
 | 				rs = decode(h, acht); | 
 | 				nibbles(rs, &rrrr, &ssss); | 
 | 				if(ssss == 0){ | 
 | 					if(rrrr < 15){ | 
 | 						eobrun = 0; | 
 | 						if(rrrr > 0) | 
 | 							eobrun = receiveEOB(h, rrrr)-1; | 
 | 						while(k <= Se){ | 
 | 							increment(h, acc, k, qt[k]<<Al); | 
 | 							k++; | 
 | 						} | 
 | 						break; | 
 | 					} | 
 | 					for(i=0; i<16; k++){ | 
 | 						increment(h, acc, k, qt[k]<<Al); | 
 | 						if(acc[k] == 0) | 
 | 							i++; | 
 | 					} | 
 | 					continue; | 
 | 				}else if(ssss != 1) | 
 | 					jpgerror(h, "ReadJPG: ssss!=1 in progressive increment"); | 
 | 				nzeros = rrrr; | 
 | 				pending = receivebit(h); | 
 | 				if(pending == 0) | 
 | 					pending = -1; | 
 | 				pending *= qt[k]<<Al; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* process restart marker, if present */ | 
 | 		mcu++; | 
 | 		if(ri>0 && mcu<nmcu && mcu%ri==0){ | 
 | 			restart(h, mcu); | 
 | 			eobrun = 0; | 
 | 			nzeros = -1; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | progressivescan(Header *h, int colorspace) | 
 | { | 
 | 	uchar *ss; | 
 | 	int Ns, Ss, Ah, Al, c, comp, i; | 
 |  | 
 | 	if(h->dccoeff[0] == nil) | 
 | 		progressiveinit(h, colorspace); | 
 |  | 
 | 	ss = h->ss; | 
 | 	Ns = ss[0]; | 
 | 	Ss = ss[1+2*Ns]; | 
 | 	nibbles(ss[3+2*Ns], &Ah, &Al); | 
 | 	c = ss[1]; | 
 | 	comp = -1; | 
 | 	for(i=0; i<h->Nf; i++) | 
 | 		if(h->comp[i].C == c) | 
 | 			comp = i; | 
 | 	if(comp == -1) | 
 | 		jpgerror(h, "ReadJPG: bad component index in scan header"); | 
 |  | 
 | 	if(Ss == 0){ | 
 | 		progressivedc(h, comp, Ah, Al); | 
 | 		return; | 
 | 	} | 
 | 	if(Ah == 0){ | 
 | 		progressiveac(h, comp, Al); | 
 | 		return; | 
 | 	} | 
 | 	progressiveacinc(h, comp, Al); | 
 | } | 
 |  | 
 | enum { | 
 | 	c1 = 2871,	/* 1.402 * 2048 */ | 
 | 	c2 = 705,		/* 0.34414 * 2048 */ | 
 | 	c3 = 1463,	/* 0.71414 * 2048 */ | 
 | 	c4 = 3629	/* 1.772 * 2048 */ | 
 | }; | 
 |  | 
 | static | 
 | void | 
 | colormap1(Header *h, int colorspace, Rawimage *image, int data[8*8], int mcu, int nacross) | 
 | { | 
 | 	uchar *pic; | 
 | 	int x, y, dx, dy, minx, miny; | 
 | 	int r, k, pici; | 
 |  | 
 | 	USED(colorspace); | 
 | 	pic = image->chans[0]; | 
 | 	minx = 8*(mcu%nacross); | 
 | 	dx = 8; | 
 | 	if(minx+dx > h->X) | 
 | 		dx = h->X-minx; | 
 | 	miny = 8*(mcu/nacross); | 
 | 	dy = 8; | 
 | 	if(miny+dy > h->Y) | 
 | 		dy = h->Y-miny; | 
 | 	pici = miny*h->X+minx; | 
 | 	k = 0; | 
 | 	for(y=0; y<dy; y++){ | 
 | 		for(x=0; x<dx; x++){ | 
 | 			r = clamp[(data[k+x]+128)+CLAMPOFF]; | 
 | 			pic[pici+x] = r; | 
 | 		} | 
 | 		pici += h->X; | 
 | 		k += 8; | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | colormapall1(Header *h, int colorspace, Rawimage *image, int data0[8*8], int data1[8*8], int data2[8*8], int mcu, int nacross) | 
 | { | 
 | 	uchar *rpic, *gpic, *bpic, *rp, *gp, *bp; | 
 | 	int *p0, *p1, *p2; | 
 | 	int x, y, dx, dy, minx, miny; | 
 | 	int r, g, b, k, pici; | 
 | 	int Y, Cr, Cb; | 
 |  | 
 | 	rpic = image->chans[0]; | 
 | 	gpic = image->chans[1]; | 
 | 	bpic = image->chans[2]; | 
 | 	minx = 8*(mcu%nacross); | 
 | 	dx = 8; | 
 | 	if(minx+dx > h->X) | 
 | 		dx = h->X-minx; | 
 | 	miny = 8*(mcu/nacross); | 
 | 	dy = 8; | 
 | 	if(miny+dy > h->Y) | 
 | 		dy = h->Y-miny; | 
 | 	pici = miny*h->X+minx; | 
 | 	k = 0; | 
 | 	for(y=0; y<dy; y++){ | 
 | 		p0 = data0+k; | 
 | 		p1 = data1+k; | 
 | 		p2 = data2+k; | 
 | 		rp = rpic+pici; | 
 | 		gp = gpic+pici; | 
 | 		bp = bpic+pici; | 
 | 		if(colorspace == CYCbCr) | 
 | 			for(x=0; x<dx; x++){ | 
 | 				*rp++ = clamp[*p0++ + 128 + CLAMPOFF]; | 
 | 				*gp++ = clamp[*p1++ + 128 + CLAMPOFF]; | 
 | 				*bp++ = clamp[*p2++ + 128 + CLAMPOFF]; | 
 | 			} | 
 | 		else | 
 | 			for(x=0; x<dx; x++){ | 
 | 				Y = (*p0++ + 128) << 11; | 
 | 				Cb = *p1++; | 
 | 				Cr = *p2++; | 
 | 				r = Y+c1*Cr; | 
 | 				g = Y-c2*Cb-c3*Cr; | 
 | 				b = Y+c4*Cb; | 
 | 				*rp++ = clamp[(r>>11)+CLAMPOFF]; | 
 | 				*gp++ = clamp[(g>>11)+CLAMPOFF]; | 
 | 				*bp++ = clamp[(b>>11)+CLAMPOFF]; | 
 | 			} | 
 | 		pici += h->X; | 
 | 		k += 8; | 
 | 	} | 
 | } | 
 |  | 
 | static | 
 | void | 
 | colormap(Header *h, int colorspace, Rawimage *image, int *data0[8*8], int *data1[8*8], int *data2[8*8], int mcu, int nacross, int Hmax, int Vmax,  int *H, int *V) | 
 | { | 
 | 	uchar *rpic, *gpic, *bpic; | 
 | 	int x, y, dx, dy, minx, miny; | 
 | 	int r, g, b, pici, H0, H1, H2; | 
 | 	int t, b0, b1, b2, y0, y1, y2, x0, x1, x2; | 
 | 	int Y, Cr, Cb; | 
 |  | 
 | 	rpic = image->chans[0]; | 
 | 	gpic = image->chans[1]; | 
 | 	bpic = image->chans[2]; | 
 | 	minx = 8*Hmax*(mcu%nacross); | 
 | 	dx = 8*Hmax; | 
 | 	if(minx+dx > h->X) | 
 | 		dx = h->X-minx; | 
 | 	miny = 8*Vmax*(mcu/nacross); | 
 | 	dy = 8*Vmax; | 
 | 	if(miny+dy > h->Y) | 
 | 		dy = h->Y-miny; | 
 | 	pici = miny*h->X+minx; | 
 | 	H0 = H[0]; | 
 | 	H1 = H[1]; | 
 | 	H2 = H[2]; | 
 | 	for(y=0; y<dy; y++){ | 
 | 		t = y*V[0]; | 
 | 		b0 = H0*(t/(8*Vmax)); | 
 | 		y0 = 8*((t/Vmax)&7); | 
 | 		t = y*V[1]; | 
 | 		b1 = H1*(t/(8*Vmax)); | 
 | 		y1 = 8*((t/Vmax)&7); | 
 | 		t = y*V[2]; | 
 | 		b2 = H2*(t/(8*Vmax)); | 
 | 		y2 = 8*((t/Vmax)&7); | 
 | 		x0 = 0; | 
 | 		x1 = 0; | 
 | 		x2 = 0; | 
 | 		for(x=0; x<dx; x++){ | 
 | 			if(colorspace == CYCbCr){ | 
 | 				rpic[pici+x] = clamp[data0[b0][y0+x0++*H0/Hmax] + 128 + CLAMPOFF]; | 
 | 				gpic[pici+x] = clamp[data1[b1][y1+x1++*H1/Hmax] + 128 + CLAMPOFF]; | 
 | 				bpic[pici+x] = clamp[data2[b2][y2+x2++*H2/Hmax] + 128 + CLAMPOFF]; | 
 | 			}else{ | 
 | 				Y = (data0[b0][y0+x0++*H0/Hmax]+128)<<11; | 
 | 				Cb = data1[b1][y1+x1++*H1/Hmax]; | 
 | 				Cr = data2[b2][y2+x2++*H2/Hmax]; | 
 | 				r = Y+c1*Cr; | 
 | 				g = Y-c2*Cb-c3*Cr; | 
 | 				b = Y+c4*Cb; | 
 | 				rpic[pici+x] = clamp[(r>>11)+CLAMPOFF]; | 
 | 				gpic[pici+x] = clamp[(g>>11)+CLAMPOFF]; | 
 | 				bpic[pici+x] = clamp[(b>>11)+CLAMPOFF]; | 
 | 			} | 
 | 			if(x0*H0/Hmax >= 8){ | 
 | 				x0 = 0; | 
 | 				b0++; | 
 | 			} | 
 | 			if(x1*H1/Hmax >= 8){ | 
 | 				x1 = 0; | 
 | 				b1++; | 
 | 			} | 
 | 			if(x2*H2/Hmax >= 8){ | 
 | 				x2 = 0; | 
 | 				b2++; | 
 | 			} | 
 | 		} | 
 | 		pici += h->X; | 
 | 	} | 
 | } | 
 |  | 
 | /* | 
 |  * decode next 8-bit value from entropy-coded input.  chart F-26 | 
 |  */ | 
 | static | 
 | int | 
 | decode(Header *h, Huffman *t) | 
 | { | 
 | 	int code, v, cnt, m, sr, i; | 
 | 	int *maxcode; | 
 | 	static int badcode; | 
 |  | 
 | 	maxcode = t->maxcode; | 
 | 	if(h->cnt < 8) | 
 | 		nextbyte(h, 0); | 
 | 	/* fast lookup */ | 
 | 	code = (h->sr>>(h->cnt-8))&0xFF; | 
 | 	v = t->value[code]; | 
 | 	if(v >= 0){ | 
 | 		h->cnt -= t->shift[code]; | 
 | 		return v; | 
 | 	} | 
 |  | 
 | 	h->cnt -= 8; | 
 | 	if(h->cnt == 0) | 
 | 		nextbyte(h, 0); | 
 | 	h->cnt--; | 
 | 	cnt = h->cnt; | 
 | 	m = 1<<cnt; | 
 | 	sr = h->sr; | 
 | 	code <<= 1; | 
 | 	i = 9; | 
 | 	for(;;i++){ | 
 | 		if(sr & m) | 
 | 			code |= 1; | 
 | 		if(code <= maxcode[i]) | 
 | 			break; | 
 | 		code <<= 1; | 
 | 		m >>= 1; | 
 | 		if(m == 0){ | 
 | 			sr = nextbyte(h, 0); | 
 | 			m = 0x80; | 
 | 			cnt = 8; | 
 | 		} | 
 | 		cnt--; | 
 | 	} | 
 | 	if(i >= 17){ | 
 | 		if(badcode == 0) | 
 | 			fprint(2, "badly encoded %dx%d JPEG file; ignoring bad value\n", h->X, h->Y); | 
 | 		badcode = 1; | 
 | 		i = 0; | 
 | 	} | 
 | 	h->cnt = cnt; | 
 | 	return t->val[t->valptr[i]+(code-t->mincode[i])]; | 
 | } | 
 |  | 
 | /* | 
 |  * load next byte of input | 
 |  */ | 
 | static | 
 | int | 
 | nextbyte(Header *h, int marker) | 
 | { | 
 | 	int b, b2; | 
 |  | 
 | 	if(h->peek >= 0){ | 
 | 		b = h->peek; | 
 | 		h->peek = -1; | 
 | 	}else{ | 
 | 		b = Bgetc(h->fd); | 
 | 		if(b == Beof) | 
 | 			jpgerror(h, "truncated file"); | 
 | 		b &= 0xFF; | 
 | 	} | 
 |  | 
 | 	if(b == 0xFF){ | 
 | 		if(marker) | 
 | 			return b; | 
 | 		b2 = Bgetc(h->fd); | 
 | 		if(b2 != 0){ | 
 | 			if(b2 == Beof) | 
 | 				jpgerror(h, "truncated file"); | 
 | 			b2 &= 0xFF; | 
 | 			if(b2 == DNL) | 
 | 				jpgerror(h, "ReadJPG: DNL marker unimplemented"); | 
 | 			/* decoder is reading into marker; satisfy it and restore state */ | 
 | 			Bungetc(h->fd); | 
 | 			h->peek = b; | 
 | 		} | 
 | 	} | 
 | 	h->cnt += 8; | 
 | 	h->sr = (h->sr<<8) | b; | 
 | 	return b; | 
 | } | 
 |  | 
 | /* | 
 |  * return next s bits of input, MSB first, and level shift it | 
 |  */ | 
 | static | 
 | int | 
 | receive(Header *h, int s) | 
 | { | 
 | 	int v, m; | 
 |  | 
 | 	while(h->cnt < s) | 
 | 		nextbyte(h, 0); | 
 | 	h->cnt -= s; | 
 | 	v = h->sr >> h->cnt; | 
 | 	m = (1<<s); | 
 | 	v &= m-1; | 
 | 	/* level shift */ | 
 | 	if(v < (m>>1)) | 
 | 		v += ~(m-1)+1; | 
 | 	return v; | 
 | } | 
 |  | 
 | /* | 
 |  * return next s bits of input, decode as EOB | 
 |  */ | 
 | static | 
 | int | 
 | receiveEOB(Header *h, int s) | 
 | { | 
 | 	int v, m; | 
 |  | 
 | 	while(h->cnt < s) | 
 | 		nextbyte(h, 0); | 
 | 	h->cnt -= s; | 
 | 	v = h->sr >> h->cnt; | 
 | 	m = (1<<s); | 
 | 	v &= m-1; | 
 | 	/* level shift */ | 
 | 	v += m; | 
 | 	return v; | 
 | } | 
 |  | 
 | /*  | 
 |  * return next bit of input | 
 |  */ | 
 | static | 
 | int | 
 | receivebit(Header *h) | 
 | { | 
 | 	if(h->cnt < 1) | 
 | 		nextbyte(h, 0); | 
 | 	h->cnt--; | 
 | 	return (h->sr >> h->cnt) & 1; | 
 | } | 
 |  | 
 | /* | 
 |  *  Scaled integer implementation. | 
 |  *  inverse two dimensional DCT, Chen-Wang algorithm | 
 |  * (IEEE ASSP-32, pp. 803-816, Aug. 1984) | 
 |  * 32-bit integer arithmetic (8 bit coefficients) | 
 |  * 11 mults, 29 adds per DCT | 
 |  * | 
 |  * coefficients extended to 12 bit for IEEE1180-1990 compliance | 
 |  */ | 
 |  | 
 | enum { | 
 | 	W1		= 2841,	/* 2048*sqrt(2)*cos(1*pi/16)*/ | 
 | 	W2		= 2676,	/* 2048*sqrt(2)*cos(2*pi/16)*/ | 
 | 	W3		= 2408,	/* 2048*sqrt(2)*cos(3*pi/16)*/ | 
 | 	W5		= 1609,	/* 2048*sqrt(2)*cos(5*pi/16)*/ | 
 | 	W6		= 1108,	/* 2048*sqrt(2)*cos(6*pi/16)*/ | 
 | 	W7		= 565,	/* 2048*sqrt(2)*cos(7*pi/16)*/ | 
 |  | 
 | 	W1pW7	= 3406,	/* W1+W7*/ | 
 | 	W1mW7	= 2276,	/* W1-W7*/ | 
 | 	W3pW5	= 4017,	/* W3+W5*/ | 
 | 	W3mW5	= 799,	/* W3-W5*/ | 
 | 	W2pW6	= 3784,	/* W2+W6*/ | 
 | 	W2mW6	= 1567,	/* W2-W6*/ | 
 |  | 
 | 	R2		= 181	/* 256/sqrt(2)*/ | 
 | }; | 
 |  | 
 | static | 
 | void | 
 | idct(int b[8*8]) | 
 | { | 
 | 	int x, y, eighty, v; | 
 | 	int x0, x1, x2, x3, x4, x5, x6, x7, x8; | 
 | 	int *p; | 
 |  | 
 | 	/* transform horizontally*/ | 
 | 	for(y=0; y<8; y++){ | 
 | 		eighty = y<<3; | 
 | 		/* if all non-DC components are zero, just propagate the DC term*/ | 
 | 		p = b+eighty; | 
 | 		if(p[1]==0) | 
 | 		if(p[2]==0 && p[3]==0) | 
 | 		if(p[4]==0 && p[5]==0) | 
 | 		if(p[6]==0 && p[7]==0){ | 
 | 			v = p[0]<<3; | 
 | 			p[0] = v; | 
 | 			p[1] = v; | 
 | 			p[2] = v; | 
 | 			p[3] = v; | 
 | 			p[4] = v; | 
 | 			p[5] = v; | 
 | 			p[6] = v; | 
 | 			p[7] = v; | 
 | 			continue; | 
 | 		} | 
 | 		/* prescale*/ | 
 | 		x0 = (p[0]<<11)+128; | 
 | 		x1 = p[4]<<11; | 
 | 		x2 = p[6]; | 
 | 		x3 = p[2]; | 
 | 		x4 = p[1]; | 
 | 		x5 = p[7]; | 
 | 		x6 = p[5]; | 
 | 		x7 = p[3]; | 
 | 		/* first stage*/ | 
 | 		x8 = W7*(x4+x5); | 
 | 		x4 = x8 + W1mW7*x4; | 
 | 		x5 = x8 - W1pW7*x5; | 
 | 		x8 = W3*(x6+x7); | 
 | 		x6 = x8 - W3mW5*x6; | 
 | 		x7 = x8 - W3pW5*x7; | 
 | 		/* second stage*/ | 
 | 		x8 = x0 + x1; | 
 | 		x0 -= x1; | 
 | 		x1 = W6*(x3+x2); | 
 | 		x2 = x1 - W2pW6*x2; | 
 | 		x3 = x1 + W2mW6*x3; | 
 | 		x1 = x4 + x6; | 
 | 		x4 -= x6; | 
 | 		x6 = x5 + x7; | 
 | 		x5 -= x7; | 
 | 		/* third stage*/ | 
 | 		x7 = x8 + x3; | 
 | 		x8 -= x3; | 
 | 		x3 = x0 + x2; | 
 | 		x0 -= x2; | 
 | 		x2 = (R2*(x4+x5)+128)>>8; | 
 | 		x4 = (R2*(x4-x5)+128)>>8; | 
 | 		/* fourth stage*/ | 
 | 		p[0] = (x7+x1)>>8; | 
 | 		p[1] = (x3+x2)>>8; | 
 | 		p[2] = (x0+x4)>>8; | 
 | 		p[3] = (x8+x6)>>8; | 
 | 		p[4] = (x8-x6)>>8; | 
 | 		p[5] = (x0-x4)>>8; | 
 | 		p[6] = (x3-x2)>>8; | 
 | 		p[7] = (x7-x1)>>8; | 
 | 	} | 
 | 	/* transform vertically*/ | 
 | 	for(x=0; x<8; x++){ | 
 | 		/* if all non-DC components are zero, just propagate the DC term*/ | 
 | 		p = b+x; | 
 | 		if(p[8*1]==0) | 
 | 		if(p[8*2]==0 && p[8*3]==0) | 
 | 		if(p[8*4]==0 && p[8*5]==0) | 
 | 		if(p[8*6]==0 && p[8*7]==0){ | 
 | 			v = (p[8*0]+32)>>6; | 
 | 			p[8*0] = v; | 
 | 			p[8*1] = v; | 
 | 			p[8*2] = v; | 
 | 			p[8*3] = v; | 
 | 			p[8*4] = v; | 
 | 			p[8*5] = v; | 
 | 			p[8*6] = v; | 
 | 			p[8*7] = v; | 
 | 			continue; | 
 | 		} | 
 | 		/* prescale*/ | 
 | 		x0 = (p[8*0]<<8)+8192; | 
 | 		x1 = p[8*4]<<8; | 
 | 		x2 = p[8*6]; | 
 | 		x3 = p[8*2]; | 
 | 		x4 = p[8*1]; | 
 | 		x5 = p[8*7]; | 
 | 		x6 = p[8*5]; | 
 | 		x7 = p[8*3]; | 
 | 		/* first stage*/ | 
 | 		x8 = W7*(x4+x5) + 4; | 
 | 		x4 = (x8+W1mW7*x4)>>3; | 
 | 		x5 = (x8-W1pW7*x5)>>3; | 
 | 		x8 = W3*(x6+x7) + 4; | 
 | 		x6 = (x8-W3mW5*x6)>>3; | 
 | 		x7 = (x8-W3pW5*x7)>>3; | 
 | 		/* second stage*/ | 
 | 		x8 = x0 + x1; | 
 | 		x0 -= x1; | 
 | 		x1 = W6*(x3+x2) + 4; | 
 | 		x2 = (x1-W2pW6*x2)>>3; | 
 | 		x3 = (x1+W2mW6*x3)>>3; | 
 | 		x1 = x4 + x6; | 
 | 		x4 -= x6; | 
 | 		x6 = x5 + x7; | 
 | 		x5 -= x7; | 
 | 		/* third stage*/ | 
 | 		x7 = x8 + x3; | 
 | 		x8 -= x3; | 
 | 		x3 = x0 + x2; | 
 | 		x0 -= x2; | 
 | 		x2 = (R2*(x4+x5)+128)>>8; | 
 | 		x4 = (R2*(x4-x5)+128)>>8; | 
 | 		/* fourth stage*/ | 
 | 		p[8*0] = (x7+x1)>>14; | 
 | 		p[8*1] = (x3+x2)>>14; | 
 | 		p[8*2] = (x0+x4)>>14; | 
 | 		p[8*3] = (x8+x6)>>14; | 
 | 		p[8*4] = (x8-x6)>>14; | 
 | 		p[8*5] = (x0-x4)>>14; | 
 | 		p[8*6] = (x3-x2)>>14; | 
 | 		p[8*7] = (x7-x1)>>14; | 
 | 	} | 
 | } |