source: trunk/src/Cubes/saveImage.cc @ 1100

Last change on this file since 1100 was 1100, checked in by MatthewWhiting, 12 years ago

Several changes to the saving of FITS files, including working round the main problem with #167 - we now save the mask FITS file as integers, rather than shorts (removing the type
conversion). Have also improved the use of cfitsio writing functions so that they better match what we're trying to do, and are consistent across the different functions.

File size: 20.5 KB
RevLine 
[299]1// -----------------------------------------------------------------------
2// saveImage.cc: Write a wavelet-reconstructed or smoothed array to a
3//               FITS file.
4// -----------------------------------------------------------------------
5// Copyright (C) 2006, Matthew Whiting, ATNF
6//
7// This program is free software; you can redistribute it and/or modify it
8// under the terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// Duchamp is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15// for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with Duchamp; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20//
21// Correspondence concerning Duchamp may be directed to:
22//    Internet email: Matthew.Whiting [at] atnf.csiro.au
23//    Postal address: Dr. Matthew Whiting
24//                    Australia Telescope National Facility, CSIRO
25//                    PO Box 76
26//                    Epping NSW 1710
27//                    AUSTRALIA
28// -----------------------------------------------------------------------
[3]29#include <iostream>
30#include <sstream>
31#include <string>
[643]32#include <string.h>
[394]33#include <wcslib/wcs.h>
34#include <wcslib/wcshdr.h>
[757]35#include <wcslib/wcsunits.h>
[146]36#define WCSLIB_GETWCSTAB
37// define this so that we don't try and redefine wtbarr
38// (this is a problem when using cfitsio v.3 and g++ v.4)
39
[66]40#include <fitsio.h>
[393]41#include <duchamp/duchamp.hh>
42#include <duchamp/Cubes/cubes.hh>
43#include <duchamp/PixelMap/Voxel.hh>
44#include <duchamp/PixelMap/Object3D.hh>
[3]45
[378]46namespace duchamp
[208]47{
48
[528]49  /// @brief Write FITS headers in correct format for reconstructed array output
[378]50  void writeReconHeaderInfo(fitsfile *fptr, Param &par, std::string nature);
[208]51
[528]52  /// @brief Write FITS headers in correct format for smoothed array output
[378]53  void writeSmoothHeaderInfo(fitsfile *fptr, Param &par);
[208]54
[528]55  /// @brief Write FITS headers in correct format for mask array output
[379]56  void writeMaskHeaderInfo(fitsfile *fptr, Param &par);
[670]57
58  /// @brief Write FITS headers in correct format for moment-0 array output
59  void writeMomentMapHeaderInfo(fitsfile *fptr, Param &par);
60
[379]61  //---------------------------------------------------------------------------
62
[670]63
[695]64  void duchampFITSerror(int status, std::string subroutine, std::string error)
[670]65  {
[695]66    if(status){
[913]67      DUCHAMPWARN(subroutine,error);
[695]68      fits_report_error(stderr, status);
69    }
70  }
71
72
73  OUTCOME Cube::saveMomentMapImage()
74  {
[670]75    /// @details
76    ///  A function to save the moment-0 map to a FITS file.
77   
78    int newbitpix = FLOAT_IMG;
[902]79    long *fpixel = new long[this->head.WCS().naxis];
80    for(int i=0;i<this->header().WCS().naxis;i++) fpixel[i]=1;
[670]81    int status = 0;  /* MUST initialize status */
82    fitsfile *fptr;         
83
84    std::string fileout = "!" + this->par.outputMomentMapFile();
85    // the ! is there so that it writes over an existing file.
86
87    status = 0;
[695]88    if(fits_create_file(&fptr,fileout.c_str(),&status)){
89      duchampFITSerror(status,"saveMomentMapImage","Error creating file:");
90      return FAILURE;
[670]91    }
92    else {
93
[902]94      if(this->writeBasicHeader(fptr, newbitpix,true)==FAILURE){
[913]95        DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[902]96        return FAILURE;
[670]97      }
98
99      writeMomentMapHeaderInfo(fptr, this->par);
100       
101      long size = this->axisDim[0] * this->axisDim[1];
102      float *momentMap = new float[size];
[946]103      std::vector<bool> detectionMap = this->getMomentMap(momentMap);
[670]104      status=0;
105      if(fits_write_pix(fptr, TFLOAT, fpixel, size, momentMap, &status)){
[695]106        duchampFITSerror(status,"saveMomentMapImage","Error writing data");
[670]107      }
108      status = 0;
109      if(fits_close_file(fptr, &status)){
[695]110        duchampFITSerror(status,"saveMomentMapImage","Error closing file");
[670]111      }
112
113      delete [] momentMap;
114
115    }
116
117    delete [] fpixel;
118
[695]119    return SUCCESS;
[670]120
121  }
122
[695]123  OUTCOME Cube::saveMaskCube()
[379]124  {
[528]125    /// @details
126    ///  A function to save a mask to a FITS file, indicating where the
127    ///  detections where made. The value of the detected pixels is
128    ///  determined by the flagMaskWithObjectNum parameter: if true,
129    ///  the value of the pixels is given by the corresponding object
130    ///  ID number; if false, they take the value 1 for all
131    ///  objects. Pixels not in a detected object have the value 0.
[379]132
[1100]133    int newbitpix = LONG_IMG;
[902]134    long *fpixel = new long[this->head.WCS().naxis];
[385]135    for(int i=0;i<this->header().WCS().naxis;i++) fpixel[i]=1;
[379]136    int status = 0;  /* MUST initialize status */
[900]137    fitsfile *fptrNew;         
[379]138
139    std::string fileout = "!" + this->par.outputMaskFile();
140    // the ! is there so that it writes over an existing file.
141
142    status = 0;
[695]143    if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
144      duchampFITSerror(status,"saveMask","Error creating file:");
145      return FAILURE;
[379]146    }
147    else {
[900]148      if(this->writeBasicHeader(fptrNew, newbitpix)==FAILURE){
[1019]149        DUCHAMPWARN("write Mask Cube", "Failure writing to header");
[695]150        return FAILURE;
[379]151      }
[900]152
153      writeMaskHeaderInfo(fptrNew, this->par);
154
[1019]155      char *comment = new char[FLEN_COMMENT];
156      strcpy(comment,"");
[902]157      char *keyword = new char[FLEN_KEYWORD];
[521]158      std::string newunits;
159      if(this->par.getFlagMaskWithObjectNum())
160        newunits = "Object ID";
161      else
162        newunits = "Detection flag";
[644]163      strcpy(keyword,"BUNIT");
[695]164      if(fits_update_key(fptrNew, TSTRING, keyword, (char *)newunits.c_str(), comment, &status)){
165        duchampFITSerror(status,"saveMask","Error writing BUNIT header:");
[521]166      }
[379]167      delete [] comment;
[661]168      delete [] keyword;
[379]169       
[1100]170      int *mask = new int[this->numPixels];
[894]171      for(size_t i=0;i<this->numPixels;i++) mask[i]=0;
[623]172      std::vector<Detection>::iterator obj;
173      for(obj=this->objectList->begin();obj<this->objectList->end();obj++){
174        std::vector<PixelInfo::Voxel> voxlist = obj->getPixelSet();
175        std::vector<PixelInfo::Voxel>::iterator vox;
176        for(vox=voxlist.begin();vox<voxlist.end();vox++){
[920]177          size_t pixelpos = vox->getX() + this->axisDim[0]*vox->getY() +
[623]178            this->axisDim[0]*this->axisDim[1]*vox->getZ();
179          if(this->par.getFlagMaskWithObjectNum()) mask[pixelpos] = obj->getID();
[521]180          else mask[pixelpos] = 1;
[379]181        }
182      }
183      status=0;
[1100]184      long group=0;
185      LONGLONG first=1;
186      LONGLONG nelem=LONGLONG(this->numPixels);
187      if(fits_write_img_int(fptrNew, group, first, nelem, mask, &status)){
188        duchampFITSerror(status,"saveMask","Error writing mask array!:");
[379]189      }
190      status = 0;
[695]191      if(fits_close_file(fptrNew, &status)){
192        duchampFITSerror(status,"saveMask","Error closing file:");
[379]193      }
194
195      delete [] mask;
196
197    }
198
199    delete [] fpixel;
200
[695]201    return SUCCESS;
[379]202  }
203 
204  //---------------------------------------------------------------------------
205
[695]206  OUTCOME Cube::saveSmoothedCube()
[378]207  {
[528]208    /// @brief
209    ///   A function to save the smoothed arrays to a FITS file.
210    ///   Additional header keywords are written as well, indicating the
211    ///   width of the Hanning filter or the dimensions of the Gaussian
212    ///   kernel.
213    ///   The file is always written -- if the filename (as calculated
214    ///    based on the parameters) exists, then it is overwritten.
[3]215 
[378]216    float blankval = this->par.getBlankPixVal();
[3]217
[378]218    int status = 0;  /* MUST initialize status */
[900]219    fitsfile *fptrNew;         
[695]220
[378]221    if(this->par.getFlagOutputSmooth()){
222      std::string fileout = "!" + this->par.outputSmoothFile();
223      // the ! is there so that it writes over an existing file.
[3]224
[378]225      status = 0;
[695]226      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
227        duchampFITSerror(status,"saveSmoothedCube","Error creating smoothed FITS file:");
228        return FAILURE;
229      }
[378]230      else {
[46]231
[1100]232          if(this->writeBasicHeader(fptrNew, FLOAT_IMG)==FAILURE){
[913]233            DUCHAMPWARN("write Smoothed Cube", "Failure writing to header");
[900]234            return FAILURE;
235          }
236
[378]237        writeSmoothHeaderInfo(fptrNew, this->par);
[3]238
[1100]239        long group=0;
[103]240        if(this->par.getFlagBlankPix())
[1100]241          fits_write_imgnull_flt(fptrNew, group, 1, this->numPixels, this->recon, blankval, &status);
[578]242        else
[1100]243          fits_write_img_flt(fptrNew, group, 1, this->numPixels, this->recon, &status);
[695]244        if(status){
245          duchampFITSerror(status,"saveSmothedCube","Error writing smoothed array:");
246          return FAILURE;
247        }
[3]248
[103]249        status = 0;
[695]250        if(fits_close_file(fptrNew, &status)){
251          duchampFITSerror(status,"saveSmoothedCube","Error closing file:");
252        }
[103]253      }
[378]254    }
255
[695]256    return SUCCESS;
257
[3]258  }
259
[379]260  //---------------------------------------------------------------------------
[103]261
[695]262  OUTCOME Cube::saveReconstructedCube()
[378]263  {
[528]264    /// @details
265    ///  A function to save the reconstructed and/or residual arrays.
266    ///   A number of header keywords are written as well, indicating the
267    ///    nature of the reconstruction that has been done.
268    ///   The file is always written -- if the filename (as calculated
269    ///    based on the recon parameters) exists, then it is overwritten.
[378]270 
271    float blankval = this->par.getBlankPixVal();
[71]272
[757]273    if(!this->reconAllocated){
[913]274      DUCHAMPERROR("saveReconCube","Have not allocated reconstructed array, so cannot save");
[757]275      return FAILURE;
276    }
277
[378]278    int status = 0;  /* MUST initialize status */
[1100]279    long group=0;
[900]280    fitsfile *fptrNew;         
[378]281 
282    if(this->par.getFlagOutputRecon()){
283      std::string fileout = "!" + this->par.outputReconFile();
284      // the ! is there so that it writes over an existing file.
285
286      status = 0;
[695]287      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
288        duchampFITSerror(status,"saveReconCube","Error creating file:");
289        return FAILURE;
290      }
[378]291      else
292        {
[900]293
[1100]294          if(this->writeBasicHeader(fptrNew, FLOAT_IMG)==FAILURE){
[913]295            DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[695]296            return FAILURE;
297          }
[900]298         
[378]299          writeReconHeaderInfo(fptrNew, this->par, "recon");
300
[757]301          status=0;
[378]302          if(this->par.getFlagBlankPix())
[757]303            fits_write_imgnull_flt(fptrNew, group, 1, this->numPixels, this->recon, blankval, &status);
[578]304          else 
[757]305            fits_write_img_flt(fptrNew, group, 1, this->numPixels, this->recon, &status);
[695]306          if(status){
307            duchampFITSerror(status,"saveReconCube","Error writing reconstructed array:");
308            return FAILURE;
309          }
[378]310
311          status = 0;
[695]312          if(fits_close_file(fptrNew, &status)){
313            duchampFITSerror(status,"saveReconCube","Error closing file:");
314          }
[103]315        }
[378]316    }
[3]317
[71]318
[378]319    if(this->par.getFlagOutputResid()){
[578]320      float *resid = new float[this->numPixels];
[894]321      for(size_t i=0;i<this->numPixels;i++)
[578]322        resid[i] = this->array[i] - this->recon[i];
323
[378]324      std::string fileout = "!" + this->par.outputResidFile();
325      // the ! is there so that it writes over an existing file.
326      status = 0;
[695]327      if(fits_create_file(&fptrNew,fileout.c_str(),&status)){
328        duchampFITSerror(status,"saveResidualCube","Error creating new file:");
329        return FAILURE;
330      }
[378]331      else
332        {
[900]333
334          if(this->writeBasicHeader(fptrNew, -32)==FAILURE){
[913]335            DUCHAMPWARN("write Recon Cube", "Failure writing to header");
[695]336            return FAILURE;
337          }
[900]338
[378]339          writeReconHeaderInfo(fptrNew, this->par, "resid");
[71]340
[378]341          if(this->par.getFlagBlankPix())
[1100]342            fits_write_imgnull_flt(fptrNew, group, 1, this->numPixels, resid, blankval, &status);
[578]343          else 
[1100]344            fits_write_img_flt(fptrNew, group, 1, this->numPixels, resid, &status);
[695]345          if(status){
346            duchampFITSerror(status,"saveResidualCube","Error writing reconstructed array:");
347            return FAILURE;
348          }
[71]349
[695]350          status=0;
351          if(fits_close_file(fptrNew, &status)){
352            duchampFITSerror(status,"saveResidualCube","Error closing file:");
353          }
[378]354        }
[578]355      delete [] resid;
[378]356    }
[86]357
[695]358    return SUCCESS;
[378]359  }
[71]360
[379]361  //---------------------------------------------------------------------------
[378]362
363  void writeReconHeaderInfo(fitsfile *fptr, Param &par, std::string nature)
364  {
[528]365    /// @details
366    ///   A simple function that writes all the necessary keywords and comments
367    ///    to the FITS header pointed to by fptr.
368    ///   The keyword names and comments are taken from duchamp.hh
369    ///   The parameter "nature" indicates what type of file is being written:
370    ///    should be either "recon" or "resid".
[378]371
372    int status = 0;
373    std::string explanation = "",ReconResid="";
374
375    fits_write_history(fptr, (char *)header_reconHistory1.c_str(), &status);
[71]376                                   
[378]377    fits_write_history(fptr, (char *)header_reconHistory2.c_str(), &status);
[71]378
[378]379    fits_write_history(fptr, (char *)header_reconHistory_input.c_str(), &status);
[71]380
[378]381    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
[105]382
[378]383    if(par.getFlagSubsection()){
384      fits_write_comment(fptr,(char *)header_reconSubsection_comment.c_str(),
385                         &status);
386      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
387                     (char *)par.getSubsection().c_str(),
388                     (char *)comment_subsection.c_str(), &status);
389    }
[105]390   
[378]391    fits_write_comment(fptr, (char *)header_atrous_comment.c_str(), &status);
[105]392
[378]393    float valf = par.getAtrousCut();
394    fits_write_key(fptr, TFLOAT, (char *)keyword_snrRecon.c_str(), &valf,
395                   (char *)comment_snrRecon.c_str(), &status);
[71]396
[378]397    int vali = par.getReconDim();
398    fits_write_key(fptr, TINT, (char *)keyword_reconDim.c_str(), &vali,
399                   (char *)comment_reconDim.c_str(), &status);
[103]400
[378]401    vali = par.getMinScale();
402    fits_write_key(fptr, TINT, (char *)keyword_scaleMin.c_str(), &vali,
403                   (char *)comment_scaleMin.c_str(), &status);
[71]404
[378]405    vali = par.getFilterCode();
406    fits_write_key(fptr, TINT, (char *)keyword_filterCode.c_str(), &vali,
407                   (char *)comment_filterCode.c_str(), &status);
[71]408
[378]409    if(nature == "recon"){
410      explanation = "Duchamp: This is the RECONSTRUCTED cube";
411      ReconResid = "RECON";
412    }
413    else if(nature == "resid"){
414      explanation = "Duchamp: This is the RESIDUAL cube";
415      ReconResid = "RESID";
416    }
[913]417    else DUCHAMPWARN("write_header_info","explanation not present");
[378]418    fits_write_comment(fptr, (char *)explanation.c_str(), &status);
419    fits_write_key(fptr, TSTRING, (char *)keyword_ReconResid.c_str(),
420                   (char *)ReconResid.c_str(),
421                   (char *)comment_ReconResid.c_str(), &status);
422
[71]423  }
424
[379]425  //---------------------------------------------------------------------------
426
[378]427  void writeSmoothHeaderInfo(fitsfile *fptr, Param &par)
428  {
[528]429    /// @details
430    ///   A simple function that writes all the necessary keywords and comments
431    ///    to the FITS header pointed to by fptr.
432    ///   The keyword names and comments are taken from duchamp.hh
[208]433
[378]434    int status = 0;
[208]435
[378]436    fits_write_history(fptr, (char *)header_smoothHistory.c_str(), &status);
[208]437    status = 0;
[378]438    fits_write_history(fptr, (char *)header_smoothHistory_input.c_str(),&status);
[208]439    status = 0;
[378]440    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
441
442    if(par.getFlagSubsection()){
443      status = 0;
444      fits_write_comment(fptr,(char *)header_smoothSubsection_comment.c_str(),
445                         &status);
446      status = 0;
447      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
448                     (char *)par.getSubsection().c_str(),
449                     (char *)comment_subsection.c_str(), &status);
450    }
[208]451   
[378]452    if(par.getSmoothType()=="spatial"){
453      // if kernMin is negative (not defined), make it equal to kernMaj
454      if(par.getKernMin() < 0) par.setKernMin(par.getKernMaj());
[285]455
[378]456      fits_write_key(fptr, TSTRING, (char *)keyword_smoothtype.c_str(),
457                     (char *)header_smoothSpatial.c_str(),
458                     (char *)comment_smoothtype.c_str(), &status);
459      float valf = par.getKernMaj();
460      fits_write_key(fptr, TFLOAT, (char *)keyword_kernmaj.c_str(), &valf,
461                     (char *)comment_kernmaj.c_str(), &status);
462      valf = par.getKernMin();
463      fits_write_key(fptr, TFLOAT, (char *)keyword_kernmin.c_str(), &valf,
464                     (char *)comment_kernmin.c_str(), &status);
465      valf = par.getKernPA();
466      fits_write_key(fptr, TFLOAT, (char *)keyword_kernpa.c_str(), &valf,
467                     (char *)comment_kernpa.c_str(), &status);
468    }
469    else if(par.getSmoothType()=="spectral"){
470      fits_write_key(fptr, TSTRING, (char *)keyword_smoothtype.c_str(),
471                     (char *)header_smoothSpectral.c_str(),
472                     (char *)comment_smoothtype.c_str(), &status);
473      int vali = par.getHanningWidth();
474      fits_write_key(fptr, TINT, (char *)keyword_hanningwidth.c_str(), &vali,
475                     (char *)comment_hanningwidth.c_str(), &status);
476    }
[277]477  }
[378]478
[379]479  //---------------------------------------------------------------------------
480
481  void writeMaskHeaderInfo(fitsfile *fptr, Param &par)
482  {
[528]483    /// @details
484    ///   A simple function that writes all the necessary keywords and comments
485    ///    to the FITS header pointed to by fptr.
486    ///   The keyword names and comments are taken from duchamp.hh
[379]487
488    int status = 0;
489
490    fits_write_history(fptr, (char *)header_maskHistory.c_str(), &status);
491    status = 0;
492    fits_write_history(fptr, (char *)header_maskHistory_input.c_str(),&status);
493    status = 0;
494    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
495
496    if(par.getFlagSubsection()){
497      status = 0;
498      fits_write_comment(fptr,(char *)header_maskSubsection_comment.c_str(),
499                         &status);
500      status = 0;
501      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
502                     (char *)par.getSubsection().c_str(),
503                     (char *)comment_subsection.c_str(), &status);
504    }
505  }
506
[670]507  //---------------------------------------------------------------------------
508
509  void writeMomentMapHeaderInfo(fitsfile *fptr, Param &par)
510  {
511    /// @details
512    ///   A simple function that writes all the necessary keywords and comments
513    ///    to the FITS header pointed to by fptr.
514    ///   The keyword names and comments are taken from duchamp.hh
515
516    int status = 0;
517
518    fits_write_history(fptr, (char *)header_moment0History.c_str(), &status);
519    status = 0;
520    fits_write_history(fptr, (char *)header_moment0History_input.c_str(),&status);
521    status = 0;
522    fits_write_history(fptr, (char *)par.getImageFile().c_str(), &status);
523
524    if(par.getFlagSubsection()){
525      status = 0;
526      fits_write_comment(fptr,(char *)header_moment0Subsection_comment.c_str(),
527                         &status);
528      status = 0;
529      fits_write_key(fptr, TSTRING, (char *)keyword_subsection.c_str(),
530                     (char *)par.getSubsection().c_str(),
531                     (char *)comment_subsection.c_str(), &status);
532    }
533  }
534
[900]535
536  //---------------------------------------------------------------------------
537
[902]538  OUTCOME Cube::writeBasicHeader(fitsfile *fptr, int bitpix, bool is2D)
[900]539  {
540    char *header, *hptr, keyname[9];
541    int  i, nkeyrec, status = 0;
542   
[936]543    const size_t naxis=this->numDim;
544    long* naxes = new long[this->numDim];
545    for(size_t i=0;i<naxis;i++) naxes[i]=this->axisDim[i];
[902]546    if(is2D) naxes[this->head.WCS().spec]=1;
[900]547    // write the required header keywords
[1100]548    std::cerr << "Creating image with bitpix = " << bitpix << "\n";
[900]549    fits_write_imghdr(fptr, bitpix, naxis, naxes,  &status);
550
551    // Write beam information
552    this->head.beam().writeToFITS(fptr);
553
554    // Write bunit information
555    status = 0;
556    strcpy(keyname,"BUNIT");
557    if (fits_update_key(fptr, TSTRING, keyname, (char *)this->head.getFluxUnits().c_str(), NULL, &status)){
[913]558      DUCHAMPWARN("saveImage","Error writing bunit info:");
[900]559      fits_report_error(stderr, status);
560      return FAILURE;
561    }
562
563    // convert the wcsprm struct to a set of 80-char keys
564    if ((status = wcshdo(WCSHDO_all, this->head.getWCS(), &nkeyrec, &header))) {
[913]565      DUCHAMPWARN("saveImage","Could not convert WCS information to FITS header. WCS Error Code = "<<status<<": "<<wcs_errmsg[status]);
[900]566      return FAILURE;
567    }
568
569    hptr = header;
570    strncpy(keyname,hptr,8);
571    for (i = 0; i < nkeyrec; i++, hptr += 80) {
572      status=0;
573      if(fits_update_card(fptr,keyname,hptr,&status)){
[913]574        DUCHAMPWARN("saveImage","Error writing header card");
[900]575        fits_report_error(stderr,status);
576        return FAILURE;
577      }
578    }
579   
580    if(bitpix>0){
[903]581      if(this->par.getFlagBlankPix()){
582        strcpy(keyname,"BSCALE");
583        float bscale=this->head.getBscaleKeyword();
584        if(fits_update_key(fptr, TFLOAT, keyname, &bscale, NULL, &status)){
585          duchampFITSerror(status,"saveImage","Error writing BSCALE header:");
586        }
587        strcpy(keyname,"BZERO");
588        float bzero=this->head.getBzeroKeyword();
589        if(fits_update_key(fptr, TFLOAT, keyname, &bzero, NULL, &status)){
590          duchampFITSerror(status,"saveImage","Error writing BZERO header:");
591        }
592        strcpy(keyname,"BLANK");
593        int blank=this->head.getBlankKeyword();
594        if(fits_update_key(fptr, TINT, keyname, &blank, NULL, &status)){
595          duchampFITSerror(status,"saveImage","Error writing BLANK header:");
596        }
597        if(fits_set_imgnull(fptr, blank, &status)){
598          duchampFITSerror(status, "saveImage", "Error setting null value:");
599        }
600        if(fits_set_bscale(fptr, bscale, bzero, &status)){
601          duchampFITSerror(status,"saveImage","Error setting scale:");
602        }
[900]603      }
604    }
605
[936]606    delete [] naxes;
607
[900]608    return SUCCESS;
609
610  }
611
[208]612}
Note: See TracBrowser for help on using the repository browser.