V10/cmd/qsnap/piclib.c
#include <stdio.h>
#include <sgtty.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "piclib.h"
extern char *malloc();
static getfile(), getwindow(), gettd(), unwind(), putwindow(), puttd(), tdheader();
openf(s, image)
char *s;
struct pfile *image;
{
int fd;
strcpy(image->name, s);
if ((fd = open(s, 0)) >= 0)
{ fd = readheader(fd, image);
if (image->type != RUNCODE)
return fd;
}
return -1;
}
newf(image)
struct pfile *image;
{
int w = image->r.corner.x - image->r.origin.x;
int h = image->r.corner.y - image->r.origin.y;
switch (image->nchan) {
default: image->pixblu = (unsigned char *) malloc(w*h); /* fall through */
case 2: image->pixgrn = (unsigned char *) malloc(w*h); /* fall through */
case 1: image->pixred = (unsigned char *) malloc(w*h); break;
}
if (image->pixred == NULL)
return 0;
switch (image->nchan) {
default: break;
case 1: image->pixgrn = image->pixred; /* fall through */
case 2: image->pixblu = image->pixred; break;
}
return 1;
}
closef(image)
struct pfile *image;
{
switch (image->nchan) {
case 3: if (image->pixblu) free(image->pixblu);
case 2: if (image->pixgrn) free(image->pixgrn);
case 1: if (image->pixred) free(image->pixred);
default: break;
}
}
dumpf(s, image)
char *s;
struct pfile *image;
{
int fd, res=1;
if ((fd = creat(s, 0666)) <= 0)
return 0;
switch (image->type) {
case PICO:
res = putfile(fd, image);
break;
case RUNCODE:
case DUMP:
res = puttd(fd, image);
break;
}
close(fd);
return res;
}
readheader(fd, files)
struct pfile *files;
{ char line[512];
int i, a, b, c, d, n, sawtype=0;
extern double sqrt();
struct sgttyb sttybuf, sttysave;
struct stat stbuf;
files->r.origin.x = files->r.origin.y = 0;
files->r.corner.x = files->r.corner.y = 0;
files->pixred = files->pixgrn = files->pixblu = NULL;
files->nchan = 1;
lseek(fd, 0L, 0);
for (;;)
{ for (i = 0; i < 127; i++)
{ read(fd, &line[i], 1);
if (line[i] == '\n')
{ line[i] = '\0';
break;
} }
if (i == 0)
{ if (sawtype)
return fd; /* end of header */
i = 127;
}
if (i == 127)
{ lseek(fd, 0L, 0);
fstat(fd, &stbuf);
n = (int) sqrt(stbuf.st_size+1.0);
files->r.corner.x = files->r.corner.y = n;
files->type = PICO;
files->nchan = 1;
return fd; /* no header */
}
if (sscanf(line, "WINDOW=%d %d %d %d", &a, &b, &c, &d) == 4)
{ if (a > c) i = a, a = c, c = i; /* flip */
if (b > d) i = b, b = d, d = i;
if (a < 0) c -= a, a = 0; /* normalize */
if (b < 0) d -= b, b = 0;
files->r.origin.x = a; files->r.origin.y = b;
files->r.corner.x = c; files->r.corner.y = d;
} else if (sscanf(line, "NCHAN=%d", &a) == 1)
{ files->nchan = a;
} else if (strncmp(line, "CHAN=", 5) == 0
&& (line[5] == 'm' || line[5] == 'r' ||
line[5] == 'b' || line[5] == 'g'))
/* files->nchan = 1 */;
else if (strcmp(line, "TYPE=dump") == 0)
{ files->type = DUMP; sawtype = 1;
} else if (strcmp(line, "TYPE=runcode") == 0)
{ files->type = RUNCODE; sawtype = 1;
} else if (strcmp(line, "TYPE=pico") == 0)
{ files->type = PICO; sawtype = 1;
} else if (strcmp(line, "TYPE=binary") == 0)
{ files->type = BINARY; sawtype = 1;
} else if (strncmp(line, "TYPE", 4) == 0)
return -1; /* unknown format */
}
}
readf(fd, image)
struct pfile *image;
{
int w = image->r.corner.x - image->r.origin.x;
int h = image->r.corner.y - image->r.origin.y;
if (w > 0 && h > 0 && (image->pixred != NULL || newf(image)))
switch (image->type) {
case BINARY:
case PICO:
return getfile(fd, image, w, h);
break;
case RUNCODE:
return -1;
case DUMP:
return gettd(fd, image, w, h);
break;
}
return 0;
}
static getfile(fd, image, w, h)
struct pfile *image;
{
if (!getwindow(fd, image->pixred, w, h)) return 0;
if (image->nchan >= 2)
if (!getwindow(fd, image->pixgrn, w, h)) return 0;
if (image->nchan >= 3)
if (!getwindow(fd, image->pixblu, w, h)) return 0;
return 1;
}
static getwindow(fd, dest, w, d)
unsigned char *dest;
{
int i; unsigned char *z = dest;
for (i = 0; i < d; i++, z += w)
if (read(fd, z, w) != w)
return 0;
return 1;
}
static gettd(fd, image, w, d)
struct pfile *image;
{
unsigned char *z = (unsigned char *) malloc(w * image->nchan);
unsigned char *r = image->pixred;
unsigned char *g = image->pixgrn;
unsigned char *b = image->pixblu;
int i, res=1, j = w*image->nchan;
if (z == NULL)
return 0;
for (i = 0; i < d; i++)
{ if (read(fd, z, j) != j || !unwind(z, r, g, b, w, image->nchan))
{ res = 0;
break;
}
r += w; g += w; b += w;
}
free(z);
return res;
}
static unwind(p, R, G, B, w, nchan)
unsigned char *p, *R, *G, *B;
{
register unsigned char *r = R, *g = G, *b = B;
register unsigned char *z = p;
register int i;
switch (nchan) {
default: return 0; /* bad number of channels */
case 4: for(i=0; i<w; i++){ *r++=*z++; *g++=*z++; *b++=*z++; z++; } break;
case 3: for(i=0; i<w; i++){ *r++=*z++; *g++=*z++; *b++=*z++; } break;
case 2: for(i=0; i<w; i++){ *r++=*z++; *g++=*z++; } break;
case 1: for(i=0; i<w; i++){ *r++=*z++; } break;
}
return 1;
}
putheader(fd, image)
struct pfile *image;
{
int w = image->r.corner.x - image->r.origin.x;
int d = image->r.corner.y - image->r.origin.y;
if (image->nchan != 1 || w != d
|| image->r.origin.x != 0
|| image->r.origin.y != 0)
{ if (image->type == PICO)
picoheader(fd, image);
else
tdheader(fd, image);
}
}
putfile(fd, image)
struct pfile *image;
{
int w = image->r.corner.x - image->r.origin.x;
int d = image->r.corner.y - image->r.origin.y;
if (image->nchan != 1 || w != d
|| image->r.origin.x != 0
|| image->r.origin.y != 0)
picoheader(fd, image);
if (!putwindow(fd, image->pixred, w, d))
return 0;
if (image->nchan >= 2)
{ if (!putwindow(fd, image->pixgrn, w, d))
return 0;
}
if (image->nchan >= 3)
return putwindow(fd, image->pixblu, w, d);
return 1;
}
static putwindow(fd, source, w, d)
unsigned char *source;
{
register unsigned char *z = source;
register int i;
for (i = 0; i < d; i++, z += w)
if (write(fd, z, w) != w)
return 0;
return 1;
}
static puttd(fd, image)
struct pfile *image;
{
unsigned char *r = image->pixred;
unsigned char *g = image->pixgrn;
unsigned char *b = image->pixblu;
int w = image->r.corner.x - image->r.origin.x;
int d = image->r.corner.y - image->r.origin.y;
int i, j, res=1;
unsigned char *zz, *tmp = (unsigned char *) malloc(w*image->nchan);
if (tmp == NULL)
return 0;
tdheader(fd, image);
for (i = 0; i < d; i++)
{ switch (image->nchan) {
default: for (j = 0, zz = tmp; j < w; j++)
{ *zz++ = *r++, *zz++ = *g++, *zz++ = *b++;
zz += image->nchan - 3;
}
break;
case 3: for (j = 0, zz = tmp; j < w; j++)
{ *zz++ = *r++, *zz++ = *g++, *zz++ = *b++; }
break;
case 2: for (j = 0, zz = tmp; j < w; j++)
{ *zz++ = *r++, *zz++ = *g++; }
break;
case 1: for (j = 0, zz = tmp; j < w; j++) *zz++ = *r++;
break;
}
if (write(fd, tmp, w*image->nchan) != w*image->nchan)
{ res = 0;
break;
}
}
free(tmp);
return res;
}
static tdheader(fd, image)
struct pfile *image;
{ char line[128];
int n = image->nchan;
int a = image->r.origin.x;
int b = image->r.origin.y;
int c = image->r.corner.x;
int d = image->r.corner.y;
sprintf(line, "TYPE=dump\nWINDOW=%d %d %d %d\nNCHAN=%d\n\n", a,b,c,d,n);
write(fd, line, strlen(line));
}
picoheader(fd, image)
struct pfile *image;
{ char line[128];
int n = image->nchan;
int a = image->r.origin.x;
int b = image->r.origin.y;
int c = image->r.corner.x;
int d = image->r.corner.y;
sprintf(line, "TYPE=pico\nWINDOW=%d %d %d %d\nNCHAN=%d\n\n", a,b,c,d,n);
write(fd, line, strlen(line));
}