Along the pathway

what keeps my mind busy

Reading/Writing PGM Files in C March 4, 2010

Filed under: Technical Posts — ugurkoltuk @ 9:41 pm
Tags: , , ,

Howdy!

Last semester at school was rather tough for me. I had many classes and my junior project, and plus I had a lot of stress because I had no chance to fail in any class. Lucky that stress drives me through better motivation, I was successful in all of my classes and my junior project :)

Here in this post, I’d like to share a part of one of my Image Processing homeworks. It’s just two functions which read and write PGM files, so it’s no big deal. But some of my friends in class asked me if they could use my so-called API (hehe, imagine an API consisting of 2 functions :P) for their homeworks, so I thought it might be useful.

First of all, I find it necessary to say a couple of words on PGM files. The PGM Format Specifification can be found here. As you can see here, there are a couple of PGM files, and these functions (because we were supposed to do it that way in the homework) read only the raw format “P5″.

So here it goes:

typedef struct _PGMData {
    int row;
    int col;
    int max_gray;
    int **matrix;
} PGMData;

This is the data structure to represent the PGM file on the memory. It’s a simle matrix with rows and columns, the top left corner of this matrix is the top left of the image, and top right corner is the top right corner of the image. We will use this structure as an handle to our image on memory.
These are the helper functions, because I have to use these repeatedly:
int **allocate_dynamic_matrix(int row, int col)
{
	int **ret_val;
	int i;

	ret_val = (int **)malloc(sizeof(int *) * row);
	if (ret_val == NULL) {
		perror("memory allocation failure");
		exit(EXIT_FAILURE);
	}

	for (i = 0; i < row; ++i) {
		ret_val[i] = (int *)malloc(sizeof(int) * col);
		if (ret_val[i] == NULL) {
			perror("memory allocation failure");
			exit(EXIT_FAILURE);
		}
	}

	return ret_val;
}

void deallocate_dynamic_matrix(int **matrix, int row)
{
	int i;

	for (i = 0; i < row; ++i)
		free(matrix[i]);
	free(matrix);
}

And here we have 2 macro definitions to be used:

#define HI(num)	(((num) & 0x0000FF00) >> 8)
#define LO(num)	((num) & 0x000000FF)

As you can see, they are responsible for allocating and freeing a matrix (2 dimensional dynamic array.)
And we have another helper function, for parsing purposes which skips the comments in a PGM file:
void SkipComments(FILE *fp)
{
	int ch;
	char line[100];

	while ((ch = fgetc(fp)) != EOF && isspace(ch))
		;
	if (ch == '#') {
		fgets(line, sizeof(line), fp);
		SkipComments(fp);
	} else
		fseek(fp, -1, SEEK_CUR);
}

And here goes the two main functions, for reading from and for writing to a PGM file:

/*for reading:*/
PGMData* readPGM(const char *file_name, PGMData *data)
{
	FILE *pgmFile;
	char version[3];
	int i, j;
	int lo, hi;

	pgmFile = fopen(file_name, "rb");
	if (pgmFile == NULL) {
		perror("cannot open file to read");
		exit(EXIT_FAILURE);
	}

	fgets(version, sizeof(version), pgmFile);
	if (strcmp(version, "P5")) {
		fprintf(stderr, "Wrong file type!\n");
		exit(EXIT_FAILURE);
	}

	SkipComments(pgmFile);
	fscanf(pgmFile, "%d", &data->col);
	SkipComments(pgmFile);
	fscanf(pgmFile, "%d", &data->row);
	SkipComments(pgmFile);
	fscanf(pgmFile, "%d", &data->max_gray);
	fgetc(pgmFile);

	data->matrix = allocate_dynamic_matrix(data->row, data->col);
	if (data->max_gray > 255)
		for (i = 0; i < data->row; ++i)
			for (j = 0; j < data->col; ++j) {
				hi = fgetc(pgmFile);
				lo = fgetc(pgmFile);
				data->matrix[i][j] = (hi << 8) + lo;
			}
	else
		for (i = 0; i < data->row; ++i)
			for (j = 0; j < data->col; ++j) {
				lo = fgetc(pgmFile);
				data->matrix[i][j] = lo;
			}

	fclose(pgmFile);
	return data;

}

/*and for writing*/

void writePGM(const char *filename, const PGMData *data)
{
	FILE *pgmFile;
	int i, j;
	int hi, lo;

	pgmFile = fopen(filename, "wb");
	if (pgmFile == NULL) {
		perror("cannot open file to write");
		exit(EXIT_FAILURE);
	}

	fprintf(pgmFile, "P5 ");
	fprintf(pgmFile, "%d %d ", data->col, data->row);
	fprintf(pgmFile, "%d ", data->max_gray);

	if (data->max_gray > 255) {
		for (i = 0; i < data->row; ++i) {
			for (j = 0; j < data->col; ++j) {
				hi = HI(data->matrix[i][j]);
				lo = LO(data->matrix[i][j]);
				fputc(hi, pgmFile);
				fputc(lo, pgmFile);
			}

		}
	} else {
		for (i = 0; i < data->row; ++i)
			for (j = 0; j < data->col; ++j) {
				lo = LO(data->matrix[i][j]);
				fputc(lo, pgmFile);
			}
	}

	fclose(pgmFile);
	deallocate_dynamic_matrix(data->matrix, data->row);
}

Well, that’s all. I told you that it’s not a big deal, I just wanted to paste it somewhere.
Good luck,
Hayri Uğur KOLTUK

Advertisement
 

2 Responses to “Reading/Writing PGM Files in C”

  1. Rodrigo Says:

    thanks man!
    we have to implement an image compression algorithm, a simplified version of JPEG-LS.
    thanks to your code we don’t need to deal with the i/o!
    :)
    if you’re interested, i’ll post a link to our code if we get something reasonable done.

    thanks again!

  2. rohit Says:

    thanx buddy
    i was looking for a handy code to read and write a pgm image
    i got it , thanx


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.