/*
* #%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.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import loci.common.DataTools;
import loci.common.DateTools;
import loci.common.xml.BaseHandler;
import loci.formats.CoreMetadata;
import loci.formats.FormatException;
import loci.formats.FormatTools;
import loci.formats.MetadataTools;
import loci.formats.meta.MetadataStore;
import ome.units.UNITS;
import ome.units.quantity.Length;
import ome.xml.model.primitives.NonNegativeInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
/**
* DefaultHandler implementation for handling XML produced by Nikon Elements.
*/
public class ND2Handler extends BaseHandler {
// -- Constants --
private static final Logger LOGGER =
LoggerFactory.getLogger(ND2Handler.class);
private static final String DATE_FORMAT = "dd/MM/yyyy HH:mm:ss";
private static final int FIELD_INDEX = 2;
// -- Fields --
private String prefix = null;
private String prevRuntype = null;
private String prevElement = null;
private Hashtable<String, Object> metadata = new Hashtable<String, Object>();
private List<CoreMetadata> core;
private boolean isLossless;
private ArrayList<Long> zs = new ArrayList<Long>();
private ArrayList<Long> ts = new ArrayList<Long>();
private int numSeries = 0;
private double pixelSizeX, pixelSizeY, pixelSizeZ;
private Double pinholeSize, voltage, mag, na;
private String objectiveModel, immersion, correction;
private Double refractiveIndex;
private ArrayList<String> channelNames = new ArrayList<String>();
private ArrayList<String> modality = new ArrayList<String>();
private ArrayList<String> binning = new ArrayList<String>();
private ArrayList<Double> speed = new ArrayList<Double>();
private ArrayList<Double> gain = new ArrayList<Double>();
private ArrayList<Double> temperature = new ArrayList<Double>();
private ArrayList<Double> exposureTime = new ArrayList<Double>();
private ArrayList<Double> exWave = new ArrayList<Double>();
private ArrayList<Double> emWave = new ArrayList<Double>();
private ArrayList<Integer> power = new ArrayList<Integer>();
private ArrayList<Hashtable<String, String>> rois =
new ArrayList<Hashtable<String, String>>();
private ArrayList<Length> posX = new ArrayList<Length>();
private ArrayList<Length> posY = new ArrayList<Length>();
private ArrayList<Length> posZ = new ArrayList<Length>();
private ArrayList<String> posNames = new ArrayList<String>();
private String cameraModel;
private String date;
private Hashtable<String, Integer> colors = new Hashtable<String, Integer>();
private Hashtable<String, String> dyes = new Hashtable<String, String>();
private Hashtable<String, Integer> realColors =
new Hashtable<String, Integer>();
private int nXFields = 0, nYFields = 0;
private boolean populateXY = true;
private int nImages = 0;
private ArrayList<Boolean> validLoopState = new ArrayList<Boolean>();
private boolean canAdjustDimensions = true;
private boolean firstTimeLoop = true;
// -- Constructor --
public ND2Handler(List<CoreMetadata> core, int nImages) {
this(core, true, nImages);
}
public ND2Handler(List<CoreMetadata> core, boolean populateXY, int nImages) {
super();
this.populateXY = populateXY;
this.nImages = nImages;
this.core = new ArrayList<CoreMetadata>(core);
}
// -- ND2Handler API methods --
public int getXFields() {
return nXFields;
}
public List<CoreMetadata> getCoreMetadataList() {
return core;
}
public void populateROIs(MetadataStore store) {
for (int r=0; r<rois.size(); r++) {
Hashtable<String, String> roi = rois.get(r);
String type = roi.get("ROIType");
if (type.equals("Text")) {
String roiID = MetadataTools.createLSID("ROI", r);
for (int i=0; i<core.size(); i++) {
store.setImageROIRef(roiID, i, r);
}
store.setROIID(roiID, r);
store.setLabelID(MetadataTools.createLSID("Shape", r, 0), r, 0);
int fontSize = Integer.parseInt(roi.get("fHeight"));
if (fontSize >= 0) {
store.setLabelFontSize(new Length(fontSize, UNITS.PT), r, 0);
}
store.setLabelText(roi.get("eval-text"), r, 0);
Length l = new Length(new Double(roi.get("line-width")), UNITS.PIXEL);
store.setLabelStrokeWidth(l, r, 0);
String rectangle = roi.get("rectangle");
String[] p = rectangle.split(",");
double[] points = new double[p.length];
for (int i=0; i<p.length; i++) {
points[i] = Double.parseDouble(p[i]);
}
store.setLabelX(points[0], r, 0);
store.setLabelY(points[1], r, 0);
store.setRectangleID(MetadataTools.createLSID("Shape", r, 1), r, 1);
store.setRectangleX(points[0], r, 1);
store.setRectangleY(points[1], r, 1);
store.setRectangleWidth(points[2] - points[0], r, 1);
store.setRectangleHeight(points[3] - points[1], r, 1);
}
else if (type.equals("HorizontalLine") || type.equals("VerticalLine")) {
String roiID = MetadataTools.createLSID("ROI", r);
for (int i=0; i<core.size(); i++) {
store.setImageROIRef(roiID, i, r);
}
store.setROIID(roiID, r);
String segments = roi.get("segments");
segments = segments.replaceAll("\\[\\]", "");
String[] points = segments.split("\\)");
StringBuffer sb = new StringBuffer();
for (int i=0; i<points.length; i++) {
points[i] = points[i].substring(points[i].indexOf(":") + 1);
sb.append(points[i]);
if (i < points.length - 1) sb.append(" ");
}
store.setPolylineID(MetadataTools.createLSID("Shape", r, 0), r, 0);
store.setPolylinePoints(sb.toString(), r, 0);
}
}
}
public String getDate() {
return date;
}
public Hashtable<String, Object> getMetadata() {
return metadata;
}
public int getSeriesCount() {
return numSeries;
}
public boolean isLossless() {
return isLossless;
}
public ArrayList<Long> getZSections() {
return zs;
}
public ArrayList<Long> getTimepoints() {
return ts;
}
public double getPixelSizeX() {
return pixelSizeX;
}
public double getPixelSizeY() {
return pixelSizeY;
}
public double getPixelSizeZ() {
return pixelSizeZ;
}
public Double getPinholeSize() {
return pinholeSize;
}
public Double getVoltage() {
return voltage;
}
public Double getMagnification() {
return mag;
}
public Double getNumericalAperture() {
return na;
}
public String getObjectiveModel() {
return objectiveModel;
}
public String getImmersion() {
return immersion;
}
public String getCorrection() {
return correction;
}
public Double getRefractiveIndex() {
return refractiveIndex;
}
public ArrayList<String> getChannelNames() {
return channelNames;
}
public ArrayList<String> getModalities() {
return modality;
}
public ArrayList<String> getBinnings() {
return binning;
}
public ArrayList<Double> getSpeeds() {
return speed;
}
public ArrayList<Double> getGains() {
return gain;
}
public ArrayList<Double> getTemperatures() {
return temperature;
}
public ArrayList<Double> getExposureTimes() {
return exposureTime;
}
public ArrayList<Double> getExcitationWavelengths() {
return exWave;
}
public ArrayList<Double> getEmissionWavelengths() {
return emWave;
}
public ArrayList<Integer> getPowers() {
return power;
}
public ArrayList<Hashtable<String, String>> getROIs() {
return rois;
}
public ArrayList<Length> getXPositions() {
return posX;
}
public ArrayList<Length> getYPositions() {
return posY;
}
public ArrayList<Length> getZPositions() {
return posZ;
}
public ArrayList<String> getPositionNames() {
return posNames;
}
public String getCameraModel() {
return cameraModel;
}
public int getFieldIndex() {
return FIELD_INDEX;
}
public Hashtable<String, Integer> getChannelColors() {
return realColors;
}
// -- DefaultHandler API methods --
public void endElement(String uri, String localName, String qName,
Attributes attributes)
{
if (qName.equals("CalibrationSeq") || qName.equals("MetadataSeq")) {
prefix = null;
}
if (qName.equals(prevElement)) {
prevElement = null;
}
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes)
{
String runtype = attributes.getValue("runtype");
if ("CLxListVariant".equals(runtype) || "RLxIRect".equals(runtype)) {
prevElement = qName;
}
String value = attributes.getValue("value");
CoreMetadata ms0 = core.get(0);
try {
if (qName.equals("uiWidth")) {
int x = Integer.parseInt(value);
if (x != 0 && populateXY) {
ms0.sizeX = x;
}
}
else if (qName.equals("uiCamPxlCountX")) {
if (ms0.sizeX == 0 && populateXY) {
ms0.sizeX = Integer.parseInt(value);
}
}
else if (qName.equals("uiCamPxlCountY")) {
if (ms0.sizeY == 0 && populateXY) {
ms0.sizeY = Integer.parseInt(value);
}
}
else if (qName.equals("iXFields")) {
int fields = Integer.parseInt(value);
nXFields += fields;
}
else if (qName.equals("iYFields")) {
int fields = Integer.parseInt(value);
nYFields += fields;
}
else if ("rectSensorUser".equals(prevElement) && populateXY) {
if (qName.equals("left") && ms0.sizeX == 0) {
ms0.sizeX = -1 * Integer.parseInt(value);
}
else if (qName.equals("top") && ms0.sizeY == 0) {
ms0.sizeY = -1 * Integer.parseInt(value);
}
else if (qName.equals("right") && ms0.sizeX <= 0) {
ms0.sizeX += Integer.parseInt(value);
}
else if (qName.equals("bottom") && ms0.sizeY <= 0) {
ms0.sizeY += Integer.parseInt(value);
}
}
else if ("LoopState".equals(prevElement) && value != null) {
long v = Long.parseLong(value);
validLoopState.add(v != 529 && v < 0xfffff);
}
else if ("LoopSize".equals(prevElement) && value != null) {
int v = Integer.parseInt(value);
int loopIndex = 0;
while (validLoopState.get(loopIndex) == null) {
loopIndex++;
}
boolean loop = validLoopState.get(loopIndex);
if (!loop && validLoopState.contains(true)) {
v = 1;
}
if (ms0.sizeT == 0 || (ms0.sizeT * ms0.sizeZ > nImages && v < ms0.sizeT)) {
ms0.sizeT = v;
}
else if (qName.equals("no_name") && v > 1 && core.size() == 1) {
core = new ArrayList<CoreMetadata>();
for (int q=0; q<v; q++) {
core.add(ms0);
}
}
else if (ms0.sizeZ == 0) {
ms0.sizeZ = v;
}
else {
canAdjustDimensions = false;
}
ms0.dimensionOrder = "CZT";
}
else if ("pPosName".equals(prevElement) && value != null) {
posNames.add(value);
}
else if (qName.equals("FramesBefore")) {
if (ms0.sizeZ == 0) {
ms0.sizeZ = 1;
}
// only adjust if we haven't parsed all of the dimensions already
if (canAdjustDimensions && core.size() == 1 &&
(ms0.sizeT <= 1 || ms0.sizeT * ms0.sizeZ != nImages))
{
ms0.sizeZ *= Integer.parseInt(value);
}
}
else if (qName.equals("FramesAfter")) {
int loopIndex = 0;
while (validLoopState.get(loopIndex) == null) {
loopIndex++;
}
boolean loop = validLoopState.get(loopIndex);
validLoopState.set(loopIndex, null);
if (canAdjustDimensions && core.size() == 1) {
ms0.sizeZ *= Integer.parseInt(value);
if (ms0.sizeT * ms0.sizeZ > nImages &&
ms0.sizeT <= nImages &&
ms0.sizeT != ms0.sizeZ)
{
ms0.sizeZ = ms0.sizeT;
ms0.sizeT = 1;
}
}
}
else if (qName.equals("TimeBefore") && canAdjustDimensions) {
if (ms0.sizeT == 0) {
ms0.sizeT = 1;
}
ms0.sizeT *= Integer.parseInt(value);
}
else if (qName.equals("TimeAfter") && canAdjustDimensions) {
ms0.sizeT *= Integer.parseInt(value);
}
else if (qName.equals("uiMaxDst")) {
int maxPixelValue = Integer.parseInt(value) + 1;
int bits = 0;
while (maxPixelValue > 0) {
maxPixelValue /= 2;
bits++;
}
try {
if (ms0.pixelType == 0) {
ms0.pixelType =
FormatTools.pixelTypeFromBytes(bits / 8, false, false);
}
}
catch (FormatException e) {
LOGGER.warn("Could not set the pixel type", e);
}
}
else if (qName.equals("uiWidthBytes") || qName.startsWith("uiBpc")) {
int div = qName.equals("uiWidthBytes") ? ms0.sizeX : 8;
if (div > 0) {
int bits = Integer.parseInt(value);
int bytes = bits / div;
if (bytes * div == bits) {
try {
ms0.pixelType =
FormatTools.pixelTypeFromBytes(bytes, false, false);
}
catch (FormatException e) { }
}
parseKeyAndValue(qName, value, prevRuntype);
}
}
else if ("dPosX".equals(prevElement) && qName.startsWith("item_")) {
final Double number = Double.valueOf(DataTools.sanitizeDouble(value));
posX.add(new Length(number, UNITS.REFERENCEFRAME));
metadata.put("X position for position #" + posX.size(), value);
}
else if ("dPosY".equals(prevElement) && qName.startsWith("item_")) {
final Double number = Double.valueOf(DataTools.sanitizeDouble(value));
posY.add(new Length(number, UNITS.REFERENCEFRAME));
metadata.put("Y position for position #" + posY.size(), value);
}
else if ("dPosZ".equals(prevElement) && qName.startsWith("item_")) {
final Double number = Double.valueOf(DataTools.sanitizeDouble(value));
posZ.add(new Length(number, UNITS.REFERENCEFRAME));
metadata.put("Z position for position #" + posZ.size(), value);
}
else if (qName.startsWith("item_")) {
int v = Integer.parseInt(qName.substring(qName.indexOf("_") + 1));
if (v == numSeries) {
numSeries++;
}
}
else if (qName.equals("uiCompCount")) {
int v = Integer.parseInt(value);
ms0.sizeC = (int) Math.max(ms0.sizeC, v);
}
else if (qName.equals("uiHeight") && populateXY) {
int y = Integer.parseInt(value);
if (y != 0) {
ms0.sizeY = y;
}
}
else if (qName.startsWith("TextInfo")) {
parseKeyAndValue(qName, attributes.getValue("Text"), prevRuntype);
parseKeyAndValue(qName, value, prevRuntype);
}
else if (qName.equals("dCompressionParam")) {
isLossless = Double.parseDouble(value) > 0;
parseKeyAndValue(qName, value, prevRuntype);
}
else if (qName.equals("CalibrationSeq") || qName.equals("MetadataSeq")) {
prefix = qName + " " + attributes.getValue("_SEQUENCE_INDEX");
}
else if (qName.equals("HorizontalLine") || qName.equals("VerticalLine") ||
qName.equals("Text"))
{
Hashtable<String, String> roi = new Hashtable<String, String>();
roi.put("ROIType", qName);
for (int q=0; q<attributes.getLength(); q++) {
roi.put(attributes.getQName(q), attributes.getValue(q));
}
rois.add(roi);
}
else if (qName.equals("dPinholeRadius")) {
pinholeSize = new Double(DataTools.sanitizeDouble(value));
metadata.put("Pinhole size", value);
}
else if (qName.endsWith("ChannelColor")) {
String name = qName.substring(0, qName.indexOf("Channel"));
colors.put(name, new Integer(value));
}
else if (qName.endsWith("DyeName")) {
int channelIndex = qName.indexOf("Channel");
if (channelIndex < 0) channelIndex = 0;
dyes.put(qName.substring(0, channelIndex), value);
}
else if (qName.equals("uiSequenceCount")) {
int imageCount = Integer.parseInt(value);
if (core.size() > 0) {
int newCount = imageCount / core.size();
if (newCount * core.size() == imageCount) {
imageCount = newCount;
}
}
if (ms0.sizeZ * ms0.sizeT != imageCount &&
ms0.sizeZ * ms0.sizeC * ms0.sizeT != imageCount)
{
if (ms0.sizeZ > 1 && ms0.sizeT <= 1) {
ms0.sizeZ = imageCount;
ms0.sizeT = 1;
ms0.imageCount = imageCount;
}
else if (ms0.sizeT > 1 && ms0.sizeZ <= 1) {
ms0.sizeT = imageCount;
ms0.sizeZ = 1;
ms0.imageCount = imageCount;
}
else if (imageCount == 0) {
ms0.sizeT = 0;
ms0.sizeZ = 0;
ms0.imageCount = 0;
}
}
metadata.put(qName, value);
}
else {
StringBuffer sb = new StringBuffer();
if (prefix != null) {
sb.append(prefix);
sb.append(" ");
}
sb.append(qName);
parseKeyAndValue(sb.toString(), value, prevRuntype);
}
}
catch (NumberFormatException exc) {
LOGGER.warn("Could not parse {} value: {}", qName, value);
}
prevRuntype = attributes.getValue("runtype");
}
@Override
public void endDocument() {
for (String name : colors.keySet()) {
String chName = dyes.get(name);
if (chName == null) chName = name;
realColors.put(chName, colors.get(name));
}
if (nXFields > 0 && nXFields < 10 && nYFields > 0 && nYFields < 10 &&
populateXY)
{
CoreMetadata ms0 = core.get(0);
ms0.sizeX *= nXFields;
ms0.sizeY *= nYFields;
}
}
// -- Helper methods --
public void parseKeyAndValue(String key, String value, String runtype) {
if (key == null || value == null) return;
CoreMetadata ms0 = core.get(0);
metadata.put(key, value);
try {
if (key.endsWith("dCalibration")) {
pixelSizeX = Double.parseDouble(DataTools.sanitizeDouble(value));
pixelSizeY = pixelSizeX;
}
else if (key.endsWith("dZStep")) {
pixelSizeZ = Double.parseDouble(DataTools.sanitizeDouble(value));
}
else if (key.endsWith("Gain")) {
value = DataTools.sanitizeDouble(value);
if (!value.equals("")) {
gain.add(new Double(value));
}
}
else if (key.endsWith("dLampVoltage")) {
voltage = new Double(DataTools.sanitizeDouble(value));
}
else if (key.endsWith("dObjectiveMag") && mag == null) {
mag = new Double(DataTools.sanitizeDouble(value));
}
else if (key.endsWith("dObjectiveNA")) {
na = new Double(DataTools.sanitizeDouble(value));
}
else if (key.endsWith("dRefractIndex1")) {
refractiveIndex = new Double(DataTools.sanitizeDouble(value));
}
else if (key.equals("sObjective") || key.equals("wsObjectiveName") ||
key.equals("sOptics"))
{
String[] tokens = value.split(" ");
int magIndex = -1;
for (int i=0; i<tokens.length; i++) {
if (tokens[i].indexOf("x") != -1) {
magIndex = i;
break;
}
}
StringBuffer s = new StringBuffer();
for (int i=0; i<magIndex; i++) {
s.append(tokens[i]);
}
correction = s.toString();
if (magIndex >= 0) {
String m =
tokens[magIndex].substring(0, tokens[magIndex].indexOf("x"));
m = DataTools.sanitizeDouble(m);
if (m.length() > 0) {
mag = new Double(m);
}
}
if (magIndex + 1 < tokens.length) immersion = tokens[magIndex + 1];
}
else if (key.endsWith("dTimeMSec")) {
long v = (long) Double.parseDouble(DataTools.sanitizeDouble(value));
if (!ts.contains(new Long(v))) {
ts.add(new Long(v));
metadata.put("number of timepoints", ts.size());
}
}
else if (key.endsWith("dZPos")) {
long v = (long) Double.parseDouble(DataTools.sanitizeDouble(value));
if (!zs.contains(new Long(v))) {
zs.add(new Long(v));
}
}
else if (key.endsWith("uiCount")) {
if (runtype != null) {
if (runtype.endsWith("ZStackLoop")) {
if (ms0.sizeZ == 0) {
ms0.sizeZ = Integer.parseInt(value);
if (ms0.dimensionOrder.indexOf("Z") == -1) {
ms0.dimensionOrder = "Z" + ms0.dimensionOrder;
}
}
}
else if (runtype.endsWith("TimeLoop")) {
if (ms0.sizeT == 0) {
ms0.sizeT = Integer.parseInt(value);
if (ms0.dimensionOrder.indexOf("T") == -1) {
ms0.dimensionOrder = "T" + ms0.dimensionOrder;
}
}
}
else if (runtype.endsWith("XYPosLoop") && core.size() == 1) {
int len = Integer.parseInt(value);
core = new ArrayList<CoreMetadata>();
for (int i=0; i<len; i++) {
core.add(ms0);
}
}
}
}
else if (key.endsWith("uiBpcSignificant")) {
ms0.bitsPerPixel = Integer.parseInt(value);
}
else if (key.equals("VirtualComponents")) {
if (ms0.sizeC == 0) {
ms0.sizeC = Integer.parseInt(value);
if (ms0.dimensionOrder.indexOf("C") == -1) {
ms0.dimensionOrder += "C" + ms0.dimensionOrder;
}
}
}
else if (key.startsWith("TextInfoItem") || key.endsWith("TextInfoItem")) {
metadata.remove(key);
value = value.replaceAll("
", "");
value = value.replaceAll("#x000d;", "");
value = value.replaceAll("
", "\n");
value = value.replaceAll("#x000a;", "\n");
String[] tokens = value.split("\n");
for (String t : tokens) {
t = t.trim();
String[] v = t.split(":");
if (v.length == 0) {
continue;
}
else if (v.length == 2) {
parseKeyAndValue(v[0].trim(), v[1].trim(), runtype);
}
else if (v[0].equals("Line")) {
parseKeyAndValue(v[0], t.substring(t.indexOf(":") + 1).trim(), runtype);
}
else if (v.length > 1) {
v[0] = v[0].replace('{', ' ');
v[0] = v[0].replace('}', ' ');
metadata.put(v[0].trim(), v[1]);
}
else if (v.length == 1) {
metadata.put(key, v[0]);
}
}
}
else if (isDimensions(key)) {
String[] dims = value.split(" x ");
if (ms0.sizeZ == 0) ms0.sizeZ = 1;
if (ms0.sizeT == 0) ms0.sizeT = 1;
if (ms0.sizeC == 0) ms0.sizeC = 1;
for (String dim : dims) {
dim = dim.trim();
int v = Integer.parseInt(dim.replaceAll("\\D", ""));
v = (int) Math.max(v, 1);
if (dim.startsWith("XY")) {
numSeries = v;
if (numSeries > 1) {
int x = ms0.sizeX;
int y = ms0.sizeY;
int z = ms0.sizeZ;
int tSize = ms0.sizeT;
int c = ms0.sizeC;
String order = ms0.dimensionOrder;
core = new ArrayList<CoreMetadata>();
for (int i=0; i<numSeries; i++) {
CoreMetadata ms = new CoreMetadata();
core.add(ms);
ms.sizeX = x;
ms.sizeY = y;
ms.sizeZ = z == 0 ? 1 : z;
ms.sizeC = c == 0 ? 1 : c;
ms.sizeT = tSize == 0 ? 1 : tSize;
ms.dimensionOrder = order;
}
ms0 = core.get(0);
}
}
else if (dim.startsWith("T")) {
if (ms0.sizeT <= 1 || v < ms0.sizeT) {
ms0.sizeT = v;
}
}
else if (dim.startsWith("Z")) {
if (ms0.sizeZ <= 1) {
ms0.sizeZ = v;
}
}
else if (ms0.sizeC <= 1) {
ms0.sizeC = v;
}
}
ms0.imageCount = ms0.sizeZ * ms0.sizeC * ms0.sizeT;
}
else if (key.startsWith("Number of Picture Planes")) {
ms0.sizeC = Integer.parseInt(value.replaceAll("\\D", ""));
}
else if (key.equals("Name")) {
channelNames.add(value);
}
else if (key.equals("Modality")) {
modality.add(value);
}
else if (key.equals("Camera Type")) {
cameraModel = value;
}
else if (key.equals("Binning")) {
binning.add(value);
}
else if (key.equals("Readout Speed")) {
int last = value.lastIndexOf(" ");
if (last != -1) value = value.substring(0, last);
speed.add(new Double(DataTools.sanitizeDouble(value)));
}
else if (key.equals("Temperature")) {
String temp = value.replaceAll("[\\D&&[^-.]]", "");
temperature.add(new Double(DataTools.sanitizeDouble(temp)));
}
else if (key.equals("Exposure")) {
String[] s = value.trim().split(" ");
s[0] = DataTools.sanitizeDouble(s[0]);
if (s[0].trim().length() > 0) {
double time = Double.parseDouble(s[0]);
// TODO: check for other units
if (s.length > 1) {
if (s[1].equals("ms")) time /= 1000;
}
else {
// assume time is in milliseconds
time /= 1000;
}
exposureTime.add(new Double(time));
}
}
else if (key.equals("{Pinhole Size}")) {
pinholeSize = new Double(DataTools.sanitizeDouble(value));
metadata.put("Pinhole size", value);
}
else if (key.startsWith("- Step")) {
int space = key.indexOf(" ", key.indexOf("Step") + 1);
int last = key.indexOf(" ", space + 1);
if (last == -1) last = key.length();
try {
pixelSizeZ = Double.parseDouble(
DataTools.sanitizeDouble(key.substring(space, last)));
}
catch (Exception e) {
LOGGER.trace("Could not parse Z step '{}'", key, e);
}
}
else if (key.equals("Line")) {
String[] values = value.split(";");
for (int q=0; q<values.length; q++) {
int colon = values[q].indexOf(":");
if (colon < 0) continue;
String nextKey = values[q].substring(0, colon).trim();
String nextValue = values[q].substring(colon + 1).trim();
parseKeyAndValue(nextKey, nextValue, runtype);
}
}
else if (key.equalsIgnoreCase("Emission wavelength")) {
String[] v = value.split(" ");
emWave.add(new Double(v[0]));
}
else if (key.equalsIgnoreCase("Excitation wavelength")) {
String[] v = value.split(" ");
exWave.add(new Double(v[0]));
}
else if (key.equals("Power")) {
value = DataTools.sanitizeDouble(value);
power.add(new Integer((int) Double.parseDouble(value)));
}
else if (key.equals("CameraUniqueName")) {
cameraModel = value;
}
else if (key.equals("ExposureTime")) {
exposureTime.add(new Double(value) / 1000d);
}
else if (key.equals("sDate")) {
date = DateTools.formatDate(value, DATE_FORMAT);
}
else if (key.equals("Name") && channelNames.size() < ms0.sizeC) {
channelNames.add(value);
}
else if (key.equals("Z Stack Loop")) {
int v = Integer.parseInt(value);
if (v <= nImages || nImages <= 0) {
core.get(0).sizeZ = v;
}
}
else if (key.equals("Time Loop")) {
int v = Integer.parseInt(value);
if (v <= nImages && firstTimeLoop) {
core.get(0).sizeT = v;
firstTimeLoop = false;
}
}
}
catch (NumberFormatException exc) {
LOGGER.warn("Could not parse {} value: {}", key, value);
}
}
/**
* Returns whether or not the specified key is denotes dimensions.
* Full versions of Elements allow the user to choose a language,
* though it's not clear what all of the choices are.
* Most keys are always recorded in English, but some are recorded
* in the language specified by the user.
*/
public boolean isDimensions(String key) {
return key.startsWith("Dimensions") || key.startsWith("Abmessungen");
}
}