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