plan9port

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

readppm.c (3603B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include <draw.h>
      5 #include <ctype.h>
      6 #include "imagefile.h"
      7 
      8 Rawimage *readppm(Biobuf*, Rawimage*);
      9 
     10 /*
     11  * fetch a non-comment character.
     12  */
     13 static
     14 int
     15 Bgetch(Biobuf *b)
     16 {
     17 	int c;
     18 
     19 	c = Bgetc(b);
     20 	if(c == '#') {
     21 		while((c = Bgetc(b)) != Beof && c != '\n')
     22 			;
     23 	}
     24 	return c;
     25 }
     26 
     27 /*
     28  * fetch a nonnegative decimal integer.
     29  */
     30 static
     31 int
     32 Bgetint(Biobuf *b)
     33 {
     34 	int c;
     35 	int i;
     36 
     37 	while((c = Bgetch(b)) != Beof && !isdigit(c))
     38 		;
     39 	if(c == Beof)
     40 		return -1;
     41 
     42 	i = 0;
     43 	do {
     44 		i = i*10 + (c-'0');
     45 	} while((c = Bgetch(b)) != Beof && isdigit(c));
     46 
     47 	return i;
     48 }
     49 
     50 static
     51 int
     52 Bgetdecimalbit(Biobuf *b)
     53 {
     54 	int c;
     55 	while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
     56 		;
     57 	if(c == Beof)
     58 		return -1;
     59 	return c == '1';
     60 }
     61 
     62 static int bitc, nbit;
     63 
     64 static
     65 int
     66 Bgetbit(Biobuf *b)
     67 {
     68 	if(nbit == 0) {
     69 		nbit = 8;
     70 		bitc = Bgetc(b);
     71 		if(bitc == -1)
     72 			return -1;
     73 	}
     74 	nbit--;
     75 	return (bitc >> (nbit-1)) & 0x1;
     76 }
     77 
     78 static
     79 void
     80 Bflushbit(Biobuf *b)
     81 {
     82 	USED(b);
     83 	nbit = 0;
     84 }
     85 
     86 
     87 Rawimage**
     88 readpixmap(int fd, int colorspace)
     89 {
     90 	Rawimage **array, *a;
     91 	Biobuf b;
     92 	char buf[ERRMAX];
     93 	int i;
     94 	char *e;
     95 
     96 	USED(colorspace);
     97 	if(Binit(&b, fd, OREAD) < 0)
     98 		return nil;
     99 
    100 	werrstr("");
    101 	e = "out of memory";
    102 	if((array = malloc(sizeof *array)) == nil)
    103 		goto Error;
    104 	if((array[0] = malloc(sizeof *array[0])) == nil)
    105 		goto Error;
    106 	memset(array[0], 0, sizeof *array[0]);
    107 
    108 	for(i=0; i<3; i++)
    109 		array[0]->chans[i] = nil;
    110 
    111 	e = "bad file format";
    112 	switch(Bgetc(&b)) {
    113 	case 'P':
    114 		Bungetc(&b);
    115 		a = readppm(&b, array[0]);
    116 		break;
    117 	default:
    118 		a = nil;
    119 		break;
    120 	}
    121 	if(a == nil)
    122 		goto Error;
    123 	array[0] = a;
    124 
    125 	return array;
    126 
    127 Error:
    128 	if(array)
    129 		free(array[0]);
    130 	free(array);
    131 
    132 	errstr(buf, sizeof buf);
    133 	if(buf[0] == 0)
    134 		strcpy(buf, e);
    135 	errstr(buf, sizeof buf);
    136 
    137 	return nil;
    138 }
    139 
    140 typedef struct Pix	Pix;
    141 struct Pix {
    142 	char magic;
    143 	int	maxcol;
    144 	int	(*fetch)(Biobuf*);
    145 	int	nchan;
    146 	int	chandesc;
    147 	int	invert;
    148 	void	(*flush)(Biobuf*);
    149 };
    150 
    151 static Pix pix[] = {
    152 	{ '1', 1, Bgetdecimalbit, 1, CY, 1, 0 },	/* portable bitmap */
    153 	{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit },	/* raw portable bitmap */
    154 	{ '2', 0, Bgetint, 1, CY, 0, 0 },	/* portable greymap */
    155 	{ '5', 0, Bgetc, 1, CY, 0, 0 },	/* raw portable greymap */
    156 	{ '3', 0, Bgetint, 3, CRGB, 0, 0 },	/* portable pixmap */
    157 	{ '6', 0, Bgetc, 3, CRGB, 0, 0 },	/* raw portable pixmap */
    158 	{ 0 }
    159 };
    160 
    161 Rawimage*
    162 readppm(Biobuf *b, Rawimage *a)
    163 {
    164 	int i, ch, wid, ht, r, c;
    165 	int maxcol, nchan, invert;
    166 	int (*fetch)(Biobuf*);
    167 	uchar *rgb[3];
    168 	char buf[ERRMAX];
    169 	char *e;
    170 	Pix *p;
    171 
    172 	e = "bad file format";
    173 	if(Bgetc(b) != 'P')
    174 		goto Error;
    175 
    176 	c = Bgetc(b);
    177 	for(p=pix; p->magic; p++)
    178 		if(p->magic == c)
    179 			break;
    180 	if(p->magic == 0)
    181 		goto Error;
    182 
    183 
    184 	wid = Bgetint(b);
    185 	ht = Bgetint(b);
    186 	if(wid <= 0 || ht <= 0)
    187 		goto Error;
    188 	a->r = Rect(0,0,wid,ht);
    189 
    190 	maxcol = p->maxcol;
    191 	if(maxcol == 0) {
    192 		maxcol = Bgetint(b);
    193 		if(maxcol <= 0)
    194 			goto Error;
    195 	}
    196 
    197 	e = "out of memory";
    198 	for(i=0; i<p->nchan; i++)
    199 		if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
    200 			goto Error;
    201 	a->nchans = p->nchan;
    202 	a->chanlen = wid*ht;
    203 	a->chandesc = p->chandesc;
    204 
    205 	e = "error reading file";
    206 
    207 	fetch = p->fetch;
    208 	nchan = p->nchan;
    209 	invert = p->invert;
    210 	for(r=0; r<ht; r++) {
    211 		for(c=0; c<wid; c++) {
    212 			for(i=0; i<nchan; i++) {
    213 				if((ch = (*fetch)(b)) < 0)
    214 					goto Error;
    215 				if(invert)
    216 					ch = maxcol - ch;
    217 				*rgb[i]++ = (ch * 255)/maxcol;
    218 			}
    219 		}
    220 		if(p->flush)
    221 			(*p->flush)(b);
    222 	}
    223 
    224 	return a;
    225 
    226 Error:
    227 	errstr(buf, sizeof buf);
    228 	if(buf[0] == 0)
    229 		strcpy(buf, e);
    230 	errstr(buf, sizeof buf);
    231 
    232 	for(i=0; i<3; i++)
    233 		free(a->chans[i]);
    234 	free(a->cmap);
    235 	return nil;
    236 }