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;
81int Card::write(
int fd,
int ncard,
char *record)
const {
82 char *card = &record[80 * ncard];
86 if (keyword ==
"" || keyword ==
"COMMENT" || keyword ==
"END" || keyword ==
"HISTORY") {
87 sprintf(card,
"%-8.8s%-72s", keyword.c_str(),
str.c_str());
89 sprintf(card,
"%-8.8s= '%s' %c%-*s", keyword.c_str(),
str.c_str(), (comment ==
"" ?
' ' :
'/'),
90 (
int)(80 - 14 -
str.size()), comment.c_str());
93 sprintf(card,
"%-8.8s= ", keyword.c_str());
95 if (value.type() ==
typeid(
bool)) {
96 sprintf(card,
"%20s", std::any_cast<bool>(value) ?
"T" :
"F");
97 }
else if (value.type() ==
typeid(
int)) {
98 sprintf(card,
"%20d", std::any_cast<int>(value));
99 }
else if (value.type() ==
typeid(
double)) {
100 sprintf(card,
"%20.10f", std::any_cast<double>(value));
101 }
else if (value.type() ==
typeid(
float)) {
102 sprintf(card,
"%20.7f", std::any_cast<float>(value));
105 sprintf(card,
" %c%-48s", (comment ==
"" ?
' ' :
'/'), comment.c_str());
127void 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) {
145void 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) {
161void 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) {
181void 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) {
204int 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.";
229 sprintf(key,
"NAXIS%d", i + 1);
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);
259void 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");
278int 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)
282 if (bytes_per_pixel > 1) {
287 char *buff =
nullptr;
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: ");
336 return (nbyte == 0 ? 0 : -1);
340 cards.
emplace_back(
str(boost::format(
"CRVAL1%s") % wcsName), x0,
"(output) Column pixel of Reference Pixel");
341 cards.
emplace_back(
str(boost::format(
"CRVAL2%s") % wcsName), y0,
"(output) Row pixel of Reference Pixel");
342 cards.
emplace_back(
str(boost::format(
"CRPIX1%s") % wcsName), 1.0,
"Column Pixel Coordinate of Reference");
343 cards.
emplace_back(
str(boost::format(
"CRPIX2%s") % wcsName), 1.0,
"Row Pixel Coordinate of Reference");
344 cards.
emplace_back(
str(boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection");
345 cards.
emplace_back(
str(boost::format(
"CTYPE1%s") % wcsName),
"LINEAR",
"Type of projection");
346 cards.
emplace_back(
str(boost::format(
"CUNIT1%s") % wcsName),
"PIXEL",
"Column unit");
347 cards.
emplace_back(
str(boost::format(
"CUNIT2%s") % wcsName),
"PIXEL",
"Row unit");
355template <
typename ImageT>
358 geom::SkyWcs
const *Wcs,
368 int bitpix = lsst::afw::fits::getBitPix<typename ImageT::Pixel>();
373 }
else if (bitpix == 0) {
379 addWcs(
"A", cards,
data.getX0(),
data.getY0());
386 cards.
emplace_back(
"OBJECT", title,
"Image being displayed");
391 if (Wcs ==
nullptr) {
397 auto newWcs = Wcs->copyAtShiftedPixelOrigin(shift);
401 NameList paramNames = metadata->paramNames();
403 for (
auto const ¶mName : paramNames) {
404 if (paramName ==
"SIMPLE" || paramName ==
"BITPIX" || paramName ==
"NAXIS" || paramName ==
"NAXIS1" || paramName ==
"NAXIS2" ||
405 paramName ==
"XTENSION" || paramName ==
"PCOUNT" || paramName ==
"GCOUNT") {
409 if (
type ==
typeid(
bool)) {
411 }
else if (
type ==
typeid(
int)) {
413 }
else if (
type ==
typeid(
float)) {
415 }
else if (
type ==
typeid(
double)) {
427 naxes[0] =
data.getWidth();
428 naxes[1] =
data.getHeight();
430 write_fits_hdr(fd, bitpix, naxis, naxes, cards, 1);
431 for (
int y = 0;
y !=
data.getHeight(); ++
y) {
432 if (write_fits_data(fd, bitpix, (
char *)(
data.row_begin(
y)), (
char *)(
data.row_end(
y))) < 0) {
434 (boost::format(
"Error writing data for row %d") %
y).
str());
438 pad_to_fits_record(fd,
data.getWidth() *
data.getHeight(), bitpix);
441template <
typename ImageT>
444 geom::SkyWcs
const *Wcs,
448 if ((filename.
c_str())[0] ==
'|') {
449 const char *cmd = filename.
c_str() + 1;
450 while (isspace(*cmd)) {
454 fd = fileno(popen(cmd,
"w"));
456 fd = creat(filename.
c_str(), 777);
461 (boost::format(
"Cannot open \"%s\"") % filename).
str());
475#define INSTANTIATE(IMAGET) \
476 template void writeBasicFits(int, IMAGET const &, geom::SkyWcs const *, char const *); \
477 template void writeBasicFits(std::string const &, IMAGET const &, geom::SkyWcs const *, char const *)
479#define INSTANTIATE_IMAGE(T) INSTANTIATE(lsst::afw::image::Image<T>)
480#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.
Provides consistent interface for LSST exceptions.
Reports errors that are due to events beyond the control of the program.
T emplace_back(T... args)
#define INSTANTIATE_IMAGE(IMAGE)
void writeBasicFits(int fd, ImageT const &data, geom::SkyWcs const *Wcs, char const *title)
Extent< double, 2 > Extent2D