//
// OIFReader.java
//
/*
LOCI Bio-Formats package for reading and converting biological file formats.
Copyright (C) 2005-@year@ Melissa Linkert, Curtis Rueden, Chris Allan,
Eric Kjellman and Brian Loranger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Library 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 Library General Public License for more details.
You should have received a copy of the GNU Library 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.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import loci.formats.*;
/**
* OIFReader is the file format reader for Fluoview FV 1000 OIF files.
*
* <dl><dt><b>Source code:</b></dt>
* <dd><a href="https://skyking.microscopy.wisc.edu/trac/java/browser/trunk/loci/formats/in/OIFReader.java">Trac</a>,
* <a href="https://skyking.microscopy.wisc.edu/svn/java/trunk/loci/formats/in/OIFReader.java">SVN</a></dd></dl>
*
* @author Melissa Linkert linkert at wisc.edu
*/
public class OIFReader extends FormatReader {
// -- Fields --
/** Names of every TIFF file to open. */
protected Vector tiffs;
/** Helper reader to open TIFF files. */
protected TiffReader[] tiffReader;
/** Helper reader to open the thumbnail. */
protected BMPReader thumbReader;
/** List of files in the current OIF dataset. */
protected Vector usedFiles;
protected String[] size = new String[9], code = new String[9];
protected int imageDepth;
// -- Constructor --
/** Constructs a new OIF reader. */
public OIFReader() {
super("Fluoview FV1000 OIF",
new String[] {"oif", "roi", "pty", "lut", "bmp"});
}
// -- IFormatReader API methods --
/* @see loci.formats.IFormatReader#isThisType(byte[]) */
public boolean isThisType(byte[] block) {
return false;
}
/* @see loci.formats.IFormatReader#fileGroupOption(String) */
public int fileGroupOption(String id) throws FormatException, IOException {
return FormatTools.MUST_GROUP;
}
/* @see loci.formats.IFormatReader#openBytes(int, byte[]) */
public byte[] openBytes(int no, byte[] buf)
throws FormatException, IOException
{
FormatTools.assertId(currentId, true, 1);
FormatTools.checkPlaneNumber(this, no);
tiffReader[no].openBytes(0, buf);
tiffReader[no].close();
return buf;
}
/* @see loci.formats.IFormatReader#openThumbImage(int) */
public BufferedImage openThumbImage(int no)
throws FormatException, IOException
{
FormatTools.assertId(currentId, true, 1);
FormatTools.checkPlaneNumber(this, no);
String dir =
currentId.substring(0, currentId.lastIndexOf(File.separator) + 1);
dir += currentId.substring(currentId.lastIndexOf(File.separator) + 1) +
".files" + File.separator;
String thumbId = dir + currentId.substring(currentId.lastIndexOf(
File.separator) + 1, currentId.lastIndexOf(".")) + "_Thumb.bmp";
thumbReader.setId(thumbId);
return thumbReader.openImage(0);
}
/* @see loci.formats.IFormatReader#getUsedFiles() */
public String[] getUsedFiles() {
FormatTools.assertId(currentId, true, 1);
return (String[]) usedFiles.toArray(new String[0]);
}
/* @see loci.formats.IFormatReader#close(boolean) */
public void close(boolean fileOnly) throws IOException {
if (fileOnly) {
if (in != null) in.close();
if (thumbReader != null) thumbReader.close(fileOnly);
if (tiffReader != null) {
for (int i=0; i<tiffReader.length; i++) {
if (tiffReader[i] != null) tiffReader[i].close(fileOnly);
}
}
}
else close();
}
// -- IFormatHandler API methods --
/* @see loci.formats.IFormatHandler#close() */
public void close() throws IOException {
super.close();
if (thumbReader != null) thumbReader.close();
if (tiffReader != null) {
for (int i=0; i<tiffReader.length; i++) {
if (tiffReader[i] != null) tiffReader[i].close();
}
}
tiffs = null;
}
// -- Internal FormatReader API methods --
/* @see loci.formats.FormatReader#initFile(String) */
protected void initFile(String id) throws FormatException, IOException {
if (debug) debug("OIFReader.initFile(" + id + ")");
// check to make sure that we have the OIF file
// if not, we need to look for it in the parent directory
status("Finding metadata file");
String oifFile = id;
if (!id.toLowerCase().endsWith("oif")) {
Location current = new Location(id);
current = current.getAbsoluteFile();
String parent = current.getParent();
Location tmp = new Location(parent);
parent = tmp.getParent();
// strip off the filename
id = current.getPath();
oifFile = id.substring(id.lastIndexOf(File.separator));
oifFile = parent + oifFile.substring(0, oifFile.indexOf("_")) + ".oif";
tmp = new Location(oifFile);
if (!tmp.exists()) {
oifFile = oifFile.substring(0, oifFile.lastIndexOf(".")) + ".OIF";
tmp = new Location(oifFile);
if (!tmp.exists()) throw new FormatException("OIF file not found");
currentId = oifFile;
}
else currentId = oifFile;
}
super.initFile(oifFile);
in = new RandomAccessStream(oifFile);
usedFiles = new Vector();
usedFiles.add(new Location(oifFile).getAbsolutePath());
int slash = oifFile.lastIndexOf(File.separator);
String path = slash < 0 ? "." : oifFile.substring(0, slash);
// parse each key/value pair (one per line)
status("Parsing metadata values");
byte[] b = new byte[(int) in.length()];
in.read(b);
String s = new String(b);
StringTokenizer st = new StringTokenizer(s, "\r\n");
Hashtable filenames = new Hashtable();
String prefix = "";
while (st.hasMoreTokens()) {
String line = DataTools.stripString(st.nextToken().trim());
if (!line.startsWith("[") && (line.indexOf("=") > 0)) {
String key = line.substring(0, line.indexOf("=")).trim();
String value = line.substring(line.indexOf("=") + 1).trim();
if (key.startsWith("IniFileName") && key.indexOf("Thumb") == -1) {
int pos = Integer.parseInt(key.substring(11));
filenames.put(new Integer(pos), value.trim());
}
addMeta(prefix + key, value);
if (prefix.startsWith("[Axis ") &&
prefix.endsWith("Parameters Common] - "))
{
int ndx =
Integer.parseInt(prefix.substring(6, prefix.indexOf("P")).trim());
if (key.equals("AxisCode")) code[ndx] = value;
else if (key.equals("MaxSize")) size[ndx] = value;
}
else if ((prefix + key).equals("[Axis Parameter Common] - AxisOrder")) {
core.currentOrder[0] = value;
}
else if ((prefix + key).equals(
"[Reference Image Parameter] - ImageDepth"))
{
imageDepth = Integer.parseInt(value);
}
}
else if (line.length() > 0) {
if (line.indexOf("[") == 2) {
line = line.substring(2, line.length());
}
prefix = line + " - ";
}
}
int reference = ((String) filenames.get(new Integer(0))).length();
int numFiles = filenames.size();
for (int i=0; i<numFiles; i++) {
String value = (String) filenames.get(new Integer(i));
if (value.length() > reference) {
filenames.remove(new Integer(i));
}
}
status("Initializing helper readers");
thumbReader = new BMPReader();
core.imageCount[0] = filenames.size();
tiffs = new Vector(core.imageCount[0]);
tiffReader = new TiffReader[core.imageCount[0]];
for (int i=0; i<core.imageCount[0]; i++) {
tiffReader[i] = new TiffReader();
if (i > 0) tiffReader[i].setMetadataCollected(false);
}
// open each INI file (.pty extension)
status("Reading additional metadata");
String tiffPath = null;
RandomAccessStream ptyReader;
for (int i=0; i<core.imageCount[0]; i++) {
String file = (String) filenames.get(new Integer(i));
file = file.substring(1, file.length() - 1);
file = file.replace('\\', File.separatorChar);
file = file.replace('/', File.separatorChar);
file = path + File.separator + file;
tiffPath = file.substring(0, file.lastIndexOf(File.separator));
ptyReader = new RandomAccessStream(file);
b = new byte[(int) ptyReader.length()];
ptyReader.read(b);
s = new String(b);
st = new StringTokenizer(s, "\n");
while (st.hasMoreTokens()) {
String line = st.nextToken().trim();
if (!line.startsWith("[") && (line.indexOf("=") > 0)) {
String key = line.substring(0, line.indexOf("=") - 1).trim();
String value = line.substring(line.indexOf("=") + 1).trim();
key = DataTools.stripString(key);
value = DataTools.stripString(value);
if (key.equals("DataName")) {
value = value.substring(1, value.length() - 1);
if (value.indexOf("-R") == -1) {
tiffs.add(i, tiffPath + File.separator + value);
tiffReader[i].setId((String) tiffs.get(i));
}
}
addMeta("Image " + i + " : " + key, value);
}
}
ptyReader.close();
}
if (tiffPath != null) {
Location dir = new Location(tiffPath);
String[] list = dir.list();
for (int i=0; i<list.length; i++) {
usedFiles.add(new Location(tiffPath, list[i]).getAbsolutePath());
}
}
status("Populating metadata");
for (int i=0; i<9; i++) {
int ss = Integer.parseInt(size[i]);
if (code[i].equals("\"X\"")) core.sizeX[0] = ss;
else if (code[i].equals("\"Y\"")) core.sizeY[0] = ss;
else if (code[i].equals("\"C\"")) core.sizeC[0] = ss;
else if (code[i].equals("\"T\"")) core.sizeT[0] = ss;
else if (code[i].equals("\"Z\"")) core.sizeZ[0] = ss;
}
if (core.sizeZ[0] == 0) core.sizeZ[0] = 1;
if (core.sizeC[0] == 0) core.sizeC[0] = 1;
if (core.sizeT[0] == 0) core.sizeT[0] = 1;
while (core.imageCount[0] >
core.sizeZ[0] * core.sizeT[0] * getEffectiveSizeC())
{
if (core.sizeZ[0] == 1) core.sizeT[0]++;
else if (core.sizeT[0] == 1) core.sizeZ[0]++;
}
core.currentOrder[0] =
core.currentOrder[0].substring(1, core.currentOrder[0].length() - 1);
if (core.currentOrder[0] == null) core.currentOrder[0] = "XYZTC";
else {
String[] names = new String[] {"X", "Y", "Z", "C", "T"};
if (core.currentOrder[0].length() < 5) {
for (int i=0; i<names.length; i++) {
if (core.currentOrder[0].indexOf(names[i]) == -1) {
core.currentOrder[0] += names[i];
}
}
}
}
BufferedImage thumbImage = openThumbImage(0);
core.thumbSizeX[0] = thumbImage.getWidth();
core.thumbSizeY[0] = thumbImage.getHeight();
// The metadata store we're working with.
MetadataStore store = getMetadataStore();
store.setImage(currentId, null, null, null);
switch (imageDepth) {
case 1:
core.pixelType[0] = FormatTools.UINT8;
break;
case 2:
core.pixelType[0] = FormatTools.UINT16;
break;
case 4:
core.pixelType[0] = FormatTools.UINT32;
break;
default:
throw new RuntimeException(
"Unknown matching for pixel depth of: " + imageDepth);
}
core.rgb[0] = tiffReader[0].isRGB();
core.littleEndian[0] = true;
core.interleaved[0] = false;
core.metadataComplete[0] = true;
core.indexed[0] = tiffReader[0].isIndexed();
core.falseColor[0] = false;
FormatTools.populatePixels(store, this);
prefix = "[Reference Image Parameter] - ";
String px = (String) getMeta(prefix + "WidthConvertValue");
String py = (String) getMeta(prefix + "HeightConvertValue");
Float pixX = null, pixY = null;
if (px != null) pixX = new Float(px);
if (py != null) pixY = new Float(py);
store.setDimensions(pixX, pixY, null, null, null, null);
for (int i=0; i<core.sizeC[0]; i++) {
prefix = "[Channel " + (i+1) + " Parameters] - ";
String name = (String) getMeta(prefix + "CH Name");
String emWave = (String) getMeta(prefix + "EmissionWavelength");
String exWave = (String) getMeta(prefix + "ExcitationWavelength");
prefix = "[Channel " + (i+1) + " Parameters] - ";
String gain = (String) getMeta(prefix + "CountingPMTGain");
String voltage = (String) getMeta(prefix + "CountingPMTVoltage");
String offset = (String) getMeta(prefix + "CountingPMTOffset");
if (gain != null) gain.replaceAll("\"", "");
if (voltage != null) voltage.replaceAll("\"", "");
if (offset != null) offset.replaceAll("\"", "");
if (voltage != null) {
store.setDetector(null, null, null, null, null, new Float(voltage),
null, null, new Integer(i));
}
store.setLogicalChannel(i, name, null, null, null, null, null, null,
null, offset == null ? null : new Float(offset),
gain == null ? null : new Float(gain), null, null, null, null, null,
null, null, null, null, emWave == null ? null : new Integer(emWave),
exWave == null ? null : new Integer(exWave), null, null, null);
}
String mag = (String) getMeta("Image 0 : Magnification");
if (mag != null) {
store.setObjective(null, null, null, null, new Float(mag), null, null);
}
String num =
(String) getMeta("[Acquisition Parameters Common] - Number of use Laser");
if (num != null) {
int numLasers = Integer.parseInt(num);
for (int i=0; i<numLasers; i++) {
String wave = (String) getMeta("[Acquisition Parameters Common] - " +
"LaserWavelength0" + (i+1));
if (wave != null) {
store.setLaser(null, null, new Integer(wave), null, null, null, null,
null, null, null, new Integer(i));
}
}
}
}
}