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 c = Bgetc(b);20 if(c == '#') {21 while((c = Bgetc(b)) != Beof && c != '\n')22 ;23 }24 return c;25 }27 /*28 * fetch a nonnegative decimal integer.29 */30 static31 int32 Bgetint(Biobuf *b)33 {34 int c;35 int i;37 while((c = Bgetch(b)) != Beof && !isdigit(c))38 ;39 if(c == Beof)40 return -1;42 i = 0;43 do {44 i = i*10 + (c-'0');45 } while((c = Bgetch(b)) != Beof && isdigit(c));47 return i;48 }50 static51 int52 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 }62 static int bitc, nbit;64 static65 int66 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 }78 static79 void80 Bflushbit(Biobuf *b)81 {82 USED(b);83 nbit = 0;84 }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;96 USED(colorspace);97 if(Binit(&b, fd, OREAD) < 0)98 return nil;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]);108 for(i=0; i<3; i++)109 array[0]->chans[i] = nil;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;125 return array;127 Error:128 if(array)129 free(array[0]);130 free(array);132 errstr(buf, sizeof buf);133 if(buf[0] == 0)134 strcpy(buf, e);135 errstr(buf, sizeof buf);137 return nil;138 }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 };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 };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;172 e = "bad file format";173 if(Bgetc(b) != 'P')174 goto Error;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;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);190 maxcol = p->maxcol;191 if(maxcol == 0) {192 maxcol = Bgetint(b);193 if(maxcol <= 0)194 goto Error;195 }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;205 e = "error reading file";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 }224 return a;226 Error:227 errstr(buf, sizeof buf);228 if(buf[0] == 0)229 strcpy(buf, e);230 errstr(buf, sizeof buf);232 for(i=0; i<3; i++)233 free(a->chans[i]);234 free(a->cmap);235 return nil;236 }