/***************************************************************************
                          cimage.cpp  -  description
                             -------------------
    begin                : Wed Jul 18 2001
    copyright            : (C) 2001 by Alper Yilmaz
    email                : yilmaz@cs.ucf.edu
 ***************************************************************************/

//#include <fstream.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "cimage.h"
/***************************************************************************
 *                                                                         *
 *   Constructor                                                           *
 *                                                                         *
 ***************************************************************************/
CImage::CImage()
{
    gradient_called=false;
    image_read=false;
}

CImage::CImage(CImage &image)
{
    int i,j;

    image_read=image.image_read;
    if (image_read)
    {
        rows=image.rows;
        cols=image.cols;
        gradient_called=image.gradient_called;
        type=image.type;
        for (i=0;i<image.rows;i++)
            for (j=0;j<image.cols;j++)
            {
                r[i][j] =image.r[i][j];
                g[i][j] =image.g[i][j];
                b[i][j] =image.b[i][j];
                fx[i][j]=image.fx[i][j];
                fy[i][j]=image.fy[i][j];
            }
    }
}
/***************************************************************************
 *                                                                         *
 *   Distructor                                                            *
 *                                                                         *
 ***************************************************************************/
CImage::~CImage()
{
    if (image_read)
    {
        for (int i=0;i<rows;i++)
        {
            delete [] r[i];
            delete [] g[i];
            delete [] b[i];
        }
        delete [] r;
        delete [] g;
        delete [] b;
        if (gradient_called)
        {
            for (int i=0;i<rows;i++)
            {
                delete [] fx[i];
                delete [] fy[i];
            }
            delete [] fx;
            delete [] fy;
        }
    }
}

/***************************************************************************
 *                                                                         *
 *   Read image file                                                       *
 *                                                                         *
 ***************************************************************************/
void CImage::read_file(char *filename)
{
    int max,i,j;
    char buffer[500];
    char im_type[5];
    unsigned char value;
    FILE *fp;

    if (image_read)
    {
        for (i=0;i<rows;i++)
        {
            delete [] r[i];
            delete [] g[i];
            delete [] b[i];
        }
        delete [] r;
        delete [] g;
        delete [] b;
        if (gradient_called)
        {
            for (int i=0;i<rows;i++)
            {
                delete [] fx[i];
                delete [] fy[i];
            }
            delete [] fx;
            delete [] fy;
        }
    }


    if ( (fp=fopen(filename,"rb"))==NULL) {
        fprintf(stderr,"Couldn't open file %s :( Exiting!\n",filename);
        exit(0);
    }

    fscanf(fp, "%s\n", im_type);
    //read type of the file
    if (im_type[1]=='5')
        type=PGM;
    else
        type=PPM;
    //read the comments
    do
    {
        fgets(buffer,499,fp);
    }
    while(buffer[0] == '#');
    //read number of rowsand cols
    sscanf(buffer,"%d %d",&cols,&rows);
    //read max gray level
    fscanf(fp, "%d", &max);
    fgetc(fp); // read the extra newline character
    r=new float*[rows];
    for (i=0;i<rows;i++)
        r[i]=new float [cols];
    g=new float*[rows];
    for (i=0;i<rows;i++)
        g[i]=new float [cols];
    b=new float*[rows];
    for (i=0;i<rows;i++)
        b[i]=new float [cols];
    if (type == PGM)
        for(i=0;i<rows;i++)
            for(j=0;j<cols;j++)
            {
                value=fgetc(fp);
                r[i][j]=(float )value;
                g[i][j]=(float )value;
                b[i][j]=(float )value;
            }
    else
    {
        for(i=0;i<rows;i++)
            for(j=0;j<cols;j++)
            {
                value=fgetc(fp);
                r[i][j]=(float )value;
                value=fgetc(fp);
                g[i][j]=(float )value;
                value=fgetc(fp);
                b[i][j]=(float )value;
            }
    }
    fclose(fp);
    image_read=true;
//    delete buffer;
//    delete im_type;
}

/***************************************************************************
 *                                                                         *
 *   Write image file                                                      *
 *                                                                         *
 ***************************************************************************/
