/*** reduce.cpp  
*
*   reduce image size by pixel averaging.
*
***/

#include <stdio.h>
#include <stdlib.h>
#include "image.h"
#include "errmsg.h"

void reduce_gray(IMAGE *in, IMAGE *out, int magx, int magy);
void reduce_rgb(IMAGE *in, IMAGE *out, int magx, int magy);


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

	if (argc<4) {
		printf("usage: reduce infile outfile magx [magy]\n");
		return -1;
	}
	infile=argv[1];
	outfile=argv[2];
	sscanf(argv[3],"%d",&magx);
	if (argc>4) sscanf(argv[4],"%d",&magy);
	else magy=magx;
	in = open_image(infile);
	if (!in) return -1;
	printf("input image: %s\n",infile);
	printf("image size: %d x %d\n",in->hlen,in->vlen);
	printf("reduction factors: %d x %d\n\n",magx,magy);
	if (magx<1 || magy < 1) {
		printf("illegal reduction factors\n");
		return -1;
	}
	if (magx == 1 && magy == 1) {
		printf("no reduction required\n");
		return -1;
	}

	out = make_image(outfile,in->hlen/magx,in->vlen/magy,in->type);
	printf("output image: %s\n",outfile);
	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) reduce_rgb(in, out, magx, magy);
	else reduce_gray(in,out,magx,magy);
	return 0;
}


void reduce_gray(IMAGE *in, IMAGE *out, int magx, int magy)
{
	pixel *buf1, *buf2;
	float *inbuf,  *outbuf, sum, magxy;
	int i, j, kx, ky, nx, ny;

	magxy = (float) magx * (float) magy;
	
	buf1 = make_buffer(in);
	buf2 = make_buffer(in);
	inbuf = (float *) buf1;
	outbuf = (float *) buf2;

	for (j=ny=0; j<out->vlen; j++) {
		// sum over rows
		get_line(in,ny,buf2,PIX_FLOAT);
		ny++;
		for (ky=1; ky<magy; ky++, ny++) {
			get_line(in,ny,buf1,PIX_FLOAT);
			for (i=0; i<in->hlen; i++) {
				outbuf[i] += inbuf[i];
			}
		}
		for (i=nx=0; i<out->hlen; i++) {
			// sum over columns
			sum = outbuf[nx];
			nx++;
			for (kx=1; kx<magx; kx++, nx++) {
				sum += outbuf[nx];
			}
			outbuf[i] = sum/magxy;
		}
		put_line(out,j,buf2,PIX_FLOAT);
	}
	free_buffer(buf1);
	free_buffer(buf2);
}



void reduce_rgb(IMAGE *in, IMAGE *out, int magx, int magy)
{
	pixel *buf, val;
	double *red, *grn, *blu;
	double redtot, grntot, blutot, magxy;
	int i, j, kx, ky, nx, ny;

	magxy = (float) magx * (float) magy;

	buf = make_buffer(in);

	red = new double[in->hlen];
	grn = new double[in->hlen];
	blu = new double[in->hlen];
	if (!red || !grn || !blu) errmsg("alloc error in reduce_rgb");

	for (j=ny=0; j<out->vlen; j++) {
		// sum over rows
		get_line(in,ny,buf,PIX_RGB);
		for (i=0; i<in->hlen; i++) {
			val = buf[i];
			red[i] = GetRValue(val);
			grn[i] = GetGValue(val);
			blu[i] = GetBValue(val);
		}
		ny++;
		for (ky=1; ky<magy; ky++, ny++) {
			get_line(in,ny,buf,PIX_RGB);
			for (i=0; i<in->hlen; i++) {
				val = buf[i];
				red[i] += GetRValue(val);
				grn[i] += GetGValue(val);
				blu[i] += GetBValue(val);
			}
		}
		for (i=nx=0; i<out->hlen; i++) {
			// sum over columns
			redtot = red[nx];
			grntot = grn[nx];
			blutot = blu[nx];
			nx++;
			for (kx=1; kx<magx; kx++, nx++) {
				redtot += red[nx];
				grntot += grn[nx];
				blutot += blu[nx];
			}
			redtot /= magxy;
			grntot /= magxy;
			blutot /= magxy;
			buf[i] = RGB((int)redtot,(int)grntot,(int)blutot);
		}
		put_line(out,j,buf,PIX_RGB);
	}
	free_buffer(buf);
	delete [] red;
	delete [] grn;
	delete [] blu;
}