// // BrukerReader.java // /* OME Bio-Formats package for reading and converting biological file formats. Copyright (C) 2005-@year@ UW-Madison LOCI and Glencoe Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package loci.formats.in; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; 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.MetadataStore; /** * BrukerReader is the file format reader for Bruker MRI files. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/in/BrukerReader.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/BrukerReader.java;hb=HEAD">Gitweb</a></dd></dl> * * @author Melissa Linkert melissa at glencoesoftware.com */ public class BrukerReader extends FormatReader { // -- Constants -- private static final String DATE_FORMAT = "HH:mm:ss d MMM yyyy"; // -- Fields -- private ArrayList<String> pixelsFiles = new ArrayList<String>(); private ArrayList<String> allFiles = new ArrayList<String>(); // -- Constructor -- /** Constructs a new Bruker reader. */ public BrukerReader() { super("Bruker", ""); suffixSufficient = false; domains = new String[] {FormatTools.MEDICAL_DOMAIN}; hasCompanionFiles = true; datasetDescription = "One 'fid' and one 'acqp' plus several other " + "metadata files and a 'pdata' directory"; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isSingleFile(String) */ public boolean isSingleFile(String id) throws FormatException, IOException { return false; } /* @see loci.formats.IFormatReader#isThisType(String, boolean) */ public boolean isThisType(String name, boolean open) { Location file = new Location(name).getAbsoluteFile(); return file.getName().equals("fid") || file.getName().equals("acqp"); } /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ public boolean isThisType(RandomAccessInputStream stream) throws IOException { return false; } /** * @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int) */ public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h) throws FormatException, IOException { FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h); RandomAccessInputStream s = new RandomAccessInputStream(pixelsFiles.get(getSeries())); s.seek(no * FormatTools.getPlaneSize(this)); readPlane(s, x, y, w, h, buf); s.close(); return buf; } /* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */ public String[] getSeriesUsedFiles(boolean noPixels) { FormatTools.assertId(currentId, true, 1); String dir = pixelsFiles.get(getSeries()); Location realDir = new Location(dir).getParentFile(); realDir = realDir.getParentFile(); realDir = realDir.getParentFile(); dir = realDir.getAbsolutePath(); ArrayList<String> files = new ArrayList<String>(); for (String f : allFiles) { if (f.startsWith(dir) && (!f.endsWith("2dseq") || !noPixels)) { files.add(f); } } return files.toArray(new String[files.size()]); } /* @see loci.formats.IFormatReader#fileGroupOption(String) */ public int fileGroupOption(String id) throws FormatException, IOException { return FormatTools.MUST_GROUP; } /* @see loci.formats.IFormatReader#close(boolean) */ public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { pixelsFiles.clear(); allFiles.clear(); } } // -- Internal FormatReader API methods -- /* @see loci.formats.FormatReader#initFile(String) */ protected void initFile(String id) throws FormatException, IOException { super.initFile(id); Location originalFile = new Location(id).getAbsoluteFile(); Location parent = originalFile.getParentFile().getParentFile(); String[] acquisitionDirs = parent.list(true); Comparator<String> comparator = new Comparator<String>() { public int compare(String s1, String s2) { Integer i1 = 0; try { i1 = new Integer(s1); } catch (NumberFormatException e) { } Integer i2 = 0; try { i2 = new Integer(s2); } catch (NumberFormatException e) { } return i1.compareTo(i2); } }; Arrays.sort(acquisitionDirs, comparator); ArrayList<String> acqpFiles = new ArrayList<String>(); ArrayList<String> recoFiles = new ArrayList<String>(); for (String f : acquisitionDirs) { Location dir = new Location(parent, f); if (dir.isDirectory()) { String[] files = dir.list(true); for (String file : files) { Location child = new Location(dir, file); if (!child.isDirectory()) { allFiles.add(child.getAbsolutePath()); if (file.equals("acqp")) { acqpFiles.add(child.getAbsolutePath()); } } else { Location grandchild = new Location(child, "1"); if (grandchild.exists()) { String[] moreFiles = grandchild.list(true); for (String m : moreFiles) { Location ggc = new Location(grandchild, m); if (!ggc.isDirectory()) { allFiles.add(ggc.getAbsolutePath()); if (m.equals("2dseq")) { pixelsFiles.add(ggc.getAbsolutePath()); } else if (m.equals("reco")) { recoFiles.add(ggc.getAbsolutePath()); } } } } } } if (acqpFiles.size() > pixelsFiles.size()) { acqpFiles.remove(acqpFiles.size() - 1); } if (recoFiles.size() > pixelsFiles.size()) { recoFiles.remove(recoFiles.size() - 1); } } } core = new CoreMetadata[pixelsFiles.size()]; String[] imageNames = new String[pixelsFiles.size()]; String[] timestamps = new String[pixelsFiles.size()]; String[] institutions = new String[pixelsFiles.size()]; String[] users = new String[pixelsFiles.size()]; for (int series=0; series<pixelsFiles.size(); series++) { setSeries(series); core[series] = new CoreMetadata(); String acqData = DataTools.readFile(acqpFiles.get(series)); String[] lines = acqData.split("\n"); String[] sizes = null; String[] ordering = null; int ni = 0, nr = 0, ns = 0; int bits = 0; boolean signed = false; for (int i=0; i<lines.length; i++) { String line = lines[i]; int index = line.indexOf("="); if (index >= 0) { String key = line.substring(0, index); String value = line.substring(index + 1); if (value.startsWith("(")) { value = lines[i + 1].trim(); if (value.startsWith("<")) { value = value.substring(1, value.length() - 1); } } if (key.length() < 4) { continue; } addSeriesMeta(key.substring(3), value); if (key.equals("##$NI")) { ni = Integer.parseInt(value); } else if (key.equals("##$NR")) { nr = Integer.parseInt(value); } else if (key.equals("##$ACQ_word_size")) { bits = Integer.parseInt(value.substring(1, value.lastIndexOf("_"))); } else if (key.equals("##$BYTORDA")) { core[series].littleEndian = value.toLowerCase().equals("little"); } else if (key.equals("##$ACQ_size")) { sizes = value.split(" "); } else if (key.equals("##$ACQ_obj_order")) { ordering = value.split(" "); } else if (key.equals("##$ACQ_time")) { timestamps[series] = value; } else if (key.equals("##$ACQ_institution")) { institutions[series] = value; } else if (key.equals("##$ACQ_operator")) { users[series] = value; } else if (key.equals("##$ACQ_scan_name")) { imageNames[series] = value; } else if (key.equals("##$ACQ_ns_list_size")) { ns = Integer.parseInt(value); } } } String recoData = DataTools.readFile(recoFiles.get(series)); lines = recoData.split("\n"); for (int i=0; i<lines.length; i++) { String line = lines[i]; int index = line.indexOf("="); if (index >= 0) { String key = line.substring(0, index); String value = line.substring(index + 1); if (value.startsWith("(")) { value = lines[i + 1].trim(); if (value.startsWith("<")) { value = value.substring(1, value.length() - 1); } } if (key.length() < 4) { continue; } addSeriesMeta(key.substring(3), value); if (key.equals("##$RECO_size")) { sizes = value.split(" "); } else if (key.equals("##$RECO_wordtype")) { bits = Integer.parseInt(value.substring(1, value.indexOf("BIT"))); signed = value.indexOf("_SGN_") >= 0; } } } int td = Integer.parseInt(sizes[0]); int ys = sizes.length > 1 ? Integer.parseInt(sizes[1]) : 0; int zs = sizes.length > 2 ? Integer.parseInt(sizes[2]) : 0; if (sizes.length == 2) { if (ni == 1) { core[series].sizeY = ys; core[series].sizeZ = nr; } else { core[series].sizeY = ys; core[series].sizeZ = ni; } } else if (sizes.length == 3) { core[series].sizeY = ni * ys; core[series].sizeZ = nr * zs; } core[series].sizeX = td; core[series].sizeZ /= ns; core[series].sizeT = ns * nr; core[series].sizeC = 1; core[series].imageCount = getSizeZ() * getSizeC() * getSizeT(); core[series].dimensionOrder = "XYCTZ"; core[series].rgb = false; core[series].interleaved = false; core[series].pixelType = FormatTools.pixelTypeFromBytes(bits / 8, true, signed); } MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this); for (int series=0; series<getSeriesCount(); series++) { store.setImageName(imageNames[series] + " #" + (series + 1), series); store.setImageAcquiredDate( DateTools.formatDate(timestamps[series], DATE_FORMAT), series); String expID = MetadataTools.createLSID("Experimenter", series); store.setExperimenterID(expID, series); store.setExperimenterDisplayName(users[series], series); store.setExperimenterInstitution(institutions[series], series); store.setImageExperimenterRef(expID, series); } } }