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


/******************************************************************************/

typedef struct {
	int width;
	int height;
	unsigned char **pixels;
} Image;


/*******************************************************************************
 Creates an Image with 'width' columns and 'height' rows.
 'width' and 'height' are supposed to be greater than 0.
 Returns a pointer to the Image (NULL if unsuccessful).
 All grey levels in the Image are set to 'greyLevel',
 which is supposed to be between 0 and 255.
 ******************************************************************************/

Image *createImage (int width, int height, int greylevel) {
    
	int i, j;
	unsigned char **pixels;
	Image *ima;
    
    ima=(Image *)malloc(sizeof(Image));
    if(ima==NULL) return NULL;
    
	ima->width=width;
	ima->height=height;
    
    pixels=(unsigned char **)malloc(height*sizeof(unsigned char *));
    if(pixels==NULL) {
        free(ima);
        return NULL;
    }
    
	for(i=0;i<height;i++) {
        
		pixels[i]=(unsigned char *)calloc(width,sizeof(unsigned char));
        if(pixels[i]==NULL) {
            for(j=0;j<i;j++)
                free(pixels[j]);
            free(pixels);
            free(ima);
            return NULL;
        }
        
        if(greylevel!=0)
            for(j=0;j<width;j++)
                pixels[i][j]=greylevel;
    }
    
	ima->pixels=pixels;
    return ima;
}


/*******************************************************************************
 Reads a P2 (text) or P5 (binary) 8-bit pgm/pbm file and returns 
 a pointer to the corresponding Image (NULL if unsuccessful).
 ******************************************************************************/

Image *readImage (char *filename) {
   
    FILE *fp;
    Image *ima;
    char line[256];
    unsigned char **pixels;
    int i, j, k, w, h, binary;

    fp=fopen(filename,"rb");
    if(fp==NULL) return NULL;

    fgets(line,256,fp);
    if(strncmp(line,"P5",2)) {
	    if(strncmp(line,"P2",2)) {
		    fclose(fp);
			return NULL;
	    } else binary=0;
    } else binary=1;

    fgets(line,256,fp);
    while(line[0]=='#') fgets(line,256,fp);
    i=sscanf(line,"%d %d ",&w,&h);
    if(i==1) {
        fgets(line,256,fp);
        sscanf(line,"%d",&h);
    }
    
    fgets(line,256,fp);
    sscanf(line,"%d",&k);
    if(k!=255) {
        fclose(fp);
        return NULL;
    }
    
    ima=createImage(w,h,0);
    if(ima==NULL) {
        fclose(fp);
        return NULL;
    }
    
    pixels=ima->pixels;
	if(binary)
		for(j=0;j<h;j++)
			fread((void*)(pixels[j]),sizeof(unsigned char),w,fp);
    else
        for(j=0;j<h;j++) 
            for(i=0;i<w;i++) {
                fscanf(fp,"%d",&k);
                pixels[j][i]=k;
            }

    fclose(fp);
    return(ima);
}


/*******************************************************************************
 Writes an Image into a P2 (if 'binary' is 0) or P5 (if 'binary' is not 0)
 pgm/pbm file. Returns 1 if the file 'filename' could be created, 0 otherwise.
 ******************************************************************************/

int writeImage (char *filename, int binary, Image *ima) {
    
	FILE *fp;
	unsigned char **pixels;
	int i, j, w, h;
	
	fp=fopen(filename,"w");
    if(fp==NULL) return 0;
    
	w=ima->width;
	h=ima->height;
	pixels=ima->pixels;
    
    if(binary) fprintf(fp,"P5\n");
    else fprintf(fp,"P2\n");
	fprintf(fp,"%d\n%d\n",w,h);
	fprintf(fp,"%d\n",255);
    
    if(binary)
        for(j=0;j<h;j++)
            fwrite((void*)(pixels[j]),sizeof(unsigned char),w,fp);
    else
        for(j=0;j<h;j++) {
            for(i=0;i<w;i++)
                fprintf(fp,"%d ",(int)(pixels[j][i]));
            fprintf(fp,"\n");
        }
    
	fclose(fp);
	return 1;
}


/*******************************************************************************
 Frees the memory used by an Image.
 ******************************************************************************/

void destroyImage (Image *ima) {
    
	int i, h;
	unsigned char **pixels;
    
	h=ima->height;
	pixels=ima->pixels;
	for(i=0;i<h;i++)
		free(pixels[i]);
	free(pixels);
	free(ima);
}

