/*
* 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.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
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.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.ShortDataset;
import org.eclipse.january.dataset.SliceND;
import org.eclipse.january.metadata.Metadata;
/**
* This class should be used to load .pgm datafiles (Portable Grey Map)
* into the ScanFileHolder object.
* <p>
* <b>Note</b>: the header data from this loader is left as strings
*/
public class PgmLoader extends AbstractFileLoader {
private Map<String, String> textMetadata = new HashMap<String, String>();
private static final String DATA_NAME = "Portable Grey Map";
public PgmLoader() {
}
/**
* @param fileName
*/
public PgmLoader(String fileName) {
this.fileName = fileName;
}
@Override
protected void clearMetadata() {
metadata = null;
textMetadata.clear();
}
@Override
public DataHolder loadFile() throws ScanFileHolderException {
return loadFile(null);
}
@Override
public DataHolder loadFile(IMonitor mon) throws ScanFileHolderException {
ILazyDataset data = null;
DataHolder output = new DataHolder();
File f = null;
FileInputStream fi = null;
try {
f = new File(fileName);
fi = new FileInputStream(f);
BufferedReader br = new BufferedReader(new FileReader(f));
int[] vals = readMetaData(br, mon, textMetadata);
int index = vals[0];
int width = vals[1];
int height = vals[2];
int maxval = vals[3];
if (loadLazily) {
data = createLazyDataset(DEF_IMAGE_NAME, maxval < 256 ? Dataset.INT16 : Dataset.INT32, new int[] {height, width}, new LazyLoaderStub() {
@Override
public IDataset getDataset(IMonitor mon, SliceND slice) throws IOException {
try {
Dataset data = loadDataset(fileName);
return data == null ? null : data.getSliceView(slice);
} catch (ScanFileHolderException e) {
throw new IOException(e);
}
}
});
} else {
// Now read the data
if (maxval < 256) {
data = DatasetFactory.zeros(ShortDataset.class, height, width);
Utils.readByte(fi, (ShortDataset) data, index);
} else {
data = DatasetFactory.zeros(IntegerDataset.class, height, width);
Utils.readBeShort(fi, (IntegerDataset) data, index, false);
}
data.setName(DEF_IMAGE_NAME);
}
} catch (Exception e) {
throw new ScanFileHolderException("File failed to load " + fileName, e);
} finally {
if (fi != null) {
try {
fi.close();
} catch (IOException ex) {
// do nothing
}
fi = null;
}
}
output.addDataset(DATA_NAME, data);
if (loadMetadata) {
createMetadata();
data.setMetadata(metadata);
output.setMetadata(metadata);
}
return output;
}
private static Dataset loadDataset(String fileName) throws ScanFileHolderException {
IDataHolder holder = LoaderFactory.fetchData(fileName, false);
if (holder != null) {
IDataset data = holder.getDataset(DEF_IMAGE_NAME);
if (data != null) {
return DatasetUtils.convertToDataset(data);
}
}
File f = null;
FileInputStream fi = null;
try {
f = new File(fileName);
fi = new FileInputStream(f);
BufferedReader br = new BufferedReader(new FileReader(f));
int[] vals = readMetaData(br, null, new HashMap<String, String>());
int index = vals[0];
int width = vals[1];
int height = vals[2];
int maxval = vals[3];
Dataset data;
// Now read the data
if (maxval < 256) {
data = DatasetFactory.zeros(ShortDataset.class, height, width);
Utils.readByte(fi, (ShortDataset) data, index);
} else {
data = DatasetFactory.zeros(IntegerDataset.class, height, width);
Utils.readBeShort(fi, (IntegerDataset) data, index, false);
}
data.setName(DEF_IMAGE_NAME);
if (holder == null) {
holder = new DataHolder();
holder.setLoaderClass(PgmLoader.class);
holder.setFilePath(fileName);
LoaderFactory.cacheData(holder);
}
holder.addDataset(DEF_IMAGE_NAME, data);
return data;
} catch (Exception 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 static int[] readMetaData(BufferedReader br, IMonitor mon, Map<String, String> textMetadata) throws Exception {
int width = 0;
int height = 0;
int maxval = 0;
textMetadata.clear();
if (!monitorIncrement(mon)) {
throw new ScanFileHolderException("Loader cancelled during reading!");
}
String line = br.readLine();
if (line == null) {
throw new ScanFileHolderException("End of file reached with no metadata found");
}
int index = line.length()+1;
String token;
StringTokenizer s1 = new StringTokenizer(line);
token = s1.nextToken();
textMetadata.put("MagicNumber", token);
if (token.startsWith("P5")) {
if (!s1.hasMoreTokens()) {
do {
line = br.readLine();
if (line == null) {
throw new ScanFileHolderException("End of file reached with width not found");
}
index += line.length() + 1;
} while (line.startsWith("#")); // ignore comment lines
s1 = new StringTokenizer(line);
}
token = s1.nextToken();
textMetadata.put("Width", token);
width = Integer.parseInt(token);
if (!s1.hasMoreTokens()) {
line = br.readLine();
if (line == null) {
throw new ScanFileHolderException("End of file reached with height not found");
}
index += line.length()+1;
s1 = new StringTokenizer(line);
}
token = s1.nextToken();
textMetadata.put("Height", token);
height = Integer.parseInt(token);
if (!s1.hasMoreTokens()) {
line = br.readLine();
if (line == null) {
throw new ScanFileHolderException("End of file reached with max value not found");
}
index += line.length()+1;
s1 = new StringTokenizer(line);
}
token = s1.nextToken();
textMetadata.put("Maxval", token);
maxval = Integer.parseInt(token);
}
return new int[]{index, width, height, maxval};
}
private void createMetadata() {
metadata = new Metadata();
metadata.initialize(textMetadata);
metadata.setFilePath(fileName);
metadata.addDataInfo(DATA_NAME, Integer.parseInt(textMetadata.get("Height")), Integer.parseInt(textMetadata.get("Width")));
}
public String getHeaderValue(String key) {
return textMetadata.get(key);
}
}