001 /* @(#)FitsData.java $Revision: 1.7 $ $Date: 2003/04/11 08:41:15 $ 002 * 003 * Copyright (C) 2002 European Southern Observatory 004 * License: GNU General Public License version 2 or later 005 */ 006 package org.eso.fits; 007 008 import java.io.*; 009 010 /** FitsData class represents a FITS data unit 011 * 012 * @version $Revision: 1.7 $ $Date: 2003/04/11 08:41:15 $ 013 * @author P.Grosbol, DMD/ESO, <pgrosbol@eso.org> 014 */ 015 public class FitsData { 016 017 protected int type; 018 protected int[] naxis; 019 protected long size; 020 protected int bitpix = 0; 021 protected int noParm = 0; 022 protected int noGroup = 1; 023 protected boolean changeData = false; 024 025 protected RandomAccessFile dataFile = null; 026 protected long dataOffset = 0; 027 protected byte[] dataArray = null; 028 protected boolean isRAFile = false; 029 030 /** Constructor for FitsData class given a FITS header with 031 * associated data unit as a file. 032 * 033 * @param header FitsHeader object with the image header 034 * @param file RandomAccess file positioned at the start of the 035 * associated data unit 036 * @param sflag Flag for storing data matrix internally 037 * @exception FitsException 038 */ 039 public FitsData(FitsHeader header, DataInput file, boolean sflag) throws FitsException { 040 041 if (file instanceof RandomAccessFile) { 042 dataFile = (RandomAccessFile) file; 043 try { 044 dataOffset = dataFile.getFilePointer(); 045 } catch (IOException e) { 046 throw new FitsException("Cannot read data offset", FitsException.FILE); 047 } 048 isRAFile = true; 049 } 050 051 size = header.getDataSize(); 052 type = header.getType(); 053 long skip = size; 054 if (size%Fits.RECORD != 0) { 055 // John Talbot : Fails on SDSS spectra - data size is not an integer multiple of 2880 056 skip = (size/Fits.RECORD+1)*Fits.RECORD; 057 } 058 059 try { 060 if (sflag && !isRAFile) { 061 dataArray = new byte[(int) skip]; 062 file.readFully(dataArray); 063 } else { 064 file.skipBytes((int) skip); 065 } 066 } catch (IOException e) { 067 throw new FitsException("Cannot read/skip over data matrix", FitsException.FILE); 068 } 069 070 decodeBasicHeader(header); 071 } 072 073 /** Constructor for FitsData class given the size of the data matrix. 074 * An array equal to the size of the data matrix will be allocated. 075 * 076 * @param bitpix value of FITS BITPIX keyword bits/pixel 077 * @param nax Integer array defining the dimensions of the 078 * data matrix or for BINTABLE the heap size 079 * @exception FitsException 080 */ 081 public FitsData(int bitpix, int nax[]) 082 throws FitsException { 083 switch (bitpix) { 084 case Fits.BYTE : 085 case Fits.SHORT : 086 case Fits.INT : 087 case Fits.FLOAT : 088 case Fits.DOUBLE : this.bitpix = bitpix; break; 089 default: throw new FitsException("Invalid BITPIX value", 090 FitsException.DATA); 091 } 092 type = Fits.UNKNOWN; 093 size = 1; 094 naxis = new int[nax.length]; 095 for (int n=0; n<nax.length; n++) { 096 naxis[n] = nax[n]; 097 size *= naxis[n]; 098 } 099 size *= Math.abs(this.bitpix)/8; 100 if (size < 0) throw new FitsException("Data size less than zero", 101 FitsException.DATA); 102 103 long skip = size; 104 if (size%Fits.RECORD != 0) { 105 skip = (size/Fits.RECORD+1)*Fits.RECORD; 106 } 107 108 dataArray = new byte[(int) skip]; 109 } 110 111 /** Decodes basic header information for data matrix. 112 * 113 * @param header FITS header 114 */ 115 private void decodeBasicHeader(FitsHeader header) throws FitsException { 116 117 FitsKeyword kw = header.getKeyword("NAXIS"); 118 if (kw == null) { 119 throw new FitsException("Missing NAXIS keyword", FitsException.HEADER); 120 } 121 int nax = kw.getInt(); 122 naxis = new int[nax]; 123 kw = header.getKeyword("BITPIX"); 124 if (kw == null) { 125 throw new FitsException("Missing BITPIX keyword", FitsException.HEADER); 126 } 127 bitpix = kw.getInt(); 128 129 for (int n=1; n<=nax; n++) { 130 kw = header.getKeyword("NAXIS"+n); 131 if (kw == null) { 132 throw new FitsException("Missing NAXIS" + n + " keyword", FitsException.HEADER); 133 } 134 naxis[n-1] = kw.getInt(); 135 } 136 137 kw = header.getKeyword("GCOUNT"); 138 noGroup = (kw == null) ? 1 : kw.getInt(); 139 kw = header.getKeyword("PCOUNT"); 140 noParm = (kw == null) ? 0 : kw.getInt(); 141 changeData = false; 142 } 143 144 /** Create and return a minimum FITS header for data Matrix. 145 */ 146 public FitsHeader getHeader() { 147 FitsHeader hdr = new FitsHeader(); 148 149 hdr.addKeyword(new FitsKeyword("SIMPLE", true, "Standard FITS format; NOST 100-2.0")); 150 hdr.addKeyword(new FitsKeyword("BITPIX", bitpix, "No. of bits per pixel")); 151 hdr.addKeyword(new FitsKeyword("NAXIS", naxis.length, "No. of axes in image")); 152 for (int n=1; n<=naxis.length; n++) { 153 hdr.addKeyword(new FitsKeyword("NAXIS"+n, naxis[n-1], "No. of pixels")); 154 } 155 hdr.addKeyword(new FitsKeyword("PCOUNT", 0, "Parameter count")); 156 hdr.addKeyword(new FitsKeyword("GCOUNT", 1, "Group count")); 157 158 return hdr; 159 } 160 161 /** Write data martix to DataOutput stream. 162 * 163 * @param file DataOutput stream to which data are written 164 * @exception IOException, FitsException */ 165 public void writeFile(DataOutput file) throws IOException, FitsException { 166 byte[] buf; 167 int nbytes = 0; 168 int block = 10*Fits.RECORD; 169 170 if (isRAFile) { 171 buf = new byte[block]; 172 dataFile.seek(dataOffset); 173 int nrec = (int) size/block; // write large block first 174 while (0<nrec--) { 175 dataFile.read(buf); 176 file.write(buf); 177 } 178 179 nbytes = (int) size%block; // and then the remaining blocks 180 if (nbytes == 0) return; 181 182 buf = new byte[nbytes]; 183 dataFile.read(buf); 184 file.write(buf); 185 } else if (dataArray != null) { 186 file.write(dataArray); 187 } 188 189 if (nbytes%Fits.RECORD != 0) { // finally fill with zeros 190 nbytes = Fits.RECORD*(nbytes/Fits.RECORD + 1) - nbytes; 191 buf = new byte[nbytes]; 192 if (type == Fits.ATABLE) { // or if ASCII table the space fill 193 for (int n=0; n<nbytes; n++) buf[n] = 0x20; 194 } 195 file.write(buf); 196 } 197 } 198 199 /** Closes the associated data file */ 200 public void closeFile(){ 201 dataFile = null; 202 dataOffset = 0; 203 size = 0; 204 type = 0; 205 } 206 207 /** Retrives number of axes defined for the data unit (ref. NAXIS) */ 208 public int getNoAxes(){ 209 return naxis.length; 210 } 211 212 /** Gets FITS type of data unit. This is specified in the 213 * assocated header such as Fits.IMAGE or Fits.BTABLE */ 214 public int getType(){ 215 return type; 216 } 217 218 /** Gets the dimentions of the axes. This is defined for the data 219 * unit by the NAXISn keywords. */ 220 public int[] getNaxis(){ 221 return naxis; 222 } 223 } 224 225