void CImage::write_file(char *filename)
{
    int  i,j;
    FILE* outfile;
    outfile=fopen(filename,"wb");
    if (type==PGM)
    {
        fprintf(outfile,"P5\n#my output\n%d %d\n255\n",cols,rows);
        for (i=0;i<rows;i++)
            for (j=0;j<cols;j++)
                fprintf(outfile,"%c",(unsigned char)r[i][j]);
    }
    else
    {
        fprintf(outfile,"P6\n#my output\n%d %d\n255\n",cols,rows);
        for (i=0;i<rows;i++)
            for (j=0;j<cols;j++)
                fprintf(outfile,"%c%c%c",(unsigned char)r[i][j],
                        (unsigned char)g[i][j],
                        (unsigned char)b[i][j]);
    }
    fclose(outfile);
}

/***************************************************************************
 *                                                                         *
 *   Draw circle in the image                                              *
 *                                                                         *
 ***************************************************************************/
void CImage::draw_circle (int origx,int origy,int radius,float _r,float _g,float _b)
{
    int x,y;
    for (x=0;x<=radius;x++)
    {
        y=(int)ceil(sqrt(radius*radius-x*x));
        if (origx+x<cols && origy-y>=0)
        {
            r[ (origy-y)][(origx+x)]=_r;
            g[ (origy-y)][(origx+x)]=_g;
            b[ (origy-y)][(origx+x)]=_b;
        }
        if (origx+x<cols && origy+y<rows)
        {
            r[ (origy+y)][(origx+x)]=_r;
            g[ (origy+y)][(origx+x)]=_g;
            b[ (origy+y)][(origx+x)]=_b;
        }
        if (origx-x>=0 && origy-y>=0)
        {
            r[ (origy-y)][(origx-x)]=_r;
            g[ (origy-y)][(origx-x)]=_g;
            b[ (origy-y)][(origx-x)]=_b;
        }
        if (origx-x>=0 && origy+y<rows)
        {
            r[ (origy+y)][(origx-x)]=_r;
            g[ (origy+y)][(origx-x)]=_g;
            b[ (origy+y)][(origx-x)]=_b;
        }
    }
    for (y=0;y<=radius;y++)
    {
        x=(int)ceil(sqrt(radius*radius-y*y));
        if (origx+x<cols && origy-y>=0)
        {
            r[ (origy-y)][(origx+x)]=_r;
            g[ (origy-y)][(origx+x)]=_g;
            b[ (origy-y)][(origx+x)]=_b;
        }
        if (origx+x<cols && origy+y<rows)
        {
            r[ (origy+y)][(origx+x)]=_r;
            g[ (origy+y)][(origx+x)]=_g;
            b[ (origy+y)][(origx+x)]=_b;
        }
        if (origx-x>=0 && origy-y>=0)
        {
            r[ (origy-y)][(origx-x)]=_r;
            g[ (origy-y)][(origx-x)]=_g;
            b[ (origy-y)][(origx-x)]=_b;
        }
        if (origx-x>=0 && origy+y<rows)
        {
            r[ (origy+y)][(origx-x)]=_r;
            g[ (origy+y)][(origx-x)]=_g;
            b[ (origy+y)][(origx-x)]=_b;
        }
    }
    return;
}

/***************************************************************************
 *                                                                         *
 *   Draw a cros in the image                                              *
 *                                                                         *
 ***************************************************************************/
void CImage::draw_cross (int center_x,int center_y,int radius,float _r,float _g,float _b)
{
    int i;
    for (i=-radius;i<=radius;i++)
    {
        if (center_x+i>=0 && center_x+i<cols)
        {
            r[center_y][center_x+i]=_r;
            g[center_y][center_x+i]=_g;
            b[center_y][center_x+i]=_b;
        }
        if (center_y+i>=0 && center_y+i<rows)
        {
            r[center_y+i][center_x]=_r;
            g[center_y+i][center_x]=_g;
            b[center_y+i][center_x]=_b;
        }
    }
    return;
}

