/*
* #%L
* OME Bio-Formats package for reading and converting biological file formats.
* %%
* Copyright (C) 2005 - 2015 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* 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, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/
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 loci.formats.tiff.IFD;
import loci.formats.tiff.TiffParser;
import ome.units.quantity.Length;
import ome.xml.model.primitives.PositiveFloat;
import ome.xml.model.primitives.PositiveInteger;
import ome.units.quantity.Length;
import ome.units.UNITS;
/**
* NikonTiffReader is the file format reader for Nikon TIFF files.
*/
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 Double magnification;
private double lensNA, workingDistance, pinholeSize;
private String correction, immersion;
private Vector<Double> gain;
private Vector<Double> 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) */
@Override
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) */
@Override
public void close(boolean fileOnly) throws IOException {
super.close(fileOnly);
if (!fileOnly) {
physicalSizeX = physicalSizeY = physicalSizeZ = 0;
dichroicModels = filterModels = laserIDs = null;
magnification = null;
lensNA = workingDistance = pinholeSize = 0;
correction = immersion = null;
gain = null;
wavelength = emWave = exWave = null;
}
}
// -- Internal BaseTiffReader API methods --
/* @see BaseTiffReader#initStandardMetadata() */
@Override
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<Double>();
emWave = new Vector<Double>();
exWave = new Vector<Double>();
// 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 = new Double(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 Double(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 Double(tokens[i]));
}
}
else if (key.equals("sensor s_params LambdaEm")) {
for (int i=nTokensInKey; i<tokens.length; i++) {
emWave.add(new Double(tokens[i]));
}
}
addGlobalMeta(key, value);
}
parseDimensionSizes(dimensionLabels, dimensionSizes);
}
/* @see BaseTiffReader#initMetadataStore() */
@Override
protected void initMetadataStore() throws FormatException {
super.initMetadataStore();
MetadataStore store = makeFilterMetadata();
MetadataTools.populatePixels(store, this);
if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
store.setImageDescription("", 0);
Length sizeX = FormatTools.getPhysicalSizeX(physicalSizeX);
Length sizeY = FormatTools.getPhysicalSizeY(physicalSizeY);
Length sizeZ = FormatTools.getPhysicalSizeZ(physicalSizeZ);
if (sizeX != null) {
store.setPixelsPhysicalSizeX(sizeX, 0);
}
if (sizeY != null) {
store.setPixelsPhysicalSizeY(sizeY, 0);
}
if (sizeZ != null) {
store.setPixelsPhysicalSizeZ(sizeZ, 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.setObjectiveSettingsID(objectiveID, 0);
store.setObjectiveNominalMagnification(magnification, 0, 0);
if (correction == null) correction = "Other";
store.setObjectiveCorrection(getCorrection(correction), 0, 0);
store.setObjectiveLensNA(lensNA, 0, 0);
store.setObjectiveWorkingDistance(new Length(workingDistance, UNITS.MICROM), 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);
Length wave = FormatTools.getWavelength(wavelength.get(i));
if (wave != null) {
store.setLaserWavelength(wave, 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(new Length(pinholeSize, UNITS.MICROM), 0, c);
if (c < exWave.size()) {
Length wave = FormatTools.getExcitationWavelength(exWave.get(c));
if (wave != null) {
store.setChannelExcitationWavelength(wave, 0, c);
}
}
if (c < emWave.size()) {
Length wave = FormatTools.getEmissionWavelength(emWave.get(c));
if (wave != null) {
store.setChannelEmissionWavelength(wave, 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]);
}
}
}
}