/*
* #%L
* OME Bio-Formats package for reading and converting biological file formats.
* %%
* Copyright (C) 2005 - 2015 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.io.IOException;
import loci.common.services.DependencyException;
import loci.common.services.ServiceException;
import loci.common.services.ServiceFactory;
import loci.formats.CoreMetadata;
import loci.formats.FormatException;
import loci.formats.FormatTools;
import loci.formats.ImageWriter;
import loci.formats.meta.IMetadata;
import loci.formats.ome.OMEXMLMetadata;
import loci.formats.services.OMEXMLService;
import loci.formats.MetadataTools;
import ome.xml.model.enums.DimensionOrder;
import ome.xml.model.enums.EnumerationException;
import ome.xml.model.enums.PixelType;
import ome.xml.model.primitives.PositiveInteger;
import ome.xml.model.primitives.NonNegativeInteger;
import ome.xml.model.enums.NamingConvention;
/**
* Example class that shows how to export raw pixel data to OME-TIFF as a Plate
* using Bio-Formats version 5.0.3 or later.
*/
public class FileExportSPW {
private final int sizeT = 3;
private final int rows = 2;
private final int cols = 2;
private final int fovPerWell = 2;
/** The file writer. */
private ImageWriter writer;
/** The name of the output file. */
private final String outputFile;
/**
* Construct a new FileExport that will save to the specified file.
*
* @param outputFile
* the file to which we will export
*/
public FileExportSPW(String outputFile) {
this.outputFile = outputFile;
}
/** Save a single uint16 plane of data. */
public void export() {
int width = 4, height = 4;
int pixelType = FormatTools.UINT16;
Exception exception = null;
IMetadata omexml = initializeMetadata(width, height, pixelType);
int series = 0;
int nSeries = rows * cols * fovPerWell;
// only save data if the file writer was initialized successfully
boolean initializationSuccess = initializeWriter(omexml);
if (initializationSuccess) {
while (series < nSeries) {
for (int p = 0; p < sizeT; p++) {
savePlane(width, height, pixelType, p, series);
}
series++;
if (series < nSeries) {
try {
writer.setSeries(series);
} catch (FormatException e) {
System.err.println("Fatal error unable to select correct image in series! " + e.getMessage());
break;
}
}
} // endwhile
} // endif
cleanup();
}
/**
* Set up the file writer.
*
* @param omexml
* the IMetadata object that is to be associated with the writer
* @return true if the file writer was successfully initialized; false if an
* error occurred
*/
private boolean initializeWriter(IMetadata omexml) {
// create the file writer and associate the OME-XML metadata with it
writer = new ImageWriter();
writer.setMetadataRetrieve(omexml);
Exception exception = null;
try {
writer.setId(outputFile);
} catch (FormatException e) {
exception = e;
} catch (IOException e) {
exception = e;
}
if (exception != null) {
System.err.println("Failed to initialize file writer.");
exception.printStackTrace();
}
return exception == null;
}
/**
* Populate the minimum amount of metadata required to export a Plate.
*
* @param width
* the width (in pixels) of the image
* @param height
* the height (in pixels) of the image
* @param pixelType
* the pixel type of the image; @see loci.formats.FormatTools
*/
private IMetadata initializeMetadata(int width, int height, int pixelType) {
Exception exception = null;
try {
// create the OME-XML metadata storage object
ServiceFactory factory = new ServiceFactory();
OMEXMLService service = factory.getInstance(OMEXMLService.class);
OMEXMLMetadata meta = service.createOMEXMLMetadata();
meta.createRoot();
int plateIndex = 0;
int series = 0; // count of images
int well = 0;
// Create Minimal 2x2 Plate
meta.setPlateID(MetadataTools.createLSID("Plate", 0), 0);
meta.setPlateRowNamingConvention(NamingConvention.LETTER, 0);
meta.setPlateColumnNamingConvention(NamingConvention.NUMBER, 0);
meta.setPlateRows(new PositiveInteger(rows), 0);
meta.setPlateColumns(new PositiveInteger(cols), 0);
meta.setPlateName("First test Plate", 0);
PositiveInteger pwidth = new PositiveInteger(width);
PositiveInteger pheight = new PositiveInteger(height);
char rowChar = 'A';
for (int row = 0; row < rows; row++) {
for (int column = 0; column < cols; column++) {
// set up well
String wellID = MetadataTools.createLSID("Well:", well);
meta.setWellID(wellID, plateIndex, well);
meta.setWellRow(new NonNegativeInteger(row), plateIndex, well);
meta.setWellColumn(new NonNegativeInteger(column), plateIndex, well);
for (int fov = 0; fov < fovPerWell; fov++) {
// Create Image
String imageName = rowChar + ":" + Integer.toString(column+1)
+ ":FOV:" + Integer.toString(fov+1);
String imageID = MetadataTools.createLSID("Image", well, fov);
meta.setImageID(imageID, series);
meta.setImageName(imageName, series);
String pixelsID = MetadataTools
.createLSID("Pixels", row, well, fov);
meta.setPixelsID(pixelsID, series);
// specify that the pixel data is stored in big-endian format
// change 'TRUE' to 'FALSE' to specify little-endian format
meta.setPixelsBinDataBigEndian(Boolean.TRUE, series, 0);
// specify that the image is stored in ZCT order
meta.setPixelsDimensionOrder(DimensionOrder.XYZCT, series);
// specify the pixel type of the image
meta.setPixelsType(
PixelType.fromString(FormatTools.getPixelTypeString(pixelType)),
series);
// specify the dimensions of the image
meta.setPixelsSizeX(pwidth, series);
meta.setPixelsSizeY(pheight, series);
meta.setPixelsSizeZ(new PositiveInteger(1), series);
meta.setPixelsSizeC(new PositiveInteger(1), series);
meta.setPixelsSizeT(new PositiveInteger(sizeT), series);
// define each channel and specify the number of samples in the
// channel the number of samples is 3 for RGB images and 1 otherwise
String channelID = MetadataTools.createLSID("Channel", well, fov);
meta.setChannelID(channelID, series, 0);
meta.setChannelSamplesPerPixel(new PositiveInteger(1), series, 0);
// set sample
String wellSampleID = MetadataTools.createLSID("WellSample", well,
fov);
meta.setWellSampleID(wellSampleID, 0, well, fov);
// NB sampleIndex here == series ie the image No
meta.setWellSampleIndex(new NonNegativeInteger(series), 0, well,
fov);
meta.setWellSampleImageRef(imageID, 0, well, fov);
// add FLIM ModuloAlongT annotation if required
// CoreMetadata modlo = createModuloAnn();
// meta.addModuloAlong(meta, modlo, series);
series++;
} // end of samples
well++;
}
rowChar++;
}
return meta;
} catch (DependencyException e) {
exception = e;
} catch (ServiceException e) {
exception = e;
} catch (EnumerationException e) {
exception = e;
}
System.err.println("Failed to populate OME-XML metadata object.");
exception.printStackTrace();
return null;
}
/**
* Add ModuloAlong annotation.
*
* @param meta
* OMEXMLMetadata Object to which Modulo need to be added
*/
private CoreMetadata createModuloAnn() {
CoreMetadata modlo = new CoreMetadata();
modlo.moduloT.type = loci.formats.FormatTools.LIFETIME;
modlo.moduloT.unit = "ps";
modlo.moduloT.typeDescription = "Gated";
modlo.moduloT.labels = new String[sizeT];
for (int i = 0; i < sizeT; i++) {
modlo.moduloT.labels[i] = Integer.toString(i * 1000);
}
return modlo;
}
/**
* Generate a plane of pixel data and save it to the output file.
*
* @param width
* the width of the image in pixels
* @param height
* the height of the image in pixels
* @param pixelType
* the pixel type of the image; @see loci.formats.FormatTools
*/
private void savePlane(int width, int height, int pixelType, int index,
int series) {
byte[] plane = createImage(width, height, pixelType, index, series);
Exception exception = null;
try {
writer.saveBytes(index, plane);
} catch (FormatException e) {
exception = e;
} catch (IOException e) {
exception = e;
}
if (exception != null) {
System.err.println("Failed to save plane.");
exception.printStackTrace();
}
}
/**
* Generate a plane of pixel data.
*
* @param width
* the width of the image in pixels
* @param height
* the height of the image in pixels
* @param pixelType
* the pixel type of the image; @see loci.formats.FormatTools
*/
private byte[] createImage(int width, int height, int pixelType, int index,
int series) {
// create a blank image of the specified size
int bpp = FormatTools.getBytesPerPixel(pixelType);
byte[] img = new byte[width * height * bpp];
ByteBuffer bb = ByteBuffer.wrap(img);
bb.order(ByteOrder.BIG_ENDIAN);
// fill it with background
for (int i = 0; i < img.length; i += bpp) {
bb.putShort(i, (short) 200);
}
// then set 1 pixel to non-zero. Different values in each plane
switch (index) {
case 0:
bb.putShort(series * bpp, (short) 1000);
break;
case 1:
bb.putShort(series * bpp, (short) 700);
break;
case 2:
bb.putShort(series * bpp, (short) 300);
break;
}
return img;
}
/** Close the file writer. */
private void cleanup() {
try {
writer.close();
} catch (IOException e) {
System.err.println("Failed to close file writer. " + e.getMessage());
}
}
/**
* To export a file to OME-TIFF:
*
* $ java FileExportSPW output-file.ome.tiff
*
* @param args
* @throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
String fileName = args[0];
File file = new File(fileName);
Exception exception = null;
// delete file if it exists
// NB deleting old files seems to be critical
if (file.exists()) {
file.delete();
}
FileExportSPW exporter = new FileExportSPW(fileName);
exporter.export();
}
}