28 #ifndef DOXYGEN // Doxygen doesn't like includes inside namespaces
34 using namespace posix;
43 #include "boost/any.hpp"
51 #define FITS_SIZE 2880
57 : keyword(
name), value(
val), comment(commnt) {}
59 : keyword(
name), value(
val), comment(commnt) {}
61 : keyword(
name), value(
val), comment(commnt) {}
63 : keyword(
name), value(
val), comment(commnt) {}
65 : keyword(
name), value(
val), comment(commnt) {}
71 int write(
int fd,
int ncard,
char *record)
const;
81 int Card::write(
int fd,
int ncard,
char *record)
const {
82 char *card = &record[80 * ncard];
85 const char *str = boost::any_cast<std::string>(value).c_str();
86 if (keyword ==
"" || keyword ==
"COMMENT" || keyword ==
"END" || keyword ==
"HISTORY") {
87 sprintf(card,
"%-8.8s%-72s", keyword.c_str(), str);
89 sprintf(card,
"%-8.8s= '%s' %c%-*s", keyword.c_str(), str, (comment ==
"" ?
' ' :
'/'),
90 (
int)(80 - 14 -
strlen(str)), comment.c_str());
93 sprintf(card,
"%-8.8s= ", keyword.c_str());
95 if (value.type() ==
typeid(
bool)) {
96 sprintf(card,
"%20s", boost::any_cast<bool>(value) ?
"T" :
"F");
97 }
else if (value.type() ==
typeid(
int)) {
98 sprintf(card,
"%20d", boost::any_cast<int>(value));
99 }
else if (value.type() ==
typeid(
double)) {
100 sprintf(card,
"%20.10f", boost::any_cast<double>(value));
101 }
else if (value.type() ==
typeid(
float)) {
102 sprintf(card,
"%20.7f", boost::any_cast<float>(value));
105 sprintf(card,
" %c%-48s", (comment ==
"" ?
' ' :
'/'), comment.c_str());
127 void flip_high_bit(
char *arr,
131 (
boost::format(
"Attempt to bit flip odd number of bytes: %d") % n).str());
134 unsigned short *uarr =
reinterpret_cast<unsigned short *
>(arr);
135 for (
unsigned short *
end = uarr + n / 2; uarr <
end; ++uarr) {
145 void swap_2(
char *arr,
149 (
boost::format(
"Attempt to byte swap odd number of bytes: %d") % n).str());
152 for (
char *
end = arr + n; arr <
end; arr += 2) {
161 void swap_4(
char *arr,
165 (
boost::format(
"Attempt to byte swap non-multiple of 4 bytes: %d") % n).str());
168 for (
char *
end = arr + n; arr <
end; arr += 4) {
181 void swap_8(
char *arr,
185 (
boost::format(
"Attempt to byte swap non-multiple of 8 bytes: %d") % n).str());
188 for (
char *
end = arr + n; arr <
end; arr += 8) {
204 int write_fits_hdr(
int fd,
int bitpix,
int naxis,
int *naxes,
std::list<Card> &cards,
212 Card card(
"SIMPLE",
true);
213 ncard = card.write(fd, ncard, record);
215 Card card(
"XTENSION",
"IMAGE");
216 ncard = card.write(fd, ncard, record);
220 Card card(
"BITPIX", bitpix);
221 ncard = card.write(fd, ncard, record);
224 Card card(
"NAXIS", naxis);
225 ncard = card.write(fd, ncard, record);
227 for (i = 0; i < naxis; i++) {
228 char key[] =
"NAXIS.";
230 Card card(
key, naxes[i]);
231 ncard = card.write(fd, ncard, record);
234 Card card(
"EXTEND",
true,
"There may be extensions");
235 ncard = card.write(fd, ncard, record);
241 ncard = card->write(fd, ncard, record);
245 Card card(
"END",
"");
246 ncard = card.write(fd, ncard, record);
250 ncard = card.write(fd, ncard, record);
259 void pad_to_fits_record(
int fd,
263 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix) / 8;
264 int nbyte = npixel * bytes_per_pixel;
270 memset(record,
' ', nbyte);
271 if (
write(fd, record, nbyte) != nbyte) {
273 "error padding file to multiple of fits block size");
278 int write_fits_data(
int fd,
int bitpix,
char *begin,
char *
end) {
279 const int bytes_per_pixel = (bitpix > 0 ? bitpix : -bitpix) / 8;
281 #if defined(LSST_LITTLE_ENDIAN) // we'll need to byte swap FITS
282 if (bytes_per_pixel > 1) {
288 bool allocated =
false;
289 if (swap_bytes || bitpix == 16) {
290 buff =
new char[
FITS_SIZE * bytes_per_pixel];
296 for (
char *
ptr = begin;
ptr !=
end; nbyte -= nwrite,
ptr += nwrite) {
304 flip_high_bit(buff, nwrite);
307 if (bytes_per_pixel == 2) {
308 swap_2(buff, nwrite);
309 }
else if (bytes_per_pixel == 4) {
310 swap_4(buff, nwrite);
311 }
else if (bytes_per_pixel == 8) {
312 swap_8(buff, nwrite);
314 fprintf(stderr,
"You cannot get here\n");
320 flip_high_bit(buff, nwrite);
326 if (
write(fd, buff, nwrite) != nwrite) {
327 perror(
"Error writing image: ");
337 return (nbyte == 0 ? 0 : -1);
344 x0,
"(output) Column pixel of Reference Pixel"));
346 y0,
"(output) Row pixel of Reference Pixel"));
348 "Column Pixel Coordinate of Reference"));
350 "Row Pixel Coordinate of Reference"));
362 template <
typename ImageT>
365 geom::SkyWcs
const *Wcs,
375 int bitpix = lsst::afw::fits::getBitPix<typename ImageT::Pixel>();
377 cards.
push_back(Card(
"BZERO", 32768.0,
""));
378 cards.
push_back(Card(
"BSCALE", 1.0,
""));
380 }
else if (bitpix == 0) {
386 addWcs(
"A", cards,
data.getX0(),
data.getY0());
393 cards.
push_back(Card(
"OBJECT", title,
"Image being displayed"));
404 auto newWcs = Wcs->copyAtShiftedPixelOrigin(shift);
410 for (NameList::const_iterator i = paramNames.begin(),
end = paramNames.end(); i !=
end; ++i) {
411 if (*i ==
"SIMPLE" || *i ==
"BITPIX" || *i ==
"NAXIS" || *i ==
"NAXIS1" || *i ==
"NAXIS2" ||
412 *i ==
"XTENSION" || *i ==
"PCOUNT" || *i ==
"GCOUNT") {
416 if (
type ==
typeid(
bool)) {
418 }
else if (
type ==
typeid(
int)) {
420 }
else if (
type ==
typeid(
float)) {
422 }
else if (
type ==
typeid(
double)) {
434 naxes[0] =
data.getWidth();
435 naxes[1] =
data.getHeight();
437 write_fits_hdr(fd, bitpix, naxis, naxes, cards, 1);
438 for (
int y = 0;
y !=
data.getHeight(); ++
y) {
439 if (write_fits_data(fd, bitpix, (
char *)(
data.row_begin(
y)), (
char *)(
data.row_end(
y))) < 0) {
445 pad_to_fits_record(fd,
data.getWidth() *
data.getHeight(), bitpix);
448 template <
typename ImageT>
451 geom::SkyWcs
const *Wcs,
455 if ((filename.
c_str())[0] ==
'|') {
456 const char *
cmd = filename.
c_str() + 1;
457 while (isspace(*
cmd)) {
461 fd = fileno(popen(
cmd,
"w"));
463 fd = creat(filename.
c_str(), 777);
482 #define INSTANTIATE(IMAGET) \
483 template void writeBasicFits(int, IMAGET const &, geom::SkyWcs const *, char const *); \
484 template void writeBasicFits(std::string const &, IMAGET const &, geom::SkyWcs const *, char const *)
486 #define INSTANTIATE_IMAGE(T) INSTANTIATE(lsst::afw::image::Image<T>)
487 #define INSTANTIATE_MASK(T) INSTANTIATE(lsst::afw::image::Mask<T>)