/*
* #%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 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.meta.MetadataStore;
import ome.xml.model.primitives.PositiveFloat;
import ome.units.quantity.Length;
/**
* Ecat7Reader is the file format reader for ECAT 7 files.
*/
public class Ecat7Reader extends FormatReader {
// -- Constants --
public static final String ECAT7_MAGIC = "MATRIX72v";
private static final long HEADER_SIZE = 1536;
// -- Constructor --
/** Constructs a new ECAT7 reader. */
public Ecat7Reader() {
super("ECAT7", "v");
domains = new String[] {FormatTools.MEDICAL_DOMAIN};
suffixNecessary = false;
}
// -- IFormatReader API methods --
/* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */
@Override
public boolean isThisType(RandomAccessInputStream stream) throws IOException {
final int blockLen = ECAT7_MAGIC.length();
if (!FormatTools.validStream(stream, blockLen, false)) return false;
return stream.readString(blockLen).equals(ECAT7_MAGIC);
}
/**
* @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);
int[] zct = getZCTCoords(no);
int tSkip = 0;
for (int i=0; i<zct[2]; i++) {
tSkip += 512;
if (i > 0 && (i % 30) == 0) tSkip += 512;
}
in.seek(HEADER_SIZE + no * FormatTools.getPlaneSize(this) + tSkip);
readPlane(in, x, y, w, h, buf);
return buf;
}
// -- 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 ms0 = core.get(0);
String check = in.readString(14).trim();
if (!check.equals(ECAT7_MAGIC)) {
throw new FormatException("Invalid ECAT 7 file.");
}
String originalPath = in.readString(32);
short version = in.readShort();
short systemType = in.readShort();
short fileType = in.readShort();
String serialNumber = in.readString(10);
int scanStart = in.readInt();
String isotopeName = in.readString(8);
float isotopeHalflife = in.readFloat();
String radioPharmaceutical = in.readString(32);
float gantryTilt = in.readFloat();
float gantryRotation = in.readFloat();
float bedElevation = in.readFloat();
float intrinsicTilt = in.readFloat();
short wobbleSpeed = in.readShort();
short sourceType = in.readShort();
float distanceScanned = in.readFloat();
float transaxialFOV = in.readFloat();
short angularCompression = in.readShort();
short coinSampleMode = in.readShort();
short axialSampleMode = in.readShort();
float calibrationFactor = in.readFloat();
short calibrationUnits = in.readShort();
short calibrationLabel = in.readShort();
short compression = in.readShort();
String studyType = in.readString(12);
String patientID = in.readString(16);
String patientName = in.readString(32);
String patientSex = in.readString(1);
String patientDexterity = in.readString(1);
float patientAge = in.readFloat();
float patientHeight = in.readFloat();
float patientWeight = in.readFloat();
int patientBirthDate = in.readInt();
String physicianName = in.readString(32);
String operatorName = in.readString(32);
String description = in.readString(32);
short acquisitionType = in.readShort();
short patientOrientation = in.readShort();
String facilityName = in.readString(20);
ms0.sizeZ = in.readShort();
ms0.sizeT = in.readShort();
short numGates = in.readShort();
short numBedPositions = in.readShort();
float initBedPosition = in.readFloat();
float[] bedPositions = new float[15];
for (int i=0; i<bedPositions.length; i++) {
bedPositions[i] = in.readFloat();
}
float planeSeparation = in.readFloat();
short lowerThreshold = in.readShort();
short trueLowerThreshold = in.readShort();
short trueUpperThreshold = in.readShort();
String processCode = in.readString(10);
short acquisitionMode = in.readShort();
float binSize = in.readFloat();
float branchingFraction = in.readFloat();
int doseStartTime = in.readInt();
float dosage = in.readFloat();
float wellCounterCorrectionFactor = in.readFloat();
String dataUnits = in.readString(32);
short septaState = in.readShort();
short[] fillCTI = new short[6];
for (int i=0; i<fillCTI.length; i++) {
fillCTI[i] = in.readShort();
}
in.skipBytes(512);
short dataType = in.readShort();
short numDimensions = in.readShort();
ms0.sizeX = in.readShort();
ms0.sizeY = in.readShort();
in.skipBytes(2);
float xOffset = in.readFloat();
float yOffset = in.readFloat();
float zOffset = in.readFloat();
float reconZoom = in.readFloat();
float scaleFactor = in.readFloat();
short imageMin = in.readShort();
short imageMax = in.readShort();
float xPixelSize = in.readFloat();
float yPixelSize = in.readFloat();
float zPixelSize = in.readFloat();
int frameDuration = in.readInt();
int frameStartTime = in.readInt();
short filterCode = in.readShort();
float xResolution = in.readFloat();
float yResolution = in.readFloat();
float zResolution = in.readFloat();
float numRElements = in.readFloat();
float numAngles = in.readFloat();
float zRotationAngle = in.readFloat();
float decayCorrectionFactor = in.readFloat();
int processingCode = in.readInt();
int gateDuration = in.readInt();
int rWaveOffset = in.readInt();
int numAcceptedBeats = in.readInt();
float filterCutoffFrequency = in.readFloat();
float filterResolution = in.readFloat();
float filterRampSlope = in.readFloat();
short filterOrder = in.readShort();
float filterScatterFraction = in.readFloat();
float filterScatterSlope = in.readFloat();
String annotation = in.readString(40);
float[][] matrix = new float[3][4];
for (int i=0; i<matrix.length; i++) {
for (int j=0; j<matrix[i].length-1; j++) {
matrix[i][j] = in.readFloat();
}
}
float rFilterCutoff = in.readFloat();
float rFilterResolution = in.readFloat();
short rFilterCode = in.readShort();
short rFilterOrder = in.readShort();
float zFilterCutoff = in.readFloat();
float zFilterResolution = in.readFloat();
short zFilterCode = in.readShort();
short zFilterOrder = in.readShort();
matrix[0][3] = in.readFloat();
matrix[1][3] = in.readFloat();
matrix[2][3] = in.readFloat();
short scatterType = in.readShort();
short reconType = in.readShort();
short reconViews = in.readShort();
short[] ctiFill = new short[87];
for (int i=0; i<ctiFill.length; i++) {
ctiFill[i] = in.readShort();
}
short[] userFill = new short[48];
for (int i=0; i<userFill.length; i++) {
userFill[i] = in.readShort();
}
ms0.sizeC = 1;
ms0.imageCount = getSizeZ() * getSizeT() * getSizeC();
ms0.dimensionOrder = "XYZTC";
switch (dataType) {
case 6:
ms0.pixelType = FormatTools.UINT16;
break;
default:
throw new FormatException("Unsupported data type: " + dataType);
}
addGlobalMeta("Original path", originalPath);
addGlobalMeta("Version", version);
addGlobalMeta("System type", systemType);
addGlobalMeta("File type", fileType);
addGlobalMeta("Serial number", serialNumber);
addGlobalMeta("Scan start", scanStart);
addGlobalMeta("Isotope Name", isotopeName);
addGlobalMeta("Isotope half-life", isotopeHalflife);
addGlobalMeta("Radiopharmaceutical", radioPharmaceutical);
addGlobalMeta("Gantry tilt", gantryTilt);
addGlobalMeta("Gantry rotation", gantryRotation);
addGlobalMeta("Bed elevation", bedElevation);
addGlobalMeta("Intrinsic tilt", intrinsicTilt);
addGlobalMeta("Wobble speed", wobbleSpeed);
addGlobalMeta("Source type", sourceType);
addGlobalMeta("Distance scanned", distanceScanned);
addGlobalMeta("Transaxial FOV", transaxialFOV);
addGlobalMeta("Angular compression", angularCompression);
addGlobalMeta("Coin. sample mode", coinSampleMode);
addGlobalMeta("Axial sample mode", axialSampleMode);
addGlobalMeta("Calibration factor", calibrationFactor);
addGlobalMeta("Calibration units", calibrationUnits);
addGlobalMeta("Calibration units label", calibrationLabel);
addGlobalMeta("Compression", compression);
addGlobalMeta("Study type", studyType);
addGlobalMeta("Patient ID", patientID);
addGlobalMeta("Patient name", patientName);
addGlobalMeta("Patient sex", patientSex);
addGlobalMeta("Patient dexterity", patientDexterity);
addGlobalMeta("Patient age", patientAge);
addGlobalMeta("Patient height", patientHeight);
addGlobalMeta("Patient weight", patientWeight);
addGlobalMeta("Patient birth date", patientBirthDate);
addGlobalMeta("Physician name", physicianName);
addGlobalMeta("Operator name", operatorName);
addGlobalMeta("Description", description);
addGlobalMeta("Acquisition type", acquisitionType);
addGlobalMeta("Patient orientation", patientOrientation);
addGlobalMeta("Facility name", facilityName);
addGlobalMeta("Number of gates", numGates);
addGlobalMeta("Number of bed positions", numBedPositions);
for (float bedPos : bedPositions) {
addGlobalMetaList("Bed position", bedPos);
}
addGlobalMeta("Plane separation", planeSeparation);
addGlobalMeta("Lower threshold", lowerThreshold);
addGlobalMeta("True lower threshold", trueLowerThreshold);
addGlobalMeta("True upper threshold", trueUpperThreshold);
addGlobalMeta("Process code", processCode);
addGlobalMeta("Acquistion mode", acquisitionMode);
addGlobalMeta("Bin size", binSize);
addGlobalMeta("Branching fraction", branchingFraction);
addGlobalMeta("Dose start time", doseStartTime);
addGlobalMeta("Dosage", dosage);
addGlobalMeta("Well counter correction factor",
wellCounterCorrectionFactor);
addGlobalMeta("Data units", dataUnits);
addGlobalMeta("Septa state", septaState);
for (float fill : fillCTI) {
addGlobalMetaList("Fill CTI", fill);
}
addGlobalMeta("Data type", dataType);
addGlobalMeta("Number of dimensions", numDimensions);
addGlobalMeta("X offset", xOffset);
addGlobalMeta("Y offset", yOffset);
addGlobalMeta("Z offset", zOffset);
addGlobalMeta("Recon. zoom", reconZoom);
addGlobalMeta("Scale factor", scaleFactor);
addGlobalMeta("Image minimum", imageMin);
addGlobalMeta("Image maximum", imageMax);
addGlobalMeta("X pixel size", xPixelSize);
addGlobalMeta("Y pixel size", yPixelSize);
addGlobalMeta("Z pixel size", zPixelSize);
addGlobalMeta("Frame duration", frameDuration);
addGlobalMeta("Frame start time", frameStartTime);
addGlobalMeta("Filter code", filterCode);
addGlobalMeta("X resolution", xResolution);
addGlobalMeta("Y resolution", yResolution);
addGlobalMeta("Z resolution", zResolution);
addGlobalMeta("Number of R elements", numRElements);
addGlobalMeta("Number of angles", numAngles);
addGlobalMeta("Z rotation angle", zRotationAngle);
addGlobalMeta("Decay correction factor", decayCorrectionFactor);
addGlobalMeta("Processing code", processingCode);
addGlobalMeta("Gate duration", gateDuration);
addGlobalMeta("R wave offset", rWaveOffset);
addGlobalMeta("Number of accepted beats", numAcceptedBeats);
addGlobalMeta("Filter cutoff frequency", filterCutoffFrequency);
addGlobalMeta("Filter resolution", filterResolution);
addGlobalMeta("Filter ramp slope", filterRampSlope);
addGlobalMeta("Filter order", filterOrder);
addGlobalMeta("Filter scatter fraction", filterScatterFraction);
addGlobalMeta("Filter scatter slope", filterScatterSlope);
addGlobalMeta("Annotation", annotation);
for (int i=0; i<matrix.length; i++) {
for (int j=0; j<matrix[i].length; j++) {
addGlobalMeta("MT (" + (i + 1) + ", " + (j + 1) + ")", matrix[i][j]);
}
}
addGlobalMeta("R filter cutoff", rFilterCutoff);
addGlobalMeta("R filter resolution", rFilterResolution);
addGlobalMeta("R filter code", rFilterCode);
addGlobalMeta("R filter order", rFilterOrder);
addGlobalMeta("Z filter cutoff", zFilterCutoff);
addGlobalMeta("Z filter resolution", zFilterResolution);
addGlobalMeta("Z filter code", zFilterCode);
addGlobalMeta("Z filter order", zFilterOrder);
addGlobalMeta("Scatter type", scatterType);
addGlobalMeta("Recon. type", reconType);
addGlobalMeta("Recon. views", reconViews);
for (float cti : ctiFill) {
addGlobalMeta("CTI fill", cti);
}
for (float user : userFill) {
addGlobalMeta("User fill", user);
}
MetadataStore store = makeFilterMetadata();
MetadataTools.populatePixels(store, this);
if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
store.setImageDescription(description, 0);
Length sizeX =
FormatTools.getPhysicalSizeX(new Double(xPixelSize));
Length sizeY =
FormatTools.getPhysicalSizeY(new Double(yPixelSize));
Length sizeZ =
FormatTools.getPhysicalSizeZ(new Double(zPixelSize));
if (sizeX != null) {
store.setPixelsPhysicalSizeX(sizeX, 0);
}
if (sizeY != null) {
store.setPixelsPhysicalSizeY(sizeY, 0);
}
if (sizeZ != null) {
store.setPixelsPhysicalSizeZ(sizeZ, 0);
}
}
}
}