/* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.conrad.io; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import edu.stanford.rsl.conrad.utils.CONRAD; import ij.IJ; import ij.io.FileInfo; public class NRRDProjectionSource extends FileProjectionSource { public final String uint8Types="uchar, unsigned char, uint8, uint8_t"; public final String int16Types="short, short int, signed short, signed short int, int16, int16_t"; public final String uint16Types="ushort, unsigned short, unsigned short int, uint16, uint16_t"; public final String int32Types="int, signed int, int32, int32_t"; public final String uint32Types="uint, unsigned int, uint32, uint32_t"; private String notes = ""; private boolean detachedHeader=false; protected String headerPath=null; protected String imagePath=null; protected String imageName=null; public void initStream (String filename) throws IOException { fi = getHeaderInfo(filename); if (fi!=null && fi.width>0 && fi.height>0) { init(); } else { throw new IOException("Format does not match: width = " + fi.width + " height = " + fi.height + " offset = " + fi.offset); } } public FileInfo getHeaderInfo( String filename ) throws IOException { if (IJ.debugMode) CONRAD.log("Entering Nrrd_Reader.readHeader():"); FileInfo fi = new FileInfo(); File file = new File(filename); fi.fileName=file.getName(); fi.directory = file.getParent() + "/"; // NB Need RAF in order to ensure that we know file offset RandomAccessFile input = new RandomAccessFile(fi.directory+fi.fileName,"r"); String thisLine,noteType,noteValue, noteValuelc; fi.fileType = FileInfo.GRAY8; // just assume this for the mo fi.fileFormat = FileInfo.RAW; fi.nImages = 1; int dimension = 0; // parse the header file, until reach an empty line// boolean keepReading=true; while(true) { thisLine=input.readLine(); if(thisLine==null || thisLine.equals("")) { if(!detachedHeader) fi.longOffset = input.getFilePointer(); break; } notes+=thisLine+"\n"; if(thisLine.indexOf("#")==0) continue; // ignore comments noteType=getFieldPart(thisLine,0).toLowerCase(); // case irrelevant noteValue=getFieldPart(thisLine,1); noteValuelc=noteValue.toLowerCase(); String firstNoteValue=getSubField(thisLine,0); if (IJ.debugMode) CONRAD.log("NoteType:"+noteType+", noteValue:"+noteValue); if (noteType.equals("data file")||noteType.equals("datafile")) { // This is a detached header file // There are 3 kinds of specification for the data files // 1. data file: <filename> // 2. data file: <format> <min> <max> <step> [<subdim>] // 3. data file: LIST [<subdim>] if(firstNoteValue.equals("LIST")) { // TOFIX - type 3 throw new IOException("Nrrd_Reader: not yet able to handle datafile: LIST specifications"); } else if(!getSubField(thisLine,1).equals("")) { // TOFIX - type 2 throw new IOException("Nrrd_Reader: not yet able to handle datafile: sprintf file specifications"); } else { // Type 1 specification File imageFile; // Relative or absolute if(noteValue.indexOf("/")==0) { // absolute imageFile=new File(noteValue); // TOFIX could also check local directory if absolute path given // but dir does not exist } else { //CONRAD.log("fi.directory = "+fi.directory); imageFile=new File(fi.directory,noteValue); } //CONRAD.log("image file ="+imageFile); if(imageFile.exists()) { fi.directory=imageFile.getParent(); fi.fileName=imageFile.getName(); imagePath=imageFile.getPath(); detachedHeader=true; } else { throw new IOException("Unable to find image file ="+imageFile.getPath()); } } } if (noteType.equals("dimension")) { dimension=Integer.valueOf(noteValue).intValue(); if(dimension>3) throw new IOException("Nrrd_Reader: Dimension>3 not yet implemented!"); } if (noteType.equals("sizes")) { for(int i=0;i<dimension;i++) { int integer =Integer.valueOf(getSubField(thisLine,i)).intValue(); if(i==0) fi.width=integer; if(i==1) fi.height=integer; if(i==2) fi.nImages=integer; } } if (noteType.equals("type")) { if (uint8Types.indexOf(noteValuelc)>=0) { fi.fileType=FileInfo.GRAY8; } else if(uint16Types.indexOf(noteValuelc)>=0) { fi.fileType=FileInfo.GRAY16_SIGNED; } else if(int16Types.indexOf(noteValuelc)>=0) { fi.fileType=FileInfo.GRAY16_UNSIGNED; } else if(uint32Types.indexOf(noteValuelc)>=0) { fi.fileType=FileInfo.GRAY32_UNSIGNED; } else if(int32Types.indexOf(noteValuelc)>=0) { fi.fileType=FileInfo.GRAY32_INT; } else if(noteValuelc.equals("float")) { fi.fileType=FileInfo.GRAY32_FLOAT; } else if(noteValuelc.equals("double")) { fi.fileType=FileInfo.GRAY64_FLOAT; } else { throw new IOException("Unimplemented data type ="+noteValue); } } if (noteType.equals("byte skip")||noteType.equals("byteskip")) fi.longOffset=Long.valueOf(noteValue).longValue(); if (noteType.equals("endian")) { if(noteValuelc.equals("little")) { fi.intelByteOrder = true; } else { fi.intelByteOrder = false; } } if (noteType.equals("encoding")) { if(noteValuelc.equals("gz")) noteValuelc="gzip"; //fi.encoding=noteValuelc; } } if(!detachedHeader) fi.longOffset = input.getFilePointer(); input.close(); return (fi); } String getFieldPart(String str, int fieldIndex) { str=str.trim(); // trim the string String[] fieldParts=str.split(":\\s+"); if(fieldParts.length<2) return(fieldParts[0]); //CONRAD.log("field = "+fieldParts[0]+"; value = "+fieldParts[1]+"; fieldIndex = "+fieldIndex); if(fieldIndex==0) return fieldParts[0]; else return fieldParts[1]; } String getSubField(String str, int fieldIndex) { String fieldDescriptor=getFieldPart(str,1); fieldDescriptor=fieldDescriptor.trim(); // trim the string if (IJ.debugMode) CONRAD.log("fieldDescriptor = "+fieldDescriptor+"; fieldIndex = "+fieldIndex); String[] fields_values=fieldDescriptor.split("\\s+"); if (fieldIndex>=fields_values.length) { return ""; } else { String rval=fields_values[fieldIndex]; if(rval.startsWith("\"")) rval=rval.substring(1); if(rval.endsWith("\"")) rval=rval.substring(0, rval.length()-1); return rval; } } }