/*
* #%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%
*/
package loci.formats.in;
import java.io.IOException;
import java.util.ArrayList;
import loci.common.DataTools;
import loci.common.RandomAccessInputStream;
import loci.common.xml.BaseHandler;
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.meta.MetadataStore;
import ome.xml.model.primitives.PositiveFloat;
import ome.xml.model.primitives.Timestamp;
import org.xml.sax.Attributes;
import ome.units.quantity.Time;
import ome.units.UNITS;
/**
* BioRadSCNReader is the reader for Bio-Rad .scn files
*/
public class BioRadSCNReader extends FormatReader {
// -- Constants --
private static final String MAGIC = "Generated by Image Lab";
// -- Fields --
private long pixelsOffset;
private Double gain;
private Double exposureTime;
private String imageName;
private String serialNumber;
private String acquisitionDate;
private String binning;
private String model;
private Double physicalSizeX, physicalSizeY;
// -- Constructor --
/** Constructs a new Bio-Rad .scn reader. */
public BioRadSCNReader() {
super("Bio-Rad SCN", "scn");
domains = new String[] {FormatTools.GEL_DOMAIN};
suffixSufficient = false;
}
// -- IFormatReader API methods --
/* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */
@Override
public boolean isThisType(RandomAccessInputStream stream) throws IOException {
final int blockLen = 64;
if (!FormatTools.validStream(stream, blockLen, false)) return false;
String check = stream.readString(blockLen);
return check.indexOf(MAGIC) >= 0;
}
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
@Override
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);
in.seek(pixelsOffset);
readPlane(in, x, y, w, h, buf);
return buf;
}
/* @see loci.formats.IFormatReader#close(boolean) */
@Override
public void close(boolean fileOnly) throws IOException {
super.close(fileOnly);
pixelsOffset = 0;
gain = null;
exposureTime = null;
imageName = null;
serialNumber = null;
acquisitionDate = null;
binning = null;
model = null;
physicalSizeX = null;
physicalSizeY = null;
}
// -- Internal FormatReader API methods --
/* @see loci.formats.FormatReader#initFile(String) */
@Override
protected void initFile(String id) throws FormatException, IOException {
super.initFile(id);
in = new RandomAccessInputStream(id);
CoreMetadata m = core.get(0);
String line = in.readLine();
String currentBoundary = "";
String currentType = "";
int currentLength = 0;
ArrayList<String> xml = new ArrayList<String>();
while (in.getFilePointer() < in.length() && line != null) {
line = line.trim();
if (line.startsWith("Content-Type")) {
currentType = line.substring(line.indexOf(" ") + 1);
int boundary = currentType.indexOf("boundary");
if (boundary > 0) {
currentBoundary =
currentType.substring(boundary + 10, currentType.length() - 1);
}
if (currentType.indexOf(";") > 0) {
currentType = currentType.substring(0, currentType.indexOf(";"));
}
}
else if (line.equals("--" + currentBoundary)) {
currentLength = 0;
}
else if (line.startsWith("Content-Length")) {
currentLength = Integer.parseInt(line.substring(line.indexOf(" ") + 1));
}
else if (line.length() == 0) {
if (currentType.equals("application/octet-stream")) {
pixelsOffset = in.getFilePointer();
in.skipBytes(currentLength);
}
else if (currentType.equals("text/xml")) {
String xmlBlock = in.readString(currentLength);
xml.add(xmlBlock);
}
}
line = in.readLine();
}
SCNHandler handler = new SCNHandler();
for (String block : xml) {
XMLTools.parseXML(block, handler);
}
m.sizeZ = 1;
m.sizeT = 1;
m.imageCount = 1;
m.dimensionOrder = "XYCZT";
MetadataStore store = makeFilterMetadata();
MetadataTools.populatePixels(store, this, exposureTime != null);
store.setInstrumentID(MetadataTools.createLSID("Instrument", 0), 0);
if (serialNumber != null) {
store.setMicroscopeSerialNumber(serialNumber, 0);
}
if (model != null) {
store.setMicroscopeModel(model, 0);
}
if (imageName != null) {
store.setImageName(imageName, 0);
}
if (acquisitionDate != null) {
store.setImageAcquisitionDate(new Timestamp(acquisitionDate), 0);
}
if (gain != null || binning != null) {
String detector = MetadataTools.createLSID("Detector", 0, 0);
store.setDetectorID(detector, 0, 0);
store.setDetectorSettingsID(detector, 0, 0);
}
if (gain != null) {
store.setDetectorSettingsGain(gain, 0, 0);
}
if (binning != null) {
store.setDetectorSettingsBinning(getBinning(binning), 0, 0);
}
if (exposureTime != null) {
store.setPlaneExposureTime(new Time(exposureTime, UNITS.S), 0, 0);
}
if (physicalSizeX != null) {
store.setPixelsPhysicalSizeX(FormatTools.createLength(physicalSizeX, UNITS.MICROM), 0);
}
if (physicalSizeY != null) {
store.setPixelsPhysicalSizeY(FormatTools.createLength(physicalSizeY, UNITS.MICROM), 0);
}
}
class SCNHandler extends BaseHandler {
// -- Fields --
private String key;
// -- DefaultHandler API methods --
@Override
public void endElement(String uri, String localName, String qName) {
key = null;
}
@Override
public void characters(char[] ch, int start, int length) {
String value = new String(ch, start, length);
addGlobalMeta(key, value);
if ("endian".equals(key)) {
core.get(0).littleEndian = value.equals("little");
}
else if ("channel_count".equals(key)) {
core.get(0).sizeC = Integer.parseInt(value);
}
else if ("application_gain".equals(key)) {
gain = new Double(value);
}
else if ("exposure_time".equals(key)) {
exposureTime = new Double(value);
}
else if ("name".equals(key)) {
imageName = value;
}
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes)
{
key = qName;
for (int i=0; i<attributes.getLength(); i++) {
String attrKey = attributes.getQName(i);
String attrValue = attributes.getValue(i);
addGlobalMeta(key + " " + attrKey, attrValue);
if (key.equals("size_pix")) {
if (attrKey.equals("width")) {
core.get(0).sizeX = Integer.parseInt(attrValue);
}
else if (attrKey.equals("height")) {
core.get(0).sizeY = Integer.parseInt(attrValue);
}
}
else if (key.equals("scanner")) {
if (attrKey.equals("max_value")) {
long value = Long.parseLong(attrValue);
if (value <= 256) {
core.get(0).pixelType = FormatTools.UINT8;
}
else if (value <= 65535) {
core.get(0).pixelType = FormatTools.UINT16;
}
}
}
else if (key.equals("size_mm")) {
if (attrKey.equals("width")) {
physicalSizeX = new Double(attrValue) / getSizeX();
physicalSizeX *= 1000; // convert from mm to um
}
else if (attrKey.equals("height")) {
physicalSizeY = new Double(attrValue) / getSizeY();
physicalSizeY *= 1000; // convert from mm to um
}
}
else if (key.equals("serial_number")) {
if (attrKey.equals("value")) {
serialNumber = attrValue;
}
}
else if (key.equals("binning")) {
if (attrKey.equals("value")) {
binning = attrValue;
}
}
else if (key.equals("image_date")) {
if (attrKey.equals("value")) {
acquisitionDate = attrValue;
}
}
else if (key.equals("imager")) {
if (attrKey.equals("value")) {
model = attrValue;
}
}
}
}
}
}