/* * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.io; import java.io.BufferedReader; import java.io.IOException; import java.io.Serializable; import java.io.StringReader; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.DoubleBuffer; import java.nio.IntBuffer; import java.util.HashMap; import javax.vecmath.Matrix3d; import javax.vecmath.Vector3d; import org.eclipse.dawnsci.analysis.api.diffraction.DetectorProperties; import org.eclipse.dawnsci.analysis.api.diffraction.DiffractionCrystalEnvironment; import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException; import org.eclipse.dawnsci.analysis.api.tree.Attribute; import org.eclipse.dawnsci.analysis.api.tree.GroupNode; import org.eclipse.dawnsci.analysis.api.tree.NodeLink; import org.eclipse.dawnsci.analysis.api.tree.Tree; import org.eclipse.dawnsci.analysis.tree.TreeFactory; import org.eclipse.january.IMonitor; import org.eclipse.january.MetadataException; import org.eclipse.january.dataset.Dataset; import org.eclipse.january.dataset.DatasetFactory; import org.eclipse.january.dataset.DatasetUtils; import org.eclipse.january.dataset.DoubleDataset; import org.eclipse.january.dataset.ILazyDataset; import org.eclipse.january.dataset.IndexIterator; import org.eclipse.january.dataset.IntegerDataset; import org.eclipse.january.dataset.ShapeUtils; import org.eclipse.january.metadata.Metadata; import org.eclipse.january.metadata.MetadataFactory; import org.eclipse.january.metadata.StatisticsMetadata; import org.iucr.cbflib.SWIGTYPE_p_p_char; import org.iucr.cbflib.cbf; import org.iucr.cbflib.cbf_handle_struct; import org.iucr.cbflib.intP; import org.iucr.cbflib.sizetP; import org.iucr.cbflib.uintP; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.ac.diamond.CBFlib.CBFlib; /** * Crystallographic Binary File (CBF) and image-supporting Crystallographic Information File (imgCIF) loader * */ public class CBFLoader extends AbstractFileLoader { protected static final Logger logger = LoggerFactory.getLogger(CBFLoader.class); private HashMap<String, String> metadataMap = new HashMap<String, String>(); public HashMap<String, Serializable> GDAMetadata = new HashMap<String, Serializable>(); static { CBFlib.loadLibrary(); } public CBFLoader() { } /** * @param FileName */ public CBFLoader(String FileName) { fileName = FileName; } @Override protected void clearMetadata() { metadata = null; metadataMap.clear(); GDAMetadata.clear(); } @Override public DataHolder loadFile() throws ScanFileHolderException { DataHolder output = new DataHolder(); ILazyDataset data = null; ImageOrientation imageOrien = null; logger.info("Loading {}", fileName); cbf_handle_struct chs = new cbf_handle_struct(fileName); Tree tree = readAllMetadata(chs); if (loadMetadata) { NodeLink link = tree.getGroupNode().iterator().next(); // first group in root group if (link.isDestinationGroup()) { GroupNode group = (GroupNode) link.getDestination(); parseMiniCBFHeader(group); imageOrien = parseCBFHeaderData(group); } } imageOrien = readImageOrientation(chs, imageOrien); if (loadLazily) { data = createLazyDataset(DEF_IMAGE_NAME, imageOrien.getDType(), imageOrien.getShape(), new CBFLoader(fileName)); } else { data = readCBFBinaryData(chs, imageOrien); } chs.delete(); // this also closes the file output.addDataset(DEF_IMAGE_NAME, data); if (loadMetadata) { int[] shape = imageOrien.getShape(); try { createGDAMetadata(shape[1], shape[0]); } catch (Exception e) { // ignore } data.setMetadata(metadata); output.setMetadata(metadata); // We need to read the header completely if (loadMetadata && metadata==null) { // We create something metadata = new Metadata(); metadata.initialize(metadataMap); metadata.setFilePath(fileName); } } return output; } private static final String PLACE_HOLDER = "."; // can mean inapplicable or inappropriate for a row and also use default private static final String MISSING = "?"; // missing value private Tree readAllMetadata(cbf_handle_struct chs) throws ScanFileHolderException { SWIGTYPE_p_p_char s = cbf.new_charPP(); uintP n = new uintP(); Tree tree = TreeFactory.createTreeFile(fileName.hashCode(), fileName); GroupNode gt = tree.getGroupNode(); CBFError.errorChecker(cbf.cbf_rewind_datablock(chs)); do { CBFError.errorChecker(cbf.cbf_datablock_name(chs, s)); String blockName = new String(cbf.charPP_value(s)); GroupNode block; if (gt.containsGroupNode(blockName)) { block = tree.getGroupNode().getGroupNode(blockName); } else { block = TreeFactory.createGroupNode(blockName.hashCode()); gt.addGroupNode(blockName, block); } // TODO add save frame support using block-item functions CBFError.errorChecker(cbf.cbf_rewind_category(chs)); do { CBFError.errorChecker(cbf.cbf_category_name(chs, s)); String catName = new String(cbf.charPP_value(s)); GroupNode category; if (block.containsGroupNode(catName)) { category = block.getGroupNode(catName); } else { category = TreeFactory.createGroupNode(catName.hashCode()); block.addGroupNode(catName, category); } CBFError.errorChecker(cbf.cbf_count_columns(chs, n.cast())); int c = (int) n.value(); CBFError.errorChecker(cbf.cbf_count_rows(chs, n.cast())); int r = (int) n.value(); if (c == 0 || r == 0) { continue; } CBFError.errorChecker(cbf.cbf_rewind_row(chs)); do { CBFError.errorChecker(cbf.cbf_row_number(chs, n.cast())); int row = (int) n.value(); CBFError.errorChecker(cbf.cbf_rewind_column(chs)); do { CBFError.errorChecker(cbf.cbf_column_name(chs, s)); String colName = new String(cbf.charPP_value(s)); Attribute column = category.getAttribute(colName); String v = null; if (cbf.cbf_get_value(chs, s) == 0) { v = cbf.charPP_value(s); if (!PLACE_HOLDER.equals(v) && !MISSING.equals(v)) { Number num = Utils.parseValue(v); if (column == null) { int dt = num == null ? Dataset.STRING : (num instanceof Float || num instanceof Double ? Dataset.FLOAT64 : Dataset.INT32); Dataset ds = DatasetFactory.zeros(new int[] {r}, dt); column = TreeFactory.createAttribute(colName, ds, false); category.addAttribute(column); } column.getValue().set(num == null ? v : num, row); } } } while (CBFError.errorChecker(cbf.cbf_next_column(chs))); } while (CBFError.errorChecker(cbf.cbf_next_row(chs))); } while (CBFError.errorChecker(cbf.cbf_next_category(chs))); } while (CBFError.errorChecker(cbf.cbf_next_datablock(chs))); return tree; } static String[] miniCBFheaderNames = { "Pixel_size", "Silicon sensor, thickness", "Exposure_time", "Exposure_period", "Tau =", "Count_cutoff", "Threshold_setting,", "N_excluded_pixels =", "Excluded_pixels:", "Flat_field:", "Trim_directory:", "Wavelength", "Energy_range", "Detector_distance", "Detector_Voffset", "Beam_xy", "Flux", "Filter_transmission", "Start_angle", "Angle_increment", "Detector_2theta", "Polarization", "Alpha", "Kappa", "Phi", "Chi", "Oscillation_axis", "N_oscillations" }; private void parseMiniCBFHeader(GroupNode group) { NodeLink link = group.getNodeLink("array_data"); if (link == null || !link.isDestinationGroup()) return; String header = getString((GroupNode) link.getDestination(), "header_contents", 0); if (header == null || header.length() == 0) return; BufferedReader in = new BufferedReader(new StringReader(header)); String temp; int unknownNum = 0; try { while ((temp = in.readLine()) != null) { if (temp.length() == 0) continue; boolean found = false; for (String name : miniCBFheaderNames) { if (temp.startsWith(name, 2)) { metadataMap.put(name, temp.substring(2 + name.length()).trim()); found = true; break; } } if (!found) { metadataMap.put("Unknown " + unknownNum, temp); unknownNum++; } } } catch (IOException e) { } } private ImageOrientation parseCBFHeaderData(GroupNode block) throws ScanFileHolderException { int xLength = 0; int yLength = 0; boolean xIncreasing = false; boolean yIncreasing = false; boolean isRowsX = false; GroupNode category = null; if (block.containsGroupNode("diffrn_frame_data")) { category = block.getGroupNode("diffrn_frame_data"); } else if (block.containsGroupNode("diffrn_data_frame")) { category = block.getGroupNode("diffrn_data_frame"); } if (category == null) return null; // no proper CBF metadata!!! String arrayid = category.getAttribute("array_id").getFirstElement(); metadataMap.put("diffrn_data_frame.array_id", arrayid); // get the image dimensions if (block.containsGroupNode("array_structure_list")) { category = block.getGroupNode("array_structure_list"); Dataset values = DatasetUtils.convertToDataset(category.getAttribute("array_id").getValue()); IndexIterator it = values.getIterator(); int i = 0; while (it.hasNext()) { if (values.getObjectAbs(it.index).equals(arrayid)) { int ind = getInteger(category, "index", i); int dim = getInteger(category, "dimension", i); int pre = getInteger(category, "precedence", i); String dir = getString(category, "direction", i); String asi = getString(category, "axis_set_id", i); metadataMap.put("SIZE " + ind, String.valueOf(dim)); metadataMap.put("precedence " + ind, String.valueOf(pre)); metadataMap.put("direction " + ind, dir); metadataMap.put("axis_set_id " + ind, asi); } i++; } } // Attempt to find rows that matches above array_id if (isMatch("axis_set_id 1", "ELEMENT_X")) { // FIXME is this always the case? isRowsX = getInteger("precedence 1") == 1; xLength = getInteger("SIZE 1"); yLength = getInteger("SIZE 2"); xIncreasing = isMatch("direction 1", "increasing"); yIncreasing = isMatch("direction 2", "increasing"); } else { isRowsX = getInteger("precedence 2") == 1; xLength = getInteger("SIZE 2"); yLength = getInteger("SIZE 1"); xIncreasing = isMatch("direction 2", "increasing"); yIncreasing = isMatch("direction 1", "increasing"); } String pixelSize = metadataMap.get("Pixel_size"); if (pixelSize == null) { // need to fake mini-header /* * */ // TODO // Beam_xy // Detector_distance // Wavelength /* * _diffrn_radiation.diffrn_id DS1 _diffrn_radiation.wavelength_id WAVELENGTH1 _diffrn_radiation.probe x-ray _diffrn_radiation_wavelength.id WAVELENGTH1 _diffrn_radiation_wavelength.wavelength 0.979399979114532 _diffrn_radiation_wavelength.wt 1.0 */ // Start_angle // Angle_increment // Exposure_time // Count_cutoff } metadataMap.put("numPixels_x", String.valueOf(xLength)); metadataMap.put("numPixels_y", String.valueOf(yLength)); return new ImageOrientation(xLength, yLength, -1, -1, xIncreasing, yIncreasing, isRowsX); } private static Object getObject(GroupNode category, String attribute, int... pos) { Attribute attr = category.getAttribute(attribute); return attr == null ? null : attr.getValue().getObject(pos); } private static String getString(GroupNode category, String attribute, int... pos) { Object obj = getObject(category, attribute, pos); return obj == null ? null : obj.toString(); } private static int getInteger(GroupNode category, String attribute, int... pos) { String str = getString(category, attribute, pos); Object obj = str == null ? null : Utils.parseValue(str); return obj == null ? 0 : ((Number) obj).intValue(); } private void createGDAMetadata(int x, int y) throws ScanFileHolderException { try { String pixelSize = metadataMap.get("Pixel_size"); if (pixelSize == null) { throw new ScanFileHolderException("No relevant metadata found"); } String[] xypixVal = pixelSize.split("m x"); double xPxVal = Double.parseDouble(xypixVal[0])*1000; double yPXVal = Double.parseDouble(xypixVal[1].split("m")[0])*1000; String tmp = metadataMap.get("Beam_xy"); double beamPosX; double beamPosY; if (tmp != null) { String[] beamxy = tmp.split(","); beamPosX = Double.parseDouble(beamxy[0].split("\\(")[1]); beamPosY = Double.parseDouble(beamxy[1].split("\\)")[0]); } else { beamPosX = x/2; beamPosY = y/2; } // NXGeometery:NXtranslation // double[] detectorOrigin = { // (Double.parseDouble(getMetadataValue("numPixels_x")) - beamPosX)* xPxVal , // (Double.parseDouble(getMetadataValue("numPixels_y")) - beamPosY)* yPXVal , // Double.parseDouble(getMetadataValue("Detector_distance").split("m")[0])*1000 }; double[] detectorOrigin = { beamPosX* xPxVal, beamPosY* yPXVal , getFirstDouble("Detector_distance", "m")*1000 }; GDAMetadata.put("NXdetector:NXgeometry:NXtranslation", detectorOrigin); //System.out.println(detectorOrigin[0] +" "+detectorOrigin[1]+" "+detectorOrigin[2]); GDAMetadata.put("NXdetector:NXgeometry:NXtranslation@units", "milli*metre"); // NXGeometery:NXOrientation double [] directionCosine = {1,0,0,0,1,0}; // to form identity matrix as no header data GDAMetadata.put("NXdetector:NXgeometry:NXorientation",directionCosine); // NXGeometery:XShape (shape from origin (+x, +y, +z,0, 0, 0) > x,y,0,0,0,0) double[] detectorShape = { getDouble("numPixels_x") * xPxVal, getDouble("numPixels_y") * yPXVal,0,0,0,0 }; GDAMetadata.put("NXdetector:NXgeometry:NXshape", detectorShape); GDAMetadata.put("NXdetector:NXgeometry:NXshape@units","milli*metre"); // NXGeometery:NXFloat GDAMetadata.put("NXdetector:x_pixel_size", xPxVal); GDAMetadata.put("NXdetector:x_pixel_size@units", "milli*metre"); GDAMetadata.put("NXdetector:y_pixel_size", yPXVal); GDAMetadata.put("NXdetector:y_pixel_size@units", "milli*metre"); // "NXmonochromator:wavelength" double lambda = Double.NaN; String value; value = metadataMap.get("Wavelength"); if (value != null) { if (value.contains("A")) lambda = getFirstDouble("Wavelength", "A"); else if (value.contains("nm")) lambda = getFirstDouble("Wavelength", "nm")*10; } if (Double.isNaN(lambda)) throw new ScanFileHolderException("The wavelength could not be parsed in from the mini cbf file header"); GDAMetadata.put("NXmonochromator:wavelength",lambda); GDAMetadata.put("NXmonochromator:wavelength@units", "Angstrom"); // oscillation range GDAMetadata.put("NXsample:rotation_start", getFirstDouble("Start_angle", "deg")); GDAMetadata.put("NXsample:rotation_start@units","degree"); GDAMetadata.put("NXsample:rotation_range", getFirstDouble("Angle_increment", "deg")); GDAMetadata.put("NXsample:rotation_range@units", "degree"); //Exposure time GDAMetadata.put("NXsample:exposure_time", getFirstDouble("Exposure_time", "s")); GDAMetadata.put("NXsample:exposure_time@units", "seconds"); GDAMetadata.put("NXdetector:pixel_overload", getFirstDouble("Count_cutoff", "counts")); GDAMetadata.put("NXdetector:pixel_overload@units", "counts"); createMetadata(detectorOrigin, xPxVal, yPXVal, lambda); } catch (NumberFormatException e) { throw new ScanFileHolderException("There was a problem parsing numerical value from string ",e); } } private void createMetadata(double[] detectorOrigin, double xPxVal, double yPXVal, double lambda) { try { // This is new metadata Matrix3d identityMatrix = new Matrix3d(); identityMatrix.setIdentity(); DetectorProperties detectorProperties = new DetectorProperties(new Vector3d(detectorOrigin), getInteger("numPixels_x"), getInteger("numPixels_y"), xPxVal, yPXVal, identityMatrix); DiffractionCrystalEnvironment diffractionCrystalEnvironment = new DiffractionCrystalEnvironment(lambda, getFirstDouble("Start_angle", "deg"), getFirstDouble("Angle_increment", "deg"), getFirstDouble( "Exposure_time", "s")); metadata = new DiffractionMetadata(fileName, detectorProperties, diffractionCrystalEnvironment); metadata.addDataInfo(DEF_IMAGE_NAME, getInteger("numPixels_x"), getInteger("numPixels_y")); metadata.setMetadata(metadataMap); } catch (ScanFileHolderException e) { metadata = new Metadata(); metadata.initialize(metadataMap); } metadata.setFilePath(fileName); } private ImageOrientation readImageOrientation(cbf_handle_struct chs, ImageOrientation imageOrien) throws ScanFileHolderException { CBFError.errorChecker(cbf.cbf_rewind_datablock(chs)); CBFError.errorChecker(cbf.cbf_rewind_category(chs)); CBFError.errorChecker(cbf.cbf_find_category(chs, "array_data")); CBFError.errorChecker(cbf.cbf_rewind_row(chs)); CBFError.errorChecker(cbf.cbf_rewind_column(chs)); CBFError.errorChecker(cbf.cbf_find_column(chs, "data")); uintP cifcomp = new uintP(); intP bid = new intP(), els = new intP(), elu = new intP(); intP minel = new intP(), maxel = new intP(), isre = new intP(); sizetP elsize = new sizetP(), elnum = new sizetP(); sizetP dim1 = new sizetP(), dim2 = new sizetP(), dim3 = new sizetP(), pad = new sizetP(); SWIGTYPE_p_p_char byteorder = cbf.new_charPP(); CBFError.errorChecker(cbf.cbf_get_arrayparameters_wdims(chs, cifcomp.cast(), bid.cast(), elsize.cast(), els .cast(), elu.cast(), elnum.cast(), minel.cast(), maxel.cast(), isre.cast(), byteorder, dim1.cast(), dim2.cast(), dim3.cast(), pad.cast())); if (imageOrien == null) { imageOrien = new ImageOrientation((int) dim1.value(), (int) dim2.value(), isre.value(), els.value()); } else { imageOrien.isReal = isre.value(); imageOrien.isSigned = els.value(); } metadataMap.put("numPixels_x", String.valueOf(imageOrien.shape[1])); metadataMap.put("numPixels_y", String.valueOf(imageOrien.shape[0])); long numPixels = ShapeUtils.calcLongSize(imageOrien.shape); if (numPixels != elnum.value()) { throw new ScanFileHolderException("Mismatch of CBF binary data size: " + numPixels + " cf " + elnum.value()); } cifcomp.delete(); minel.delete(); maxel.delete(); isre.delete(); elsize.delete(); elnum.delete(); dim1.delete(); dim2.delete(); dim3.delete(); pad.delete(); bid.delete(); els.delete(); elu.delete(); return imageOrien; } @SuppressWarnings("unchecked") private Dataset readCBFBinaryData(cbf_handle_struct chs, ImageOrientation imageOrien) throws ScanFileHolderException { int[] shape = imageOrien.getShape(); int xLength = shape[1]; int yLength = shape[0]; boolean xIncreasing = imageOrien.isXIncreasing(); boolean yIncreasing = imageOrien.isYIncreasing(); boolean isRowsX = imageOrien.isRowsX(); int numPixels = xLength * yLength; // System.out.println("Loading " + fileName + ", " + numPixels); // remember to explicitly delete arrays allocated on the JNI side // as finalize method is up to garbage collector and is tardily done // TODO add smaller data type support (with sign extension ala NeXus) // deal with floating point data differently than integer data int stride1; // stride is change in position on n-th dim int stride2; int start; // start is offset in position if (!isRowsX) { // swap row and column directions boolean b = yIncreasing; yIncreasing = !xIncreasing; xIncreasing = !b; } if (!yIncreasing) { // note that image in GDA is plotted so Y increases from top to bottom stride1 = xLength; start = 0; } else { stride1 = -xLength; start = xLength*yLength - xLength; } if (xIncreasing) { stride2 = 1; } else { stride2 = -1; start += xLength - 1; } int rows; int cols; int rstep; int cstep; if (isRowsX) { rows = yLength; cols = xLength; rstep = stride1; cstep = stride2; } else { rows = xLength; cols = yLength; rstep = stride2; cstep = stride1; } int index = 0; // index in destination int position = 0; // position in buffer int hash = 0; intP bid = new intP(); sizetP rsize = new sizetP(); CBFError.errorChecker(cbf.cbf_rewind_datablock(chs)); CBFError.errorChecker(cbf.cbf_rewind_category(chs)); CBFError.errorChecker(cbf.cbf_find_category(chs, "array_data")); CBFError.errorChecker(cbf.cbf_rewind_row(chs)); CBFError.errorChecker(cbf.cbf_rewind_column(chs)); CBFError.errorChecker(cbf.cbf_find_column(chs, "data")); Dataset data = DatasetFactory.zeros(shape, imageOrien.getDType()); StatisticsMetadata<Number> stats = null; try { stats = MetadataFactory.createMetadata(StatisticsMetadata.class, data); } catch (MetadataException e) { logger.error("Could not create max/min metadata", e); } if (data instanceof DoubleDataset) { DoubleBuffer ddata; try { ddata = ByteBuffer.allocateDirect(numPixels * 8).order(ByteOrder.nativeOrder()).asDoubleBuffer(); } catch (OutOfMemoryError e) { throw new ScanFileHolderException("CBFloader failed to while allocating the byte buffer ", e); } catch (Exception eb) { throw new ScanFileHolderException("CBFloader failed to while allocating the byte buffer ", eb); } CBFError.errorChecker(cbf.cbf_get_realarray(chs, bid.cast(), ddata, (Double.SIZE / 8), numPixels, rsize.cast())); if (numPixels != rsize.value()) { throw new ScanFileHolderException("Mismatch of CBF binary data size"); } if (stats != null) { double[] dArray = ((DoubleDataset) data).getData(); // map from CBF data to dataset double amax = -Double.MAX_VALUE; double amin = Double.MAX_VALUE; double dhash = 0; for (int j = 0; j < rows; j++) { position = start; for (int i = 0; i < cols; i++) { double value = ddata.get(position); position += cstep; if (Double.isInfinite(value) || Double.isNaN(value)) dhash = (dhash * 19) % Integer.MAX_VALUE; else dhash = (dhash * 19 + value) % Integer.MAX_VALUE; dArray[index++] = value; if (value > amax) { amax = value; } if (value < amin) { amin = value; } } start += rstep; } hash = (int) dhash; stats.setMaximumMinimum(amax, amin); ddata = null; } } else { IntBuffer idata; try { idata = ByteBuffer.allocateDirect(numPixels * 4).order(ByteOrder.nativeOrder()).asIntBuffer(); } catch (OutOfMemoryError e) { throw new ScanFileHolderException("CBFLoader failed to allocate bytebuffer (intbuffer)",e); } catch (Exception eb) { throw new ScanFileHolderException("CBFLoader failed to allocate bytebuffer (intbuffer)",eb); } int signed = imageOrien.isSigned; CBFError.errorChecker(cbf.cbf_get_integerarray(chs, bid.cast(), idata, (Integer.SIZE / 8), signed, numPixels, rsize.cast())); if (numPixels != rsize.value()) { throw new ScanFileHolderException("Mismatch of CBF binary data size"); } if (stats != null) { int[] dArray = ((IntegerDataset) data).getData(); int amax = Integer.MIN_VALUE; int amin = Integer.MAX_VALUE; for (int j = 0; j < rows; j++) { position = start; for (int i = 0; i < cols; i++) { int value = idata.get(position); position += cstep; hash = hash * 19 + value; dArray[index++] = value; if (value > amax) { amax = value; } if (value < amin) { amin = value; } } start += rstep; } stats.setMaximumMinimum(amax, amin); idata = null; } } rsize.delete(); bid.delete(); if (stats != null) { hash = hash*19 + data.getDType()*17 + data.getElementsPerItem(); stats.setHash(hash); data.addMetadata(stats); } return data; } private int getInteger(String key) throws ScanFileHolderException { try { String value = metadataMap.get(key); if (value == null) { throw new ScanFileHolderException("No such key: " + key); } return Integer.parseInt(value); } catch (NumberFormatException e) { throw new ScanFileHolderException("There was a problem parsing integer value from string",e); } } private double getDouble(String key) throws ScanFileHolderException { try { String value = metadataMap.get(key); if (value == null) { throw new ScanFileHolderException("No such key: " + key); } return Double.parseDouble(value); } catch (NumberFormatException e) { throw new ScanFileHolderException("There was a problem parsing double value from string",e); } } private double getFirstDouble(String key, String split) throws ScanFileHolderException { try { String value = metadataMap.get(key); if (value == null) { throw new ScanFileHolderException("No such key: " + key); } return Double.parseDouble(value.split(split)[0]); } catch (NumberFormatException e) { throw new ScanFileHolderException("There was a problem parsing double value from string",e); } } private boolean isMatch(String key, String value) throws ScanFileHolderException { try { String mValue = metadataMap.get(key); return value.equalsIgnoreCase(mValue); } catch (NumberFormatException e) { throw new ScanFileHolderException("There was a problem parsing double value from string",e); } } private class ImageOrientation { int [] shape; boolean xIncreasing; boolean yIncreasing; boolean isRowsX; int isReal; int isSigned; private ImageOrientation(int x, int y, int isReal, int isSigned) { // these values are to support the 6M on i24 for the time being this(x, y, isReal, isSigned, true, false, true); } private ImageOrientation(int x, int y, int isReal, int isSigned, boolean increasingX, boolean increasingY, boolean areRowsX) { shape = new int[] {y, x}; this.isReal = isReal; this.isSigned = isSigned; xIncreasing = increasingX; yIncreasing = increasingY; isRowsX = areRowsX; } public int getDType() { if (isReal == -1) return -1; if (isReal == 0) return Dataset.INT32; return Dataset.FLOAT64; } public int[] getShape() { return shape; } public boolean isXIncreasing() { return xIncreasing; } public boolean isYIncreasing() { return yIncreasing; } public boolean isRowsX() { return isRowsX; } } @Override public void loadMetadata(IMonitor mon) throws IOException { // We need to read the header completely if (loadMetadata && metadata==null) { // We create something metadata = new Metadata(); metadata.initialize(metadataMap); metadata.setFilePath(fileName); } } }