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 }