// // FileStitcher.java // /* LOCI Bio-Formats package for reading and converting biological file formats. Copyright (C) 2005-@year@ Melissa Linkert, Curtis Rueden, Chris Allan, Eric Kjellman and Brian Loranger. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library 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 Library General Public License for more details. You should have received a copy of the GNU Library 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; import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.util.*; /** * Logic to stitch together files with similar names. * Assumes that all files have the same dimensions. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="https://skyking.microscopy.wisc.edu/trac/java/browser/trunk/loci/formats/FileStitcher.java">Trac</a>, * <a href="https://skyking.microscopy.wisc.edu/svn/java/trunk/loci/formats/FileStitcher.java">SVN</a></dd></dl> */ public class FileStitcher implements IFormatReader { // -- Fields -- /** FormatReader to use as a template for constituent readers. */ private IFormatReader reader; /** * Whether string ids given should be treated * as file patterns rather than single file paths. */ private boolean patternIds = false; /** Current file pattern string. */ private String currentId; /** File pattern object used to build the list of files. */ private FilePattern fp; /** Axis guesser object used to guess which dimensional axes are which. */ private AxisGuesser[] ag; /** The matching files. */ private String[] files; /** Used files list. */ private String[] usedFiles; /** Reader used for each file. */ private IFormatReader[] readers; /** Blank buffered image, for use when image counts vary between files. */ private BufferedImage[] blankImage; /** Blank image bytes, for use when image counts vary between files. */ private byte[][] blankBytes; /** Blank buffered thumbnail, for use when image counts vary between files. */ private BufferedImage[] blankThumb; /** Blank thumbnail bytes, for use when image counts vary between files. */ private byte[][] blankThumbBytes; /** Number of images per file. */ private int[] imagesPerFile; /** Dimensional axis lengths per file. */ private int[] sizeZ, sizeC, sizeT; /** Component lengths for each axis type. */ private int[][] lenZ, lenC, lenT; /** Core metadata. */ private CoreMetadata core; // -- Constructors -- /** Constructs a FileStitcher around a new image reader. */ public FileStitcher() { this(new ImageReader()); } /** * Constructs a FileStitcher around a new image reader. * @param patternIds Whether string ids given should be treated as file * patterns rather than single file paths. */ public FileStitcher(boolean patternIds) { this(new ImageReader(), patternIds); } /** * Constructs a FileStitcher with the given reader. * @param r The reader to use for reading stitched files. */ public FileStitcher(IFormatReader r) { this(r, false); } /** * Constructs a FileStitcher with the given reader. * @param r The reader to use for reading stitched files. * @param patternIds Whether string ids given should be treated as file * patterns rather than single file paths. */ public FileStitcher(IFormatReader r, boolean patternIds) { reader = r; this.patternIds = patternIds; } // -- FileStitcher API methods -- /** Gets the wrapped reader prototype. */ public IFormatReader getReader() { return reader; } /** * Gets the axis type for each dimensional block. * @return An array containing values from the enumeration: * <ul> * <li>AxisGuesser.Z_AXIS: focal planes</li> * <li>AxisGuesser.T_AXIS: time points</li> * <li>AxisGuesser.C_AXIS: channels</li> * </ul> */ public int[] getAxisTypes() { FormatTools.assertId(currentId, true, 2); return ag[getSeries()].getAxisTypes(); } /** * Sets the axis type for each dimensional block. * @param axes An array containing values from the enumeration: * <ul> * <li>AxisGuesser.Z_AXIS: focal planes</li> * <li>AxisGuesser.T_AXIS: time points</li> * <li>AxisGuesser.C_AXIS: channels</li> * </ul> */ public void setAxisTypes(int[] axes) throws FormatException { FormatTools.assertId(currentId, true, 2); ag[getSeries()].setAxisTypes(axes); computeAxisLengths(); } /** Gets the file pattern object used to build the list of files. */ public FilePattern getFilePattern() { FormatTools.assertId(currentId, true, 2); return fp; } /** * Gets the axis guesser object used to guess * which dimensional axes are which. */ public AxisGuesser getAxisGuesser() { FormatTools.assertId(currentId, true, 2); return ag[getSeries()]; } /** * Finds the file pattern for the given ID, based on the state of the file * stitcher. Takes both ID map entries and the patternIds flag into account. */ public FilePattern findPattern(String id) { FormatTools.assertId(currentId, true, 2); if (!patternIds) { // find the containing pattern Hashtable map = Location.getIdMap(); String pattern = null; if (map.containsKey(id)) { // search ID map for pattern, rather than files on disk String[] idList = new String[map.size()]; Enumeration en = map.keys(); for (int i=0; i<idList.length; i++) { idList[i] = (String) en.nextElement(); } pattern = FilePattern.findPattern(id, null, idList); } else { // id is an unmapped file path; look to similar files on disk pattern = FilePattern.findPattern(new Location(id)); } if (pattern != null) id = pattern; } return new FilePattern(id); } // -- IFormatReader API methods -- /* @see IFormatReader#isThisType(byte[]) */ public boolean isThisType(byte[] block) { return reader.isThisType(block); } /* @see IFormatReader#setId(String) */ public void setId(String id) throws FormatException, IOException { if (!id.equals(currentId)) initFile(id); } /* @see IFormatReader#setId(String, boolean) */ public void setId(String id, boolean force) throws FormatException, IOException { if (!id.equals(currentId) || force) initFile(id); } /* @see IFormatReader#getImageCount() */ public int getImageCount() { FormatTools.assertId(currentId, true, 2); return core.imageCount[getSeries()]; } /* @see IFormatReader#isRGB() */ public boolean isRGB() { FormatTools.assertId(currentId, true, 2); return core.rgb[getSeries()]; } /* @see IFormatReader#getSizeX() */ public int getSizeX() { FormatTools.assertId(currentId, true, 2); return core.sizeX[getSeries()]; } /* @see IFormatReader#getSizeY() */ public int getSizeY() { FormatTools.assertId(currentId, true, 2); return core.sizeY[getSeries()]; } /* @see IFormatReader#getSizeZ() */ public int getSizeZ() { FormatTools.assertId(currentId, true, 2); return core.sizeZ[getSeries()]; } /* @see IFormatReader#getSizeC() */ public int getSizeC() { FormatTools.assertId(currentId, true, 2); return core.sizeC[getSeries()]; } /* @see IFormatReader#getSizeT() */ public int getSizeT() { FormatTools.assertId(currentId, true, 2); return core.sizeT[getSeries()]; } /* @see IFormatReader#getPixelType() */ public int getPixelType() { FormatTools.assertId(currentId, true, 2); return core.pixelType[getSeries()]; } /* @see IFormatReader#getEffectiveSizeC() */ public int getEffectiveSizeC() { FormatTools.assertId(currentId, true, 2); return getImageCount() / (getSizeZ() * getSizeT()); } /* @see IFormatReader#getRGBChannelCount() */ public int getRGBChannelCount() { FormatTools.assertId(currentId, true, 2); return getSizeC() / getEffectiveSizeC(); } /* @see IFormatReader#isIndexed() */ public boolean isIndexed() { FormatTools.assertId(currentId, true, 2); return reader.isIndexed(); } /* @see IFormatReader#isFalseColor() */ public boolean isFalseColor() { FormatTools.assertId(currentId, true, 2); return reader.isFalseColor(); } /* @see IFormatReader#get8BitLookupTable() */ public byte[][] get8BitLookupTable() throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); return reader.get8BitLookupTable(); } /* @see IFormatReader#get16BitLookupTable() */ public short[][] get16BitLookupTable() throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); return reader.get16BitLookupTable(); } /* @see IFormatReader#getChannelDimLengths() */ public int[] getChannelDimLengths() { FormatTools.assertId(currentId, true, 1); return core.cLengths[getSeries()]; } /* @see IFormatReader#getChannelDimTypes() */ public String[] getChannelDimTypes() { FormatTools.assertId(currentId, true, 1); return core.cTypes[getSeries()]; } /* @see IFormatReader#getThumbSizeX() */ public int getThumbSizeX() { FormatTools.assertId(currentId, true, 2); return reader.getThumbSizeX(); } /* @see IFormatReader#getThumbSizeY() */ public int getThumbSizeY() { FormatTools.assertId(currentId, true, 2); return reader.getThumbSizeY(); } /* @see IFormatReader#isLittleEndian() */ public boolean isLittleEndian() { FormatTools.assertId(currentId, true, 2); return reader.isLittleEndian(); } /* @see IFormatReader#getDimensionOrder() */ public String getDimensionOrder() { FormatTools.assertId(currentId, true, 2); return core.currentOrder[getSeries()]; } /* @see IFormatReader#isOrderCertain() */ public boolean isOrderCertain() { FormatTools.assertId(currentId, true, 2); return core.orderCertain[getSeries()]; } /* @see IFormatReader#isInterleaved() */ public boolean isInterleaved() { FormatTools.assertId(currentId, true, 2); return reader.isInterleaved(); } /* @see IFormatReader#isInterleaved(int) */ public boolean isInterleaved(int subC) { FormatTools.assertId(currentId, true, 2); return reader.isInterleaved(subC); } /* @see IFormatReader#openImage(int) */ public BufferedImage openImage(int no) throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); int[] q = computeIndices(no); int fno = q[0], ino = q[1]; if (ino < readers[fno].getImageCount()) { return readers[fno].openImage(ino); } // return a blank image to cover for the fact that // this file does not contain enough image planes int sno = getSeries(); if (blankImage[sno] == null) { blankImage[sno] = ImageTools.blankImage(core.sizeX[sno], core.sizeY[sno], sizeC[sno], getPixelType()); } return blankImage[sno]; } /* @see IFormatReader#openBytes(int) */ public byte[] openBytes(int no) throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); int[] q = computeIndices(no); int fno = q[0], ino = q[1]; if (ino < readers[fno].getImageCount()) { return readers[fno].openBytes(ino); } // return a blank image to cover for the fact that // this file does not contain enough image planes int sno = getSeries(); if (blankBytes[sno] == null) { int bytes = FormatTools.getBytesPerPixel(getPixelType()); blankBytes[sno] = new byte[core.sizeX[sno] * core.sizeY[sno] * bytes * getRGBChannelCount()]; } return blankBytes[sno]; } /* @see IFormatReader#openBytes(int, byte[]) */ public byte[] openBytes(int no, byte[] buf) throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); int[] q = computeIndices(no); int fno = q[0], ino = q[1]; if (ino < readers[fno].getImageCount()) { return readers[fno].openBytes(ino, buf); } // return a blank image to cover for the fact that // this file does not contain enough image planes Arrays.fill(buf, (byte) 0); return buf; } /* @see IFormatReader#openThumbImage(int) */ public BufferedImage openThumbImage(int no) throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); int[] q = computeIndices(no); int fno = q[0], ino = q[1]; if (ino < readers[fno].getImageCount()) { return readers[fno].openThumbImage(ino); } // return a blank image to cover for the fact that // this file does not contain enough image planes int sno = getSeries(); if (blankThumb[sno] == null) { blankThumb[sno] = ImageTools.blankImage(getThumbSizeX(), getThumbSizeY(), sizeC[sno], getPixelType()); } return blankThumb[sno]; } /* @see IFormatReader#openThumbBytes(int) */ public byte[] openThumbBytes(int no) throws FormatException, IOException { FormatTools.assertId(currentId, true, 2); int[] q = computeIndices(no); int fno = q[0], ino = q[1]; if (ino < readers[fno].getImageCount()) { return readers[fno].openThumbBytes(ino); } // return a blank image to cover for the fact that // this file does not contain enough image planes int sno = getSeries(); if (blankThumbBytes[sno] == null) { int bytes = FormatTools.getBytesPerPixel(getPixelType()); blankThumbBytes[sno] = new byte[getThumbSizeX() * getThumbSizeY() * bytes * getRGBChannelCount()]; } return blankThumbBytes[sno]; } /* @see IFormatReader#close(boolean) */ public void close(boolean fileOnly) throws IOException { if (readers == null) reader.close(fileOnly); else { for (int i=0; i<readers.length; i++) readers[i].close(fileOnly); } if (!fileOnly) { readers = null; blankImage = null; blankBytes = null; currentId = null; } } /* @see IFormatReader#close() */ public void close() throws IOException { if (readers == null) reader.close(); else { for (int i=0; i<readers.length; i++) readers[i].close(); } readers = null; blankImage = null; blankBytes = null; currentId = null; } /* @see IFormatReader#getSeriesCount() */ public int getSeriesCount() { FormatTools.assertId(currentId, true, 2); return reader.getSeriesCount(); } /* @see IFormatReader#setSeries(int) */ public void setSeries(int no) { FormatTools.assertId(currentId, true, 2); reader.setSeries(no); } /* @see IFormatReader#getSeries() */ public int getSeries() { FormatTools.assertId(currentId, true, 2); return reader.getSeries(); } /* @see IFormatReader#setGroupFiles(boolean) */ public void setGroupFiles(boolean group) { for (int i=0; i<readers.length; i++) readers[i].setGroupFiles(group); } /* @see IFormatReader#isGroupFiles() */ public boolean isGroupFiles() { return readers[0].isGroupFiles(); } /* @see IFormatReader#fileGroupOption(String) */ public int fileGroupOption(String id) throws FormatException, IOException { return readers[0].fileGroupOption(id); } /* @see IFormatReader#isMetadataComplete() */ public boolean isMetadataComplete() { return readers[0].isMetadataComplete(); } /* @see IFormatReader#setNormalized(boolean) */ public void setNormalized(boolean normalize) { FormatTools.assertId(currentId, false, 2); if (readers == null) reader.setNormalized(normalize); else { for (int i=0; i<readers.length; i++) { readers[i].setNormalized(normalize); } } } /* @see IFormatReader#isNormalized() */ public boolean isNormalized() { return reader.isNormalized(); } /* @see IFormatReader#setMetadataCollected(boolean) */ public void setMetadataCollected(boolean collect) { FormatTools.assertId(currentId, false, 2); if (readers == null) reader.setMetadataCollected(collect); else { for (int i=0; i<readers.length; i++) { readers[i].setMetadataCollected(collect); } } } /* @see IFormatReader#isMetadataCollected() */ public boolean isMetadataCollected() { return reader.isMetadataCollected(); } /* @see IFormatReader#setOriginalMetadataPopulated(boolean) */ public void setOriginalMetadataPopulated(boolean populate) { FormatTools.assertId(currentId, false, 1); if (readers == null) reader.setOriginalMetadataPopulated(populate); else { for (int i=0; i<readers.length; i++) { readers[i].setOriginalMetadataPopulated(populate); } } } /* @see IFormatReader#isOriginalMetadataPopulated() */ public boolean isOriginalMetadataPopulated() { return reader.isOriginalMetadataPopulated(); } /* @see IFormatReader#getUsedFiles() */ public String[] getUsedFiles() { FormatTools.assertId(currentId, true, 2); // returning the files list directly here is fast, since we do not // have to call initFile on each constituent file; but we can only do so // when each constituent file does not itself have multiple used files if (reader.getUsedFiles().length > 1) { // each constituent file has multiple used files; we must build the list // this could happen with, e.g., a stitched collection of ICS/IDS pairs // we have no datasets structured this way, so this logic is untested if (usedFiles == null) { String[][] used = new String[files.length][]; int total = 0; for (int i=0; i<files.length; i++) { try { readers[i].setId(files[i]); } catch (FormatException exc) { LogTools.trace(exc); return null; } catch (IOException exc) { LogTools.trace(exc); return null; } used[i] = readers[i].getUsedFiles(); total += used[i].length; } usedFiles = new String[total]; for (int i=0, off=0; i<used.length; i++) { System.arraycopy(used[i], 0, usedFiles, off, used[i].length); off += used[i].length; } } return usedFiles; } // assume every constituent file has no other used files // this logic could fail if the first constituent has no extra used files, // but later constituents do; in practice, this scenario seems unlikely return files; } /* @see IFormatReader#getCurrentFile() */ public String getCurrentFile() { return currentId; } /* @see IFormatReader#getIndex(int, int, int) */ public int getIndex(int z, int c, int t) { return FormatTools.getIndex(this, z, c, t); } /* @see IFormatReader#getZCTCoords(int) */ public int[] getZCTCoords(int index) { return FormatTools.getZCTCoords(this, index); } /* @see IFormatReader#getMetadataValue(String) */ public Object getMetadataValue(String field) { FormatTools.assertId(currentId, true, 2); return reader.getMetadataValue(field); } /* @see IFormatReader#getMetadata() */ public Hashtable getMetadata() { FormatTools.assertId(currentId, true, 2); return reader.getMetadata(); } /* @see IFormatReader#getCoreMetadata() */ public CoreMetadata getCoreMetadata() { FormatTools.assertId(currentId, true, 2); return core; } /* @see IFormatReader#setMetadataFiltered(boolean) */ public void setMetadataFiltered(boolean filter) { FormatTools.assertId(currentId, false, 2); reader.setMetadataFiltered(filter); } /* @see IFormatReader#isMetadataFiltered() */ public boolean isMetadataFiltered() { return reader.isMetadataFiltered(); } /* @see IFormatReader#setMetadataStore(MetadataStore) */ public void setMetadataStore(MetadataStore store) { FormatTools.assertId(currentId, false, 2); reader.setMetadataStore(store); } /* @see IFormatReader#getMetadataStore() */ public MetadataStore getMetadataStore() { FormatTools.assertId(currentId, true, 2); return reader.getMetadataStore(); } /* @see IFormatReader#getMetadataStoreRoot() */ public Object getMetadataStoreRoot() { FormatTools.assertId(currentId, true, 2); return reader.getMetadataStoreRoot(); } // -- IFormatHandler API methods -- /* @see IFormatHandler#isThisType(String) */ public boolean isThisType(String name) { return reader.isThisType(name); } /* @see IFormatHandler#isThisType(String, boolean) */ public boolean isThisType(String name, boolean open) { return reader.isThisType(name, open); } /* @see IFormatHandler#getFormat() */ public String getFormat() { FormatTools.assertId(currentId, true, 2); return reader.getFormat(); } /* @see IFormatHandler#getSuffixes() */ public String[] getSuffixes() { return reader.getSuffixes(); } // -- StatusReporter API methods -- /* @see IFormatHandler#addStatusListener(StatusListener) */ public void addStatusListener(StatusListener l) { if (readers == null) reader.addStatusListener(l); else { for (int i=0; i<readers.length; i++) readers[i].addStatusListener(l); } } /* @see IFormatHandler#removeStatusListener(StatusListener) */ public void removeStatusListener(StatusListener l) { if (readers == null) reader.removeStatusListener(l); else { for (int i=0; i<readers.length; i++) readers[i].removeStatusListener(l); } } /* @see IFormatHandler#getStatusListeners() */ public StatusListener[] getStatusListeners() { return reader.getStatusListeners(); } // -- Helper methods -- /** Initializes the given file. */ protected void initFile(String id) throws FormatException, IOException { if (FormatHandler.debug) { LogTools.println("calling FileStitcher.initFile(" + id + ")"); } currentId = id; fp = findPattern(id); // verify that file pattern is valid and matches existing files String msg = " Please rename your files or disable file stitching."; if (!fp.isValid()) { throw new FormatException("Invalid " + (patternIds ? "file pattern" : "filename") + " (" + currentId + "): " + fp.getErrorMessage() + msg); } files = fp.getFiles(); if (files == null) { throw new FormatException("No files matching pattern (" + fp.getPattern() + "). " + msg); } for (int i=0; i<files.length; i++) { if (!new Location(files[i]).exists()) { throw new FormatException("File #" + i + " (" + files[i] + ") does not exist."); } } // determine reader type for these files; assume all are the same type Vector classes = new Vector(); IFormatReader r = reader; while (r instanceof ReaderWrapper) { classes.add(r.getClass()); r = ((ReaderWrapper) r).getReader(); } if (r instanceof ImageReader) r = ((ImageReader) r).getReader(files[0]); classes.add(r.getClass()); // construct list of readers for all files readers = new IFormatReader[files.length]; readers[0] = reader; for (int i=1; i<readers.length; i++) { // use crazy reflection to instantiate a reader of the proper type try { r = null; for (int j=classes.size()-1; j>=0; j--) { Class c = (Class) classes.elementAt(j); if (r == null) r = (IFormatReader) c.newInstance(); else { r = (IFormatReader) c.getConstructor( new Class[] {IFormatReader.class}).newInstance(new Object[] {r}); } } readers[i] = (IFormatReader) r; } catch (InstantiationException exc) { LogTools.trace(exc); } catch (IllegalAccessException exc) { LogTools.trace(exc); } catch (NoSuchMethodException exc) { LogTools.trace(exc); } catch (InvocationTargetException exc) { LogTools.trace(exc); } } // sync reader configurations with original reader boolean normalized = reader.isNormalized(); boolean metadataFiltered = reader.isMetadataFiltered(); boolean metadataCollected = reader.isMetadataCollected(); StatusListener[] statusListeners = reader.getStatusListeners(); for (int i=1; i<readers.length; i++) { readers[i].setNormalized(normalized); readers[i].setMetadataFiltered(metadataFiltered); readers[i].setMetadataCollected(metadataCollected); for (int j=0; j<statusListeners.length; j++) { readers[i].addStatusListener(statusListeners[j]); } } reader.setId(files[0]); int seriesCount = reader.getSeriesCount(); ag = new AxisGuesser[seriesCount]; blankImage = new BufferedImage[seriesCount]; blankBytes = new byte[seriesCount][]; blankThumb = new BufferedImage[seriesCount]; blankThumbBytes = new byte[seriesCount][]; imagesPerFile = new int[seriesCount]; sizeZ = new int[seriesCount]; sizeC = new int[seriesCount]; sizeT = new int[seriesCount]; boolean[] certain = new boolean[seriesCount]; lenZ = new int[seriesCount][]; lenC = new int[seriesCount][]; lenT = new int[seriesCount][]; // analyze first file; assume each file has the same parameters core = new CoreMetadata(seriesCount); int oldSeries = reader.getSeries(); for (int i=0; i<seriesCount; i++) { reader.setSeries(i); core.sizeX[i] = reader.getSizeX(); core.sizeY[i] = reader.getSizeY(); // NB: core.sizeZ populated in computeAxisLengths below // NB: core.sizeC populated in computeAxisLengths below // NB: core.sizeT populated in computeAxisLengths below core.pixelType[i] = reader.getPixelType(); imagesPerFile[i] = reader.getImageCount(); core.imageCount[i] = files.length * imagesPerFile[i]; core.thumbSizeX[i] = reader.getThumbSizeX(); core.thumbSizeY[i] = reader.getThumbSizeY(); // NB: core.cLengths[i] populated in computeAxisLengths below // NB: core.cTypes[i] populated in computeAxisLengths below core.currentOrder[i] = reader.getDimensionOrder(); // NB: core.orderCertain[i] populated below core.rgb[i] = reader.isRGB(); core.littleEndian[i] = reader.isLittleEndian(); core.interleaved[i] = reader.isInterleaved(); core.seriesMetadata[i] = reader.getMetadata(); sizeZ[i] = reader.getSizeZ(); sizeC[i] = reader.getSizeC(); sizeT[i] = reader.getSizeT(); certain[i] = reader.isOrderCertain(); } reader.setSeries(oldSeries); // guess at dimensions corresponding to file numbering for (int i=0; i<seriesCount; i++) { ag[i] = new AxisGuesser(fp, core.currentOrder[i], sizeZ[i], sizeT[i], sizeC[i], certain[i]); } // order may need to be adjusted for (int i=0; i<seriesCount; i++) { setSeries(i); core.currentOrder[i] = ag[i].getAdjustedOrder(); core.orderCertain[i] = ag[i].isCertain(); computeAxisLengths(); } setSeries(oldSeries); // initialize used files list only when requested usedFiles = null; } /** Computes axis length arrays, and total axis lengths. */ protected void computeAxisLengths() throws FormatException { int sno = getSeries(); int[] count = fp.getCount(); int[] axes = ag[sno].getAxisTypes(); int numZ = ag[sno].getAxisCountZ(); int numC = ag[sno].getAxisCountC(); int numT = ag[sno].getAxisCountT(); core.sizeZ[sno] = sizeZ[sno]; core.sizeC[sno] = sizeC[sno]; core.sizeT[sno] = sizeT[sno]; lenZ[sno] = new int[numZ + 1]; lenC[sno] = new int[numC + 1]; lenT[sno] = new int[numT + 1]; lenZ[sno][0] = sizeZ[sno]; lenC[sno][0] = sizeC[sno]; lenT[sno][0] = sizeT[sno]; for (int i=0, z=1, c=1, t=1; i<axes.length; i++) { switch (axes[i]) { case AxisGuesser.Z_AXIS: core.sizeZ[sno] *= count[i]; lenZ[sno][z++] = count[i]; break; case AxisGuesser.C_AXIS: core.sizeC[sno] *= count[i]; lenC[sno][c++] = count[i]; break; case AxisGuesser.T_AXIS: core.sizeT[sno] *= count[i]; lenT[sno][t++] = count[i]; break; default: throw new FormatException("Unknown axis type for axis #" + i + ": " + axes[i]); } } int[] cLengths = reader.getChannelDimLengths(); String[] cTypes = reader.getChannelDimTypes(); int cCount = 0; for (int i=0; i<cLengths.length; i++) { if (cLengths[i] > 1) cCount++; } for (int i=1; i<lenC[sno].length; i++) { if (lenC[sno][i] > 1) cCount++; } if (cCount == 0) { core.cLengths[sno] = new int[] {1}; core.cTypes[sno] = new String[] {FormatTools.CHANNEL}; } else { core.cLengths[sno] = new int[cCount]; core.cTypes[sno] = new String[cCount]; } int c = 0; for (int i=0; i<cLengths.length; i++) { if (cLengths[i] == 1) continue; core.cLengths[sno][c] = cLengths[i]; core.cTypes[sno][c] = cTypes[i]; c++; } for (int i=1; i<lenC[sno].length; i++) { if (lenC[sno][i] == 1) continue; core.cLengths[sno][c] = lenC[sno][i]; core.cTypes[sno][c] = FormatTools.CHANNEL; } // populate metadata store int pixelType = getPixelType(); boolean little = reader.isLittleEndian(); MetadataStore s = reader.getMetadataStore(); s.setPixels(new Integer(core.sizeX[sno]), new Integer(core.sizeY[sno]), new Integer(core.sizeZ[sno]), new Integer(core.sizeC[sno]), new Integer(core.sizeT[sno]), new Integer(pixelType), new Boolean(!little), core.currentOrder[sno], new Integer(sno), null); } /** * Gets the file index, and image index into that file, * corresponding to the given global image index. * * @return An array of size 2, dimensioned {file index, image index}. */ protected int[] computeIndices(int no) throws FormatException, IOException { int sno = getSeries(); int[] axes = ag[sno].getAxisTypes(); int[] count = fp.getCount(); // get Z, C and T positions int[] zct = getZCTCoords(no); zct[1] *= getRGBChannelCount(); int[] posZ = FormatTools.rasterToPosition(lenZ[sno], zct[0]); int[] posC = FormatTools.rasterToPosition(lenC[sno], zct[1]); int[] posT = FormatTools.rasterToPosition(lenT[sno], zct[2]); // convert Z, C and T position lists into file index and image index int[] pos = new int[axes.length]; int z = 1, c = 1, t = 1; for (int i=0; i<axes.length; i++) { if (axes[i] == AxisGuesser.Z_AXIS) pos[i] = posZ[z++]; else if (axes[i] == AxisGuesser.C_AXIS) pos[i] = posC[c++]; else if (axes[i] == AxisGuesser.T_AXIS) pos[i] = posT[t++]; else { throw new FormatException("Unknown axis type for axis #" + i + ": " + axes[i]); } } int fno = FormatTools.positionToRaster(count, pos); // configure the reader, in case we haven't done this one yet readers[fno].setId(files[fno]); readers[fno].setSeries(reader.getSeries()); int ino; if (posZ[0] < readers[fno].getSizeZ() && posC[0] < readers[fno].getSizeC() && posT[0] < readers[fno].getSizeT()) { ino = FormatTools.getIndex(readers[fno], posZ[0], posC[0], posT[0]); } else ino = Integer.MAX_VALUE; // coordinates out of range return new int[] {fno, ino}; } /** * Gets a list of readers to include in relation to the given C position. * @return Array with indices corresponding to the list of readers, and * values indicating the internal channel index to use for that reader. */ protected int[] getIncludeList(int theC) throws FormatException, IOException { int[] include = new int[readers.length]; Arrays.fill(include, -1); for (int t=0; t<sizeT[getSeries()]; t++) { for (int z=0; z<sizeZ[getSeries()]; z++) { int no = getIndex(z, theC, t); int[] q = computeIndices(no); int fno = q[0], ino = q[1]; include[fno] = ino; } } return include; } // -- Deprecated FileStitcher API methods -- /** @deprecated Replaced by {@link #getAxisTypes()} */ public int[] getAxisTypes(String id) throws FormatException, IOException { setId(id); return getAxisTypes(); } /** @deprecated Replaced by {@link #setAxisTypes(int[])} */ public void setAxisTypes(String id, int[] axes) throws FormatException, IOException { setId(id); setAxisTypes(axes); } /** @deprecated Replaced by {@link #getFilePattern()} */ public FilePattern getFilePattern(String id) throws FormatException, IOException { setId(id); return getFilePattern(); } /** @deprecated Replaced by {@link #getAxisGuesser()} */ public AxisGuesser getAxisGuesser(String id) throws FormatException, IOException { setId(id); return getAxisGuesser(); } // -- Deprecated IFormatReader API methods -- /** @deprecated Replaced by {@link #getImageCount()} */ public int getImageCount(String id) throws FormatException, IOException { setId(id); return getImageCount(); } /** @deprecated Replaced by {@link #isRGB()} */ public boolean isRGB(String id) throws FormatException, IOException { setId(id); return isRGB(); } /** @deprecated Replaced by {@link #getSizeX()} */ public int getSizeX(String id) throws FormatException, IOException { setId(id); return getSizeX(); } /** @deprecated Replaced by {@link #getSizeY()} */ public int getSizeY(String id) throws FormatException, IOException { setId(id); return getSizeY(); } /** @deprecated Replaced by {@link #getSizeZ()} */ public int getSizeZ(String id) throws FormatException, IOException { setId(id); return getSizeZ(); } /** @deprecated Replaced by {@link #getSizeC()} */ public int getSizeC(String id) throws FormatException, IOException { setId(id); return getSizeC(); } /** @deprecated Replaced by {@link #getSizeT()} */ public int getSizeT(String id) throws FormatException, IOException { setId(id); return getSizeT(); } /** @deprecated Replaced by {@link #getPixelType()} */ public int getPixelType(String id) throws FormatException, IOException { setId(id); return getPixelType(); } /** @deprecated Replaced by {@link #getEffectiveSizeC()} */ public int getEffectiveSizeC(String id) throws FormatException, IOException { setId(id); return getEffectiveSizeC(); } /** @deprecated Replaced by {@link #getRGBChannelCount()} */ public int getRGBChannelCount(String id) throws FormatException, IOException { setId(id); return getSizeC() / getEffectiveSizeC(); } /** @deprecated Replaced by {@link #getChannelDimLengths()} */ public int[] getChannelDimLengths(String id) throws FormatException, IOException { setId(id); return getChannelDimLengths(); } /** @deprecated Replaced by {@link #getChannelDimTypes()} */ public String[] getChannelDimTypes(String id) throws FormatException, IOException { setId(id); return getChannelDimTypes(); } /** @deprecated Replaced by {@link #getThumbSizeX()} */ public int getThumbSizeX(String id) throws FormatException, IOException { setId(id); return getThumbSizeX(); } /** @deprecated Replaced by {@link #getThumbSizeY()} */ public int getThumbSizeY(String id) throws FormatException, IOException { setId(id); return getThumbSizeY(); } /** @deprecated Replaced by {@link #isLittleEndian()} */ public boolean isLittleEndian(String id) throws FormatException, IOException { setId(id); return isLittleEndian(); } /** @deprecated Replaced by {@link #getDimensionOrder()} */ public String getDimensionOrder(String id) throws FormatException, IOException { setId(id); return getDimensionOrder(); } /** @deprecated Replaced by {@link #isOrderCertain()} */ public boolean isOrderCertain(String id) throws FormatException, IOException { setId(id); return isOrderCertain(); } /** @deprecated Replaced by {@link #isInterleaved()} */ public boolean isInterleaved(String id) throws FormatException, IOException { setId(id); return isInterleaved(); } /** @deprecated Replaced by {@link #isInterleaved(int)} */ public boolean isInterleaved(String id, int subC) throws FormatException, IOException { setId(id); return isInterleaved(subC); } /** @deprecated Replaced by {@link #openImage(int)} */ public BufferedImage openImage(String id, int no) throws FormatException, IOException { setId(id); return openImage(no); } /** @deprecated Replaced by {@link #openBytes(int)} */ public byte[] openBytes(String id, int no) throws FormatException, IOException { setId(id); return openBytes(no); } /** @deprecated Replaced by {@link #openBytes(int, byte[])} */ public byte[] openBytes(String id, int no, byte[] buf) throws FormatException, IOException { setId(id); return openBytes(no, buf); } /** @deprecated Replaced by {@link #openThumbImage(int)} */ public BufferedImage openThumbImage(String id, int no) throws FormatException, IOException { setId(id); return openThumbImage(no); } /** @deprecated Replaced by {@link #openThumbImage(int)} */ public byte[] openThumbBytes(String id, int no) throws FormatException, IOException { setId(id); return openThumbBytes(no); } /** @deprecated Replaced by {@link #getSeriesCount()} */ public int getSeriesCount(String id) throws FormatException, IOException { setId(id); return getSeriesCount(); } /** @deprecated Replaced by {@link #setSeries(int)} */ public void setSeries(String id, int no) throws FormatException, IOException { setId(id); setSeries(no); } /** @deprecated Replaced by {@link #getSeries()} */ public int getSeries(String id) throws FormatException, IOException { setId(id); return getSeries(); } /** @deprecated Replaced by {@link #getUsedFiles()} */ public String[] getUsedFiles(String id) throws FormatException, IOException { setId(id); return getUsedFiles(); } /** @deprecated Replaced by {@link #getIndex(int, int, int)} */ public int getIndex(String id, int z, int c, int t) throws FormatException, IOException { setId(id); return getIndex(z, c, t); } /** @deprecated Replaced by {@link #getZCTCoords(int)} */ public int[] getZCTCoords(String id, int index) throws FormatException, IOException { setId(id); return getZCTCoords(index); } /** @deprecated Replaced by {@link #getMetadataValue(String)} */ public Object getMetadataValue(String id, String field) throws FormatException, IOException { setId(id); return getMetadataValue(field); } /** @deprecated Replaced by {@link #getMetadata()} */ public Hashtable getMetadata(String id) throws FormatException, IOException { setId(id); return getMetadata(); } /** @deprecated Replaced by {@link #getCoreMetadata()} */ public CoreMetadata getCoreMetadata(String id) throws FormatException, IOException { setId(id); return getCoreMetadata(); } /** @deprecated Replaced by {@link #getMetadataStore()} */ public MetadataStore getMetadataStore(String id) throws FormatException, IOException { setId(id); return getMetadataStore(); } /** @deprecated Replaced by {@link #getMetadataStoreRoot()} */ public Object getMetadataStoreRoot(String id) throws FormatException, IOException { setId(id); return getMetadataStoreRoot(); } }