//
// ZeissCZIReader.java
//
/*
OME Bio-Formats package for reading and converting biological file formats.
Copyright (C) 2005-@year@ UW-Madison LOCI and Glencoe Software, Inc.
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package loci.formats.in;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import loci.common.DateTools;
import loci.common.Location;
import loci.common.RandomAccessInputStream;
import loci.common.xml.XMLTools;
import loci.formats.CoreMetadata;
import loci.formats.FormatException;
import loci.formats.FormatReader;
import loci.formats.FormatTools;
import loci.formats.MetadataTools;
import loci.formats.codec.CodecOptions;
import loci.formats.codec.JPEGCodec;
import loci.formats.codec.LZWCodec;
import loci.formats.meta.MetadataStore;
import ome.xml.model.primitives.NonNegativeInteger;
import ome.xml.model.primitives.PercentFraction;
import ome.xml.model.primitives.PositiveFloat;
import ome.xml.model.primitives.PositiveInteger;
import org.xml.sax.SAXException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* ZeissCZIReader is the file format reader for Zeiss .czi files.
*
* <dl><dt><b>Source code:</b></dt>
* <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/in/ZeissCZIReader.java">Trac</a>,
* <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/ZeissCZIReader.java;hb=HEAD">Gitweb</a></dd></dl>
*/
public class ZeissCZIReader extends FormatReader {
// -- Constants --
private static final int ALIGNMENT = 32;
private static final int HEADER_SIZE = 32;
private static final String CZI_MAGIC_STRING = "ZISRAWFILE";
/** Compression constants. */
private static final int UNCOMPRESSED = 0;
private static final int JPEG = 1;
private static final int LZW = 2;
/** Pixel type constants. */
private static final int GRAY8 = 0;
private static final int GRAY16 = 1;
private static final int GRAY_FLOAT = 2;
private static final int BGR_24 = 3;
private static final int BGR_48 = 4;
private static final int BGR_FLOAT = 8;
private static final int BGRA_8 = 9;
private static final int COMPLEX = 10;
private static final int COMPLEX_FLOAT = 11;
private static final int GRAY32 = 12;
private static final int GRAY_DOUBLE = 13;
// -- Fields --
private MetadataStore store;
private ArrayList<SubBlock> planes;
private int rotations = 1;
private int positions = 1;
private int illuminations = 1;
private int acquisitions = 1;
private int mosaics = 1;
private int phases = 1;
private String acquiredDate;
private String userDisplayName, userName;
private String userFirstName, userLastName, userMiddleName;
private String userEmail;
private String userInstitution;
private String temperature, airPressure, humidity, co2Percent;
private String correctionCollar, medium, refractiveIndex;
private ArrayList<String> emissionWavelengths = new ArrayList<String>();
private ArrayList<String> excitationWavelengths = new ArrayList<String>();
private ArrayList<String> pinholeSizes = new ArrayList<String>();
private ArrayList<String> channelNames = new ArrayList<String>();
private ArrayList<String> channelColors = new ArrayList<String>();
private ArrayList<String> binnings = new ArrayList<String>();
private ArrayList<String> detectorRefs = new ArrayList<String>();
private ArrayList<String> objectiveIDs = new ArrayList<String>();
private Double[] positionsX;
private Double[] positionsY;
private Double[] positionsZ;
private int previousChannel = 0;
// -- Constructor --
/** Constructs a new Zeiss .czi reader. */
public ZeissCZIReader() {
super("Zeiss CZI", "czi");
domains = new String[] {FormatTools.LM_DOMAIN};
suffixSufficient = true;
suffixNecessary = false;
}
// -- IFormatReader API methods --
/**
* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream)
*/
public boolean isThisType(RandomAccessInputStream stream) throws IOException {
final int blockLen = 10;
if (!FormatTools.validStream(stream, blockLen, true)) return false;
String check = stream.readString(blockLen);
return check.equals(CZI_MAGIC_STRING);
}
/* @see loci.formats.IFormatReader#get8BitLookupTable() */
public byte[][] get8BitLookupTable() throws FormatException, IOException {
if ((getPixelType() != FormatTools.INT8 &&
getPixelType() != FormatTools.UINT8) || previousChannel == -1)
{
return null;
}
byte[][] lut = new byte[3][256];
String color = channelColors.get(previousChannel);
if (color != null) {
color = color.replaceAll("#", "");
try {
int colorValue = Integer.parseInt(color, 16);
int redMax = (colorValue & 0xff0000) >> 16;
int greenMax = (colorValue & 0xff00) >> 8;
int blueMax = colorValue & 0xff;
for (int i=0; i<lut[0].length; i++) {
lut[0][i] = (byte) (redMax * (i / 255.0));
lut[1][i] = (byte) (greenMax * (i / 255.0));
lut[2][i] = (byte) (blueMax * (i / 255.0));
}
return lut;
}
catch (NumberFormatException e) {
return null;
}
}
else return null;
}
/* @see loci.formats.IFormatReader#get16BitLookupTable() */
public short[][] get16BitLookupTable() throws FormatException, IOException {
if ((getPixelType() != FormatTools.INT16 &&
getPixelType() != FormatTools.UINT16) || previousChannel == -1)
{
return null;
}
short[][] lut = new short[3][65536];
String color = channelColors.get(previousChannel);
if (color != null) {
color = color.replaceAll("#", "");
try {
int colorValue = Integer.parseInt(color, 16);
int redMax = (colorValue & 0xff0000) >> 16;
int greenMax = (colorValue & 0xff00) >> 8;
int blueMax = colorValue & 0xff;
redMax = (int) (65535 * (redMax / 255.0));
greenMax = (int) (65535 * (greenMax / 255.0));
blueMax = (int) (65535 * (blueMax / 255.0));
for (int i=0; i<lut[0].length; i++) {
lut[0][i] = (short) ((int) (redMax * (i / 65535.0)) & 0xffff);
lut[1][i] = (short) ((int) (greenMax * (i / 65535.0)) & 0xffff);
lut[2][i] = (short) ((int) (blueMax * (i / 65535.0)) & 0xffff);
}
return lut;
}
catch (NumberFormatException e) {
return null;
}
}
else return null;
}
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
previousChannel = getZCTCoords(no)[1];
int currentSeries = getSeries();
for (SubBlock plane : planes) {
if (plane.seriesIndex == currentSeries && plane.planeIndex == no) {
byte[] rawData = plane.readPixelData();
RandomAccessInputStream s = new RandomAccessInputStream(rawData);
readPlane(s, x, y, w, h, buf);
s.close();
break;
}
}
return buf;
}
/* @see loci.formats.IFormatReader#close(boolean) */
public void close(boolean fileOnly) throws IOException {
super.close(fileOnly);
if (!fileOnly) {
planes = null;
rotations = 1;
positions = 1;
illuminations = 1;
acquisitions = 1;
mosaics = 1;
phases = 1;
store = null;
acquiredDate = null;
userDisplayName = null;
userName = null;
userFirstName = null;
userLastName = null;
userMiddleName = null;
userEmail = null;
userInstitution = null;
temperature = null;
airPressure = null;
humidity = null;
co2Percent = null;
correctionCollar = null;
medium = null;
refractiveIndex = null;
positionsX = null;
positionsY = null;
positionsZ = null;
emissionWavelengths.clear();
excitationWavelengths.clear();
pinholeSizes.clear();
channelNames.clear();
channelColors.clear();
binnings.clear();
detectorRefs.clear();
objectiveIDs.clear();
previousChannel = 0;
}
}
// -- Internal FormatReader API methods --
/* @see loci.formats.FormatReader#initFile(String) */
protected void initFile(String id) throws FormatException, IOException {
super.initFile(id);
in = new RandomAccessInputStream(id);
core[0].littleEndian = true;
in.order(isLittleEndian());
ArrayList<Segment> segments = new ArrayList<Segment>();
planes = new ArrayList<SubBlock>();
while (in.getFilePointer() < in.length()) {
Segment segment = readSegment();
segments.add(segment);
if (segment instanceof SubBlock) {
planes.add((SubBlock) segment);
}
}
calculateDimensions();
convertPixelType(planes.get(0).directoryEntry.pixelType);
// remove any invalid SubBlocks
int planeSize =
getSizeX() * getSizeY() * FormatTools.getBytesPerPixel(getPixelType());
for (int i=0; i<planes.size(); i++) {
byte[] pixels = planes.get(i).readPixelData();
if (pixels.length < planeSize) {
planes.remove(i);
i--;
}
}
if (getSizeZ() == 0) {
core[0].sizeZ = 1;
}
if (getSizeC() == 0) {
core[0].sizeC = 1;
}
if (getSizeT() == 0) {
core[0].sizeT = 1;
}
// finish populating the core metadata
int seriesCount = rotations * positions * illuminations * acquisitions *
mosaics * phases;
core[0].imageCount = planes.size() / seriesCount;
if (seriesCount > 1) {
CoreMetadata firstSeries = core[0];
core = new CoreMetadata[seriesCount];
for (int i=0; i<seriesCount; i++) {
core[i] = firstSeries;
}
}
core[0].dimensionOrder = "XYCZT";
assignPlaneIndices();
// populate the OME metadata
store = makeFilterMetadata();
MetadataTools.populatePixels(store, this, true);
for (Segment segment : segments) {
if (segment instanceof Metadata) {
String xml = ((Metadata) segment).xml;
xml = XMLTools.sanitizeXML(xml);
translateMetadata(xml);
}
}
if (channelColors.size() > 0) {
for (int i=0; i<seriesCount; i++) {
core[i].indexed = true;
}
}
String experimenterID = MetadataTools.createLSID("Experimenter", 0);
store.setExperimenterID(experimenterID, 0);
store.setExperimenterDisplayName(userDisplayName, 0);
store.setExperimenterEmail(userEmail, 0);
store.setExperimenterFirstName(userFirstName, 0);
store.setExperimenterInstitution(userInstitution, 0);
store.setExperimenterLastName(userLastName, 0);
store.setExperimenterMiddleName(userMiddleName, 0);
store.setExperimenterUserName(userName, 0);
String name = new Location(getCurrentFile()).getName();
for (int i=0; i<getSeriesCount(); i++) {
store.setImageAcquiredDate(acquiredDate, i);
store.setImageExperimenterRef(experimenterID, i);
store.setImageName(name + " #" + (i + 1), i);
if (airPressure != null) {
store.setImagingEnvironmentAirPressure(new Double(airPressure), i);
}
if (co2Percent != null) {
store.setImagingEnvironmentCO2Percent(
PercentFraction.valueOf(co2Percent), i);
}
if (humidity != null) {
store.setImagingEnvironmentHumidity(
PercentFraction.valueOf(humidity), i);
}
if (temperature != null) {
store.setImagingEnvironmentTemperature(new Double(temperature), i);
}
store.setImageObjectiveSettingsID(objectiveIDs.get(0), i);
if (correctionCollar != null) {
store.setImageObjectiveSettingsCorrectionCollar(
new Double(correctionCollar), i);
}
store.setImageObjectiveSettingsMedium(getMedium(medium), i);
if (refractiveIndex != null) {
store.setImageObjectiveSettingsRefractiveIndex(
new Double(refractiveIndex), i);
}
Double startTime = null;
if (acquiredDate != null) {
startTime =
DateTools.getTime(acquiredDate, DateTools.ISO8601_FORMAT) / 1000d;
}
for (int plane=0; plane<getImageCount(); plane++) {
for (SubBlock p : planes) {
if (p.seriesIndex == i && p.planeIndex == plane) {
if (startTime == null) {
startTime = p.timestamp;
}
if (p.stageX != null) {
store.setPlanePositionX(p.stageX, i, plane);
}
else if (positionsX != null && i < positionsX.length) {
store.setPlanePositionX(positionsX[i], i, plane);
}
if (p.stageY != null) {
store.setPlanePositionY(p.stageY, i, plane);
}
else if (positionsY != null && i < positionsY.length) {
store.setPlanePositionY(positionsY[i], i, plane);
}
if (positionsZ != null && i < positionsZ.length) {
store.setPlanePositionZ(positionsZ[i], i, plane);
}
if (p.timestamp != null) {
store.setPlaneDeltaT(p.timestamp - startTime, i, plane);
}
if (p.exposureTime != null) {
store.setPlaneExposureTime(p.exposureTime, i, plane);
}
}
}
}
for (int c=0; c<getEffectiveSizeC(); c++) {
if (c < channelNames.size()) {
store.setChannelName(channelNames.get(c), i, c);
}
if (c < channelColors.size()) {
String color = channelColors.get(c);
if (color != null) {
color = color.replaceAll("#", "");
try {
store.setChannelColor(Integer.parseInt(color, 16), i, c);
}
catch (NumberFormatException e) { }
}
}
if (c < emissionWavelengths.size()) {
String emWave = emissionWavelengths.get(c);
if (emWave != null) {
Double wave = new Double(emWave);
if (wave.intValue() > 0) {
store.setChannelEmissionWavelength(
new PositiveInteger(wave.intValue()), i, c);
}
}
}
if (c < excitationWavelengths.size()) {
String exWave = excitationWavelengths.get(c);
if (exWave != null) {
Double wave = new Double(exWave);
if (wave.intValue() > 0) {
store.setChannelExcitationWavelength(
new PositiveInteger(wave.intValue()), i, c);
}
}
}
if (c < pinholeSizes.size() && pinholeSizes.get(c) != null) {
store.setChannelPinholeSize(new Double(pinholeSizes.get(c)), i, c);
}
if (c < detectorRefs.size()) {
String detector = detectorRefs.get(c);
store.setDetectorSettingsID(detector, i, c);
if (c < binnings.size()) {
store.setDetectorSettingsBinning(getBinning(binnings.get(c)), i, c);
}
}
}
}
}
// -- Helper methods --
private void calculateDimensions() {
// calculate the dimensions
for (SubBlock plane : planes) {
for (DimensionEntry dimension : plane.directoryEntry.dimensionEntries) {
switch (dimension.dimension.charAt(0)) {
case 'X':
core[0].sizeX = dimension.size;
break;
case 'Y':
core[0].sizeY = dimension.size;
break;
case 'C':
if (dimension.start >= getSizeC()) {
core[0].sizeC = dimension.start + 1;
}
break;
case 'Z':
if (dimension.start >= getSizeZ()) {
core[0].sizeZ = dimension.start + 1;
}
break;
case 'T':
if (dimension.start >= getSizeT()) {
core[0].sizeT = dimension.start + 1;
}
break;
case 'R':
if (dimension.start >= rotations) {
rotations = dimension.start + 1;
}
break;
case 'S':
if (dimension.start >= positions) {
positions = dimension.start + 1;
}
break;
case 'I':
if (dimension.start >= illuminations) {
illuminations = dimension.start + 1;
}
break;
case 'B':
if (dimension.start >= acquisitions) {
acquisitions = dimension.start + 1;
}
break;
case 'M':
if (dimension.start >= mosaics) {
mosaics = dimension.start + 1;
}
break;
case 'H':
if (dimension.start >= phases) {
phases = dimension.start + 1;
}
break;
}
}
}
}
private void assignPlaneIndices() {
// assign plane and series indices to each SubBlock
int[] extraLengths =
{rotations, positions, illuminations, acquisitions, mosaics, phases};
for (SubBlock plane : planes) {
int z = 0;
int c = 0;
int t = 0;
int[] extra = new int[6];
for (DimensionEntry dimension : plane.directoryEntry.dimensionEntries) {
switch (dimension.dimension.charAt(0)) {
case 'C':
c = dimension.start;
break;
case 'Z':
z = dimension.start;
break;
case 'T':
t = dimension.start;
break;
case 'R':
extra[0] = dimension.start;
break;
case 'S':
extra[1] = dimension.start;
break;
case 'I':
extra[2] = dimension.start;
break;
case 'B':
extra[3] = dimension.start;
break;
case 'M':
extra[4] = dimension.start;
break;
case 'H':
extra[5] = dimension.start;
break;
}
}
plane.planeIndex = getIndex(z, c, t);
plane.seriesIndex = FormatTools.positionToRaster(extraLengths, extra);
}
}
private void translateMetadata(String xml) throws FormatException, IOException
{
Element root = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
ByteArrayInputStream s = new ByteArrayInputStream(xml.getBytes());
root = parser.parse(s).getDocumentElement();
s.close();
}
catch (ParserConfigurationException e) {
throw new FormatException(e);
}
catch (SAXException e) {
throw new FormatException(e);
}
if (root == null) {
throw new FormatException("Could not parse the XML metadata.");
}
NodeList children = root.getChildNodes();
Element realRoot = null;
for (int i=0; i<children.getLength(); i++) {
if (children.item(i) instanceof Element) {
realRoot = (Element) children.item(i);
break;
}
}
translateInformation(realRoot);
translateScaling(realRoot);
translateDisplaySettings(realRoot);
translateLayers(realRoot);
translateExperiment(realRoot);
Stack<String> nameStack = new Stack<String>();
HashMap<String, Integer> indexes = new HashMap<String, Integer>();
populateOriginalMetadata(realRoot, nameStack, indexes);
}
private void translateInformation(Element root) throws FormatException {
NodeList informations = root.getElementsByTagName("Information");
if (informations.getLength() == 0) {
return;
}
Element information = (Element) informations.item(0);
Element image = getFirstNode(information, "Image");
Element user = getFirstNode(information, "User");
Element environment = getFirstNode(information, "Environment");
Element instrument = getFirstNode(information, "Instrument");
if (image != null) {
String bitCount = getFirstNodeValue(image, "ComponentBitCount");
if (bitCount != null) {
core[0].bitsPerPixel = Integer.parseInt(bitCount);
}
acquiredDate = getFirstNodeValue(image, "AcquisitionDateAndTime");
Element objectiveSettings = getFirstNode(image, "ObjectiveSettings");
correctionCollar =
getFirstNodeValue(objectiveSettings, "CorrectionCollar");
medium = getFirstNodeValue(objectiveSettings, "Medium");
refractiveIndex = getFirstNodeValue(objectiveSettings, "RefractiveIndex");
Element dimensions = getFirstNode(image, "Dimensions");
NodeList channels = getGrandchildren(dimensions, "Channel");
if (channels != null) {
for (int i=0; i<channels.getLength(); i++) {
Element channel = (Element) channels.item(i);
emissionWavelengths.add(
getFirstNodeValue(channel, "EmissionWavelength"));
excitationWavelengths.add(
getFirstNodeValue(channel, "ExcitationWavelength"));
pinholeSizes.add(getFirstNodeValue(channel, "PinholeSize"));
channelNames.add(channel.getAttribute("Name"));
Element detectorSettings = getFirstNode(channel, "DetectorSettings");
binnings.add(getFirstNodeValue(detectorSettings, "Binning"));
Element detector = getFirstNode(detectorSettings, "Detector");
if (detector != null) {
detectorRefs.add(detector.getAttribute("Id"));
}
}
}
}
if (user != null) {
userDisplayName = getFirstNodeValue(user, "DisplayName");
userFirstName = getFirstNodeValue(user, "FirstName");
userLastName = getFirstNodeValue(user, "LastName");
userMiddleName = getFirstNodeValue(user, "MiddleName");
userEmail = getFirstNodeValue(user, "Email");
userInstitution = getFirstNodeValue(user, "Institution");
userName = getFirstNodeValue(user, "UserName");
}
if (environment != null) {
temperature = getFirstNodeValue(environment, "Temperature");
airPressure = getFirstNodeValue(environment, "AirPressure");
humidity = getFirstNodeValue(environment, "Humidity");
co2Percent = getFirstNodeValue(environment, "CO2Percent");
}
if (instrument != null) {
NodeList microscopes = getGrandchildren(instrument, "Microscope");
Element manufacturerNode = null;
store.setInstrumentID(MetadataTools.createLSID("Instrument", 0), 0);
if (microscopes != null) {
Element microscope = (Element) microscopes.item(0);
manufacturerNode = getFirstNode(microscope, "Manufacturer");
store.setMicroscopeManufacturer(
getFirstNodeValue(manufacturerNode, "Manufacturer"), 0);
store.setMicroscopeModel(
getFirstNodeValue(manufacturerNode, "Model"), 0);
store.setMicroscopeSerialNumber(
getFirstNodeValue(manufacturerNode, "SerialNumber"), 0);
store.setMicroscopeLotNumber(
getFirstNodeValue(manufacturerNode, "LotNumber"), 0);
store.setMicroscopeType(
getMicroscopeType(getFirstNodeValue(microscope, "Type")), 0);
}
NodeList lightSources = getGrandchildren(instrument, "LightSource");
if (lightSources != null) {
for (int i=0; i<lightSources.getLength(); i++) {
Element lightSource = (Element) lightSources.item(i);
manufacturerNode = getFirstNode(lightSource, "Manufacturer");
String manufacturer =
getFirstNodeValue(manufacturerNode, "Manufacturer");
String model = getFirstNodeValue(manufacturerNode, "Model");
String serialNumber =
getFirstNodeValue(manufacturerNode, "SerialNumber");
String lotNumber = getFirstNodeValue(manufacturerNode, "LotNumber");
String type = getFirstNodeValue(lightSource, "LightSourceType");
String power = getFirstNodeValue(lightSource, "Power");
if ("Laser".equals(type)) {
store.setLaserPower(new Double(power), 0, i);
store.setLaserLotNumber(lotNumber, 0, i);
store.setLaserManufacturer(manufacturer, 0, i);
store.setLaserModel(model, 0, i);
store.setLaserSerialNumber(serialNumber, 0, i);
}
else if ("Arc".equals(type)) {
store.setArcPower(new Double(power), 0, i);
store.setArcLotNumber(lotNumber, 0, i);
store.setArcManufacturer(manufacturer, 0, i);
store.setArcModel(model, 0, i);
store.setArcSerialNumber(serialNumber, 0, i);
}
else if ("LightEmittingDiode".equals(type)) {
store.setLightEmittingDiodePower(new Double(power), 0, i);
store.setLightEmittingDiodeLotNumber(lotNumber, 0, i);
store.setLightEmittingDiodeManufacturer(manufacturer, 0, i);
store.setLightEmittingDiodeModel(model, 0, i);
store.setLightEmittingDiodeSerialNumber(serialNumber, 0, i);
}
else if ("Filament".equals(type)) {
store.setFilamentPower(new Double(power), 0, i);
store.setFilamentLotNumber(lotNumber, 0, i);
store.setFilamentManufacturer(manufacturer, 0, i);
store.setFilamentModel(model, 0, i);
store.setFilamentSerialNumber(serialNumber, 0, i);
}
}
}
NodeList detectors = getGrandchildren(instrument, "Detector");
if (detectors != null) {
for (int i=0; i<detectors.getLength(); i++) {
Element detector = (Element) detectors.item(i);
manufacturerNode = getFirstNode(detector, "Manufacturer");
String manufacturer =
getFirstNodeValue(manufacturerNode, "Manufacturer");
String model = getFirstNodeValue(manufacturerNode, "Model");
String serialNumber =
getFirstNodeValue(manufacturerNode, "SerialNumber");
String lotNumber = getFirstNodeValue(manufacturerNode, "LotNumber");
store.setDetectorID(detector.getAttribute("Id"), 0, i);
store.setDetectorManufacturer(manufacturer, 0, i);
store.setDetectorModel(model, 0, i);
store.setDetectorSerialNumber(serialNumber, 0, i);
store.setDetectorLotNumber(lotNumber, 0, i);
String gain = getFirstNodeValue(detector, "Gain");
if (gain != null) {
store.setDetectorGain(new Double(gain), 0, i);
}
String voltage = getFirstNodeValue(detector, "Voltage");
if (voltage != null) {
store.setDetectorVoltage(new Double(voltage), 0, i);
}
String offset = getFirstNodeValue(detector, "Offset");
if (offset != null) {
store.setDetectorOffset(new Double(offset), 0, i);
}
String zoom = getFirstNodeValue(detector, "Zoom");
if (zoom != null) {
store.setDetectorZoom(new Double(zoom), 0, i);
}
String ampGain = getFirstNodeValue(detector, "AmplificationGain");
if (ampGain != null) {
store.setDetectorAmplificationGain(new Double(ampGain), 0, i);
}
store.setDetectorType(
getDetectorType(getFirstNodeValue(detector, "Type")), 0, i);
}
}
NodeList objectives = getGrandchildren(instrument, "Objective");
if (objectives != null) {
for (int i=0; i<objectives.getLength(); i++) {
Element objective = (Element) objectives.item(i);
manufacturerNode = getFirstNode(objective, "Manufacturer");
String manufacturer =
getFirstNodeValue(manufacturerNode, "Manufacturer");
String model = getFirstNodeValue(manufacturerNode, "Model");
String serialNumber =
getFirstNodeValue(manufacturerNode, "SerialNumber");
String lotNumber = getFirstNodeValue(manufacturerNode, "LotNumber");
objectiveIDs.add(objective.getAttribute("Id"));
store.setObjectiveID(objective.getAttribute("Id"), 0, i);
store.setObjectiveManufacturer(manufacturer, 0, i);
store.setObjectiveModel(model, 0, i);
store.setObjectiveSerialNumber(serialNumber, 0, i);
store.setObjectiveLotNumber(lotNumber, 0, i);
store.setObjectiveCorrection(
getCorrection(getFirstNodeValue(objective, "Correction")), 0, i);
store.setObjectiveImmersion(
getImmersion(getFirstNodeValue(objective, "Immersion")), 0, i);
store.setObjectiveLensNA(
new Double(getFirstNodeValue(objective, "LensNA")), 0, i);
store.setObjectiveNominalMagnification(PositiveInteger.valueOf(
getFirstNodeValue(objective, "NominalMagnification")), 0, i);
String calibratedMag =
getFirstNodeValue(objective, "CalibratedMagnification");
if (calibratedMag != null) {
store.setObjectiveCalibratedMagnification(
new Double(calibratedMag), 0, i);
}
String wd = getFirstNodeValue(objective, "WorkingDistance");
if (wd != null) {
store.setObjectiveWorkingDistance(new Double(wd), 0, i);
}
String iris = getFirstNodeValue(objective, "Iris");
if (iris != null) {
store.setObjectiveIris(new Boolean(iris), 0, i);
}
}
}
NodeList filterSets = getGrandchildren(instrument, "FilterSet");
if (filterSets != null) {
for (int i=0; i<filterSets.getLength(); i++) {
Element filterSet = (Element) filterSets.item(i);
manufacturerNode = getFirstNode(filterSet, "Manufacturer");
String manufacturer =
getFirstNodeValue(manufacturerNode, "Manufacturer");
String model = getFirstNodeValue(manufacturerNode, "Model");
String serialNumber =
getFirstNodeValue(manufacturerNode, "SerialNumber");
String lotNumber = getFirstNodeValue(manufacturerNode, "LotNumber");
store.setFilterSetID(filterSet.getAttribute("Id"), 0, i);
store.setFilterSetManufacturer(manufacturer, 0, i);
store.setFilterSetModel(model, 0, i);
store.setFilterSetSerialNumber(serialNumber, 0, i);
store.setFilterSetLotNumber(lotNumber, 0, i);
store.setFilterSetDichroicRef(
getFirstNodeValue(filterSet, "DichroicRef"), 0, i);
NodeList excitations = getGrandchildren(
filterSet, "ExcitationFilters", "ExcitationFilterRef");
NodeList emissions = getGrandchildren(filterSet, "EmissionFilters",
"EmissionFilterRef");
for (int ex=0; ex<excitations.getLength(); ex++) {
store.setFilterSetExcitationFilterRef(
excitations.item(ex).getTextContent(), 0, i, ex);
}
for (int em=0; em<emissions.getLength(); em++) {
store.setFilterSetEmissionFilterRef(
emissions.item(em).getTextContent(), 0, i, em);
}
}
}
NodeList filters = getGrandchildren(instrument, "Filter");
if (filters != null) {
for (int i=0; i<filters.getLength(); i++) {
Element filter = (Element) filters.item(i);
manufacturerNode = getFirstNode(filter, "Manufacturer");
String manufacturer =
getFirstNodeValue(manufacturerNode, "Manufacturer");
String model = getFirstNodeValue(manufacturerNode, "Model");
String serialNumber =
getFirstNodeValue(manufacturerNode, "SerialNumber");
String lotNumber = getFirstNodeValue(manufacturerNode, "LotNumber");
store.setFilterID(filter.getAttribute("Id"), 0, i);
store.setFilterManufacturer(manufacturer, 0, i);
store.setFilterModel(model, 0, i);
store.setFilterSerialNumber(serialNumber, 0, i);
store.setFilterLotNumber(lotNumber, 0, i);
store.setFilterType(
getFilterType(getFirstNodeValue(filter, "Type")), 0, i);
store.setFilterFilterWheel(
getFirstNodeValue(filter, "FilterWheel"), 0, i);
Element transmittance = getFirstNode(filter, "TransmittanceRange");
store.setTransmittanceRangeCutIn(PositiveInteger.valueOf(
getFirstNodeValue(transmittance, "CutIn")), 0, i);
store.setTransmittanceRangeCutOut(PositiveInteger.valueOf(
getFirstNodeValue(transmittance, "CutOut")), 0, i);
store.setTransmittanceRangeCutInTolerance(NonNegativeInteger.valueOf(
getFirstNodeValue(transmittance, "CutInTolerance")), 0, i);
store.setTransmittanceRangeCutOutTolerance(NonNegativeInteger.valueOf(
getFirstNodeValue(transmittance, "CutOutTolerance")), 0, i);
store.setTransmittanceRangeTransmittance(PercentFraction.valueOf(
getFirstNodeValue(transmittance, "Transmittance")), 0, i);
}
}
NodeList dichroics = getGrandchildren(instrument, "Dichroic");
if (dichroics != null) {
for (int i=0; i<dichroics.getLength(); i++) {
Element dichroic = (Element) dichroics.item(i);
manufacturerNode = getFirstNode(dichroic, "Manufacturer");
String manufacturer =
getFirstNodeValue(manufacturerNode, "Manufacturer");
String model = getFirstNodeValue(manufacturerNode, "Model");
String serialNumber =
getFirstNodeValue(manufacturerNode, "SerialNumber");
String lotNumber = getFirstNodeValue(manufacturerNode, "LotNumber");
store.setDichroicID(dichroic.getAttribute("Id"), 0, i);
store.setDichroicManufacturer(manufacturer, 0, i);
store.setDichroicModel(model, 0, i);
store.setDichroicSerialNumber(serialNumber, 0, i);
store.setDichroicLotNumber(lotNumber, 0, i);
}
}
}
}
private void translateScaling(Element root) {
NodeList scalings = root.getElementsByTagName("Scaling");
if (scalings.getLength() == 0) {
return;
}
Element scaling = (Element) scalings.item(0);
NodeList distances = getGrandchildren(scaling, "Items", "Distance");
for (int i=0; i<distances.getLength(); i++) {
Element distance = (Element) distances.item(i);
String id = distance.getAttribute("Id");
Double value = new Double(getFirstNodeValue(distance, "Value")) * 1000000;
if (value > 0) {
PositiveFloat size = new PositiveFloat(value);
if (id.equals("X")) {
for (int series=0; series<getSeriesCount(); series++) {
store.setPixelsPhysicalSizeX(size, series);
}
}
else if (id.equals("Y")) {
for (int series=0; series<getSeriesCount(); series++) {
store.setPixelsPhysicalSizeY(size, series);
}
}
else if (id.equals("Z")) {
for (int series=0; series<getSeriesCount(); series++) {
store.setPixelsPhysicalSizeZ(size, series);
}
}
}
}
}
private void translateDisplaySettings(Element root) {
NodeList displaySettings = root.getElementsByTagName("DisplaySetting");
if (displaySettings.getLength() == 0) {
return;
}
Element displaySetting = (Element) displaySettings.item(0);
NodeList channels = getGrandchildren(displaySetting, "Channel");
for (int i=0; i<channels.getLength(); i++) {
Element channel = (Element) channels.item(i);
channelColors.add(getFirstNodeValue(channel, "Color"));
}
}
private void translateLayers(Element root) {
NodeList layerses = root.getElementsByTagName("Layers");
if (layerses.getLength() == 0) {
return;
}
Element layersNode = (Element) layerses.item(0);
NodeList layers = layersNode.getElementsByTagName("Layer");
for (int i=0; i<layers.getLength(); i++) {
Element layer = (Element) layers.item(i);
String roiID = MetadataTools.createLSID("ROI", i);
store.setROIID(roiID, i);
store.setROIName(layer.getAttribute("Name"), i);
store.setROIDescription(getFirstNodeValue(layer, "Usage"), i);
for (int series=0; series<getSeriesCount(); series++) {
store.setImageROIRef(roiID, series, i);
}
int shape = 0;
NodeList lines = getGrandchildren(layer, "Elements", "Line");
for (int s=0; s<lines.getLength(); s++, shape++) {
Element line = (Element) lines.item(s);
Element geometry = getFirstNode(line, "Geometry");
Element textElements = getFirstNode(line, "TextElements");
Element attributes = getFirstNode(line, "Attributes");
store.setLineX1(
new Double(getFirstNodeValue(geometry, "X1")), i, shape);
store.setLineX2(
new Double(getFirstNodeValue(geometry, "X2")), i, shape);
store.setLineY1(
new Double(getFirstNodeValue(geometry, "Y1")), i, shape);
store.setLineY2(
new Double(getFirstNodeValue(geometry, "Y2")), i, shape);
store.setLineName(getFirstNodeValue(attributes, "Name"), i, shape);
store.setLineLabel(getFirstNodeValue(textElements, "Text"), i, shape);
}
NodeList rectangles = getGrandchildren(layer, "Elements", "Rectangle");
shape = populateRectangles(rectangles, i, shape);
NodeList ellipses = getGrandchildren(layer, "Elements", "Ellipse");
for (int s=0; s<ellipses.getLength(); s++, shape++) {
Element ellipse = (Element) ellipses.item(s);
Element geometry = getFirstNode(ellipse, "Geometry");
Element textElements = getFirstNode(ellipse, "TextElements");
Element attributes = getFirstNode(ellipse, "Attributes");
store.setEllipseID(
MetadataTools.createLSID("Shape", i, shape), i, shape);
store.setEllipseRadiusX(
new Double(getFirstNodeValue(geometry, "RadiusX")), i, shape);
store.setEllipseRadiusY(
new Double(getFirstNodeValue(geometry, "RadiusY")), i, shape);
store.setEllipseX(
new Double(getFirstNodeValue(geometry, "CenterX")), i, shape);
store.setEllipseY(
new Double(getFirstNodeValue(geometry, "CenterY")), i, shape);
store.setEllipseName(getFirstNodeValue(attributes, "Name"), i, shape);
store.setEllipseLabel(
getFirstNodeValue(textElements, "Text"), i, shape);
}
// translate all of the circle ROIs
NodeList circles = getGrandchildren(layer, "Elements", "Circle");
shape = populateCircles(circles, i, shape);
NodeList inOutCircles =
getGrandchildren(layer, "Elements", "InOutCircle");
shape = populateCircles(inOutCircles, i, shape);
NodeList outInCircles =
getGrandchildren(layer, "Elements", "OutInCircle");
shape = populateCircles(outInCircles, i, shape);
NodeList pointsCircles =
getGrandchildren(layer, "Elements", "PointsCircle");
shape = populateCircles(pointsCircles, i, shape);
NodeList polygons = getGrandchildren(layer, "Elements", "Polygon");
shape = populatePolylines(polygons, i, shape, true);
NodeList polylines = getGrandchildren(layer, "Elements", "Polyline");
shape = populatePolylines(polylines, i, shape, false);
NodeList openPolylines =
getGrandchildren(layer, "Elements", "OpenPolyline");
shape = populatePolylines(polylines, i, shape, false);
NodeList closedPolylines =
getGrandchildren(layer, "Elements", "ClosedPolyline");
shape = populatePolylines(polygons, i, shape, true);
NodeList rectRoi = getGrandchildren(layer, "Elements", "RectRoi");
shape = populateRectangles(rectRoi, i, shape);
NodeList textBoxes = getGrandchildren(layer, "Elements", "TextBox");
shape = populateRectangles(textBoxes, i, shape);
NodeList text = getGrandchildren(layer, "Elements", "Text");
shape = populateRectangles(text, i, shape);
}
}
private int populateRectangles(NodeList rectangles, int roi, int shape) {
for (int s=0; s<rectangles.getLength(); s++, shape++) {
Element rectangle = (Element) rectangles.item(s);
Element geometry = getFirstNode(rectangle, "Geometry");
Element textElements = getFirstNode(rectangle, "TextElements");
Element attributes = getFirstNode(rectangle, "Attributes");
String left = getFirstNodeValue(geometry, "Left");
String top = getFirstNodeValue(geometry, "Top");
String width = getFirstNodeValue(geometry, "Width");
String height = getFirstNodeValue(geometry, "Height");
if (left != null && top != null && width != null && height != null) {
store.setRectangleID(
MetadataTools.createLSID("Shape", roi, shape), roi, shape);
store.setRectangleX(new Double(left), roi, shape);
store.setRectangleY(
new Double(getSizeY() - Double.parseDouble(top)), roi, shape);
store.setRectangleWidth(new Double(width), roi, shape);
store.setRectangleHeight(new Double(height), roi, shape);
String name = getFirstNodeValue(attributes, "Name");
String label = getFirstNodeValue(textElements, "Text");
if (name != null) {
store.setRectangleName(name, roi, shape);
}
if (label != null) {
store.setRectangleLabel(label, roi, shape);
}
}
}
return shape;
}
private int populatePolylines(NodeList polylines, int roi, int shape,
boolean closed)
{
for (int s=0; s<polylines.getLength(); s++, shape++) {
Element polyline = (Element) polylines.item(s);
Element geometry = getFirstNode(polyline, "Geometry");
Element textElements = getFirstNode(polyline, "TextElements");
Element attributes = getFirstNode(polyline, "Attributes");
store.setPolylineID(
MetadataTools.createLSID("Shape", roi, shape), roi, shape);
store.setPolylinePoints(
getFirstNodeValue(geometry, "Points"), roi, shape);
store.setPolylineClosed(closed, roi, shape);
store.setPolylineName(getFirstNodeValue(attributes, "Name"), roi, shape);
store.setPolylineLabel(
getFirstNodeValue(textElements, "Text"), roi, shape);
}
return shape;
}
private int populateCircles(NodeList circles, int roi, int shape) {
for (int s=0; s<circles.getLength(); s++, shape++) {
Element circle = (Element) circles.item(s);
Element geometry = getFirstNode(circle, "Geometry");
Element textElements = getFirstNode(circle, "TextElements");
Element attributes = getFirstNode(circle, "Attributes");
store.setEllipseID(
MetadataTools.createLSID("Shape", roi, shape), roi, shape);
store.setEllipseRadiusX(
new Double(getFirstNodeValue(geometry, "Radius")), roi, shape);
store.setEllipseRadiusY(
new Double(getFirstNodeValue(geometry, "Radius")), roi, shape);
store.setEllipseX(
new Double(getFirstNodeValue(geometry, "CenterX")), roi, shape);
store.setEllipseY(
new Double(getFirstNodeValue(geometry, "CenterY")), roi, shape);
store.setEllipseName(getFirstNodeValue(attributes, "Name"), roi, shape);
store.setEllipseLabel(
getFirstNodeValue(textElements, "Text"), roi, shape);
}
return shape;
}
private void translateExperiment(Element root) {
NodeList experiments = root.getElementsByTagName("Experiment");
if (experiments.getLength() == 0) {
return;
}
Element experimentBlock =
getFirstNode((Element) experiments.item(0), "ExperimentBlocks");
Element acquisition = getFirstNode(experimentBlock, "AcquisitionBlock");
Element tilesSetup = getFirstNode(acquisition, "TilesSetup");
NodeList groups = getGrandchildren(tilesSetup, "PositionGroup");
positionsX = new Double[core.length];
positionsY = new Double[core.length];
positionsZ = new Double[core.length];
for (int i=0; i<groups.getLength(); i++) {
Element group = (Element) groups.item(i);
int tilesX = Integer.parseInt(getFirstNodeValue(group, "TilesX"));
int tilesY = Integer.parseInt(getFirstNodeValue(group, "TilesY"));
Element position = getFirstNode(group, "Position");
Double xPos = new Double(position.getAttribute("X"));
Double yPos = new Double(position.getAttribute("Y"));
Double zPos = new Double(position.getAttribute("Z"));
Double overlap =
new Double(getFirstNodeValue(group, "TileAcquisitionOverlap"));
for (int tile=0; tile<tilesX * tilesY; tile++) {
int index = i * tilesX * tilesY + tile;
positionsX[index] = xPos;
positionsY[index] = yPos;
positionsZ[index] = zPos;
}
}
}
private Element getFirstNode(Element root, String name) {
if (root == null) {
return null;
}
NodeList list = root.getElementsByTagName(name);
if (list == null) {
return null;
}
return (Element) list.item(0);
}
private NodeList getGrandchildren(Element root, String name) {
return getGrandchildren(root, name + "s", name);
}
private NodeList getGrandchildren(Element root, String child, String name) {
if (root == null) {
return null;
}
NodeList children = root.getElementsByTagName(child);
if (children.getLength() > 0) {
Element childNode = (Element) children.item(0);
return childNode.getElementsByTagName(name);
}
return null;
}
private String getFirstNodeValue(Element root, String name) {
if (root == null) {
return null;
}
NodeList nodes = root.getElementsByTagName(name);
if (nodes.getLength() > 0) {
return nodes.item(0).getTextContent();
}
return null;
}
private void populateOriginalMetadata(Element root, Stack<String> nameStack,
HashMap<String, Integer> indexes)
{
String name = root.getNodeName();
nameStack.push(name);
if (root.getChildNodes().getLength() == 1) {
String value = root.getTextContent();
StringBuffer key = new StringBuffer();
for (String k : nameStack) {
key.append(k);
key.append(" ");
}
if (value != null && key.length() > 0) {
Integer i = indexes.get(key.toString());
String storedKey = key.toString() + (i == null ? 0 : i);
indexes.put(key.toString(), i == null ? 1 : i + 1);
addGlobalMeta(storedKey, value);
}
}
NodeList children = root.getChildNodes();
for (int i=0; i<children.getLength(); i++) {
Object child = children.item(i);
if (child instanceof Element) {
populateOriginalMetadata((Element) child, nameStack, indexes);
}
}
nameStack.pop();
}
private Segment readSegment() throws IOException {
// align the stream to a multiple of 32 bytes
int skip =
(ALIGNMENT - (int) (in.getFilePointer() % ALIGNMENT)) % ALIGNMENT;
in.skipBytes(skip);
long startingPosition = in.getFilePointer();
// instantiate a Segment subclass based upon the segment ID
String segmentID = in.readString(16).trim();
Segment segment = null;
if (segmentID.equals("ZISRAWFILE")) {
segment = new FileHeader();
}
else if (segmentID.equals("ZISRAWMETADATA")) {
segment = new Metadata();
}
else if (segmentID.equals("ZISRAWSUBBLOCK")) {
segment = new SubBlock();
}
else if (segmentID.equals("ZISRAWATTACH")) {
segment = new Attachment();
}
else {
LOGGER.info("Unknown segment type: " + segmentID);
segment = new Segment();
}
segment.startingPosition = startingPosition;
segment.id = segmentID;
segment.fillInData();
in.seek(segment.startingPosition + segment.allocatedSize + HEADER_SIZE);
return segment;
}
private void convertPixelType(int pixelType) throws FormatException {
switch (pixelType) {
case GRAY8:
core[0].pixelType = FormatTools.UINT8;
break;
case GRAY16:
core[0].pixelType = FormatTools.UINT16;
break;
case GRAY32:
core[0].pixelType = FormatTools.UINT32;
break;
case GRAY_FLOAT:
core[0].pixelType = FormatTools.FLOAT;
break;
case GRAY_DOUBLE:
core[0].pixelType = FormatTools.DOUBLE;
break;
case BGR_24:
core[0].pixelType = FormatTools.UINT8;
core[0].sizeC *= 3;
core[0].rgb = true;
break;
case BGR_48:
core[0].pixelType = FormatTools.UINT16;
core[0].sizeC *= 3;
core[0].rgb = true;
break;
case BGRA_8:
core[0].pixelType = FormatTools.UINT8;
core[0].sizeC *= 4;
core[0].rgb = true;
break;
case BGR_FLOAT:
core[0].pixelType = FormatTools.FLOAT;
core[0].sizeC *= 3;
core[0].rgb = true;
break;
case COMPLEX:
case COMPLEX_FLOAT:
throw new FormatException("Sorry, complex pixel data not supported.");
default:
throw new FormatException("Unknown pixel type: " + pixelType);
}
}
// -- Helper classes --
/** Top-level class that implements logic common to all types of Segment. */
class Segment {
public long startingPosition;
public String id;
public long allocatedSize;
public long usedSize;
public void fillInData() throws IOException {
// read the segment header
allocatedSize = in.readLong();
usedSize = in.readLong();
if (usedSize == 0) {
usedSize = allocatedSize;
}
}
}
/** Segment with ID "ZISRAWFILE". */
class FileHeader extends Segment {
public int majorVersion;
public int minorVersion;
public long primaryFileGUID;
public long fileGUID;
public int filePart;
public long directoryPosition;
public long metadataPosition;
public boolean updatePending;
public long attachmentDirectoryPosition;
public void fillInData() throws IOException {
super.fillInData();
majorVersion = in.readInt();
minorVersion = in.readInt();
in.skipBytes(4); // reserved 1
in.skipBytes(4); // reserved 2
primaryFileGUID = in.readLong();
fileGUID = in.readLong();
filePart = in.readInt();
directoryPosition = in.readLong();
metadataPosition = in.readLong();
updatePending = in.readInt() != 0;
attachmentDirectoryPosition = in.readLong();
}
}
/** Segment with ID "ZISRAWMETADATA". */
class Metadata extends Segment {
public String xml;
public byte[] attachment;
public void fillInData() throws IOException {
super.fillInData();
int xmlSize = in.readInt();
int attachmentSize = in.readInt();
in.skipBytes(248);
xml = in.readString(xmlSize);
attachment = new byte[attachmentSize];
in.read(attachment);
}
}
/** Segment with ID "ZISRAWSUBBLOCK". */
class SubBlock extends Segment {
public int metadataSize;
public int attachmentSize;
public long dataSize;
public DirectoryEntry directoryEntry;
public String metadata;
public int seriesIndex;
public int planeIndex;
private long dataOffset;
private Double stageX, stageY, timestamp, exposureTime;
public void fillInData() throws IOException {
super.fillInData();
long fp = in.getFilePointer();
metadataSize = in.readInt();
attachmentSize = in.readInt();
dataSize = in.readLong();
directoryEntry = new DirectoryEntry();
in.skipBytes((int) Math.max(256 - (in.getFilePointer() - fp), 0));
metadata = in.readString(metadataSize).trim();
dataOffset = in.getFilePointer();
in.seek(in.getFilePointer() + dataSize + attachmentSize);
parseMetadata();
}
// -- SubBlock API methods --
public byte[] readPixelData() throws FormatException, IOException {
in.seek(dataOffset);
byte[] data = new byte[(int) dataSize];
in.read(data);
CodecOptions options = new CodecOptions();
options.interleaved = isInterleaved();
options.littleEndian = isLittleEndian();
options.maxBytes = getSizeX() * getSizeY() * getRGBChannelCount() *
FormatTools.getBytesPerPixel(getPixelType());
switch (directoryEntry.compression) {
case JPEG:
data = new JPEGCodec().decompress(data, options);
break;
case LZW:
data = new LZWCodec().decompress(data, options);
break;
}
return data;
}
// -- Helper methods --
private void parseMetadata() throws IOException {
if (metadata.length() == 0) {
return;
}
Element root = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
ByteArrayInputStream s = new ByteArrayInputStream(metadata.getBytes());
root = parser.parse(s).getDocumentElement();
s.close();
}
catch (ParserConfigurationException e) {
return;
}
catch (SAXException e) {
return;
}
if (root == null) {
return;
}
NodeList children = root.getChildNodes();
for (int i=0; i<children.getLength(); i++) {
if (!(children.item(i) instanceof Element)) {
continue;
}
Element child = (Element) children.item(i);
if (child.getNodeName().equals("Tags")) {
NodeList tags = child.getChildNodes();
for (int tag=0; tag<tags.getLength(); tag++) {
if (!(tags.item(tag) instanceof Element)) {
continue;
}
Element tagNode = (Element) tags.item(tag);
if (tagNode.getNodeName().equals("StageXPosition")) {
stageX = new Double(tagNode.getTextContent());
}
else if (tagNode.getNodeName().equals("StageYPosition")) {
stageY = new Double(tagNode.getTextContent());
}
else if (tagNode.getNodeName().equals("AcquisitionTime")) {
timestamp = DateTools.getTime(
tagNode.getTextContent(), DateTools.ISO8601_FORMAT) / 1000d;
}
else if (tagNode.getNodeName().equals("ExposureTime")) {
exposureTime = new Double(tagNode.getTextContent());
}
}
}
}
}
}
/** Segment with ID "ZISRAWATTACH". */
class Attachment extends Segment {
public int dataSize;
public AttachmentEntry attachment;
public byte[] attachmentData;
public void fillInData() throws IOException {
super.fillInData();
dataSize = in.readInt();
in.skipBytes(12); // reserved
attachment = new AttachmentEntry();
in.skipBytes(112); // reserved
attachmentData = new byte[dataSize];
in.read(attachmentData);
}
}
class DirectoryEntry {
public String schemaType;
public int pixelType;
public long filePosition;
public int filePart;
public int compression;
public byte pyramidType;
public int dimensionCount;
public DimensionEntry[] dimensionEntries;
public DirectoryEntry() throws IOException {
schemaType = in.readString(2);
pixelType = in.readInt();
filePosition = in.readLong();
filePart = in.readInt();
compression = in.readInt();
pyramidType = in.readByte();
in.skipBytes(1); // reserved
in.skipBytes(4); // reserved
dimensionCount = in.readInt();
dimensionEntries = new DimensionEntry[dimensionCount];
for (int i=0; i<dimensionEntries.length; i++) {
dimensionEntries[i] = new DimensionEntry();
}
}
}
class DimensionEntry {
public String dimension;
public int start;
public int size;
public float startCoordinate;
public int storedSize;
public DimensionEntry() throws IOException {
dimension = in.readString(4).trim();
start = in.readInt();
size = in.readInt();
startCoordinate = in.readFloat();
storedSize = in.readInt();
}
}
class AttachmentEntry {
public String schemaType;
public long filePosition;
public int filePart;
public String contentGUID;
public String contentFileType;
public String name;
public AttachmentEntry() throws IOException {
schemaType = in.readString(2);
in.skipBytes(10); // reserved
filePosition = in.readLong();
filePart = in.readInt();
contentGUID = in.readString(16);
contentFileType = in.readString(8);
name = in.readString(80);
}
}
}