8 #include <unordered_set> 9 #include <unordered_map> 16 #include "boost/regex.hpp" 17 #include "boost/filesystem.hpp" 18 #include "boost/preprocessor/seq/for_each.hpp" 19 #include "boost/format.hpp" 48 daf::base::PropertySet
const &metadata) {
50 for (
auto const &fullName : paramNames) {
52 auto name = (lastPeriod == std::string::npos) ? fullName : fullName.substr(lastPeriod + 1);
57 if (
name.size() > 8) {
62 if (type ==
typeid(
bool)) {
63 out += metadata.get<
bool>(
name) ?
"T" :
"F";
66 }
else if (type ==
typeid(
int)) {
68 }
else if (type ==
typeid(
double)) {
71 }
else if (type ==
typeid(
float)) {
75 if (out.
size() > 80) {
80 int const len = out.
size();
83 }
else if (len > 80) {
86 "Formatted data too long: " +
std::to_string(len) +
" > 80: \"" + out +
"\"");
103 class StringStartSet {
107 for (
auto const &word : input) {
109 if (size < _minSize) {
113 for (
auto const &word : input) {
115 assert(_words.
count(start) == 0);
116 _words[start] = word;
122 auto const iter = _words.
find(startString(key));
123 if (iter == _words.
end()) {
148 "SIMPLE",
"BITPIX",
"NAXIS",
"EXTEND",
"GCOUNT",
"PCOUNT",
"XTENSION",
"TFIELDS",
"BSCALE",
"BZERO",
150 "ZBITPIX",
"ZIMAGE",
"ZCMPTYPE",
"ZSIMPLE",
"ZEXTEND",
"ZBLANK",
"ZDATASUM",
"ZHECKSUM",
152 "DATASUM",
"CHECKSUM"};
159 StringStartSet
const ignoreKeyStarts{
160 "NAXIS",
"TZERO",
"TSCAL",
162 "ZNAXIS",
"ZTILE",
"ZNAME",
"ZVAL"};
169 StringStartSet
const ignoreKeyStartsWrite{
"TFORM",
"TTYPE"};
173 if (s.
empty())
return s;
176 return s.
substr(i1, (i1 == std::string::npos) ? 0 : 1 + i2 - i1);
181 char getFormatCode(
bool *) {
return 'X'; }
190 char getFormatCode(
float *) {
return 'E'; }
191 char getFormatCode(
double *) {
return 'D'; }
198 template <
typename T>
201 return (
boost::format(
"%d%c") % size % getFormatCode((T *)0)).str();
202 }
else if (size < 0) {
204 return (
boost::format(
"1Q%c(%d)") % getFormatCode((T *)0) % (-size)).str();
207 return (
boost::format(
"1Q%c") % getFormatCode((T *)0)).str();
213 template <
typename T>
217 struct FitsType<bool> {
218 static int const CONSTANT = TLOGICAL;
221 struct FitsType<char> {
222 static int const CONSTANT = TSTRING;
225 struct FitsType<signed char> {
226 static int const CONSTANT = TSBYTE;
229 struct FitsType<unsigned char> {
230 static int const CONSTANT = TBYTE;
233 struct FitsType<short> {
234 static int const CONSTANT = TSHORT;
237 struct FitsType<unsigned short> {
238 static int const CONSTANT = TUSHORT;
241 struct FitsType<
int> {
242 static int const CONSTANT = TINT;
245 struct FitsType<unsigned
int> {
246 static int const CONSTANT = TUINT;
249 struct FitsType<long> {
250 static int const CONSTANT = TLONG;
253 struct FitsType<unsigned long> {
254 static int const CONSTANT = TULONG;
257 struct FitsType<long long> {
258 static int const CONSTANT = TLONGLONG;
261 struct FitsType<unsigned long long> {
262 static int const CONSTANT = TLONGLONG;
265 struct FitsType<
float> {
266 static int const CONSTANT = TFLOAT;
269 struct FitsType<double> {
270 static int const CONSTANT = TDOUBLE;
274 static int const CONSTANT = TDOUBLE;
277 struct FitsType<
std::complex<float> > {
278 static int const CONSTANT = TCOMPLEX;
281 struct FitsType<
std::complex<double> > {
282 static int const CONSTANT = TDBLCOMPLEX;
286 template <
typename T>
287 struct FitsTableType :
public FitsType<T> {};
289 struct FitsTableType<bool> {
290 static int const CONSTANT = TBIT;
293 template <
typename T>
297 struct FitsBitPix<unsigned char> {
298 static int const CONSTANT = BYTE_IMG;
301 struct FitsBitPix<short> {
302 static int const CONSTANT = SHORT_IMG;
305 struct FitsBitPix<unsigned short> {
306 static int const CONSTANT = USHORT_IMG;
309 struct FitsBitPix<
int> {
310 static int const CONSTANT = LONG_IMG;
313 struct FitsBitPix<unsigned
int> {
314 static int const CONSTANT = ULONG_IMG;
317 struct FitsBitPix<
std::int64_t> {
318 static int const CONSTANT = LONGLONG_IMG;
321 struct FitsBitPix<
std::uint64_t> {
322 static int const CONSTANT = LONGLONG_IMG;
325 struct FitsBitPix<
float> {
326 static int const CONSTANT = FLOAT_IMG;
329 struct FitsBitPix<double> {
330 static int const CONSTANT = DOUBLE_IMG;
333 bool isFitsImageTypeSigned(
int constant) {
335 case BYTE_IMG:
return false;
336 case SHORT_IMG:
return true;
337 case USHORT_IMG:
return false;
338 case LONG_IMG:
return true;
339 case ULONG_IMG:
return false;
340 case LONGLONG_IMG:
return true;
341 case FLOAT_IMG:
return true;
342 case DOUBLE_IMG:
return true;
344 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
"Invalid constant.");
347 static bool allowImageCompression =
true;
349 int fitsTypeForBitpix(
int bitpix) {
365 os <<
"Invalid bitpix value: " << bitpix;
366 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, os.
str());
376 ItemInfo(
bool isComment,
bool isValid) : isComment(isComment), isValid(isValid) {}
388 ItemInfo isCommentIsValid(daf::base::PropertyList
const &pl,
std::string const &
name) {
389 if (!pl.exists(name)) {
390 return ItemInfo(
false,
false);
393 if ((name ==
"COMMENT") || (name ==
"HISTORY")) {
394 return ItemInfo(
true, type ==
typeid(
std::string));
396 return ItemInfo(
false,
true);
407 os <<
"cfitsio error";
408 if (fileName !=
"") {
409 os <<
" (" << fileName <<
")";
412 char fitsErrMsg[FLEN_ERRMSG];
413 fits_get_errstatus(status, fitsErrMsg);
414 os <<
": " << fitsErrMsg <<
" (" << status <<
")";
419 os <<
"\ncfitsio error stack:\n";
420 char cfitsioMsg[FLEN_ERRMSG];
421 while (fits_read_errmsg(cfitsioMsg) != 0) {
422 os <<
" " << cfitsioMsg <<
"\n";
429 fitsfile *fd =
reinterpret_cast<fitsfile *
>(fptr);
430 if (fd != 0 && fd->Fptr != 0 && fd->Fptr->filename != 0) {
431 fileName = fd->Fptr->filename;
446 for (
auto const &
name : allParamNames) {
451 return makeLimitedFitsHeaderImpl(desiredParamNames, metadata);
468 template <
typename T>
470 return FitsBitPix<T>::CONSTANT;
479 fitsfile *fd =
reinterpret_cast<fitsfile *
>(fptr);
480 if (fd != 0 && fd->Fptr != 0 && fd->Fptr->filename != 0) {
481 fileName = fd->Fptr->filename;
488 fits_get_hdu_num(reinterpret_cast<fitsfile *>(fptr), &n);
494 fits_movrel_hdu(reinterpret_cast<fitsfile *>(fptr), hdu, 0, &status);
495 if (behavior & AUTO_CHECK) {
500 fits_movabs_hdu(reinterpret_cast<fitsfile *>(fptr), hdu + 1, 0, &status);
502 if (hdu ==
DEFAULT_HDU && getHdu() == 0 && getImageDim() == 0) {
504 int tmpStatus = status;
505 fits_movrel_hdu(reinterpret_cast<fitsfile *>(fptr), 1, 0, &tmpStatus);
507 if (behavior & AUTO_CHECK) {
515 fits_get_num_hdus(reinterpret_cast<fitsfile *>(fptr), &n, &status);
516 if (behavior & AUTO_CHECK) {
534 std::string nonFiniteDoubleToString(
double value) {
552 double stringToNonFiniteDouble(
std::string const &value) {
553 if (value ==
"NAN") {
556 if (value ==
"+INFINITY") {
559 if (value ==
"-INFINITY") {
565 template <
typename T>
566 void updateKeyImpl(
Fits &
fits,
char const *key, T
const &value,
char const *comment) {
567 fits_update_key(reinterpret_cast<fitsfile *>(fits.
fptr), FitsType<T>::CONSTANT, const_cast<char *>(key),
568 const_cast<T *>(&value), const_cast<char *>(comment), &fits.
status);
571 void updateKeyImpl(
Fits &fits,
char const *key,
std::string const &value,
char const *comment) {
572 fits_update_key_longstr(reinterpret_cast<fitsfile *>(fits.
fptr), const_cast<char *>(key),
573 const_cast<char *>(value.
c_str()), const_cast<char *>(comment), &fits.
status);
576 void updateKeyImpl(
Fits &fits,
char const *key,
bool const &value,
char const *comment) {
578 fits_update_key(reinterpret_cast<fitsfile *>(fits.
fptr), TLOGICAL, const_cast<char *>(key), &v,
579 const_cast<char *>(comment), &fits.
status);
582 void updateKeyImpl(
Fits &fits,
char const *key,
double const &value,
char const *comment) {
583 std::string strValue = nonFiniteDoubleToString(value);
584 if (!strValue.
empty()) {
585 updateKeyImpl(fits, key, strValue, comment);
587 fits_update_key(reinterpret_cast<fitsfile *>(fits.
fptr), FitsType<double>::CONSTANT,
588 const_cast<char *>(key), const_cast<double *>(&value), const_cast<char *>(comment),
593 template <
typename T>
594 void writeKeyImpl(
Fits &fits,
char const *key, T
const &value,
char const *comment) {
595 fits_write_key(reinterpret_cast<fitsfile *>(fits.
fptr), FitsType<T>::CONSTANT, const_cast<char *>(key),
596 const_cast<T *>(&value), const_cast<char *>(comment), &fits.
status);
599 void writeKeyImpl(
Fits &fits,
char const *key,
std::string const &value,
char const *comment) {
600 if (strncmp(key,
"COMMENT", 7) == 0) {
601 fits_write_comment(reinterpret_cast<fitsfile *>(fits.
fptr), const_cast<char *>(value.
c_str()),
603 }
else if (strncmp(key,
"HISTORY", 7) == 0) {
604 fits_write_history(reinterpret_cast<fitsfile *>(fits.
fptr), const_cast<char *>(value.
c_str()),
607 fits_write_key_longstr(reinterpret_cast<fitsfile *>(fits.
fptr), const_cast<char *>(key),
608 const_cast<char *>(value.
c_str()), const_cast<char *>(comment), &fits.
status);
612 void writeKeyImpl(
Fits &fits,
char const *key,
bool const &value,
char const *comment) {
614 fits_write_key(reinterpret_cast<fitsfile *>(fits.
fptr), TLOGICAL, const_cast<char *>(key), &v,
615 const_cast<char *>(comment), &fits.
status);
618 void writeKeyImpl(
Fits &fits,
char const *key,
double const &value,
char const *comment) {
619 std::string strValue = nonFiniteDoubleToString(value);
620 if (!strValue.
empty()) {
621 writeKeyImpl(fits, key, strValue, comment);
623 fits_write_key(reinterpret_cast<fitsfile *>(fits.
fptr), FitsType<double>::CONSTANT,
624 const_cast<char *>(key), const_cast<double *>(&value), const_cast<char *>(comment),
631 template <
typename T>
633 updateKeyImpl(*
this, key.
c_str(), value, comment.
c_str());
634 if (behavior & AUTO_CHECK) {
639 template <
typename T>
641 writeKeyImpl(*
this, key.
c_str(), value, comment.
c_str());
642 if (behavior & AUTO_CHECK) {
647 template <
typename T>
649 updateKeyImpl(*
this, key.
c_str(), value, 0);
650 if (behavior & AUTO_CHECK) {
655 template <
typename T>
657 writeKeyImpl(*
this, key.
c_str(), value, 0);
658 if (behavior & AUTO_CHECK) {
663 template <
typename T>
665 updateKey((
boost::format(
"%s%d") % prefix % (n + 1)).
str(), value, comment);
666 if (behavior & AUTO_CHECK) {
671 template <
typename T>
674 if (behavior & AUTO_CHECK) {
679 template <
typename T>
682 if (behavior & AUTO_CHECK) {
687 template <
typename T>
690 if (behavior & AUTO_CHECK) {
699 template <
typename T>
700 void readKeyImpl(
Fits &
fits,
char const *key, T &value) {
701 fits_read_key(reinterpret_cast<fitsfile *>(fits.
fptr), FitsType<T>::CONSTANT, const_cast<char *>(key),
707 fits_read_key_longstr(reinterpret_cast<fitsfile *>(fits.
fptr), const_cast<char *>(key), &buf, 0,
715 void readKeyImpl(
Fits &fits,
char const *key,
double &value) {
719 char buf[FLEN_VALUE];
720 fits_read_keyword(reinterpret_cast<fitsfile *>(fits.
fptr), const_cast<char *>(key), buf, 0, &fits.
status);
724 if (
std::string(buf).find(
'\'') != std::string::npos) {
726 readKeyImpl(fits, key, unquoted);
730 value = stringToNonFiniteDouble(unquoted);
734 (
boost::format(
"Unrecognised string value for keyword '%s' when parsing as double: %s") %
739 fits_read_key(reinterpret_cast<fitsfile *>(fits.
fptr), FitsType<double>::CONSTANT,
740 const_cast<char *>(key), &value, 0, &fits.
status);
746 template <
typename T>
748 readKeyImpl(*
this, key.
c_str(), value);
749 if (behavior & AUTO_CHECK) {
759 fits_get_hdrspace(reinterpret_cast<fitsfile *>(fptr), &nKeys, 0, &status);
765 fits_read_keyn(reinterpret_cast<fitsfile *>(fptr), i, key, value, comment, &status);
768 commentStr = comment;
770 while (valueStr.
size() > 2 && valueStr[valueStr.
size() - 2] ==
'&' && i <= nKeys) {
772 fits_read_record(reinterpret_cast<fitsfile *>(fptr), i, key, &status);
773 if (strncmp(key,
"CONTINUE", 8) != 0) {
780 if (firstQuote == std::string::npos) {
785 boost::format(
"Invalid CONTINUE at header key %d: \"%s\".") % i % card));
788 if (lastQuote == std::string::npos) {
793 boost::format(
"Invalid CONTINUE at header key %d: \"%s\".") % i % card));
795 valueStr += card.
substr(firstQuote + 1, lastQuote - firstQuote);
797 if (slash != std::string::npos) {
802 if (behavior & AUTO_CHECK) {
805 functor(keyStr, valueStr, commentStr);
813 bool isKeyIgnored(
std::string const &key,
bool write =
false) {
814 return ((ignoreKeys.
find(key) != ignoreKeys.
end()) || ignoreKeyStarts.matches(key) ||
815 (write && ignoreKeyStartsWrite.matches(key)));
822 template <
typename T>
825 list->add(key, value, comment);
827 set->add(key, value);
832 daf::base::PropertySet *
set;
838 static boost::regex
const boolRegex(
"[tTfF]");
839 static boost::regex
const intRegex(
"[+-]?[0-9]+");
840 static boost::regex
const doubleRegex(
"[+-]?([0-9]*\\.?[0-9]+|[0-9]+\\.?[0-9]*)([eE][+-]?[0-9]+)?");
841 static boost::regex
const fitsStringRegex(
"'(.*?) *'");
843 static boost::regex
const fitsDefinitionCommentRegex(
844 " *(FITS \\(Flexible Image Transport System\\)|and Astrophysics', volume 376, page 359).*");
845 boost::smatch matchStrings;
847 if (
strip && isKeyIgnored(key)) {
852 if (boost::regex_match(value, boolRegex)) {
854 add(key,
bool(value ==
"T" || value ==
"t"), comment);
855 }
else if (boost::regex_match(value, intRegex)) {
859 if (val < (1
LL << 31) && val > -(1
LL << 31)) {
860 add(key, static_cast<int>(val), comment);
862 add(key, val, comment);
864 }
else if (boost::regex_match(value, doubleRegex)) {
868 add(key, val, comment);
869 }
else if (boost::regex_match(value, matchStrings, fitsStringRegex)) {
871 double val = stringToNonFiniteDouble(str);
873 add(key, val, comment);
875 add(key, str, comment);
877 }
else if (key ==
"HISTORY") {
878 add(key, comment,
"");
879 }
else if (key ==
"COMMENT" && !(
strip && boost::regex_match(comment, fitsDefinitionCommentRegex))) {
880 add(key, comment,
"");
881 }
else if (value.
empty()) {
885 afw::fits::FitsError,
886 (
boost::format(
"Could not parse header value for key '%s': '%s'") % key % value).
str());
890 void writeKeyFromProperty(Fits &
fits, daf::base::PropertySet
const &metadata,
std::string const &key,
891 char const *comment = 0) {
893 if (valueType ==
typeid(
bool)) {
894 if (metadata.isArray(key)) {
898 writeKeyImpl(fits, key.
c_str(),
static_cast<bool>(tmp[i]), comment);
901 writeKeyImpl(fits, key.
c_str(), metadata.get<
bool>(
key), comment);
904 if (metadata.isArray(key)) {
907 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
912 }
else if (valueType ==
typeid(
int)) {
913 if (metadata.isArray(key)) {
916 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
919 writeKeyImpl(fits, key.
c_str(), metadata.get<
int>(
key), comment);
921 }
else if (valueType ==
typeid(
long)) {
922 if (metadata.isArray(key)) {
925 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
928 writeKeyImpl(fits, key.
c_str(), metadata.get<
long>(
key), comment);
930 }
else if (valueType ==
typeid(
long long)) {
931 if (metadata.isArray(key)) {
934 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
937 writeKeyImpl(fits, key.
c_str(), metadata.get<
long long>(
key), comment);
940 if (metadata.isArray(key)) {
943 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
948 }
else if (valueType ==
typeid(
double)) {
949 if (metadata.isArray(key)) {
952 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
955 writeKeyImpl(fits, key.
c_str(), metadata.get<
double>(
key), comment);
958 if (metadata.isArray(key)) {
961 writeKeyImpl(fits, key.
c_str(), tmp[i], comment);
971 BOOST_CURRENT_FUNCTION % valueType.
name() %
key));
981 MetadataIterationFunctor f;
997 for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
998 if (!isKeyIgnored(*i,
true)) {
1000 writeKeyFromProperty(*
this, metadata, *i, pl->
getComment(*i).
c_str());
1002 writeKeyFromProperty(*
this, metadata, *i);
1013 fits_create_tbl(reinterpret_cast<fitsfile *>(fptr), BINARY_TBL, 0, 0, &ttype, &tform, 0, 0, &status);
1014 if (behavior & AUTO_CHECK) {
1019 template <
typename T>
1022 fits_get_num_cols(reinterpret_cast<fitsfile *>(fptr), &nCols, &status);
1024 fits_insert_col(reinterpret_cast<fitsfile *>(fptr), nCols + 1, const_cast<char *>(ttype.
c_str()),
1025 const_cast<char *>(tform.
c_str()), &status);
1026 if (behavior & AUTO_CHECK) {
1032 template <
typename T>
1034 int nCols = addColumn<T>(ttype, size);
1035 updateColumnKey(
"TTYPE", nCols, ttype, comment);
1036 if (behavior & AUTO_CHECK) {
1044 fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &first, &status);
1045 fits_insert_rows(reinterpret_cast<fitsfile *>(fptr), first, nRows, &status);
1046 if (behavior & AUTO_CHECK) {
1054 fits_get_num_rows(reinterpret_cast<fitsfile *>(fptr), &r, &status);
1055 if (behavior & AUTO_CHECK) {
1061 template <
typename T>
1063 fits_write_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1064 nElements, const_cast<T *>(value), &status);
1065 if (behavior & AUTO_CHECK) {
1067 nElements % row % col);
1076 char const *tmp = value.
c_str();
1077 fits_write_col(reinterpret_cast<fitsfile *>(fptr), TSTRING, col + 1, row + 1, 1, 1,
1078 const_cast<char const **>(&tmp), &status);
1079 if (behavior & AUTO_CHECK) {
1084 template <
typename T>
1087 fits_read_col(reinterpret_cast<fitsfile *>(fptr), FitsTableType<T>::CONSTANT, col + 1, row + 1, 1,
1088 nElements, 0, value, &anynul, &status);
1089 if (behavior & AUTO_CHECK) {
1096 long size = isVariableLength ? getTableArraySize(row, col) : getTableArraySize(col);
1101 char *tmp = &buf.
front();
1102 fits_read_col(reinterpret_cast<fitsfile *>(fptr), TSTRING, col + 1, row + 1, 1, 1, 0, &tmp, &anynul,
1104 if (behavior & AUTO_CHECK) {
1114 fits_get_coltype(reinterpret_cast<fitsfile *>(fptr), col + 1, &typecode, &result, &width, &status);
1115 if (behavior & AUTO_CHECK) {
1124 fits_read_descript(reinterpret_cast<fitsfile *>(fptr), col + 1, row + 1, &result, &offset, &status);
1125 if (behavior & AUTO_CHECK) {
1135 fits_create_img(reinterpret_cast<fitsfile *>(fptr), 8, 0, &naxes, &status);
1136 if (behavior & AUTO_CHECK) {
1141 void Fits::createImageImpl(
int bitpix,
int naxis,
long const *naxes) {
1142 fits_create_img(reinterpret_cast<fitsfile *>(fptr), bitpix, naxis, const_cast<long *>(naxes), &status);
1143 if (behavior & AUTO_CHECK) {
1148 template <
typename T>
1149 void Fits::writeImageImpl(T
const *
data,
int nElements) {
1150 fits_write_img(reinterpret_cast<fitsfile *>(fptr), FitsType<T>::CONSTANT, 1, nElements,
1151 const_cast<T *>(data), &status);
1152 if (behavior & AUTO_CHECK) {
1163 struct ImageCompressionContext {
1166 :
fits(fits_), old(
fits.getImageCompression()) {
1167 fits.setImageCompression(useThis);
1169 ~ImageCompressionContext() {
1173 fits.setImageCompression(old);
1188 template <
typename T>
1192 auto fits =
reinterpret_cast<fitsfile *
>(fptr);
1198 ImageCompressionContext comp(*
this, compression);
1199 if (behavior & AUTO_CHECK) {
1206 ndarray::Vector<long, 2> dims(image.
getArray().getShape().reverse());
1214 copy->combine(wcsMetadata);
1217 header = wcsMetadata;
1219 writeMetadata(*header);
1233 fits_set_bscale(
fits, 1.0, 0.0, &status);
1234 if (behavior & AUTO_CHECK) {
1240 int const fitsType = scale.
bitpix == 0 ? FitsType<T>::CONSTANT : fitsTypeForBitpix(scale.
bitpix);
1241 fits_write_img(
fits, fitsType, 1, pixels->getNumElements(),
const_cast<void *
>(pixels->getData()),
1243 if (behavior & AUTO_CHECK) {
1253 if (scale.
bzero != 0.0) {
1254 fits_write_key_lng(
fits,
"BZERO", static_cast<long>(scale.
bzero),
1255 "Scaling: MEMORY = BZERO + BSCALE * DISK", &status);
1257 if (scale.
bscale != 1.0) {
1258 fits_write_key_lng(
fits,
"BSCALE", static_cast<long>(scale.
bscale),
1259 "Scaling: MEMORY = BZERO + BSCALE * DISK", &status);
1262 fits_write_key_dbl(
fits,
"BZERO", scale.
bzero, 12,
"Scaling: MEMORY = BZERO + BSCALE * DISK",
1264 fits_write_key_dbl(
fits,
"BSCALE", scale.
bscale, 12,
"Scaling: MEMORY = BZERO + BSCALE * DISK",
1267 if (behavior & AUTO_CHECK) {
1273 fits_write_key_lng(
fits,
"BLANK", scale.
blank,
"Value for undefined pixels", &status);
1274 fits_write_key_lng(
fits,
"ZDITHER0", options.
scaling.
seed,
"Dithering seed", &status);
1275 fits_write_key_str(
fits,
"ZQUANTIZ",
"SUBTRACTIVE_DITHER_1",
"Dithering algorithm", &status);
1276 if (behavior & AUTO_CHECK) {
1284 fits_set_hdustruc(
fits, &status);
1285 if (behavior & AUTO_CHECK) {
1293 template <
typename T,
class Enable =
void>
1295 static T constexpr value = 0;
1299 template <
typename T>
1300 struct NullValue<T, typename std::enable_if<std::numeric_limits<T>::has_quiet_NaN>
::type> {
1306 template <
typename T>
1307 void Fits::readImageImpl(
int nAxis, T *data,
long *begin,
long *
end,
long *increment) {
1308 T null = NullValue<T>::value;
1310 fits_read_subset(reinterpret_cast<fitsfile *>(fptr), FitsType<T>::CONSTANT, begin, end, increment,
1311 reinterpret_cast<void *>(&null), data, &anyNulls, &status);
1317 fits_get_img_dim(reinterpret_cast<fitsfile *>(fptr), &nAxis, &status);
1322 void Fits::getImageShapeImpl(
int maxDim,
long *nAxes) {
1323 fits_get_img_size(reinterpret_cast<fitsfile *>(fptr), maxDim, nAxes, &status);
1327 template <
typename T>
1330 fits_get_img_equivtype(reinterpret_cast<fitsfile *>(fptr), &imageType, &status);
1333 if (imageType < 0) {
1337 if (isFitsImageTypeSigned(imageType)) {
1338 return FitsBitPix<T>::CONSTANT >= imageType;
1341 return FitsBitPix<T>::CONSTANT > imageType;
1344 if (!isFitsImageTypeSigned(imageType)) {
1345 return FitsBitPix<T>::CONSTANT >= imageType;
1346 }
else if (imageType == LONGLONG_IMG) {
1349 return FitsBitPix<T>::CONSTANT >= imageType;
1361 fits_get_img_equivtype(reinterpret_cast<fitsfile *>(fptr), &bitpix, &status);
1374 case BYTE_IMG:
return "uint8";
1375 case SBYTE_IMG:
return "int8";
1376 case SHORT_IMG:
return "int16";
1377 case USHORT_IMG:
return "uint16";
1378 case LONG_IMG:
return "int32";
1379 case ULONG_IMG:
return "uint32";
1380 case LONGLONG_IMG:
return "int64";
1389 auto fits =
reinterpret_cast<fitsfile *
>(fptr);
1391 fits_get_compression_type(
fits, &compType, &status);
1392 if (behavior & AUTO_CHECK) {
1397 fits_get_tile_dim(
fits, tiles.getNumElements(), tiles.getData(), &status);
1398 if (behavior & AUTO_CHECK) {
1402 float quantizeLevel;
1403 fits_get_quantize_level(
fits, &quantizeLevel, &status);
1404 if (behavior & AUTO_CHECK) {
1412 auto fits =
reinterpret_cast<fitsfile *
>(fptr);
1413 fits_unset_compression_request(
fits, &status);
1417 if (behavior & AUTO_CHECK) {
1426 fits_set_tile_dim(
fits, comp.
tiles.getNumElements(), comp.
tiles.getData(), &status);
1427 if (behavior & AUTO_CHECK) {
1433 if (behavior & AUTO_CHECK) {
1446 : fptr(0), status(0), behavior(behavior_) {
1447 if (mode ==
"r" || mode ==
"rb") {
1448 fits_open_file(reinterpret_cast<fitsfile **>(&
fptr), const_cast<char *>(filename.
c_str()), READONLY,
1450 }
else if (mode ==
"w" || mode ==
"wb") {
1451 boost::filesystem::remove(filename);
1452 fits_create_file(reinterpret_cast<fitsfile **>(&
fptr), const_cast<char *>(filename.
c_str()), &
status);
1453 }
else if (mode ==
"a" || mode ==
"ab") {
1454 fits_open_file(reinterpret_cast<fitsfile **>(&
fptr), const_cast<char *>(filename.
c_str()), READWRITE,
1457 fits_get_num_hdus(reinterpret_cast<fitsfile *>(
fptr), &nHdu, &
status);
1458 fits_movabs_hdu(reinterpret_cast<fitsfile *>(
fptr), nHdu, NULL, &
status);
1463 fits_close_file(reinterpret_cast<fitsfile *>(
fptr), &tmpStatus);
1468 (
boost::format(
"Invalid mode '%s' given when opening file '%s'") % mode % filename).
str());
1477 typedef void *(*Reallocator)(
void *,
std::size_t);
1480 if (mode ==
"r" || mode ==
"rb") {
1481 fits_open_memfile(reinterpret_cast<fitsfile **>(&
fptr),
"unused", READONLY, &manager._ptr,
1482 &manager._len, 0, 0,
1484 }
else if (mode ==
"w" || mode ==
"wb") {
1485 Reallocator reallocator = 0;
1487 fits_create_memfile(reinterpret_cast<fitsfile **>(&
fptr), &manager._ptr, &manager._len, 0,
1490 }
else if (mode ==
"a" || mode ==
"ab") {
1491 Reallocator reallocator = 0;
1493 fits_open_memfile(reinterpret_cast<fitsfile **>(&
fptr),
"unused", READWRITE, &manager._ptr,
1494 &manager._len, 0, reallocator, &
status);
1496 fits_get_num_hdus(reinterpret_cast<fitsfile *>(
fptr), &nHdu, &
status);
1497 fits_movabs_hdu(reinterpret_cast<fitsfile *>(
fptr), nHdu, NULL, &
status);
1502 fits_close_file(reinterpret_cast<fitsfile *>(
fptr), &tmpStatus);
1506 (
boost::format(
"Invalid mode '%s' given when opening memory file at '%s'") % mode %
1512 *
this,
boost::format(
"Opening memory file at '%s' with mode '%s'") % manager._ptr % mode);
1517 fits_close_file(reinterpret_cast<fitsfile *>(
fptr), &
status);
1524 auto combined = std::make_shared<daf::base::PropertyList>();
1525 bool const asScalar =
true;
1526 for (
auto const &
name : first->getOrderedNames()) {
1527 auto const iscv = isCommentIsValid(*first,
name);
1528 if (iscv.isComment) {
1533 combined->copy(
name, first,
name, asScalar);
1536 for (
auto const &
name : second->getOrderedNames()) {
1537 auto const iscv = isCommentIsValid(*second,
name);
1538 if (iscv.isComment) {
1544 combined->copy(
name, second,
name, asScalar);
1563 auto metadata = std::make_shared<lsst::daf::base::PropertyList>();
1566 int oldHdu = fitsfile.
getHdu();
1567 if (oldHdu != 0 && metadata->exists(
"INHERIT")) {
1568 bool inherit =
false;
1569 if (metadata->typeOf(
"INHERIT") ==
typeid(
std::string)) {
1570 inherit = (metadata->get<
std::string>(
"INHERIT") ==
"T");
1572 inherit = metadata->get<
bool>(
"INHERIT");
1574 if (strip) metadata->remove(
"INHERIT");
1580 auto primaryHduMetadata = std::make_shared<daf::base::PropertyList>();
1585 auto const emptyMetadata = std::make_shared<lsst::daf::base::PropertyList>();
1598 _fits.
setHdu(hdu, relative);
1620 auto fits =
reinterpret_cast<fitsfile *
>(fptr);
1621 if (getHdu() != 0 || countHdus() == 1) {
1626 fits_get_img_dim(
fits, &naxis, &status);
1627 if (behavior & AUTO_CHECK) {
1635 bool isCompressed = fits_is_compressed_image(
fits, &status);
1636 if (behavior & AUTO_CHECK) {
1642 return isCompressed;
1649 config.getAsDouble(
"compression.quantizeLevel")),
1651 config.getAsInt(
"scaling.bitpix"),
1652 config.exists(
"scaling.maskPlanes") ? config.getArray<
std::string>(
"scaling.maskPlanes")
1654 config.getAsInt(
"scaling.seed"), config.getAsDouble(
"scaling.quantizeLevel"),
1655 config.getAsDouble(
"scaling.quantizePad"), config.get<
bool>(
"scaling.fuzz"),
1656 config.getAsDouble(
"scaling.bscale"), config.getAsDouble(
"scaling.bzero")) {}
1660 template <
typename T>
1663 output.
add(name, input.
get<T>(name, defaultValue));
1666 template <
typename T>
1675 auto validated = std::make_shared<daf::base::PropertySet>();
1677 validateEntry(*validated, config,
"compression.algorithm",
std::string(
"NONE"));
1678 validateEntry(*validated, config,
"compression.columns", 0);
1679 validateEntry(*validated, config,
"compression.rows", 1);
1680 validateEntry(*validated, config,
"compression.quantizeLevel", 0.0);
1682 validateEntry(*validated, config,
"scaling.algorithm",
std::string(
"NONE"));
1683 validateEntry(*validated, config,
"scaling.bitpix", 0);
1685 validateEntry(*validated, config,
"scaling.seed", 1);
1686 validateEntry(*validated, config,
"scaling.quantizeLevel", 5.0);
1687 validateEntry(*validated, config,
"scaling.quantizePad", 10.0);
1688 validateEntry(*validated, config,
"scaling.fuzz",
true);
1689 validateEntry(*validated, config,
"scaling.bscale", 1.0);
1690 validateEntry(*validated, config,
"scaling.bzero", 0.0);
1693 for (
auto const &
name : config.
names(
false)) {
1694 if (!validated->exists(
name)) {
1696 os <<
"Invalid image write option: " <<
name;
1704 #define INSTANTIATE_KEY_OPS(r, data, T) \ 1705 template void Fits::updateKey(std::string const &, T const &, std::string const &); \ 1706 template void Fits::writeKey(std::string const &, T const &, std::string const &); \ 1707 template void Fits::updateKey(std::string const &, T const &); \ 1708 template void Fits::writeKey(std::string const &, T const &); \ 1709 template void Fits::updateColumnKey(std::string const &, int, T const &, std::string const &); \ 1710 template void Fits::writeColumnKey(std::string const &, int, T const &, std::string const &); \ 1711 template void Fits::updateColumnKey(std::string const &, int, T const &); \ 1712 template void Fits::writeColumnKey(std::string const &, int, T const &); \ 1713 template void Fits::readKey(std::string const &, T &); 1715 #define INSTANTIATE_IMAGE_OPS(r, data, T) \ 1716 template void Fits::writeImageImpl(T const *, int); \ 1717 template void Fits::writeImage(image::ImageBase<T> const &, ImageWriteOptions const &, \ 1718 std::shared_ptr<daf::base::PropertySet const>, \ 1719 std::shared_ptr<image::Mask<image::MaskPixel> const>); \ 1720 template void Fits::readImageImpl(int, T *, long *, long *, long *); \ 1721 template bool Fits::checkImageType<T>(); \ 1722 template int getBitPix<T>(); 1724 #define INSTANTIATE_TABLE_OPS(r, data, T) \ 1725 template int Fits::addColumn<T>(std::string const &ttype, int size); \ 1726 template int Fits::addColumn<T>(std::string const &ttype, int size, std::string const &comment); 1727 #define INSTANTIATE_TABLE_ARRAY_OPS(r, data, T) \ 1728 template void Fits::writeTableArray(std::size_t row, int col, int nElements, T const *value); \ 1729 template void Fits::readTableArray(std::size_t row, int col, int nElements, T *value); 1736 (bool)(unsigned char)(short)(unsigned short)(int)(unsigned int)(long)(unsigned long)(LONGLONG)( \ 1737 float)(double)(std::complex<float>)(std::complex<double>)(std::string) 1739 #define COLUMN_TYPES \ 1740 (bool)(std::string)(std::int8_t)(std::uint8_t)(std::int16_t)(std::uint16_t)(std::int32_t)(std::uint32_t) \ 1741 (std::int64_t)(float)(double)(lsst::geom::Angle)(std::complex<float>)(std::complex<double>) 1743 #define COLUMN_ARRAY_TYPES \ 1744 (bool)(char)(std::uint8_t)(std::int16_t)(std::uint16_t)(std::int32_t)(std::uint32_t)(std::int64_t)( \ 1745 float)(double)(lsst::geom::Angle)(std::complex<float>)(std::complex<double>) 1747 #define IMAGE_TYPES \ 1748 (unsigned char)(short)(unsigned short)(int)(unsigned int)(std::int64_t)(std::uint64_t)(float)(double) #define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
int getImageDim()
Return the number of dimensions in the current HDU.
std::size_t countRows()
Return the number of row in a table.
#define INSTANTIATE_TABLE_OPS(r, data, T)
std::shared_ptr< daf::base::PropertyList > combineMetadata(std::shared_ptr< const daf::base::PropertyList > first, std::shared_ptr< const daf::base::PropertyList > second)
Combine two sets of metadata in a FITS-appropriate fashion.
std::string getFileName() const
Return the file name associated with the FITS object or "<unknown>" if there is none.
void forEachKey(HeaderIterationFunctor &functor)
Call a polymorphic functor for every key in the header.
ImageCompressionOptions getImageCompression()
Return the current image compression settings.
ImageCompressionOptions compression
Options controlling compression.
T find_first_not_of(T... args)
void writeMetadata(daf::base::PropertySet const &metadata)
Read a FITS header into a PropertySet or PropertyList.
#define LSST_FITS_CHECK_STATUS(fitsObj,...)
Throw a FitsError exception if the status of the given Fits object is nonzero.
std::vector< T > getArray(std::string const &name) const
Get the vector of values for a property name (possibly hierarchical).
int compressionAlgorithmToCfitsio(ImageCompressionOptions::CompressionAlgorithm algorithm)
Convert ImageCompressionOptions::CompressionAlgorithm to cfitsio.
Class for storing ordered metadata with comments.
T get(std::string const &name) const
Get the last value for a property name (possibly hierarchical).
long blank
Value for integer images indicating non-finite values.
void readKey(std::string const &key, T &value)
Read a FITS header key into the given reference.
int bitpix
Bits per pixel; negative means floating-point: 8,16,32,64,-32,-64.
void updateColumnKey(std::string const &prefix, int n, T const &value, std::string const &comment)
Update a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.
Options for writing an image to FITS.
std::string const & getComment(std::string const &name) const
Get the comment for a string property name (possibly hierarchical).
def scale(algorithm, min, max=None, frame=None)
int getBitPix()
Return the cfitsio integer BITPIX code for the given data type.
void readTableScalar(std::size_t row, int col, T &value)
Read an array scalar from a binary table.
bool checkImageType()
Return true if the current HDU is compatible with the given pixel type.
void writeColumnKey(std::string const &prefix, int n, T const &value, std::string const &comment)
Write a key of the form XXXXXnnn, where XXXXX is the prefix and nnn is a column number.
#define INSTANTIATE_TABLE_ARRAY_OPS(r, data, T)
std::vector< std::string > paramNames(bool topLevelOnly=true) const
A variant of names that excludes the names of subproperties.
CompressionAlgorithm
Compression algorithms.
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
The base class for all image classed (Image, Mask, MaskedImage, ...)
long getTableArraySize(int col)
Return the size of an array column.
FITS BITPIX header value by C++ type.
void closeFile()
Close a FITS file.
A class representing an angle.
int seed
Seed for random number generator when fuzzing.
void createEmpty()
Create an empty image HDU with NAXIS=0 at the end of the file.
std::string getImageDType()
Return the numpy dtype equivalent of the image pixel type (e.g.
void updateKey(std::string const &key, T const &value, std::string const &comment)
Set a FITS header key, editing if it already exists and appending it if not.
LSST DM logging module built on log4cxx.
ndarray::Array< T const, N, N > const makeContiguousArray(ndarray::Array< T, N, C > const &array)
Construct a contiguous ndarray.
An exception thrown when problems are found when reading or writing FITS files.
Tiles tiles
Tile size; a dimension with 0 means infinite (e.g., to specify one row: 0,1)
Options for tile compression of image pixels.
A base class for image defects.
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Represent a 2-dimensional array of bitmask pixels.
int64_t getAsInt64(std::string const &name) const
Get the last value for a bool/char/short/int/int64_t property name (possibly hierarchical).
Lifetime-management for memory that goes into FITS memory files.
double bzero
Zero-point to apply when reading from FITS.
std::size_t addRows(std::size_t nRows)
Append rows to a table, and return the index of the first new row.
std::shared_ptr< daf::base::PropertyList > createTrivialWcsMetadata(std::string const &wcsName, lsst::geom::Point2I const &xy0)
ImageCompressionOptions::CompressionAlgorithm compressionAlgorithmFromString(std::string const &name)
Interpret compression algorithm expressed in string.
Fits()
Default constructor; set all data members to 0.
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
ndarray::Array< long, 1, 1 > Tiles
void createTable()
Create a new binary table extension.
#define LOGL_WARN(logger, message...)
Log a warn-level message using a varargs/printf style interface.
double bscale
Scale to apply when reading from FITS.
void setHdu(int hdu, bool relative=false)
Set the current HDU.
T find_last_not_of(T... args)
#define INSTANTIATE_IMAGE_OPS(r, data, T)
BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_COLUMNVIEW_SCALAR, _, BOOST_PP_TUPLE_TO_SEQ(AFW_TABLE_SCALAR_FIELD_TYPE_N, AFW_TABLE_SCALAR_FIELD_TYPE_TUPLE)) BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_COLUMNVIEW_ARRAY
lsst::geom::Point2I getXY0() const
Return the image's origin.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
#define INSTANTIATE_KEY_OPS(r, data, T)
ImageScalingOptions scaling
Options controlling scaling.
static std::shared_ptr< daf::base::PropertySet > validate(daf::base::PropertySet const &config)
Validate a PropertySet.
void disable()
Disable the guard, leaving the HDU at its current state at destruction.
bool checkCompressedImagePhu()
Go to the first image header in the FITS file.
void setAllowImageCompression(bool allow)
Class for storing generic metadata.
float quantizeLevel
quantization level: 0.0 = none requires use of GZIP or GZIP_SHUFFLE
void writeTableArray(std::size_t row, int col, int nElements, T const *value)
Write an array value to a binary table.
void reset()
Return the manager to the same state it would be if default-constructed.
CompressionAlgorithm algorithm
Compresion algorithm to use.
void readTableArray(std::size_t row, int col, int nElements, T *value)
Read an array value from a binary table.
ImageCompressionOptions::CompressionAlgorithm compressionAlgorithmFromCfitsio(int cfitsio)
Convert compression algorithm from cfitsio to ImageCompressionOptions::CompressionAlgorithm.
ImageScale determine(image::ImageBase< T > const &image, std::shared_ptr< image::Mask< image::MaskPixel > const > mask=nullptr) const
Determine the scaling for a particular image.
void setImageCompression(ImageCompressionOptions const &options)
Set compression options for writing FITS images.
#define COLUMN_ARRAY_TYPES
void writeKey(std::string const &key, T const &value, std::string const &comment)
Add a FITS header key to the bottom of the header.
bool fuzz
Fuzz the values when quantising floating-point values?
std::vector< std::string > names(bool topLevelOnly=true) const
Get the names in the PropertySet, optionally including those in subproperties.
bool getAllowImageCompression()
int getHdu()
Return the current HDU (0-indexed; 0 is the Primary HDU).
void add(std::string const &name, T const &value)
Append a single value to the vector of values for a property name (possibly hierarchical).
void writeImage(ndarray::Array< T const, N, C > const &array)
Write an ndarray::Array to a FITS image HDU.
std::vector< std::string > getOrderedNames() const
Get the list of property names, in the order they were added.
int addColumn(std::string const &ttype, int size, std::string const &comment)
Add a column to a table.
daf::base::PropertyList * list
std::string makeErrorMessage(std::string const &fileName="", int status=0, std::string const &msg="")
Return an error message reflecting FITS I/O errors.
RAII scoped guard for moving the HDU in a Fits object.
ImageScalingOptions::ScalingAlgorithm scalingAlgorithmFromString(std::string const &name)
Interpret scaling algorithm expressed in string.
std::string const wcsNameForXY0
void writeTableScalar(std::size_t row, int col, T value)
Write a scalar value to a binary table.
void readMetadata(daf::base::PropertySet &metadata, bool strip=false)
Read a FITS header into a PropertySet or PropertyList.
std::string makeLimitedFitsHeader(lsst::daf::base::PropertySet const &metadata, std::set< std::string > const &excludeNames={})
Format a PropertySet into an FITS header string in a simplistic fashion.
Reports errors that are due to events beyond the control of the program.
const int DEFAULT_HDU
Specify that the default HDU should be read.
std::shared_ptr< detail::PixelArrayBase > toFits(ndarray::Array< T const, 2, 2 > const &image, bool forceNonfiniteRemoval, bool fuzz=true, ndarray::Array< long, 1 > const &tiles=ndarray::Array< long, 1, 1 >(), int seed=1) const
Convert to an array of pixel values to write to FITS.
ImageWriteOptions(image::Image< T > const &image)
Construct with default options for images.
int countHdus()
Return the number of HDUs in the file.