When reading fits files, you usually want to use a FITS library like CFITSIO. Sometimes, though, you want to write a stand-alone program without any external dependencies. FITS is a simple format, and reading one directly is not that hard.
Note that this example is extremely bare-bones; I do not show any error handling, verification that the data is in FITS format, or tolerence (or even detection) of valid differences in how the FITS file might legally be written.
Writing a FITS file is somewhat more challenging, because the standard has many requirements that the reader can safely ignore but the writer cannot. (This example can give you some idea what is involved.)
Start by declaring a structure that mirrors the columns of the FITS table. Each element in the structure must have the same number of bytes as that column in the fits table. For example, for a FITS header with column definitions like this:
TFORM1 = '1D ' TTYPE1 = 'ra0 ' TFORM2 = '1D ' TTYPE2 = 'dec0 ' TFORM3 = '1J ' TTYPE3 = 'run ' TFORM4 = '1J ' TTYPE4 = 'rerun ' TFORM5 = '1J ' TTYPE5 = 'camcol ' TFORM6 = '1J ' TTYPE6 = 'field ' TFORM7 = '1J ' TTYPE7 = 'primary ' |
/** @file sdssfield.h
* @brief The fits structure mirroring the FITS table row content
* @author Eric H. Neilsen, Jr.
*/
typedef struct {
double ra;
double dec;
long run;
long rerun;
long camcol;
long field;
long primary;
} sdssfield;
|
Next, if we want our program to run on a little-endian machine, like most Intel based computers, you need a function to swap bytes from the big-endian FITS format:
/** @file swap_bytes.c
* @brief Swap bytes to switch between big and little endian
* @author Eric H. Neilsen, Jr.
*/
#include <string.h>
int
swap_bytes(void *in,size_t s)
{
char *swapped; /*< Buffer for swapped bytes */
char *outbyte; /*< Pointer to next byte to be written*/
char *inbyte; /*< Pointer to next byte to be read */
swapped=malloc(s);
inbyte = (char *) in + s;
for (outbyte=swapped;outbyte<swapped+s;outbyte++) {
inbyte--;
*outbyte=*inbyte;
}
memcpy(in,swapped,s);
free(swapped);
return s;
}
|
Finally, read the file:
/** @file simple_fits_read.c
* @brief Read a fits table of known structure without a fits library
* @author Eric H. Neilsen, Jr.
*/
#include <stdio.h>
#include <sysexits.h>
#include <string.h>
#include <assert.h>
#include <sdssfield.h>
/**
* @brief The main function, where the work is done
*/
int
main (int argc, const char **argv)
{
char *filename;
FILE *fp;
char hcard[81];
char keyword[9];
char assignment[3];
char comment[71];
int card_index;
int hpassed=0;
long nrows;
long row_index;
sdssfield row;
long endian_test = 1;
int little_endian;
little_endian = (int) ( *(char *)&endian_test ); (1)
filename=(char *) argv[1]; (2)
fp=fopen(filename,"r");
hcard[80]='\0'; (3)
while(hpassed < 2) { (4)
for (card_index=0; card_index<36; card_index++) { (5)
fread(hcard,1,80,fp);
if( strncmp(hcard,"NAXIS2 ",8) == 0 ) { (6)
sscanf(hcard,"%8s%1s%i%s",
keyword,assignment,&nrows,comment);
}
if( strncmp(hcard,"END ",8) == 0 ) {
hpassed++;
}
}
}
for (row_index=0; row_index<nrows; row_index++) {
/* It is safer to read each field individually, rather than
the whole structure, due to memory alignment issues */
fread(&(row.ra),sizeof(row.ra),1,fp);
fread(&(row.dec),sizeof(row.dec),1,fp);
fread(&(row.run),sizeof(row.run),1,fp);
fread(&(row.rerun),sizeof(row.rerun),1,fp);
fread(&(row.camcol),sizeof(row.camcol),1,fp);
fread(&(row.field),sizeof(row.field),1,fp);
fread(&(row.primary),sizeof(row.primary),1,fp);
if ( little_endian ) {
swap_bytes(&(row.ra),sizeof(row.ra));
swap_bytes(&(row.dec),sizeof(row.dec));
swap_bytes(&(row.run),sizeof(row.run));
swap_bytes(&(row.rerun),sizeof(row.rerun));
swap_bytes(&(row.camcol),sizeof(row.camcol));
swap_bytes(&(row.field),sizeof(row.field));
swap_bytes(&(row.primary),sizeof(row.primary));
}
printf("%g\t%g\t%d\t%d\t%d\t%d\n",row.ra,row.dec,row.run,row.rerun,row.camcol,row.field);
}
close(fp);
return EX_OK;
}
|