/* Laplace filter v1.0.0 Ver.:OK (c) 12/07 - Christos Iosifides */
/*
   Name:   Laplace_8ui
   Version:  1.0.0
   Author:  Christos Iosifidis
   Date:   03/12/07 11:30
   Description: Laplace filter on 8bit unsigned int BIL datasets
   Usage: >Laplace_8ui filename_of_the_8bit_unsigned_int_BIL_dataset filename_of_the_IEEE4byteReal_BIL_Laplaced_dataset rows columns bands

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void error(const char *);

int main(int argc, char *argv[]) {
    FILE *fpin, *fpout;
    int rows, cols, bands, win, win_2, rows_1, cols_1, cols2, rows_win_2, cols_win_2, win_1, bv[9], X;
    unsigned char *in_buffer;
    unsigned short int *out_buffer;
    register int r, c, i, j;

    if (argc!=6)
        error("Usage parameters: Input_image Output_image rows cols bands");

    rows=atoi(argv[3]);
    cols=atoi(argv[4]);
    bands=atoi(argv[5]);
    if (rows<3)
        error("rows must be larger than 3");
    if (cols<3)
        error("columns must be larger than 3");
    if (bands<1)
        error("bands must be more than 1");

    cols*=bands;
    rows_1=rows-1;
    cols_1=cols-1;
    cols2=cols<<1;
    win=3;
    win_2=1; /* 3>>1 */

    /* Allocate input buffer */
    if ((in_buffer=(unsigned char *)malloc(win*cols))==NULL)
        error("Not enough memory avaliable for input buffer");
    /* Open input image */
    if ((fpin=fopen(argv[1],"rb"))==NULL)
        error("Bad input file name");
    /* Open output image */
    if ((fpout=fopen(argv[2],"wb"))==NULL)
        error("Bad output file open");
    /* Allocate output file */
    if ((out_buffer=(unsigned short int *)malloc(cols*sizeof(unsigned short int)))==NULL)
        error("Not enough memory avaliable for output buffer");

    /* Store 0 in first empty line */
    memset(out_buffer, 0, cols2);
    /* Write first empty line */
    if (fwrite(out_buffer, sizeof(unsigned short int), cols, fpout)!=cols)
        error("Bad write to output file 1");
    /* Read first two lines in buffer */
    if (fread(in_buffer, 1, cols2, fpin)!=cols2)
        error("Bad read from input file 1");

    /* For every row in [ 1, rows-1 ] */
    for (r=1;r<rows_1;r++) {
        /* Store first and last pixels */
        out_buffer[0]=out_buffer[cols_1]=0;
        /* Read line in buffer */
        if (fread(in_buffer+cols2, 1, cols, fpin)!=cols)
            error("Bad read from input file 2");
        /* For every column in [ 1, cols-1 ] */
        for (c=1;c<cols_1;c++) {
            /* Store window into image buffer */
            bv[0]=in_buffer[c-1];
            bv[1]=in_buffer[c];
            bv[2]=in_buffer[c+1];
            bv[3]=in_buffer[cols+c-1];
            bv[4]=in_buffer[cols+c];
            bv[5]=in_buffer[cols+c+1];
            bv[6]=in_buffer[cols2+c-1];
            bv[7]=in_buffer[cols2+c];
            bv[8]=in_buffer[cols2+c+1];
            /* Compute Laplace operator */
            X=8*bv[4]-(bv[0]+bv[1]+bv[2]+bv[3]+bv[5]+bv[6]+bv[7]+bv[8]);
            /* Store result */
            out_buffer[c]=(unsigned short int)( X + 2048 ); //8*256
        }
        /* Scroll win_2 lines up in buffer */
        memcpy(in_buffer, in_buffer+cols, cols2);
        /* Write results */
        if (fwrite(out_buffer, sizeof(unsigned short int), cols, fpout)!=cols)
            error("Bad write to output file 2");
    }
    /* Store 0 in last empty line */
    memset(out_buffer, 0, cols2);
    /* Write last empty line */
    if (fwrite(out_buffer, sizeof(unsigned short int), cols, fpout)!=cols)
        error("Bad write to output file 3");

    /* Close files and ... */
    fclose(fpin);
    fclose(fpout);
    free(in_buffer);
    free(out_buffer);
    return 0;
}

void error(const char *s) {
    printf("\nLaplace_8UI reports: Error: <%s>.\n",s);
    exit(1);
}

