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) {}
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) {}
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;
81 int 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);
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,
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,
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.";
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);
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];
294 int nbyte = end - begin;
296 for (
char *
ptr = begin;
ptr !=
end; nbyte -= nwrite,
ptr += nwrite) {
297 if (end - ptr < nwrite) {
302 memcpy(buff, 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");
319 memcpy(buff, ptr, nwrite);
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>
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"));
408 NameList paramNames = metadata->paramNames();
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>
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>)
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
Provides consistent interface for LSST exceptions.
#define INSTANTIATE_IMAGE(IMAGE)
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
void writeBasicFits(std::string const &filename, ImageT const &data, geom::SkyWcs const *Wcs, char const *title)
A base class for image defects.
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
std::shared_ptr< SkyWcs > copyAtShiftedPixelOrigin(lsst::geom::Extent2D const &shift) const
Return a copy of this SkyWcs with the pixel origin shifted by the specified amount.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Class for storing generic metadata.
Extent< double, 2 > Extent2D
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
Reports errors that are due to events beyond the control of the program.