// // HISReader.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.IOException; import loci.common.DataTools; import loci.common.DateTools; import loci.common.RandomAccessInputStream; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.FormatReader; import loci.formats.FormatTools; import loci.formats.MetadataTools; import loci.formats.codec.BitBuffer; import loci.formats.meta.MetadataStore; /** * HISReader is the file format reader for Hamamatsu .his 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/HISReader.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/HISReader.java;hb=HEAD">Gitweb</a></dd></dl> */ public class HISReader extends FormatReader { // -- Constants -- public static final String HIS_MAGIC_STRING = "IM"; // -- Fields -- /** Offsets to pixel data for each series. */ private long[] pixelOffset; // -- Constructor -- /** Constructs a new Hamamatsu .his reader. */ public HISReader() { super("Hamamatsu HIS", "his"); domains = new String[] {FormatTools.SEM_DOMAIN}; } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ public boolean isThisType(RandomAccessInputStream stream) throws IOException { final int blockLen = 2; if (!FormatTools.validStream(stream, blockLen, false)) return false; return (stream.readString(blockLen)).indexOf(HIS_MAGIC_STRING) >= 0; } /** * @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); in.seek(pixelOffset[getSeries()]); if ((getBitsPerPixel() % 8) == 0) { readPlane(in, x, y, w, h, buf); } else { int bits = getBitsPerPixel(); int bpp = FormatTools.getBytesPerPixel(getPixelType()); byte[] b = new byte[(getSizeX() * getSizeY() * getSizeC() * bits) / 8]; in.read(b); BitBuffer bb = new BitBuffer(b); bb.skipBits(y * getSizeX() * getSizeC() * bits); for (int row=0; row<h; row++) { int rowOffset = row * getSizeX() * getSizeC() * bpp; bb.skipBits(x * getSizeC() * bits); for (int col=0; col<w; col++) { int colOffset = col * getSizeC() * bpp; for (int c=0; c<getSizeC(); c++) { int sample = bb.getBits(bits); DataTools.unpackBytes(sample, buf, rowOffset + colOffset + c * bpp, bpp, isLittleEndian()); } } bb.skipBits(getSizeC() * bits * (getSizeX() - w - x)); } } return buf; } // -- 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); in.order(true); in.skipBytes(14); int nSeries = in.readShort(); pixelOffset = new long[nSeries]; core = new CoreMetadata[nSeries]; String[] date = new String[nSeries]; String[] binning = new String[nSeries]; double[] offset = new double[nSeries]; double[] exposureTime = new double[nSeries]; boolean adjustedBitDepth = false; in.seek(0); for (int i=0; i<nSeries; i++) { core[i] = new CoreMetadata(); String checkString = in.readString(2); if (!checkString.equals("IM") && i > 0) { if (getBitsPerPixel() == 12) { core[i - 1].bitsPerPixel = 16; int prevSkip = (getSizeX() * getSizeY() * getSizeC() * 12) / 8; int totalBytes = FormatTools.getPlaneSize(this); in.skipBytes(totalBytes - prevSkip); adjustedBitDepth = true; } } setSeries(i); int commentBytes = in.readShort(); core[i].sizeX = in.readShort(); core[i].sizeY = in.readShort(); in.skipBytes(4); int dataType = in.readShort(); switch (dataType) { case 1: core[i].pixelType = FormatTools.UINT8; break; case 2: core[i].pixelType = FormatTools.UINT16; break; case 6: core[i].pixelType = FormatTools.UINT16; core[i].bitsPerPixel = adjustedBitDepth ? 16 : 12; break; case 11: core[i].pixelType = FormatTools.UINT8; core[i].sizeC = 3; break; case 12: core[i].pixelType = FormatTools.UINT16; core[i].sizeC = 3; break; case 14: core[i].pixelType = FormatTools.UINT16; core[i].sizeC = 3; core[i].bitsPerPixel = adjustedBitDepth ? 16 : 12; break; } in.skipBytes(50); String comment = in.readString(commentBytes); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { String[] data = comment.split(";"); for (String token : data) { int eq = token.indexOf("="); if (eq != -1) { String key = token.substring(0, eq); String value = token.substring(eq + 1); addSeriesMeta(key, value); if (key.equals("vDate")) { date[i] = value; } else if (key.equals("vTime")) { date[i] += " " + value; date[i] = DateTools.formatDate(date[i], "yyyy/MM/dd HH:mm:ss"); } else if (key.equals("vOffset")) { offset[i] = Double.parseDouble(value); } else if (key.equals("vBinX")) { binning[i] = value; } else if (key.equals("vBinY")) { binning[i] += "x" + value; } else if (key.equals("vExpTim1")) { exposureTime[i] = Double.parseDouble(value) * 100; } } } } pixelOffset[i] = in.getFilePointer(); core[i].littleEndian = true; if (core[i].sizeC == 0) core[i].sizeC = 1; core[i].sizeT = 1; core[i].sizeZ = 1; core[i].imageCount = 1; core[i].rgb = core[i].sizeC > 1; core[i].interleaved = isRGB(); core[i].dimensionOrder = "XYCZT"; in.skipBytes( (getSizeX() * getSizeY() * getSizeC() * getBitsPerPixel()) / 8); } MetadataStore store = makeFilterMetadata(); MetadataTools.populatePixels(store, this, true); String instrumentID = MetadataTools.createLSID("Instrument", 0); store.setInstrumentID(instrumentID, 0); if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) { for (int i=0; i<nSeries; i++) { store.setImageInstrumentRef(instrumentID, i); store.setImageAcquiredDate(date[i], i); store.setPlaneExposureTime(exposureTime[i], i, 0); String detectorID = MetadataTools.createLSID("Detector", 0, i); store.setDetectorID(detectorID, 0, i); store.setDetectorOffset(offset[i], 0, i); store.setDetectorType(getDetectorType("Other"), 0, i); store.setDetectorSettingsID(detectorID, i, 0); store.setDetectorSettingsBinning(getBinning(binning[i]), i, 0); } } } }