/* Copyright (c) 1992 Regents of the University of California */

#ifndef lint
static char SCCSid[] = "@(#)ra_ppm.c 2.4 10/2/92 LBL";
#endif

/*
 *  program to convert between RADIANCE and Poskanzer Pixmaps
 */

#include  <stdio.h>

#ifdef MSDOS
#include  <fcntl.h>
#endif

#include  <math.h>

#include  <ctype.h>

#include  "color.h"

#include  "resolu.h"


extern char  *malloc();

int  agryscan(), bgryscan(), aclrscan(), bclrscan();

int  bradj = 0;				/* brightness adjustment */

int  maxval = 255;			/* maximum primary value */

char  *progname;

int  xmax, ymax;


main(argc, argv)
int  argc;
char  *argv[];
{
	char  inpbuf[2];
	double	gamma = 2.2;
	int  binflag = 1;
	int  reverse = 0;
	int  ptype;
	int  i;
	
	progname = argv[0];

	for (i = 1; i < argc; i++)
		if (argv[i][0] == '-')
			switch (argv[i][1]) {
			case 'g':
				gamma = atof(argv[++i]);
				break;
			case 'e':
				if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
					goto userr;
				bradj = atoi(argv[++i]);
				break;
			case 'a':
				binflag = 0;
				break;
			case 'r':
				reverse = !reverse;
				break;
			default:
				goto userr;
			}
		else
			break;

	if (i < argc-2)
		goto userr;
	if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) {
		fprintf(stderr, "%s: can't open input \"%s\"\n",
				progname, argv[i]);
		exit(1);
	}
	if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) {
		fprintf(stderr, "can't open output \"%s\"\n",
				progname, argv[i+1]);
		exit(1);
	}
	setcolrgam(gamma);
	if (reverse) {
					/* get header */
		if (read(fileno(stdin), inpbuf, 2) != 2 || inpbuf[0] != 'P')
			quiterr("input not a Poskanzer Pixmap");
		ptype = inpbuf[1];
#ifdef MSDOS
		if (ptype > 4)
			setmode(fileno(stdin), O_BINARY);
		setmode(fileno(stdout), O_BINARY);
#endif
		xmax = scanint(stdin);
		ymax = scanint(stdin);
		maxval = scanint(stdin);
					/* put header */
		printargs(i, argv, stdout);
		fputformat(COLRFMT, stdout);
		putchar('\n');
		fprtresolu(xmax, ymax, stdout);
					/* convert file */
		switch (ptype) {
		case '2':
			ppm2ra(agryscan);
			break;
		case '5':
			ppm2ra(bgryscan);
			break;
		case '3':
			ppm2ra(aclrscan);
			break;
		case '6':
			ppm2ra(bclrscan);
			break;
		default:
			quiterr("unsupported Pixmap type");
		}
	} else {
#ifdef MSDOS
		setmode(fileno(stdin), O_BINARY);
		if (binflag)
			setmode(fileno(stdout), O_BINARY);
#endif
					/* get header info. */
		if (checkheader(stdin, COLRFMT, NULL) < 0 ||
				fgetresolu(&xmax, &ymax, stdin) < 0)
			quiterr("bad picture format");
					/* write PPM header */
		printf("P%c\n%d %d\n%d\n", binflag ? '6' : '3',
				xmax, ymax, maxval);
					/* convert file */
		ra2ppm(binflag);
	}
	exit(0);
userr:
	fprintf(stderr,
		"Usage: %s [-r][-a][-g gamma][-e +/-stops] [input [output]]\n",
			progname);
	exit(1);
}


quiterr(err)		/* print message and exit */
char  *err;
{
	if (err != NULL) {
		fprintf(stderr, "%s: %s\n", progname, err);
		exit(1);
	}
	exit(0);
}


