Changeset 15179 for trunk/psLib/src/fits/psFitsHeader.c
- Timestamp:
- Oct 3, 2007, 11:27:21 AM (19 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/fits/psFitsHeader.c (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/fits/psFitsHeader.c
r14460 r15179 7 7 * @author Robert DeSonia, MHPCC 8 8 * 9 * @version $Revision: 1.3 4$ $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 $ 11 11 * 12 12 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii … … 19 19 #include <unistd.h> 20 20 21 #include "psAssert.h" 21 22 #include "psFits.h" 22 23 #include "string.h" … … 32 33 33 34 #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 34 36 35 37 // list of FITS header keys to ignore; NULL-terminated 36 static c har* ignoreFitsKeys[] = {"", NULL};38 static const char* ignoreFitsKeys[] = { "", NULL}; 37 39 38 40 // List of FITS header keys that may be duplicated; NULL-terminated 39 static c har *duplicateFitsKeys[] = {"COMMENT", "HIERARCH", "HISTORY", NULL};41 static const char *duplicateFitsKeys[] = { "COMMENT", "HIERARCH", "HISTORY", NULL}; 40 42 41 43 // 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}; 44 static const char *noWriteFitsKeys[] = { "SIMPLE", "XTENSION", "BITPIX", "NAXIS", "EXTNAME", "BSCALE", 45 "BZERO", "TFIELDS", "PCOUNT", "GCOUNT", "ZIMAGE", "ZBITPIX", 46 "ZCMPTYPE", NULL}; 47 44 48 // 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 } 49 static 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 53 static 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 57 static 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 70 bool 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 144 char *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 168 static 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 61 174 62 175 // Get number of key names … … 74 187 75 188 // 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)) { 83 190 // We're done here; skip to the next key 84 191 continue; 85 192 } 86 193 87 #if 088 // This doesn't seem to be necessary89 if (strncmp(keyName, "HIERARCH ", 9) == 0) {90 char temp[MAX_STRING_LENGTH];91 strcpy(temp, &keyName[9]);92 strcpy(keyName, temp);93 }94 #endif95 96 194 // Check to see if the keyword should be duplicated 97 195 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; 102 198 } 103 199 … … 116 212 case 'X': // bit 117 213 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)); 119 215 break; 120 216 case 'I': // short int. … … 122 218 // Trap NAN, INF and -INF, which cfitsio doesn't handle. 123 219 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); 125 221 } 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); 127 223 } 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); 129 225 } 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)); 131 228 } 132 229 break; 133 230 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)); 135 232 break; 136 233 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)); 138 235 break; 139 236 140 237 case 'K': // long int. can't all fit in a psS32, put in psF64 141 238 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)); 143 240 break; 144 241 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); 173 257 } 258 break; 259 } 174 260 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 } 179 265 default: 180 266 psError(PS_ERR_IO, true, _("Specified FITS metadata type, %c, is not supported."), keyType); 181 return out; 267 psFree(header); 268 return NULL; 182 269 } 183 270 184 271 if (!success) { 185 272 psError(PS_ERR_UNKNOWN, false, _("Failed to add metadata item, %s."), keyName); 186 return out; 273 psFree(header); 274 return NULL; 187 275 } 188 276 … … 193 281 (void)fits_get_errstatus(status, fitsErr); 194 282 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 291 psMetadata* 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); 198 339 return out; 199 340 } … … 201 342 psMetadata* psFitsReadHeaderSet(psMetadata* out, const psFits* fits) 202 343 { 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) { 210 347 out = psMetadataAlloc(); 211 348 } … … 279 416 // image, the NAXISn haven't been changed; or after converting to F32, the BITPIX hasn't been 280 417 // 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)) { 288 419 // Don't write it; skip to the next key 289 420 continue; … … 294 425 // that go in are correct. However, when we're writing a "blank" HDU (header only), we want 295 426 // to preserve NAXISn etc for reference, so we don't do this. 427 bool writeKey = true; // Write this keyword? 296 428 for (int i = 0; noWriteFitsKeyStarts[i] && writeKey; i++) { 297 429 if (strncmp(item->name, noWriteFitsKeyStarts[i], strlen(noWriteFitsKeyStarts[i])) == 0) { … … 349 481 } 350 482 } 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); 352 485 } 353 486 break; … … 364 497 } 365 498 } 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); 367 501 } 368 502 break; … … 395 529 ) 396 530 { 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); 406 533 407 534 return fitsWriteHeader(fits, output, true); … … 413 540 ) 414 541 { 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); 419 543 420 544 // We allow output == NULL in order to write a minimal header. … … 458 582 bool psFitsHeaderValidate(psMetadata *header) 459 583 { 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); 464 585 465 586 // Traverse the metadata list and inspect at each key
Note:
See TracChangeset
for help on using the changeset viewer.
