IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 2, 2007, 5:01:45 PM (19 years ago)
Author:
Paul Price
Message:

Cleaning up some code, using PS_ASSERT_FITS_NON_NULL instead of custom code in each function. Adding function to determine if the FITS file pointer is on a PHU that should truly be a FITS image (but it's compressed so it's a FITS table, which can't be the PHU). Putting hooks to this function into the header and image read functions, so that they read what the user Really Wants. This behaviour (which some may not want if they want the unadulterated FITS file) can be turned off by setting psFits.compression=false (default is true). This works for reading uncompressed data, data we've compressed ourselves, and data compressed with fpack-0.93. It doesn't yet work with data compressed with cfitsio's imcopy program (due to multiple EXTNAME keywords; about to put in a fix for this).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/pap_branch_070920/psLib/src/fits/psFitsHeader.c

    r15154 r15168  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.34.4.4 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2007-10-01 21:51:42 $
     9 *  @version $Revision: 1.34.4.5 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2007-10-03 03:01:45 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    6868
    6969
    70 bool psFitsEmptyPHU(const psFits *fits, const psMetadata *header)
    71 {
    72     PS_ASSERT_PTR_NON_NULL(fits, false);
    73     PS_ASSERT_METADATA_NON_NULL(header, false);
     70bool psFitsCheckSingleCompressedImagePHU(const psFits *fits, psMetadata *header)
     71{
     72    PS_ASSERT_FITS_NON_NULL(fits, false);
     73
     74    if (!fits->compression) {
     75        // User has turned off compression conventions; doesn't want any nasty surprises
     76        return false;
     77    }
    7478
    7579    if (psFitsGetExtNum(fits) != 0) {
    76         // It's not the PHU, so it can't be an empty PHU!
    77         return false;
    78     }
    79 
    80     if (header->list->n == 0) {
    81         // There's nothing in the list
     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)) {
    82132        return true;
    83133    }
    84134
    85     // Check if it's got any keywords of potential interest
    86     psMetadataIterator *iter = psMetadataIteratorAlloc(header, PS_LIST_HEAD, NULL); // Iterator
    87     psMetadataItem *item;               // Item from iteration
    88     while ((item = psMetadataGetAndIncrement(iter))) {
    89         if (!keywordInList(item->name, emptyKeys)) {
    90             psFree(iter);
    91             return false;
    92         }
    93     }
    94     psFree(iter);
    95 
    96     return true;
    97 }
    98 
    99 
    100 psMetadata* psFitsReadHeader(psMetadata* out,
    101                              const psFits* fits)
    102 {
    103     if (fits == NULL) {
    104         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    105                 _("The input psFits object can not NULL."));
    106         return NULL;
    107     }
    108 
    109     if (out == NULL) {
    110         out = psMetadataAlloc();
    111     }
     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
     144// Read the header
     145static psMetadata *readHeader(const psFits *fits // FITS file from which to read header
     146                              )
     147{
     148    assert(fits);
     149
     150    psMetadata *header = psMetadataAlloc(); // Header, to return
    112151
    113152    // Get number of key names
     
    150189        case 'X': // bit
    151190        case 'B': // byte
    152             success = psMetadataAddS8(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
     191            success = psMetadataAddS8(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
    153192            break;
    154193        case 'I': // short int.
     
    156195            // Trap NAN, INF and -INF, which cfitsio doesn't handle.
    157196            if (strncasecmp(keyValue, "NAN", 3) == 0) {
    158                 success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
     197                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
    159198            } else if (strncasecmp(keyValue, "INF", 3) == 0) {
    160                 success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
     199                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
    161200            } else if (strncasecmp(keyValue, "-INF", 4) == 0) {
    162                 success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
     201                success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
    163202            } else {
    164                 success = psMetadataAddS32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
     203                success = psMetadataAddS32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment,
     204                                           atoi(keyValue));
    165205            }
    166206            break;
    167207        case 'J': // int.
    168             success = psMetadataAddS32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
     208            success = psMetadataAddS32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atoi(keyValue));
    169209            break;
    170210        case 'U': // unsigned int.
    171             success = psMetadataAddU32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atol(keyValue));
     211            success = psMetadataAddU32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atol(keyValue));
    172212            break;
    173213
    174214        case 'K': // long int. can't all fit in a psS32, put in psF64
    175215        case 'F':
    176             success = psMetadataAddF64(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, atof(keyValue));
     216            success = psMetadataAddF64(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, atof(keyValue));
    177217            break;
    178218        case 'C': {
     
    195235                // cfitsio won't write these, so we write them as strings, and then have to trap them on read.
    196236                if (strcasecmp(keyValueFixed, "NAN") == 0) {
    197                     success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
     237                    success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, NAN);
    198238                } else if (strcasecmp(keyValueFixed, "INF") == 0) {
    199                     success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
     239                    success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, INFINITY);
    200240                } else if (strcasecmp(keyValueFixed, "-INF") == 0) {
    201                     success = psMetadataAddF32(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
     241                    success = psMetadataAddF32(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, -INFINITY);
    202242                } else {
    203                     success = psMetadataAddStr(out, PS_LIST_TAIL, keyName, dupFlag, keyComment,
     243                    success = psMetadataAddStr(header, PS_LIST_TAIL, keyName, dupFlag, keyComment,
    204244                                               keyValueFixed);
    205245                }
     
    208248        case 'L': {
    209249                bool temp = (keyValue[0] == 'T') ? 1 : 0;
    210                 success = psMetadataAddBool(out, PS_LIST_TAIL, keyName, dupFlag, keyComment, temp);
     250                success = psMetadataAddBool(header, PS_LIST_TAIL, keyName, dupFlag, keyComment, temp);
    211251                break;
    212252            }
    213253        default:
    214254            psError(PS_ERR_IO, true, _("Specified FITS metadata type, %c, is not supported."), keyType);
    215             return out;
     255            psFree(header);
     256            return NULL;
    216257        }
    217258
    218259        if (!success) {
    219260            psError(PS_ERR_UNKNOWN, false, _("Failed to add metadata item, %s."), keyName);
    220             return out;
     261            psFree(header);
     262            return NULL;
    221263        }
    222264
     
    227269        (void)fits_get_errstatus(status, fitsErr);
    228270        psError(PS_ERR_IO, true, _("Failed to add metadata item, %s."), fitsErr);
    229         return false;
    230     }
    231 
     271        psFree(header);
     272        return false;
     273    }
     274
     275    return header;
     276}
     277
     278
     279psMetadata* psFitsReadHeader(psMetadata* out,
     280                             const psFits* fits)
     281{
     282    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     283
     284    psMetadata *header = readHeader(fits); // Header
     285    if (!header) {
     286        return NULL;
     287    }
     288
     289    // Explore the potential case that this is an empty PHU, and the first extension contains the sole image,
     290    // which is compressed.
     291    if (psFitsCheckSingleCompressedImagePHU(fits, header)) {
     292        // This is really what we want, not the empty PHU
     293        psTrace("psLib.fits", 1,
     294                "This PHU should really be a compressed image --- getting that header instead.");
     295        psFree(header);
     296        header = readHeader(fits);
     297        if (!header) {
     298            return NULL;
     299        }
     300    }
     301
     302    if (!out) {
     303        return header;
     304    }
     305
     306    // Need to move header onto the nominated metadata
     307    psMetadataIterator *iter = psMetadataIteratorAlloc(header, PS_LIST_HEAD, NULL); // Iterator
     308    psMetadataItem *item;           // Item from iteration
     309    while ((item = psMetadataGetAndIncrement(iter))) {
     310        // Need to look for MULTI, which won't be picked up using the iterator.
     311        psMetadataItem *multiCheckItem = psMetadataLookup(header, item->name);
     312        assert(multiCheckItem);
     313        unsigned int flag = 0;      // Flag to indicate MULTI; otherwise default action
     314        if (multiCheckItem->type == PS_DATA_METADATA_MULTI) {
     315            flag = PS_META_DUPLICATE_OK;
     316        }
     317        if (!psMetadataAddItem(out, item, PS_LIST_TAIL, flag)) {
     318            psError(PS_ERR_UNKNOWN, false, "Unable to add header item %s to extant metadata.",
     319                    item->name);
     320            psFree(iter);
     321            psFree(header);
     322            return NULL;
     323        }
     324    }
     325    psFree(iter);
     326    psFree(header);
    232327    return out;
    233328}
     
    235330psMetadata* psFitsReadHeaderSet(psMetadata* out, const psFits* fits)
    236331{
    237     if (fits == NULL) {
    238         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    239         psFree(out);
    240         return NULL;
    241     }
    242 
    243     if (out == NULL) {
     332    PS_ASSERT_FITS_NON_NULL(fits, NULL);
     333
     334    if (!out) {
    244335        out = psMetadataAlloc();
    245336    }
     
    378469                        }
    379470                    } else {
    380                         fits_update_key(fits->fd, TFLOAT, item->name, &item->data.F32, item->comment, &status);
     471                        fits_update_key(fits->fd, TFLOAT, item->name, &item->data.F32, item->comment,
     472                                        &status);
    381473                    }
    382474                    break;
     
    393485                        }
    394486                    } else {
    395                         fits_update_key(fits->fd, TDOUBLE, item->name, &item->data.F64, item->comment, &status);
     487                        fits_update_key(fits->fd, TDOUBLE, item->name, &item->data.F64, item->comment,
     488                                        &status);
    396489                    }
    397490                    break;
     
    424517                      )
    425518{
    426     if (!fits) {
    427         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    428         return false;
    429     }
    430 
    431     if (!output) {
    432         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed."));
    433         return false;
    434     }
     519    PS_ASSERT_FITS_NON_NULL(fits, false);
     520    PS_ASSERT_METADATA_NON_NULL(output, false);
    435521
    436522    return fitsWriteHeader(fits, output, true);
     
    442528                     )
    443529{
    444     if (!fits) {
    445         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psFits object can not NULL."));
    446         return false;
    447     }
     530    PS_ASSERT_FITS_NON_NULL(fits, false);
    448531
    449532    // We allow output == NULL in order to write a minimal header.
     
    487570bool psFitsHeaderValidate(psMetadata *header)
    488571{
    489     if (header == NULL) {
    490         psError(PS_ERR_BAD_PARAMETER_NULL, true, _("The input psMetadata was NULL.  Need a non-NULL psMetadata for operation to be performed."));
    491         return false;
    492     }
     572    PS_ASSERT_METADATA_NON_NULL(header, false);
    493573
    494574    // Traverse the metadata list and inspect at each key
Note: See TracChangeset for help on using the changeset viewer.