// Copyright (C) 1999-2017 // Smithsonian Astrophysical Observatory, Cambridge, MA, USA // For conditions of distribution and use, see copyright notice in "copyright" #include "context.h" #include "framebase.h" #include "framergb.h" #include "fitsimage.h" #include "outfile.h" #include "outchannel.h" #include "outsocket.h" #include "sigbus.h" void Base::saveFits(OutFitsStream& str) { FitsImage* ptr = currentContext->fits; if (!ptr) return; int dd = currentContext->naxis(2); if (!ptr->isIIS()) { ptr->saveFitsHeader(str,dd); size_t cnt =0; FitsImage* sptr = ptr; while (sptr) { cnt += sptr->saveFits(str); sptr = sptr->nextSlice(); } ptr->saveFitsPad(str,cnt,'\0'); } else { ptr->saveFitsIISHeader(str); size_t cnt = ptr->saveFitsIIS(str); ptr->saveFitsPad(str,cnt,'\0'); } } void Base::saveFitsTable(OutFitsStream& str) { FitsImage* ptr = currentContext->fits; if (ptr) { if (ptr->isTable()) ptr->saveFitsTable(str); else { Tcl_AppendResult(interp, " not a fits table", NULL); result = TCL_ERROR; } } } void Base::saveFitsSlice(OutFitsStream& str) { FitsImage* ptr = currentContext->cfits; if (!ptr) return; ptr->saveFitsHeader(str,1); size_t cnt = ptr->saveFits(str); ptr->saveFitsPad(str,cnt,'\0'); } void Base::saveFitsExtCube(OutFitsStream& str) { FitsImage* ptr = currentContext->fits; if (!ptr) return; ptr->saveFitsPrimHeader(str); while (ptr) { ptr->saveFitsXtHeader(str, 1); size_t cnt = ptr->saveFits(str); ptr->saveFitsPad(str,cnt,'\0'); ptr = ptr->nextSlice(); } } void Base::saveFitsMosaic(OutFitsStream& str, int which) { FitsImage* ptr = currentContext->fits; int dd = currentContext->naxis(2); // which 1 to n which--; while (ptr && which) { ptr = ptr->nextMosaic(); which--; } if (!ptr) return; ptr->saveFitsHeader(str,dd); size_t cnt =0; FitsImage* sptr = ptr; while (sptr) { cnt += sptr->saveFits(str); sptr = sptr->nextSlice(); } ptr->saveFitsPad(str,cnt,'\0'); } void Base::saveFitsMosaicImage(OutFitsStream& str) { FitsImage* ptr = currentContext->fits; if (!ptr) return; int dd = currentContext->naxis(2); ptr->saveFitsPrimHeader(str); while (ptr) { ptr->saveFitsXtHeader(str,dd); size_t cnt =0; FitsImage* sptr = ptr; while (sptr) { cnt += sptr->saveFits(str); sptr = sptr->nextSlice(); } ptr->saveFitsPad(str,cnt,'\0'); ptr = ptr->nextMosaic(); } } void FrameRGB::saveFitsRGBImage(OutFitsStream& str) { FitsImage* ptr = keyContext->fits; if (!ptr) return; // fake primary header ptr->saveFitsPrimHeader(str); for (int ii=0; ii<3; ii++) { if (context[ii].fits) { context[ii].fits->saveFitsXtHeader(str,1); size_t cnt = context[ii].fits->saveFits(str); context[ii].fits->saveFitsPad(str,cnt,'\0'); } } } void FrameRGB::saveFitsRGBCube(OutFitsStream& str) { FitsImage* ptr = keyContext->fits; if (!ptr) return; int ss =0; for (int ii=0; ii<3; ii++) if (context[ii].fits) ss++; ptr->saveFitsHeader(str,ss); size_t cnt =0; for (int ii=0; ii<3; ii++) if (context[ii].fits) cnt += context[ii].fits->saveFits(str); ptr->saveFitsPad(str,cnt,'\0'); } void Base::saveArray(OutFitsStream& str, FitsFile::ArchType endian) { FitsImage* ptr = currentContext->fits; if (!ptr) return; // set endian if needed if (endian == FitsFile::NATIVE) { if (lsb()) endian = FitsFile::LITTLE; else endian = FitsFile::BIG; } // dump each slice while (ptr) { ptr->saveArray(str,endian); ptr = ptr->nextSlice(); } } void FrameRGB::saveArrayRGBCube(OutFitsStream& str, FitsFile::ArchType endian) { FitsImage* ptr = keyContext->fits; if (!ptr) return; // set endian if needed if (endian == FitsFile::NATIVE) { if (lsb()) endian = FitsFile::LITTLE; else endian = FitsFile::BIG; } for (int ii=0; ii<3; ii++) if (context[ii].fits) context[ii].fits->saveArray(str,endian); } void Base::saveNRRD(OutFitsStream& str, FitsFile::ArchType endian) { FitsImage* ptr = currentContext->fits; if (!ptr) return; // set endian if needed if (endian == FitsFile::NATIVE) { if (lsb()) endian = FitsFile::LITTLE; else endian = FitsFile::BIG; } // dump header ostringstream hstr; hstr << "NRRD0002" << endl; if (currentContext->naxis(2)>1) { hstr << "dimension: 3" << endl; hstr << "sizes: " << ptr->naxis(0) << ' ' << ptr->naxis(1) << ' ' << currentContext->naxis(2) << endl; } else { hstr << "dimension: 2" << endl; hstr << "sizes: " << ptr->naxis(0) << ' ' << ptr->naxis(1) << endl; } switch (ptr->bitpix()) { case 8: hstr << "type: char" << endl; break; case 16: hstr << "type: short" << endl; break; case 32: hstr << "type: int" << endl; break; case 64: hstr << "type: longlong" << endl; break; case -32: hstr << "type: float" << endl; break; case -64: hstr << "type: double" << endl; break; } if (abs(ptr->bitpix()) > 8) { switch (endian) { case FitsFile::LITTLE: hstr << "endian: little" << endl; break; case FitsFile::BIG: hstr << "endian: big" << endl; break; default: // na break; } } hstr << "encoding: raw" << endl; // very important hstr << endl << ends; str.write((char*)hstr.str().c_str(),hstr.str().length()); // now dump each slice while (ptr) { ptr->saveArray(str,endian); ptr = ptr->nextSlice(); } } void Base::saveENVI(ostream& hstr, OutFitsStream& fstr, FitsFile::ArchType endian) { FitsImage* ptr = currentContext->fits; if (!ptr) return; // set endian if needed if (endian == FitsFile::NATIVE) { if (lsb()) endian = FitsFile::LITTLE; else endian = FitsFile::BIG; } // header hstr << "ENVI" << endl; hstr << "description = {}" << endl; hstr << "samples = " << ptr->naxis(0) << endl; hstr << "lines = " << ptr->naxis(1) << endl; if (currentContext->naxis(2)>1) { hstr << "bands = " << currentContext->naxis(2) << endl; } hstr << "header offset = 0" << endl; hstr << "file type = ENVI Standard" << endl; hstr << "data type = "; switch (ptr->bitpix()) { case 8: hstr << "1" << endl; break; case 16: hstr << "2" << endl; break; case -16: hstr << "12" << endl; break; case 32: hstr << "3" << endl; break; case 64: hstr << "14" << endl; break; case -32: hstr << "4" << endl; break; case -64: hstr << "5" << endl; break; } hstr << "interleave = bsq" << endl; hstr << "byte order = "; switch (endian) { case FitsFile::LITTLE: hstr << "0" << endl; break; case FitsFile::BIG: hstr << "1" << endl; break; default: // na break; } // now dump each slice while (ptr) { ptr->saveArray(fstr,endian); ptr = ptr->nextSlice(); } } void FrameBase::saveFitsResample(OutFitsStream& str) { int& width = options->width; int& height = options->height; int bitpix_ = -32; int datapixels_ = width*height; int realbytes_ = datapixels_ * (abs(bitpix_)/8); int datablocks_ = (realbytes_ + (FTY_BLOCK-1))/FTY_BLOCK; int databytes_ = datablocks_ * FTY_BLOCK; // create header FitsHead hd(width, height, 1, bitpix_); // write keywords saveFitsResampleKeyword(str, hd); // write header str.write(hd.cards(), hd.headbytes()); // write data saveFitsResampleFits(str); // pad rest of block { int diff = databytes_ - realbytes_; char buf[diff]; memset(buf,'\0',diff); str.write(buf, diff); } } void FrameBase::saveFitsResampleKeyword(OutFitsStream& str, FitsHead& dst) { FitsHead* src = currentContext->fits->head(); Vector center = Vector(options->width, options->height)/2.; // OBJECT char* object = src->getString("OBJECT"); if (object) { dst.appendString("OBJECT", object, NULL); delete [] object; } // DATE-OBS char* date = src->getString("DATE"); if (date) { dst.appendString("DATE", date, NULL); delete [] date; } char* dateobs = src->getString("DATE-OBS"); if (dateobs) { dst.appendString("DATE-OBS", dateobs, NULL); delete [] dateobs; } char* timeobs = src->getString("TIME-OBS"); if (timeobs) { dst.appendString("TIME-OBS", timeobs, NULL); delete [] timeobs; } char* dateend = src->getString("DATE-END"); if (dateend) { dst.appendString("DATE-END", dateend, NULL); delete [] dateend; } char* timeend = src->getString("TIME-END"); if (timeend) { dst.appendString("TIME-END", timeend, NULL); delete [] timeend; } // LTMV,DTMV if (!isMosaic()) { if (currentContext->fits->hasLTMV()) { Matrix ltmv = currentContext->fits->physicalToRef * refToWidget * Translate(-center) * Translate(1,0) * FlipY() * Translate(center); dst.appendReal("LTM1_1", ltmv[0][0], 9, NULL); dst.appendReal("LTM1_2", ltmv[0][1], 9, NULL); dst.appendReal("LTM2_1", ltmv[1][0], 9, NULL); dst.appendReal("LTM2_2", ltmv[1][1], 9, NULL); dst.appendReal("LTV1", ltmv[2][0], 9, NULL); dst.appendReal("LTV2", ltmv[2][1], 9, NULL); } } else { if (currentContext->fits->hasDTMV()) { Matrix dtmv = currentContext->fits->detectorToRef * refToWidget * Translate(-center) * Translate(1,0) * FlipY() * Translate(center); dst.appendReal("DTM1_1", dtmv[0][0], 9, NULL); dst.appendReal("DTM1_2", dtmv[0][1], 9, NULL); dst.appendReal("DTM2_1", dtmv[1][0], 9, NULL); dst.appendReal("DTM2_2", dtmv[1][1], 9, NULL); dst.appendReal("DTV1", dtmv[2][0], 9, NULL); dst.appendReal("DTV2", dtmv[2][1], 9, NULL); } } // WCS if (currentContext->fits->hasWCS(Coord::WCS)) { WorldCoor* wcs = currentContext->fits->getWCS(Coord::WCS); // abort if this is a DSS, ZPN, TNX if (!strncmp(wcs->ptype,"DSS",3) || !strncmp(wcs->ptype,"ZPN",3) || !strncmp(wcs->ptype,"TNX",3)) return; dst.appendString("RADESYS", wcs->radecsys, NULL); dst.appendReal("EQUINOX", wcs->equinox, 9, NULL); dst.appendString("CTYPE1", wcs->ctype[0], NULL); dst.appendString("CTYPE2", wcs->ctype[1], NULL); dst.appendReal("CRVAL1", wcs->crval[0], 9, NULL); dst.appendReal("CRVAL2", wcs->crval[1], 9, NULL); char* cunit1 = src->getString("CUNIT1"); if (cunit1) { dst.appendString("CUNIT1", cunit1, NULL); delete [] cunit1; } char* cunit2 = src->getString("CUNIT2"); if (cunit2) { dst.appendString("CUNIT2", cunit2, NULL); delete [] cunit2; } // crpix Vector crpix = Vector(wcs->crpix[0],wcs->crpix[1]) * currentContext->fits->imageToWidget * Translate(-center) * Translate(1,0) * FlipY() * Translate(center); dst.appendReal("CRPIX1", crpix[0], 9, NULL); dst.appendReal("CRPIX2", crpix[1], 9, NULL); // cd matrix Matrix cd = Matrix(wcs->cd[0],wcs->cd[1],wcs->cd[2],wcs->cd[3],0,0) * currentContext->fits->imageToRef * refToUser * wcsOrientationMatrix * Rotate(wcsRotation) * orientationMatrix * Scale(zoom_.invert()) * Rotate(rotation) * Translate(center) * Translate(-center) * Translate(1,0) * FlipY() * Translate(center); dst.appendReal("CD1_1", cd.matrix(0,0), 9, NULL); dst.appendReal("CD1_2", cd.matrix(0,1), 9, NULL); dst.appendReal("CD2_1", cd.matrix(1,0), 9, NULL); dst.appendReal("CD2_2", cd.matrix(1,1), 9, NULL); } } void FrameBase::saveFitsResampleFits(OutFitsStream& str) { int& width = options->width; int& height = options->height; // basics FitsImage* sptr = currentContext->fits; int mosaic = isMosaic(); // variable double* mm = sptr->matrixToData(Coord::WIDGET).mm(); FitsBound* params = sptr->getDataParams(currentContext->secMode()); int srcw = sptr->width(); // main loop SETSIGBUS for (int jj=height-1; jj>=0; jj--) { for (int ii=0; iifits; mm = sptr->matrixToData(Coord::WIDGET).mm(); params = sptr->getDataParams(currentContext->secMode()); srcw = sptr->width(); } float v = NAN; do { double xx = ii*mm[0] + jj*mm[3] + mm[6]; double yy = ii*mm[1] + jj*mm[4] + mm[7]; if (xx>=params->xmin && xxxmax && yy>=params->ymin && yyymax) { v = sptr->getValueFloat(long(yy)*srcw + long(xx)); break; } else { if (mosaic) { sptr = sptr->nextMosaic(); if (sptr) { mm = sptr->matrixToData(Coord::WIDGET).mm(); params = sptr->getDataParams(currentContext->secMode()); srcw = sptr->width(); } } } } while (mosaic && sptr); if (lsb()) str.writeSwap((char*)(&v), 4, -32); else str.write((char*)(&v), 4); } } CLEARSIGBUS }