Created
June 18, 2012 17:09
-
-
Save okthatsneat/2949459 to your computer and use it in GitHub Desktop.
pgmnorm.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <math.h> | |
#include <errno.h> | |
#define STRINGBUF 1024 | |
#define SPACE 32 | |
#define LINEBREAK 10 | |
#define CHAR_P 80 | |
#define CHAR_5 53 | |
typedef unsigned char byte; // einen neuen Daten-Typ-Bezeichner "byte" definiert. | |
typedef struct image { | |
char pgmType[2]; // P5 for binary PGM | |
char** comments; // not mandatory | |
unsigned short width; | |
unsigned short height; | |
byte** data; // datamatrix for greyvalues | |
unsigned short depth; // max grey value (255) | |
} Image; | |
/********************************************************************************************/ | |
int usage(char* s) { | |
printf("usage: %s <infile> -o <outfile> or %s <infile> | display\n",s,s); | |
return 1; | |
} | |
/********************************************************************************************/ | |
unsigned short LoadPGM(FILE * inFile, Image * inImg) { | |
// parse binary pgn file to validate format, extract width, height, and greyvalue data array. | |
// read file bytewise | |
int position = 1; | |
int c; | |
// parse first line. Expecting P5, abort if not. P is 80, 5 is 53, linebreak is 10 | |
while ((c = fgetc(inFile)) != LINEBREAK) { | |
if( position == 1 && !(c == CHAR_P) ) { | |
printf("argument is not binary PGM file> fail\n"); | |
return 1; | |
} | |
if( position == 2 && !(c == CHAR_5) ) { | |
printf("argument is not binary PGM file> fail\n"); | |
return 1; | |
} | |
inImg->pgmType[position-1] = c; | |
position ++; | |
} | |
/********************************************************************************************/ | |
// skip the next 3 lines, those are comments. | |
for (int i=0; i<3; i++) { | |
while ((c = fgetc(inFile)) != LINEBREAK){} | |
} | |
/********************************************************************************************/ | |
// now we're at the width. 32 is space, so read till 32 for width, and then till newline(=10) for height. | |
// construct the byte array that is the width byte by byte. | |
position=0; | |
// dirty fix> have to figure out how to determine the size of the bytearray sometime. this will only work if i know the values in advance... | |
char soonAnInt[STRINGBUF]; | |
memset(&soonAnInt[0], 0, sizeof(soonAnInt)); | |
while ((c = fgetc(inFile)) != SPACE){ | |
soonAnInt[position] = c; | |
position++; | |
if(position > STRINGBUF) { | |
//freak out | |
} | |
} | |
inImg->width = atoi(soonAnInt); | |
/********************************************************************************************/ | |
// now the height | |
// reset position and char array helpers | |
position=0; | |
memset(&soonAnInt[0], 0, sizeof(soonAnInt)); | |
// and again, only here till line break | |
while ((c = fgetc(inFile)) != LINEBREAK){ | |
soonAnInt[position] = c; | |
position++; | |
} | |
inImg->height = atoi(soonAnInt); | |
/********************************************************************************************/ | |
// now we're getting the depth info, 255 / ignore till next newline | |
position=0; | |
memset(&soonAnInt[0], 0, sizeof(soonAnInt)); | |
while ((c = fgetc(inFile)) != LINEBREAK){ | |
soonAnInt[position] = c; | |
position++; | |
} | |
inImg->depth = atoi(soonAnInt); | |
/********************************************************************************************/ | |
/********************************************************************************************/ | |
// allocate memory for inImg bytes | |
int i=0,j=0; | |
// Allocation | |
inImg->data = (byte **) malloc(inImg->height*sizeof(byte*)); | |
for(i=0;i<inImg->height;i++){ | |
inImg->data[i]=(byte *) malloc(inImg->width*sizeof(byte)); | |
} | |
/********************************************************************************************/ | |
// fill data with values | |
for(i=0;i<inImg->height;i++) { | |
//runs once for every line | |
for(j=0;j<inImg->width;j++) { | |
//runs once for every pixel inside that line, for each line. | |
if ((c = fgetc(inFile)) != EOF) { | |
inImg->data[i][j] = c; | |
} else { | |
inImg->data[i][j] = 0; | |
} | |
} | |
} | |
return 0; | |
} | |
/********************************************************************************************/ | |
unsigned short PrintPGM(Image * outImg){ | |
// first put the pgm type info, followed by a LINEBREAK | |
// convert chars in pgmtype to int | |
putchar(outImg->pgmType[0]); | |
putchar(outImg->pgmType[1]); | |
putchar(LINEBREAK); | |
// width and height delimited by space | |
printf("%i %i", outImg->width, outImg->height ); | |
putchar(LINEBREAK); | |
// bit depth | |
printf("%i", outImg->depth ); | |
putchar(LINEBREAK); | |
// pixel byte data | |
for(int i=0;i<outImg->height;i++){ | |
for(int j=0;j<outImg->width;j++){ | |
putchar(outImg->data[i][j]); | |
} | |
} | |
return 1; | |
} | |
/********************************************************************************************/ | |
unsigned short NormPGM(Image * inImg, Image * outImg){ | |
int i,j; | |
// determine min and max values of inImg | |
int maxVal=0; | |
int minVal=0; | |
for(i=0;i<inImg->height;i++){ | |
for(j=0;j<inImg->width;j++){ | |
int val = inImg->data[i][j]; | |
if (maxVal < val) { | |
maxVal = val; | |
} | |
if (minVal > val) { | |
minVal = val; | |
} | |
} | |
} | |
// Allocation | |
outImg->data = (byte **) malloc(inImg->height*sizeof(byte*)); | |
for(i=0;i<inImg->height;i++){ | |
outImg->data[i]=(byte *) malloc(inImg->width*sizeof(byte)); | |
} | |
// copy other metadata from inImg to outImg | |
outImg->width = inImg->width; | |
outImg->height = inImg->height; | |
outImg->depth = inImg->depth; | |
outImg->pgmType[0] = inImg->pgmType[0]; | |
outImg->pgmType[1] = inImg->pgmType[1]; | |
// normalize algorithm | |
int oldRange = maxVal-minVal; | |
int val=0; | |
for(int i=0;i<inImg->height;i++){ | |
for(int j=0;j<inImg->width;j++){ | |
val = inImg->data[i][j]; | |
outImg->data[i][j] = (val-minVal)*(inImg->depth/oldRange); | |
//printf("normalizing old val %i to %i (%i reduction)\n",val,outImg->data[i][j],(val-outImg->data[i][j])); | |
} | |
} | |
return 1; | |
} | |
/********************************************************************************************/ | |
unsigned short SavePGM(FILE * outFile, Image * outImg){ | |
// first put the pgm type info, followed by a LINEBREAK | |
// convert chars in pgmtype to int | |
fputc( outImg->pgmType[0], outFile ); | |
fputc( outImg->pgmType[1], outFile ); | |
fputc(LINEBREAK, outFile); | |
// fputc the comments here - not mandatory | |
// width and height delimited by space | |
fprintf(outFile, "%i %i", outImg->width, outImg->height ); | |
fputc(LINEBREAK, outFile); | |
// bit depth | |
fprintf(outFile, "%i", outImg->depth ); | |
fputc(LINEBREAK, outFile); | |
// pixel byte data | |
for(int i=0;i<outImg->height;i++){ | |
for(int j=0;j<outImg->width;j++){ | |
fputc(outImg->data[i][j], outFile); | |
//printf("writing data[%i][%i] to file (%1x)\n", i,j,(unsigned)(unsigned char)outImg->data[i][j]); | |
} | |
} | |
fclose(outFile); | |
return 1; | |
} | |
/********************************************************************************************/ | |
Image* NewPGM() { | |
return calloc(1,sizeof(Image)); | |
} | |
/********************************************************************************************/ | |
void FreePGM(Image* image) { | |
// free any stuff pointed to by a struct Image | |
for(int i=0;i<image->height;i++){ | |
free(image->data[i]); | |
} | |
free(image->data); | |
} | |
/********************************************************************************************/ | |
int main(int argc, char* argv[]) { | |
int rv; | |
FILE* fp; | |
Image* im = NewPGM(); | |
Image* imOut = NewPGM(); | |
char* outfilename = 0; | |
/* | |
Aufruf: (wahlweise) | |
pgmnorm.elf <infile> | display (pipe to: display) | |
pgmnorm.elf <infile> -o <outfile> | |
Beispiel: | |
pgmnorm logo.bin.pgm -o normalized.bin.pgm | |
*/ | |
if(argc == 1) { | |
return(usage(argv[0])); | |
} | |
int i; | |
for(i = 1; i < argc; i++) { | |
if(argv[i][0] == '-') { | |
if(argv[i][1] == 'o') { | |
outfilename = argv[i+1]; | |
} | |
} | |
} | |
fp = fopen(argv[1], "r"); | |
if (!fp) { | |
fprintf (stderr, "failed opening file\n"); | |
return EXIT_FAILURE; | |
} | |
if( (rv = LoadPGM(fp, im)) ) { | |
fprintf(stderr, "LoadPGM returns %i\n",rv); | |
return EXIT_FAILURE; | |
} | |
NormPGM(im, imOut); | |
if(outfilename) { | |
fp = fopen(outfilename,"w+"); | |
SavePGM(fp, imOut); | |
} else { | |
PrintPGM(imOut); | |
} | |
FreePGM(im); | |
if(im != imOut) { | |
FreePGM(imOut); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment