29 #ifndef DOXYGEN // Doxygen doesn't like includes inside namespaces
35 using namespace posix;
44 #include "boost/any.hpp"
52 #define FITS_SIZE 2880
57 Card(
const std::string &
name,
bool val,
const char *commnt =
""
58 ) : keyword(name), value(val), comment(commnt) { }
59 Card(
const std::string &name,
int val,
const char *commnt =
""
60 ) : keyword(name), value(val), comment(commnt) { }
61 Card(
const std::string &name,
double val,
const char *commnt =
""
62 ) : keyword(name), value(val), comment(commnt) { }
63 Card(
const std::string &name,
float val,
const char *commnt =
""
64 ) : keyword(name), value(val), comment(commnt) { }
65 Card(
const std::string &name,
const std::string &val,
const char *commnt =
""
66 ) : keyword(name), value(val), comment(commnt) { }
67 Card(
const std::string &name,
const char *val,
const char *commnt =
""
68 ) : keyword(name), value(std::string(val)), comment(commnt) { }
72 int write(
int fd,
int ncard,
char *record)
const;
83 int Card::write(
int fd,
87 char *card = &record[80*ncard];
89 if (value.type() ==
typeid(std::string)) {
90 const char *str = boost::any_cast<std::string>(value).c_str();
92 keyword ==
"COMMENT" || keyword ==
"END" || keyword ==
"HISTORY") {
93 sprintf(card,
"%-8.8s%-72s", keyword.c_str(), str);
95 sprintf(card,
"%-8.8s= '%s' %c%-*s",
97 (comment ==
"" ?
' ' :
'/'),
98 (
int)(80 - 14 - strlen(str)), comment.c_str());
101 sprintf(card,
"%-8.8s= ", keyword.c_str());
103 if (value.type() ==
typeid(bool)) {
104 sprintf(card,
"%20s", boost::any_cast<bool>(value) ?
"T" :
"F");
105 }
else if (value.type() ==
typeid(int)) {
106 sprintf(card,
"%20d", boost::any_cast<int>(value));
107 }
else if (value.type() ==
typeid(double)) {
108 sprintf(card,
"%20.10f", boost::any_cast<double>(value));
109 }
else if (value.type() ==
typeid(float)) {
110 sprintf(card,
"%20.7f", boost::any_cast<float>(value));
113 sprintf(card,
" %c%-48s", (comment ==
"" ?
' ' :
'/'), comment.c_str());
120 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
"Cannot write header record");
136 void flip_high_bit(
char *arr,
139 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
140 (
boost::format(
"Attempt to bit flip odd number of bytes: %d") % n).str());
143 unsigned short* uarr =
reinterpret_cast<unsigned short *
>(arr);
144 for(
unsigned short *end = uarr + n/2; uarr < end; ++uarr) {
154 void swap_2(
char *arr,
157 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
158 (
boost::format(
"Attempt to byte swap odd number of bytes: %d") % n).str());
161 for(
char *end = arr + n;arr < end;arr += 2) {
170 void swap_4(
char *arr,
173 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
174 (
boost::format(
"Attempt to byte swap non-multiple of 4 bytes: %d") % n).str());
177 for(
char *end = arr + n;arr < end;arr += 4) {
190 void swap_8(
char *arr,
193 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
194 (
boost::format(
"Attempt to byte swap non-multiple of 8 bytes: %d") % n).str());
197 for(
char *end = arr + n;arr < end;arr += 8) {
215 int write_fits_hdr(
int fd,
219 std::list<Card>& cards,
227 Card card(
"SIMPLE",
true);
228 ncard = card.write(fd, ncard, record);
230 Card card(
"XTENSION",
"IMAGE");
231 ncard = card.write(fd, ncard, record);
235 Card card(
"BITPIX", bitpix);
236 ncard = card.write(fd, ncard, record);
239 Card card(
"NAXIS", naxis);
240 ncard = card.write(fd, ncard, record);
242 for(i = 0; i < naxis; i++) {
243 char key[] =
"NAXIS.";
244 sprintf(key,
"NAXIS%d", i + 1);
245 Card card(key, naxes[i]);
246 ncard = card.write(fd, ncard, record);
249 Card card(
"EXTEND",
true,
"There may be extensions");
250 ncard = card.write(fd,ncard,record);
255 for (std::list<Card>::const_iterator card = cards.begin(); card != cards.end(); card++) {
256 ncard = card->write(fd,ncard,record);
260 Card card(
"END",
"");
261 ncard = card.write(fd,ncard,record);
265 ncard = card.write(fd,ncard,record);
274 void pad_to_fits_record(
int fd,
278 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix)/8;
279 int nbyte = npixel*bytes_per_pixel;
285 memset(record,
' ', nbyte);
286 if (write(fd, record, nbyte) != nbyte) {
287 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
288 "error padding file to multiple of fits block size");
293 int write_fits_data(
int fd,
298 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix)/8;
300 #if defined(LSST_LITTLE_ENDIAN) // we'll need to byte swap FITS
301 if (bytes_per_pixel > 1) {
307 bool allocated =
false;
308 if (swap_bytes || bitpix == 16) {
309 buff =
new char[
FITS_SIZE*bytes_per_pixel];
313 int nbyte = end - begin;
315 for (
char *ptr = begin; ptr != end; nbyte -= nwrite, ptr += nwrite) {
316 if (end - ptr < nwrite) {
321 memcpy(buff, ptr, nwrite);
323 flip_high_bit(buff, nwrite);
326 if (bytes_per_pixel == 2) {
327 swap_2(buff, nwrite);
328 }
else if (bytes_per_pixel == 4) {
329 swap_4(buff, nwrite);
330 }
else if (bytes_per_pixel == 8) {
331 swap_8(buff, nwrite);
333 fprintf(stderr,
"You cannot get here\n");
338 memcpy(buff, ptr, nwrite);
339 flip_high_bit(buff, nwrite);
345 if (write(fd, buff, nwrite) != nwrite) {
346 perror(
"Error writing image: ");
355 return (nbyte == 0 ? 0 : -1);
359 namespace lsst {
namespace afw {
namespace display {
361 template<
typename ImageT>
370 std::list<Card> cards;
374 int bitpix = lsst::afw::fits::getBitPix<typename ImageT::Pixel>();
376 cards.push_back(Card(
"BZERO", 32768.0,
""));
377 cards.push_back(Card(
"BSCALE", 1.0,
""));
379 }
else if (bitpix == 0) {
380 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
"Unsupported image type");
385 std::string wcsName =
"A";
386 cards.push_back(Card(str(
boost::format(
"CRVAL1%s") % wcsName),
387 data.getX0(),
"(output) Column pixel of Reference Pixel"));
388 cards.push_back(Card(str(
boost::format(
"CRVAL2%s") % wcsName),
389 data.getY0(),
"(output) Row pixel of Reference Pixel"));
390 cards.push_back(Card(str(
boost::format(
"CRPIX1%s") % wcsName), 1.0,
391 "Column Pixel Coordinate of Reference"));
392 cards.push_back(Card(str(
boost::format(
"CRPIX2%s") % wcsName), 1.0,
"Row Pixel Coordinate of Reference"));
393 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
394 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
395 cards.push_back(Card(str(
boost::format(
"CUNIT1%s") % wcsName),
"PIXEL",
"Column unit"));
396 cards.push_back(Card(str(
boost::format(
"CUNIT2%s") % wcsName),
"PIXEL",
"Row unit"));
401 cards.push_back(Card(str(
boost::format(
"CRVAL1%s") % wcsName), 0,
402 "(output) Column pixel of Reference Pixel"));
403 cards.push_back(Card(str(
boost::format(
"CRVAL2%s") % wcsName), 0,
404 "(output) Row pixel of Reference Pixel"));
405 cards.push_back(Card(str(
boost::format(
"CRPIX1%s") % wcsName), 1.0,
406 "Column Pixel Coordinate of Reference"));
407 cards.push_back(Card(str(
boost::format(
"CRPIX2%s") % wcsName), 1.0,
"Row Pixel Coordinate of Reference"));
408 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
409 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
410 cards.push_back(Card(str(
boost::format(
"CUNIT1%s") % wcsName),
"PIXEL",
"Column unit"));
411 cards.push_back(Card(str(
boost::format(
"CUNIT2%s") % wcsName),
"PIXEL",
"Row unit"));
414 cards.push_back(Card(
"OBJECT", title,
"Image being displayed"));
420 typedef std::vector<std::string> NameList;
423 newWcs->shiftReferencePixel(-data.getX0(), -data.getY0());
427 NameList paramNames = metadata->paramNames();
429 for (NameList::const_iterator i = paramNames.begin(), end = paramNames.end(); i != end; ++i) {
430 if (*i ==
"SIMPLE" ||
441 std::type_info
const &type = metadata->typeOf(*i);
442 if (type ==
typeid(
bool)) {
443 cards.push_back(Card(*i, metadata->get<
bool>(*i)));
444 }
else if (type ==
typeid(
int)) {
445 cards.push_back(Card(*i, metadata->get<
int>(*i)));
446 }
else if (type ==
typeid(
float)) {
447 cards.push_back(Card(*i, metadata->get<
float>(*i)));
448 }
else if (type ==
typeid(
double)) {
449 cards.push_back(Card(*i, metadata->get<
double>(*i)));
451 cards.push_back(Card(*i, metadata->get<std::string>(*i)));
460 naxes[0] = data.getWidth();
461 naxes[1] = data.getHeight();
463 write_fits_hdr(fd, bitpix, naxis, naxes, cards, 1);
464 for (
int y = 0;
y != data.getHeight(); ++
y) {
465 if (write_fits_data(fd, bitpix, (
char *)(data.row_begin(
y)), (
char *)(data.row_end(
y))) < 0){
466 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
471 pad_to_fits_record(fd, data.getWidth()*data.getHeight(), bitpix);
476 template<
typename ImageT>
483 if ((filename.c_str())[0] ==
'|') {
484 const char *cmd = filename.c_str() + 1;
485 while (isspace(*cmd)) {
489 fd = fileno(popen(cmd,
"w"));
491 fd = creat(filename.c_str(), 777);
495 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
510 #define INSTANTIATE(IMAGET) \
511 template void writeBasicFits(int, IMAGET const&, image::Wcs const *, char const *); \
512 template void writeBasicFits(std::string const&, IMAGET const&, image::Wcs const *, char const *)
514 #define INSTANTIATE_IMAGE(T) INSTANTIATE(lsst::afw::image::Image<T>)
515 #define INSTANTIATE_MASK(T) INSTANTIATE(lsst::afw::image::Mask<T>)
523 INSTANTIATE_MASK(std::uint16_t);
table::Key< std::string > name
void writeBasicFits(int fd, ImageT const &data, image::Wcs const *Wcs, char const *title)
Include files required for standard LSST Exception handling.
Definitions to write a FITS image.
#define INSTANTIATE_IMAGE(IMAGE)
Implementation of the WCS standard for a any projection.
virtual Ptr clone(void) const
std::shared_ptr< Wcs > Ptr
table::Key< table::Array< Kernel::Pixel > > image
lsst::daf::base::PropertySet PropertySet
bool any(CoordinateExpr< N > const &expr)
Return true if any elements are true.
metadata import lsst afw display as afwDisplay n
Utilities for working with FITS files.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
std::shared_ptr< PropertySet > Ptr