#include <stdio.h>
#include <png.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
/* usage: eWav2png-4096 input.eWav output.png (1|2|3|4|5|6) */
int main(int argc, char* argv[])
{
/***************************/
/* Variable initialization */
/***************************/
FILE *ifp,*ofp;
int DEBUG=0;
/* eWav information */
u_int16_t *Amplitude;
typedef struct eWavHead
{
u_int64_t Channels; /* number of channels stored in file */
u_int64_t WFD_Offset; /* Offset in bytes from beginning of file to first eWav File Directory */
} eWavHead; /* 16 bytes */
typedef struct ChannelHeader
{
float ResX; /* Image resolution in dots/cm */
float RexY; /* Image resolution in dots/cm */
double Scale_mm_sec;
double Scale_mv_cm;
u_int32_t Samples;
} ChannelHeader;
eWavHead FileHeader;
ChannelHeader ch;
u_int16_t max,min;
/* image information */
int data_width, image_width,image_height, x, y, row, image_float, image_size;
int bottom, top, last, i, j, png_scale, amp;
float xpixline,ypixline,xstep,ystep;
/* png information */
png_structp write_ptr;
png_infop write_info_ptr;
unsigned char **row_pointers, invisigrey, linegrey, background, signalblack;
/*********************/
/* Read in eWav file */
/*********************/
ifp = fopen(argv[1], "rb");
fread(&FileHeader,sizeof(eWavHead),1,ifp);
fread(&ch,sizeof(ChannelHeader),1,ifp);
if (DEBUG) fprintf(stderr,"Channels:%d, Offset:%d\n",(int)FileHeader.Channels,(int)FileHeader.WFD_Offset);
if (DEBUG) fprintf(stderr,"X resolution: %f, Y resolution: %f, cm/sec: %f, Millivolts/cm: %f, Samples:%d\n",
ch.ResX,ch.RexY,ch.Scale_mm_sec/10,ch.Scale_mv_cm,(int)ch.Samples);
png_scale=atoi(argv[3]);
data_width=ch.Samples;
Amplitude=(u_int16_t *)calloc(data_width,sizeof(u_int16_t));
fread(Amplitude,sizeof(u_int16_t),data_width,ifp);
fclose(ifp);
/*******************************/
/* Find max and min amplitudes */
/*******************************/
max=min=Amplitude[0];
for(i=0;i<data_width;i++)
{
if (Amplitude[i]>max)
max=Amplitude[i];
if (Amplitude[i]<min)
min=Amplitude[i];
}
if (DEBUG) fprintf(stderr,"Max amp=%d, Min amp=%d\n",max,min);
if (DEBUG) fprintf(stderr,"Pixels/sec:%f, Pixels/mVolt:%f\n",ch.ResX*ch.Scale_mm_sec/10,ch.RexY*ch.Scale_mv_cm);
/*****************************************/
/* Determine image size and grid spacing */
/*****************************************/
xpixline=((ch.ResX*ch.Scale_mm_sec/10)/5)/png_scale; /* width in pixels between */
ypixline=(ch.RexY*ch.Scale_mv_cm)/png_scale;
if (DEBUG) fprintf(stderr,"xpixline=%f, ypixline=%f\n",xpixline,ypixline);
image_height=1.2*(max-min)/png_scale;
image_float=0.1*(max-min)/png_scale;
if (4096>=data_width/png_scale)
image_width=data_width/png_scale;
else
image_width=4096;
xstep=image_width/xpixline;
ystep=image_height/ypixline;
if (DEBUG) fprintf(stderr,"xstep=%f, ystep=%f\n",xstep,ystep);
/******************************/
/* Allocate clear image space */
/******************************/
row_pointers=malloc(image_height*sizeof(unsigned char *));
for (row = 0; row < image_height; row++)
{
row_pointers[row] = malloc(image_width*sizeof(unsigned char));
memset(row_pointers[row],255,image_width*sizeof(unsigned char));
}
if (DEBUG) fprintf(stderr,"Created image space.\n");
image_size=image_height*image_width;
printf("%d %d %d\n",image_height,image_width,image_size);
/*************/
/* Draw Dots */
/*************/
background=255;
invisigrey=240;
linegrey=200;
if (DEBUG) fprintf(stderr," Draw vertical guidelines\n");
/* Draw vertical guidelines */
for (x=0;x<=(int)(xstep*5);x++)
for (y=0;y<image_height;y++)
{
row_pointers[y][(int)floor(x*xpixline/5)]=invisigrey;
row_pointers[y][(int)floor(x*xpixline/5)+1]=invisigrey;
}
if (DEBUG) fprintf(stderr," Draw virtual horizontal guidelines marking intersections with vertical guidelines\n");
/* Draw virtual horizontal guidelines marking intersections with vertical guidelines */
for (y=0;y<=(int)(ystep*5);y++)
for (x=0;x<image_width;x++)
{
if (invisigrey==row_pointers[(int)floor(y*ypixline/5)][x])
row_pointers[(int)floor(y*ypixline/5)][x]=linegrey;
if (invisigrey==row_pointers[((int)floor(y*ypixline/5)+1)][x])
row_pointers[((int)floor(y*ypixline/5)+1)][x]=linegrey;
}
if (DEBUG) fprintf(stderr," Erase vertical guidelines\n");
/* Erase vertical guidelines */
for (x=0;x<=(int)(xstep*5);x++)
for (y=0;y<image_height;y++)
{
if (invisigrey==row_pointers[y][(int)floor(x*xpixline/5)])
row_pointers[y][(int)floor(x*xpixline/5)]=background;
if (invisigrey==row_pointers[y][(int)floor(x*xpixline/5)+1])
row_pointers[y][(int)floor(x*xpixline/5)+1]=background;
}
/*************/
/* Draw grid */
/*************/
if (DEBUG) fprintf(stderr," Draw vertical grid lines\n");
/* Draw vertical grid lines */
for (x=0;x<=(int)(xstep);x++)
for (y=0;y<image_height;y++)
{
row_pointers[y][(int)floor(x*xpixline)]=linegrey;
row_pointers[y][(int)floor(x*xpixline)+1]=linegrey;
}
if (DEBUG) fprintf(stderr," Draw horizontal grid lines\n");
/* Draw horizontal grid lines */
for (y=0;y<=(int)(ystep);y++)
for (x=0;x<image_width;x++)
{
row_pointers[(int)floor(y*ypixline)][x]=linegrey;
row_pointers[((int)floor(y*ypixline)+1)][x]=linegrey;
}
/***************/
/* Draw signal */
/***************/
signalblack=0;
last=Amplitude[0]/png_scale;
for (x=1;x<image_width*png_scale-png_scale;x+=png_scale)
{
bottom=-1;
top=1;
amp=0;
for (i=0; i<png_scale;i++)
{
j=x+i;
amp+=Amplitude[j];
if (DEBUG) fprintf(stderr,"Amplitude[%d+%d]=%d\n",x,i,Amplitude[j]);
}
amp/=png_scale; /* take average */
if (DEBUG) fprintf(stderr," Average=%d ",amp);
amp/=png_scale; /* reduce scale */
if (DEBUG) fprintf(stderr,"Scale=%d\n",amp);
/* This makes the line at least 5 pixels wide. */
/* if the datapoints are seperated by more than 2 pixels, the line is made */
/* wider by the corresponding number of pixels. */
if (last-amp<bottom)
bottom=last-amp-1;
if (last-amp>top)
top=last-amp+1;
if (DEBUG) fprintf(stderr,"Last=%d, current=%d, Bottom=%d, Top=%d\n",last,amp,bottom,top);
last=amp;
for (y=bottom;y<=top;y++)
for (j=-1;j<=1;j++)
{
if (DEBUG) fprintf(stderr,"row_pointers[(%d-(%d-%d+%d+%d))][%d+%d]\n",image_height,amp,min/png_scale,image_float,y,x/png_scale,j);
row_pointers[(image_height-(amp-min/png_scale+image_float+y))][x/png_scale+j]=signalblack;
}
}
/*******************/
/* Write PNG image */
/*******************/
/* Open output file */
ofp = fopen(argv[2], "wb");
if (!ofp)
return(1); /* 1 = couldn't open output file */
if (DEBUG) fprintf(stderr,"Opened output file.\n");
/* Initialize image variables */
write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
(png_error_ptr)NULL, (png_error_ptr)NULL);
if (!write_ptr)
return(2); /* 2 = couldn't allocate write structure */
if (DEBUG) fprintf(stderr,"Allocated write structure.\n");
write_info_ptr = png_create_info_struct(write_ptr);
if (!write_info_ptr)
{
png_destroy_write_struct(&write_ptr,(png_infopp)NULL);
return(3); /* 3 = couldn't allocate info structure */
}
if (DEBUG) fprintf(stderr,"Allocated Info structure.\n");
if (setjmp(write_ptr->jmpbuf))
{
png_destroy_write_struct(&write_ptr, &write_info_ptr);
fclose(ofp);
return(4); /* 4 = libpng write error */
}
if (DEBUG) fprintf(stderr,"Tested longjmp\n");
png_init_io(write_ptr, ofp);
if (DEBUG) fprintf(stderr,"Initialized output pointer.\n");
/* Define information about image */
png_set_IHDR(write_ptr, write_info_ptr, image_width, image_height,
8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
if (DEBUG) fprintf(stderr,"Defined info about image.\n");
/* Write info up to image data */
png_write_info(write_ptr, write_info_ptr);
if (DEBUG) fprintf(stderr,"Wrote preliminary image data.\n");
png_write_image(write_ptr, row_pointers);
png_write_end(write_ptr, write_info_ptr);
if (DEBUG) fprintf(stderr,"Called end to data.\n");
/* Tidy up */
png_destroy_write_struct(&write_ptr, &write_info_ptr);
if (DEBUG) fprintf(stderr,"Destroyed write structure.\n");
exit(0);
}