/* * #%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.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import loci.common.DataTools; import loci.common.DateTools; import loci.common.Location; import loci.common.RandomAccessInputStream; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.FormatReader; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.meta.IMinMaxStore; import loci.formats.meta.MetadataStore; import ome.xml.model.enums.Correction; import ome.xml.model.enums.Immersion; import ome.xml.model.primitives.Timestamp; import ome.units.quantity.Frequency; import ome.units.quantity.Length; import ome.units.quantity.Time; import ome.units.UNITS; /** * DeltavisionReader is the file format reader for Deltavision files. * * @author Melissa Linkert melissa at glencoesoftware.com */ public class DeltavisionReader extends FormatReader { // -- Constants -- public static final int DV_MAGIC_BYTES_1 = 0xa0c0; public static final int DV_MAGIC_BYTES_2 = 0xc0a0; public static final String DATE_FORMAT = "E MMM d HH:mm:ss yyyy"; private static final short LITTLE_ENDIAN = -16224; private static final int HEADER_LENGTH = 1024; private static final String[] IMAGE_TYPES = new String[] { "normal", "Tilt-series", "Stereo tilt-series", "Averaged images", "Averaged stereo pairs" }; // -- Fields -- /** Size of extended header. */ private int extSize; /** Size of one wave in the extended header. */ protected int wSize; /** Size of one z section in the extended header. */ protected int zSize; /** Size of one time element in the extended header. */ protected int tSize; /** Number of tiles in X direction. */ private int xTiles; /** Number of tiles in Y direction. */ private int yTiles; /** Whether or not the stage moved backwards. */ private boolean backwardsStage = false; /** * The number of ints in each extended header section. These fields appear * to be all blank but need to be skipped to get to the floats afterwards */ protected int numIntsPerSection; protected int numFloatsPerSection; /** Initialize an array of Extended Header Field structures. */ protected DVExtHdrFields[][][] extHdrFields = null; private Double[] ndFilters; private int[] lengths; private String logFile; private String deconvolutionLogFile; private boolean truncatedFileFlag = false; // -- Constructor -- /** Constructs a new Deltavision reader. */ public DeltavisionReader() { super("Deltavision", new String[] {"dv", "r3d", "r3d_d3d", "dv.log", "r3d.log"}); suffixNecessary = false; suffixSufficient = false; domains = new String[] {FormatTools.LM_DOMAIN}; hasCompanionFiles = true; datasetDescription = "One .dv, .r3d, or .d3d file and up to two " + "optional .log 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 (checkSuffix(name, "dv.log") || checkSuffix(name, "r3d.log") || name.endsWith("_log.txt")) { return true; } if (checkSuffix(name, "pnl")) return false; return super.isThisType(name, open); } /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ @Override public boolean isThisType(RandomAccessInputStream stream) throws IOException { final int blockLen = 98; if (!FormatTools.validStream(stream, blockLen, true)) return false; stream.seek(96); int magic = stream.readShort() & 0xffff; boolean valid = magic == DV_MAGIC_BYTES_1 || magic == DV_MAGIC_BYTES_2; if (!valid) { return false; } stream.order(magic == (LITTLE_ENDIAN & 0xffff)); stream.seek(0); int x = stream.readInt(); int y = stream.readInt(); int count = stream.readInt(); return x > 0 && y > 0 && count > 0; } /* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */ @Override public String[] getSeriesUsedFiles(boolean noPixels) { FormatTools.assertId(currentId, true, 1); final List<String> files = new ArrayList<String>(); if (!noPixels) files.add(currentId); if (logFile != null) files.add(logFile); if (deconvolutionLogFile != null) files.add(deconvolutionLogFile); 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); int[] coords = getZCTCoords(no); long offset = getPlaneByteOffset(coords[0], coords[1], coords[2]); if (offset < in.length()) { in.seek(offset); readPlane(in, x, getSizeY() - h - y, w, h, buf); // reverse the order of the rows // planes are stored with the origin in the lower-left corner byte[] tmp = new byte[w * FormatTools.getBytesPerPixel(getPixelType())]; for (int row=0; row<h/2; row++) { int src = row * tmp.length; int dest = (h - row - 1) * tmp.length; System.arraycopy(buf, src, tmp, 0, tmp.length); System.arraycopy(buf, dest, buf, src, tmp.length); System.arraycopy(tmp, 0, buf, dest, tmp.length); } } return buf; } /* @see loci.formats.IFormatReader#close(boolean) */ @Override public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { extSize = wSize = zSize = tSize = 0; numIntsPerSection = numFloatsPerSection = 0; extHdrFields = null; ndFilters = null; logFile = deconvolutionLogFile = null; lengths = null; backwardsStage = false; xTiles = 0; yTiles = 0; } } /** * This flag indicates if the file is known to be truncated. * If true, the dimension size information is kept * as it is specified in the file header, otherwise the length * of the file is used to override size information. * * This flag must be set before {@link #setId(String)} is called. * * Default is false. */ public void setTruncatedFileFlag(boolean truncatedFileFlag) { FormatTools.assertId(currentId, false, 1); this.truncatedFileFlag = truncatedFileFlag; } // -- Internal FormatReader API methods -- /* @see loci.formats.FormatReader#initFile(String) */ @Override protected void initFile(String id) throws FormatException, IOException { if (!checkSuffix(id, "dv")) { if (checkSuffix(id, "dv.log") || checkSuffix(id, "r3d.log")) { id = id.substring(0, id.lastIndexOf(".")); } else if (id.endsWith("_log.txt")) { id = id.substring(0, id.lastIndexOf("_")) + ".dv"; } Location file = new Location(id).getAbsoluteFile(); if (!file.exists()) { Location dir = file.getParentFile(); String[] list = dir.list(true); String name = file.getName(); name = name.substring(0, name.lastIndexOf(".")); for (String f : list) { if (checkSuffix(f, "dv") && f.startsWith(name)) { id = new Location(dir, f).getAbsolutePath(); break; } } } } super.initFile(id); findLogFiles(); in = new RandomAccessInputStream(currentId); initPixels(); MetadataLevel metadataLevel = metadataOptions.getMetadataLevel(); if (metadataLevel != MetadataLevel.MINIMUM) { initExtraMetadata(); } } protected void initPixels() throws FormatException, IOException { LOGGER.info("Reading header"); MetadataStore store = makeFilterMetadata(); in.seek(96); in.order(true); boolean little = in.readShort() == LITTLE_ENDIAN; in.order(little); in.seek(0); int sizeX = in.readInt(); int sizeY = in.readInt(); int imageCount = in.readInt(); int filePixelType = in.readInt(); in.seek(180); int rawSizeT = in.readShort(); int sizeT = rawSizeT == 0 ? 1 : rawSizeT; int sequence = in.readShort(); in.seek(92); extSize = in.readInt(); in.seek(196); int rawSizeC = in.readShort(); int sizeC = rawSizeC == 0 ? 1 : rawSizeC; // --- compute some secondary values --- String imageSequence = getImageSequence(sequence); int sizeZ = imageCount / (sizeC * sizeT); // --- populate core metadata --- LOGGER.info("Populating core metadata"); CoreMetadata m = core.get(0); m.littleEndian = little; m.sizeX = sizeX; m.sizeY = sizeY; m.imageCount = imageCount; String pixel = getPixelString(filePixelType); m.pixelType = getPixelType(filePixelType); m.dimensionOrder = "XY" + imageSequence.replaceAll("W", "C"); int planeSize = getSizeX() * getSizeY() * FormatTools.getBytesPerPixel(getPixelType()); int realPlaneCount = (int) ((in.length() - HEADER_LENGTH - extSize) / planeSize); if (realPlaneCount < getImageCount() && !truncatedFileFlag) { LOGGER.debug("Truncated file"); m.imageCount = realPlaneCount; if (sizeZ == 1) { sizeT = realPlaneCount / sizeC; } else if (sizeT == 1) { sizeZ = realPlaneCount / sizeC; if ((realPlaneCount % sizeC) != 0) { sizeZ++; m.imageCount = sizeZ * sizeC; } } else if (getDimensionOrder().indexOf("Z") < getDimensionOrder().indexOf("T")) { sizeZ = realPlaneCount / (sizeC * sizeT); if (sizeZ == 0) { sizeT = 1; sizeZ = realPlaneCount / sizeC; if ((realPlaneCount % sizeC) != 0) { sizeZ++; m.imageCount = sizeZ * sizeC; } } if (getImageCount() > (sizeZ * sizeC * sizeT)) { m.imageCount = imageCount; sizeC = rawSizeC == 0 ? 1 : rawSizeC; sizeT = rawSizeT == 0 ? 1 : rawSizeT; sizeZ = getImageCount() / (sizeC * sizeT); } } else { sizeT = realPlaneCount / (sizeC * sizeZ); } } m.sizeT = sizeT; m.sizeC = sizeC; m.sizeZ = sizeZ; m.rgb = false; m.interleaved = false; m.metadataComplete = true; m.indexed = false; m.falseColor = false; // --- parse extended header --- in.seek(128); numIntsPerSection = in.readShort(); numFloatsPerSection = in.readShort(); LOGGER.info("Reading extended header"); setOffsetInfo(sequence, getSizeZ(), getSizeC(), getSizeT()); extHdrFields = new DVExtHdrFields[getSizeZ()][getSizeC()][getSizeT()]; ndFilters = new Double[getSizeC()]; final List<Length> uniqueTileX = new ArrayList<Length>(); final List<Length> uniqueTileY = new ArrayList<Length>(); // Run through every image and fill in the // Extended Header information array for that image int offset = HEADER_LENGTH + numIntsPerSection * 4; boolean hasZeroX = false; boolean hasZeroY = false; for (int i=0; i<getImageCount(); i++) { int[] coords = getZCTCoords(i); int z = coords[0]; int w = coords[1]; int t = coords[2]; // -- read in the extended header data -- in.seek(offset + getTotalOffset(z, w, t)); DVExtHdrFields hdr = new DVExtHdrFields(in); extHdrFields[z][w][t] = hdr; if (!uniqueTileX.contains(hdr.stageXCoord) && hdr.stageXCoord.value().floatValue() != 0) { uniqueTileX.add(hdr.stageXCoord); } else if (hdr.stageXCoord.value().floatValue() == 0) { hasZeroX = true; } if (!uniqueTileY.contains(hdr.stageYCoord) && hdr.stageYCoord.value().floatValue() != 0) { uniqueTileY.add(hdr.stageYCoord); } else if (hdr.stageYCoord.value().floatValue() == 0) { hasZeroY = true; } } xTiles = uniqueTileX.size(); yTiles = uniqueTileY.size(); if (xTiles > 1 || yTiles > 1) { if (hasZeroX) { xTiles++; } if (hasZeroY) { yTiles++; } } if (yTiles > 1) { // TODO: use compareTo once Length implements Comparable final Number y0 = uniqueTileY.get(0).value(UNITS.REFERENCEFRAME); final Number y1 = uniqueTileY.get(1).value(UNITS.REFERENCEFRAME); if (y1.floatValue() < y0.floatValue()) { backwardsStage = true; } } int nStagePositions = xTiles * yTiles; if (nStagePositions > 0 && nStagePositions <= getSizeT()) { int t = getSizeT(); m.sizeT /= nStagePositions; if (getSizeT() * nStagePositions != t) { m.sizeT = t; nStagePositions = 1; } else { m.imageCount /= nStagePositions; } if (nStagePositions > 1) { CoreMetadata originalCore = core.get(0); core.clear(); for (int i=0; i<nStagePositions; i++) { core.add(originalCore); } } } lengths = new int[4]; int lengthIndex = 0; int dimIndex = 0; while (lengthIndex < lengths.length) { char dim = imageSequence.charAt(dimIndex++); switch (dim) { case 'Z': lengths[lengthIndex++] = getSizeZ(); break; case 'W': lengths[lengthIndex++] = getSizeC(); break; case 'T': lengths[lengthIndex++] = getSeriesCount(); lengths[lengthIndex++] = getSizeT(); break; } } // --- populate original metadata --- LOGGER.info("Populating original metadata"); addGlobalMeta("ImageWidth", sizeX); addGlobalMeta("ImageHeight", sizeY); addGlobalMeta("NumberOfImages", imageCount); addGlobalMeta("PixelType", pixel); addGlobalMeta("Number of timepoints", rawSizeT); addGlobalMeta("Image sequence", imageSequence); addGlobalMeta("Number of wavelengths", rawSizeC); addGlobalMeta("Number of focal planes", sizeZ); for (int series=0; series<getSeriesCount(); series++) { setSeries(series); for (int plane=0; plane<getImageCount(); plane++) { int[] coords = getZCTCoords(plane); int tIndex = getSeriesCount() * coords[2] + series; DVExtHdrFields hdr = extHdrFields[coords[0]][coords[1]][tIndex]; // -- record original metadata -- String prefix = "Extended header Z" + coords[0] + " W" + coords[1] + " T" + coords[2]; for (Map.Entry<String, Object> entry : hdr.asMap().entrySet()) { addSeriesMeta(prefix + ":" + entry.getKey(), entry.getValue()); } addGlobalMetaList("X position for position", hdr.stageXCoord); addGlobalMetaList("Y position for position", hdr.stageYCoord); addGlobalMetaList("Z position for position", hdr.stageZCoord); } } setSeries(0); // --- populate OME metadata --- LOGGER.info("Populating OME metadata"); MetadataTools.populatePixels(store, this, true); // link Instrument and Image String instrumentID = MetadataTools.createLSID("Instrument", 0); store.setInstrumentID(instrumentID, 0); for (int i=0; i<getSeriesCount(); i++) { store.setImageInstrumentRef(instrumentID, i); } } protected void initExtraMetadata() throws FormatException, IOException { MetadataStore store = makeFilterMetadata(); // --- read in the image header data --- LOGGER.info("Reading header"); in.seek(16); int subImageStartX = in.readInt(); int subImageStartY = in.readInt(); int subImageStartZ = in.readInt(); int pixelSamplingX = in.readInt(); int pixelSamplingY = in.readInt(); int pixelSamplingZ = in.readInt(); float pixX = in.readFloat(); float pixY = in.readFloat(); float pixZ = in.readFloat(); float xAxisAngle = in.readFloat(); float yAxisAngle = in.readFloat(); float zAxisAngle = in.readFloat(); int xAxisSeq = in.readInt(); int yAxisSeq = in.readInt(); int zAxisSeq = in.readInt(); float[] minWave = new float[5]; float[] maxWave = new float[5]; minWave[0] = in.readFloat(); maxWave[0] = in.readFloat(); float meanIntensity = in.readFloat(); int spaceGroupNumber = in.readInt(); in.seek(132); short numSubResSets = in.readShort(); short zAxisReductionQuotient = in.readShort(); for (int i=1; i<=3; i++) { minWave[i] = in.readFloat(); maxWave[i] = in.readFloat(); } int type = in.readShort(); int lensID = in.readShort(); in.seek(172); minWave[4] = in.readFloat(); maxWave[4] = in.readFloat(); in.seek(184); float xTiltAngle = in.readFloat(); float yTiltAngle = in.readFloat(); float zTiltAngle = in.readFloat(); in.skipBytes(2); short[] waves = new short[5]; for (int i=0; i<waves.length; i++) { waves[i] = in.readShort(); } float xOrigin = in.readFloat(); float yOrigin = in.readFloat(); float zOrigin = in.readFloat(); in.skipBytes(4); String[] title = new String[10]; for (int i=0; i<title.length; i++) { // Make sure that "null" characters are stripped out title[i] = in.readByteToString(80).replaceAll("\0", ""); } // --- compute some secondary values --- String imageType = type < IMAGE_TYPES.length ? IMAGE_TYPES[type] : "unknown"; String imageDesc = title[0]; if (imageDesc != null && imageDesc.length() == 0) imageDesc = null; // --- populate original metadata --- LOGGER.info("Populating original metadata"); addGlobalMeta("Sub-image starting point (X)", subImageStartX); addGlobalMeta("Sub-image starting point (Y)", subImageStartY); addGlobalMeta("Sub-image starting point (Z)", subImageStartZ); addGlobalMeta("Pixel sampling size (X)", pixelSamplingX); addGlobalMeta("Pixel sampling size (Y)", pixelSamplingY); addGlobalMeta("Pixel sampling size (Z)", pixelSamplingZ); addGlobalMeta("X element length (in um)", pixX); addGlobalMeta("Y element length (in um)", pixY); addGlobalMeta("Z element length (in um)", pixZ); addGlobalMeta("X axis angle", xAxisAngle); addGlobalMeta("Y axis angle", yAxisAngle); addGlobalMeta("Z axis angle", zAxisAngle); addGlobalMeta("Column axis sequence", xAxisSeq); addGlobalMeta("Row axis sequence", yAxisSeq); addGlobalMeta("Section axis sequence", zAxisSeq); addGlobalMeta("Image Type", imageType); addGlobalMeta("Lens ID Number", lensID); addGlobalMeta("X axis tilt angle", xTiltAngle); addGlobalMeta("Y axis tilt angle", yTiltAngle); addGlobalMeta("Z axis tilt angle", zTiltAngle); for (int i=0; i<waves.length; i++) { addGlobalMeta("Wavelength " + (i + 1) + " (in nm)", waves[i]); } addGlobalMeta("X origin (in um)", xOrigin); addGlobalMeta("Y origin (in um)", yOrigin); addGlobalMeta("Z origin (in um)", zOrigin); for (String t : title) { addGlobalMetaList("Title", t); } for (int i=0; i<minWave.length; i++) { addGlobalMeta("Wavelength " + (i + 1) + " min. intensity", minWave[i]); addGlobalMeta("Wavelength " + (i + 1) + " max. intensity", maxWave[i]); } addGlobalMeta("Wavelength 1 mean intensity", meanIntensity); addGlobalMeta("Space group number", spaceGroupNumber); addGlobalMeta("Number of Sub-resolution sets", numSubResSets); addGlobalMeta("Z axis reduction quotient", zAxisReductionQuotient); // --- populate OME metadata --- LOGGER.info("Populating OME metadata"); for (int series=0; series<getSeriesCount(); series++) { if (store instanceof IMinMaxStore) { IMinMaxStore minMaxStore = (IMinMaxStore) store; for (int i=0; i<minWave.length; i++) { if (i < getEffectiveSizeC()) { minMaxStore.setChannelGlobalMinMax( i, minWave[i], maxWave[i], series); } } } Double x = new Double(pixX); Length sizeX = FormatTools.getPhysicalSizeX(x); if (sizeX != null) { store.setPixelsPhysicalSizeX(sizeX, series); } Double y = new Double(pixY); Length sizeY = FormatTools.getPhysicalSizeY(y); if (sizeY != null) { store.setPixelsPhysicalSizeY(sizeY, series); } Double z = new Double(pixZ); Length sizeZ = FormatTools.getPhysicalSizeZ(z); if (sizeZ != null) { store.setPixelsPhysicalSizeZ(sizeZ, series); } store.setImageDescription(imageDesc, series); } populateObjective(store, lensID); // if matching log file exists, extract key/value pairs from it boolean logFound = isGroupFiles() ? parseLogFile(store) : false; if (isGroupFiles()) parseDeconvolutionLog(store); if (getSeriesCount() == 1) { xTiles = 1; yTiles = 1; backwardsStage = false; } for (int series=0; series<getSeriesCount(); series++) { int seriesIndex = series; if (backwardsStage) { int x = series % xTiles; int y = series / xTiles; seriesIndex = (yTiles - y - 1) * xTiles + (xTiles - x - 1); } for (int i=0; i<getImageCount(); i++) { int[] coords = getZCTCoords(i); int tIndex = getSeriesCount() * coords[2] + seriesIndex; DVExtHdrFields hdr = extHdrFields[coords[0]][coords[1]][tIndex]; // plane timing store.setPlaneDeltaT(new Time(new Double(hdr.timeStampSeconds), UNITS.S), series, i); store.setPlaneExposureTime( new Time(new Double(extHdrFields[0][coords[1]][0].expTime), UNITS.S), series, i); // stage position if (!logFound || getSeriesCount() > 1) { store.setPlanePositionX(hdr.stageXCoord, series, i); store.setPlanePositionY(hdr.stageYCoord, series, i); store.setPlanePositionZ(hdr.stageZCoord, series, i); } } for (int w=0; w<getSizeC(); w++) { DVExtHdrFields hdrC = extHdrFields[0][w][series]; Length emission = FormatTools.getEmissionWavelength(new Double(waves[w])); Length excitation = FormatTools.getExcitationWavelength(new Double(hdrC.exWavelen)); if (emission != null) { store.setChannelEmissionWavelength(emission, series, w); } if (excitation != null) { store.setChannelExcitationWavelength(excitation, series, w); } if (ndFilters[w] == null) ndFilters[w] = new Double(hdrC.ndFilter); store.setChannelNDFilter(ndFilters[w], series, w); } } } // -- Helper methods -- /** Get a descriptive string representing the pixel type. */ private String getPixelString(int filePixelType) { switch (filePixelType) { case 0: return "8 bit unsigned integer"; case 1: return "16 bit signed integer"; case 2: return "32 bit floating point"; case 3: return "16 bit complex"; case 4: return "64 bit complex"; case 6: return "16 bit unsigned integer"; } return "unknown"; } /** Get the OME pixel type from the pixel type stored in the file. */ private int getPixelType(int filePixelType) { switch (filePixelType) { case 0: return FormatTools.UINT8; case 1: return FormatTools.INT16; case 2: return FormatTools.FLOAT; case 3: return FormatTools.INT16; case 4: return FormatTools.FLOAT; case 6: return FormatTools.UINT16; } return FormatTools.UINT8; } /** Get the image sequence string. */ private String getImageSequence(int imageSequence) { switch (imageSequence) { case 0: return "ZTW"; case 1: return "WZT"; case 2: return "ZWT"; case 65536: return "WZT"; } return "ZTW"; } /** * This method calculates the size of a w, t, z section depending on which * sequence is being used (either ZTW, WZT, or ZWT) * @param imgSequence * @param numZSections * @param numWaves * @param numTimes */ private void setOffsetInfo(int imgSequence, int numZSections, int numWaves, int numTimes) { int smallOffset = (numIntsPerSection + numFloatsPerSection) * 4; switch (imgSequence) { // ZTW sequence case 0: zSize = smallOffset; tSize = zSize * numZSections; wSize = tSize * numTimes; break; // WZT sequence case 1: wSize = smallOffset; zSize = wSize * numWaves; tSize = zSize * numZSections; break; // ZWT sequence case 2: zSize = smallOffset; wSize = zSize * numZSections; tSize = wSize * numWaves; break; } } /** * Given any specific Z, W, and T of a plane, determine the totalOffset from * the start of the extended header. * @param currentZ * @param currentW * @param currentT */ private int getTotalOffset(int currentZ, int currentW, int currentT) { return (zSize * currentZ) + (wSize * currentW) + (tSize * currentT); } /** * Given any specific Z, W, and T of a plane, determine the absolute * byte offset of the plane in the file. * @param currentZ * @param currentW * @param currentT */ public long getPlaneByteOffset(int currentZ, int currentW, int currentT) { FormatTools.assertId(currentId, true, 1); int[] newCoords = new int[4]; int coordIndex = 0; int dimIndex = 2; while (coordIndex < newCoords.length) { char dim = getDimensionOrder().charAt(dimIndex++); switch (dim) { case 'Z': newCoords[coordIndex++] = currentZ; break; case 'C': newCoords[coordIndex++] = currentW; break; case 'T': newCoords[coordIndex++] = getSeries(); newCoords[coordIndex++] = currentT; break; } } int planeIndex = FormatTools.positionToRaster(lengths, newCoords); long planeSize = (long) FormatTools.getPlaneSize(this); long planeOffset = planeSize * planeIndex; long offset = planeOffset + HEADER_LENGTH + extSize; return offset; } /** Find the log files. */ private void findLogFiles() throws IOException { if (getCurrentFile().lastIndexOf(".") == -1) { // The current file name has no extension, skip trying to find the // log file(s). logFile = null; deconvolutionLogFile = null; return; } if (getCurrentFile().endsWith("_D3D.dv")) { logFile = getCurrentFile(); logFile = logFile.substring(0, logFile.indexOf("_D3D.dv")) + ".dv.log"; } else { logFile = getCurrentFile() + ".log"; if (!new Location(logFile).exists()) { logFile = getCurrentFile(); logFile = logFile.substring(0, logFile.lastIndexOf(".")) + ".log"; } } if (!new Location(logFile).exists()) logFile = null; int dot = getCurrentFile().lastIndexOf("."); String base = getCurrentFile().substring(0, dot); deconvolutionLogFile = base + "_log.txt"; if (!new Location(deconvolutionLogFile).exists()) { deconvolutionLogFile = null; } } /** Extract metadata from associated log file, if it exists. */ private boolean parseLogFile(MetadataStore store) throws FormatException, IOException { if (logFile == null || !new Location(logFile).exists()) { logFile = null; return false; } LOGGER.info("Parsing log file"); String[] lines = DataTools.readFile(logFile).split("[\r\n]"); String key, value = "", prefix = ""; int currentImage = 0; List<String> channelNames = new ArrayList<String>(); List<Double> filters = new ArrayList<Double>(); for (String line : lines) { int colon = line.indexOf(":"); if (colon != -1 && !line.startsWith("Created")) { key = line.substring(0, colon).trim(); value = line.substring(colon + 1).trim(); if (value.equals("") && !key.equals("")) prefix = key; addGlobalMeta(prefix + " " + key, value); // Objective properties if (key.equals("Objective")) { // assume first word is the manufacturer's name int space = value.indexOf(" "); if (space != -1) { String manufacturer = value.substring(0, space); String extra = value.substring(space + 1); String[] tokens = extra.split(","); store.setObjectiveManufacturer(manufacturer, 0, 0); String magnification = "", na = ""; if (tokens.length >= 1) { int end = tokens[0].indexOf("X"); if (end > 0) magnification = tokens[0].substring(0, end); int start = tokens[0].indexOf("/"); if (start >= 0) na = tokens[0].substring(start + 1); } try { Double mag = new Double(magnification); store.setObjectiveNominalMagnification(mag, 0, 0); } catch (NumberFormatException e) { LOGGER.warn("Could not parse magnification '{}'", magnification); } try { store.setObjectiveLensNA(new Double(na), 0, 0); } catch (NumberFormatException e) { LOGGER.warn("Could not parse N.A. '{}'", na); } if (tokens.length >= 2) { store.setObjectiveCorrection(getCorrection(tokens[1]), 0, 0); } // TODO: Token #2 is the microscope model name. if (tokens.length > 3) store.setObjectiveModel(tokens[3], 0, 0); } } else if (key.equalsIgnoreCase("Lens ID")) { if (value.indexOf(",") != -1) { value = value.substring(0, value.indexOf(",")); } if (value.indexOf(" ") != -1) { value = value.substring(value.indexOf(" ") + 1); } if (!value.equals("null")) { String objectiveID = "Objective:" + value; store.setObjectiveID(objectiveID, 0, 0); for (int series=0; series<getSeriesCount(); series++) { store.setObjectiveSettingsID(objectiveID, series); } store.setObjectiveCorrection(getCorrection("Other"), 0, 0); store.setObjectiveImmersion(getImmersion("Other"), 0, 0); } } // Image properties else if (key.equals("Pixel Size")) { String[] pixelSizes = value.split(" "); for (int q=0; q<pixelSizes.length; q++) { Double size = null; try { size = new Double(pixelSizes[q].trim()); } catch (NumberFormatException e) { LOGGER.warn("Could not parse pixel size '{}'", pixelSizes[q].trim()); } if (q == 0) { Length sizeX = FormatTools.getPhysicalSizeX(size); if (sizeX != null) { for (int series=0; series<getSeriesCount(); series++) { store.setPixelsPhysicalSizeX(sizeX, series); } } } if (q == 1) { Length sizeY = FormatTools.getPhysicalSizeY(size); if (sizeY != null) { for (int series=0; series<getSeriesCount(); series++) { store.setPixelsPhysicalSizeY(sizeY, series); } } } if (q == 2) { Length sizeZ = FormatTools.getPhysicalSizeZ(size); if (sizeZ != null) { for (int series=0; series<getSeriesCount(); series++) { store.setPixelsPhysicalSizeZ(sizeZ, series); } } } } } else if (key.equals("Binning")) { store.setDetectorType(getDetectorType("Other"), 0, 0); String detectorID = MetadataTools.createLSID("Detector", 0, 0); store.setDetectorID(detectorID, 0, 0); for (int series=0; series<getSeriesCount(); series++) { for (int c=0; c<getSizeC(); c++) { store.setDetectorSettingsBinning(getBinning(value), series, c); // link DetectorSettings to an actual Detector store.setDetectorSettingsID(detectorID, series, c); } } } // Camera properties else if (key.equals("Type")) { store.setDetectorModel(value, 0, 0); } else if (key.equals("Gain")) { value = value.replaceAll("X", ""); try { String detectorID = MetadataTools.createLSID("Detector", 0, 0); store.setDetectorID(detectorID, 0, 0); for (int series=0; series<getSeriesCount(); series++) { for (int c=0; c<getSizeC(); c++) { store.setDetectorSettingsGain(new Double(value), series, c); store.setDetectorSettingsID(detectorID, series, c); } } } catch (NumberFormatException e) { LOGGER.warn("Could not parse gain '{}'", value); } } else if (key.equals("Speed")) { value = value.replaceAll("KHz", ""); try { double khz = Double.parseDouble(value); String detectorID = MetadataTools.createLSID("Detector", 0, 0); store.setDetectorID(detectorID, 0, 0); for (int series=0; series<getSeriesCount(); series++) { for (int c=0; c<getSizeC(); c++) { store.setDetectorSettingsReadOutRate( new Frequency(khz, UNITS.KHZ), series, c); store.setDetectorSettingsID(detectorID, series, c); } } } catch (NumberFormatException e) { LOGGER.warn("Could not parse read-out rate '{}'", value); } } else if (key.equals("Temp Setting")) { value = value.replaceAll("C", "").trim(); try { // this is the camera temperature, not the environment temperature //store.setImagingEnvironmentTemperature(value, 0); } catch (NumberFormatException e) { LOGGER.warn("Could not parse temperature '{}'", value); } } // Plane properties else if (key.equals("EM filter")) { if (!channelNames.contains(value)) { channelNames.add(value); } } else if (key.equals("ND filter")) { value = value.replaceAll("%", ""); try { double nd = Double.parseDouble(value) / 100; if (!filters.contains(nd)) { filters.add(nd); } } catch (NumberFormatException exc) { // "BLANK" is the default (e.g. for deconvolved data), // so no need to log it explicitly if (!value.equals("BLANK")) { LOGGER.warn("Could not parse ND filter '{}'", value); } filters.add(null); } catch (IllegalArgumentException e) { LOGGER.debug("", e); } } else if (key.equals("Stage coordinates")) { if (value.length() > 1) { value = value.substring(1, value.length() - 1); } String[] coords = value.split(","); for (int i=0; i<coords.length; i++) { Length p = null; try { final Double number = Double.valueOf(coords[i]); p = new Length(number, UNITS.REFERENCEFRAME); } catch (NumberFormatException e) { LOGGER.warn("Could not parse stage coordinate '{}'", coords[i]); } if (currentImage < getImageCount() && getSeriesCount() == 1) { // NB: the positions are intentionally only populated for the // first series. Positions for the other series are parsed // from the extended header. if (i == 0) { store.setPlanePositionX(p, 0, currentImage); } if (i == 1) { store.setPlanePositionY(p, 0, currentImage); } if (i == 2) { store.setPlanePositionZ(p, 0, currentImage); } } } currentImage++; } } else if (line.startsWith("Image")) prefix = line; else if (line.startsWith("Created")) { if (line.length() > 8) line = line.substring(8).trim(); String date = DateTools.formatDate(line, DATE_FORMAT); if (date != null) { for (int series=0; series<getSeriesCount(); series++) { store.setImageAcquisitionDate(new Timestamp(date), series); } } else { LOGGER.warn("Could not parse date '{}'", line); } } } for (int series=0; series<getSeriesCount(); series++) { for (int c=0; c<getEffectiveSizeC(); c++) { if (c < channelNames.size()) { store.setChannelName(channelNames.get(c), series, c); } if (c < filters.size()) { ndFilters[c] = filters.get(c); } } } return true; } /** Parse deconvolution output, if it exists. */ private void parseDeconvolutionLog(MetadataStore store) throws IOException { if (deconvolutionLogFile == null || !new Location(deconvolutionLogFile).exists()) { return; } LOGGER.info("Parsing deconvolution log file"); RandomAccessInputStream s = new RandomAccessInputStream(deconvolutionLogFile); boolean doStatistics = false; int cc = 0, tt = 0; String previousLine = null; while (s.getFilePointer() < s.length() - 1) { String line = s.readLine(); if (line == null || line.length() == 0) continue; if (doStatistics) { String[] keys = line.split(" "); final List<String> realKeys = new ArrayList<String>(); for (int i=0; i<keys.length; i++) { keys[i] = keys[i].trim(); if (!keys[i].isEmpty()) realKeys.add(keys[i]); } keys = realKeys.toArray(new String[0]); s.readLine(); line = s.readLine().trim(); while (line != null && line.length() != 0) { String[] values = line.split(" "); final List<String> realValues = new ArrayList<String>(); for (int i=0; i<values.length; i++) { values[i] = values[i].trim(); if (!values[i].isEmpty()) { realValues.add(values[i]); } } values = realValues.toArray(new String[0]); try { if (values.length > 0) { int zz = Integer.parseInt(values[0]) - 1; int index = getIndex(zz, cc, tt); for (int i=1; i<keys.length; i++) { addGlobalMeta("Plane " + index + " " + keys[i], values[i]); } } } catch (NumberFormatException e) { LOGGER.warn("Could not parse Z position '{}'", values[0]); } catch (IllegalArgumentException iae) { LOGGER.debug("", iae); } line = s.readLine().trim(); } } else { int index = line.indexOf(".\t"); if (index != -1) { String key = line.substring(0, index).trim(); String value = line.substring(index + 2).trim(); // remove trailing dots from key while (key.endsWith(".")) { key = key.substring(0, key.length() - 1); } if (previousLine != null && (previousLine.endsWith("Deconvolution Results:") || previousLine.endsWith("open OTF"))) { addGlobalMeta(previousLine + " " + key, value); } else addGlobalMeta(key, value); } } if (line.indexOf("correcting time point\t") != -1) { int index = line.indexOf("time point\t") + 11; if (index > 10) { String t = line.substring(index, line.indexOf(",", index)); try { tt = Integer.parseInt(t) - 1; } catch (NumberFormatException e) { LOGGER.warn("Could not parse timepoint '{}'", t); } index = line.indexOf("wavelength\t") + 11; if (index > 10) { String c = line.substring(index, line.indexOf(".", index)); try { cc = Integer.parseInt(c) - 1; } catch (NumberFormatException e) { LOGGER.warn("Could not parse channel position '{}'", c); } } } } if (line.length() > 0 && line.indexOf(".") == -1) previousLine = line; doStatistics = line.endsWith("- reading image data..."); } s.close(); } private void readWavelength(int channel, MetadataStore store) throws FormatException, IOException { float min = in.readFloat(); float max = in.readFloat(); addGlobalMeta("Wavelength " + (channel + 1) + " min. intensity", min); addGlobalMeta("Wavelength " + (channel + 1) + " max. intensity", max); if (store instanceof IMinMaxStore) { ((IMinMaxStore) store).setChannelGlobalMinMax(channel, min, max, 0); } } /** * Populate an Objective based upon the lens ID. * This is based upon information received from Applied Precision. */ private void populateObjective(MetadataStore store, int lensID) throws FormatException { Double lensNA = null; Double workingDistance = null; Immersion immersion = getImmersion("Other"); Correction correction = getCorrection("Other"); String manufacturer = null; String model = null; double magnification = 0; Double calibratedMagnification = null; if (lensID >= 10000 && lensID <= 32000) { if (lensID < 12000) { manufacturer = "Olympus"; } else if (lensID < 14000) { manufacturer = "Nikon"; } else if (lensID < 16000) { manufacturer = "Zeiss"; } else if (lensID < 18000) { manufacturer = "Leica"; } else if (lensID < 20000) { manufacturer = "APLLC"; } magnification = ((lensID % 1000) - (lensID % 100)) / 10.0; if (magnification == 0) { magnification = 100; } } switch (lensID) { case 2001: lensNA = 1.15; immersion = getImmersion("Water"); break; case 10100: lensNA = 0.30; immersion = getImmersion("Air"); model = "1-LP134"; correction = getCorrection("Achromat"); break; case 10101: lensNA = 0.40; immersion = getImmersion("Air"); model = "1-LB331"; correction = getCorrection("Apo"); break; case 10102: lensNA = 0.30; immersion = getImmersion("Air"); model = "1-LP134"; break; case 10103: lensNA = 0.13; calibratedMagnification = 4.0; immersion = getImmersion("Air"); model = "1-LP124"; break; case 10104: lensNA = 0.40; immersion = getImmersion("Air"); model = "1-LB331"; break; case 10105: lensNA = 0.40; workingDistance = 3.10; immersion = getImmersion("Air"); model = "1-LP331"; break; case 10106: lensNA = 0.16; calibratedMagnification = 4.0; workingDistance = 13.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "1-UB822"; break; case 10107: lensNA = 0.40; immersion = getImmersion("Air"); workingDistance = 3.10; model = "1-UB823"; correction = getCorrection("PlanApo"); break; case 10108: lensNA = 0.25; workingDistance = 9.8; immersion = getImmersion("Air"); model = "1-UC243"; break; case 10109: lensNA = 0.30; immersion = getImmersion("Air"); model = "1-UB532"; correction = getCorrection("PlanFluor"); break; case 10110: lensNA = 0.13; calibratedMagnification = 4.0; immersion = getImmersion("Air"); break; case 10111: lensNA = 0.08; calibratedMagnification = 2.0; immersion = getImmersion("Air"); break; case 10112: lensNA = 0.13; calibratedMagnification = 4.0; immersion = getImmersion("Air"); model = "1-UB522"; break; case 10113: lensNA = 0.04; calibratedMagnification = 1.25; workingDistance = 5.1; immersion = getImmersion("Air"); model = "1-UB920"; correction = getCorrection("PlanApo"); break; case 10114: lensNA = 0.08; calibratedMagnification = 2.0; workingDistance = 6.0; immersion = getImmersion("Air"); model = "1-UB921"; correction = getCorrection("PlanApo"); break; case 10200: lensNA = 0.40; workingDistance = 3.0; immersion = getImmersion("Air"); break; case 10201: lensNA = 0.65; workingDistance = 1.03; immersion = getImmersion("Air"); model = "1-LB343"; correction = getCorrection("Apo"); break; case 10202: lensNA = 0.40; immersion = getImmersion("Air"); model = "1-LP146"; break; case 10203: lensNA = 0.80; immersion = getImmersion("Oil"); model = "1-LB342"; correction = getCorrection("PlanApo"); break; case 10204: lensNA = 0.70; immersion = getImmersion("Air"); model = "1-LB341"; break; case 10205: lensNA = 0.75; workingDistance = 0.55; immersion = getImmersion("Air"); model = "1-UB765"; correction = getCorrection("Apo"); break; case 10206: lensNA = 0.50; workingDistance = 0.55; immersion = getImmersion("Air"); model = "1-UC525"; break; case 10207: lensNA = 0.40; workingDistance = 3.0; immersion = getImmersion("Air"); model = "1-UC145"; correction = getCorrection("Achromat"); break; case 10208: lensNA = 0.50; workingDistance = 0.55; immersion = getImmersion("Air"); model = "1-UB525"; break; case 10209: lensNA = 0.40; workingDistance = 6.9; immersion = getImmersion("Air"); model = "1-UC345"; break; case 10210: lensNA = 0.40; workingDistance = 6.9; immersion = getImmersion("Air"); model = "1-UB345"; break; case 10400: lensNA = 0.55; workingDistance = 2.04; immersion = getImmersion("Air"); break; case 10401: lensNA = 0.85; workingDistance = 0.25; immersion = getImmersion("Air"); break; case 10402: lensNA = 1.30; workingDistance = 0.12; immersion = getImmersion("Oil"); model = "1-LB356"; break; case 10403: lensNA = 1.35; workingDistance = 0.10; immersion = getImmersion("Oil"); model = "1-UB768"; break; case 10404: lensNA = 0.85; workingDistance = 0.20; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "1-UB827"; break; case 10405: lensNA = 0.95; workingDistance = 0.14; immersion = getImmersion("Air"); model = "1-UB927"; correction = getCorrection("PlanApo"); break; case 10406: lensNA = 1.0; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "1-UB828"; break; case 10407: lensNA = 0.75; correction = getCorrection("PlanFluor"); immersion = getImmersion("Air"); model = "1-UB527"; break; case 10408: lensNA = 0.60; workingDistance = 2.15; immersion = getImmersion("Air"); model = "1-UB347"; break; case 10409: lensNA = 0.60; workingDistance = 2.15; immersion = getImmersion("Air"); model = "1-UC347"; break; case 10410: lensNA = 1.15; immersion = getImmersion("Water"); model = "1-UB769"; break; case 10411: lensNA = 0.75; immersion = getImmersion("Air"); model = "1-UC527"; correction = getCorrection("PlanFluor"); break; case 10412: lensNA = 1.34; workingDistance = 0.10; immersion = getImmersion("Oil"); correction = getCorrection("Apo"); break; case 10000: lensNA = 1.30; correction = getCorrection("Apo"); immersion = getImmersion("Oil"); model = "1-LB393"; break; case 10001: lensNA = 1.30; immersion = getImmersion("Oil"); model = "1-LB392"; break; case 10002: lensNA = 1.40; workingDistance = 0.10; immersion = getImmersion("Oil"); model = "1-UB935"; correction = getCorrection("PlanApo"); break; case 10003: lensNA = 1.35; workingDistance = 0.10; immersion = getImmersion("Oil"); model = "1-UB836"; correction = getCorrection("PlanApo"); break; case 10004: lensNA = 1.30; immersion = getImmersion("Oil"); model = "1-UB535"; break; case 10005: lensNA = 1.35; workingDistance = 0.10; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); break; case 10006: lensNA = 1.40; workingDistance = 0.10; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); break; case 10007: lensNA = 1.40; workingDistance = 0.13; immersion = getImmersion("Oil");; model = "1-U2B836"; break; case 10600: lensNA = 1.40; workingDistance = 0.30; immersion = getImmersion("Oil"); break; case 10601: lensNA = 1.40; immersion = getImmersion("Oil"); model = "1-LB751"; break; case 10602: lensNA = 1.40; workingDistance = 0.1; immersion = getImmersion("Oil"); model = "1-UB932"; correction = getCorrection("PlanApo"); break; case 10603: lensNA = 1.20; workingDistance = 0.25; immersion = getImmersion("Water"); model = "1-UB891"; break; case 10604: lensNA = 1.20; workingDistance = 0.25; immersion = getImmersion("Water"); break; case 10605: lensNA = 0.70; workingDistance = 1.10; immersion = getImmersion("Air"); model = "1-UB351"; break; case 10606: lensNA = 0.70; workingDistance = 1.10; immersion = getImmersion("Air"); model = "1-UC351"; break; case 10607: lensNA = 1.40; immersion = getImmersion("Oil"); model = "1-UC932"; correction = getCorrection("PlanApo"); break; case 10608: lensNA = 1.25; immersion = getImmersion("Oil"); model = "1-UB532"; break; case 10609: lensNA = 1.40; workingDistance = 0.15; immersion = getImmersion("Oil"); model = "1-UB933"; correction = getCorrection("PlanApo"); break; case 10610: lensNA = 1.40; workingDistance = 0.15; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); break; case 10611: lensNA = 1.20; workingDistance = 0.25; immersion = getImmersion("Water"); correction = getCorrection("PlanApo"); break; case 10612: lensNA = 1.42; workingDistance = 0.15; immersion = getImmersion("Oil"); model = "1-U2B933"; correction = getCorrection("PlanApo"); break; case 12201: lensNA = 0.75; immersion = getImmersion("Air"); correction = getCorrection("PlanFluor"); model = "93146"; break; case 12203: lensNA = 0.45; workingDistance = 8.1; immersion = getImmersion("Air"); correction = getCorrection("PlanFluor"); model = "93150"; break; case 12204: lensNA = 0.45; workingDistance = 4.50; immersion = getImmersion("Air"); model = "MUE01200/92777"; break; case 12205: lensNA = 0.50; workingDistance = 2.10; immersion = getImmersion("Air"); correction = getCorrection("PlanFluor"); model = "MRH00200/93135"; break; case 12401: lensNA = 1.30; workingDistance = 0.16; immersion = getImmersion("Oil"); model = "85028"; break; case 12402: lensNA = 1.30; workingDistance = 0.22; immersion = getImmersion("Oil"); model = "85004"; break; case 12403: lensNA = 0.75; immersion = getImmersion("Air"); model = "140508"; break; case 12404: lensNA = 1.30; workingDistance = 0.22; immersion = getImmersion("Oil"); break; case 12405: lensNA = 0.95; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "93105"; break; case 12406: lensNA = 1.00; workingDistance = 0.16; immersion = getImmersion("Oil"); model = "93106"; break; case 12600: lensNA = 1.40; workingDistance = 0.17; immersion = getImmersion("Oil"); model = "85020"; break; case 12601: lensNA = 1.40; workingDistance = 0.21; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "93108"; break; case 12602: lensNA = 1.20; workingDistance = 0.22; immersion = getImmersion("Water"); correction = getCorrection("PlanApo"); model = "93109"; break; case 12000: lensNA = 1.40; workingDistance = 0.1; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "85025"; break; case 12001: lensNA = 1.30; workingDistance = 0.14; immersion = getImmersion("Oil"); model = "85005"; break; case 12002: lensNA = 1.30; workingDistance = 0.14; immersion = getImmersion("Oil"); correction = getCorrection("UV"); model = "85005"; break; case 12003: lensNA = 1.40; workingDistance = 0.13; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "93110"; break; case 12004: lensNA = 1.30; workingDistance = 0.20; immersion = getImmersion("Oil"); model = "93129"; break; case 12101: lensNA = 0.10; calibratedMagnification = 2.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "202294"; break; case 12102: lensNA = 0.20; calibratedMagnification = 4.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "108388"; break; case 12103: lensNA = 0.2; calibratedMagnification = 4.0; workingDistance = 15.7; correction = getCorrection("PlanApo"); immersion = getImmersion("Air"); model = "93102"; break; case 12104: lensNA = 0.45; workingDistance = 4.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "93103"; break; case 12105: lensNA = 0.30; workingDistance = 16.0; immersion = getImmersion("Air"); correction = getCorrection("PlanFluor"); model = "93134"; break; case 12106: lensNA = 0.50; workingDistance = 1.20; immersion = getImmersion("Air"); correction = getCorrection("SuperFluor"); model = "93126"; break; case 12107: lensNA = 0.25; workingDistance = 10.5; immersion = getImmersion("Air"); model = "93183"; break; case 12108: lensNA = 0.25; workingDistance = 6.10; immersion = getImmersion("Air"); correction = getCorrection("Achromat"); model = "93161"; break; case 14001: lensNA = 1.40; workingDistance = 0.1; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "44 07 08 (02)"; break; case 14002: lensNA = 1.30; workingDistance = 0.1; immersion = getImmersion("Oil"); model = "44 07 86"; break; case 14003: lensNA = 1.40; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "44 07 80 (02)"; break; case 14004: lensNA = 1.30; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "46 19 46 - 9903"; break; case 14005: lensNA = 1.40; immersion = getImmersion("Oil"); model = "44 07 86 (02)"; break; case 14006: lensNA = 1.30; immersion = getImmersion("Oil"); break; case 14601: lensNA = 1.40; calibratedMagnification = 63.0; workingDistance = 0.09; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "44 07 60 (03)"; break; case 14602: lensNA = 1.40; calibratedMagnification = 63.0; workingDistance = 0.09; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "44 07 62 (02)"; break; case 14603: lensNA = 0.90; calibratedMagnification = 63.0; immersion = getImmersion("Water"); model = "44 00 69"; break; case 14604: lensNA = 1.20; workingDistance = 0.09; calibratedMagnification = 63.0; immersion = getImmersion("Water"); model = "44 06 68"; break; case 14401: lensNA = 1.30; workingDistance = 0.14; immersion = getImmersion("Oil"); correction = getCorrection("Fluar"); model = "44 02 55 (01)"; break; case 14402: lensNA = 1.00; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); model = "44 07 51"; break; case 14403: lensNA = 1.20; immersion = getImmersion("Water"); correction = getCorrection("Apo"); model = "44 00 52"; break; case 14404: lensNA = 0.75; immersion = getImmersion("Air"); correction = getCorrection("PlanNeofluar"); model = "44 03 51"; break; case 14405: lensNA = 1.30; workingDistance = 0.15; immersion = getImmersion("Oil"); correction = getCorrection("PlanNeofluar"); model = "44 04 50"; break; case 14406: lensNA = 0.60; immersion = getImmersion("Air"); model = "44 08 65"; break; case 14407: lensNA = 1.30; immersion = getImmersion("Air"); correction = getCorrection("PlanNeofluar"); break; case 14301: lensNA = 0.80; calibratedMagnification = 25.0; workingDistance = 0.80; correction = getCorrection("PlanNeofluar"); model = "44 05 44"; break; case 14302: lensNA = 0.80; workingDistance = 0.80; calibratedMagnification = 25.0; correction = getCorrection("PlanNeofluar"); model = "44 05 42"; break; case 14303: lensNA = 0.80; calibratedMagnification = 25.0; immersion = getImmersion("Air"); correction = getCorrection("PlanNeofluar"); model = "44 05 45"; break; case 14201: lensNA = 0.50; immersion = getImmersion("Air"); correction = getCorrection("PlanNeofluar"); model = "44 03 41 (01)"; break; case 14202: lensNA = 0.60; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "44 06 40"; break; case 14203: lensNA = 0.75; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "44 06 49"; break; case 14204: lensNA = 0.75; immersion = getImmersion("Air"); correction = getCorrection("Fluar"); model = "44 01 45"; break; case 14101: lensNA = 0.30; immersion = getImmersion("Air"); correction = getCorrection("PlanNeofluar"); model = "44 03 30"; break; case 14102: lensNA = 0.25; immersion = getImmersion("Air"); model = "44 01 31"; break; case 14103: lensNA = 0.25; immersion = getImmersion("Air"); model = "44 00 31"; break; case 14104: lensNA = 0.45; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "44 06 39"; break; case 14105: lensNA = 0.16; calibratedMagnification = 5.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); model = "44 06 20"; break; case 18101: lensNA = 0.20; workingDistance = 3.33; calibratedMagnification = 4.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); break; case 18102: lensNA = 0.20; workingDistance = 2.883; calibratedMagnification = 2.46; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); break; case 18103: lensNA = 0.20; workingDistance = 2.883; calibratedMagnification = 4.0; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); break; case 18104: lensNA = 0.45; calibratedMagnification = 6.15; workingDistance = 2.883; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); break; case 18105: lensNA = 0.45; workingDistance = 2.883; immersion = getImmersion("Air"); correction = getCorrection("PlanApo"); break; case 18106: lensNA = 0.1; workingDistance = 24.00; calibratedMagnification = 1.0; immersion = getImmersion("Air"); break; case 18201: lensNA = 0.55; workingDistance = 13.00; immersion = getImmersion("Air"); break; case 18202: lensNA = 0.50; workingDistance = 13.00; immersion = getImmersion("Air"); break; case 18204: lensNA = 0.45; workingDistance = 4.50; immersion = getImmersion("Air"); model = "MUE01200/92777"; break; case 18205: lensNA = 0.50; workingDistance = 2.10; immersion = getImmersion("Air"); model = "MRH00200/93135"; break; case 1: lensNA = 0.25; manufacturer = "Zeiss"; calibratedMagnification = 10.0; immersion = getImmersion("Air"); break; case 2: lensNA = 0.50; manufacturer = "Zeiss"; calibratedMagnification = 25.0; immersion = getImmersion("Air"); break; case 3: lensNA = 1.00; manufacturer = "Zeiss"; calibratedMagnification = 50.0; immersion = getImmersion("Oil"); break; case 4: lensNA = 1.25; manufacturer = "Zeiss"; calibratedMagnification = 63.0; immersion = getImmersion("Oil"); break; case 5: lensNA = 1.30; manufacturer = "Zeiss"; calibratedMagnification = 100.0; immersion = getImmersion("Oil"); break; case 6: lensNA = 1.30; calibratedMagnification = 100.0; correction = getCorrection("Neofluor"); immersion = getImmersion("Oil"); break; case 7: lensNA = 1.40; calibratedMagnification = 63.0; manufacturer = "Leitz"; immersion = getImmersion("Oil"); correction = getCorrection("PlanApo"); break; case 8: lensNA = 1.20; calibratedMagnification = 63.0; immersion = getImmersion("Water"); break; case 9: lensNA = 0.40; workingDistance = 0.30; calibratedMagnification = 10.0; manufacturer = "Olympus"; immersion = getImmersion("Air"); break; case 10: lensNA = 0.80; workingDistance = 0.30; manufacturer = "Olympus"; calibratedMagnification = 20.0; immersion = getImmersion("Oil"); break; case 11: lensNA = 1.30; calibratedMagnification = 40.0; manufacturer = "Olympus"; workingDistance = 0.30; immersion = getImmersion("Oil"); break; case 12: lensNA = 1.40; workingDistance = 0.30; manufacturer = "Olympus"; calibratedMagnification = 60.0; immersion = getImmersion("Oil"); break; case 13: lensNA = 1.40; workingDistance = 0.30; manufacturer = "Nikon"; calibratedMagnification = 100.0; immersion = getImmersion("Oil"); break; } String objectiveID = "Objective:" + lensID; store.setObjectiveID(objectiveID, 0, 0); for (int series=0; series<getSeriesCount(); series++) { store.setObjectiveSettingsID(objectiveID, series); } store.setObjectiveLensNA(lensNA, 0, 0); store.setObjectiveImmersion(immersion, 0, 0); store.setObjectiveCorrection(correction, 0, 0); store.setObjectiveManufacturer(manufacturer, 0, 0); store.setObjectiveModel(model, 0, 0); store.setObjectiveNominalMagnification(magnification, 0, 0); if (calibratedMagnification != null) { store.setObjectiveCalibratedMagnification(calibratedMagnification, 0, 0); } if (workingDistance != null) { store.setObjectiveWorkingDistance(new Length(workingDistance * 1000, UNITS.MICROM), 0, 0); } } // -- Helper classes -- /** * This private class structure holds the details for the extended header. * Instances of the class should <em>NOT</em> leak out of the containing * instance. * @author Brian W. Loranger */ private static class DVExtHdrFields { /** Photosensor reading. Typically in mV. */ public float photosensorReading; /** Time stamp in seconds since the experiment began. */ public float timeStampSeconds; /** X stage coordinates. */ public Length stageXCoord; /** Y stage coordinates. */ public Length stageYCoord; /** Z stage coordinates. */ public Length stageZCoord; /** Minimum intensity */ public float minInten; /** Maxiumum intensity. */ public float maxInten; /** Exposure time in seconds. */ public float expTime; /** Neutral density value. */ public float ndFilter; /** Excitation filter wavelength. */ public float exWavelen; /** Emission filter wavelength. */ public float emWavelen; /** Intensity scaling factor. Usually 1. */ public float intenScaling; /** Energy conversion factor. Usually 1. */ public float energyConvFactor; public Map<String, Object> asMap() { Map<String, Object> rv = new HashMap<String, Object>(); rv.put("photosensorReading", photosensorReading); rv.put("timeStampSeconds", timeStampSeconds); rv.put("stageXCoord", stageXCoord); rv.put("stageYCoord", stageYCoord); rv.put("stageZCoord", stageZCoord); rv.put("minInten", minInten); rv.put("maxInten", maxInten); rv.put("expTime", expTime); rv.put("ndFilter", ndFilter); rv.put("exWavelen", exWavelen); rv.put("emWavelen", emWavelen); rv.put("intenScaling", intenScaling); rv.put("energyConvFactor", energyConvFactor); return rv; } /** * Helper function which overrides toString, printing out the values in * the header section. */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("photosensorReading: "); sb.append(photosensorReading); sb.append("\ntimeStampSeconds: "); sb.append(timeStampSeconds); sb.append("\nstageXCoord: "); sb.append(stageXCoord); sb.append("\nstageYCoord: "); sb.append(stageYCoord); sb.append("\nstageZCoord: "); sb.append(stageZCoord); sb.append("\nminInten: "); sb.append(minInten); sb.append("\nmaxInten: "); sb.append(maxInten); sb.append("\nexpTime: "); sb.append(expTime); sb.append("\nndFilter: "); sb.append(ndFilter); sb.append("\nexWavelen: "); sb.append(exWavelen); sb.append("\nemWavelen: "); sb.append(emWavelen); sb.append("\nintenScaling: "); sb.append(intenScaling); sb.append("\nenergyConvFactor: "); sb.append(energyConvFactor); return sb.toString(); } private DVExtHdrFields(RandomAccessInputStream in) { try { // NB: this is consistent with the Deltavision Opener plugin // for ImageJ (http://rsb.info.nih.gov/ij/plugins/track/delta.html) photosensorReading = in.readFloat(); timeStampSeconds = in.readFloat(); stageXCoord = new Length(in.readFloat(), UNITS.REFERENCEFRAME); stageYCoord = new Length(in.readFloat(), UNITS.REFERENCEFRAME); stageZCoord = new Length(in.readFloat(), UNITS.REFERENCEFRAME); minInten = in.readFloat(); maxInten = in.readFloat(); in.skipBytes(4); expTime = in.readFloat(); ndFilter = in.readFloat(); exWavelen = in.readFloat(); emWavelen = in.readFloat(); intenScaling = in.readFloat(); energyConvFactor = in.readFloat(); // the stored value could be a percent fraction or a percentage if (ndFilter >= 1) { ndFilter /= 100; } } catch (IOException e) { LOGGER.debug("Could not parse extended header", e); } } } }