// // VarianFDFReader.java // /* OME Bio-Formats package for reading and converting biological file formats. Copyright (C) 2005-@year@ UW-Madison LOCI and Glencoe Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package loci.formats.in; import java.io.IOException; import java.util.Arrays; import java.util.Vector; import loci.common.Location; import loci.common.RandomAccessInputStream; import loci.formats.FormatException; import loci.formats.FormatReader; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.meta.MetadataStore; import ome.xml.model.primitives.PositiveFloat; /** * VarianFDFReader is the file format reader for Varian FDF files. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/in/VarianFDFReader.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/VarianFDFReader.java;hb=HEAD">Gitweb</a></dd></dl> */ public class VarianFDFReader extends FormatReader { // -- Fields -- private Vector<String> files = new Vector<String>(); private long[] pixelOffsets; private double pixelSizeX; private double pixelSizeY; private double pixelSizeZ; private double originX; private double originY; private double originZ; private String[] units; // -- Constructor -- /** Constructs a new Varian FDF reader. */ public VarianFDFReader() { super("Varian FDF", "fdf"); domains = new String[] {FormatTools.MEDICAL_DOMAIN}; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ public boolean isThisType(RandomAccessInputStream stream) throws IOException { return false; } /** * @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */ public String[] getSeriesUsedFiles(boolean noPixels) { if (noPixels) return null; if (files.size() == 0) return new String[] {currentId}; return files.toArray(new String[files.size()]); } /** * @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int) */ public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) throws FormatException, IOException { FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h); if (files.size() > 1) { in = new RandomAccessInputStream(files.get(no)); in.order(isLittleEndian()); } in.seek(pixelOffsets[no]); readPlane(in, x, y, w, h, buf); int bpp = FormatTools.getBytesPerPixel(getPixelType()); byte[] rowBuf = new byte[w * bpp]; for (int row=0; row<h/2; row++) { int src = row * rowBuf.length; int dest = (h - row - 1) * rowBuf.length; System.arraycopy(buf, src, rowBuf, 0, rowBuf.length); System.arraycopy(buf, dest, buf, src, rowBuf.length); System.arraycopy(rowBuf, 0, buf, dest, rowBuf.length); } if (files.size() > 1) { in.close(); } return buf; } /* @see loci.formats.IFormatReader#close(boolean) */ public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { pixelOffsets = null; files.clear(); pixelSizeX = 0d; pixelSizeY = 0d; pixelSizeZ = 0d; originX = 0d; originY = 0d; originZ = 0d; units = null; } } // -- Internal FormatReader API methods -- /* @see loci.formats.FormatReader#initFile(String) */ protected void initFile(String id) throws FormatException, IOException { super.initFile(id); core[0].sizeZ = 1; core[0].sizeC = 1; core[0].sizeT = 1; parseFDF(id); core[0].imageCount = getSizeZ() * getSizeC() * getSizeT(); core[0].dimensionOrder = "XYTZC"; if (files.size() > getImageCount()) { int rem = files.size() / getImageCount(); core[0].sizeT *= rem; core[0].imageCount = getSizeZ() * getSizeC() * getSizeT(); } pixelOffsets = new long[getImageCount()]; int planeSize = FormatTools.getPlaneSize(this); for (int i=0; i<pixelOffsets.length; i++) { if (files.size() > 1) { in.close(); in = new RandomAccessInputStream(files.get(i)); pixelOffsets[i] = in.length() - planeSize; } else { pixelOffsets[i] = in.length() - (planeSize * (getImageCount() - i)); } } boolean minMetadata = getMetadataOptions().getMetadataLevel() == MetadataLevel.MINIMUM; MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this, !minMetadata); if (!minMetadata) { if (pixelSizeX > 0) { store.setPixelsPhysicalSizeX(new PositiveFloat(pixelSizeX), 0); } if (pixelSizeY > 0) { store.setPixelsPhysicalSizeY(new PositiveFloat(pixelSizeY), 0); } if (pixelSizeZ > 0) { store.setPixelsPhysicalSizeZ(new PositiveFloat(pixelSizeZ), 0); } for (int i=0; i<getImageCount(); i++) { store.setPlanePositionX(originX, 0, i); store.setPlanePositionY(originY, 0, i); store.setPlanePositionZ(originZ, 0, i); } } } // -- Helper methods -- private void parseFDF(String file) throws FormatException, IOException { in = new RandomAccessInputStream(file); boolean storedFloats = false; boolean multifile = false; while (true) { String line = in.readLine().trim(); if (line.length() == 0) break; if (line.startsWith("#")) continue; int space = line.indexOf(" "); int eq = line.indexOf("="); String type = line.substring(0, space).trim(); String var = line.substring(space, eq).trim(); String value = line.substring(eq + 1, line.indexOf(";")).trim(); if (var.equals("*storage")) { storedFloats = value.equals("\"float\""); } if (var.equals("bits")) { core[0].bitsPerPixel = Integer.parseInt(value); if (value.equals("8")) { core[0].pixelType = FormatTools.UINT8; } else if (value.equals("16")) { core[0].pixelType = FormatTools.UINT16; } else if (value.equals("32")) { if (storedFloats) { core[0].pixelType = FormatTools.FLOAT; } else core[0].pixelType = FormatTools.UINT32; } else throw new FormatException("Unsupported bits: " + value); } else if (var.equals("matrix[]")) { String[] values = parseArray(value); core[0].sizeX = (int) Double.parseDouble(values[0]); core[0].sizeY = (int) Double.parseDouble(values[1]); if (values.length > 2) { core[0].sizeZ = (int) Double.parseDouble(values[2]); } } else if (var.equals("slices")) { core[0].sizeZ = Integer.parseInt(value); multifile = true; } else if (var.equals("echoes")) { core[0].sizeT = Integer.parseInt(value); multifile = true; } else if (var.equals("span[]")) { String[] values = parseArray(value); if (values.length > 0) { pixelSizeX = computePhysicalSize(getSizeX(), values[0], units[0]); } if (values.length > 1) { pixelSizeY = computePhysicalSize(getSizeY(), values[1], units[1]); } if (values.length > 2) { pixelSizeZ = computePhysicalSize(getSizeZ(), values[2], units[2]); } } else if (var.equals("origin[]")) { String[] values = parseArray(value); if (values.length > 0) { originX = computePhysicalSize(1, values[0], units[0]); addGlobalMeta("X position for position #1", originX); } if (values.length > 1) { originY = computePhysicalSize(1, values[1], units[1]); addGlobalMeta("Y position for position #1", originY); } if (values.length > 2) { originZ = computePhysicalSize(1, values[2], units[2]); addGlobalMeta("Z position for position #1", originZ); } } else if (var.equals("*abscissa[]")) { units = parseArray(value); } else if (var.equals("bigendian")) { core[0].littleEndian = value.equals("0"); in.order(isLittleEndian()); } addGlobalMeta(var, value); } if (multifile && files.size() == 0) { Location thisFile = new Location(file).getAbsoluteFile(); Location parent = thisFile.getParentFile(); String[] list = parent.list(true); Arrays.sort(list); for (String f : list) { if (checkSuffix(f, "fdf") && f.length() == thisFile.getName().length()) { files.add(new Location(parent, f).getAbsolutePath()); } } } } /** Split a String that represents an array into individual elements. */ private String[] parseArray(String value) { value = value.replaceAll("[{}]", ""); String[] values = value.split(","); for (int i=0; i<values.length; i++) { values[i] = values[i].replaceAll("\"", ""); values[i] = values[i].trim(); } return values; } /** * Return the physical size of a pixel, in microns, along an arbitrary axis * based on the supplied physical and pixel lengths of the axis. * * @param length the length, in pixels, of the axis * @param physicalLength the length, in physical units of the axis * @param unit the units for the physical length * @return the size, in microns, of a pixel */ private double computePhysicalSize( int length, String physicalLength, String unit) { double size = Double.parseDouble(physicalLength) / length; if (unit.equals("cm")) { size *= 1000; } return size; } }