ppm2ra(getscan)		/* convert color Pixmap to Radiance picture */
int  (*getscan)();
{
	COLR	*scanout;
	register int	x;
	int	y;
						/* allocate scanline */
	scanout = (COLR *)malloc(xmax*sizeof(COLR));
	if (scanout == NULL)
		quiterr("out of memory in ppm2ra");
						/* convert image */
	for (y = ymax-1; y >= 0; y--) {
		if ((*getscan)(scanout, xmax, stdin) < 0)
			quiterr("error reading Pixmap");
		gambs_colrs(scanout, xmax);
		if (bradj)
			shiftcolrs(scanout, xmax, bradj);
		if (fwritecolrs(scanout, xmax, stdout) < 0)
			quiterr("error writing Radiance picture");
	}
						/* free scanline */
	free((char *)scanout);
}


ra2ppm(binary)		/* convert Radiance picture to Pixmap */
int  binary;
{
	COLR	*scanin;
	register int	x;
	int	y;
						/* allocate scanline */
	scanin = (COLR *)malloc(xmax*sizeof(COLR));
	if (scanin == NULL)
		quiterr("out of memory in ra2pr");
						/* convert image */
	for (y = ymax-1; y >= 0; y--) {
		if (freadcolrs(scanin, xmax, stdin) < 0)
			quiterr("error reading Radiance picture");
		if (bradj)
			shiftcolrs(scanin, xmax, bradj);
		colrs_gambs(scanin, xmax);
		if (binary)
			for (x = 0; x < xmax; x++) {
				putc(scanin[x][RED], stdout);
				putc(scanin[x][GRN], stdout);
				putc(scanin[x][BLU], stdout);
			}
		else
			for (x = 0; x < xmax; x++)
				printf("%d %d %d\n", scanin[x][RED],
						scanin[x][GRN],
						scanin[x][BLU]);
		if (ferror(stdout))
			quiterr("error writing Pixmap");
	}
						/* free scanline */
	free((char *)scanin);
}


agryscan(scan, len, fp)			/* get an ASCII greyscale scanline */
register COLR  *scan;
register int  len;
FILE  *fp;
{
	while (len-- > 0) {
		scan[0][RED] =
		scan[0][GRN] =
		scan[0][BLU] = normval(scanint(fp));
		scan++;
	}
	return(0);
}


bgryscan(scan, len, fp)			/* get a binary greyscale scanline */
register COLR  *scan;
int  len;
register FILE  *fp;
{
	register int  c;

	while (len-- > 0) {
		if ((c = getc(fp)) == EOF)
			return(-1);
		if (maxval != 255)
			c = normval(c);
		scan[0][RED] =
		scan[0][GRN] =
		scan[0][BLU] = c;
		scan++;
	}
	return(0);
}


aclrscan(scan, len, fp)			/* get an ASCII color scanline */
register COLR  *scan;
register int  len;
FILE  *fp;
{
	while (len-- > 0) {
		scan[0][RED] = normval(scanint(fp));
		scan[0][GRN] = normval(scanint(fp));
		scan[0][BLU] = normval(scanint(fp));
		scan++;
	}
	return(0);
}


bclrscan(scan, len, fp)			/* get a binary color scanline */
register COLR  *scan;
int  len;
register FILE  *fp;
{
	int  r, g, b;

	while (len-- > 0) {
		r = getc(fp);
		g = getc(fp);
		if ((b = getc(fp)) == EOF)
			return(-1);
		if (maxval == 255) {
			scan[0][RED] = r;
			scan[0][GRN] = g;
			scan[0][BLU] = b;
		} else {
			scan[0][RED] = normval(r);
			scan[0][GRN] = normval(g);
			scan[0][BLU] = normval(b);
		}
		scan++;
	}
	return(0);
}


int
scanint(fp)			/* scan the next positive integer value */
register FILE  *fp;
{
	register int  i, c;
tryagain:
	while (isspace(c = getc(fp)))
		;
	if (c == EOF)
		quiterr("unexpected end of file");
	if (c == '#') {		/* comment */
		while ((c = getc(fp)) != EOF && c != '\n')
			;
		goto tryagain;
	}
				/* should be integer */
	i = 0;
	do {
		if (!isdigit(c))
			quiterr("error reading integer");
		i = 10*i + c - '0';
		c = getc(fp);
	} while (c != EOF && !isspace(c));
	return(i);
}


int
normval(v)			/* normalize a value to [0,255] */
register int  v;
{
	if (v >= maxval)
		return(255);
	if (maxval == 255)
		return(v);
	return(v*255L/maxval);
}
