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>)