// // NikonTiffReader.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.Vector; import loci.common.RandomAccessInputStream; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.meta.MetadataStore; import ome.xml.model.primitives.PositiveFloat; import loci.formats.tiff.IFD; import loci.formats.tiff.TiffParser; import ome.xml.model.primitives.PositiveInteger; /** * NikonTiffReader is the file format reader for Nikon TIFF 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/NikonTiffReader.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/NikonTiffReader.java;hb=HEAD">Gitweb</a></dd></dl> */ public class NikonTiffReader extends BaseTiffReader { // -- Constants -- private static final String[] TOP_LEVEL_KEYS = new String[] { "document document", "document", "history Acquisition", "history objective", "history history", "history laser", "history step", "history", "sensor s_params", "sensor", "view" }; // -- Fields -- private double physicalSizeX, physicalSizeY, physicalSizeZ; private Vector<String> filterModels, dichroicModels, laserIDs; private int magnification; private double lensNA, workingDistance, pinholeSize; private String correction, immersion; private Vector<Double> gain; private Vector<Integer> wavelength, emWave, exWave; // -- Constructor -- public NikonTiffReader() { super("Nikon TIFF", new String[] {"tif", "tiff"}); suffixSufficient = false; domains = new String[] {FormatTools.LM_DOMAIN}; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ public boolean isThisType(RandomAccessInputStream stream) throws IOException { TiffParser tp = new TiffParser(stream); IFD ifd = tp.getFirstIFD(); if (ifd == null) return false; String software = ifd.getIFDTextValue(IFD.SOFTWARE); return software != null && software.toString().indexOf("EZ-C1") != -1; } /* @see loci.formats.IFormatReader#close(boolean) */ public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { physicalSizeX = physicalSizeY = physicalSizeZ = 0; dichroicModels = filterModels = laserIDs = null; magnification = 0; lensNA = workingDistance = pinholeSize = 0; correction = immersion = null; gain = null; wavelength = emWave = exWave = null; } } // -- Internal BaseTiffReader API methods -- /* @see BaseTiffReader#initStandardMetadata() */ protected void initStandardMetadata() throws FormatException, IOException { super.initStandardMetadata(); if (getMetadataOptions().getMetadataLevel() == MetadataLevel.MINIMUM) { return; } filterModels = new Vector<String>(); dichroicModels = new Vector<String>(); laserIDs = new Vector<String>(); gain = new Vector<Double>(); wavelength = new Vector<Integer>(); emWave = new Vector<Integer>(); exWave = new Vector<Integer>(); // parse key/value pairs in the comment String comment = ifds.get(0).getComment(); metadata.remove("Comment"); String[] lines = comment.split("\n"); StringBuffer k = null, v = null; String[] dimensionLabels = null, dimensionSizes = null; for (String line : lines) { String[] tokens = line.split("\t"); line = line.replaceAll("\t", " "); int nTokensInKey = 0; for (String key : TOP_LEVEL_KEYS) { if (line.startsWith(key)) { nTokensInKey = key.indexOf(" ") != -1 ? 3 : 2; break; } } k = new StringBuffer(); for (int i=0; i<nTokensInKey; i++) { k.append(tokens[i]); if (i < nTokensInKey - 1) k.append(" "); } v = new StringBuffer(); for (int i=nTokensInKey; i<tokens.length; i++) { v.append(tokens[i]); if (i < tokens.length - 1) v.append(" "); } String key = k.toString(); String value = v.toString(); if (key.equals("document label")) { dimensionLabels = value.toLowerCase().split(" "); } else if (key.equals("document scale")) { dimensionSizes = value.split(" "); } else if (key.startsWith("history Acquisition") && key.indexOf("Filter") != -1) { filterModels.add(value); } else if (key.startsWith("history Acquisition") && key.indexOf("Dichroic") != -1) { dichroicModels.add(value); } else if (key.equals("history objective Type")) { correction = value; } else if (key.equals("history objective Magnification")) { magnification = (int) Double.parseDouble(value); } else if (key.equals("history objective NA")) { lensNA = Double.parseDouble(value); } else if (key.equals("history objective WorkingDistance")) { workingDistance = Double.parseDouble(value); } else if (key.equals("history objective Immersion")) { immersion = value; } else if (key.startsWith("history gain")) { gain.add(new Double(value)); } else if (key.equals("history pinhole")) { pinholeSize = new Double(value.substring(0, value.indexOf(" "))); } else if (key.startsWith("history laser") && key.endsWith("wavelength")) { wavelength.add(new Integer(value.replaceAll("\\D", ""))); } else if (key.startsWith("history laser") && key.endsWith("name")) { laserIDs.add(value); } else if (key.equals("sensor s_params LambdaEx")) { for (int i=nTokensInKey; i<tokens.length; i++) { exWave.add(new Integer(tokens[i])); } } else if (key.equals("sensor s_params LambdaEm")) { for (int i=nTokensInKey; i<tokens.length; i++) { emWave.add(new Integer(tokens[i])); } } addGlobalMeta(key, value); } parseDimensionSizes(dimensionLabels, dimensionSizes); } /* @see BaseTiffReader#initMetadataStore() */ protected void initMetadataStore() throws FormatException { super.initMetadataStore(); MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { store.setImageDescription("", 0); if (physicalSizeX > 0) { store.setPixelsPhysicalSizeX(new PositiveFloat(physicalSizeX), 0); } if (physicalSizeY > 0) { store.setPixelsPhysicalSizeY(new PositiveFloat(physicalSizeY), 0); } if (physicalSizeZ > 0) { store.setPixelsPhysicalSizeZ(new PositiveFloat(physicalSizeZ), 0); } String instrumentID = MetadataTools.createLSID("Instrument", 0); store.setInstrumentID(instrumentID, 0); store.setImageInstrumentRef(instrumentID, 0); String objectiveID = MetadataTools.createLSID("Objective", 0, 0); store.setObjectiveID(objectiveID, 0, 0); store.setImageObjectiveSettingsID(objectiveID, 0); if (magnification > 0) { store.setObjectiveNominalMagnification( new PositiveInteger(magnification), 0, 0); } if (correction == null) correction = "Other"; store.setObjectiveCorrection(getCorrection(correction), 0, 0); store.setObjectiveLensNA(lensNA, 0, 0); store.setObjectiveWorkingDistance(workingDistance, 0, 0); if (immersion == null) immersion = "Other"; store.setObjectiveImmersion(getImmersion(immersion), 0, 0); for (int i=0; i<wavelength.size(); i++) { String laser = MetadataTools.createLSID("LightSource", 0, i); store.setLaserID(laser, 0, i); store.setLaserModel(laserIDs.get(i), 0, i); store.setLaserWavelength(new PositiveInteger(wavelength.get(i)), 0, i); store.setLaserType(getLaserType("Other"), 0, i); store.setLaserLaserMedium(getLaserMedium("Other"), 0, i); } for (int i=0; i<gain.size(); i++) { store.setDetectorID(MetadataTools.createLSID("Detector", 0, i), 0, i); store.setDetectorGain(gain.get(i), 0, i); store.setDetectorType(getDetectorType("Other"), 0, i); } for (int c=0; c<getEffectiveSizeC(); c++) { store.setChannelPinholeSize(pinholeSize, 0, c); if (c < exWave.size()) { store.setChannelExcitationWavelength( new PositiveInteger(exWave.get(c)), 0, c); } if (c < emWave.size()) { store.setChannelEmissionWavelength( new PositiveInteger(emWave.get(c)), 0, c); } } for (int i=0; i<filterModels.size(); i++) { String filter = MetadataTools.createLSID("Filter", 0, i); store.setFilterID(filter, 0, i); store.setFilterModel(filterModels.get(i), 0, i); } for (int i=0; i<dichroicModels.size(); i++) { String dichroic = MetadataTools.createLSID("Dichroic", 0, i); store.setDichroicID(dichroic, 0, i); store.setDichroicModel(dichroicModels.get(i), 0, i); } } } // -- Helper methods -- private void parseDimensionSizes(String[] labels, String[] sizes) { for (int i=0; i<labels.length; i++) { if (labels[i].startsWith("z")) { physicalSizeZ = Double.parseDouble(sizes[i]); } else if (labels[i].equals("x")) { physicalSizeX = Double.parseDouble(sizes[i]); } else if (labels[i].equals("y")) { physicalSizeY = Double.parseDouble(sizes[i]); } } } }