#include "image.h"

Image *CreateImage(int ncols, int nrows)
{
  Image *img=NULL;
  int i;

  img = (Image *) calloc(1,sizeof(Image));
  if (img == NULL){
    Error(MSG1,"CreateImage");
  }

  img->val   = AllocIntArray(nrows*ncols);
  img->tbrow = AllocIntArray(nrows);

  img->tbrow[0]=0;
  for (i=1; i < nrows; i++)
    img->tbrow[i]=img->tbrow[i-1]+ncols;
  img->ncols = ncols;
  img->nrows = nrows;
 
 return(img);
}

void DestroyImage(Image **img)
{
  Image *aux;

  aux = *img;
  if(aux != NULL){
    if (aux->val != NULL)   free(aux->val); 
    if (aux->tbrow != NULL) free(aux->tbrow);
    free(aux);    
    *img = NULL;
  }
}

Image *Scale(Image *img, float Sx, float Sy) 
{
  float S[2][2],x,y,d1,d2,d3,d4,Ix1,Ix2,If;
  Image *scl;
  Pixel u,v,prev,next;
  
  if (Sx == 0.0) Sx = 1.0;
  if (Sy == 0.0) Sy = 1.0;

  S[0][0] = 1.0/Sx;
  S[0][1] = 0;
  S[1][0] = 0;
  S[1][1] = 1.0/Sy;

  scl = CreateImage((int)(img->ncols*fabs(Sx) + 0.5),(int)(img->nrows*fabs(Sy) + 0.5)); 

  for (v.y=0; v.y < scl->nrows; v.y++)
    for (v.x=0; v.x < scl->ncols; v.x++){
      x = ((v.x-scl->ncols/2.)*S[0][0] + (v.y-scl->nrows/2.)*S[0][1]) 
	+ img->ncols/2.;
      y = ((v.x-scl->ncols/2.)*S[1][0] + (v.y-scl->nrows/2.)*S[1][1]) 
	+ img->nrows/2.;
      u.x = (int)(x+0.5);
      u.y = (int)(y+0.5);
      if (ValidPixel(img,u.x,u.y)){
	if (x < u.x) {
	  next.x = u.x;
	  prev.x = u.x - 1;
	} else {
	  next.x = u.x + 1;
	  prev.x = u.x;
	}
	d1 = next.x - x;
	d2 = x - prev.x;
	if (y < u.y) {
	  next.y = u.y;
	  prev.y = u.y - 1;
	} else {
	  next.y = u.y + 1;
	  prev.y = u.y;
	}
	d3 = next.y - y;
	d4 = y - prev.y;

	if (ValidPixel(img,prev.x,prev.y)&&ValidPixel(img,next.x,prev.y))
	  Ix1 = d1*img->val[prev.x+img->tbrow[prev.y]] + 
	    d2*img->val[next.x+img->tbrow[prev.y]];
	else
	  Ix1 = img->val[u.x+img->tbrow[u.y]];

	if (ValidPixel(img,prev.x,next.y)&&ValidPixel(img,next.x,next.y))
	  Ix2 = d1*img->val[prev.x+img->tbrow[next.y]] + 
	    d2*img->val[next.x+img->tbrow[next.y]];
	else
	  Ix2 = img->val[u.x+img->tbrow[u.y]];
	
	If = d3*Ix1 + d4*Ix2;

	scl->val[v.x+scl->tbrow[v.y]] = (int)If;
      }
    }
  
  return(scl);
}

char ValidPixel(Image *img, int x, int y)
{
  if ((x >= 0)&&(x < img->ncols)&&
      (y >= 0)&&(y < img->nrows))
    return(1);
  else
    return(0);
}

CImage *CreateCImage(int ncols, int nrows)
{
  CImage *cimg=NULL;
  int i;

  cimg = (CImage *) calloc(1, sizeof(CImage));
  for (i=0; i < 3; i++) 
    cimg->C[i] = CreateImage(ncols,nrows);
  return(cimg);
}

void    DestroyCImage(CImage **cimg)
{
  CImage *tmp;
  int i;

  tmp = *cimg;
  if (tmp != NULL) {
    for (i=0; i < 3; i++) 
      DestroyImage(&(tmp->C[i]));
    free(tmp);
    *cimg = NULL;
  }
}

