29 #ifndef DOXYGEN // Doxygen doesn't like includes inside namespaces
35 using namespace posix;
43 #include "boost/any.hpp"
51 #define FITS_SIZE 2880
56 Card(
const std::string &
name,
bool val,
const char *commnt =
""
57 ) : keyword(name), value(val), comment(commnt) { }
58 Card(
const std::string &name,
int val,
const char *commnt =
""
59 ) : keyword(name), value(val), comment(commnt) { }
60 Card(
const std::string &name,
double val,
const char *commnt =
""
61 ) : keyword(name), value(val), comment(commnt) { }
62 Card(
const std::string &name,
float val,
const char *commnt =
""
63 ) : keyword(name), value(val), comment(commnt) { }
64 Card(
const std::string &name,
const std::string &val,
const char *commnt =
""
65 ) : keyword(name), value(val), comment(commnt) { }
66 Card(
const std::string &name,
const char *val,
const char *commnt =
""
67 ) : keyword(name), value(std::string(val)), comment(commnt) { }
71 int write(
int fd,
int ncard,
char *record)
const;
82 int Card::write(
int fd,
86 char *card = &record[80*ncard];
88 if (value.type() ==
typeid(std::string)) {
89 const char *str = boost::any_cast<std::string>(value).c_str();
91 keyword ==
"COMMENT" || keyword ==
"END" || keyword ==
"HISTORY") {
92 sprintf(card,
"%-8.8s%-72s", keyword.c_str(), str);
94 sprintf(card,
"%-8.8s= '%s' %c%-*s",
96 (comment ==
"" ?
' ' :
'/'),
97 (
int)(80 - 14 - strlen(str)), comment.c_str());
100 sprintf(card,
"%-8.8s= ", keyword.c_str());
102 if (value.type() ==
typeid(bool)) {
103 sprintf(card,
"%20s", boost::any_cast<bool>(value) ?
"T" :
"F");
104 }
else if (value.type() ==
typeid(int)) {
105 sprintf(card,
"%20d", boost::any_cast<int>(value));
106 }
else if (value.type() ==
typeid(double)) {
107 sprintf(card,
"%20.10f", boost::any_cast<double>(value));
108 }
else if (value.type() ==
typeid(float)) {
109 sprintf(card,
"%20.7f", boost::any_cast<float>(value));
112 sprintf(card,
" %c%-48s", (comment ==
"" ?
' ' :
'/'), comment.c_str());
119 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
"Cannot write header record");
135 void flip_high_bit(
char *arr,
138 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
139 (
boost::format(
"Attempt to bit flip odd number of bytes: %d") % n).str());
142 unsigned short* uarr =
reinterpret_cast<unsigned short *
>(arr);
143 for(
unsigned short *end = uarr + n/2; uarr < end; ++uarr) {
153 void swap_2(
char *arr,
156 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
157 (
boost::format(
"Attempt to byte swap odd number of bytes: %d") % n).str());
160 for(
char *end = arr + n;arr < end;arr += 2) {
169 void swap_4(
char *arr,
172 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
173 (
boost::format(
"Attempt to byte swap non-multiple of 4 bytes: %d") % n).str());
176 for(
char *end = arr + n;arr < end;arr += 4) {
189 void swap_8(
char *arr,
192 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
193 (
boost::format(
"Attempt to byte swap non-multiple of 8 bytes: %d") % n).str());
196 for(
char *end = arr + n;arr < end;arr += 8) {
214 int write_fits_hdr(
int fd,
218 std::list<Card>& cards,
226 Card card(
"SIMPLE",
true);
227 ncard = card.write(fd, ncard, record);
229 Card card(
"XTENSION",
"IMAGE");
230 ncard = card.write(fd, ncard, record);
234 Card card(
"BITPIX", bitpix);
235 ncard = card.write(fd, ncard, record);
238 Card card(
"NAXIS", naxis);
239 ncard = card.write(fd, ncard, record);
241 for(i = 0; i < naxis; i++) {
242 char key[] =
"NAXIS.";
243 sprintf(key,
"NAXIS%d", i + 1);
244 Card card(key, naxes[i]);
245 ncard = card.write(fd, ncard, record);
248 Card card(
"EXTEND",
true,
"There may be extensions");
249 ncard = card.write(fd,ncard,record);
254 for (std::list<Card>::const_iterator card = cards.begin(); card != cards.end(); card++) {
255 ncard = card->write(fd,ncard,record);
259 Card card(
"END",
"");
260 ncard = card.write(fd,ncard,record);
264 ncard = card.write(fd,ncard,record);
273 void pad_to_fits_record(
int fd,
277 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix)/8;
278 int nbyte = npixel*bytes_per_pixel;
284 memset(record,
' ', nbyte);
285 if (write(fd, record, nbyte) != nbyte) {
286 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
287 "error padding file to multiple of fits block size");
292 int write_fits_data(
int fd,
297 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix)/8;
299 #if defined(LSST_LITTLE_ENDIAN) // we'll need to byte swap FITS
300 if (bytes_per_pixel > 1) {
306 bool allocated =
false;
307 if (swap_bytes || bitpix == 16) {
308 buff =
new char[
FITS_SIZE*bytes_per_pixel];
312 int nbyte = end - begin;
314 for (
char *ptr = begin; ptr != end; nbyte -= nwrite, ptr += nwrite) {
315 if (end - ptr < nwrite) {
320 memcpy(buff, ptr, nwrite);
322 flip_high_bit(buff, nwrite);
325 if (bytes_per_pixel == 2) {
326 swap_2(buff, nwrite);
327 }
else if (bytes_per_pixel == 4) {
328 swap_4(buff, nwrite);
329 }
else if (bytes_per_pixel == 8) {
330 swap_8(buff, nwrite);
332 fprintf(stderr,
"You cannot get here\n");
337 memcpy(buff, ptr, nwrite);
338 flip_high_bit(buff, nwrite);
344 if (write(fd, buff, nwrite) != nwrite) {
345 perror(
"Error writing image: ");
354 return (nbyte == 0 ? 0 : -1);
358 namespace lsst {
namespace afw {
namespace display {
360 template<
typename ImageT>
369 std::list<Card> cards;
373 int bitpix = lsst::afw::fits::getBitPix<typename ImageT::Pixel>();
375 cards.push_back(Card(
"BZERO", 32768.0,
""));
376 cards.push_back(Card(
"BSCALE", 1.0,
""));
378 }
else if (bitpix == 0) {
379 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
"Unsupported image type");
384 std::string wcsName =
"A";
385 cards.push_back(Card(str(
boost::format(
"CRVAL1%s") % wcsName),
386 data.getX0(),
"(output) Column pixel of Reference Pixel"));
387 cards.push_back(Card(str(
boost::format(
"CRVAL2%s") % wcsName),
388 data.getY0(),
"(output) Row pixel of Reference Pixel"));
389 cards.push_back(Card(str(
boost::format(
"CRPIX1%s") % wcsName), 1.0,
390 "Column Pixel Coordinate of Reference"));
391 cards.push_back(Card(str(
boost::format(
"CRPIX2%s") % wcsName), 1.0,
"Row Pixel Coordinate of Reference"));
392 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
393 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
394 cards.push_back(Card(str(
boost::format(
"CUNIT1%s") % wcsName),
"PIXEL",
"Column unit"));
395 cards.push_back(Card(str(
boost::format(
"CUNIT2%s") % wcsName),
"PIXEL",
"Row unit"));
400 cards.push_back(Card(str(
boost::format(
"CRVAL1%s") % wcsName), 0,
401 "(output) Column pixel of Reference Pixel"));
402 cards.push_back(Card(str(
boost::format(
"CRVAL2%s") % wcsName), 0,
403 "(output) Row pixel of Reference Pixel"));
404 cards.push_back(Card(str(
boost::format(
"CRPIX1%s") % wcsName), 1.0,
405 "Column Pixel Coordinate of Reference"));
406 cards.push_back(Card(str(
boost::format(
"CRPIX2%s") % wcsName), 1.0,
"Row Pixel Coordinate of Reference"));
407 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
408 cards.push_back(Card(str(
boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection"));
409 cards.push_back(Card(str(
boost::format(
"CUNIT1%s") % wcsName),
"PIXEL",
"Column unit"));
410 cards.push_back(Card(str(
boost::format(
"CUNIT2%s") % wcsName),
"PIXEL",
"Row unit"));
413 cards.push_back(Card(
"OBJECT", title,
"Image being displayed"));
419 typedef std::vector<std::string> NameList;
422 newWcs->shiftReferencePixel(-data.getX0(), -data.getY0());
426 NameList paramNames = metadata->paramNames();
428 for (NameList::const_iterator i = paramNames.begin(), end = paramNames.end(); i != end; ++i) {
429 if (*i ==
"SIMPLE" ||
440 std::type_info
const &type = metadata->typeOf(*i);
441 if (type ==
typeid(
bool)) {
442 cards.push_back(Card(*i, metadata->get<
bool>(*i)));
443 }
else if (type ==
typeid(
int)) {
444 cards.push_back(Card(*i, metadata->get<
int>(*i)));
445 }
else if (type ==
typeid(
float)) {
446 cards.push_back(Card(*i, metadata->get<
float>(*i)));
447 }
else if (type ==
typeid(
double)) {
448 cards.push_back(Card(*i, metadata->get<
double>(*i)));
450 cards.push_back(Card(*i, metadata->get<std::string>(*i)));
459 naxes[0] = data.getWidth();
460 naxes[1] = data.getHeight();
462 write_fits_hdr(fd, bitpix, naxis, naxes, cards, 1);
463 for (
int y = 0;
y != data.getHeight(); ++
y) {
464 if (write_fits_data(fd, bitpix, (
char *)(data.row_begin(
y)), (
char *)(data.row_end(
y))) < 0){
465 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
470 pad_to_fits_record(fd, data.getWidth()*data.getHeight(), bitpix);
475 template<
typename ImageT>
482 if ((filename.c_str())[0] ==
'|') {
483 const char *cmd = filename.c_str() + 1;
484 while (isspace(*cmd)) {
488 fd = fileno(popen(cmd,
"w"));
490 fd = creat(filename.c_str(), 777);
494 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
509 #define INSTANTIATE(IMAGET) \
510 template void writeBasicFits(int, IMAGET const&, image::Wcs const *, char const *); \
511 template void writeBasicFits(std::string const&, IMAGET const&, image::Wcs const *, char const *)
513 #define INSTANTIATE_IMAGE(T) INSTANTIATE(lsst::afw::image::Image<T>)
514 #define INSTANTIATE_MASK(T) INSTANTIATE(lsst::afw::image::Mask<T>)
522 INSTANTIATE_MASK(boost::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.
boost::shared_ptr< PropertySet > Ptr
virtual Ptr clone(void) const
Implementation of the WCS standard for a any projection.
#define INSTANTIATE_IMAGE(IMAGE)
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.
boost::shared_ptr< Wcs > Ptr
#define LSST_EXCEPT(type,...)