/* resize.cpp
*
*/
#include <stdio.h>
#include <math.h>
#include "image.h"


void resize_gray(IMAGE *in, IMAGE *out);
void resize_rgb(IMAGE *in, IMAGE *out);

int main(int argc, char *argv[])
{
	int magx, magy;
	IMAGE *in, *out;
	char *infile,*outfile;

	if (argc<3) {
		printf("usage: resize infile outfile [magx] [magy]\n");
		printf("Image size expanded using bilinear interpolation.\n");
		return -1;
	}
	infile=argv[1];
	outfile=argv[2];
	if (argc>3) sscanf(argv[3],"%d",&magx);
	else magx = 1;
	if (argc>4) sscanf(argv[4],"%d",&magy);
	else magy=magx;
	printf("input image: %s\n",infile);
	in = open_image(infile);
	if (!in) {
		printf("error opening image file\n");
		return -1;
	}
	printf("image size: %d x %d\n",in->hlen,in->vlen);

	printf("pixel magnification: %d x %d\n\n",magx,magy);
	if (magx<=1 && magy<=1) {
		printf("no enlargement necessary\n");
		return -1;
	}
	printf("output image: %s\n",outfile);
	out = make_image(outfile,in->hlen*magx,in->vlen*magy,in->type);
	if (!out) {
		printf("error creating output file\n");
		return -1;
	}
	printf("image size: %d x %d\n",out->hlen,out->vlen);
	if (in->type==PIX_RGB) resize_rgb(in,out);
	else resize_gray(in,out);
	return 0;
}

inline float linint(double x, double x1, float fx1, float fx2)
{
	return (float)((fx2-fx1)*(x-x1)+fx1);
}

/*****
*
C
C   RESIZE USES BI-LINEAR INTERPOLATION TO CHANGE THE PICTURE ON
C   WORKFILE WFIN TO A DIFFERENT SIZE PICTURE ON WFOUT.  OUTPIX IS THE   
C   NUMBER OF PIXELS/LINE ON THE NEW PICTURE, AND OUTLIN IS THE NUMBER   
C   OF LINES
C
******/

void resize_gray(IMAGE *in, IMAGE *out)
{
	int i, j, ipntr;
	int x0, y0, x1;
	double fpix, flin, lp, ps, pp;
	pixel *buf, *buf1, *buf2, *buf3;
	float *fbuf1, *fbuf2, *fbuf3;
	float t1, t2;

	buf1 = make_buffer(in);
	buf2 = make_buffer(in);
	buf3 = make_buffer(out);

	/*   compute incremental factors */

	fpix = (double) (in->hlen-1)/ (double) (out->hlen-1);
	flin = (double) (in->vlen-1) / (double) (out->vlen-1);
	ps=0.0;
	lp=0.0;

	/*  get window */

	get_line(in,0,buf1,PIX_FLOAT);
	get_line(in,1,buf2,PIX_FLOAT);
	ipntr=1;
	for (j=0; j<out->vlen; j++) {
		if (lp>ipntr) {
			buf= buf1; buf1 = buf2; buf2 = buf;
			ipntr++;
			get_line(in,ipntr,buf2,PIX_FLOAT);
		}

		/*   interpolate */
		pp = ps;
		fbuf1 = (float *) buf1;
		fbuf2 = (float *) buf2;
		fbuf3 = (float *) buf3;
		for (i=0; i<out->hlen; i++, pp += fpix) {
			x0 = (int) floor(pp);
			y0 = (int) floor(lp);
			x1 = x0+1;
			if (pp==x0) fbuf3[i] = linint(lp,y0,fbuf1[x0],fbuf2[x0]);
			else if (pp==x1) fbuf3[i] = linint(lp,y0,fbuf1[x1],fbuf2[x1]);
			else {
				t1 = linint(pp,x0,fbuf1[x0],fbuf1[x1]);
				t2 = linint(pp,x0,fbuf2[x0],fbuf2[x1]);
				fbuf3[i] = linint(lp,y0,t1,t2);
			}
		}
	
		/* write line to output file */

		put_line(out,j,buf3,PIX_FLOAT);
		lp += flin;
	}
	free_buffer(buf3);
	free_buffer(buf2);
	free_buffer(buf1);
}

struct rgb_color {
	float red, green, blue;
	void set(pixel val);
	pixel rgb();
	void interp(double x, double x1, rgb_color &c1, rgb_color &c2);
};

void rgb_color::set(pixel val)
{
	red = GetRValue(val);
	green = GetGValue(val);
	blue = GetBValue(val);
}

inline pixel rgb_color::rgb()
{
	return RGB((int)red,(int)green,(int)blue);
}

void rgb_color::interp(double x, double x1, rgb_color &c1, rgb_color &c2)
{
	float dx = (float)(x-x1);
	red = (c2.red-c1.red)*dx + c1.red;
	green = (c2.green-c1.green)*dx + c1.green;
	blue = (c2,blue-c1.blue)*dx + c1.blue;
}


void resize_rgb(IMAGE *in, IMAGE *out)
{
	int i, j, ipntr;
	int x0, y0, x1;
	double fpix, flin, lp, ps, pp;
	pixel *inpbuf, *outbuf;
	rgb_color val, t1, t2;
	rgb_color *buf, *buf1, *buf2;

	inpbuf = make_buffer(in);
	outbuf = make_buffer(in);
	buf1 = new rgb_color[in->hlen];
	buf2 = new rgb_color[in->hlen];

	/*   compute incremental factors */

	fpix = (double) (in->hlen-1)/ (double) (out->hlen-1);
	flin = (double) (in->vlen-1) / (double) (out->vlen-1);
	ps=0.0;
	lp=0.0;

	/*  get window */

	get_line(in,0,inpbuf,PIX_RGB);
	for (i=0; i<in->hlen; i++) buf1[i].set(inpbuf[i]);
	get_line(in,1,inpbuf,PIX_RGB);
	for (i=0; i<in->hlen; i++) buf2[i].set(inpbuf[i]);
	ipntr=1;
	for (j=0; j<out->vlen; j++) {
		if (lp>ipntr) {
			buf= buf1; buf1 = buf2; buf2 = buf;
			ipntr++;
			get_line(in,ipntr,inpbuf,PIX_RGB);
			for (i=0; i<in->hlen; i++) buf2[i].set(inpbuf[i]);
		}

		/*   interpolate */
		pp = ps;
		for (i=0; i<out->hlen; i++, pp += fpix) {
			x0 = (int) floor(pp);
			y0 = (int) floor(lp);
			x1 = x0+1;
			if (pp==x0) val.interp(lp,y0,buf1[x0],buf2[x0]);
			else if (pp==x1) val.interp(lp,y0,buf1[x1],buf2[x1]);
			else {
				t1.interp(pp,x0,buf1[x0],buf1[x1]);
				t2.interp(pp,x0,buf2[x0],buf2[x1]);
				val.interp(lp,y0,t1,t2);
			}
			outbuf[i] = val.rgb();
		}
	
		/* write line to output file */

		put_line(out,j,outbuf,PIX_RGB);
		lp += flin;
	}
	free_buffer(outbuf);
	free_buffer(inpbuf);
	delete [] buf1;
	delete [] buf2;
}