xref: /plan9-contrib/sys/src/cmd/jpg/readppm.c (revision 9863c128e160e47d0bf3a33658496e0e3d0bd48e)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <draw.h>
57dd7cddfSDavid du Colombier #include <ctype.h>
67dd7cddfSDavid du Colombier #include "imagefile.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier Rawimage *readppm(Biobuf*, Rawimage*);
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier /*
117dd7cddfSDavid du Colombier  * fetch a non-comment character.
127dd7cddfSDavid du Colombier  */
137dd7cddfSDavid du Colombier static
147dd7cddfSDavid du Colombier int
Bgetch(Biobufhdr * b)157dd7cddfSDavid du Colombier Bgetch(Biobufhdr *b)
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier 	int c;
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier 	for(;;) {
207dd7cddfSDavid du Colombier 		c = Bgetc(b);
217dd7cddfSDavid du Colombier 		if(c == '#') {
227dd7cddfSDavid du Colombier 			while((c = Bgetc(b)) != Beof && c != '\n')
237dd7cddfSDavid du Colombier 				;
247dd7cddfSDavid du Colombier 		}
257dd7cddfSDavid du Colombier 		return c;
267dd7cddfSDavid du Colombier 	}
277dd7cddfSDavid du Colombier }
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /*
307dd7cddfSDavid du Colombier  * fetch a nonnegative decimal integer.
317dd7cddfSDavid du Colombier  */
327dd7cddfSDavid du Colombier static
337dd7cddfSDavid du Colombier int
Bgetint(Biobufhdr * b)347dd7cddfSDavid du Colombier Bgetint(Biobufhdr *b)
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier 	int c;
377dd7cddfSDavid du Colombier 	int i;
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier 	while((c = Bgetch(b)) != Beof && !isdigit(c))
407dd7cddfSDavid du Colombier 		;
417dd7cddfSDavid du Colombier 	if(c == Beof)
427dd7cddfSDavid du Colombier 		return -1;
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier 	i = 0;
457dd7cddfSDavid du Colombier 	do {
467dd7cddfSDavid du Colombier 		i = i*10 + (c-'0');
477dd7cddfSDavid du Colombier 	} while((c = Bgetch(b)) != Beof && isdigit(c));
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 	return i;
507dd7cddfSDavid du Colombier }
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier static
537dd7cddfSDavid du Colombier int
Bgetdecimalbit(Biobufhdr * b)547dd7cddfSDavid du Colombier Bgetdecimalbit(Biobufhdr *b)
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier 	int c;
577dd7cddfSDavid du Colombier 	while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
587dd7cddfSDavid du Colombier 		;
597dd7cddfSDavid du Colombier 	if(c == Beof)
607dd7cddfSDavid du Colombier 		return -1;
617dd7cddfSDavid du Colombier 	return c == '1';
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier static int bitc, nbit;
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier static
677dd7cddfSDavid du Colombier int
Bgetbit(Biobufhdr * b)687dd7cddfSDavid du Colombier Bgetbit(Biobufhdr *b)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	if(nbit == 0) {
717dd7cddfSDavid du Colombier 		nbit = 8;
727dd7cddfSDavid du Colombier 		bitc = Bgetc(b);
737dd7cddfSDavid du Colombier 		if(bitc == -1)
747dd7cddfSDavid du Colombier 			return -1;
757dd7cddfSDavid du Colombier 	}
767dd7cddfSDavid du Colombier 	nbit--;
77*9863c128SDavid du Colombier 	return (bitc >> nbit) & 0x1;
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier static
817dd7cddfSDavid du Colombier void
Bflushbit(Biobufhdr *)827dd7cddfSDavid du Colombier Bflushbit(Biobufhdr*)
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier 	nbit = 0;
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier Rawimage**
readpixmap(int fd,int colorspace)897dd7cddfSDavid du Colombier readpixmap(int fd, int colorspace)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier 	Rawimage **array, *a;
927dd7cddfSDavid du Colombier 	Biobuf b;
939a747e4fSDavid du Colombier 	char buf[ERRMAX];
947dd7cddfSDavid du Colombier 	int i;
957dd7cddfSDavid du Colombier 	char *e;
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier 	USED(colorspace);
987dd7cddfSDavid du Colombier 	if(Binit(&b, fd, OREAD) < 0)
997dd7cddfSDavid du Colombier 		return nil;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	werrstr("");
1027dd7cddfSDavid du Colombier 	e = "out of memory";
1037dd7cddfSDavid du Colombier 	if((array = malloc(sizeof *array)) == nil)
1047dd7cddfSDavid du Colombier 		goto Error;
1057dd7cddfSDavid du Colombier 	if((array[0] = malloc(sizeof *array[0])) == nil)
1067dd7cddfSDavid du Colombier 		goto Error;
1077dd7cddfSDavid du Colombier 	memset(array[0], 0, sizeof *array[0]);
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	for(i=0; i<3; i++)
1107dd7cddfSDavid du Colombier 		array[0]->chans[i] = nil;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	e = "bad file format";
1137dd7cddfSDavid du Colombier 	switch(Bgetc(&b)) {
1147dd7cddfSDavid du Colombier 	case 'P':
1157dd7cddfSDavid du Colombier 		Bungetc(&b);
1167dd7cddfSDavid du Colombier 		a = readppm(&b, array[0]);
1177dd7cddfSDavid du Colombier 		break;
1187dd7cddfSDavid du Colombier 	default:
1197dd7cddfSDavid du Colombier 		a = nil;
1207dd7cddfSDavid du Colombier 		break;
1217dd7cddfSDavid du Colombier 	}
1227dd7cddfSDavid du Colombier 	if(a == nil)
1237dd7cddfSDavid du Colombier 		goto Error;
1247dd7cddfSDavid du Colombier 	array[0] = a;
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier 	return array;
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier Error:
1297dd7cddfSDavid du Colombier 	if(array)
1307dd7cddfSDavid du Colombier 		free(array[0]);
1317dd7cddfSDavid du Colombier 	free(array);
1327dd7cddfSDavid du Colombier 
1339a747e4fSDavid du Colombier 	errstr(buf, sizeof buf);
1347dd7cddfSDavid du Colombier 	if(buf[0] == 0)
1357dd7cddfSDavid du Colombier 		strcpy(buf, e);
1369a747e4fSDavid du Colombier 	errstr(buf, sizeof buf);
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	return nil;
1397dd7cddfSDavid du Colombier }
1407dd7cddfSDavid du Colombier 
1417dd7cddfSDavid du Colombier typedef struct Pix	Pix;
1427dd7cddfSDavid du Colombier struct Pix {
1437dd7cddfSDavid du Colombier 	char magic;
1447dd7cddfSDavid du Colombier 	int	maxcol;
1457dd7cddfSDavid du Colombier 	int	(*fetch)(Biobufhdr*);
1467dd7cddfSDavid du Colombier 	int	nchan;
1477dd7cddfSDavid du Colombier 	int	chandesc;
1487dd7cddfSDavid du Colombier 	int	invert;
1497dd7cddfSDavid du Colombier 	void	(*flush)(Biobufhdr*);
1507dd7cddfSDavid du Colombier };
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier static Pix pix[] = {
1537dd7cddfSDavid du Colombier 	{ '1', 1, Bgetdecimalbit, 1, CY, 1, nil },	/* portable bitmap */
1547dd7cddfSDavid du Colombier 	{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit },	/* raw portable bitmap */
1557dd7cddfSDavid du Colombier 	{ '2', 0, Bgetint, 1, CY, 0, nil },	/* portable greymap */
1567dd7cddfSDavid du Colombier 	{ '5', 0, Bgetc, 1, CY, 0, nil },	/* raw portable greymap */
1577dd7cddfSDavid du Colombier 	{ '3', 0, Bgetint, 3, CRGB, 0, nil },	/* portable pixmap */
1587dd7cddfSDavid du Colombier 	{ '6', 0, Bgetc, 3, CRGB, 0, nil },	/* raw portable pixmap */
1597dd7cddfSDavid du Colombier 	{ 0 },
1607dd7cddfSDavid du Colombier };
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier Rawimage*
readppm(Biobuf * b,Rawimage * a)1637dd7cddfSDavid du Colombier readppm(Biobuf *b, Rawimage *a)
1647dd7cddfSDavid du Colombier {
1657dd7cddfSDavid du Colombier 	int i, ch, wid, ht, r, c;
1667dd7cddfSDavid du Colombier 	int maxcol, nchan, invert;
1677dd7cddfSDavid du Colombier 	int (*fetch)(Biobufhdr*);
1687dd7cddfSDavid du Colombier 	uchar *rgb[3];
1699a747e4fSDavid du Colombier 	char buf[ERRMAX];
1707dd7cddfSDavid du Colombier 	char *e;
1717dd7cddfSDavid du Colombier 	Pix *p;
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	e = "bad file format";
1747dd7cddfSDavid du Colombier 	if(Bgetc(b) != 'P')
1757dd7cddfSDavid du Colombier 		goto Error;
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier 	c = Bgetc(b);
1787dd7cddfSDavid du Colombier 	for(p=pix; p->magic; p++)
1797dd7cddfSDavid du Colombier 		if(p->magic == c)
1807dd7cddfSDavid du Colombier 			break;
1817dd7cddfSDavid du Colombier 	if(p->magic == 0)
1827dd7cddfSDavid du Colombier 		goto Error;
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	wid = Bgetint(b);
1867dd7cddfSDavid du Colombier 	ht = Bgetint(b);
1877dd7cddfSDavid du Colombier 	if(wid <= 0 || ht <= 0)
1887dd7cddfSDavid du Colombier 		goto Error;
1897dd7cddfSDavid du Colombier 	a->r = Rect(0,0,wid,ht);
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier 	maxcol = p->maxcol;
1927dd7cddfSDavid du Colombier 	if(maxcol == 0) {
1937dd7cddfSDavid du Colombier 		maxcol = Bgetint(b);
1947dd7cddfSDavid du Colombier 		if(maxcol <= 0)
1957dd7cddfSDavid du Colombier 			goto Error;
1967dd7cddfSDavid du Colombier 	}
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 	e = "out of memory";
1997dd7cddfSDavid du Colombier 	for(i=0; i<p->nchan; i++)
2007dd7cddfSDavid du Colombier 		if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
2017dd7cddfSDavid du Colombier 			goto Error;
2027dd7cddfSDavid du Colombier 	a->nchans = p->nchan;
2037dd7cddfSDavid du Colombier 	a->chanlen = wid*ht;
2047dd7cddfSDavid du Colombier 	a->chandesc = p->chandesc;
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier 	e = "error reading file";
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	fetch = p->fetch;
2097dd7cddfSDavid du Colombier 	nchan = p->nchan;
2107dd7cddfSDavid du Colombier 	invert = p->invert;
2117dd7cddfSDavid du Colombier 	for(r=0; r<ht; r++) {
2127dd7cddfSDavid du Colombier 		for(c=0; c<wid; c++) {
2137dd7cddfSDavid du Colombier 			for(i=0; i<nchan; i++) {
2147dd7cddfSDavid du Colombier 				if((ch = (*fetch)(b)) < 0)
2157dd7cddfSDavid du Colombier 					goto Error;
2167dd7cddfSDavid du Colombier 				if(invert)
2177dd7cddfSDavid du Colombier 					ch = maxcol - ch;
2187dd7cddfSDavid du Colombier 				*rgb[i]++ = (ch * 255)/maxcol;
2197dd7cddfSDavid du Colombier 			}
2207dd7cddfSDavid du Colombier 		}
2217dd7cddfSDavid du Colombier 		if(p->flush)
2227dd7cddfSDavid du Colombier 			(*p->flush)(b);
2237dd7cddfSDavid du Colombier 	}
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier 	return a;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier Error:
2289a747e4fSDavid du Colombier 	errstr(buf, sizeof buf);
2297dd7cddfSDavid du Colombier 	if(buf[0] == 0)
2307dd7cddfSDavid du Colombier 		strcpy(buf, e);
2319a747e4fSDavid du Colombier 	errstr(buf, sizeof buf);
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier 	for(i=0; i<3; i++)
2347dd7cddfSDavid du Colombier 		free(a->chans[i]);
2357dd7cddfSDavid du Colombier 	free(a->cmap);
2367dd7cddfSDavid du Colombier 	return nil;
2377dd7cddfSDavid du Colombier }
238