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