CImage *ReadCImage(char *filename)
{
  CImage *cimg=NULL;
  FILE *fp=NULL;
  char type[10];
  int  i,ncols,nrows,n;
  char z[256];

  fp = fopen(filename,"rb");
  if (fp == NULL){
    fprintf(stderr,"Cannot open %s\n",filename);
    exit(-1);
  }
  fscanf(fp,"%s\n",type);
  if((strcmp(type,"P6")==0)){
    NCFgets(z,255,fp);
    sscanf(z,"%d %d\n",&ncols,&nrows);
    n = ncols*nrows;
    NCFgets(z,255,fp);
    sscanf(z,"%d\n",&i);
    cimg = CreateCImage(ncols,nrows);
    for (i=0; i < n; i++){
      cimg->C[0]->val[i] = fgetc(fp);
      cimg->C[1]->val[i] = fgetc(fp);
      cimg->C[2]->val[i] = fgetc(fp);
    }
    fclose(fp);
  }else{
    fprintf(stderr,"Input image must be P6\n");
    exit(-1);
  }

  return(cimg);
}

void    WriteCImage(CImage *cimg, char *filename)
{
  FILE *fp;
  int i,n;

  fp = fopen(filename,"w");
  fprintf(fp,"P6\n");
  fprintf(fp,"%d %d\n",cimg->C[0]->ncols,cimg->C[0]->nrows);
  fprintf(fp,"255\n"); 
  n = cimg->C[0]->ncols*cimg->C[0]->nrows;
  for (i=0; i < n; i++) {
    fputc(cimg->C[0]->val[i],fp);
    fputc(cimg->C[1]->val[i],fp);
    fputc(cimg->C[2]->val[i],fp);
  }
  fclose(fp); 
}

CImage *CScale(CImage *cimg, float Sx, float Sy)
{
  CImage *scl=NULL;
  int i;

  scl = (CImage *) calloc(1,sizeof(CImage));
  if (scl == NULL){
    Error(MSG1,"CreateCImage");
  }
  for (i=0; i<3; i++)
    scl->C[i] = Scale(cimg->C[i], Sx, Sy);
  return (scl);
}


CImage *CImageRGBtoYCbCr(CImage *cimg)
{
  CImage *ncimg=NULL;
  int p,n,i;


  ncimg = CreateCImage(cimg->C[0]->ncols,cimg->C[0]->nrows);
  n    = ncimg->C[0]->ncols*ncimg->C[0]->nrows;

  for (p=0; p < n; p++){

    i = triplet(cimg->C[0]->val[p],cimg->C[1]->val[p],cimg->C[2]->val[p]);
    i = RGB2YCbCr(i);
    ncimg->C[0]->val[p]=t0(i);
    ncimg->C[1]->val[p]=t1(i);
    ncimg->C[2]->val[p]=t2(i);
  }

  return(ncimg);
}

CImage *CImageYCbCrtoRGB(CImage *cimg)
{
  CImage *ncimg=NULL;
  int p,n,i;


  ncimg = CreateCImage(cimg->C[0]->ncols,cimg->C[0]->nrows);
  n    = ncimg->C[0]->ncols*ncimg->C[0]->nrows;

  for (p=0; p < n; p++){

    i = triplet(cimg->C[0]->val[p],cimg->C[1]->val[p],cimg->C[2]->val[p]);
    i = YCbCr2RGB(i);
    ncimg->C[0]->val[p]=t0(i);
    ncimg->C[1]->val[p]=t1(i);
    ncimg->C[2]->val[p]=t2(i);
  }

  return(ncimg);
}

CImage *CImageRGBtoHSV(CImage *cimg)
{
  CImage *ncimg=NULL;
  int p,n,i;


  ncimg = CreateCImage(cimg->C[0]->ncols,cimg->C[0]->nrows);
  n    = ncimg->C[0]->ncols*ncimg->C[0]->nrows;

  for (p=0; p < n; p++){

    i = triplet(cimg->C[0]->val[p],cimg->C[1]->val[p],cimg->C[2]->val[p]);
    i = RGB2HSV(i);
    ncimg->C[0]->val[p]=t0(i);
    ncimg->C[1]->val[p]=t1(i);
    ncimg->C[2]->val[p]=t2(i);
  }

  return(ncimg);
}


CImage *CImageHSVtoRGB(CImage *cimg)
{
  CImage *ncimg=NULL;
  int p,n,i;


  ncimg = CreateCImage(cimg->C[0]->ncols,cimg->C[0]->nrows);
  n    = ncimg->C[0]->ncols*ncimg->C[0]->nrows;

  for (p=0; p < n; p++){

    i = triplet(cimg->C[0]->val[p],cimg->C[1]->val[p],cimg->C[2]->val[p]);
    i = HSV2RGB(i);
    ncimg->C[0]->val[p]=t0(i);
    ncimg->C[1]->val[p]=t1(i);
    ncimg->C[2]->val[p]=t2(i);
  }

  return(ncimg);
}
