/* * #%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 loci.common.Constants; 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.MetadataStore; import ome.xml.model.primitives.PositiveFloat; import ome.units.quantity.Length; import ome.units.quantity.Time; import ome.units.UNITS; /** * IPLabReader is the file format reader for IPLab (.IPL) files. * * @author Melissa Linkert melissa at glencoesoftware.com * @author Curtis Rueden ctrueden at wisc.edu */ public class IPLabReader extends FormatReader { // -- Fields -- private Double pixelSize, timeIncrement; // -- Constructor -- /** Constructs a new IPLab reader. */ public IPLabReader() { super("IPLab", "ipl"); suffixNecessary = false; // allow extensionless IPLab files suffixSufficient = false; domains = new String[] {FormatTools.UNKNOWN_DOMAIN}; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ @Override public boolean isThisType(RandomAccessInputStream stream) throws IOException { final int blockLen = 12; if (!FormatTools.validStream(stream, blockLen, false)) return false; String s = stream.readString(4); boolean little = s.equals("iiii"); boolean big = s.equals("mmmm"); if (!big && !little) return false; stream.order(little); int size = stream.readInt(); if (size != 4) return false; // first block size should be 4 int version = stream.readInt(); return version >= 0x100e; } /** * @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 numPixels = FormatTools.getPlaneSize(this); in.seek(numPixels * no + 44); readPlane(in, x, y, w, h, buf); return buf; } /* @see loci.formats.IFormatReader#close(boolean) */ @Override public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { pixelSize = timeIncrement = null; } } // -- Internal FormatReader API methods -- /* @see loci.formats.FormatReader#initFile(String) */ @Override protected void initFile(String id) throws FormatException, IOException { super.initFile(id); in = new RandomAccessInputStream(id); LOGGER.info("Populating metadata"); CoreMetadata m = core.get(0); m.littleEndian = in.readString(4).equals("iiii"); in.order(isLittleEndian()); in.skipBytes(12); // read axis sizes from header int dataSize = in.readInt() - 28; m.sizeX = in.readInt(); m.sizeY = in.readInt(); m.sizeC = in.readInt(); m.sizeZ = in.readInt(); m.sizeT = in.readInt(); int filePixelType = in.readInt(); m.imageCount = getSizeZ() * getSizeT(); String ptype; switch (filePixelType) { case 0: ptype = "8 bit unsigned"; m.pixelType = FormatTools.UINT8; break; case 1: ptype = "16 bit signed short"; m.pixelType = FormatTools.INT16; break; case 2: ptype = "16 bit unsigned short"; m.pixelType = FormatTools.UINT16; break; case 3: ptype = "32 bit signed long"; m.pixelType = FormatTools.INT32; break; case 4: ptype = "32 bit single-precision float"; m.pixelType = FormatTools.FLOAT; break; case 5: ptype = "Color24"; m.pixelType = FormatTools.UINT32; break; case 6: ptype = "Color48"; m.pixelType = FormatTools.UINT16; break; case 10: ptype = "64 bit double-precision float"; m.pixelType = FormatTools.DOUBLE; break; default: ptype = "reserved"; // for values 7-9 } m.dimensionOrder = "XY"; if (getSizeC() > 1) m.dimensionOrder += "CZT"; else m.dimensionOrder += "ZTC"; m.rgb = getSizeC() > 1; m.interleaved = false; m.indexed = false; m.falseColor = false; m.metadataComplete = true; addGlobalMeta("PixelType", ptype); addGlobalMeta("Width", getSizeX()); addGlobalMeta("Height", getSizeY()); addGlobalMeta("Channels", getSizeC()); addGlobalMeta("ZDepth", getSizeZ()); addGlobalMeta("TDepth", getSizeT()); // The metadata store we're working with. MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this, true); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { in.skipBytes(dataSize); parseTags(store); Length sizeX = FormatTools.getPhysicalSizeX(pixelSize); Length sizeY = FormatTools.getPhysicalSizeY(pixelSize); if (sizeX != null) { store.setPixelsPhysicalSizeX(sizeX, 0); } if (sizeY != null) { store.setPixelsPhysicalSizeY(sizeY, 0); } if (timeIncrement != null) { store.setPixelsTimeIncrement(new Time(timeIncrement, UNITS.S), 0); } } } // -- Helper methods -- private void parseTags(MetadataStore store) throws FormatException, IOException { LOGGER.info("Reading tags"); byte[] tagBytes = new byte[4]; in.read(tagBytes); String tag = new String(tagBytes, Constants.ENCODING); while (!tag.equals("fini") && in.getFilePointer() < in.length() - 4) { int size = in.readInt(); if (tag.equals("clut")) { // read in Color Lookup Table if (size == 8) { // indexed lookup table in.skipBytes(4); int type = in.readInt(); String[] types = new String[] { "monochrome", "reverse monochrome", "BGR", "classify", "rainbow", "red", "green", "blue", "cyan", "magenta", "yellow", "saturated pixels" }; String clutType = (type >= 0 && type < types.length) ? types[type] : "unknown"; addGlobalMeta("LUT type", clutType); } else { // explicitly defined lookup table // length is 772 in.skipBytes(772); } } else if (tag.equals("norm")) { // read in normalization information if (size != (44 * getSizeC())) { throw new FormatException("Bad normalization settings"); } String[] types = new String[] { "user", "plane", "sequence", "saturated plane", "saturated sequence", "ROI" }; for (int i=0; i<getSizeC(); i++) { int source = in.readInt(); String sourceType = (source >= 0 && source < types.length) ? types[source] : "user"; addGlobalMetaList("NormalizationSource", sourceType); double min = in.readDouble(); double max = in.readDouble(); double gamma = in.readDouble(); double black = in.readDouble(); double white = in.readDouble(); addGlobalMetaList("NormalizationMin", min); addGlobalMetaList("NormalizationMax", max); addGlobalMetaList("NormalizationGamma", gamma); addGlobalMetaList("NormalizationBlack", black); addGlobalMetaList("NormalizationWhite", white); } } else if (tag.equals("head")) { // read in header labels for (int i=0; i<size / 22; i++) { int num = in.readShort(); addGlobalMeta("Header" + num, in.readString(20)); } } else if (tag.equals("mmrc")) { in.skipBytes(size); } else if (tag.equals("roi ") && getMetadataOptions().getMetadataLevel() != MetadataLevel.NO_OVERLAYS) { // read in ROI information in.skipBytes(4); int roiLeft = in.readInt(); int roiTop = in.readInt(); int roiRight = in.readInt(); int roiBottom = in.readInt(); int numRoiPts = in.readInt(); store.setRectangleID(MetadataTools.createLSID("Shape", 0, 0), 0, 0); store.setRectangleX(new Double(roiLeft), 0, 0); store.setRectangleY(new Double(roiTop), 0, 0); store.setRectangleWidth(new Double(roiRight - roiLeft), 0, 0); store.setRectangleHeight(new Double(roiBottom - roiTop), 0, 0); String roiID = MetadataTools.createLSID("ROI", 0, 0); store.setROIID(roiID, 0); store.setImageROIRef(roiID, 0, 0); in.skipBytes(8 * numRoiPts); } else if (tag.equals("mask")) { // read in Segmentation Mask in.skipBytes(size); } else if (tag.equals("unit")) { // read in units for (int i=0; i<4; i++) { int xResStyle = in.readInt(); float unitsPerPixel = in.readFloat(); int xUnitName = in.readInt(); addGlobalMetaList("ResolutionStyle", xResStyle); addGlobalMetaList("UnitsPerPixel", unitsPerPixel); switch (xUnitName) { case 2: // mm unitsPerPixel *= 1000; break; case 3: // cm unitsPerPixel *= 10000; break; case 4: // m unitsPerPixel *= 1000000; break; case 5: // inch unitsPerPixel *= 3937; break; case 6: //ft unitsPerPixel *= 47244; break; } if (i == 0) pixelSize = new Double(unitsPerPixel); addGlobalMetaList("UnitName", xUnitName); } } else if (tag.equals("view")) { // read in view in.skipBytes(size); } else if (tag.equals("plot")) { // read in plot // skipping this field for the moment in.skipBytes(size); } else if (tag.equals("note")) { // read in notes (image info) String descriptor = in.readString(64); String notes = in.readString(512); addGlobalMeta("Descriptor", descriptor); addGlobalMeta("Notes", notes); store.setImageDescription(notes, 0); } else if (tagBytes[0] == 0x1a && tagBytes[1] == (byte) 0xd9 && tagBytes[2] == (byte) 0x8b && tagBytes[3] == (byte) 0xef) { int units = in.readInt(); for (int i=0; i<getSizeT(); i++) { float timepoint = in.readFloat(); // normalize to seconds switch (units) { case 0: // time stored in milliseconds timepoint /= 1000; break; case 2: // time stored in minutes timepoint *= 60; break; case 3: // time stored in hours timepoint *= 60 * 60; break; } addGlobalMetaList("Timestamp", timepoint); for (int c=0; c<getSizeC(); c++) { for (int z=0; z<getSizeZ(); z++) { int plane = getIndex(z, c, i); store.setPlaneDeltaT(new Time(new Double(timepoint), UNITS.S), 0, plane); } } if (i == 1) { timeIncrement = new Double(timepoint); } } } else in.skipBytes(size); if (in.getFilePointer() + 4 <= in.length()) { in.read(tagBytes); tag = new String(tagBytes, Constants.ENCODING); } else { tag = "fini"; } if (in.getFilePointer() >= in.length() && !tag.equals("fini")) { tag = "fini"; } } } }