/*
* 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.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import javax.imageio.ImageIO;
import javax.media.jai.PlanarImage;
import javax.media.jai.TiledImage;
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.dataset.Dataset;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.metadata.IMetadata;
/**
* Class that saves data from DataHolder using native Java ImageIO library
* with built-in image reader/writer
*
* If the DataHolder contains more than one dataset then multiple image
* files are saved with names labelled from 00001 to 99999.
*/
public class JavaImageSaver implements IFileSaver {
static {
ImageIO.scanForPlugins(); // in case the ImageIO jar has not been loaded yet
}
private String fileName = "";
private String fileType = "";
protected double maxVal;
protected boolean unsigned = false;
private int numBits;
/**
* @param FileName
* which is the name of the file being passed to this class.
* @param FileType
* type of file to be saved
* @param NumBits
* number of bits in each pixel (greyscale representation); use > 32 for floats (TIFF only)
* @param asUnsigned
* treat dataset items as unsigned (unless saving as floats)
*/
public JavaImageSaver(String FileName, String FileType, int NumBits, boolean asUnsigned) {
fileName = FileName;
fileType = FileType; // format name
numBits = NumBits;
if (numBits <= 32) {
maxVal = (1L << NumBits) - 1.0; // 2^NumBits - 1 (use long in case of overflow)
unsigned = asUnsigned;
} else {
maxVal = 1.0; // flag to use doubles (TIFF only)
}
}
@Override
public void saveFile(IDataHolder dh) throws ScanFileHolderException {
File f = null;
if (numBits <= 0) {
throw new ScanFileHolderException(
"Number of bits specified must be greater than 0");
}
for (int i = 0, imax = dh.size(); i < imax; i++) {
try {
String name = null;
if (imax == 1) {
name = fileName;
} else {
try {
name = fileName.substring(0,
(fileName.lastIndexOf(".")));
} catch (Exception e) {
name = fileName;
}
NumberFormat format = new DecimalFormat("00000");
name = name + format.format(i + 1);
}
int l = new File(name).getName().lastIndexOf(".");
if (l < 0) {
name = name + "." + fileType;
}
f = new File(name);
IDataset idata = dh.getDataset(i);
Dataset data = DatasetUtils.convertToDataset(idata);
if (numBits <= 16) {
// test to see if the values of the data are within the
// capabilities of format
if (maxVal > 0 && data.max().doubleValue() > maxVal) {
throw new ScanFileHolderException("The value of a pixel exceeds the maximum value that "
+ fileType + " is capable of handling. To save a "
+ fileType + " it is recommended to use a ScaledSaver class. File "
+ fileName + " not written");
}
if (unsigned && data.min().doubleValue() < 0) {
throw new ScanFileHolderException(
"The value of a pixel is less than 0. Recommended using a ScaledSaver class.");
}
BufferedImage image = AWTImageUtils.makeBufferedImage(data, numBits);
if (image == null) {
throw new ScanFileHolderException("Unable to create a buffered image to save file type");
}
boolean w = writeImageLocked(image, fileType, f, dh);
if (!w)
throw new ScanFileHolderException("No writer for '" + fileName + "' of type " + fileType);
} else {
TiledImage image = AWTImageUtils.makeTiledImage(data, numBits);
if (image == null) {
throw new ScanFileHolderException("Unable to create a tiled image to save file type");
}
boolean w = writeImageLocked(image, fileType, f, dh);
if (!w)
throw new ScanFileHolderException("No writer for '" + fileName + "' of type " + fileType);
}
} catch (ScanFileHolderException e) {
throw e;
} catch (Exception e) {
throw new ScanFileHolderException("Error saving file '" + fileName + "'", e);
}
}
}
protected boolean writeImageLocked(RenderedImage image, String fileType, File f, IDataHolder dh) throws Exception {
// Write meta data to image header
if (image instanceof PlanarImage) {
PlanarImage pi = (PlanarImage)image;
if (dh.getFilePath()!=null) {
pi.setProperty("originalDataSource", dh.getFilePath());
}
IMetadata meta = dh.getMetadata();
if (meta != null) {
Collection<String> dNames = meta.getMetaNames();
if (dNames!=null) for (String name : dNames) {
pi.setProperty(name, meta.getMetaValue(name));
}
}
}
// Separate method added as may add file locking option.
return ImageIO.write(image, fileType, f);
}
}