/*
* #%L
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2005 - 2015 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package loci.formats.out;
import ch.systemsx.cisd.base.mdarray.MDArray;
import ch.systemsx.cisd.base.mdarray.MDByteArray;
import ch.systemsx.cisd.base.mdarray.MDIntArray;
import ch.systemsx.cisd.base.mdarray.MDShortArray;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Locale;
import loci.common.services.DependencyException;
import loci.common.services.ServiceFactory;
import loci.formats.FormatException;
import loci.formats.FormatTools;
import loci.formats.FormatWriter;
import loci.formats.MissingLibraryException;
import loci.formats.in.CellH5Reader;
import loci.formats.in.CellH5Reader.CellH5Constants;
import loci.formats.meta.MetadataRetrieve;
import loci.formats.services.JHDFService;
import loci.formats.services.JHDFServiceImpl;
import loci.formats.tiff.IFD;
import ome.units.quantity.Time;
import ome.units.quantity.Length;
import ome.units.UNITS;
import ome.xml.model.enums.DimensionOrder;
import ome.xml.model.primitives.NonNegativeInteger;
/**
* CellH5Writer is the file format writer for CellH5 format.
*/
public class CellH5Writer extends FormatWriter {
// -- Constants --
// -- Fields --
private transient JHDFService jhdf;
private long bpp;
private String outputPath;
// -- Constructors --
public CellH5Writer() {
this("CellH5 File Format", new String[] {"ch5"});
}
public CellH5Writer(String format, String[] exts) {
super(format, exts);
}
// -- FormatWriter API methods --
/* @see loci.formats.FormatWriter#setId(String) */
@Override
public void setId(String id) throws FormatException, IOException {
if (id.equals(currentId)) return;
super.setId(id);
try {
ServiceFactory factory = new ServiceFactory();
jhdf = factory.getInstance(JHDFService.class);
jhdf.setFileForWrite(id);
} catch (DependencyException e) {
throw new MissingLibraryException(JHDFServiceImpl.NO_JHDF_MSG, e);
}
MetadataRetrieve retrieve = getMetadataRetrieve();
int sizeX = retrieve.getPixelsSizeX(0).getValue();
int sizeY = retrieve.getPixelsSizeY(0).getValue();
int sizeZ = retrieve.getPixelsSizeZ(0).getValue();
int sizeC = retrieve.getPixelsSizeC(0).getValue();
int sizeT = retrieve.getPixelsSizeT(0).getValue();
int type = FormatTools.pixelTypeFromString(retrieve.getPixelsType(0).toString());
bpp = FormatTools.getBytesPerPixel(type);
LOGGER.info("CellH5Writer: Found image with dimensions XYZCT {}x{}x{}x{}x{}, and bits per pixel {}", sizeX, sizeY, sizeZ, sizeC, sizeT, bpp);
String plate = "PLATE_00";
String well = "WELL_00";
int site = 1;
if (retrieve.getPlateCount()>0) {
plate = retrieve.getPlateName(0);
well = retrieve.getWellExternalIdentifier(0, 0);
site = retrieve.getWellSampleIndex(0, 0, 0).getValue();
LOGGER.info("CellH5Writer: Found plate information Plate / Well / Site {} / {} / {}", plate, well, site);
} else {
LOGGER.info("CellH5Writer: No plate information found. Using default values...");
}
jhdf.createGroup(CellH5Constants.DEFINITION + CellH5Reader.CellH5Constants.OBJECT);
jhdf.createGroup(CellH5Constants.DEFINITION + CellH5Reader.CellH5Constants.FEATURE);
jhdf.createGroup(CellH5Constants.DEFINITION + CellH5Reader.CellH5Constants.IMAGE);
outputPath = String.format("/sample/0/plate/%s/experiment/%s/position/%d/image/channel", plate, well, site);
jhdf.initIntArray(outputPath, new long[] {sizeC, sizeT, sizeZ, sizeY, sizeX}, bpp);
}
/**
* Saves the given image to the specified (possibly already open) file.
*/
@Override
public void saveBytes(int no, byte[] buf)
throws IOException, FormatException
{
LOGGER.info("CellH5Writer: Save image to HDF5 path: " + outputPath);
MetadataRetrieve r = getMetadataRetrieve();
int sizeX = r.getPixelsSizeX(series).getValue();
int sizeY = r.getPixelsSizeY(series).getValue();
int sizeC = r.getPixelsSizeC(series).getValue();
int sizeT = r.getPixelsSizeT(series).getValue();
int sizeZ = r.getPixelsSizeZ(series).getValue();
DimensionOrder dimo = r.getPixelsDimensionOrder(0);
int c, z, t;
if (dimo.equals(DimensionOrder.XYCZT)) {
c = no % sizeC;
z = ((no - c) / sizeC) % sizeZ;
t = (((no - c) / sizeC)) / sizeZ;
} else if (dimo.equals(DimensionOrder.XYCTZ)){
c = no % sizeC;
t = ((no - c) / sizeC) % sizeT;
z = (((no - c) / sizeC)) / sizeT;
} else if (dimo.equals(DimensionOrder.XYZTC)){
z = no % sizeZ;
t = ((no - z) / sizeZ) % sizeT;
c = (((no - z) / sizeZ)) / sizeT;
} else {
throw new FormatException("CellH5Writer: Dimension order not understood: " + dimo.getValue());
}
LOGGER.info("CellH5Writer.saveBytes(): Current c, t, z == {} {} {}", c,t,z);
LOGGER.info("CellH5Writer.saveBytes(): bpp {} byte buffer len {}", bpp, buf.length);
if (bpp==1) {
MDByteArray image = new MDByteArray(new int[] {1, 1, 1, sizeY, sizeX});
for (int x_i=0; x_i < sizeX; x_i++) {
for (int y_i=0; y_i < sizeY; y_i++) {
byte value = (byte) buf[y_i*sizeX + x_i];
image.set(value, 0, 0, 0, y_i, x_i );
}
}
jhdf.writeArraySlice(outputPath, image, new long[] {c,t,z, 0, 0});
} else if (bpp==2) {
ByteBuffer bb = ByteBuffer.wrap(buf);
ShortBuffer sb = bb.asShortBuffer();
MDShortArray image = new MDShortArray(new int[] {1, 1, 1, sizeY, sizeX});
for (int x_i=0; x_i < sizeX; x_i++) {
for (int y_i=0; y_i < sizeY; y_i++) {
short value = sb.get(y_i*sizeX + x_i);
image.set(value, 0, 0, 0, y_i, x_i );
}
}
jhdf.writeArraySlice(outputPath, image, new long[] {c,t,z, 0, 0});
} else if (bpp==4) {
ByteBuffer bb = ByteBuffer.wrap(buf);
IntBuffer ib = bb.asIntBuffer();
MDIntArray image = new MDIntArray(new int[] {1, 1, 1, sizeY, sizeX});
for (int x_i=0; x_i < sizeX; x_i++) {
for (int y_i=0; y_i < sizeY; y_i++) {
int value = (int) ib.get(y_i*sizeX + x_i);
image.set(value, 0, 0, 0, y_i, x_i );
}
}
jhdf.writeArraySlice(outputPath, image, new long[] {c,t,z, 0, 0});
} else {
throw new FormatException("CellH5Writer: Pixel type not supported");
}
}
// -- FormatWriter API methods --
/* (non-Javadoc)
* @see loci.formats.FormatWriter#close()
*/
@Override
public void close() throws IOException {
jhdf.close();
super.close();
}
/* @see loci.formats.FormatWriter#getPlaneCount() */
@Override
public int getPlaneCount() {
MetadataRetrieve retrieve = getMetadataRetrieve();
int c = getSamplesPerPixel();
int type = FormatTools.pixelTypeFromString(
retrieve.getPixelsType(series).toString());
int bytesPerPixel = FormatTools.getBytesPerPixel(type);
if (bytesPerPixel > 1 && c != 1 && c != 3) {
return super.getPlaneCount() * c;
}
return super.getPlaneCount();
}
// -- IFormatWriter API methods --
/**
* @see loci.formats.IFormatWriter#saveBytes(int, byte[], int, int, int, int)
*/
@Override
public void saveBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
// always save to full image
saveBytes(no, buf);
}
/* @see loci.formats.IFormatWriter#canDoStacks(String) */
@Override
public boolean canDoStacks() { return true; }
/* @see loci.formats.IFormatWriter#getPixelTypes(String) */
@Override
public int[] getPixelTypes(String codec) {
return new int[] {FormatTools.UINT8, FormatTools.UINT16, FormatTools.INT32};
}
}