/*
* #%L
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2005 - 2015 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package loci.formats.in;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Vector;
import loci.common.DataTools;
import loci.common.DateTools;
import loci.common.Location;
import loci.common.RandomAccessInputStream;
import loci.common.xml.BaseHandler;
import loci.common.xml.XMLTools;
import loci.formats.CoreMetadata;
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;
import ome.xml.model.primitives.Timestamp;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import ome.units.quantity.ElectricPotential;
import ome.units.quantity.Length;
import ome.units.quantity.Temperature;
import ome.units.quantity.Time;
import ome.units.UNITS;
/**
* MicromanagerReader is the file format reader for Micro-Manager files.
*/
public class MicromanagerReader extends FormatReader {
// -- Constants --
public static final String DATE_FORMAT = "EEE MMM dd HH:mm:ss zzz yyyy";
/** File containing extra metadata. */
private static final String METADATA = "metadata.txt";
/**
* Optional file containing additional acquisition parameters.
* (And yes, the spelling is correct.)
*/
private static final String XML = "Acqusition.xml";
// -- Fields --
/** Helper reader for TIFF files. */
private MinimalTiffReader tiffReader;
private Vector<Position> positions;
// -- Constructor --
/** Constructs a new Micromanager reader. */
public MicromanagerReader() {
super("Micro-Manager", new String[] {"tif", "tiff", "txt", "xml"});
domains = new String[] {FormatTools.LM_DOMAIN};
hasCompanionFiles = true;
datasetDescription = "A 'metadata.txt' file plus or or more .tif files";
}
// -- IFormatReader API methods --
/* @see loci.formats.IFormatReader#isSingleFile(String) */
@Override
public boolean isSingleFile(String id) throws FormatException, IOException {
return false;
}
/* @see loci.formats.IFormatReader#isThisType(String, boolean) */
@Override
public boolean isThisType(String name, boolean open) {
if (!open) return false; // not allowed to touch the file system
if (name.equals(METADATA) || name.endsWith(File.separator + METADATA) ||
name.equals(XML) || name.endsWith(File.separator + XML))
{
final int blockSize = 1048576;
try {
RandomAccessInputStream stream = new RandomAccessInputStream(name);
long length = stream.length();
String data = stream.readString((int) Math.min(blockSize, length));
stream.close();
return length > 0 && (data.indexOf("Micro-Manager") >= 0 ||
data.indexOf("micromanager") >= 0);
}
catch (IOException e) {
return false;
}
}
else if (!isGroupFiles()) {
// if file grouping was disabled, allow each of the TIFFs to be
// read separately; this will have no effect if the metadata file
// is chosen
return false;
}
try {
Location parent = new Location(name).getAbsoluteFile().getParentFile();
Location metaFile = new Location(parent, METADATA);
RandomAccessInputStream s = new RandomAccessInputStream(name);
boolean validTIFF = isThisType(s);
s.close();
return validTIFF && isThisType(metaFile.getAbsolutePath(), open);
}
catch (NullPointerException e) { }
catch (IOException e) { }
return false;
}
/* @see loci.formats.IFormatReader#fileGroupOption(String) */
@Override
public int fileGroupOption(String id) throws FormatException, IOException {
return FormatTools.MUST_GROUP;
}
/* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */
@Override
public boolean isThisType(RandomAccessInputStream stream) throws IOException
{
if (tiffReader == null) tiffReader = new MinimalTiffReader();
return tiffReader.isThisType(stream);
}
/* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */
@Override
public String[] getSeriesUsedFiles(boolean noPixels) {
FormatTools.assertId(currentId, true, 1);
Vector<String> files = new Vector<String>();
for (Position pos : positions) {
files.add(pos.metadataFile);
if (pos.xmlFile != null) {
files.add(pos.xmlFile);
}
if (!noPixels) {
for (String tiff : pos.tiffs) {
if (new Location(tiff).exists()) {
files.add(tiff);
}
}
}
}
return files.toArray(new String[files.size()]);
}
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
@Override
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);
String file = positions.get(getSeries()).getFile(
getDimensionOrder(), getSizeZ(), getSizeC(), getSizeT(),
getImageCount(), no);
if (file != null && new Location(file).exists()) {
tiffReader.setId(file);
return tiffReader.openBytes(0, buf, x, y, w, h);
}
LOGGER.warn("File for image #{} ({}) is missing.", no, file);
return buf;
}
/* @see loci.formats.IFormatReader#close(boolean) */
@Override
public void close(boolean fileOnly) throws IOException {
super.close(fileOnly);
if (tiffReader != null) tiffReader.close(fileOnly);
if (!fileOnly) {
positions = null;
}
}
/* @see loci.formats.IFormatReader#getOptimalTileWidth() */
@Override
public int getOptimalTileWidth() {
FormatTools.assertId(currentId, true, 1);
if (tiffReader.getCurrentFile() == null) {
setupReader();
}
return tiffReader.getOptimalTileWidth();
}
/* @see loci.formats.IFormatReader#getOptimalTileHeight() */
@Override
public int getOptimalTileHeight() {
FormatTools.assertId(currentId, true, 1);
if (tiffReader.getCurrentFile() == null) {
setupReader();
}
return tiffReader.getOptimalTileHeight();
}
// -- Internal FormatReader API methods --
/* @see loci.formats.FormatReader#initFile(String) */
@Override
public void initFile(String id) throws FormatException, IOException {
super.initFile(id);
tiffReader = new MinimalTiffReader();
positions = new Vector<Position>();
LOGGER.info("Reading metadata file");
// find metadata.txt
Location file = new Location(currentId).getAbsoluteFile();
Location parentFile = file.getParentFile();
String metadataFile = METADATA;
if (file.exists()) {
metadataFile = new Location(parentFile, METADATA).getAbsolutePath();
// look for other positions
if (parentFile.getName().indexOf("Pos_") >= 0) {
parentFile = parentFile.getParentFile();
String[] dirs = parentFile.list(true);
Arrays.sort(dirs);
for (String dir : dirs) {
if (dir.indexOf("Pos_") >= 0) {
Position pos = new Position();
Location posDir = new Location(parentFile, dir);
pos.metadataFile = new Location(posDir, METADATA).getAbsolutePath();
positions.add(pos);
}
}
}
else {
Position pos = new Position();
pos.metadataFile = metadataFile;
positions.add(pos);
}
}
int seriesCount = positions.size();
core.clear();
for (int i=0; i<seriesCount; i++) {
core.add(new CoreMetadata());
setSeries(i);
parsePosition(i);
}
setSeries(0);
populateMetadata();
}
private void populateMetadata() throws FormatException, IOException {
MetadataStore store = makeFilterMetadata();
MetadataTools.populatePixels(store, this, true);
String instrumentID = MetadataTools.createLSID("Instrument", 0);
store.setInstrumentID(instrumentID, 0);
for (int i=0; i<positions.size(); i++) {
Position p = positions.get(i);
if (p.time != null) {
String date = DateTools.formatDate(p.time, DATE_FORMAT);
if (date != null) {
store.setImageAcquisitionDate(new Timestamp(date), i);
}
}
if (positions.size() > 1) {
Location parent = new Location(p.metadataFile).getParentFile();
store.setImageName(parent.getName(), i);
}
if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
store.setImageDescription(p.comment, i);
// link Instrument and Image
store.setImageInstrumentRef(instrumentID, i);
for (int c=0; c<p.channels.length; c++) {
store.setChannelName(p.channels[c], i, c);
}
Length sizeX = FormatTools.getPhysicalSizeX(p.pixelSize);
Length sizeY = FormatTools.getPhysicalSizeY(p.pixelSize);
Length sizeZ = FormatTools.getPhysicalSizeZ(p.sliceThickness);
if (sizeX != null) {
store.setPixelsPhysicalSizeX(sizeX, i);
}
if (sizeY != null) {
store.setPixelsPhysicalSizeY(sizeY, i);
}
if (sizeZ != null) {
store.setPixelsPhysicalSizeZ(sizeZ, i);
}
int nextStamp = 0;
for (int q=0; q<getImageCount(); q++) {
store.setPlaneExposureTime(p.exposureTime, i, q);
String tiff = positions.get(getSeries()).getFile(q);
if (tiff != null && new Location(tiff).exists() &&
nextStamp < p.timestamps.length &&
p.timestamps[nextStamp] != null)
{
store.setPlaneDeltaT(new Time(p.timestamps[nextStamp++], UNITS.MS), i, q);
}
}
String serialNumber = p.detectorID;
p.detectorID = MetadataTools.createLSID("Detector", 0, i);
for (int c=0; c<p.channels.length; c++) {
store.setDetectorSettingsBinning(getBinning(p.binning), i, c);
store.setDetectorSettingsGain(new Double(p.gain), i, c);
if (c < p.voltage.size()) {
store.setDetectorSettingsVoltage(
new ElectricPotential(p.voltage.get(c), UNITS.V), i, c);
}
store.setDetectorSettingsID(p.detectorID, i, c);
}
store.setDetectorID(p.detectorID, 0, i);
if (p.detectorModel != null) {
store.setDetectorModel(p.detectorModel, 0, i);
}
if (serialNumber != null) {
store.setDetectorSerialNumber(serialNumber, 0, i);
}
if (p.detectorManufacturer != null) {
store.setDetectorManufacturer(p.detectorManufacturer, 0, i);
}
if (p.cameraMode == null) p.cameraMode = "Other";
store.setDetectorType(getDetectorType(p.cameraMode), 0, i);
store.setImagingEnvironmentTemperature(
new Temperature(p.temperature, UNITS.DEGREEC), i);
}
}
}
public void populateMetadataStore(String[] jsonData)
throws FormatException, IOException
{
FormatTools.assertId(currentId, false, 1);
currentId = "in-memory-json";
core.clear();
positions = new Vector<Position>();
for (int pos=0; pos<jsonData.length; pos++) {
core.add(new CoreMetadata());
Position p = new Position();
p.metadataFile = "Position #" + (pos + 1);
positions.add(p);
setSeries(pos);
parsePosition(jsonData[pos], pos);
}
setSeries(0);
populateMetadata();
}
// -- Helper methods --
private void parsePosition(int posIndex) throws IOException, FormatException {
Position p = positions.get(posIndex);
String s = DataTools.readFile(p.metadataFile);
parsePosition(s, posIndex);
buildTIFFList(posIndex);
}
private void buildTIFFList(int posIndex) throws FormatException {
Position p = positions.get(posIndex);
CoreMetadata ms = core.get(posIndex);
String parent = new Location(p.metadataFile).getParent();
LOGGER.info("Finding image file names");
// find the name of a TIFF file
p.tiffs = new Vector<String>();
// build list of TIFF files
buildTIFFList(posIndex, parent + File.separator + p.baseTiff);
if (p.tiffs.size() == 0) {
Vector<String> uniqueZ = new Vector<String>();
Vector<String> uniqueC = new Vector<String>();
Vector<String> uniqueT = new Vector<String>();
Location dir =
new Location(p.metadataFile).getAbsoluteFile().getParentFile();
String[] files = dir.list(true);
Arrays.sort(files);
for (String f : files) {
if (checkSuffix(f, "tif") || checkSuffix(f, "tiff")) {
String[] blocks = f.split("_");
if (!uniqueT.contains(blocks[1])) uniqueT.add(blocks[1]);
if (!uniqueC.contains(blocks[2])) uniqueC.add(blocks[2]);
if (!uniqueZ.contains(blocks[3])) uniqueZ.add(blocks[3]);
p.tiffs.add(new Location(dir, f).getAbsolutePath());
}
}
ms.sizeZ = uniqueZ.size();
ms.sizeC = uniqueC.size();
ms.sizeT = uniqueT.size();
if (p.tiffs.size() == 0) {
throw new FormatException("Could not find TIFF files.");
}
}
}
private void parsePosition(String jsonData, int posIndex)
throws IOException, FormatException
{
Position p = positions.get(posIndex);
CoreMetadata ms = core.get(posIndex);
String parent = new Location(p.metadataFile).getParent();
// now parse the rest of the metadata
// metadata.txt looks something like this:
//
// {
// "Section Name": {
// "Key": "Value",
// "Array key": [
// first array value, second array value
// ]
// }
//
// }
LOGGER.info("Populating metadata");
Vector<Double> stamps = new Vector<Double>();
p.voltage = new Vector<Double>();
StringTokenizer st = new StringTokenizer(jsonData, "\n");
int[] slice = new int[3];
while (st.hasMoreTokens()) {
String token = st.nextToken().trim();
boolean open = token.indexOf("[") != -1;
boolean closed = token.indexOf("]") != -1;
if (open || (!open && !closed && !token.equals("{") &&
!token.startsWith("}")))
{
int quote = token.indexOf("\"") + 1;
String key = token.substring(quote, token.indexOf("\"", quote));
String value = null;
if (open == closed) {
value = token.substring(token.indexOf(":") + 1);
}
else if (!closed) {
StringBuffer valueBuffer = new StringBuffer();
while (!closed) {
token = st.nextToken();
closed = token.indexOf("]") != -1;
valueBuffer.append(token);
}
value = valueBuffer.toString();
value = value.replaceAll("\n", "");
}
if (value == null) continue;
int startIndex = value.indexOf("[");
int endIndex = value.indexOf("]");
if (endIndex == -1) endIndex = value.length();
value = value.substring(startIndex + 1, endIndex).trim();
if (value.length() == 0) {
continue;
}
value = value.substring(0, value.length() - 1);
value = value.replaceAll("\"", "");
if (value.endsWith(",")) value = value.substring(0, value.length() - 1);
addSeriesMeta(key, value);
if (key.equals("Channels")) {
ms.sizeC = Integer.parseInt(value);
}
else if (key.equals("ChNames")) {
p.channels = value.split(",");
for (int q=0; q<p.channels.length; q++) {
p.channels[q] = p.channels[q].replaceAll("\"", "").trim();
}
}
else if (key.equals("Frames")) {
ms.sizeT = Integer.parseInt(value);
}
else if (key.equals("Slices")) {
ms.sizeZ = Integer.parseInt(value);
}
else if (key.equals("PixelSize_um")) {
p.pixelSize = new Double(value);
}
else if (key.equals("z-step_um")) {
p.sliceThickness = new Double(value);
}
else if (key.equals("Time")) {
p.time = value;
}
else if (key.equals("Comment")) {
p.comment = value;
}
else if (key.equals("FileName")) {
p.fileNameMap.put(new Index(slice), value);
if (p.baseTiff == null) {
p.baseTiff = value;
}
}
else if (key.equals("Width")) {
ms.sizeX = Integer.parseInt(value);
}
else if (key.equals("Height")) {
ms.sizeY = Integer.parseInt(value);
}
else if (key.equals("IJType")) {
int type = Integer.parseInt(value);
switch (type) {
case 0:
ms.pixelType = FormatTools.UINT8;
break;
case 1:
ms.pixelType = FormatTools.UINT16;
break;
default:
throw new FormatException("Unknown type: " + type);
}
}
}
if (token.startsWith("\"FrameKey")) {
int dash = token.indexOf("-") + 1;
int nextDash = token.indexOf("-", dash);
slice[2] = Integer.parseInt(token.substring(dash, nextDash));
dash = nextDash + 1;
nextDash = token.indexOf("-", dash);
slice[1] = Integer.parseInt(token.substring(dash, nextDash));
dash = nextDash + 1;
slice[0] = Integer.parseInt(token.substring(dash,
token.indexOf("\"", dash)));
token = st.nextToken().trim();
String key = "", value = "";
boolean valueArray = false;
int nestedCount = 0;
while (!token.startsWith("}") || nestedCount > 0) {
if (token.trim().endsWith("{")) {
nestedCount++;
token = st.nextToken().trim();
continue;
}
else if (token.trim().startsWith("}")) {
nestedCount--;
token = st.nextToken().trim();
continue;
}
if (valueArray) {
if (token.trim().equals("],")) {
valueArray = false;
}
else {
value += token.trim().replaceAll("\"", "");
token = st.nextToken().trim();
continue;
}
}
else {
int colon = token.indexOf(":");
key = token.substring(1, colon).trim();
value = token.substring(colon + 1, token.length() - 1).trim();
key = key.replaceAll("\"", "");
value = value.replaceAll("\"", "");
if (token.trim().endsWith("[")) {
valueArray = true;
token = st.nextToken().trim();
continue;
}
}
addSeriesMeta(key, value);
if (key.equals("Exposure-ms")) {
p.exposureTime = new Time(Double.valueOf(value), UNITS.MS);
}
else if (key.equals("ElapsedTime-ms")) {
stamps.add(Double.valueOf(value));
}
else if (key.equals("Core-Camera")) p.cameraRef = value;
else if (key.equals(p.cameraRef + "-Binning")) {
if (value.indexOf("x") != -1) p.binning = value;
else p.binning = value + "x" + value;
}
else if (key.equals(p.cameraRef + "-CameraID")) p.detectorID = value;
else if (key.equals(p.cameraRef + "-CameraName")) {
p.detectorModel = value;
}
else if (key.equals(p.cameraRef + "-Gain")) {
p.gain = (int) Double.parseDouble(value);
}
else if (key.equals(p.cameraRef + "-Name")) {
p.detectorManufacturer = value;
}
else if (key.equals(p.cameraRef + "-Temperature")) {
p.temperature = Double.parseDouble(value);
}
else if (key.equals(p.cameraRef + "-CCDMode")) {
p.cameraMode = value;
}
else if (key.startsWith("DAC-") && key.endsWith("-Volts")) {
p.voltage.add(new Double(value));
}
else if (key.equals("FileName")) {
p.fileNameMap.put(new Index(slice), value);
if (p.baseTiff == null) {
p.baseTiff = value;
}
}
token = st.nextToken().trim();
}
}
}
p.timestamps = stamps.toArray(new Double[stamps.size()]);
Arrays.sort(p.timestamps);
// look for the optional companion XML file
if (new Location(parent, XML).exists()) {
p.xmlFile = new Location(parent, XML).getAbsolutePath();
parseXMLFile();
}
if (getSizeZ() == 0) ms.sizeZ = 1;
if (getSizeT() == 0) ms.sizeT = 1;
ms.dimensionOrder = "XYZCT";
ms.interleaved = false;
ms.rgb = false;
ms.littleEndian = false;
ms.imageCount = getSizeZ() * getSizeC() * getSizeT();
ms.indexed = false;
ms.falseColor = false;
ms.metadataComplete = true;
}
/**
* Populate the list of TIFF files using the given file name as a pattern.
*/
private void buildTIFFList(int posIndex, String baseTiff) {
LOGGER.info("Building list of TIFFs");
Position p = positions.get(posIndex);
String prefix = "";
if (baseTiff.indexOf(File.separator) != -1) {
prefix = baseTiff.substring(0, baseTiff.lastIndexOf(File.separator) + 1);
baseTiff = baseTiff.substring(baseTiff.lastIndexOf(File.separator) + 1);
}
String[] blocks = baseTiff.split("_");
StringBuffer filename = new StringBuffer();
for (int t=0; t<getSizeT(); t++) {
for (int c=0; c<getSizeC(); c++) {
for (int z=0; z<getSizeZ(); z++) {
// file names are of format:
// img_<T>_<channel name>_<T>.tif
filename.append(prefix);
if (!prefix.endsWith(File.separator) &&
!blocks[0].startsWith(File.separator))
{
filename.append(File.separator);
}
filename.append(blocks[0]);
filename.append("_");
int zeros = blocks[1].length() - String.valueOf(t).length();
for (int q=0; q<zeros; q++) {
filename.append("0");
}
filename.append(t);
filename.append("_");
String prechannel = filename.toString();
if (blocks[2].length() > 0) {
String channel = p.channels[c];
if (channel.indexOf("-") != -1) {
channel = channel.substring(0, channel.indexOf("-"));
}
filename.append(channel);
}
filename.append("_");
zeros = blocks[3].length() - String.valueOf(z).length() - 4;
for (int q=0; q<zeros; q++) {
filename.append("0");
}
filename.append(z);
filename.append(".tif");
if (!new Location(filename.toString()).exists() &&
blocks[2].length() > 0)
{
// rewind and try using the full channel name
filename = new StringBuffer(prechannel);
String channel = p.channels[c];
filename.append(channel);
filename.append("_");
zeros = blocks[3].length() - String.valueOf(z).length() - 4;
for (int q=0; q<zeros; q++) {
filename.append("0");
}
filename.append(z);
filename.append(".tif");
}
p.tiffs.add(filename.toString());
filename.delete(0, filename.length());
}
}
}
// adjust timepoint count, if needed
// acquisitions can be stopped part-way through, but this isn't always
// noted in the metadata
int firstEmptyTimepoint = -1;
int nextFile = 0;
for (int t=0; t<getSizeT(); t++) {
boolean emptyTimepoint = true;
for (int c=0; c<getSizeC(); c++) {
for (int z=0; z<getSizeZ(); z++) {
String file = p.tiffs.get(nextFile++);
if (new Location(file).exists()) {
emptyTimepoint = false;
break;
}
}
if (!emptyTimepoint) {
break;
}
}
if (emptyTimepoint && firstEmptyTimepoint < 0) {
firstEmptyTimepoint = t;
}
else if (!emptyTimepoint && firstEmptyTimepoint >= 0) {
firstEmptyTimepoint = -1;
}
}
if (firstEmptyTimepoint >= 0) {
int imageCount = getImageCount() / getSizeT();
core.get(posIndex).sizeT = firstEmptyTimepoint;
core.get(posIndex).imageCount = imageCount * getSizeT();
}
}
/** Parse metadata values from the Acqusition.xml file. */
private void parseXMLFile() throws IOException {
Position p = positions.get(getSeries());
String xmlData = DataTools.readFile(p.xmlFile);
xmlData = XMLTools.sanitizeXML(xmlData);
DefaultHandler handler = new MicromanagerHandler();
XMLTools.parseXML(xmlData, handler);
}
/** Initialize the TIFF reader with the first file in the current series. */
private void setupReader() {
try {
String file = positions.get(getSeries()).getFile(
getDimensionOrder(), getSizeZ(), getSizeC(), getSizeT(),
getImageCount(), 0);
tiffReader.setId(file);
}
catch (Exception e) {
LOGGER.warn("", e);
}
}
// -- Helper classes --
/** SAX handler for parsing Acqusition.xml. */
class MicromanagerHandler extends BaseHandler {
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes)
{
if (qName.equals("entry")) {
String key = attributes.getValue("key");
String value = attributes.getValue("value");
addSeriesMeta(key, value);
}
}
}
class Position {
public String baseTiff;
public Vector<String> tiffs;
public HashMap<Index, String> fileNameMap = new HashMap<Index, String>();
public String metadataFile;
public String xmlFile;
public String[] channels;
public String comment, time;
public Time exposureTime;
public Double sliceThickness, pixelSize;
public Double[] timestamps;
public int gain;
public String binning, detectorID, detectorModel, detectorManufacturer;
public double temperature;
public Vector<Double> voltage;
public String cameraRef;
public String cameraMode;
public String getFile(int no) {
return getFile(getDimensionOrder(), getSizeZ(), getSizeC(), getSizeT(),
getImageCount(), no);
}
public String getFile(String order, int z, int c, int t, int count, int no)
{
int[] zct = FormatTools.getZCTCoords(order, z, c, t, count, no);
for (Index key : fileNameMap.keySet()) {
if (key.z == zct[0] && key.c == zct[1] && key.t == zct[2]) {
String file = fileNameMap.get(key);
if (tiffs != null) {
for (String tiff : tiffs) {
if (tiff.endsWith(File.separator + file)) {
return tiff;
}
}
}
}
}
return fileNameMap.size() == 0 ? tiffs.get(no) : null;
}
}
class Index {
public int z;
public int c;
public int t;
public Index(int[] zct) {
z = zct[0];
c = zct[1];
t = zct[2];
}
}
}