IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 15179


Ignore:
Timestamp:
Oct 3, 2007, 11:27:21 AM (19 years ago)
Author:
Paul Price
Message:

Merging branch with FITS compression development.

Location:
trunk/psLib/src/fits
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/fits/psFits.c

    r14878 r15179  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.71 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2007-09-18 03:01:17 $
     9 *  @version $Revision: 1.72 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2007-10-03 21:27:21 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    2020
    2121#include "psFits.h"
     22#include "psFitsHeader.h"
    2223#include "string.h"
    2324#include "psError.h"
     
    6566            return false;
    6667        }
    67         fits->fd = NULL;
     68        fits->fd = NULL;
    6869    }
    6970    return true;
     
    7475    if (!fits) return;
    7576    if (fits->fd) {
    76         fitsClose(fits);
     77        fitsClose(fits);
    7778    }
    7879    psFree (fits->extword);
     
    8182bool psFitsClose(psFits* fits)
    8283{
    83     if (fits == NULL) {
    84         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    85                 _("The input psFits object can not NULL."));
    86         return false;
    87     }
     84    PS_ASSERT_FITS_NON_NULL(fits, false);
    8885
    8986    bool status = fitsClose(fits);
     
    9592psFits* psFitsOpen(const char* name, const char* mode)
    9693{
     94    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
     95
    9796    int status = 0;
    9897    fitsfile *fptr = NULL;      /* Pointer to the FITS file */
    99 
    100     if (name == NULL) {
    101         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    102                 _("Specified filename can not be NULL."));
    103         return NULL;
    104     }
    10598
    10699    /* check the mode to determine how to open/create file */
     
    131124        if (access(name, F_OK) == 0) {
    132125            // file exists, delete old one first
    133             remove
    134                 (name);
     126            remove(name);
    135127        }
    136128
     
    140132        (void)fits_create_file
    141133        #endif
    142         (&fptr,
    143          name,
    144          &status);
     134        (&fptr, name, &status);
    145135        if (fptr == NULL || status != 0) {
    146             char fitsErr[MAX_STRING_LENGTH]
    147             ;
     136            char fitsErr[MAX_STRING_LENGTH];
    148137            fits_get_errstatus(status, fitsErr);
    149138            psError(PS_ERR_IO, true,
     
    158147        (void)fits_open_file
    159148        #endif
    160         (&fptr,
    161          name,
    162          iomode,
    163          &status);
     149        (&fptr, name, iomode, &status);
    164150        if (fptr == NULL || status != 0) {
    165             char fitsErr[MAX_STRING_LENGTH]
    166             ;
     151            char fitsErr[MAX_STRING_LENGTH];
    167152            fits_get_errstatus(status, fitsErr);
    168153            psError(PS_ERR_IO, true,
     
    177162    fits->writable = (iomode == READWRITE);
    178163    fits->extword = NULL;
     164    fits->conventions.compression = true;
    179165    psMemSetDeallocator(fits,(psFreeFunc)fitsFree);
    180166
     
    182168}
    183169
    184 static void psFitsOptionsFree(psFitsOptions *opt)
    185 {
    186     psFree(opt->tilesize);
    187 }
    188 
    189 psFitsOptions* psFitsOptionsAlloc(
     170psErrorCode p_psFitsError(const char* filename, unsigned int lineno, const char* func, int status,
     171                          bool new, const char *errorMsg, ...)
     172{
     173    if (status == 0) {
     174        return PS_ERR_NONE;
     175    }
     176
     177    va_list ap;                         // Variable arguments
     178    va_start(ap, errorMsg);
     179    psString msg = NULL;                // Message to pass to psError
     180    psStringAppendV(&msg, errorMsg, ap);
     181    va_end(ap);
     182
     183    char cfitsioMsg[MAX_STRING_LENGTH];   // Error message from cfitsio
     184    (void)fits_get_errstatus(status, cfitsioMsg);
     185
     186    psStringAppend(&msg, "[CFITSIO error: %s]", cfitsioMsg);
     187
     188    psErrorCode code = p_psError(filename, lineno, func, PS_ERR_IO, new, msg); // Error code
     189    psFree(msg);
     190    return code;
     191}
     192
     193static void psFitsCompressionFree(psFitsCompression *comp)
     194{
     195    PS_ASSERT_PTR_NON_NULL(comp,);
     196    psFree(comp->tilesize);
     197}
     198
     199psFitsCompression* psFitsCompressionAlloc(
    190200    psFitsCompressionType type,         ///< type of compression
    191201    psVector *tilesize,                 ///< vector defining compression tile size
     
    195205)
    196206{
    197     psFitsOptions *opt = psAlloc(sizeof(psFitsOptions));
    198 
    199     opt->type = type;
    200     opt->tilesize = psVectorCopy(NULL, tilesize, PS_DATA_S64);
    201     opt->noisebits = noisebits;
    202     opt->scale = scale;
    203     opt->smooth = smooth;
    204 
    205     psMemSetDeallocator(opt, (psFreeFunc) psFitsOptionsFree);
    206 
    207     return opt;
     207    psFitsCompression *comp = psAlloc(sizeof(psFitsCompression));
     208    psMemSetDeallocator(comp, (psFreeFunc) psFitsCompressionFree);
     209
     210    comp->type = type;
     211    comp->tilesize = psVectorCopy(NULL, tilesize, PS_DATA_S64);
     212    comp->noisebits = noisebits;
     213    comp->scale = scale;
     214    comp->smooth = smooth;
     215
     216    return comp;
    208217}
    209218
     
    224233}
    225234
    226 // move to the first HDU where extword == extname.  this is equivalent to fits_movnam_hdu() for
    227 // a user-defined word in place of EXTNAME
    228 bool p_psFitsMoveExtName_UserKey(const psFits *fits,
    229                                  const char *extname,
    230                                  const char *extword)
    231 {
    232     PS_ASSERT_PTR_NON_NULL(fits,    false);
    233     PS_ASSERT_PTR_NON_NULL(extname, false);
    234     PS_ASSERT_PTR_NON_NULL(extword, false);
    235 
    236     int hdutype = 0;
    237     char name[MAX_STRING_LENGTH];
    238     char extstring[MAX_STRING_LENGTH];
    239 
    240     sprintf (extstring, "'%s'", extname);
    241 
    242     // NOTE: fits_* return 0 for success
    243     for (int i = 1; true; i++) {
    244         // are we able to read the next HDU?
    245 
    246         int status = 0;
    247         if (fits_movabs_hdu(fits->fd, i, &hdutype, &status)) {
    248             char fitsErr[MAX_STRING_LENGTH];
    249             fits_get_errstatus(status, fitsErr);
    250             psError(PS_ERR_LOCATION_INVALID, true,
    251                     _("Could not find HDU with %s = '%s'. CFITSIO Error: %s"),
    252                     extword, extname, fitsErr);
    253             return false;
    254         }
    255         // is there a keyword called 'extword'? (read as string regardless of type)
    256         status = 0;
    257         if (fits_read_keyword(fits->fd, (char *)extword, name, NULL, &status)) {
    258             continue;
    259         }
    260         // if this was read as a string, we will have leading and trailing single-quotes
    261         // try both for comparison
    262        
    263         // do we have the right hdu (names match)?
    264         if (!strcmp (name, extname) || !strcmp (name, extstring)) {
    265             return true;
    266         }
    267     }
    268     psAbort("we should not reach here");
    269 }
    270 
    271 // XXX I will need to define a low-level function p_psFitsMoveExtName_UserKey () which
    272 // uses fits_movabs_hdu() to replicate the functionality of fits_movnam_hdu using an
    273 // alternate name for EXTNAME
     235// Files compressed with cfitsio's "imcopy" program may have multiple EXTNAME keywords, with the first set to
     236// COMPRESSED_IMAGE.  However, fits_movnam_hdu won't find the second (proper) value of EXTNAME, and so can
     237// fail to find a perfectly legitimate extension, simply because imcopy does something silly.  However, we
     238// really want to be able to read these files (MegaCam data are shipped as imcopy-compressed images).
     239// Therefore, we implement our own version of moving to an extension specified by name.  The pure cfitsio
     240// version is used if "conventions.compression" handling is turned off in the psFits structure.
    274241bool psFitsMoveExtName(const psFits* fits,
    275242                       const char* extname)
    276243{
    277     int status = 0;
    278 
    279     if (fits == NULL) {
    280         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    281                 _("The input psFits object can not NULL."));
    282         return false;
    283     }
    284 
    285     if (extname == NULL) {
    286         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    287                 _("Specified extension name can not be NULL."));
    288         return false;
    289     }
    290 
    291     if (fits->extword != NULL) {
    292         bool result = p_psFitsMoveExtName_UserKey(fits, extname, fits->extword);
    293         return (result);
    294     }
    295 
    296     if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
    297         char fitsErr[MAX_STRING_LENGTH];
    298         fits_get_errstatus(status, fitsErr);
    299         psError(PS_ERR_LOCATION_INVALID, true,
    300                 _("Could not find HDU '%s'. CFITSIO Error: %s"),
    301                 extname, fitsErr);
    302         return false;
    303     }
    304 
    305     return true;
     244    PS_ASSERT_FITS_NON_NULL(fits, false);
     245    PS_ASSERT_STRING_NON_EMPTY(extname, false);
     246
     247    int status = 0;
     248
     249    if (!fits->conventions.compression && !fits->extword) {
     250        // User wants to use cfitsio.  Good luck to them!
     251        if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
     252            psFitsError(status, true, _("Could not find HDU '%s'"), extname);
     253            return false;
     254        }
     255        return true;
     256    }
     257
     258    bool ignoreCI = (fits->conventions.compression &&
     259                     (strcmp(extname, "COMPRESSED_IMAGE") != 0)); // Ignore COMPRESSED_IMAGE extension name?
     260    char *extword = (fits->extword ? fits->extword : "EXTNAME"); // Word to use as extension name
     261
     262#if 0
     263    // XXX Future optimisation: loop through from the current HDU to the end, then from the start to the
     264    // current position.  This will save seeking through the file multiple times.
     265    int currentExt = psFitsGetExtNum(fits); // Current extension number
     266    int numExt = psFitsGetSize(fits);   // Total number of extensions
     267#endif
     268
     269    for (int i = 1; true; i++) {
     270        int hdutype = 0;
     271        if (fits_movabs_hdu(fits->fd, i, &hdutype, &status)) {
     272            // We've run off the end
     273            psFitsError(status, true, _("Could not find HDU with %s = '%s'"), extword, extname);
     274            return false;
     275        }
     276        // Is there a keyword called 'extword'? (read as string regardless of type)
     277        char name[MAX_STRING_LENGTH];  // Name of extension
     278        if (fits_read_keyword(fits->fd, extword, name, NULL, &status)) {
     279            // It doesn't exist in the header.
     280            // This isn't the extension you're looking for.  Move along.
     281            status = 0;
     282            continue;
     283        }
     284        char *fixed = p_psFitsHeaderParseString(name); // Parsed version (removing quotes and spaces)
     285
     286        if (ignoreCI && strcmp(fixed, "COMPRESSED_IMAGE") == 0) {
     287            // Read it again, Sam
     288            if (fits_read_keyword(fits->fd, extword, name, NULL, &status)) {
     289                status = 0;
     290                continue;
     291            }
     292            fixed = p_psFitsHeaderParseString(name);
     293        }
     294
     295        if (strcmp(fixed, extname) == 0) {
     296            // We've arrived
     297            return true;
     298        }
     299    }
     300    psAbort("Should never reach here.");
    306301}
    307302
     
    310305                      bool relative)
    311306{
    312     if (fits == NULL) {
    313         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    314                 _("The input psFits object can not NULL."));
    315         return false;
    316     }
     307    PS_ASSERT_FITS_NON_NULL(fits, false);
    317308
    318309    int status = 0;
     
    346337bool psFitsMoveLast(psFits* fits)
    347338{
    348     if (fits == NULL) {
    349         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    350                 _("The input psFits object can not NULL."));
    351         return false;
    352     }
     339    PS_ASSERT_FITS_NON_NULL(fits, false);
     340
    353341    int size = psFitsGetSize(fits);
    354342    if (size == 0) { // empty file -- no action needed
     
    361349int psFitsGetExtNum(const psFits* fits)
    362350{
     351    PS_ASSERT_FITS_NON_NULL(fits, false);
    363352    int hdunum;
    364 
    365     if (fits == NULL) {
    366         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    367                 _("The input psFits object can not NULL."));
    368         return PS_FITS_TYPE_NONE;
    369     }
    370 
    371 
    372353    return fits_get_hdu_num(fits->fd,&hdunum) - 1;
    373354}
     
    375356psString psFitsGetExtName(const psFits* fits)
    376357{
    377     if (fits == NULL) {
    378         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    379                 _("The input psFits object can not NULL."));
    380         return NULL;
    381     }
     358    PS_ASSERT_FITS_NON_NULL(fits, NULL);
    382359
    383360    int status = 0;
     
    389366        psError(PS_ERR_BAD_PARAMETER_NULL, true,
    390367                _("Header keyword %s is not found"), extword);
    391         return NULL;
     368        return NULL;
    392369    }
    393370    return psStringCopy(name);
     
    396373bool psFitsSetExtName(psFits* fits, const char* name)
    397374{
    398     if (fits == NULL) {
    399         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    400                 _("The input psFits object can not NULL."));
    401         return false;
    402     }
    403 
    404     if (name == NULL) {
    405         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    406                 _("Specified extension name can not be NULL."));
    407         return false;
    408     }
     375    PS_ASSERT_FITS_NON_NULL(fits, false);
     376    PS_ASSERT_STRING_NON_EMPTY(name, false);
    409377
    410378    int status = 0;
     
    428396                        bool relative)
    429397{
    430     if (fits == NULL) {
    431         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    432                 _("The input psFits object can not NULL."));
    433         return false;
    434     }
     398    PS_ASSERT_FITS_NON_NULL(fits, false);
    435399
    436400    if (! fits->writable) {
     
    466430                         const char* extname)
    467431{
    468     if (fits == NULL) {
    469         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    470                 _("The input psFits object can not NULL."));
    471         return false;
    472     }
     432    PS_ASSERT_FITS_NON_NULL(fits, false);
     433    PS_ASSERT_STRING_NON_EMPTY(extname, false);
    473434
    474435    if (! fits->writable) {
     
    504465int psFitsGetSize(const psFits* fits)
    505466{
    506     if (fits == NULL) {
    507         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    508                 _("The input psFits object can not NULL."));
    509         return 0;
    510     }
     467    PS_ASSERT_FITS_NON_NULL(fits, 0);
    511468
    512469    int num = 0;
     
    527484psFitsType psFitsGetExtType(const psFits* fits)
    528485{
    529     if (fits == NULL) {
    530         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    531                 _("The input psFits object can not NULL."));
    532         return PS_FITS_TYPE_NONE;
    533     }
     486    PS_ASSERT_FITS_NON_NULL(fits, PS_FITS_TYPE_NONE);
    534487
    535488    int status = 0;
     
    556509bool psFitsTruncate(psFits* fits)
    557510{
    558     if (fits == NULL) {
    559         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    560                 _("The input psFits object can not NULL."));
    561         return PS_FITS_TYPE_NONE;
    562     }
     511    PS_ASSERT_FITS_NON_NULL(fits, NULL);
    563512
    564513    if (! fits->writable) {
     
    597546)
    598547{
     548    PS_ASSERT_FITS_NON_NULL(fits, false);
     549
    599550    // convert psFitsCompressionType to cfitsio compression types
    600551    int comptype;
     
    640591        psAbort("can't map (long) type to a psLib type");
    641592    }
     593    psFree(dim);
    642594    // status check belongs to fits_set_tile_dim() call
    643595    if (status) {
     
    681633}
    682634
    683 
    684 bool psFitsSetOptions(
     635psFitsCompression *psFitsCompressionGet(psFits* fits)
     636{
     637    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     638
     639    int status = 0;                     // cfitsio status
     640
     641    psFitsCompressionType type = psFitsCompressionGetType(fits);
     642    if (type < 0) {
     643        psError(PS_ERR_UNKNOWN, false, "Unable to get compression type.");
     644        return NULL;
     645    }
     646
     647    psElemType tileType;                // Type corresponding to "long"
     648    if (sizeof(long) == sizeof(psS64)) {
     649        tileType = PS_TYPE_S64;
     650    } else if (sizeof(long) == sizeof(psS32)) {
     651        tileType = PS_TYPE_S32;
     652    } else {
     653        psAbort("can't map (long) type to a psLib type");
     654    }
     655
     656    psVector *tiles = psVectorAlloc(3, tileType); // Tile sizes
     657    if (fits_get_tile_dim(fits->fd, 3, (long*)tiles->data.U8, &status)) {
     658        psFitsError(status, true, "Unable to get compression tile sizes.");
     659        psFree(tiles);
     660        return NULL;
     661    }
     662
     663    int noisebits;                      // Noise bits for compression
     664    if (fits_get_noise_bits(fits->fd, &noisebits, &status)) {
     665        psFitsError(status, true, "Unable to get compression noise bits.");
     666        psFree(tiles);
     667        return NULL;
     668    }
     669
     670    int hscale = 0, hsmooth = 0;        // Scaling and smoothing for HCOMPRESS
     671
     672#if FITS_HCOMP
     673    if (fits_get_hcomp_scale(fits->fd, &hscale, &status)) {
     674        psFitsError(status, true, "Unable to get HCOMPRESS scaling.");
     675        psFree(tiles);
     676        return NULL;
     677    }
     678    if (fits_get_hcomp_smooth(fits->fd, &hsmooth, &status)) {
     679        psFitsError(status, true, "Unable to get HCOMPRESS smoothing.");
     680        psFree(tiles);
     681        return NULL;
     682    }
     683#endif // FITS_HCOMP
     684
     685    psFitsCompression *compress = psFitsCompressionAlloc(type, tiles, noisebits, hscale, hsmooth);
     686    psFree(tiles);                      // Drop reference
     687
     688    return compress;
     689}
     690
     691psFitsCompressionType psFitsCompressionGetType(psFits* fits)
     692{
     693    PS_ASSERT_FITS_NON_NULL(fits, -1);
     694
     695    int status = 0;                     // cfitsio status
     696    int comptype = 0;                   // cfitsio compression type
     697    if (fits_get_compression_type(fits->fd, &comptype, &status)) {
     698        psFitsError(status, true, "Unable to get compression type.");
     699        return -1;
     700    }
     701
     702    psFitsCompressionType type;
     703    switch (comptype) {
     704      case 0:
     705        type = PS_FITS_COMPRESS_NONE;
     706        break;
     707      case GZIP_1:
     708        type = PS_FITS_COMPRESS_GZIP;
     709        break;
     710      case RICE_1:
     711        type = PS_FITS_COMPRESS_RICE;
     712        break;
     713      case HCOMPRESS_1:
     714        type = PS_FITS_COMPRESS_HCOMPRESS;
     715        break;
     716      case PLIO_1:
     717        type = PS_FITS_COMPRESS_PLIO;
     718        break;
     719      default:
     720        psError(PS_ERR_UNKNOWN, true, "cfitsio reports unknown compression type.");
     721        return -1;
     722    }
     723
     724    return type;
     725}
     726
     727
     728bool psFitsCompressionApply(
    685729    psFits* fits,                       ///< psFits object to close
    686     psFitsOptions *opt                  ///< options object
     730    psFitsCompression *comp             ///< options object
    687731)
    688732{
    689     return psFitsSetCompression(
    690             fits,
    691             opt->type,
    692             opt->tilesize,
    693             opt->noisebits,
    694             opt->scale,
    695             opt->smooth);
     733    return psFitsSetCompression(fits, comp->type, comp->tilesize, comp->noisebits, comp->scale, comp->smooth);
    696734}
    697735
     
    826864
    827865
     866psFitsCompressionType psFitsCompressionTypeFromString(const char *string)
     867{
     868    if (!string || strlen(string) == 0) {
     869        psWarning("Unable to identify compression type --- none set.");
     870        return PS_FITS_COMPRESS_NONE;
     871    }
     872
     873    if (strcmp(string, "GZIP") == 0) return PS_FITS_COMPRESS_GZIP;
     874    if (strcmp(string, "RICE") == 0) return PS_FITS_COMPRESS_RICE;
     875    if (strcmp(string, "HCOMPRESS") == 0) return PS_FITS_COMPRESS_HCOMPRESS;
     876    if (strcmp(string, "PLIO") == 0) return PS_FITS_COMPRESS_PLIO;
     877
     878    psWarning("Unable to identify compression type (%s) --- none set.", string);
     879    return PS_FITS_COMPRESS_NONE;
     880}
  • trunk/psLib/src/fits/psFits.h

    r14877 r15179  
    44 * @author Robert DeSonia, MHPCC
    55 *
    6  * @version $Revision: 1.31 $ $Name: not supported by cvs2svn $
    7  * @date $Date: 2007-09-18 02:56:36 $
     6 * @version $Revision: 1.32 $ $Name: not supported by cvs2svn $
     7 * @date $Date: 2007-10-03 21:27:21 $
    88 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
    99 */
     
    2121#include "psMetadata.h"
    2222#include "psImage.h"
     23
     24#include "psErrorCodes.h"
    2325
    2426/** FITS HDU type.
     
    4951 *
    5052 */
    51 typedef struct
    52 {
    53     fitsfile* fd;                       ///< the CFITSIO fits files handle.
    54     bool writable;                      ///< Is the file writable?
    55     char *extword;                      ///< user-specified word to name extensions (NULL implies EXTNAME)
    56 }
    57 psFits;
    58 
    59 /** FITS options object. */
    60 typedef struct
    61 {
     53typedef struct {
     54    fitsfile* fd;                       ///< the CFITSIO fits files handle.
     55    bool writable;                      ///< Is the file writable?
     56    char *extword;                      ///< user-specified word to name extensions (NULL implies EXTNAME)
     57    struct {
     58        bool compression;               ///< Honour compression convention, handling compressed images
     59    } conventions;                      ///< Conventions to honour
     60} psFits;
     61
     62/** FITS compression settings. */
     63typedef struct {
    6264    psFitsCompressionType type;         ///< type of compression
    6365    psVector *tilesize;                 ///< vector defining compression tile size
     
    6567    int scale;                          ///< hcompress scale
    6668    int smooth;                         ///< hcompress smothing
    67 }
    68 psFitsOptions;
     69} psFitsCompression;
    6970
    7071/** Opens a FITS file and allocates the associated psFits object.
     
    8485);
    8586
    86 /** Creates a new FITS options struct
     87
     88/// Generate an error including the cfitsio error string
     89#ifdef DOXYGEN
     90psErrorCode psFitsError(
     91    int status,                         ///< cfitsio status value
     92    bool new,                           ///< new error?
     93    const char *errorMsg,               ///< printf-style format of header line
     94    ...                                 ///< any parameters required in format
     95    );
     96#else // ifdef DOXYGEN
     97psErrorCode p_psFitsError(
     98    const char* filename,               ///< file name
     99    unsigned int lineno,                ///< line number in file
     100    const char* func,                   ///< function name
     101    int status,                         ///< cfitsio status value
     102    bool new,                           ///< new error?
     103    const char *errorMsg,               ///< printf-style format of header line
     104    ...                                 ///< any parameters required in format
     105    ) PS_ATTR_FORMAT(printf, 6, 7);
     106#ifndef SWIG
     107#define psFitsError(status,new,...) \
     108      p_psFitsError(__FILE__,__LINE__,__func__,status,new,__VA_ARGS__)
     109#endif // ifndef SWIG
     110#endif // ifdef DOXYGEN
     111
     112
     113/** Creates a new FITS options struct
    87114 *
    88115 *  @return psFitsOptions or NULL on failure
    89116 */
    90 psFitsOptions* psFitsOptionsAlloc(
     117psFitsCompression* psFitsCompressionAlloc(
    91118    psFitsCompressionType type,         ///< type of compression
    92119    psVector *tilesize,                 ///< vector defining compression tile size
     
    96123);
    97124
     125/// Return the FITS compression type specified by a string
     126psFitsCompressionType psFitsCompressionTypeFromString(
     127    const char *string                  ///< String with compression type
     128    );
     129
    98130/** Closes a FITS file.
    99131 *
     
    111143 */
    112144bool psFitsSetCompression(
    113     psFits* fits,                       ///< psFits object to close
     145    psFits* fits,                       ///< psFits object for which to set compression
    114146    psFitsCompressionType type,         ///< type of compression
    115147    psVector *tilesize,                 ///< vector defining compression tile size
     
    119151);
    120152
     153/// Get the compression options for a file handle
     154psFitsCompression *psFitsCompressionGet(
     155    psFits* fits                        ///< psFits object for which to get compression
     156);
     157
     158/// Get the compression type for a file handle
     159psFitsCompressionType psFitsCompressionGetType(
     160    psFits* fits                        ///< psFits object for which to get compression type
     161    );
     162
    121163/** Sets FITS write options
    122164 *
    123165 *  @return bool      TRUE if successfully configured, otherwise FALSE
    124166 */
    125 bool psFitsSetOptions(
    126     psFits* fits,                       ///< psFits object to close
    127     psFitsOptions *opt                  ///< options object
     167bool psFitsCompressionApply(
     168    psFits* fits,                       ///< psFits object for which to set compression
     169    psFitsCompression *compress         ///< options object
    128170);
    129171
     
    146188// a user-defined word in place of EXTNAME
    147189bool p_psFitsMoveExtName_UserKey(const psFits *fits,
    148                                 const char *extname,
    149                                 const char *extword);
     190                                const char *extname,
     191                                const char *extword);
    150192
    151193/** Moves the FITS HDU to the specified extension name.
     
    261303                          );
    262304
     305#define PS_ASSERT_FITS_NON_NULL(NAME, RVAL) \
     306if (!(NAME) || !(NAME)->fd) { \
     307    psError(PS_ERR_UNEXPECTED_NULL, true, "Error: FITS file pointer %s is NULL", #NAME); \
     308    return RVAL; \
     309}
     310
    263311/// @}
    264312#endif // #ifndef PS_FITS_H
  • trunk/psLib/src/fits/psFitsHeader.c

    r14460 r15179  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.34 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2007-08-10 02:23:42 $
     9 *  @version $Revision: 1.35 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2007-10-03 21:27:21 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    1919#include <unistd.h>
    2020
     21#include "psAssert.h"
    2122#include "psFits.h"
    2223#include "string.h"
     
    3233
    3334#define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
     35#define NUM_EMPTY_KEYS 8                // Number of keywords before header is considered practically empty
    3436
    3537// list of FITS header keys to ignore; NULL-terminated
    36 static char* ignoreFitsKeys[] = {"", NULL};
     38static const char* ignoreFitsKeys[] = { "", NULL};
    3739
    3840// List of FITS header keys that may be duplicated; NULL-terminated
    39 static char *duplicateFitsKeys[] = {"COMMENT", "HIERARCH", "HISTORY", NULL};
     41static const char *duplicateFitsKeys[] = { "COMMENT", "HIERARCH", "HISTORY", NULL};
    4042
    4143// List of FITS header keys not to write (handled by cfitsio); NULL-terminated
    42 static char *noWriteFitsKeys[] = {"SIMPLE", "XTENSION", "BITPIX", "NAXIS", "EXTNAME", "BSCALE", "BZERO",
    43                                   "TFIELDS", NULL};
     44static const char *noWriteFitsKeys[] = { "SIMPLE", "XTENSION", "BITPIX", "NAXIS", "EXTNAME", "BSCALE",
     45                                         "BZERO", "TFIELDS", "PCOUNT", "GCOUNT", "ZIMAGE", "ZBITPIX",
     46                                         "ZCMPTYPE", NULL};
     47
    4448// List of the start of FITS header keys not to write (handled by cfitsio); NULL-terminated
    45 static char *noWriteFitsKeyStarts[] = {"NAXIS", "TTYPE", "TFORM", NULL};
    46 
    47 // List of FITS header keys to be written with fits_write_comment
    48 
    49 psMetadata* psFitsReadHeader(psMetadata* out,
    50                              const psFits* fits)
    51 {
    52     if (fits == NULL) {
    53         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    54                 _("The input psFits object can not NULL."));
    55         return NULL;
    56     }
    57 
    58     if (out == NULL) {
    59         out = psMetadataAlloc();
    60     }
     49static const char *noWriteFitsKeyStarts[] = { "NAXIS", "TTYPE", "TFORM", "ZNAXIS", "ZTILE", "ZNAME", "ZVAL",
     50                                              NULL};
     51
     52// List of FITS header keys that may be present if the header is considered "empty"; NULL-terminated
     53static const char *emptyKeys[] = { "SIMPLE", "BITPIX", "NAXIS", "EXTEND", "COMMENT", "CHECKSUM", "DATASUM",
     54                                   NULL };
     55
     56// Compare a keyword with a list of keywords; return true if it's in the list
     57static bool keywordInList(const char *keyword, // Keyword to check
     58                          const char **list // List of keywords
     59    )
     60{
     61    for (const char **check = list; *check; ++check) {
     62        if (strcmp(keyword, *check) == 0) {
     63            return true;
     64        }
     65    }
     66    return false;
     67}
     68
     69
     70bool psFitsCheckSingleCompressedImagePHU(const psFits *fits, psMetadata *header)
     71{
     72    PS_ASSERT_FITS_NON_NULL(fits, false);
     73
     74    if (!fits->conventions.compression) {
     75        // User has turned off compression conventions; doesn't want any nasty surprises
     76        return false;
     77    }
     78
     79    if (psFitsGetExtNum(fits) != 0) {
     80        // It's not the PHU, so it can't be the PHU for a single compressed image!
     81        return false;
     82    }
     83
     84    if (psFitsGetSize(fits) != 2) {
     85        // No second extension, or multiple extensions
     86        return false;
     87    }
     88
     89    int numKeys;                        // Number of keywords in the header
     90    int status = 0;                     // CFITSIO status
     91    fits_get_hdrspace(fits->fd, &numKeys, 0, &status);
     92    if (numKeys > NUM_EMPTY_KEYS) {
     93        return false;
     94    }
     95
     96    int bitpix, naxis;                  // Bits per pixel and number of axes
     97    long naxes[MAX_COMPRESS_DIM];       // Dimensions
     98    fits_get_img_param(fits->fd, MAX_COMPRESS_DIM, &bitpix, &naxis, naxes, &status);
     99    if (naxis != 0) {
     100        return false;
     101    }
     102
     103    if (!header) {
     104        for (int i = 1; i <= numKeys; i++) {
     105            // Just want to read the keyword names, without parsing the values and stuffing into a metadata
     106            char keyName[MAX_STRING_LENGTH];// Keyword name
     107            char keyValue[MAX_STRING_LENGTH]; // Corresponding value
     108            char keyComment[MAX_STRING_LENGTH]; // Corresponding comment
     109            fits_read_keyn(fits->fd, i, keyName, keyValue, keyComment, &status);
     110            if (!keywordInList(keyName, emptyKeys)) {
     111                return false;
     112            }
     113        }
     114    } else {
     115        psMetadataIterator *iter = psMetadataIteratorAlloc(header, PS_LIST_HEAD, NULL); // Iterator
     116        psMetadataItem *item;           // Item from iteration
     117        while ((item = psMetadataGetAndIncrement(iter))) {
     118            if (!keywordInList(item->name, emptyKeys)) {
     119                psFree(iter);
     120                return false;
     121            }
     122        }
     123        psFree(iter);
     124    }
     125
     126    if (!psFitsMoveExtNum(fits, 1, false)) {
     127        psWarning("Unable to examine first extension as suspect compressed image.");
     128        return false;
     129    }
     130
     131    if (fits_is_compressed_image(fits->fd, &status)) {
     132        return true;
     133    }
     134
     135    // It's not a single compressed image PHU --- move back to the PHU for the user
     136    if (!psFitsMoveExtNum(fits, 0, false)) {
     137        psWarning("Unable to examine first extension as suspect compressed image.");
     138        return false;
     139    }
     140
     141    return false;
     142}
     143
     144char *p_psFitsHeaderParseString(char *string)
     145{
     146    if (!string || strlen(string) == 0) {
     147        return string;
     148    }
     149
     150    char *fixed = string;       // Fixed version of the string
     151    // remove the single-quotes at front/end
     152    if (fixed[0] == '\'' && fixed[strlen(string)-1] == '\'') {
     153        string[strlen(string)-1] = '\0'; // Remove the trailing quote
     154        fixed += 1; // Advance past the leading quote
     155    }
     156    // Remove trailing spaces, which are not significant, according to the FITS standard
     157    // http://archive.stsci.edu/fits/fits_standard/node31.html
     158    char *lastSpace = NULL; // The last space in the string
     159    while (strlen(fixed) > 1 && (lastSpace = strrchr(fixed, ' ')) && lastSpace[1] == '\0') {
     160        // This is a trailing space, not a leading space.
     161        lastSpace[0] = '\0'; // Truncate the string here
     162    }
     163
     164    return fixed;
     165}
     166
     167// Read the header
     168static psMetadata *readHeader(const psFits *fits // FITS file from which to read header
     169                              )
     170{
     171    assert(fits);
     172
     173    psMetadata *header = psMetadataAlloc(); // Header, to return
    61174
    62175    // Get number of key names
     
    74187
    75188        // Check to see if the keyword should be ignored
    76         bool ignoreKey = false;         // Ignore this keyword?
    77         for (int i = 0; ignoreFitsKeys[i] && !ignoreKey; i++) {
    78             if (strcmp(keyName, ignoreFitsKeys[i]) == 0) {
    79                 ignoreKey = true;
    80             }
    81         }
    82         if (ignoreKey) {
     189        if (keywordInList(keyName, ignoreFitsKeys)) {
    83190            // We're done here; skip to the next key
    84191            continue;
    85192        }
    86193
    87 #if 0
    88         // This doesn't seem to be necessary
    89         if (strncmp(keyName, "HIERARCH ", 9) == 0) {
    90             char temp[MAX_STRING_LENGTH];
    91             strcpy(temp, &keyName[9]);
    92             strcpy(keyName, temp);
    93         }
    94 #endif
    95 
    96194        // Check to see if the keyword should be duplicated
    97195        int dupFlag = 0;                // Duplicate flag
    98         for (int i = 0; duplicateFitsKeys[i] && !dupFlag; i++) {
    99             if (strcmp(keyName, duplicateFitsKeys[i]) == 0) {
    100                 dupFlag = PS_META_DUPLICATE_OK;
    101             }
     196        if (keywordInList(keyName, duplicateFitsKeys)) {
     197            dupFlag = PS_META_DUPLICATE_OK;
    102198        }
    103199
     
    116212        case 'X': // bit
    117213        case 'B': // byte
    118             success = psMetadataAddS8(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
     214            success = psMetadataAddS8(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
    119215            break;
    120216        case 'I': // short int.
     
    122218            // Trap NAN, INF and -INF, which cfitsio doesn't handle.
    123219            if (strncasecmp(keyValue, "NAN", 3) == 0) {
    124                 success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
     220                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
    125221            } else if (strncasecmp(keyValue, "INF", 3) == 0) {
    126                 success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
     222                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
    127223            } else if (strncasecmp(keyValue, "-INF", 4) == 0) {
    128                 success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
     224                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
    129225            } else {
    130                 success = psMetadataAddS32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
     226                success = psMetadataAddS32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment,
     227                                           atoi(keyValue));
    131228            }
    132229            break;
    133230        case 'J': // int.
    134             success = psMetadataAddS32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
     231            success = psMetadataAddS32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
    135232            break;
    136233        case 'U': // unsigned int.
    137             success = psMetadataAddU32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atol(keyValue));
     234            success = psMetadataAddU32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atol(keyValue));
    138235            break;
    139236
    140237        case 'K': // long int. can't all fit in a psS32, put in psF64
    141238        case 'F':
    142             success = psMetadataAddF64(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atof(keyValue));
     239            success = psMetadataAddF64(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atof(keyValue));
    143240            break;
    144241        case 'C': {
    145                 char *keyValueFixed = keyValue; // Fixed version of the string
    146                 // remove the single-quotes at front/end
    147                 if (keyValueFixed[0] == '\'' && keyValueFixed[strlen(keyValue)-1] == '\'') {
    148                     keyValue[strlen(keyValue)-1] = '\0'; // Remove the trailing quote
    149                     keyValueFixed += 1; // Advance past the leading quote
    150                 }
    151                 // Remove trailing spaces, which are not significant, according to the FITS standard
    152                 // http://archive.stsci.edu/fits/fits_standard/node31.html
    153                 char *lastSpace = NULL; // The last space in the string
    154                 while (strlen(keyValueFixed) > 1 && (lastSpace = strrchr(keyValueFixed, ' ')) &&
    155                         lastSpace[1] == '\0') {
    156                     // This is a trailing space, not a leading space.
    157                     lastSpace[0] = '\0'; // Truncate the string here
    158                 }
    159 
    160                 // Need to trap NAN, INF and -INF written by psFitsWriteHeader.
    161                 // cfitsio won't write these, so we write them as strings, and then have to trap them on read.
    162                 if (strcasecmp(keyValueFixed, "NAN") == 0) {
    163                     success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
    164                 } else if (strcasecmp(keyValueFixed, "INF") == 0) {
    165                     success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
    166                 } else if (strcasecmp(keyValueFixed, "-INF") == 0) {
    167                     success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
    168                 } else {
    169                     success = psMetadataAddStr(out, PS_LIST_TAIL, keyName, dupFlag, keyComment,
    170                                                keyValueFixed);
    171                 }
    172                 break;
     242            char *keyValueFixed = p_psFitsHeaderParseString(keyValue); // Fixed version of the string
     243
     244            // Need to trap NAN, INF and -INF written by psFitsWriteHeader.
     245            // cfitsio won't write these, so we write them as strings, and then have to trap them on read.
     246            if (strcasecmp(keyValueFixed, "NAN") == 0) {
     247                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
     248            } else if (strcasecmp(keyValueFixed, "INF") == 0) {
     249                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
     250            } else if (strcasecmp(keyValueFixed, "-INF") == 0) {
     251                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
     252            } else if (!fits->conventions.compression ||
     253                       (strcmp(keyName, "EXTNAME") != 0 || strcmp(keyValueFixed, "COMPRESSED_IMAGE") != 0)) {
     254                // Ignore EXTNAME=COMPRESSED_IMAGE if compression convention is to be respected
     255                success = psMetadataAddStr(header, PS_LIST_TAIL, keyName, dupFlag, keyComment,
     256                                           keyValueFixed);
    173257            }
     258            break;
     259        }
    174260        case 'L': {
    175                 bool temp = (keyValue[0] == 'T') ? 1 : 0;
    176                 success = psMetadataAddBool(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, temp);
    177                 break;
    178             }
     261            bool temp = (keyValue[0] == 'T') ? 1 : 0;
     262            success = psMetadataAddBool(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, temp);
     263            break;
     264        }
    179265        default:
    180266            psError(PS_ERR_IO, true, _("Specified FITS metadata type, %c, is not supported."), keyType);
    181             return out;
     267            psFree(header);
     268            return NULL;
    182269        }
    183270
    184271        if (!success) {
    185272            psError(PS_ERR_UNKNOWN, false, _("Failed to add metadata item, %s."), keyName);
    186             return out;
     273            psFree(header);
     274            return NULL;
    187275        }
    188276
     
    193281        (void)fits_get_errstatus(status, fitsErr);
    194282        psError(PS_ERR_IO, true, _("Failed to add metadata item, %s."), fitsErr);
    195         return false;
    196     }
    197 
     283        psFree(header);
     284        return false;
     285    }
     286
     287    return header;
     288}
     289
     290
     291psMetadata* psFitsReadHeader(psMetadata* out,
     292                             const psFits* fits)
     293{
     294    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     295
     296    psMetadata *header = readHeader(fits); // Header
     297    if (!header) {
     298        return NULL;
     299    }
     300
     301    // Explore the potential case that this is an empty PHU, and the first extension contains the sole image,
     302    // which is compressed.
     303    if (psFitsCheckSingleCompressedImagePHU(fits, header)) {
     304        // This is really what we want, not the empty PHU
     305        psTrace("psLib.fits", 1,
     306                "This PHU should really be a compressed image --- getting that header instead.");
     307        psFree(header);
     308        header = readHeader(fits);
     309        if (!header) {
     310            return NULL;
     311        }
     312    }
     313
     314    if (!out) {
     315        return header;
     316    }
     317
     318    // Need to move header onto the nominated metadata
     319    psMetadataIterator *iter = psMetadataIteratorAlloc(header, PS_LIST_HEAD, NULL); // Iterator
     320    psMetadataItem *item;           // Item from iteration
     321    while ((item = psMetadataGetAndIncrement(iter))) {
     322        // Need to look for MULTI, which won't be picked up using the iterator.
     323        psMetadataItem *multiCheckItem = psMetadataLookup(header, item->name);
     324        assert(multiCheckItem);
     325        unsigned int flag = 0;      // Flag to indicate MULTI; otherwise default action
     326        if (multiCheckItem->type == PS_DATA_METADATA_MULTI) {
     327            flag = PS_META_DUPLICATE_OK;
     328        }
     329        if (!psMetadataAddItem(out, item, PS_LIST_TAIL, flag)) {
     330            psError(PS_ERR_UNKNOWN, false, "Unable to add header item %s to extant metadata.",
     331                    item->name);
     332            psFree(iter);
     333            psFree(header);
     334            return NULL;
     335        }
     336    }
     337    psFree(iter);
     338    psFree(header);
    198339    return out;
    199340}
     
    201342psMetadata* psFitsReadHeaderSet(psMetadata* out, const psFits* fits)
    202343{
    203     if (fits == NULL) {
    204         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    205         psFree(out);
    206         return NULL;
    207     }
    208 
    209     if (out == NULL) {
     344    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     345
     346    if (!out) {
    210347        out = psMetadataAlloc();
    211348    }
     
    279416            // image, the NAXISn haven't been changed; or after converting to F32, the BITPIX hasn't been
    280417            // changed) so we'll take care of that for them.
    281             bool writeKey = true;           // Should we write this keyword?
    282             for (int i = 0; noWriteFitsKeys[i] && writeKey; i++) {
    283                 if (strcmp(item->name, noWriteFitsKeys[i]) == 0) {
    284                     writeKey = false;
    285                 }
    286             }
    287             if (!writeKey) {
     418            if (keywordInList(item->name, noWriteFitsKeys)) {
    288419                // Don't write it; skip to the next key
    289420                continue;
     
    294425                // that go in are correct.  However, when we're writing a "blank" HDU (header only), we want
    295426                // to preserve NAXISn etc for reference, so we don't do this.
     427                bool writeKey = true;   // Write this keyword?
    296428                for (int i = 0; noWriteFitsKeyStarts[i] && writeKey; i++) {
    297429                    if (strncmp(item->name, noWriteFitsKeyStarts[i], strlen(noWriteFitsKeyStarts[i])) == 0) {
     
    349481                        }
    350482                    } else {
    351                         fits_update_key(fits->fd, TFLOAT, item->name, &item->data.F32, item->comment, &status);
     483                        fits_update_key(fits->fd, TFLOAT, item->name, &item->data.F32, item->comment,
     484                                        &status);
    352485                    }
    353486                    break;
     
    364497                        }
    365498                    } else {
    366                         fits_update_key(fits->fd, TDOUBLE, item->name, &item->data.F64, item->comment, &status);
     499                        fits_update_key(fits->fd, TDOUBLE, item->name, &item->data.F64, item->comment,
     500                                        &status);
    367501                    }
    368502                    break;
     
    395529                      )
    396530{
    397     if (!fits) {
    398         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    399         return false;
    400     }
    401 
    402     if (!output) {
    403         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed."));
    404         return false;
    405     }
     531    PS_ASSERT_FITS_NON_NULL(fits, false);
     532    PS_ASSERT_METADATA_NON_NULL(output, false);
    406533
    407534    return fitsWriteHeader(fits, output, true);
     
    413540                     )
    414541{
    415     if (!fits) {
    416         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    417         return false;
    418     }
     542    PS_ASSERT_FITS_NON_NULL(fits, false);
    419543
    420544    // We allow output == NULL in order to write a minimal header.
     
    458582bool psFitsHeaderValidate(psMetadata *header)
    459583{
    460     if (header == NULL) {
    461         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed."));
    462         return false;
    463     }
     584    PS_ASSERT_METADATA_NON_NULL(header, false);
    464585
    465586    // Traverse the metadata list and inspect at each key
  • trunk/psLib/src/fits/psFitsHeader.h

    r11248 r15179  
    44 * @author Robert DeSonia, MHPCC
    55 *
    6  * @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
    7  * @date $Date: 2007-01-23 22:47:23 $
     6 * @version $Revision: 1.11 $ $Name: not supported by cvs2svn $
     7 * @date $Date: 2007-10-03 21:27:21 $
    88 *
    99 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    1818#include "psFits.h"
    1919#include "psMetadata.h"
     20
     21
     22/// Determine whether the current HDU is an empty PHU with a single compressed image following.
     23///
     24/// In that case, what should be treated as an image PHU is technically an empty PHU with a binary table
     25/// extension.  We test the current position, number of extensions, the FITS headers and presence of a
     26/// following compressed image to determine if this is the case.  If so, the FITS file pointer is left
     27/// pointing at the compressed image.
     28bool psFitsCheckSingleCompressedImagePHU(const psFits *fits, ///< FITS file pointer
     29                                         const psMetadata *header ///< Header, or NULL
     30    );
     31
     32/// Parse a string read from the FITS header.
     33
     34/// Removes the quotes, and any trailing spaces.  NOTE: the returned string is NOT on the psLib memory system
     35/// --- it's simply a hacked version of the input string.  Note also that the input string is MODIFIED.
     36char *p_psFitsHeaderParseString(char *string ///< String to parse
     37    );
    2038
    2139/** Reads the header of the current HDU.
  • trunk/psLib/src/fits/psFitsImage.c

    r10999 r15179  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.17 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2007-01-09 22:38:52 $
     9 *  @version $Revision: 1.18 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2007-10-03 21:27:21 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    3838
    3939// Information required to read a FITS file
    40 typedef struct
    41 {
     40typedef struct {
    4241    int nAxis;                          // Number of axes
    4342    int bitPix;                         // Bits per pixel
     
    4847    int fitsDatatype;                   // cfitsio data type
    4948    int psDatatype;                     // psLib data type
    50 }
    51 p_psFitsReadInfo;
     49} p_psFitsReadInfo;
    5250
    5351static p_psFitsReadInfo *p_psFitsReadInfoAlloc(const psFits *fits, // The FITS file handle
     
    5654                                              )
    5755{
    58     PS_ASSERT_PTR_NON_NULL(fits, NULL);
     56    PS_ASSERT_FITS_NON_NULL(fits, NULL);
    5957    PS_ASSERT_INT_NONNEGATIVE(z, NULL);
    6058
     
    221219                        )
    222220{
     221    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     222    PS_ASSERT_INT_NONNEGATIVE(z, NULL);
     223
     224    if (psFitsCheckSingleCompressedImagePHU(fits, NULL)) {
     225        // This is really what we want, not the empty PHU
     226        psTrace("psLib.fits", 1,
     227                "This PHU should really be a compressed image --- reading that image instead.");
     228    }
     229
    223230    p_psFitsReadInfo *info = p_psFitsReadInfoAlloc(fits, region, z);
    224231
     
    243250                              )
    244251{
     252    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     253    PS_ASSERT_INT_NONNEGATIVE(z, NULL);
     254
    245255    if (output && output->parent) {
    246256        psError(PS_ERR_IO, true, "Unable to read into a buffer for a child image.\n");
    247257        return NULL;
     258    }
     259
     260    if (psFitsCheckSingleCompressedImagePHU(fits, NULL)) {
     261        // This is really what we want, not the empty PHU
     262        psTrace("psLib.fits", 1,
     263                "This PHU should really be a compressed image --- reading that image instead.");
    248264    }
    249265
     
    270286                      const char* extname)
    271287{
     288    PS_ASSERT_FITS_NON_NULL(fits, false);
     289    PS_ASSERT_IMAGE_NON_NULL(input, false);
    272290    // this is equivalent to insert after the last HDU
    273291
     
    283301                       bool after)
    284302{
    285 
    286     if (!fits) {
    287         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    288         return false;
    289     }
    290 
    291     if (!input) {
    292         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."));
    293         return false;
    294     }
     303    PS_ASSERT_FITS_NON_NULL(fits, false);
     304    PS_ASSERT_IMAGE_NON_NULL(input, false);
    295305
    296306    int numCols = input->numCols;       // Number of columns for image
     
    391401                       int z)
    392402{
     403    PS_ASSERT_FITS_NON_NULL(fits, false);
     404    PS_ASSERT_IMAGE_NON_NULL(input, false);
     405
    393406    int status = 0;
    394 
    395     if (fits == NULL) {
    396         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    397                 _("The input psFits object can not NULL."));
    398         return false;
    399     }
    400 
    401     if (input == NULL) {
    402         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    403                 _("The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."));
    404         return false;
    405     }
    406407
    407408    // check to see if we are positioned on an image HDU
     
    499500psArray *psFitsReadImageCube(const psFits *fits, psRegion region)
    500501{
     502    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     503
    501504    int nAxis = 0;                      // Number of axes
    502505    long nAxes[3];                      // Number of pixels on each axis
     
    504507    char fitsErr[80] = "";              // CFITSIO error message string
    505508
    506     if (fits == NULL) {
    507         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    508                 _("The input psFits object can not NULL."));
    509         return NULL;
    510     }
    511 
    512509    // Some of this replicates what is in psFitsReadImage, so it's a little inefficient.  But it saves
    513510    // code replication, and should be sufficient for our needs.
     511
     512    if (psFitsCheckSingleCompressedImagePHU(fits, NULL)) {
     513        // This is really what we want, not the empty PHU
     514        psTrace("psLib.fits", 1,
     515                "This PHU should really be a compressed image --- reading that image instead.");
     516    }
    514517
    515518    if (fits_get_img_dim(fits->fd, &nAxis, &status) != 0) {
     
    544547
    545548    // Bad dimensionality
    546     psError(PS_ERR_IO, true, _("Image number of dimensions, %d, is not valid.  Only two or three dimensions supported for FITS I/O."), nAxis);
     549    psError(PS_ERR_IO, true,
     550            _("Image number of dimensions, %d, is not valid."
     551              " Only two or three dimensions supported for FITS I/O."), nAxis);
    547552    return NULL;
    548553}
     
    550555bool psFitsWriteImageCube(psFits *fits, psMetadata *header, const psArray *input, const char *extname)
    551556{
    552     if (fits == NULL) {
    553         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    554                 _("The input psFits object can not NULL."));
    555         return false;
    556     }
    557 
    558     if (input == NULL) {
    559         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    560                 _("The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."));
    561         return false;
    562     }
     557    PS_ASSERT_FITS_NON_NULL(fits, false);
     558    PS_ASSERT_ARRAY_NON_NULL(input, false);
    563559
    564560    if (input->n == 0) {
     
    592588    }
    593589    bool update = psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS", PS_META_REPLACE, "Dimensionality", 3) &&
    594                   psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS1", PS_META_REPLACE, "Number of columns", numCols) &&
    595                   psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS2", PS_META_REPLACE, "Number of rows", numRows) &&
    596                   psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS3", PS_META_REPLACE, "Number of image planes",
    597                                    input->n);
     590        psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS1", PS_META_REPLACE, "Number of columns", numCols) &&
     591        psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS2", PS_META_REPLACE, "Number of rows", numRows) &&
     592        psMetadataAddS32(headerCopy, PS_LIST_HEAD, "NAXIS3", PS_META_REPLACE, "Number of image planes",
     593                         input->n);
    598594    if (! update) {
    599595        psError(PS_ERR_UNKNOWN, false, _("Failed to add metadata item, %s."),
     
    625621bool psFitsUpdateImageCube(psFits *fits, const psArray *input, int x0, int y0)
    626622{
    627     if (fits == NULL) {
    628         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    629                 _("The input psFits object can not NULL."));
    630         return false;
    631     }
    632 
    633     if (input == NULL) {
    634         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    635                 _("The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."));
    636         return false;
    637     }
     623    PS_ASSERT_FITS_NON_NULL(fits, false);
     624    PS_ASSERT_ARRAY_NON_NULL(input, false);
    638625
    639626    if (input->n == 0) {
  • trunk/psLib/src/fits/psFitsTable.c

    r12549 r15179  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.27 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2007-03-22 21:40:47 $
     9 *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2007-10-03 21:27:21 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    3838                               int row)
    3939{
     40    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     41    PS_ASSERT_INT_NONNEGATIVE(row, NULL);
     42
    4043    long numRows;
    4144    int numCols;
    4245    int status = 0;
    43 
    44     if (fits == NULL) {
    45         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    46                 _("The input psFits object can not NULL."));
    47         return NULL;
    48     }
    4946
    5047    // check to see if we even are positioned on a table HDU
     
    185182                               const char* colname)
    186183{
     184    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     185    PS_ASSERT_STRING_NON_EMPTY(colname, NULL);
     186
    187187    int colnum = 0;
    188188    int status = 0;
    189 
    190     if (fits == NULL) {
    191         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    192                 _("The input psFits object can not NULL."));
    193         return NULL;
    194     }
    195189
    196190    // check to see if we even are positioned on a table HDU
     
    266260                                   const char* colname)
    267261{
     262    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     263    PS_ASSERT_STRING_NON_EMPTY(colname, NULL);
     264
    268265    int status = 0;
    269266    int colnum = 0;
    270 
    271     if (fits == NULL) {
    272         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    273                 _("The input psFits object can not NULL."));
    274         return NULL;
    275     }
    276267
    277268    // check to see if we even are positioned on a table HDU
     
    348339psArray* psFitsReadTable(const psFits* fits)
    349340{
     341    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     342
    350343    int status = 0;
    351 
    352     if (fits == NULL) {
    353         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    354                 _("The input psFits object can not NULL."));
    355         return NULL;
    356     }
    357344
    358345    // check to see if we even are positioned on a table HDU
     
    400387                      const char *extname)
    401388{
    402     psFitsMoveLast(fits);
     389    PS_ASSERT_FITS_NON_NULL(fits, false);
     390    if (!psFitsMoveLast(fits)) {
     391        psError(PS_ERR_UNKNOWN, false, "Unable to move to last extension to write table");
     392        return false;
     393    }
    403394    return psFitsInsertTable(fits, header, table, extname, true);
    404395}
     
    460451// Column specification
    461452// Included here, because there's no need for the user to have access to it
    462 typedef struct
    463 {
     453typedef struct {
    464454    psDataType type;                    // psLib type (e.g., PS_DATA_STRING or PS_TYPE_F32)
    465455    size_t size;                        // Size (number of repeats)
    466456    psElemType vectorType;              // psLib type of vectors
    467 }
    468 colSpec;
     457} colSpec;
    469458
    470459
     
    475464                       bool after)
    476465{
     466    PS_ASSERT_FITS_NON_NULL(fits, false);
     467    PS_ASSERT_ARRAY_NON_NULL(table, false);
     468
    477469    int status = 0;
    478 
    479     PS_ASSERT_PTR_NON_NULL(fits, false);
    480     PS_ASSERT_ARRAY_NON_NULL(table, false);
    481470
    482471    long numRows = table->n;
     
    614603        char fitsErr[MAX_STRING_LENGTH];
    615604        fits_get_errstatus(status, fitsErr);
    616         psError(PS_ERR_LOCATION_INVALID, true, "Unable to create FITS table with %ld columns and %ld rows: %s",
     605        psError(PS_ERR_LOCATION_INVALID, true,
     606                "Unable to create FITS table with %ld columns and %ld rows: %s",
    617607                numColumns, table->n, fitsErr);
    618608        psFree(colSpecsIter);
     
    632622    if (extname && strlen(extname) > 0) {
    633623        if (!psFitsSetExtName(fits, extname)) {
    634             psError(PS_ERR_IO, false, "Unable to write FITS header extension name.\n");
    635             psFree(colSpecsIter);
    636             psFree(colSpecs);
    637             return false;
    638         }
     624            psError(PS_ERR_IO, false, "Unable to write FITS header extension name.\n");
     625            psFree(colSpecsIter);
     626            psFree(colSpecs);
     627            return false;
     628        }
    639629    }
    640630
     
    728718                       int row)
    729719{
     720    PS_ASSERT_FITS_NON_NULL(fits, false);
     721    PS_ASSERT_METADATA_NON_NULL(data, false);
     722    PS_ASSERT_INT_NONNEGATIVE(row, false);
     723
    730724    int status = 0;
    731 
    732     if (fits == NULL) {
    733         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    734                 _("The input psFits object can not NULL."));
    735         return false;
    736     }
    737 
    738     if (data == NULL) {
    739         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    740                 _("The input psImage was NULL.  Need a non-NULL psImage for operation to be performed."));
    741         return false;
    742     }
    743725
    744726    // check to see if we even are positioned on a table HDU
Note: See TracChangeset for help on using the changeset viewer.