/*
* 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.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.dawnsci.analysis.api.io.IDataHolder;
import org.eclipse.dawnsci.analysis.api.io.IFileSaver;
import org.eclipse.dawnsci.analysis.api.io.ScanFileHolderException;
import org.eclipse.january.IMonitor;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.ILazyDataset;
import org.eclipse.january.dataset.IntegerDataset;
import org.eclipse.january.dataset.SliceND;
import org.eclipse.january.metadata.Metadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Basic class that loads in data from the Oxford Instruments Ruby detector
*/
public class CrysalisLoader extends AbstractFileLoader implements IFileSaver {
/**
* Setup the logging facilities
*/
private static final Logger logger = LoggerFactory.getLogger(CrysalisLoader.class);
private Map<String, String> textMetadata;
public CrysalisLoader() {
textMetadata = new HashMap<String, String>(3);
}
/**
* @param FileName
*/
public CrysalisLoader(String FileName) {
textMetadata = new HashMap<String, String>(3);
setFile(FileName);
}
@Override
protected void clearMetadata() {
metadata = null;
textMetadata.clear();
}
/**
* The loading function
*
* @return The loaded data object
* @throws ScanFileHolderException
*/
@Override
public DataHolder loadFile() throws ScanFileHolderException {
ILazyDataset data = null;
BufferedReader br = null;
File f = null;
FileInputStream fi = null;
// Try to load the file
try {
f = new File(fileName);
br = new BufferedReader(new FileReader(f));
br.mark(8192);
char[] magic = new char[8];
br.read(magic);
if (!new String(magic).startsWith("OD")) {
throw new ScanFileHolderException("Not a valid Crysalis file");
}
br.reset();
String[] lines = new String[5];
for (int i = 0; i < lines.length; i++) {
lines[i] = br.readLine();
}
if (!lines[1].contains("COMPRESSION= NO")) {
throw new IllegalArgumentException("File is compressed - " + fileName);
}
Pattern p = Pattern.compile("NX= *(\\d+).*");
Matcher m = p.matcher(lines[2]);
if (!m.matches()) {
throw new IllegalArgumentException("NX not found - " + fileName);
}
int nx = Integer.valueOf(m.group(1));
textMetadata.put("nx", "" + nx);
p = Pattern.compile(".*NY= *(\\d+).*");
m = p.matcher(lines[2]);
if (!m.matches()) {
throw new IllegalArgumentException("NY not found - " + fileName);
}
int ny = Integer.valueOf(m.group(1));
textMetadata.put("ny", "" + ny);
p = Pattern.compile("NHEADER= *(\\d+).*");
m = p.matcher(lines[3]);
if (!m.matches()) {
throw new IllegalArgumentException("NHEADER not found - " + fileName);
}
final int nheader = Integer.valueOf(m.group(1));
textMetadata.put("nheader", "" + nheader);
fi = new FileInputStream(f);
fi.skip(nheader);
int[] shape = new int[] { nx, ny };
if (loadLazily) {
data = createLazyDataset(DEF_IMAGE_NAME, Dataset.INT32, shape, new LazyLoaderStub() {
@Override
public IDataset getDataset(IMonitor mon, SliceND slice) throws IOException {
try {
Dataset data = loadDataset(fileName, nheader, slice.getSourceShape());
return data.getSliceView(slice);
} catch (ScanFileHolderException e) {
throw new IOException(e);
}
}
});
} else {
data = DatasetFactory.zeros(IntegerDataset.class, shape);
Utils.readLeInt(fi, (IntegerDataset) data, 0);
}
data.setName(DEF_IMAGE_NAME);
if (loadMetadata)
createMetadata(data);
} catch (Exception e) {
logger.error("File failed to load {} with error: {}" , fileName, e);
throw new ScanFileHolderException("File failed to load " + fileName, e);
} finally {
if (fi != null) {
try {
fi.close();
} catch (IOException ex) {
// do nothing
}
fi = null;
}
if (br != null) {
try {
br.close();
} catch (IOException ex) {
// do nothing
}
br = null;
}
}
// create the holder and then put to the output.
DataHolder output = new DataHolder();
output.addDataset(DEF_IMAGE_NAME, data);
if (loadMetadata) {
data.setMetadata(metadata);
output.setMetadata(metadata);
}
return output;
}
private static Dataset loadDataset(String fileName, int header, int[] shape) throws ScanFileHolderException {
IDataHolder holder = LoaderFactory.fetchData(fileName, false);
if (holder != null) {
IDataset data = holder.getDataset(0);
if (data != null) {
return DatasetUtils.convertToDataset(data);
}
}
Dataset data = null;
FileInputStream fi = null;
// Try to load the file
try {
fi = new FileInputStream(new File(fileName));
fi.skip(header);
data = DatasetFactory.zeros(IntegerDataset.class, shape);
Utils.readLeInt(fi, (IntegerDataset) data, 0);
data.setName(DEF_IMAGE_NAME);
if (holder == null) {
holder = new DataHolder();
holder.setLoaderClass(CrysalisLoader.class);
holder.setFilePath(fileName);
LoaderFactory.cacheData(holder);
}
holder.addDataset(DEF_IMAGE_NAME, data);
return data;
} catch (Exception e) {
logger.error("File failed to load {} with error: {}" , fileName, e);
throw new ScanFileHolderException("File failed to load " + fileName, e);
} finally {
if (fi != null) {
try {
fi.close();
} catch (IOException ex) {
// do nothing
}
fi = null;
}
}
}
private void createMetadata(ILazyDataset data) {
metadata = new Metadata();
metadata.initialize(textMetadata);
metadata.addDataInfo(DEF_IMAGE_NAME, data.getShape());
metadata.setFilePath(fileName);
}
/**
* Fulfils the interface for the save function
*
* @param dh
*/
@Override
public void saveFile(IDataHolder dh) {
File f = null;
FileOutputStream fo = null;
try {
f = new File(fileName);
fo = new FileOutputStream(f);
IDataset ds = dh.getDataset(0);
int[] dims = ds.getShape();
int height = dims[0];
int width = dims[1];
Utils.writeLeInt(fo, height);
Utils.writeLeInt(fo, width);
int[] index = new int[2];
for (int j = 0; j < height; j++) { // row-major ordering
index[0] = j;
for (int i = 0; i < width; i++) {
index[1] = i;
int val = ds.getInt(index);
Utils.writeLeInt(fo, val);
}
}
} catch (Exception e) {
logger.error(e.toString());
} finally {
if (fo != null) {
try {
fo.close();
} catch (IOException ex) {
// do nothing
}
fo = null;
}
}
}
}