// // InCellReader.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.File; import java.io.IOException; import java.util.Hashtable; import java.util.Vector; import loci.common.DataTools; import loci.common.Location; import loci.common.RandomAccessInputStream; 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.NonNegativeInteger; import ome.xml.model.primitives.PositiveInteger; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; /** * InCellReader is the file format reader for InCell 1000/2000 datasets. * * <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/InCellReader.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/InCellReader.java;hb=HEAD">Gitweb</a></dd></dl> * * @author Melissa Linkert melissa at glencoesoftware.com */ public class InCellReader extends FormatReader { // -- Constants -- public static final String INCELL_MAGIC_STRING = "IN Cell Analyzer"; private static final String[] PIXELS_SUFFIXES = new String[] {"tif", "tiff", "im"}; private static final String[] METADATA_SUFFIXES = new String[] {"xml", "xlog"}; // -- Fields -- private boolean[][] plateMap; private Image[][][][] imageFiles; private MinimalTiffReader tiffReader; private Vector<Integer> emWaves, exWaves; private Vector<String> channelNames; private int totalImages; private int imageWidth, imageHeight; private String creationDate; private String rowName = "A", colName = "1"; private int fieldCount; private int wellRows, wellCols; private Hashtable<Integer, int[]> wellCoordinates; private Vector<Double> posX, posY; private boolean[][] exclude; private Vector<Integer> channelsPerTimepoint; private boolean oneTimepointPerSeries; private int totalChannels; private Vector<String> metadataFiles; // -- Constructor -- /** Constructs a new InCell 1000/2000 reader. */ public InCellReader() { super("InCell 1000/2000", new String[] {"xdce", "xml", "tiff", "tif", "xlog", "im"}); suffixSufficient = false; domains = new String[] {FormatTools.HCS_DOMAIN}; hasCompanionFiles = true; datasetDescription = "One .xdce file with at least one .tif/.tiff or " + ".im file"; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(String, boolean) */ public boolean isThisType(String name, boolean open) { if (checkSuffix(name, "xdce") || checkSuffix(name, "xml")) { return super.isThisType(name, open); } return false; } /* @see loci.formats.IFormatReader#isSingleFile(String) */ public boolean isSingleFile(String id) throws FormatException, IOException { return false; } /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ public boolean isThisType(RandomAccessInputStream stream) throws IOException { final int blockLen = 2048; if (!FormatTools.validStream(stream, blockLen, false)) return false; String check = stream.readString(blockLen); return check.indexOf(INCELL_MAGIC_STRING) >= 0; } /* @see loci.formats.IFormatReader#fileGroupOption(String) */ public int fileGroupOption(String id) throws FormatException, IOException { return FormatTools.MUST_GROUP; } /* @see loci.formats.IFormatReader#get8BitLookupTable() */ public byte[][] get8BitLookupTable() throws FormatException, IOException { FormatTools.assertId(currentId, true, 1); return tiffReader == null ? null : tiffReader.get8BitLookupTable(); } /* @see loci.formats.IFormatReader#get16BitLookupTable() */ public short[][] get16BitLookupTable() throws FormatException, IOException { FormatTools.assertId(currentId, true, 1); return tiffReader == null ? null : tiffReader.get16BitLookupTable(); } /** * @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); int[] coordinates = getZCTCoords(no); int well = getWellFromSeries(getSeries()); int field = getFieldFromSeries(getSeries()); int timepoint = oneTimepointPerSeries ? getSeries() % channelsPerTimepoint.size() : coordinates[2]; int image = getIndex(coordinates[0], coordinates[1], 0); if (imageFiles[well][field][timepoint][image] == null) return buf; String filename = imageFiles[well][field][timepoint][image].filename; if (filename == null || !(new Location(filename).exists())) return buf; if (imageFiles[well][field][timepoint][image].isTiff) { try { tiffReader.setId(filename); return tiffReader.openBytes(0, buf, x, y, w, h); } catch (FormatException e) { LOGGER.debug("", e); } catch (IOException e) { LOGGER.debug("", e); } return buf; } // pixels are stored in .im files RandomAccessInputStream s = new RandomAccessInputStream(filename); if (s.length() > FormatTools.getPlaneSize(this)) { s.seek(128); readPlane(s, x, y, w, h, buf); } s.close(); return buf; } /* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */ public String[] getSeriesUsedFiles(boolean noPixels) { FormatTools.assertId(currentId, true, 1); Vector<String> files = new Vector<String>(); files.addAll(metadataFiles); if (!noPixels && imageFiles != null) { int well = getWellFromSeries(getSeries()); int field = getFieldFromSeries(getSeries()); for (Image[] timepoints : imageFiles[well][field]) { for (Image plane : timepoints) { if (plane != null && plane.filename != null) { if (new Location(plane.filename).exists()) { files.add(plane.filename); } if (new Location(plane.thumbnailFile).exists()) { files.add(plane.thumbnailFile); } } } } } if (!files.contains(currentId)) { files.add(currentId); } return files.toArray(new String[files.size()]); } /* @see loci.formats.IFormatReader#close(boolean) */ public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (tiffReader != null) tiffReader.close(fileOnly); if (!fileOnly) { imageFiles = null; tiffReader = null; totalImages = 0; emWaves = exWaves = null; channelNames = null; wellCoordinates = null; posX = null; posY = null; creationDate = null; wellRows = wellCols = 0; fieldCount = 0; exclude = null; metadataFiles = null; imageWidth = imageHeight = 0; rowName = "A"; colName = "1"; channelsPerTimepoint = null; oneTimepointPerSeries = false; totalChannels = 0; plateMap = null; } } /* @see loci.formats.IFormatReader#getOptimalTileWidth() */ public int getOptimalTileWidth() { FormatTools.assertId(currentId, true, 1); if (imageFiles[0][0][0][0].isTiff) { return tiffReader.getOptimalTileWidth(); } return super.getOptimalTileWidth(); } /* @see loci.formats.IFormatReader#getOptimalTileHeight() */ public int getOptimalTileHeight() { FormatTools.assertId(currentId, true, 1); if (imageFiles[0][0][0][0].isTiff) { return tiffReader.getOptimalTileHeight(); } return super.getOptimalTileHeight(); } // -- Internal FormatReader API methods -- /* @see loci.formats.FormatReader#initFile(String) */ protected void initFile(String id) throws FormatException, IOException { // make sure that we have the .xdce (or .xml) file if (checkSuffix(id, PIXELS_SUFFIXES) || checkSuffix(id, "xlog")) { Location currentFile = new Location(id).getAbsoluteFile(); Location parent = currentFile.getParentFile(); String[] list = parent.list(true); for (String f : list) { if (checkSuffix(f, new String[] {"xdce", "xml"})) { String path = new Location(parent, f).getAbsolutePath(); if (isThisType(path)) { // make sure that the .xdce file references the current file // this ensures that the correct file is chosen if multiple // .xdce files are the same directory String data = DataTools.readFile(path); if (data.indexOf(currentFile.getName()) >= 0) { id = path; break; } } } } } super.initFile(id); in = new RandomAccessInputStream(id); channelNames = new Vector<String>(); emWaves = new Vector<Integer>(); exWaves = new Vector<Integer>(); channelsPerTimepoint = new Vector<Integer>(); metadataFiles = new Vector<String>(); // build list of companion files Location directory = new Location(id).getAbsoluteFile().getParentFile(); String[] files = directory.list(true); for (String file : files) { if (checkSuffix(file, METADATA_SUFFIXES)) { metadataFiles.add(new Location(directory, file).getAbsolutePath()); } } // parse metadata from the .xdce or .xml file wellCoordinates = new Hashtable<Integer, int[]>(); posX = new Vector<Double>(); posY = new Vector<Double>(); byte[] b = new byte[(int) in.length()]; in.read(b); core[0].dimensionOrder = "XYZCT"; MetadataStore store = makeFilterMetadata(); DefaultHandler handler = new MinimalInCellHandler(); XMLTools.parseXML(b, handler); if (getSizeZ() == 0) core[0].sizeZ = 1; if (getSizeC() == 0) core[0].sizeC = 1; if (getSizeT() == 0) core[0].sizeT = 1; int seriesCount = 0; if (exclude != null) { for (int row=0; row<wellRows; row++) { for (int col=0; col<wellCols; col++) { if (!exclude[row][col]) { seriesCount += imageFiles[row*wellCols + col].length; } } } int expectedSeries = totalImages / (getSizeZ() * getSizeC() * getSizeT()); seriesCount = (int) Math.min(seriesCount, expectedSeries); } else seriesCount = totalImages / (getSizeZ() * getSizeC() * getSizeT()); totalChannels = getSizeC(); oneTimepointPerSeries = false; for (int i=1; i<channelsPerTimepoint.size(); i++) { if (!channelsPerTimepoint.get(i).equals(channelsPerTimepoint.get(i - 1))) { oneTimepointPerSeries = true; break; } } if (oneTimepointPerSeries) { int imageCount = 0; for (Integer timepoint : channelsPerTimepoint) { imageCount += timepoint.intValue() * getSizeZ(); } seriesCount = (totalImages / imageCount) * getSizeT(); } int sizeT = getSizeT(); int sizeC = getSizeC(); int z = getSizeZ(); int t = oneTimepointPerSeries ? 1 : getSizeT(); core = new CoreMetadata[seriesCount]; for (int i=0; i<seriesCount; i++) { int c = oneTimepointPerSeries ? channelsPerTimepoint.get(i % sizeT).intValue() : sizeC; core[i] = new CoreMetadata(); core[i].sizeZ = z; core[i].sizeC = c; core[i].sizeT = t; core[i].imageCount = z * c * t; core[i].dimensionOrder = "XYZCT"; } int wellIndex = getWellFromSeries(0); int fieldIndex = getFieldFromSeries(0); String filename = imageFiles[wellIndex][fieldIndex][0][0].filename; boolean isTiff = imageFiles[wellIndex][fieldIndex][0][0].isTiff; if (isTiff && filename != null) { tiffReader = new MinimalTiffReader(); tiffReader.setId(filename); int nextTiming = 0; for (int i=0; i<seriesCount; i++) { core[i].sizeX = tiffReader.getSizeX(); core[i].sizeY = tiffReader.getSizeY(); core[i].interleaved = tiffReader.isInterleaved(); core[i].indexed = tiffReader.isIndexed(); core[i].rgb = tiffReader.isRGB(); core[i].pixelType = tiffReader.getPixelType(); core[i].littleEndian = tiffReader.isLittleEndian(); } } else { for (int i=0; i<seriesCount; i++) { core[i].sizeX = imageWidth; core[i].sizeY = imageHeight; core[i].interleaved = false; core[i].indexed = false; core[i].rgb = false; core[i].pixelType = FormatTools.UINT16; core[i].littleEndian = true; } } MetadataTools.populatePixels(store, this, true); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { handler = new InCellHandler(store); XMLTools.parseXML(b, handler); } String rowNaming = Character.isDigit(rowName.charAt(0)) ? "Number" : "Letter"; String colNaming = Character.isDigit(colName.charAt(0)) ? "Number" : "Letter"; String plateName = currentId; int begin = plateName.lastIndexOf(File.separator) + 1; int end = plateName.lastIndexOf("."); plateName = plateName.substring(begin, end); store.setPlateID(MetadataTools.createLSID("Plate", 0), 0); store.setPlateName(plateName, 0); store.setPlateRowNamingConvention(getNamingConvention(rowNaming), 0); store.setPlateColumnNamingConvention(getNamingConvention(colNaming), 0); for (int r=0; r<wellRows; r++) { for (int c=0; c<wellCols; c++) { int well = r * wellCols + c; String wellID = MetadataTools.createLSID("Well", 0, well); store.setWellID(wellID, 0, well); store.setWellRow(new NonNegativeInteger(r), 0, well); store.setWellColumn(new NonNegativeInteger(c), 0, well); } } String plateAcqID = MetadataTools.createLSID("PlateAcquisition", 0, 0); store.setPlateAcquisitionID(plateAcqID, 0, 0); store.setPlateAcquisitionMaximumFieldCount( new PositiveInteger(fieldCount), 0, 0); // populate Image data String instrumentID = MetadataTools.createLSID("Instrument", 0); String experimentID = MetadataTools.createLSID("Experiment", 0); store.setInstrumentID(instrumentID, 0); store.setExperimentID(experimentID, 0); for (int i=0; i<seriesCount; i++) { int well = getWellFromSeries(i); int field = getFieldFromSeries(i) + 1; int totalTimepoints = oneTimepointPerSeries ? channelsPerTimepoint.size() : 1; int timepoint = oneTimepointPerSeries ? (i % totalTimepoints) + 1 : -1; String imageID = MetadataTools.createLSID("Image", i); store.setImageID(imageID, i); store.setImageInstrumentRef(instrumentID, i); store.setImageExperimentRef(experimentID, i); int wellRow = well / wellCols; int wellCol = well % wellCols; char rowChar = rowName.charAt(rowName.length() - 1); char colChar = colName.charAt(colName.length() - 1); String row = rowName.substring(0, rowName.length() - 1); String col = colName.substring(0, colName.length() - 1); if (Character.isDigit(rowChar)) { row += wellRow + Integer.parseInt(String.valueOf(rowChar)); } else row += (char) (rowChar + wellRow); if (Character.isDigit(colChar)) { col += wellCol + Integer.parseInt(String.valueOf(colChar)); } else col += (char) (colChar + wellCol); String imageName = "Well " + row + "-" + col + ", Field #" + field; if (timepoint >= 0) { imageName += ", Timepoint #" + timepoint; } store.setImageName(imageName, i); store.setImageAcquiredDate(creationDate, i); timepoint--; if (timepoint < 0) timepoint = 0; int sampleIndex = (field - 1) * totalTimepoints + timepoint; String wellSampleID = MetadataTools.createLSID("WellSample", 0, well, sampleIndex); store.setWellSampleID(wellSampleID, 0, well, sampleIndex); store.setWellSampleIndex(new NonNegativeInteger(i), 0, well, sampleIndex); store.setWellSampleImageRef(imageID, 0, well, sampleIndex); if (field < posX.size()) { store.setWellSamplePositionX(posX.get(field), 0, well, sampleIndex); } if (field < posY.size()) { store.setWellSamplePositionY(posY.get(field), 0, well, sampleIndex); } store.setPlateAcquisitionWellSampleRef(wellSampleID, 0, 0, i); } if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { // populate PlaneTiming data for (int i=0; i<seriesCount; i++) { int well = getWellFromSeries(i); int field = getFieldFromSeries(i); int timepoint = oneTimepointPerSeries ? i % channelsPerTimepoint.size() : 0; for (int time=0; time<getSizeT(); time++) { if (!oneTimepointPerSeries) timepoint = time; int c = channelsPerTimepoint.get(timepoint).intValue(); for (int q=0; q<getSizeZ()*c; q++) { Image img = imageFiles[well][field][timepoint][q]; if (img == null) continue; int plane = time * getSizeZ() * c + q; store.setPlaneDeltaT(img.deltaT, i, plane); store.setPlaneExposureTime(img.exposure, i, plane); store.setPlanePositionX(posX.get(field), i, plane); store.setPlanePositionY(posY.get(field), i, plane); store.setPlanePositionZ(img.zPosition, i, plane); } } } // populate LogicalChannel data for (int i=0; i<seriesCount; i++) { setSeries(i); for (int q=0; q<getEffectiveSizeC(); q++) { if (q < channelNames.size()) { store.setChannelName(channelNames.get(q), i, q); } if (q < emWaves.size()) { int wave = emWaves.get(q).intValue(); if (wave > 0) { store.setChannelEmissionWavelength( new PositiveInteger(wave), i, q); } } if (q < exWaves.size()) { int wave = exWaves.get(q).intValue(); if (wave > 0) { store.setChannelExcitationWavelength( new PositiveInteger(wave), i, q); } } } } setSeries(0); // populate Plate data store.setPlateWellOriginX(0.5, 0); store.setPlateWellOriginY(0.5, 0); } } // -- Helper methods -- private int getFieldFromSeries(int series) { if (oneTimepointPerSeries) series /= channelsPerTimepoint.size(); return series % fieldCount; } private int getWellFromSeries(int series) { if (oneTimepointPerSeries) series /= channelsPerTimepoint.size(); int well = series / fieldCount; int counter = -1; for (int row=0; row<plateMap.length; row++) { for (int col=0; col<plateMap[row].length; col++) { if (plateMap[row][col]) { counter++; } if (counter == well) { return row * wellCols + col; } } } return -1; } // -- Helper classes -- class MinimalInCellHandler extends DefaultHandler { private String currentImageFile; private String currentThumbnail; private int wellRow, wellCol; private int nChannels = 0; public void endElement(String uri, String localName, String qName) { if (qName.equals("PlateMap")) { int sizeT = getSizeT(); if (sizeT == 0) { // There has been no <TimeSchedule> in the <PlateMap> defined to // populate channelsPerTimepoint so we have to assume that there is // only one timepoint otherwise the imageFiles array below will not // be correctly initialized. sizeT = 1; } if (channelsPerTimepoint.size() == 0) { // There has been no <TimeSchedule> in the <PlateMap> defined to // populate channelsPerTimepoint so we have to assume that all // channels are being acquired. channelsPerTimepoint.add(core[0].sizeC); } imageFiles = new Image[wellRows * wellCols][fieldCount][sizeT][]; for (int well=0; well<wellRows*wellCols; well++) { for (int field=0; field<fieldCount; field++) { for (int t=0; t<sizeT; t++) { int channels = channelsPerTimepoint.get(t).intValue(); imageFiles[well][field][t] = new Image[channels * getSizeZ()]; } } } } else if (qName.equals("TimePoint")) { channelsPerTimepoint.add(new Integer(nChannels)); nChannels = 0; } else if (qName.equals("Times")) { if (channelsPerTimepoint.size() == 0) { channelsPerTimepoint.add(new Integer(getSizeC())); } for (int i=0; i<channelsPerTimepoint.size(); i++) { int c = channelsPerTimepoint.get(i).intValue(); if (c == 0) { channelsPerTimepoint.setElementAt(new Integer(getSizeC()), i); } } } } public void startElement(String uri, String localName, String qName, Attributes attributes) { if (qName.equals("Plate")) { wellRows = Integer.parseInt(attributes.getValue("rows")); wellCols = Integer.parseInt(attributes.getValue("columns")); plateMap = new boolean[wellRows][wellCols]; } else if (qName.equals("Exclude")) { if (exclude == null) exclude = new boolean[wellRows][wellCols]; int row = Integer.parseInt(attributes.getValue("row")) - 1; int col = Integer.parseInt(attributes.getValue("col")) - 1; exclude[row][col] = true; } else if (qName.equals("Images")) { totalImages = Integer.parseInt(attributes.getValue("number")); } else if (qName.equals("Image")) { String file = attributes.getValue("filename"); String thumb = attributes.getValue("thumbnail"); Location current = new Location(currentId).getAbsoluteFile(); Location imageFile = new Location(current.getParentFile(), file); currentImageFile = imageFile.getAbsolutePath(); currentThumbnail = new Location(current.getParentFile(), thumb).getAbsolutePath(); } else if (qName.equals("Identifier")) { int field = Integer.parseInt(attributes.getValue("field_index")); int z = Integer.parseInt(attributes.getValue("z_index")); int c = Integer.parseInt(attributes.getValue("wave_index")); int t = Integer.parseInt(attributes.getValue("time_index")); int channels = channelsPerTimepoint.get(t).intValue(); int index = FormatTools.getIndex("XYZCT", getSizeZ(), channels, 1, getSizeZ() * channels, z, c, 0); Image img = new Image(); img.thumbnailFile = currentThumbnail; Location file = new Location(currentImageFile); img.filename = file.exists() ? currentImageFile : null; if (img.filename == null) { LOGGER.warn("{} does not exist.", currentImageFile); } currentImageFile = currentImageFile.toLowerCase(); img.isTiff = currentImageFile.endsWith(".tif") || currentImageFile.endsWith(".tiff"); imageFiles[wellRow * wellCols + wellCol][field][t][index] = img; } else if (qName.equals("offset_point")) { fieldCount++; } else if (qName.equals("TimePoint")) { core[0].sizeT++; } else if (qName.equals("Wavelength")) { String fusion = attributes.getValue("fusion_wave"); if (fusion.equals("false")) core[0].sizeC++; } else if (qName.equals("AcqWave")) { nChannels++; } else if (qName.equals("ZDimensionParameters")) { String nz = attributes.getValue("number_of_slices"); if (nz != null) { core[0].sizeZ = Integer.parseInt(nz); } else core[0].sizeZ = 1; } else if (qName.equals("Row")) { wellRow = Integer.parseInt(attributes.getValue("number")) - 1; } else if (qName.equals("Column")) { wellCol = Integer.parseInt(attributes.getValue("number")) - 1; plateMap[wellRow][wellCol] = true; } else if (qName.equals("Size")) { imageWidth = Integer.parseInt(attributes.getValue("width")); imageHeight = Integer.parseInt(attributes.getValue("height")); } else if (qName.equals("NamingRows")) { rowName = attributes.getValue("begin"); } else if (qName.equals("NamingColumns")) { colName = attributes.getValue("begin"); } } } /** SAX handler for parsing XML. */ class InCellHandler extends DefaultHandler { private String currentQName; private boolean openImage; private int nextEmWave = 0; private int nextExWave = 0; private MetadataStore store; private int nextPlate = 0; private int currentRow = -1, currentCol = -1; private int currentField = 0; private int currentImage, currentPlane; private Double timestamp, exposure, zPosition; private String channelName = null; public InCellHandler(MetadataStore store) { this.store = store; } public void characters(char[] ch, int start, int length) { String value = new String(ch, start, length); if (currentQName.equals("UserComment")) { store.setImageDescription(value, 0); } } public void endElement(String uri, String localName, String qName) { if (qName.equals("Image")) { wellCoordinates.put(new Integer(currentField), new int[] {currentRow, currentCol}); openImage = false; int well = currentRow * wellCols + currentCol; Image img = imageFiles[well][currentField][currentImage][currentPlane]; if (img != null) { img.deltaT = timestamp; img.exposure = exposure; } } else if (qName.equals("Wavelength")) { channelName = null; } } public void startElement(String uri, String localName, String qName, Attributes attributes) { currentQName = qName; for (int i=0; i<attributes.getLength(); i++) { addGlobalMeta(qName + " - " + attributes.getQName(i), attributes.getValue(i)); } if (qName.equals("Microscopy")) { String experimentID = MetadataTools.createLSID("Experiment", 0); store.setExperimentID(experimentID, 0); try { store.setExperimentType( getExperimentType(attributes.getValue("type")), 0); } catch (FormatException e) { LOGGER.warn("", e); } } else if (qName.equals("Image")) { openImage = true; double time = Double.parseDouble(attributes.getValue("acquisition_time_ms")); timestamp = new Double(time / 1000); } else if (qName.equals("Identifier")) { currentField = Integer.parseInt(attributes.getValue("field_index")); int z = Integer.parseInt(attributes.getValue("z_index")); int c = Integer.parseInt(attributes.getValue("wave_index")); int t = Integer.parseInt(attributes.getValue("time_index")); currentImage = t; currentPlane = z * getSizeC() + c; int well = currentRow * wellCols + currentCol; Image img = imageFiles[well][currentField][currentImage][currentPlane]; img.zPosition = zPosition; } else if (qName.equals("FocusPosition")) { zPosition = new Double(attributes.getValue("z")); } else if (qName.equals("Creation")) { String date = attributes.getValue("date"); // yyyy-mm-dd String time = attributes.getValue("time"); // hh:mm:ss creationDate = date + "T" + time; } else if (qName.equals("ObjectiveCalibration")) { store.setObjectiveNominalMagnification(new PositiveInteger((int) Double.parseDouble(attributes.getValue("magnification"))), 0, 0); store.setObjectiveLensNA(new Double( attributes.getValue("numerical_aperture")), 0, 0); try { store.setObjectiveImmersion(getImmersion("Other"), 0, 0); } catch (FormatException e) { LOGGER.warn("", e); } String objective = attributes.getValue("objective_name"); String[] tokens = objective.split("_"); store.setObjectiveManufacturer(tokens[0], 0, 0); String correction = tokens.length > 2 ? tokens[2] : "Other"; try { store.setObjectiveCorrection(getCorrection(correction), 0, 0); } catch (FormatException e) { LOGGER.warn("", e); } Double pixelSizeX = new Double(attributes.getValue("pixel_width")); Double pixelSizeY = new Double(attributes.getValue("pixel_height")); Double refractive = new Double(attributes.getValue("refractive_index")); // link Objective to Image String objectiveID = MetadataTools.createLSID("Objective", 0, 0); store.setObjectiveID(objectiveID, 0, 0); for (int i=0; i<getSeriesCount(); i++) { store.setImageObjectiveSettingsID(objectiveID, i); store.setImageObjectiveSettingsRefractiveIndex(refractive, i); store.setPixelsPhysicalSizeX(new PositiveFloat(pixelSizeX), i); store.setPixelsPhysicalSizeY(new PositiveFloat(pixelSizeY), i); } } else if (qName.equals("ExcitationFilter")) { String wave = attributes.getValue("wavelength"); if (wave != null) exWaves.add(new Integer(wave)); channelName = attributes.getValue("name"); } else if (qName.equals("EmissionFilter")) { String wave = attributes.getValue("wavelength"); if (wave != null) emWaves.add(new Integer(wave)); channelNames.add(attributes.getValue("name")); } else if (qName.equals("Camera")) { store.setDetectorModel(attributes.getValue("name"), 0, 0); try { store.setDetectorType(getDetectorType("Other"), 0, 0); } catch (FormatException e) { LOGGER.warn("", e); } String detectorID = MetadataTools.createLSID("Detector", 0, 0); store.setDetectorID(detectorID, 0, 0); for (int i=0; i<getSeriesCount(); i++) { setSeries(i); for (int q=0; q<getSizeC(); q++) { store.setDetectorSettingsID(detectorID, i, q); } } setSeries(0); } else if (qName.equals("Binning")) { String binning = attributes.getValue("value"); for (int i=0; i<getSeriesCount(); i++) { setSeries(i); for (int q=0; q<getSizeC(); q++) { try { store.setDetectorSettingsBinning(getBinning(binning), i, q); } catch (FormatException e) { } } } setSeries(0); } else if (qName.equals("Gain")) { String value = attributes.getValue("value"); if (value == null) { return; } Double gain = new Double(value); for (int i=0; i<getSeriesCount(); i++) { setSeries(i); for (int q=0; q<getSizeC(); q++) { store.setDetectorSettingsGain(gain, i, q); } } setSeries(0); } else if (qName.equals("PlateTemperature")) { Double temperature = new Double(attributes.getValue("value")); for (int i=0; i<getSeriesCount(); i++) { store.setImagingEnvironmentTemperature(temperature, i); } } else if (qName.equals("Plate")) { nextPlate++; } else if (qName.equals("Row")) { currentRow = Integer.parseInt(attributes.getValue("number")) - 1; } else if (qName.equals("Column")) { currentCol = Integer.parseInt(attributes.getValue("number")) - 1; } else if (qName.equals("Exposure") && openImage) { double exp = Double.parseDouble(attributes.getValue("time")); exposure = new Double(exp / 1000); } else if (qName.equals("offset_point")) { String x = attributes.getValue("x"); String y = attributes.getValue("y"); posX.add(new Double(x)); posY.add(new Double(y)); addGlobalMeta("X position for position #" + posX.size(), x); addGlobalMeta("Y position for position #" + posY.size(), y); } } } class Image { public String filename; public String thumbnailFile; public boolean isTiff; public Double deltaT, exposure; public Double zPosition; } }