summaryrefslogtreecommitdiffstats
path: root/tksao/frame/frsave.C
diff options
context:
space:
mode:
Diffstat (limited to 'tksao/frame/frsave.C')
-rw-r--r--tksao/frame/frsave.C571
1 files changed, 571 insertions, 0 deletions
diff --git a/tksao/frame/frsave.C b/tksao/frame/frsave.C
new file mode 100644
index 0000000..87a8e97
--- /dev/null
+++ b/tksao/frame/frsave.C
@@ -0,0 +1,571 @@
+// Copyright (C) 1999-2016
+// 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,0);
+ 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, 0);
+ 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,0);
+ 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; ii<width; ii++) {
+
+ if (mosaic) {
+ sptr = currentContext->fits;
+
+ 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 && xx<params->xmax &&
+ yy>=params->ymin && yy<params->ymax) {
+
+ 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
+}