/* * #%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.Arrays; import java.util.Hashtable; import java.util.Vector; import loci.common.DataTools; import loci.common.services.DependencyException; import loci.common.services.ServiceException; import loci.common.services.ServiceFactory; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.FormatReader; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.MissingLibraryException; import loci.formats.meta.MetadataStore; import loci.formats.services.NetCDFService; import ome.xml.model.primitives.PositiveFloat; import ome.units.quantity.Length; /** * MINCReader is the file format reader for MINC MRI files. */ public class MINCReader extends FormatReader { // -- Fields -- private NetCDFService netcdf; private byte[][][] pixelData; private boolean isMINC2 = false; // -- Constructor -- /** Constructs a new MINC reader. */ public MINCReader() { super("MINC MRI", "mnc"); domains = new String[] {FormatTools.MEDICAL_DOMAIN}; } // -- IFormatReader API methods -- /** * @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 bpp = FormatTools.getBytesPerPixel(getPixelType()); if (no < pixelData.length) { for (int row=0; row<h; row++) { int srcRow = getSizeY() - (row + y) - 1; if (srcRow < pixelData[no].length && x + w <= pixelData[no][srcRow].length) { System.arraycopy(pixelData[no][srcRow], x * bpp, buf, row * w * bpp, w * bpp); } } } return buf; } /* @see loci.formats.IFormatReader#close(boolean) */ @Override public void close(boolean fileOnly) throws IOException { super.close(fileOnly); if (!fileOnly) { if (netcdf != null) netcdf.close(); pixelData = null; isMINC2 = false; } } // -- Internal FormatReader API methods -- /* @see loci.formats.FormatReader#initFile(String) */ @Override protected void initFile(String id) throws FormatException, IOException { super.initFile(id); try { ServiceFactory factory = new ServiceFactory(); netcdf = factory.getInstance(NetCDFService.class); netcdf.setFile(id); } catch (DependencyException e) { throw new MissingLibraryException(e); } if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { Vector<String> variableList = netcdf.getVariableList(); for (String variable : variableList) { Hashtable<String, Object> attributes = netcdf.getVariableAttributes(variable); String[] keys = attributes.keySet().toArray(new String[0]); Arrays.sort(keys); for (String key : keys) { if (attributes.get(key) instanceof Object[]) { StringBuffer sb = new StringBuffer(); Object[] o = (Object[]) attributes.get(key); for (Object q : o) { sb.append(q.toString()); } addGlobalMeta(variable + " " + key, sb.toString()); } else { addGlobalMeta(variable + " " + key, attributes.get(key)); } } } } CoreMetadata m = core.get(0); try { Object pixels = netcdf.getVariableValue("/image"); if (pixels == null) { pixels = netcdf.getVariableValue("/minc-2.0/image/0/image"); isMINC2 = true; } if (pixels instanceof byte[][][]) { m.pixelType = FormatTools.UINT8; pixelData = (byte[][][]) pixels; } else if (pixels instanceof byte[][][][]) { byte[][][][] actualPixels = (byte[][][][]) pixels; m.pixelType = FormatTools.UINT8; pixelData = new byte[actualPixels.length * actualPixels[0].length][][]; int nextPlane = 0; for (int t=0; t<actualPixels.length; t++) { for (int z=0; z<actualPixels[t].length; z++) { pixelData[nextPlane++] = actualPixels[t][z]; } } } else if (pixels instanceof short[][][]) { m.pixelType = FormatTools.UINT16; short[][][] s = (short[][][]) pixels; pixelData = new byte[s.length][][]; for (int i=0; i<s.length; i++) { pixelData[i] = new byte[s[i].length][]; for (int j=0; j<s[i].length; j++) { pixelData[i][j] = DataTools.shortsToBytes(s[i][j], isLittleEndian()); } } } else if (pixels instanceof int[][][]) { m.pixelType = FormatTools.UINT32; int[][][] s = (int[][][]) pixels; pixelData = new byte[s.length][][]; for (int i=0; i<s.length; i++) { pixelData[i] = new byte[s[i].length][]; for (int j=0; j<s[i].length; j++) { pixelData[i][j] = DataTools.intsToBytes(s[i][j], isLittleEndian()); } } } else if (pixels instanceof float[][][]) { m.pixelType = FormatTools.FLOAT; float[][][] s = (float[][][]) pixels; pixelData = new byte[s.length][][]; for (int i=0; i<s.length; i++) { pixelData[i] = new byte[s[i].length][]; for (int j=0; j<s[i].length; j++) { pixelData[i][j] = DataTools.floatsToBytes(s[i][j], isLittleEndian()); } } } else if (pixels instanceof double[][][]) { m.pixelType = FormatTools.DOUBLE; double[][][] s = (double[][][]) pixels; pixelData = new byte[s.length][][]; for (int i=0; i<s.length; i++) { pixelData[i] = new byte[s[i].length][]; for (int j=0; j<s[i].length; j++) { pixelData[i][j] = DataTools.doublesToBytes(s[i][j], isLittleEndian()); } } } } catch (ServiceException e) { throw new FormatException(e); } m.littleEndian = isMINC2; Double physicalX = null; Double physicalY = null; Double physicalZ = null; if (isMINC2) { Hashtable<String, Object> attrs = netcdf.getVariableAttributes("/minc-2.0/dimensions/xspace"); m.sizeX = Integer.parseInt(attrs.get("length").toString()); physicalX = getStepSize(attrs); attrs = netcdf.getVariableAttributes("/minc-2.0/dimensions/yspace"); m.sizeY = Integer.parseInt(attrs.get("length").toString()); physicalY = getStepSize(attrs); attrs = netcdf.getVariableAttributes("/minc-2.0/dimensions/zspace"); m.sizeZ = Integer.parseInt(attrs.get("length").toString()); physicalZ = getStepSize(attrs); } else { m.sizeX = netcdf.getDimension("/xspace"); m.sizeY = netcdf.getDimension("/yspace"); m.sizeZ = netcdf.getDimension("/zspace"); physicalX = getStepSize(netcdf.getVariableAttributes("/xspace")); physicalY = getStepSize(netcdf.getVariableAttributes("/yspace")); physicalZ = getStepSize(netcdf.getVariableAttributes("/zspace")); } try { m.sizeT = netcdf.getDimension("/time"); } catch (NullPointerException e) { m.sizeT = 1; } m.sizeC = 1; m.imageCount = getSizeZ() * getSizeT() * getSizeC(); m.rgb = false; m.indexed = false; m.dimensionOrder = "XYZCT"; String history = null; if (isMINC2) { history = netcdf.getAttributeValue("/minc-2.0/ident"); } else { history = netcdf.getAttributeValue("/history"); } addGlobalMeta("Comment", history); MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { store.setImageDescription(history, 0); Length sizeX = FormatTools.getPhysicalSizeX(physicalX); Length sizeY = FormatTools.getPhysicalSizeY(physicalY); Length sizeZ = FormatTools.getPhysicalSizeZ(physicalZ); if (sizeX != null) { store.setPixelsPhysicalSizeX(sizeX, 0); } if (sizeY != null) { store.setPixelsPhysicalSizeY(sizeY, 0); } if (sizeZ != null) { store.setPixelsPhysicalSizeZ(sizeZ, 0); } } } private Double getStepSize(Hashtable<String, Object> attrs) { Double stepSize = Double.parseDouble(attrs.get("step").toString()); String units = attrs.get("units").toString(); if (units.equals("mm")) { stepSize *= 1000.0; } return stepSize; } }