Skip to content

Instantly share code, notes, and snippets.

@okthatsneat
Created June 18, 2012 17:09
Show Gist options
  • Save okthatsneat/2949459 to your computer and use it in GitHub Desktop.
Save okthatsneat/2949459 to your computer and use it in GitHub Desktop.
pgmnorm.c
#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