/***************************************************************************
 *                                                                         *
 *   Find gradient of the image                                            *
 *                                                                         *
 ***************************************************************************/
void CImage::gradient()
{
    int i,j;
    //allocations
    if (gradient_called==false)
    {
        fx=new float*[rows];
        fy=new float*[rows];

        for (i=0;i<rows;i++)
        {
            fx[i]=new float[cols];
            fy[i]=new float[cols];
        }
        gradient_called=true;
    }
    //intializations
    for (i=0;i<rows;i++)
        fx[i][0]=fx[i][cols-1]=fy[i][0]=fy[i][cols-1]=0.0;
    for (j=0;j<cols;j++)
        fx[0][j]=fx[rows-1][j]=fy[0][j]=fy[rows-1][j]=0.0;
    //calculations
    for (i=1;i<rows-1;i++)
        for (j=1;j<cols-1;j++)
        {
            fx[i][j]=(float)r[i][j]-(float)r[i][j-1];
            fy[i][j]=(float)r[i][j]-(float)r[i-1][j];
        }
    return;
}

/***************************************************************************
 *                                                                         *
 *   Gaussian blurring using 5x5 window                                    *
 *                                                                         *
 ***************************************************************************/
void CImage::gauss_blurring()
{
    int i,j,k;
    float gauss[5]={.05,.25,.4,.25,.05};
    float tmp[rows][cols];
    //calculations for R channel
    for (i=0;i<rows;i++)
        for (j=0;j<cols;j++)
        {
            tmp[i][j]=0.0;
            int sk;
            if (j<2)
                sk=0;
            else
                sk=j-2;
            int ek;
            if (j>=cols-2)
                ek=cols-1;
            else
                ek=j+2;
            for (k=sk;k<=ek;k++)
                tmp[i][j]+=(float)r[i][k]*gauss[k-sk];
        }
    for (i=0;i<rows;i++)
        for (j=0;j<cols;j++)
        {
            r[i][j]=0.0;
            int sk;
            if (i<2)
                sk=0;
            else
                sk=i-2;
            int ek;
            if (i>=rows-2)
                ek=rows-1;
            else
                ek=i+2;
            for (k=sk;k<=ek;k++)
                r[i][j]+=tmp[k][j]*gauss[k-sk];
        }
    //calculations for G channel
    for (i=0;i<rows;i++)
        for (j=0;j<cols;j++)
        {
            tmp[i][j]=0.0;
            int sk;
            if (j<2)
                sk=0;
            else
                sk=j-2;
            int ek;
            if (j>=cols-2)
                ek=cols-1;
            else
                ek=j+2;
            for (k=sk;k<=ek;k++)
                tmp[i][j]+=(float)g[i][k]*gauss[k-sk];
        }
    for (i=0;i<rows;i++)
        for (j=0;j<cols;j++)
        {
            g[i][j]=0.0;
            int sk;
            if (i<2)
                sk=0;
            else
                sk=i-2;
            int ek;
            if (i>=rows-2)
                ek=rows-1;
            else
                ek=i+2;
            for (k=sk;k<=ek;k++)
                g[i][j]+=tmp[k][j]*gauss[k-sk];
        }
    //calculations for B channel
    for (i=0;i<rows;i++)
        for (j=0;j<cols;j++)
        {
            tmp[i][j]=0.0;
            int sk;
            if (j<2)
                sk=0;
            else
                sk=j-2;
            int ek;
            if (j>=cols-2)
                ek=cols-1;
            else
                ek=j+2;
            for (k=sk;k<=ek;k++)
                tmp[i][j]+=(float)b[i][k]*gauss[k-sk];
        }
    for (i=0;i<rows;i++)
        for (j=0;j<cols;j++)
        {
            b[i][j]=0.0;
            int sk;
            if (i<2)
                sk=0;
            else
                sk=i-2;
            int ek;
            if (i>=rows-2)
                ek=rows-1;
            else
                ek=i+2;
            for (k=sk;k<=ek;k++)
                b[i][j]+=tmp[k][j]*gauss[k-sk];
        }
    return;
}


