package ij.plugin;
import java.awt.*;
import java.io.*;
import java.util.zip.GZIPInputStream;
import ij.*;
import ij.io.*;
import ij.process.*;
import ij.measure.*;
public class FITS_Reader extends ImagePlus implements PlugIn {
public void run(String arg) {
OpenDialog od = new OpenDialog("Open FITS...", arg);
String directory = od.getDirectory();
String fileName = od.getFileName();
if (fileName==null)
return;
IJ.showStatus("Opening: " + directory + fileName);
FitsDecoder fd = new FitsDecoder(directory, fileName);
FileInfo fi = null;
try {fi = fd.getInfo();}
catch (IOException e) {}
if (fi!=null && fi.width>0 && fi.height>0 && fi.offset>0) {
FileOpener fo = new FileOpener(fi);
ImagePlus imp = fo.openImage();
if(fi.nImages==1) {
ImageProcessor ip = imp.getProcessor();
ip.flipVertical(); setProcessor(fileName, ip);
} else {
ImageStack stack = imp.getStack(); for(int i=1; i<=stack.getSize(); i++)
stack.getProcessor(i).flipVertical();
setStack(fileName, stack);
}
Calibration cal = imp.getCalibration();
if (fi.fileType==FileInfo.GRAY16_SIGNED && fd.bscale==1.0 && fd.bzero==32768.0)
cal.setFunction(Calibration.NONE, null, "Gray Value");
setCalibration(cal);
setProperty("Info", fd.getHeaderInfo());
setFileInfo(fi); if (arg.equals("")) show();
} else
IJ.error("This does not appear to be a FITS file.");
IJ.showStatus("");
}
}
class FitsDecoder {
private String directory, fileName;
private DataInputStream f;
private StringBuffer info = new StringBuffer(512);
double bscale, bzero;
public FitsDecoder(String directory, String fileName) {
this.directory = directory;
this.fileName = fileName;
}
FileInfo getInfo() throws IOException {
FileInfo fi = new FileInfo();
fi.fileFormat = FileInfo.FITS;
fi.fileName = fileName;
fi.directory = directory;
fi.width = 0;
fi.height = 0;
fi.offset = 0;
InputStream is = new FileInputStream(directory + fileName);
if (fileName.toLowerCase().endsWith(".gz")) is = new GZIPInputStream(is);
f = new DataInputStream(is);
String line = getString(80);
info.append(line+"\n");
if (!line.startsWith("SIMPLE"))
{f.close(); return null;}
int count = 1;
while ( true ) {
count++;
line = getString(80);
info.append(line+"\n");
int index = line.indexOf ( "=" );
int commentIndex = line.indexOf ( "/", index );
if ( commentIndex < 0 )
commentIndex = line.length ();
String key;
String value;
if ( index >= 0 ) {
key = line.substring ( 0, index ).trim ();
value = line.substring ( index + 1, commentIndex ).trim ();
} else {
key = line.trim ();
value = "";
}
if (key.equals ("END") ) break;
if (key.equals("BITPIX")) {
int bitsPerPixel = Integer.parseInt ( value );
if (bitsPerPixel==8)
fi.fileType = FileInfo.GRAY8;
else if (bitsPerPixel==16)
fi.fileType = FileInfo.GRAY16_SIGNED;
else if (bitsPerPixel==32)
fi.fileType = FileInfo.GRAY32_INT;
else if (bitsPerPixel==-32)
fi.fileType = FileInfo.GRAY32_FLOAT;
else if (bitsPerPixel==-64)
fi.fileType = FileInfo.GRAY64_FLOAT;
else {
IJ.error("BITPIX must be 8, 16, 32, -32 (float) or -64 (double).");
f.close();
return null;
}
} else if (key.equals("NAXIS1"))
fi.width = Integer.parseInt ( value );
else if (key.equals("NAXIS2"))
fi.height = Integer.parseInt( value );
else if (key.equals("NAXIS3")) fi.nImages = Integer.parseInt ( value );
else if (key.equals("BSCALE"))
bscale = parseDouble ( value );
else if (key.equals("BZERO"))
bzero = parseDouble ( value );
else if (key.equals("CDELT1"))
fi.pixelWidth = parseDouble ( value );
else if (key.equals("CDELT2"))
fi.pixelHeight = parseDouble ( value );
else if (key.equals("CDELT3"))
fi.pixelDepth = parseDouble ( value );
else if (key.equals("CTYPE1"))
fi.unit = value;
if (count>360 && fi.width==0)
{f.close(); return null;}
}
f.close();
fi.offset = 2880+2880*(((count*80)-1)/2880);
return fi;
}
String getString(int length) throws IOException {
byte[] b = new byte[length];
f.readFully(b);
if (IJ.debugMode)
IJ.log(new String(b));
return new String(b);
}
int getInteger(String s) {
s = s.substring(10, 30);
s = s.trim();
return Integer.parseInt(s);
}
double parseDouble(String s) throws NumberFormatException {
Double d = new Double(s);
return d.doubleValue();
}
String getHeaderInfo() {
return new String(info);
}
}