blob: 073f4436b0640308154a1a964846bf7284cf4ec2 [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <ctype.h>
#include "imagefile.h"
Rawimage *readppm(Biobuf*, Rawimage*);
/*
* fetch a non-comment character.
*/
static
int
Bgetch(Biobuf *b)
{
int c;
c = Bgetc(b);
if(c == '#') {
while((c = Bgetc(b)) != Beof && c != '\n')
;
}
return c;
}
/*
* fetch a nonnegative decimal integer.
*/
static
int
Bgetint(Biobuf *b)
{
int c;
int i;
while((c = Bgetch(b)) != Beof && !isdigit(c))
;
if(c == Beof)
return -1;
i = 0;
do {
i = i*10 + (c-'0');
} while((c = Bgetch(b)) != Beof && isdigit(c));
return i;
}
static
int
Bgetdecimalbit(Biobuf *b)
{
int c;
while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
;
if(c == Beof)
return -1;
return c == '1';
}
static int bitc, nbit;
static
int
Bgetbit(Biobuf *b)
{
if(nbit == 0) {
nbit = 8;
bitc = Bgetc(b);
if(bitc == -1)
return -1;
}
nbit--;
return (bitc >> (nbit-1)) & 0x1;
}
static
void
Bflushbit(Biobuf *b)
{
USED(b);
nbit = 0;
}
Rawimage**
readpixmap(int fd, int colorspace)
{
Rawimage **array, *a;
Biobuf b;
char buf[ERRMAX];
int i;
char *e;
USED(colorspace);
if(Binit(&b, fd, OREAD) < 0)
return nil;
werrstr("");
e = "out of memory";
if((array = malloc(sizeof *array)) == nil)
goto Error;
if((array[0] = malloc(sizeof *array[0])) == nil)
goto Error;
memset(array[0], 0, sizeof *array[0]);
for(i=0; i<3; i++)
array[0]->chans[i] = nil;
e = "bad file format";
switch(Bgetc(&b)) {
case 'P':
Bungetc(&b);
a = readppm(&b, array[0]);
break;
default:
a = nil;
break;
}
if(a == nil)
goto Error;
array[0] = a;
return array;
Error:
if(array)
free(array[0]);
free(array);
errstr(buf, sizeof buf);
if(buf[0] == 0)
strcpy(buf, e);
errstr(buf, sizeof buf);
return nil;
}
typedef struct Pix Pix;
struct Pix {
char magic;
int maxcol;
int (*fetch)(Biobuf*);
int nchan;
int chandesc;
int invert;
void (*flush)(Biobuf*);
};
static Pix pix[] = {
{ '1', 1, Bgetdecimalbit, 1, CY, 1, 0 }, /* portable bitmap */
{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
{ '2', 0, Bgetint, 1, CY, 0, 0 }, /* portable greymap */
{ '5', 0, Bgetc, 1, CY, 0, 0 }, /* raw portable greymap */
{ '3', 0, Bgetint, 3, CRGB, 0, 0 }, /* portable pixmap */
{ '6', 0, Bgetc, 3, CRGB, 0, 0 }, /* raw portable pixmap */
{ 0 }
};
Rawimage*
readppm(Biobuf *b, Rawimage *a)
{
int i, ch, wid, ht, r, c;
int maxcol, nchan, invert;
int (*fetch)(Biobuf*);
uchar *rgb[3];
char buf[ERRMAX];
char *e;
Pix *p;
e = "bad file format";
if(Bgetc(b) != 'P')
goto Error;
c = Bgetc(b);
for(p=pix; p->magic; p++)
if(p->magic == c)
break;
if(p->magic == 0)
goto Error;
wid = Bgetint(b);
ht = Bgetint(b);
if(wid <= 0 || ht <= 0)
goto Error;
a->r = Rect(0,0,wid,ht);
maxcol = p->maxcol;
if(maxcol == 0) {
maxcol = Bgetint(b);
if(maxcol <= 0)
goto Error;
}
e = "out of memory";
for(i=0; i<p->nchan; i++)
if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
goto Error;
a->nchans = p->nchan;
a->chanlen = wid*ht;
a->chandesc = p->chandesc;
e = "error reading file";
fetch = p->fetch;
nchan = p->nchan;
invert = p->invert;
for(r=0; r<ht; r++) {
for(c=0; c<wid; c++) {
for(i=0; i<nchan; i++) {
if((ch = (*fetch)(b)) < 0)
goto Error;
if(invert)
ch = maxcol - ch;
*rgb[i]++ = (ch * 255)/maxcol;
}
}
if(p->flush)
(*p->flush)(b);
}
return a;
Error:
errstr(buf, sizeof buf);
if(buf[0] == 0)
strcpy(buf, e);
errstr(buf, sizeof buf);
for(i=0; i<3; i++)
free(a->chans[i]);
free(a->cmap);
return nil;
}