35 using namespace posix;
44 #include "boost/any.hpp"
52 #define FITS_SIZE 2880
58 : keyword(
name), value(
val), comment(commnt) {}
60 : keyword(
name), value(
val), comment(commnt) {}
62 : keyword(
name), value(
val), comment(commnt) {}
64 : keyword(
name), value(
val), comment(commnt) {}
66 : keyword(
name), value(
val), comment(commnt) {}
72 int write(
int fd,
int ncard,
char *record)
const;
82 int Card::write(
int fd,
int ncard,
char *record)
const {
83 char *card = &record[80 * ncard];
86 const char *str = boost::any_cast<std::string>(value).c_str();
87 if (keyword ==
"" || keyword ==
"COMMENT" || keyword ==
"END" || keyword ==
"HISTORY") {
88 sprintf(card,
"%-8.8s%-72s", keyword.c_str(), str);
90 sprintf(card,
"%-8.8s= '%s' %c%-*s", keyword.c_str(), str, (comment ==
"" ?
' ' :
'/'),
91 (
int)(80 - 14 -
strlen(str)), comment.c_str());
94 sprintf(card,
"%-8.8s= ", keyword.c_str());
96 if (value.type() ==
typeid(
bool)) {
97 sprintf(card,
"%20s", boost::any_cast<bool>(value) ?
"T" :
"F");
98 }
else if (value.type() ==
typeid(
int)) {
99 sprintf(card,
"%20d", boost::any_cast<int>(value));
100 }
else if (value.type() ==
typeid(
double)) {
101 sprintf(card,
"%20.10f", boost::any_cast<double>(value));
102 }
else if (value.type() ==
typeid(
float)) {
103 sprintf(card,
"%20.7f", boost::any_cast<float>(value));
106 sprintf(card,
" %c%-48s", (comment ==
"" ?
' ' :
'/'), comment.c_str());
128 void flip_high_bit(
char *arr,
132 (
boost::format(
"Attempt to bit flip odd number of bytes: %d") % n).str());
135 unsigned short *uarr =
reinterpret_cast<unsigned short *
>(arr);
136 for (
unsigned short *
end = uarr + n / 2; uarr <
end; ++uarr) {
146 void swap_2(
char *arr,
150 (
boost::format(
"Attempt to byte swap odd number of bytes: %d") % n).str());
153 for (
char *
end = arr + n; arr <
end; arr += 2) {
162 void swap_4(
char *arr,
166 (
boost::format(
"Attempt to byte swap non-multiple of 4 bytes: %d") % n).str());
169 for (
char *
end = arr + n; arr <
end; arr += 4) {
182 void swap_8(
char *arr,
186 (
boost::format(
"Attempt to byte swap non-multiple of 8 bytes: %d") % n).str());
189 for (
char *
end = arr + n; arr <
end; arr += 8) {
205 int write_fits_hdr(
int fd,
int bitpix,
int naxis,
int *naxes,
std::list<Card> &cards,
213 Card card(
"SIMPLE",
true);
214 ncard = card.write(fd, ncard, record);
216 Card card(
"XTENSION",
"IMAGE");
217 ncard = card.write(fd, ncard, record);
221 Card card(
"BITPIX", bitpix);
222 ncard = card.write(fd, ncard, record);
225 Card card(
"NAXIS", naxis);
226 ncard = card.write(fd, ncard, record);
228 for (i = 0; i < naxis; i++) {
229 char key[] =
"NAXIS.";
231 Card card(
key, naxes[i]);
232 ncard = card.write(fd, ncard, record);
235 Card card(
"EXTEND",
true,
"There may be extensions");
236 ncard = card.write(fd, ncard, record);
242 ncard = card->write(fd, ncard, record);
246 Card card(
"END",
"");
247 ncard = card.write(fd, ncard, record);
251 ncard = card.write(fd, ncard, record);
260 void pad_to_fits_record(
int fd,
264 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix) / 8;
265 int nbyte = npixel * bytes_per_pixel;
271 memset(record,
' ', nbyte);
272 if (
write(fd, record, nbyte) != nbyte) {
274 "error padding file to multiple of fits block size");
279 int write_fits_data(
int fd,
int bitpix,
char *begin,
char *
end) {
280 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix) / 8;
282 #if defined(LSST_LITTLE_ENDIAN)
283 if (bytes_per_pixel > 1) {
289 bool allocated =
false;
290 if (swap_bytes || bitpix == 16) {
291 buff =
new char[
FITS_SIZE * bytes_per_pixel];
297 for (
char *
ptr = begin;
ptr !=
end; nbyte -= nwrite,
ptr += nwrite) {
305 flip_high_bit(buff, nwrite);
308 if (bytes_per_pixel == 2) {
309 swap_2(buff, nwrite);
310 }
else if (bytes_per_pixel == 4) {
311 swap_4(buff, nwrite);
312 }
else if (bytes_per_pixel == 8) {
313 swap_8(buff, nwrite);
315 fprintf(stderr,
"You cannot get here\n");
321 flip_high_bit(buff, nwrite);
327 if (
write(fd, buff, nwrite) != nwrite) {
328 perror(
"Error writing image: ");
337 return (nbyte == 0 ? 0 : -1);
342 Card(str(
boost::format(
"CRVAL1%s") % wcsName), x0,
"(output) Column pixel of Reference Pixel"));
344 Card(str(
boost::format(
"CRVAL2%s") % wcsName), y0,
"(output) Row pixel of Reference Pixel"));
346 Card(str(
boost::format(
"CRPIX1%s") % wcsName), 1.0,
"Column Pixel Coordinate of Reference"));
347 cards.
push_back(Card(str(
boost::format(
"CRPIX2%s") % wcsName), 1.0,
"Row Pixel Coordinate of Reference"));
359 template <
typename ImageT>
362 geom::SkyWcs
const *Wcs,
372 int bitpix = lsst::afw::fits::getBitPix<typename ImageT::Pixel>();
374 cards.
push_back(Card(
"BZERO", 32768.0,
""));
375 cards.
push_back(Card(
"BSCALE", 1.0,
""));
377 }
else if (bitpix == 0) {
383 addWcs(
"A", cards,
data.getX0(),
data.getY0());
390 cards.
push_back(Card(
"OBJECT", title,
"Image being displayed"));
401 auto newWcs = Wcs->copyAtShiftedPixelOrigin(shift);
407 for (NameList::const_iterator i = paramNames.begin(),
end = paramNames.end(); i !=
end; ++i) {
408 if (*i ==
"SIMPLE" || *i ==
"BITPIX" || *i ==
"NAXIS" || *i ==
"NAXIS1" || *i ==
"NAXIS2" ||
409 *i ==
"XTENSION" || *i ==
"PCOUNT" || *i ==
"GCOUNT") {
413 if (
type ==
typeid(
bool)) {
415 }
else if (
type ==
typeid(
int)) {
417 }
else if (
type ==
typeid(
float)) {
419 }
else if (
type ==
typeid(
double)) {
431 naxes[0] =
data.getWidth();
432 naxes[1] =
data.getHeight();
434 write_fits_hdr(fd, bitpix, naxis, naxes, cards, 1);
435 for (
int y = 0;
y !=
data.getHeight(); ++
y) {
436 if (write_fits_data(fd, bitpix, (
char *)(
data.row_begin(
y)), (
char *)(
data.row_end(
y))) < 0) {
442 pad_to_fits_record(fd,
data.getWidth() *
data.getHeight(), bitpix);
445 template <
typename ImageT>
448 geom::SkyWcs
const *Wcs,
452 if ((filename.
c_str())[0] ==
'|') {
453 const char *cmd = filename.
c_str() + 1;
454 while (isspace(*cmd)) {
458 fd = fileno(popen(cmd,
"w"));
460 fd = creat(filename.
c_str(), 777);
479 #define INSTANTIATE(IMAGET) \
480 template void writeBasicFits(int, IMAGET const &, geom::SkyWcs const *, char const *); \
481 template void writeBasicFits(std::string const &, IMAGET const &, geom::SkyWcs const *, char const *)
483 #define INSTANTIATE_IMAGE(T) INSTANTIATE(lsst::afw::image::Image<T>)
484 #define INSTANTIATE_MASK(T) INSTANTIATE(lsst::afw::image::Mask<T>)
table::Key< std::string > name
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Class for storing generic metadata.
std::vector< std::string > paramNames(bool topLevelOnly=true) const
A variant of names that excludes the names of subproperties.
std::type_info const & typeOf(std::string const &name) const
Get the type of values for a property name (possibly hierarchical).
T get(std::string const &name) const
Get the last value for a property name (possibly hierarchical).
Provides consistent interface for LSST exceptions.
Reports errors that are due to events beyond the control of the program.
#define INSTANTIATE_IMAGE(IMAGE)
void writeBasicFits(std::string const &filename, ImageT const &data, geom::SkyWcs const *Wcs, char const *title)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
void write(OutputArchiveHandle &handle) const override
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
Extent< double, 2 > Extent2D
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
A base class for image defects.