/* HSTVolReader_.java * Greg Johnson, November 2005 * Corrections and evolutions from 06/2006 on: P. Cloetens * * This is a simple plugin for ImageJ that attempts to use the .XML files that coexist with volumes * to automate the reading of them. The features and known problems * are below: * 1. 32bit floating point files (.vol) or 8bit unsigned integer files (.raw) which have one or more slices. * With multi-slice volumes, a VOI may be specified or the volume is opened as virtual stack. * In the case of a VOI, the z-slices are correctly cropped, but the X/Y cropping only generates a ROI * that the user must crop themselves using the Image/Crop tool. This is not by design! * Otherwise the single slice is read into without further hesitation. * * modified March 2006 to handle volumes with larger size (offsets>integer (31 bits)). Now using .longOffset * instead of .offset. GJ * * 29/06/2006 PC * call to OpenDialog without third argument ".xml" * this seems to solve: HandleExtraFileTypes issue * next call of plugin remembers previous directory * make roi selection consistent (seems to start from 1 not 0) * do roi selection only if needed, user can correct before applying crop * * 13/04/2007 PC * correct readHeader: do not read BYTE_ORDER of an 8-bits file (info does not exist) * clean up * * 09/01/2008 PC * make compatible with virtual stack that appeared in v1.39 * cleanup * it seems necessary to do the compilation with jdom.jar in the CLASSPATH when compiling */ import java.io.*; import ij.*; import ij.plugin.*; import ij.io.*; import ij.gui.*; import org.jdom.*; import org.jdom.input.*; public class HSTVolReader_ implements PlugIn { public boolean littleEndian = false; private static boolean virtual; private int xMin,xMax,yMin,yMax,zMin,zMax; public void run(String arg) { if (IJ.versionLessThan("1.39o")){ IJ.showMessage("Please upgrade ImageJ to at least version 1.39o"); return; } OpenDialog od = new OpenDialog("Select an XML file...", arg); String directory = od.getDirectory(); String name = od.getFileName(); if (name==null) return; IJ.showStatus("Opening: " + directory + name); FileInfo fi = getVolumeInfo(directory, name); if (virtual) new FileInfoVirtualStack(fi); else { FileOpener fo = new FileOpener(fi); ImagePlus imp = fo.open(false); if ((xMin!=1)||(xMax!=fi.width)||(yMin!=1)||(yMax!=fi.height)) imp.setRoi(xMin-1,yMin-1,xMax-xMin+1,yMax-yMin+1); if (imp!=null) imp.show(); } } public FileInfo getVolumeInfo(String directory, String name) { FileInfo fi = new FileInfo(); if ((name == null) || (name == "")) return null; IJ.showStatus("Loading HST Volume File: " + directory + name); try { fi = readHeader(directory+name); } catch (IOException e) { IJ.log("HST Volume Reader: "+ e.getMessage()); } fi.directory = directory; fi.fileFormat = FileInfo.RAW; xMin=1; xMax=fi.width; yMin=1; yMax=fi.height; zMin=1; zMax=fi.nImages; if (fi.nImages!=1) { GenericDialog gd = new GenericDialog("VOI Selection"); gd.addNumericField("X minimum: ", xMin, 0); gd.addNumericField("X maximum: ", xMax, 0); gd.addNumericField("Y minimum: ", yMin, 0); gd.addNumericField("Y maximum: ", yMax, 0); gd.addNumericField("Z minimum: ", zMin, 0); gd.addNumericField("Z maximum: ", zMax, 0); gd.addCheckbox("Use Virtual Stack", virtual); gd.addMessage("Please enter VOI or use Virtual Stack."); gd.addMessage("Starts at 1 (not zero)"); gd.showDialog(); if (gd.wasCanceled()) return null; xMin=(int)gd.getNextNumber(); xMax=(int)gd.getNextNumber(); yMin=(int)gd.getNextNumber(); yMax=(int)gd.getNextNumber(); zMin=(int)gd.getNextNumber(); zMax=(int)gd.getNextNumber(); virtual = gd.getNextBoolean(); } else virtual = false; fi.longOffset=((long)zMin-1)*(long)fi.getBytesPerPixel()*(long)fi.width*(long)fi.height; fi.nImages=zMax-(zMin-1); if (IJ.debugMode) IJ.log("DEBUG: longOffset " + Long.toString(fi.longOffset) + " nImages " + Integer.toString(fi.nImages)); return fi; } public FileInfo readHeader( String hdrfile ) throws IOException { FileInfo fi = new FileInfo(); SAXBuilder builder = new SAXBuilder(); if (IJ.debugMode) { IJ.log("Starting HSTVolReader"); } try { Document doc = builder.build(hdrfile); Element root = doc.getRootElement(); Element reconstruction = root.getChild("reconstruction"); Element listSubVolume = reconstruction.getChild("listSubVolume"); Element subVolume = listSubVolume.getChild("subVolume"); Element volName = subVolume.getChild("SUBVOLUME_NAME"); String strName = volName.getTextTrim(); IJ.showStatus("Volume: " + strName); // the next element may not exist! Element rawName = subVolume.getChild("RAW_NAME"); String strRawName = new String(); if (rawName==null) { if (IJ.debugMode) IJ.log("Probably a 32 bit volume"); fi.fileName=strName; fi.fileType=FileInfo.GRAY32_FLOAT; // presume it is 32 bit float data // check low/bigendian String volEndian = subVolume.getChild("BYTE_ORDER").getText(); if (volEndian.equals("LOWBYTEFIRST")) fi.intelByteOrder=true; else fi.intelByteOrder=false; } else { strRawName= rawName.getTextTrim(); if (IJ.debugMode) IJ.log("Filename: "+ strRawName); fi.fileName=strRawName; fi.fileType=FileInfo.GRAY8; // presume it is 8 bit uint (how to specify signage??) // assume lowendian, not relevant fi.intelByteOrder=true; } int volSizeX = Integer.parseInt(subVolume.getChild("SIZEX").getText()); int volSizeY = Integer.parseInt(subVolume.getChild("SIZEY").getText()); int volSizeZ = Integer.parseInt(subVolume.getChild("SIZEZ").getText()); fi.width=volSizeX; fi.height=volSizeY; fi.nImages=volSizeZ; } catch (JDOMException e) { IJ.showStatus("Barf"); } return fi; } }