/*
* 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.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Vector;
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.IDataHolder;
import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException;
import org.eclipse.january.IMonitor;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.ILazyDataset;
import org.eclipse.january.dataset.SliceND;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to load ADSC images
*/
public class ADSCImageLoader extends AbstractFileLoader {
private static final String ADSC_IMAGE_NAME = "ADSC Image";
private static final Logger logger = LoggerFactory.getLogger(ADSCImageLoader.class);
private HashMap<String, String> metadataMap = new HashMap<String, String>();
private Vector<String> extraHeaders;
DetectorProperties detectorProperties;
DiffractionCrystalEnvironment diffractionCrystalEnvironment;
private boolean keepBitWidth = false;
private static final String DATE_FORMAT = "EEE MMM dd HH:mm:ss yyyy";
/**
* @return true if loader keeps bit width of pixels
*/
public boolean isKeepBitWidth() {
return keepBitWidth;
}
/**
* set loader to keep bit width of pixels
*
* @param keepBitWidth
*/
public void setKeepBitWidth(boolean keepBitWidth) {
this.keepBitWidth = keepBitWidth;
}
public ADSCImageLoader() {
}
/**
* @param FileName
*/
public ADSCImageLoader(String FileName) {
this(FileName, false);
}
/**
* @param FileName
* @param keepBitWidth
* true if loader keeps bit width of pixels
*/
public ADSCImageLoader(String FileName, boolean keepBitWidth) {
setFile(FileName);
this.keepBitWidth = keepBitWidth;
}
@Override
protected void clearMetadata() {
metadata = null;
metadataMap.clear();
}
@Override
public DataHolder loadFile() throws ScanFileHolderException {
DataHolder output = new DataHolder();
// opens the file and reads the header information
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(fileName, "r");
processingMetadata(raf);
} catch (FileNotFoundException fnf) {
throw new ScanFileHolderException("File not found", fnf);
} catch (ScanFileHolderException se) {
logger.warn("Ignoring problem with metadata in {}", fileName);
} catch (Exception e) {
try {
if (raf != null)
raf.close();
} catch (IOException ex) {
ex.printStackTrace();
}
throw new ScanFileHolderException("There was a problem loading or reading metadata", e);
}
// Opens the file and reads the byte information and parsed them to doubles.
try {
int height = getInteger("SIZE1");
int width = getInteger("SIZE2");
final int pointer = getInteger("HEADER_BYTES");
int[] shape = { height, width };
ILazyDataset data;
if (loadLazily) {
data = createLazyDataset(DEF_IMAGE_NAME, Dataset.INT32, shape, new LazyLoaderStub() {
@Override
public IDataset getDataset(IMonitor mon, SliceND slice) throws IOException {
try {
Dataset tmp = loadDataset(fileName, slice.getSourceShape(), pointer, keepBitWidth);
return tmp == null ? null : tmp.getSliceView(slice);
} catch (ScanFileHolderException e) {
throw new IOException(e);
}
}
});
} else {
raf.seek(pointer);
data = Utils.createDataset(raf, shape, keepBitWidth);
data.setName(DEF_IMAGE_NAME);
}
output.addDataset(ADSC_IMAGE_NAME, data);
if (loadMetadata) {
data.setMetadata(getMetadata());
output.setMetadata(data.getMetadata());
}
} catch (Exception e) {
throw new ScanFileHolderException("There was a problem reading the ADSC image", e);
} finally {
try {
raf.close();
} catch (IOException e) {
throw new ScanFileHolderException("Problem closing ADSC file", e);
}
}
return output;
}
private static Dataset loadDataset(String fileName, int[] shape, int pointer, boolean keepBitWidth) throws ScanFileHolderException {
IDataHolder holder = LoaderFactory.fetchData(fileName, false);
if (holder != null) {
IDataset data = holder.getDataset(0);
if (data != null) {
return DatasetUtils.convertToDataset(data);
}
}
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(fileName, "r");
raf.seek(pointer);
Dataset data = Utils.createDataset(raf, shape, keepBitWidth);
data.setName(DEF_IMAGE_NAME);
if (holder == null) {
holder = new DataHolder();
holder.setLoaderClass(ADSCImageLoader.class);
holder.setFilePath(fileName);
LoaderFactory.cacheData(holder);
}
holder.addDataset(ADSC_IMAGE_NAME, data);
return data;
} catch (FileNotFoundException fnf) {
throw new ScanFileHolderException("File not found", fnf);
} catch (Exception e) {
try {
if (raf != null)
raf.close();
} catch (IOException ex) {
ex.printStackTrace();
}
throw new ScanFileHolderException("There was a problem loading or reading metadata", e);
}
}
/**
* processing all Metadata between { and } tags at the top of the file, put it into a key-value pair map if they are
* in "key=value" format. remove ; from line ending
*
* @param in
* @throws ScanFileHolderException
*/
private void processingMetadata(RandomAccessFile in) throws ScanFileHolderException {
// handling metadata in the file header
try {
byte firstChar = in.readByte();
in.seek(0);
if (firstChar != '{')
throw new ScanFileHolderException("This is not a valid ADSC image");
String line = in.readLine();
// an updated header reader which ignores all of the header.
while (!line.contains("{"))
line = in.readLine();
while (true) {
line = in.readLine();
if (line.contains("}")) {// stop at end of header
double[] detectorOrigin = { getDouble("BEAM_CENTER_Y"), getDouble("BEAM_CENTER_X"),
getDouble("DISTANCE") };
// createGDAMetadata(detectorOrigin);
createMetadata(detectorOrigin);
return;
} else if (line.contains("=")) {
String[] keyvalue = line.split("=");
metadataMap.put(keyvalue[0], keyvalue[1].substring(0, keyvalue[1].length() - 1));
} else {
extraHeaders.add(line);
}
}
} catch (IOException e) {
throw new ScanFileHolderException("There was a problem parsing the ADSC header information", e);
}
}
// private void createGDAMetadata(double[] detectorOrigin) throws ScanFileHolderException {
// NXGeometry:NXtranslation
// double pixelsize = getDouble("PIXEL_SIZE");
// double x = getInteger("SIZE1") * pixelsize;
// double y = getInteger("SIZE2") * pixelsize;
// bodge since bean centre of diamond ADSC detectors are in a DIFFERENT REFERENCE FRAME!!!!!!!!
// double[] detectorOrigin = { x - getDouble("BEAM_CENTER_X"), y - getDouble("BEAM_CENTER_Y"),
// getDouble("DISTANCE") };
// GDAMetadata.put("NXdetector:NXgeometry:NXtranslation", detectorOrigin);
// GDAMetadata.put("NXdetector:NXgeometry:NXtranslation@units", "milli*meter");
//
// // 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("SIZE1") * getDouble("PIXEL_SIZE"),
// getDouble("SIZE2") * getDouble("PIXEL_SIZE"), 0, 0, 0, 0 };
// GDAMetadata.put("NXdetector:NXgeometry:NXshape", detectorShape);
// GDAMetadata.put("NXdetector:NXgeometry:NXshape@units", "milli*metre");
//
// // NXGeometery:NXFloat
// double[] pixelSize = { getDouble("PIXEL_SIZE"), getDouble("PIXEL_SIZE") };
// GDAMetadata.put("NXdetector:x_pixel_size", pixelSize[0]);
// GDAMetadata.put("NXdetector:x_pixel_size@units", "milli*metre");
// GDAMetadata.put("NXdetector:y_pixel_size", pixelSize[1]);
// GDAMetadata.put("NXdetector:y_pixel_size@units", "milli*metre");
// // "NXmonochromator:wavelength"
// GDAMetadata.put("NXmonochromator:wavelength", getDouble("WAVELENGTH"));
// GDAMetadata.put("NXmonochromator:wavelength@units", "Angstrom");
//
// // oscillation range
// GDAMetadata.put("NXsample:rotation_start", getDouble("OSC_START"));
// GDAMetadata.put("NXsample:rotation_start@units", "degree");
// GDAMetadata.put("NXsample:rotation_range", getDouble("OSC_RANGE"));
// GDAMetadata.put("NXsample:rotation_range@units", "degree");
//
// // Exposure time
// GDAMetadata.put("NXsample:exposure_time", getDouble("TIME"));
// GDAMetadata.put("NXsample:exposure_time@units", "seconds");
// }
private void createMetadata(double[] detectorOrigin) throws ScanFileHolderException {
// This is new metadata
Matrix3d identityMatrix = new Matrix3d();
identityMatrix.setIdentity();
detectorProperties = new DetectorProperties(new Vector3d(detectorOrigin), getInteger("SIZE1"),
getInteger("SIZE2"), getDouble("PIXEL_SIZE"), getDouble("PIXEL_SIZE"), identityMatrix);
diffractionCrystalEnvironment = new DiffractionCrystalEnvironment(getDouble("WAVELENGTH"),
getDouble("OSC_START"), getDouble("OSC_RANGE"), getDouble("TIME"));
DiffractionMetadata diffMetadata = new DiffractionMetadata(fileName, detectorProperties, diffractionCrystalEnvironment);
metadata = diffMetadata;
diffMetadata.addDataInfo(ADSC_IMAGE_NAME, getInteger("SIZE1"), getInteger("SIZE2"));
diffMetadata.setMetadata(metadataMap);
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
try {
Date date = sdf.parse(metadataMap.get("DATE"));
diffMetadata.setCreationDate(date);
} catch (ParseException e) {
throw new ScanFileHolderException("Could not parse the date from the header", e);
}
}
private int getInteger(String key) throws ScanFileHolderException {
try {
return Integer.parseInt(getMetadataValue(key).trim());
} catch (NumberFormatException e) {
throw new ScanFileHolderException("There was a problem parsing integer value from string",e);
}
}
private double getDouble(String key) throws ScanFileHolderException {
try {
return Double.parseDouble(getMetadataValue(key));
} catch (NumberFormatException e) {
throw new ScanFileHolderException("There was a problem parsing double value from string",e);
}
}
private String getMetadataValue(String key) throws ScanFileHolderException {
String v = metadataMap.get(key);
if (v == null)
throw new ScanFileHolderException("The keyword " + key + " was not found in the ADSC Header");
return v;
}
}