2004-04-21 22:19:33 +00:00
|
|
|
#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;
|
|
|
|
|
2005-01-14 18:33:54 +00:00
|
|
|
c = Bgetc(b);
|
|
|
|
if(c == '#') {
|
|
|
|
while((c = Bgetc(b)) != Beof && c != '\n')
|
|
|
|
;
|
|
|
|
}
|
|
|
|
return c;
|
2004-04-21 22:19:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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[] = {
|
2004-04-25 21:36:03 +00:00
|
|
|
{ '1', 1, Bgetdecimalbit, 1, CY, 1, 0 }, /* portable bitmap */
|
2004-04-21 22:19:33 +00:00
|
|
|
{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
|
2004-04-25 21:36:03 +00:00
|
|
|
{ '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 */
|
2004-04-21 22:19:33 +00:00
|
|
|
{ 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;
|
|
|
|
}
|