// fits.c - main functions to work with FITS files // // Copyright 2011 Edward V. Emelianoff // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1301, USA. #include "fits.h" #include "gtk.h" #include "fitsheaders.h" /* * Macros for error processing when working with cfitsio functions */ #define TRYFITS(f, ...) \ do{ gboolean status = FALSE; \ f(__VA_ARGS__, &status); \ if(status){ \ fits_report_error(stderr, status); \ return FALSE;} \ }while(0) #define FITSFUN(f, ...) \ do{ gboolean status = FALSE; \ int ret = f(__VA_ARGS__, &status); \ if(ret || status) \ fits_report_error(stderr, status); \ }while(0) #define WRITEKEY(...) \ do{ gboolean status = FALSE; \ fits_write_key(__VA_ARGS__, &status); \ if(status) fits_report_error(stderr, status);\ }while(0) /* * Check whether a number is a complex * If yes - returns true, no - false * If re and/or im!=NULL, in them stored values * of real and imaginary components */ gboolean cmplx_conv(gchar *value, double *re, double *im){ double sign = 1.; double r,i; gchar *ptr1, *ptr2, *eptr; ptr1 = g_strstr_len(value, -1, "("); if(ptr1){ // form is (re, im) or (re im) ptr1++; ptr2 = g_strstr_len(ptr1, -1, ")"); if(ptr2) *ptr2 = 0; ptr2 = g_strstr_len(ptr1, -1, ","); if(!ptr2) ptr2 = g_strstr_len(ptr1, -1, " "); } else{ // form is re + iim or re + jim ptr1 = value; ptr2 = g_strstr_len(ptr1, -1, "i"); if(!ptr2) ptr2 = g_strstr_len(ptr1, -1, "j"); } if(ptr2){ *ptr2 = 0; ptr2++; } else return FALSE; if(g_strrstr_len(ptr1, 3, "-")) sign=-1.; r = strtod(ptr1, &eptr); if(eptr == ptr1) return FALSE; i = sign*strtod(ptr2, &eptr); if(eptr == ptr2) return FALSE; if(re) *re = r; if(im) *im = i; return TRUE; } /* * try to guess key type: * TLONGLONG, TDOUBLE, TDBLCOMPLEX or TSTRING */ int guess_type(gchar *keyval, gchar* keytype){ char *eptr, *val; int dtype = TSTRING; val = strdup(keyval); if(strchr(val, '.')){ errno = 0; strtod(val, &eptr); if(eptr != val && errno != ERANGE) dtype = TDOUBLE; } if(dtype == TSTRING){ errno = 0; strtoll(val, &eptr, 0); if(eptr != val && errno != ERANGE) dtype = TLONGLONG; } if(dtype == TSTRING && cmplx_conv(val, NULL, NULL)) dtype = TDBLCOMPLEX; if(keytype) switch(dtype){ case TDOUBLE: sprintf(keytype, "TDOUBLE"); break; case TLONGLONG: sprintf(keytype, "TLONGLONG"); break; case TDBLCOMPLEX: sprintf(keytype, "TDBLCOMPLEX"); break; default: sprintf(keytype, "TSTRING"); } //~ DBG("dtype: %d, keytype: %s", dtype, (keytype) ? keytype : ""); free(val); return dtype; } /* * Save image-structure to a FITS file * (together whith keys) */ gboolean writefits(char *filename, IMAGE *image){ FNAME(); long naxes[2] = {image->width, image->height}; int w = image->width, h = image->height; ssize_t sz = w * h; gchar *keytype, *keyname, *keyval, *keycomment; int keyfitstype; GtkTreeIter iter; fitsfile *fp; gchar *card; #ifdef EBUG int n = 0; #endif TRYFITS(fits_create_file, &fp, filename); TRYFITS(fits_create_img, fp, image->dtype, 2, naxes); if(image->store){ GtkTreePath *path = gtk_tree_path_new_first(); GtkTreeModel *tree_model = GTK_TREE_MODEL(image->store); if(gtk_tree_model_get_iter(tree_model, &iter, path)){ // there's keys DBG("filename: %s", filename); do{ gtk_tree_model_get(tree_model, &iter, L_TYPENM, &keytype, L_KEY, &keyname, L_VAL, &keyval, L_COMM, &keycomment, L_TYPE, &keyfitstype, -1); if(keyfitstype == TSTRING) // make sure, that string is in quotes if(*keyval != '\''){ gchar *str = g_strdup_printf("'%s'", keyval); g_free(keyval); keyval = str; } card = g_strdup_printf("%-8s= %s / %s", keyname, keyval, keycomment); g_free(keytype); g_free(keyname); g_free(keyval); g_free(keycomment); DBG("key#%d: %s", ++n, card); FITSFUN(fits_write_record, fp, card); g_free(card); }while(gtk_tree_model_iter_next(tree_model, &iter)); } gtk_tree_path_free(path); } #ifdef EBUG GLfloat min, wd; min = image->stat.min; wd = image->stat.max - min; DBG("min = %f, wd = %f", min, wd); #endif /* int i,j; GLfloat *newdata = malloc(sz*sizeof(GLfloat)); GLfloat *ptro = newdata, *ptri = image->data; for(i=0; idata); TRYFITS(fits_close_file, fp); return TRUE; } gboolean try_open_file(gchar *filename, IMAGE *ima){ if(!readfits(filename, ima)){ g_err(_("Can't read fits file")); ima->data = NULL; return FALSE; } return TRUE; } /* char *del_spaces(char *str){ char *beg, *end; beg = str; end = str + strlen(str); while(*beg == ' ' && beg < end) beg++; if(beg == end) return beg; end--; if(beg == end) return beg; while(*end == ' ' && end > beg) *end-- = 0; return beg; } gboolean strip_card(char *card, char *keyname, char *keyval, char *keycomment){ char *ptr, *ptr1, *end; char *c = strdup(card); end = c + strlen(c); ptr = strchr(c, '='); if(!ptr) return FALSE; *ptr = 0; ptr++; ptr1 = del_spaces(c); strncpy(keyname, ptr1, FLEN_KEYWORD-1); ptr1 = strchr(ptr, '\''); if(ptr1){ ptr1++; ptr = strchr(ptr1, '\''); if(!ptr){ ptr = strchr(ptr1, '/'); if(!ptr){ free(c); return FALSE; } *ptr = 0; ptr++; }else{ *ptr = 0; ptr = strchr(ptr+1, '/'); if(!ptr){ free(c); return FALSE; } *ptr = 0; ptr++; } }else{ ptr1 = ptr; ptr = strchr(ptr1, '/'); if(!ptr){ free(c); return FALSE; } *ptr = 0; ptr++; ptr1 = del_spaces(ptr1); } if(ptr >= end) return FALSE; ptr1 = del_spaces(ptr1); strncpy(keyval, ptr1, FLEN_VALUE); ptr1 = del_spaces(ptr); strncpy(keycomment, ptr1, FLEN_COMMENT); free(c); return TRUE; }*/ /* * Read FITS file filename to a structure image */ gboolean readfits(gchar *filename, IMAGE *image){ FNAME(); gboolean ret = TRUE; fitsfile *fp; GLfloat nullval = 0., imBits, bZero = 0., bScale = 1.; free(image->data); image->data = NULL; int i, j, hdunum, keynum, morekeys, dtype, stat; int naxis, w, h; double val_f = -1e6; // VAL_F value long naxes[4]; ssize_t sz; //char card[FLEN_CARD]; char keyname[FLEN_KEYWORD], keyval[FLEN_VALUE]; char keycomment[FLEN_COMMENT], cdtype[32]; TRYFITS(fits_open_file, &fp, filename, READWRITE); /* TRYFITS(fits_get_hdrspace, fp, &keynum, &morekeys); if(morekeys == -1){ return FALSE; } g_print("Read header of %s, %d keys\n", filename, keynum);*/ FITSFUN(fits_get_num_hdus, fp, &hdunum); //~ g_print(_("\nFile includes %d HDUs\n"), hdunum); if(hdunum < 1){ g_err(_("Can't read HDU")); TRYFITS(fits_close_file, fp); return FALSE; } FITSFUN(fits_get_hdu_type, fp, &dtype); //~ if(dtype) g_print(_("Current HDU type: %d\n"), dtype); init_keylist(image); FITSFUN(fits_get_hdrpos ,fp, &keynum, &morekeys); for (j = 1; j <= keynum; j++){ /*FITSFUN(fits_read_record, fp, j, card); if(!strip_card(card, keyname, keyval, keycomment)){ g_print("Corrupted card: %s!\n", card); continue; }*/ FITSFUN(fits_read_keyn, fp, j, keyname, keyval, keycomment); if(strcmp(keyname, "SIMPLE") == 0 || strcmp(keyname, "EXTEND") == 0) // key "file does conform ..." continue; else if(strcmp(keyname, "COMMENT") == 0) // comment of obligatory key in FITS head continue; else if(strstr(keyname, "NAXIS") == keyname || strcmp(keyname, "BITPIX") == 0) // NAXIS, NAXISxxx, BITPIX continue; else if(strcmp(keyname, "BZERO") == 0){ bZero = atof(keyval); //continue; } else if(strcmp(keyname, "BSCALE") == 0){ bScale = atof(keyval); if(bScale < SCALE_MIN) bScale = 1.; //continue; } else if(strcmp(keyname, "VAL_F") == 0){ val_f = atof(keyval); } dtype = guess_type(keyval, cdtype); //DBG("key#%d; name=%s, dtype=%d (%s), value=%s, comment=%s\n", // j, keyname, dtype, cdtype, keyval, keycomment); add_key(image, cdtype, keyname, keyval, keycomment, dtype); } if(hdunum > 1){ for(i = 2; !(fits_movabs_hdu(fp, i, &dtype, &stat)); i++){ FITSFUN(fits_get_hdrpos ,fp, &keynum, &morekeys); for (j = 1; j <= keynum; j++){ FITSFUN(fits_read_keyn, fp, j, keyname, keyval, keycomment); dtype = guess_type(keyval, cdtype); add_key(image, cdtype, keyname, keyval, keycomment, dtype); } } if(stat != END_OF_FILE){ fits_report_error(stderr, (stat)); ret = FALSE; } } TRYFITS(fits_get_img_param, fp, 4, &dtype, &naxis, naxes); if(dtype > 0) imBits = (GLfloat)(1LL << dtype); // compute the max amplitude else imBits = -1.; // image has floating point type DBG("Image type: %d (%f bits)", dtype, imBits); image->maxVal = imBits; image->dtype = dtype; if(naxis != 2){ g_err(_("Not an image? (dimensions != 2)")); return FALSE;} image->val_f = val_f; image->bZero = bZero; image->bScale = bScale; image->width = w = naxes[0]; image->height = h = naxes[1]; sz = (ssize_t)(w) * (ssize_t)(h); image->data = malloc(sz * sizeof(GLfloat)); TRYFITS(fits_read_img, fp, TFLOAT, 1, sz, &nullval, image->data, &stat); GLfloat *ptr = image->data; GLfloat min, max; min = 1e6; max = 0.; for(i=0; i max) max = tmp; else if(tmp < min) min = tmp; } DBG("min = %f, wd = %f", min, max-min); image->stat.max = max; image->stat.min = min; // histogram isn't initialized yet image->stat.histogram.data = NULL; image->stat.histogram.size = 0; /* ptr = image->data; for(i=0; i