diff --git a/FITSmanip.h b/FITSmanip.h index 7ba41ef..ea5b5e3 100644 --- a/FITSmanip.h +++ b/FITSmanip.h @@ -60,9 +60,10 @@ typedef struct{ }Itmarray; typedef struct klist_{ - char *record; - struct klist_ *next; - struct klist_ *last; + int keyclass; // key class [look int CFITS_API ffgkcl(char *tcard) ] + char *record; // record itself + struct klist_ *next; // next record + struct klist_ *last; // previous record } KeyList; typedef struct{ @@ -96,6 +97,7 @@ typedef struct{ typedef struct{ fitsfile *fp; // cfitsio file structure + char *filename; // filename int Nimages; // amount of images in file FITSimage **images; // image array int Ntables; // amount of tables in file @@ -131,6 +133,7 @@ void keylist_remove_records(KeyList **list, char *sample); KeyList *keylist_copy(KeyList *list); KeyList *keylist_get_end(KeyList *list); void keylist_print(KeyList *list); +KeyList *keylist_read(FITS *fits); void table_free(FITStable **tbl); FITStable *table_new(char *tabname); @@ -146,9 +149,10 @@ FITSimage *image_mksimilar(FITSimage *in, int dtype); FITSimage *image_copy(FITSimage *in); FITSimage *image_build(size_t h, size_t w, int dtype, uint8_t *indata); -void fits_free(FITS **fits); -FITS *fits_read(char *filename); -bool fits_write(char *filename, FITS *fits); +void FITS_free(FITS **fits); +FITS *FITS_read(char *filename); +FITS *FITS_open(char *filename); +bool FITS_write(char *filename, FITS *fits); /************************************************************************************** * fileops.c * diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ee0b966..40eda2c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.9) project(examples) include_directories(../) -link_libraries(usefull_macros) +link_libraries(usefull_macros FITSmanip cfitsio) #add_executable(fitsstat fitsstat.c) add_executable(keylist keylist.c) diff --git a/examples/keylist.c b/examples/keylist.c index b05a070..f7dbe33 100644 --- a/examples/keylist.c +++ b/examples/keylist.c @@ -17,6 +17,7 @@ */ #include "common.h" +#include typedef struct{ char *fitsname; @@ -39,7 +40,6 @@ glob_pars G; /* = { myoption cmdlnopts[] = { // common options {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")}, - {"fitsname",NEED_ARG, NULL, 'i', arg_string, APTR(&G.fitsname), _("name of input file")}, {"list", NO_ARGS, NULL, 'l', arg_none, APTR(&G.list), _("list all keywords")}, {"addrec", MULT_PAR, NULL, 'a', arg_string, APTR(&G.addrec), _("add record to file (you can add more than one record in once, point more -a)")}, end_option @@ -54,13 +54,14 @@ myoption cmdlnopts[] = { */ glob_pars *parse_args(int argc, char **argv){ int i; - char *helpstring = "Usage: %%s [args]\n\n\tWhere args are:\n"; + char *helpstring = "Usage: %%s [args] infile.fits\n\n\tWhere args are:\n"; change_helpstring(helpstring); // parse arguments parseargs(&argc, &argv, cmdlnopts); if(help) showhelp(-1, cmdlnopts); - if(argc > 0){ - for (i = 0; i < argc; i++) + if(argc)(G.fitsname = strdup(argv[0])); + if(argc > 1){ + for (i = 1; i < argc; i++) printf("Ignore extra argument: %s\n", argv[i]); } return &G; @@ -70,8 +71,12 @@ int main(int argc, char *argv[]){ initial_setup(); parse_args(argc, argv); if(!G.fitsname) ERRX(_("No input filename given!")); - printf("Name: %s\n", G.fitsname); - if(G.list) printf("List\n"); + green("Open file %s\n", G.fitsname); + FITS *f = FITS_read(G.fitsname); + if(!f) ERRX(_("Can't open file %s"), G.fitsname); + if(G.list){ + green("List of keywords:\n"); + } if(G.addrec){ char **ptr = G.addrec; while(*ptr){ diff --git a/fileops.c b/fileops.c index fd953e0..7777c97 100644 --- a/fileops.c +++ b/fileops.c @@ -18,6 +18,8 @@ #include "FITSmanip.h" #include "local.h" +#include +#include /** * Return TRUE if file _name_ not exists diff --git a/fits.c b/fits.c index a4b3137..fd06214 100644 --- a/fits.c +++ b/fits.c @@ -40,6 +40,7 @@ * - int fits_get_keyclass(char *card) returns a classification code of keyword record * - int fits_parse_template(char *template, char *card, int *keytype, int *status) * makes record from template + * - add HYSTORY? */ /** @@ -72,6 +73,7 @@ KeyList *keylist_add_record(KeyList **list, char *rec){ WARNX(_("Can't copy data")); return NULL; } + node->keyclass = fits_get_keyclass(rec); if(list){ if(*list){ // there was root node - search last last = keylist_get_end(*list); @@ -196,8 +198,8 @@ void keylist_remove_records(KeyList **keylist, char *sample){ * @param list (io) - address of pointer to first list element */ void keylist_free(KeyList **list){ - KeyList *node = *list, *next; if(!list || !*list) return; + KeyList *node = *list, *next; do{ next = node->next; FREE(node->record); @@ -240,6 +242,43 @@ void keylist_print(KeyList *list){ } } +/** + * @brief keylist_read read all keys from current FITS file + * This function read keys from current HDU, starting from current position + * @param fits - opened structure + * @return keylist read + */ +KeyList *keylist_read(FITS *fits){ + if(!fits || !fits->fp) return NULL; + int fst, nkeys = -1, keypos = -1; + KeyList *list = fits->keylist; + fits_get_hdrpos(fits->fp, &nkeys, &keypos, &fst); + if(nkeys < 1){ + WARNX(_("No keywords in given HDU")); + return NULL; + } + if(fst){ + fits_report_error(stderr, fst); + return NULL; + } + DBG("Find %d keys, keypos=%d", nkeys, keypos); + for(int j = 1; j <= nkeys; ++j){ + char card[FLEN_CARD]; + fits_read_record(fits->fp, j, card, &fst); + if(fst) fits_report_error(stderr, fst); + else{ + KeyList *kl = keylist_add_record(&list, card); + if(!kl){ + /// "Не могу добавить запись в список" + WARNX(_("Can't add record to list")); + }else{ + DBG("add key %d [class: %d]: \"%s\"", j, kl->keyclass, card); + } + } + } + return list; +} + /************************************************************************************** * FITS tables * **************************************************************************************/ @@ -297,7 +336,7 @@ FITStable *table_copy(FITStable *intab){ * @return */ FITStable *table_read(FITS *fits){ - int ncols, i, fst, ret; + int ncols, i, fst = 0, ret; long nrows; char extname[FLEN_VALUE]; fitsfile *fp = fits->fp; @@ -314,7 +353,7 @@ FITStable *table_read(FITS *fits){ int typecode; long repeat, width; ret = fits_get_coltype(fp, i, &typecode, &repeat, &width, &fst); - if(fst){fits_report_error(stderr, fst); ret = fst;} + if(fst){fits_report_error(stderr, fst); ret = fst; fst = 0;} if(ret){ WARNX(_("Can't read column %d!"), i); continue; @@ -328,7 +367,7 @@ FITStable *table_read(FITS *fits){ int j; for(j = 0; j < repeat; ++j){ ret = fits_read_col(fp, typecode, i, j=1, 1, 1, (void*)nullval, array, &anynul, &fst); - if(fst){fits_report_error(stderr, fst); ret = fst;} + if(fst){fits_report_error(stderr, fst); ret = fst; fst = 0;} if(ret){ WARNX(_("Can't read column %d row %d!"), i, j); continue; @@ -577,7 +616,7 @@ bool table_write(FITS *file){ if(N == 0) return FALSE; fitsfile *fp = file->fp; for(i = 0; i < N; ++i){ - int fst; + int fst = 0; FITStable *tbl = file->tables[i]; size_t c, cols = tbl->ncols; char **columns = MALLOC(char*, cols); @@ -593,7 +632,7 @@ bool table_write(FITS *file){ //fits_movabs_hdu(fptr, 2, &hdutype, &status) int ret = fits_create_tbl(fp, BINARY_TBL, tbl->nrows, cols, columns, formats, units, tbl->tabname, &fst); - if(fst){fits_report_error(stderr, fst); ret = fst;} + if(fst){fits_report_error(stderr, fst); ret = fst; fst = 0;} FREE(columns); FREE(formats); FREE(units); if(ret){ WARNX(_("Can't write table %s!"), tbl->tabname); @@ -602,7 +641,7 @@ bool table_write(FITS *file){ //col = tbl->columns; for(c = 0; c < cols; ++c, ++col){ DBG("write column %zd", c); - int fst; + int fst = 0; fits_write_col(fp, col->coltype, c+1, 1, 1, col->repeat, col->contents, &fst); if(fst){ fits_report_error(stderr, fst); @@ -618,8 +657,12 @@ bool table_write(FITS *file){ * FITS files * **************************************************************************************/ -void fits_free(FITS **fits){ +void FITS_free(FITS **fits){ + if(!fits || !*fits) return; FITS *f = *fits; + FREE(f->filename); + int fst; + fits_close_file(f->fp, &fst); keylist_free(&f->keylist); int n; for(n = 0; n < f->Ntables; ++n) @@ -631,26 +674,74 @@ void fits_free(FITS **fits){ /** - TODO: these functions won't work cause on refactoring stage! + TODO: READWRITE allows to modify files on-the-fly, need to use it! + TODO: what's about HCOMPRESS? * read FITS file and fill 'IMAGE' structure (with headers and tables) * can't work with image stack - opens the first image met * works only with binary tables */ -FITS *fits_read(char *filename){ - FNAME(); - fitsfile *fp; - int hdunum = 0, fst, ret; + +/** + * @brief FITS_open - just open FITS file + * @param filename - file to open + * @return pointer to FITS structure or NULL + */ +FITS *FITS_open(char *filename){ FITS *fits = MALLOC(FITS, 1); - fits_open_file(&fp, filename, READONLY, &fst); - if(fst){fits_report_error(stderr, fst); goto returning;} - ret = fits_get_num_hdus(fp, &hdunum, &fst); - if(fst){fits_report_error(stderr, fst);} - if(ret || hdunum < 1){ + int fst; + // use fits_open_diskfile instead of fits_open_file to prevent using of extended name syntax + fits_open_diskfile(&fits->fp, filename, READWRITE, &fst); // READWRITE allows to modify files on-the-fly + if(fst){ + fits_report_error(stderr, fst); + FITS_free(&fits); + return NULL; + } + fits->filename = strdup(filename); + return fits; +} + +/** + * @brief FITS_read - try to open & read all contents of FITS file + * This function won't work with unordinary files. Use it only with simple files with primitive structure. + * @param filename - file to open + * @return pointer to FITS structure or NULL + */ +FITS *FITS_read(char *filename){ + int hdunum = 0, fst = 0; + FITS *fits = FITS_open(filename); + if(!fits) return NULL; + fits_get_num_hdus(fits->fp, &hdunum, &fst); + DBG("Got %d HDUs", hdunum); + if(fst || hdunum < 1){ + if(!fst) FITS_free(&fits); WARNX(_("Can't read HDU")); - fst = 1; goto returning; } + int hdutype; + for(int i = 1; !(fits_movabs_hdu(fits->fp, i, &hdutype, &fst)); ++i){ + DBG("try to read keys"); + keylist_read(fits); + // types: IMAGE_HDU , ASCII_TBL, BINARY_TBL + DBG("HDU[%d] type %d", i, hdutype); + switch(hdutype){ + case IMAGE_HDU: + DBG("Image"); + break; + case BINARY_TBL: + DBG("Binary table"); + break; + case ASCII_TBL: + DBG("ASCII table"); + //table_read(img, fp); + break; + default: + WARNX(_("Unknown HDU type")); + } + } + if(fst == END_OF_FILE){ + fst = 0; + }else goto returning; #if 0 // TODO: open not only images (liststruc.c from cexamples)! // TODO: open not only 2-dimensional files! @@ -669,48 +760,7 @@ FITS *fits_read(char *filename){ img->height = naxes[1]; DBG("got image %ldx%ld pix, bitpix=%d", naxes[0], naxes[1], img->dtype); // loop through all HDUs - KeyList *list = img->keylist; - int imghdu = -1; - for(i = 1; !(fits_movabs_hdu(fp, i, &hdutype, &fst)); ++i){ - int hdutype; - fits_get_hdu_type(fp, &hdutype, &fst); - if(fst){fits_report_error(stderr, fst); continue;} - // types: IMAGE_HDU , ASCII_TBL, BINARY_TBL - DBG("HDU type %d", hdutype); - if(hdutype != IMAGE_HDU){ - //if(hdutype == BINARY_TBL){ - table_read(img, fp); - continue; - } - if(imghdu < 1) imghdu = i; - fits_get_hdrpos(fp, &nkeys, &keypos, &fst); - if(fst){fits_report_error(stderr, fst); continue;} - //DBG("HDU # %d of %d keys", i, nkeys); - for(j = 1; j <= nkeys; ++j){ - /* TODO check like this and mark all special records: - for (ii = 1; ii <= nkeys; ii++) { - fits_read_record(infptr, ii, card, &status); - if (fits_get_keyclass(card) > TYP_CMPRS_KEY) - list_add_rec... - }*/ - ret = fits_read_record(fp, j, card, &fst); - if(fst){fits_report_error(stderr, fst); ret = fst;} - if(!ret){ - if(!keylist_add_record(&list, card)){ - /// "Не могу добавить запись в список" - WARNX(_("Can't add record to list")); - } - DBG("add key %d: \"%s\"", j, card); - } - } - } - img->keylist = list; - if(fst == END_OF_FILE){ - fst = 0; - }else{ - fits_report_error(stderr, fst); - goto returning; - } + if(fits_movabs_hdu(fp, imghdu, &hdutype, &fst)){ WARNX(_("Can't open image HDU #%d"), imghdu); fst = 1; @@ -725,21 +775,21 @@ FITS *fits_read(char *filename){ DBG("ready"); #endif returning: - /*if(fst){ - imfree(&img); - }*/ - ret = fits_close_file(fp, &fst); - if(fst){fits_report_error(stderr, fst);} + if(fst){ + fits_report_error(stderr, fst); + fst = 0; + FITS_free(&fits); + } return fits; } -bool fits_write(char *filename, FITS *fits){ +bool FITS_write(char *filename, FITS *fits){ if(!filename || !fits) return FALSE; - /*int w = fits->width, h = fits->height, fst; + /*int w = fits->width, h = fits->height, fst = 0; long naxes[2] = {w, h}; size_t sz = w * h; fitsfile *fp; - fits_create_file(&fp, filename, &fst); + fits_create_diskfile(&fp, filename, &fst); if(fst){fits_report_error(stderr, fst); return FALSE;} // TODO: save FITS files in original (or given by user) data format! // check fits->dtype - does all data fits it diff --git a/types.h b/types.h deleted file mode 100644 index 7fbecc9..0000000 --- a/types.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * types.h - * - * Copyright 2015 Edward V. Emelianov - * - * 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. - */ -#pragma once -#ifndef __TYPES_H__ -#define __TYPES_H__ -#include "fits.h" - -#ifndef THREAD_NUMBER - #define THREAD_NUMBER 4 // default - 4 threads -#endif - -#ifndef DBL_EPSILON -#define DBL_EPSILON (2.2204460492503131e-16) -#endif -#ifndef DBL_MAX -#define DBL_MAX (1.7976931348623157e+308) -#endif - -// ITM_EPSILON is for data comparing, set it to zero for integer types -#define ITM_EPSILON DBL_EPSILON - -#define OMP_NUM_THREADS THREAD_NUMBER -#define Stringify(x) #x -#define OMP_FOR(x) _Pragma(Stringify(omp parallel for x)) -#ifndef MAX -#define MAX(x,y) ((x) > (y) ? (x) : (y)) -#endif -#ifndef MIN -#define MIN(x,y) ((x) < (y) ? (x) : (y)) -#endif - -// FilterType (not only convolution!) -typedef enum{ - FILTER_NONE = 0 // simple start - ,MEDIAN // median filter - ,ADPT_MEDIAN // simple adaptive median - ,LAPGAUSS // laplasian of gaussian - ,GAUSS // gaussian - ,SOBELH // Sobel horizontal - ,SOBELV // -//- vertical - ,SIMPLEGRAD // simple gradient (by Sobel) - ,PREWITTH // Prewitt (horizontal) - simple derivative - ,PREWITTV // -//- (vertical) - ,SCHARRH // Scharr (modified Sobel) - ,SCHARRV - ,STEP // "posterisation" -} FType; - -typedef struct{ - Item *data; - size_t size; -}Itmarray; - -typedef struct _Filter{ - char *name; // filter name - FType FilterType; // filter type - int w; // filter width - int h; // height - double sx; // x half-width - double sy; // y half-width (sx, sy - for Gaussian-type filters) - IMAGE* (*imfunc)(IMAGE *in, struct _Filter *f, Itmarray *i); // image function for given conversion type -} Filter; - -// mathematical operations when there's no '-i' parameter (for >1 FITS-files) -typedef enum{ - MATH_NONE = 0 - ,MATH_SUM // make sum of all files - ,MATH_MEDIAN // calculate median by all files - ,MATH_MEAN // calculate mean for all files - ,MATH_DIFF // difference of first and rest files -} MathOper; - -// pointer to image conversion function -typedef IMAGE* (*imfuncptr)(IMAGE *in, Filter *f, Itmarray *i); - -#endif // __TYPES_H__ -