#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "ppm.h"
int ppm_fd, red_fd, green_fd, blue_fd;
int magic, width, height, maxval;
float scalar;
enum
{
/* Channel descriptors */
CRGB = 0, /* three channels, no map */
CYCbCr = 1, /* three channels, no map, level-shifted 601 color space */
CY = 2, /* one channel, luminance */
CRGB1 = 3, /* one channel, map present */
CRGBV = 4, /* one channel, map is RGBV, understood */
CRGB24 = 5, /* one channel in correct data order for loadimage(RGB24) */
CRGBA32 = 6, /* one channel in correct data order for loadimage(RGBA32) */
CYA16 = 7, /* one channel in correct data order for loadimage(Grey8+Alpha8) */
CRGBVA16= 8, /* one channel in correct data order for loadimage(CMAP8+Alpha8) */
/* GIF flags */
TRANSP = 1,
INPUT = 2,
DISPMASK = 7<<2
};
static int bitc, nbit;
/*
* fetch a non-comment character.
*/
static
int
Bgetch(Biobufhdr *b)
{
int c;
for(;;) {
c = Bgetc(b);
if(c == '#') {
while((c = Bgetc(b)) != Beof && c != '\n')
;
}
return c;
}
}
/*
* fetch a nonnegative decimal integer.
*/
static
int
Bgetint(Biobufhdr *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(Biobufhdr *b)
{
int c;
while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
;
if(c == Beof)
return -1;
return c == '1';
}
static
int
Bgetbit(Biobufhdr *b)
{
if(nbit == 0) {
nbit = 8;
bitc = Bgetc(b);
if(bitc == -1)
return -1;
}
nbit--;
return (bitc >> (nbit-1)) & 0x1;
}
static
void
Bflushbit(Biobufhdr*)
{
nbit = 0;
}
typedef struct Pix Pix;
struct Pix {
char magic;
int maxcol;
int (*fetch)(Biobufhdr*);
int nchan;
int chandesc;
int invert;
void (*flush)(Biobufhdr*);
};
static Pix pix[] = {
{ '1', 1, Bgetdecimalbit, 1, CY, 1, nil }, /* portable bitmap */
{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
{ '2', 0, Bgetint, 1, CY, 0, nil }, /* portable greymap */
{ '5', 0, Bgetc, 1, CY, 0, nil }, /* raw portable greymap */
{ '3', 0, Bgetint, 3, CRGB, 0, nil }, /* portable pixmap */
{ '6', 0, Bgetc, 3, CRGB, 0, nil }, /* raw portable pixmap */
{ 0 },
};
RGBint *
free_rgb(RGBint *rgb) {
if(rgb) {
free(rgb->r);
free(rgb->g);
free(rgb->b);
}
return nil;
}
void
eightbit(RGBint *img) {
int x,y, k;
float f;
if(img->maxcol == 255) return;
float s = 255.0 / img->maxcol;
k = 0;
for(x = 0; x < img->width; x++)
for(y = 0; y < img->height; y++) {
f = s * (float) img->r[k];
img->r[k] = (int) f;
f = s * (float) img->g[k];
img->g[k] = (int) f;
f = s * (float) img->b[k];
img->b[k] = (int) f;
k++;
}
}
RGBint *
readppm(Biobuf *b)
{
RGBint *rgb;
int i, c;
int (*fetch)(Biobufhdr*);
Pix *p;
int pixels;
if(Bgetc(b) != 'P') {
fprint(2, "Doubt it's a ppm");
return nil;
}
c = Bgetc(b);
for(p=pix; p->magic; p++)
if(p->magic == c)
break;
if(p->magic == 0) {
fprint(2, "Bad magic");
return nil;
}
if(c != '3' && c != '6') {
fprint(2, "sorry, RGB only");
return nil;
}
rgb = (RGBint*)malloc(sizeof(RGBint));
rgb->width = Bgetint(b);
rgb->height = Bgetint(b);
if(rgb->width <= 0 || rgb->height <= 0){
fprint(2, "width or height < 0");
free_rgb(rgb);
return nil;
}
rgb->maxcol = p->maxcol;
if(rgb->maxcol == 0) {
rgb->maxcol = Bgetint(b);
if(rgb->maxcol <= 0) {
fprint(2, "rgb->maxcol <= 0");
free_rgb(rgb);
return nil;
}
}
pixels = rgb->width * rgb->height;
rgb->r = (int*)malloc(sizeof(int)*pixels);
rgb->g = (int*)malloc(sizeof(int)*pixels);
rgb->b = (int*)malloc(sizeof(int)*pixels);
fetch = p->fetch;
for(i=0; rgb && i < pixels; i++)
if(((rgb->r[i] = (*fetch)(b)) < 0) || ((rgb->g[i] = (*fetch)(b)) < 0) || ((rgb->b[i] = (*fetch)(b)) < 0))
rgb = free_rgb(rgb);
return rgb;
}
|