/* * #%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.Arrays; import loci.common.DataTools; import loci.common.Location; import loci.common.RandomAccessInputStream; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.meta.MetadataStore; import loci.formats.tiff.IFD; import loci.formats.tiff.TiffParser; import ome.units.UNITS; import ome.units.quantity.Length; import ome.xml.model.primitives.PositiveFloat; /** */ public class SlidebookTiffReader extends BaseTiffReader { // -- Constants -- public static final String SLIDEBOOK_MAGIC_STRING = "SlideBook"; private static final int X_POS_TAG = 65000; private static final int Y_POS_TAG = 65001; private static final int Z_POS_TAG = 65002; private static final int CHANNEL_TAG = 65004; private static final int PHYSICAL_SIZE_TAG = 65007; private static final int MAGNIFICATION_TAG = 65005; // -- Fields -- private int lastFile = 0; private MinimalTiffReader[] readers; private String[] files; private ArrayList<String> channelNames = new ArrayList<String>(); // -- Constructor -- public SlidebookTiffReader() { super("Slidebook TIFF", new String[] {"tif", "tiff"}); suffixSufficient = false; domains = new String[] {FormatTools.LM_DOMAIN}; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ @Override public boolean isThisType(RandomAccessInputStream stream) throws IOException { TiffParser tp = new TiffParser(stream); IFD ifd = tp.getFirstIFD(); if (ifd == null) return false; String software = ifd.getIFDTextValue(IFD.SOFTWARE); if (software == null) return false; return software.equals(SLIDEBOOK_MAGIC_STRING) && ifd.getComment().length() == 0 && (ifd.containsKey(X_POS_TAG) || ifd.containsKey(Y_POS_TAG) || ifd.containsKey(Z_POS_TAG) || ifd.containsKey(CHANNEL_TAG) || ifd.containsKey(PHYSICAL_SIZE_TAG) || ifd.containsKey(MAGNIFICATION_TAG)); } /* @see loci.formats.IFormatReader#close(boolean) */ @Override public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { if (readers != null) { for (MinimalTiffReader reader : readers) { if (reader != null) { reader.close(); } } } lastFile = 0; readers = null; files = null; channelNames.clear(); } } /* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */ @Override public String[] getSeriesUsedFiles(boolean noPixels) { FormatTools.assertId(currentId, true, 1); return noPixels ? null : files; } /* @see loci.formats.IFormatReader#get8BitLookupTable() */ @Override public byte[][] get8BitLookupTable() throws FormatException, IOException { FormatTools.assertId(currentId, true, 1); if (readers == null || lastFile < 0 || lastFile >= readers.length || readers[lastFile] == null) { return super.get8BitLookupTable(); } return readers[lastFile].get8BitLookupTable(); } /* @see loci.formats.IFormatReader#get16BitLookupTable() */ @Override public short[][] get16BitLookupTable() throws FormatException, IOException { FormatTools.assertId(currentId, true, 1); if (readers == null || lastFile < 0 || lastFile >= readers.length || readers[lastFile] == null) { return super.get16BitLookupTable(); } return readers[lastFile].get16BitLookupTable(); } /** * @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 file = no / getSizeT(); int plane = no % getSizeT(); lastFile = file; return readers[file].openBytes(plane, buf, x, y, w, h); } // -- Internal BaseTiffReader API methods -- /* @see BaseTiffReader#initStandardMetadata() */ @Override protected void initStandardMetadata() throws FormatException, IOException { super.initStandardMetadata(); put("Slidebook", "yes"); if (isGroupFiles()) { // look for other TIFF files that belong to this dataset String timestamp = getTimestamp(currentId); Location parent = new Location(currentId).getAbsoluteFile().getParentFile(); String[] list = parent.list(true); Arrays.sort(list); ArrayList<String> matchingFiles = new ArrayList<String>(); for (String f : list) { String path = new Location(parent, f).getAbsolutePath(); if (isThisType(path) && getTimestamp(path).equals(timestamp)) { matchingFiles.add(path); } } files = matchingFiles.toArray(new String[matchingFiles.size()]); } else { files = new String[] {currentId}; } readers = new MinimalTiffReader[files.length]; CoreMetadata m = core.get(0); m.imageCount = ifds.size() * files.length; m.sizeT = ifds.size(); for (int i=0; i<readers.length; i++) { readers[i] = new MinimalTiffReader(); readers[i].setId(files[i]); String channelName = getFirstChannel(files[i]); if (!channelNames.contains(channelName)) { channelNames.add(channelName); } } m.sizeC = channelNames.size(); m.sizeZ = getImageCount() / (getSizeT() * getSizeC()); m.dimensionOrder = "XYTCZ"; } /* @see BaseTiffReader#initMetadataStore() */ @Override protected void initMetadataStore() throws FormatException { super.initMetadataStore(); MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this, true); Location file = new Location(currentId).getAbsoluteFile(); store.setImageName(file.getParentFile().getName(), 0); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { for (int c=0; c<getEffectiveSizeC(); c++) { if (c < channelNames.size()) { String name = channelNames.get(c); if (name != null) { if (name.indexOf(":") > 0) { name = name.substring(name.indexOf(":") + 1); } if (name.indexOf(";") > 0) { name = name.substring(0, name.indexOf(";")); } store.setChannelName(name.trim(), 0, c); } } } IFD ifd = ifds.get(0); String physicalSize = ifd.getIFDTextValue(PHYSICAL_SIZE_TAG); if (physicalSize != null) { Double size = new Double(physicalSize); if (size > 0) { store.setPixelsPhysicalSizeX(FormatTools.getPhysicalSizeX(size), 0); store.setPixelsPhysicalSizeY(FormatTools.getPhysicalSizeY(size), 0); } } String mag = ifd.getIFDTextValue(MAGNIFICATION_TAG); if (mag != null) { store.setInstrumentID(MetadataTools.createLSID("Instrument", 0), 0); store.setObjectiveID(MetadataTools.createLSID("Objective", 0, 0), 0, 0); store.setObjectiveCorrection(getCorrection("Other"), 0, 0); store.setObjectiveImmersion(getImmersion("Other"), 0, 0); store.setObjectiveNominalMagnification(new Double(mag), 0, 0); } final Double xn = Double.valueOf(ifd.getIFDTextValue(X_POS_TAG)); final Double yn = Double.valueOf(ifd.getIFDTextValue(Y_POS_TAG)); final Double zn = Double.valueOf(ifd.getIFDTextValue(Z_POS_TAG)); final Length xl = new Length(xn, UNITS.REFERENCEFRAME); final Length yl = new Length(yn, UNITS.REFERENCEFRAME); final Length zl = new Length(zn, UNITS.REFERENCEFRAME); for (int i=0; i<getImageCount(); i++) { store.setPlanePositionX(xl, 0, i); store.setPlanePositionY(yl, 0, i); store.setPlanePositionZ(zl, 0, i); } } } // -- Helper methods -- private String getTimestamp(String path) throws FormatException, IOException { RandomAccessInputStream s = new RandomAccessInputStream(path); TiffParser parser = new TiffParser(s); IFD ifd = parser.getFirstIFD(); Object date = ifd.getIFDValue(IFD.DATE_TIME); s.close(); return date == null ? null : date.toString(); } private String getFirstChannel(String path) throws FormatException, IOException { RandomAccessInputStream s = new RandomAccessInputStream(path); TiffParser parser = new TiffParser(s); IFD ifd = parser.getFirstIFD(); Object channel = ifd.getIFDValue(CHANNEL_TAG); s.close(); parser.getStream().close(); return channel == null ? null : channel.toString(); } }