use of loci.formats.tiff.IFDList in project bioformats by openmicroscopy.
the class TiffReader method parseCommentImageJ.
private void parseCommentImageJ(String comment) throws FormatException, IOException {
int nl = comment.indexOf("\n");
put("ImageJ", nl < 0 ? comment.substring(7) : comment.substring(7, nl));
metadata.remove("Comment");
description = "";
int z = 1, t = 1;
int c = getSizeC();
int images = 1;
CoreMetadata m = core.get(0);
if (ifds.get(0).containsKey(IMAGEJ_TAG)) {
comment += "\n" + ifds.get(0).getIFDTextValue(IMAGEJ_TAG);
}
// parse ImageJ metadata (ZCT sizes, calibration units, etc.)
StringTokenizer st = new StringTokenizer(comment, "\n");
while (st.hasMoreTokens()) {
String token = st.nextToken();
String value = null;
int eq = token.indexOf('=');
if (eq >= 0)
value = token.substring(eq + 1);
if (token.startsWith("channels="))
c = parseInt(value);
else if (token.startsWith("slices="))
z = parseInt(value);
else if (token.startsWith("frames="))
t = parseInt(value);
else if (token.startsWith("images=")) {
images = parseInt(value);
} else if (token.startsWith("mode=")) {
put("Color mode", value);
} else if (token.startsWith("unit=")) {
calibrationUnit = value;
put("Unit", calibrationUnit);
} else if (token.startsWith("finterval=")) {
Double valueDouble = parseDouble(value);
if (valueDouble != null) {
timeIncrement = new Time(valueDouble, UNITS.SECOND);
put("Frame Interval", timeIncrement);
}
} else if (token.startsWith("spacing=")) {
physicalSizeZ = parseDouble(value);
put("Spacing", physicalSizeZ);
} else if (token.startsWith("xorigin=")) {
xOrigin = parseInt(value);
put("X Origin", xOrigin);
} else if (token.startsWith("yorigin=")) {
yOrigin = parseInt(value);
put("Y Origin", yOrigin);
} else if (eq > 0) {
put(token.substring(0, eq).trim(), value);
}
}
if (z * c * t == c && isRGB()) {
t = getImageCount();
}
m.dimensionOrder = "XYCZT";
if (z * t * (isRGB() ? 1 : c) == ifds.size()) {
m.sizeZ = z;
m.sizeT = t;
m.sizeC = isRGB() ? getSizeC() : c;
} else if (z * c * t == ifds.size() && isRGB()) {
m.sizeZ = z;
m.sizeT = t;
m.sizeC *= c;
} else if (ifds.size() == 1 && images > ifds.size() && ifds.get(0).getCompression() == TiffCompression.UNCOMPRESSED) {
// file is likely corrupt or larger than 4GB (missing end IFDs)
//
// ImageJ writes TIFF files like this:
// IFD #0
// comment
// all pixel data
// IFD #1
// IFD #2
// ...
//
// since we know where the pixel data is, we can create fake
// IFDs in an attempt to read the rest of the pixels
IFD firstIFD = ifds.get(0);
int planeSize = getSizeX() * getSizeY() * getRGBChannelCount() * FormatTools.getBytesPerPixel(getPixelType());
long[] stripOffsets = firstIFD.getStripOffsets();
long[] stripByteCounts = firstIFD.getStripByteCounts();
long endOfFirstPlane = stripOffsets[stripOffsets.length - 1] + stripByteCounts[stripByteCounts.length - 1];
long totalBytes = in.length() - endOfFirstPlane;
int totalPlanes = (int) (totalBytes / planeSize) + 1;
ifds = new IFDList();
ifds.add(firstIFD);
for (int i = 1; i < totalPlanes; i++) {
IFD ifd = new IFD(firstIFD);
ifds.add(ifd);
long[] prevOffsets = ifds.get(i - 1).getStripOffsets();
long[] offsets = new long[stripOffsets.length];
offsets[0] = prevOffsets[prevOffsets.length - 1] + stripByteCounts[stripByteCounts.length - 1];
for (int j = 1; j < offsets.length; j++) {
offsets[j] = offsets[j - 1] + stripByteCounts[j - 1];
}
ifd.putIFDValue(IFD.STRIP_OFFSETS, offsets);
}
if (z * c * t == ifds.size()) {
m.sizeZ = z;
m.sizeT = t;
m.sizeC = c;
} else if (z * t == ifds.size()) {
m.sizeZ = z;
m.sizeT = t;
} else
m.sizeZ = ifds.size();
m.imageCount = ifds.size();
} else {
m.sizeT = ifds.size();
m.imageCount = ifds.size();
}
}
use of loci.formats.tiff.IFDList in project bioformats by openmicroscopy.
the class OMETiffReader method openBytes.
/*
* @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 series = getSeries();
lastPlane = no;
int i = info[series][no].ifd;
if (!info[series][no].exists) {
Arrays.fill(buf, (byte) 0);
return buf;
}
MinimalTiffReader r = (MinimalTiffReader) info[series][no].reader;
if (r.getCurrentFile() == null) {
r.setId(info[series][no].id);
}
r.lastPlane = i;
IFDList ifdList = r.getIFDs();
if (i >= ifdList.size()) {
LOGGER.warn("Error untangling IFDs; the OME-TIFF file may be malformed (IFD #{} missing).", i);
return buf;
}
IFD ifd = ifdList.get(i);
RandomAccessInputStream s = new RandomAccessInputStream(info[series][no].id, 16);
TiffParser p = new TiffParser(s);
p.getSamples(ifd, buf, x, y, w, h);
s.close();
// lower-right-most tile from a single plane file has been read
if (r.getImageCount() == 1 && w + x == getSizeX() && h + y == getSizeY()) {
r.close();
}
return buf;
}
use of loci.formats.tiff.IFDList in project bioformats by openmicroscopy.
the class MicromanagerReader method parsePosition.
// -- Helper methods --
private void parsePosition(int posIndex) throws IOException, FormatException {
Position p = positions.get(posIndex);
String s = DataTools.readFile(p.metadataFile);
parsePosition(s, posIndex);
buildTIFFList(posIndex);
// parse original metadata from each TIFF's JSON
p.positions = new Double[p.tiffs.size()][3];
int digits = String.valueOf(p.tiffs.size() - 1).length();
boolean parseMMJSONTag = true;
for (int plane = 0; plane < p.tiffs.size(); ) {
String path = p.tiffs.get(plane);
// file ordering is correct
if (p.tiffs.size() == p.fileNameMap.size() && plane < getImageCount()) {
path = p.getFile(plane);
}
if (path == null || !new Location(path).exists()) {
plane++;
continue;
}
try {
TiffParser parser = new TiffParser(path);
int nIFDs = parser.getIFDs().size();
IFD firstIFD = parser.getFirstIFD();
parser.fillInIFD(firstIFD);
// ensure that the plane dimensions and pixel type are correct
CoreMetadata ms = core.get(posIndex);
ms.sizeX = (int) firstIFD.getImageWidth();
ms.sizeY = (int) firstIFD.getImageLength();
ms.pixelType = firstIFD.getPixelType();
ms.littleEndian = firstIFD.isLittleEndian();
String json = firstIFD.getIFDTextValue(JSON_TAG);
if (json != null) {
String[] lines = json.split("\n");
for (String line : lines) {
String toSplit = line.trim();
if (toSplit.length() == 0) {
continue;
}
toSplit = toSplit.substring(0, toSplit.length() - 1);
String[] values = toSplit.split("\": ");
if (values.length < 2) {
continue;
}
String key = values[0].replaceAll("\"", "");
String value = values[1].replaceAll("\"", "");
if (key.length() > 0 && value.length() > 0) {
parseKeyAndValue(key, value, digits, plane * nIFDs, nIFDs);
}
}
}
IFDList ifds = parser.getIFDs();
for (int i = 0; i < ifds.size(); i++) {
if (!parseMMJSONTag) {
break;
}
IFD ifd = ifds.get(i);
parser.fillInIFD(ifd);
json = ifd.getIFDTextValue(MM_JSON_TAG);
LOGGER.trace("JSON for IFD #{} = {}", i, json);
if (json == null) {
// if one of the files is missing the per-plane JSON tag,
// assume all files are missing it (for performance)
parseMMJSONTag = false;
break;
}
String[] tokens = json.split("[\\{\\}:,\"]");
String key = null, value = null, propType = null;
int nEmptyTokens = 0;
for (int q = 0; q < tokens.length; q++) {
String token = tokens[q];
if (token.length() == 0) {
nEmptyTokens++;
continue;
}
if (nEmptyTokens == 5 && value == null) {
key = null;
}
if (key == null && value == null && propType == null) {
// don't use completeCoords as a key, defer to child attributes
if (!token.equals("completeCoords")) {
key = token;
}
nEmptyTokens = 0;
} else if (token.equals("PropVal") || token.equals("[")) {
value = token;
} else if (token.equals("PropType")) {
propType = token;
} else if (value != null && value.equals("PropVal") && propType == null) {
value = token;
} else if (value != null && propType == null && value.startsWith("[") && !token.startsWith("]")) {
value += token;
value += ", ";
} else if (((propType != null && propType.equals("PropType")) || token.equals("]")) || (key != null && value == null)) {
if (value == null && (propType == null || !propType.equals("PropType"))) {
StringBuilder sb = new StringBuilder(token);
while (q + 1 < tokens.length && tokens[q + 1].trim().length() > 0) {
sb.append(':');
sb.append(tokens[q + 1]);
q++;
}
value = sb.toString();
}
if (!value.equals("PropVal")) {
parseKeyAndValue(key, value, digits, plane + i, 1);
}
propType = null;
key = null;
value = null;
nEmptyTokens = 0;
}
}
}
plane += ifds.size();
parser.getStream().close();
} catch (IOException e) {
LOGGER.debug("Failed to read metadata from " + path, e);
}
}
}
use of loci.formats.tiff.IFDList in project bioformats by openmicroscopy.
the class BaseTiffReader method initStandardMetadata.
/**
* Parses standard metadata.
*
* NOTE: Absolutely <b>no</b> calls to the metadata store should be made in
* this method or methods that override this method. Data <b>will</b> be
* overwritten if you do so.
*/
protected void initStandardMetadata() throws FormatException, IOException {
if (getMetadataOptions().getMetadataLevel() == MetadataLevel.MINIMUM) {
return;
}
for (int i = 0; i < ifds.size(); i++) {
put("PageName #" + i, ifds.get(i), IFD.PAGE_NAME);
}
IFD firstIFD = ifds.get(0);
put("ImageWidth", firstIFD, IFD.IMAGE_WIDTH);
put("ImageLength", firstIFD, IFD.IMAGE_LENGTH);
put("BitsPerSample", firstIFD, IFD.BITS_PER_SAMPLE);
if (ifds.get(0).containsKey(IFD.EXIF)) {
IFDList exifIFDs = tiffParser.getExifIFDs();
if (exifIFDs.size() > 0) {
IFD exif = exifIFDs.get(0);
tiffParser.fillInIFD(exif);
for (Integer key : exif.keySet()) {
int k = key.intValue();
addGlobalMeta(getExifTagName(k), exif.get(key));
}
}
}
TiffCompression comp = firstIFD.getCompression();
put("Compression", comp.getCodecName());
PhotoInterp photo = firstIFD.getPhotometricInterpretation();
String photoInterp = photo.getName();
String metaDataPhotoInterp = photo.getMetadataType();
put("PhotometricInterpretation", photoInterp);
put("MetaDataPhotometricInterpretation", metaDataPhotoInterp);
putInt("CellWidth", firstIFD, IFD.CELL_WIDTH);
putInt("CellLength", firstIFD, IFD.CELL_LENGTH);
int or = firstIFD.getIFDIntValue(IFD.ORIENTATION);
// adjust the width and height if necessary
if (or == 8) {
put("ImageWidth", firstIFD, IFD.IMAGE_LENGTH);
put("ImageLength", firstIFD, IFD.IMAGE_WIDTH);
}
String orientation = null;
// there is no case 0
switch(or) {
case 1:
orientation = "1st row -> top; 1st column -> left";
break;
case 2:
orientation = "1st row -> top; 1st column -> right";
break;
case 3:
orientation = "1st row -> bottom; 1st column -> right";
break;
case 4:
orientation = "1st row -> bottom; 1st column -> left";
break;
case 5:
orientation = "1st row -> left; 1st column -> top";
break;
case 6:
orientation = "1st row -> right; 1st column -> top";
break;
case 7:
orientation = "1st row -> right; 1st column -> bottom";
break;
case 8:
orientation = "1st row -> left; 1st column -> bottom";
break;
}
put("Orientation", orientation);
putInt("SamplesPerPixel", firstIFD, IFD.SAMPLES_PER_PIXEL);
put("Software", firstIFD, IFD.SOFTWARE);
put("Instrument Make", firstIFD, IFD.MAKE);
put("Instrument Model", firstIFD, IFD.MODEL);
put("Document Name", firstIFD, IFD.DOCUMENT_NAME);
put("DateTime", getImageCreationDate());
put("Artist", firstIFD, IFD.ARTIST);
put("HostComputer", firstIFD, IFD.HOST_COMPUTER);
put("Copyright", firstIFD, IFD.COPYRIGHT);
put("NewSubfileType", firstIFD, IFD.NEW_SUBFILE_TYPE);
int thresh = firstIFD.getIFDIntValue(IFD.THRESHHOLDING);
String threshholding = null;
switch(thresh) {
case 1:
threshholding = "No dithering or halftoning";
break;
case 2:
threshholding = "Ordered dithering or halftoning";
break;
case 3:
threshholding = "Randomized error diffusion";
break;
}
put("Threshholding", threshholding);
int fill = firstIFD.getIFDIntValue(IFD.FILL_ORDER);
String fillOrder = null;
switch(fill) {
case 1:
fillOrder = "Pixels with lower column values are stored " + "in the higher order bits of a byte";
break;
case 2:
fillOrder = "Pixels with lower column values are stored " + "in the lower order bits of a byte";
break;
}
put("FillOrder", fillOrder);
putInt("Make", firstIFD, IFD.MAKE);
putInt("Model", firstIFD, IFD.MODEL);
putInt("MinSampleValue", firstIFD, IFD.MIN_SAMPLE_VALUE);
putInt("MaxSampleValue", firstIFD, IFD.MAX_SAMPLE_VALUE);
TiffRational xResolution = firstIFD.getIFDRationalValue(IFD.X_RESOLUTION);
TiffRational yResolution = firstIFD.getIFDRationalValue(IFD.Y_RESOLUTION);
if (xResolution != null) {
put("XResolution", xResolution.doubleValue());
}
if (yResolution != null) {
put("YResolution", yResolution.doubleValue());
}
int planar = firstIFD.getIFDIntValue(IFD.PLANAR_CONFIGURATION);
String planarConfig = null;
switch(planar) {
case 1:
planarConfig = "Chunky";
break;
case 2:
planarConfig = "Planar";
break;
}
put("PlanarConfiguration", planarConfig);
putInt("XPosition", firstIFD, IFD.X_POSITION);
putInt("YPosition", firstIFD, IFD.Y_POSITION);
putInt("FreeOffsets", firstIFD, IFD.FREE_OFFSETS);
putInt("FreeByteCounts", firstIFD, IFD.FREE_BYTE_COUNTS);
putInt("GrayResponseUnit", firstIFD, IFD.GRAY_RESPONSE_UNIT);
putInt("GrayResponseCurve", firstIFD, IFD.GRAY_RESPONSE_CURVE);
putInt("T4Options", firstIFD, IFD.T4_OPTIONS);
putInt("T6Options", firstIFD, IFD.T6_OPTIONS);
int res = firstIFD.getIFDIntValue(IFD.RESOLUTION_UNIT);
String resUnit = null;
switch(res) {
case 1:
resUnit = "None";
break;
case 2:
resUnit = "Inch";
break;
case 3:
resUnit = "Centimeter";
break;
}
put("ResolutionUnit", resUnit);
putString("PageNumber", firstIFD, IFD.PAGE_NUMBER);
putInt("TransferFunction", firstIFD, IFD.TRANSFER_FUNCTION);
int predict = firstIFD.getIFDIntValue(IFD.PREDICTOR);
String predictor = null;
switch(predict) {
case 1:
predictor = "No prediction scheme";
break;
case 2:
predictor = "Horizontal differencing";
break;
}
put("Predictor", predictor);
putInt("WhitePoint", firstIFD, IFD.WHITE_POINT);
putInt("PrimaryChromacities", firstIFD, IFD.PRIMARY_CHROMATICITIES);
putInt("HalftoneHints", firstIFD, IFD.HALFTONE_HINTS);
putInt("TileWidth", firstIFD, IFD.TILE_WIDTH);
putInt("TileLength", firstIFD, IFD.TILE_LENGTH);
putInt("TileOffsets", firstIFD, IFD.TILE_OFFSETS);
putInt("TileByteCounts", firstIFD, IFD.TILE_BYTE_COUNTS);
int ink = firstIFD.getIFDIntValue(IFD.INK_SET);
String inkSet = null;
switch(ink) {
case 1:
inkSet = "CMYK";
break;
case 2:
inkSet = "Other";
break;
}
put("InkSet", inkSet);
putInt("InkNames", firstIFD, IFD.INK_NAMES);
putInt("NumberOfInks", firstIFD, IFD.NUMBER_OF_INKS);
putInt("DotRange", firstIFD, IFD.DOT_RANGE);
put("TargetPrinter", firstIFD, IFD.TARGET_PRINTER);
putInt("ExtraSamples", firstIFD, IFD.EXTRA_SAMPLES);
int fmt = firstIFD.getIFDIntValue(IFD.SAMPLE_FORMAT);
String sampleFormat = null;
switch(fmt) {
case 1:
sampleFormat = "unsigned integer";
break;
case 2:
sampleFormat = "two's complement signed integer";
break;
case 3:
sampleFormat = "IEEE floating point";
break;
case 4:
sampleFormat = "undefined";
break;
}
put("SampleFormat", sampleFormat);
putInt("SMinSampleValue", firstIFD, IFD.S_MIN_SAMPLE_VALUE);
putInt("SMaxSampleValue", firstIFD, IFD.S_MAX_SAMPLE_VALUE);
putInt("TransferRange", firstIFD, IFD.TRANSFER_RANGE);
int jpeg = firstIFD.getIFDIntValue(IFD.JPEG_PROC);
String jpegProc = null;
switch(jpeg) {
case 1:
jpegProc = "baseline sequential process";
break;
case 14:
jpegProc = "lossless process with Huffman coding";
break;
}
put("JPEGProc", jpegProc);
putInt("JPEGInterchangeFormat", firstIFD, IFD.JPEG_INTERCHANGE_FORMAT);
putInt("JPEGRestartInterval", firstIFD, IFD.JPEG_RESTART_INTERVAL);
putInt("JPEGLosslessPredictors", firstIFD, IFD.JPEG_LOSSLESS_PREDICTORS);
putInt("JPEGPointTransforms", firstIFD, IFD.JPEG_POINT_TRANSFORMS);
putInt("JPEGQTables", firstIFD, IFD.JPEG_Q_TABLES);
putInt("JPEGDCTables", firstIFD, IFD.JPEG_DC_TABLES);
putInt("JPEGACTables", firstIFD, IFD.JPEG_AC_TABLES);
putInt("YCbCrCoefficients", firstIFD, IFD.Y_CB_CR_COEFFICIENTS);
int ycbcr = firstIFD.getIFDIntValue(IFD.Y_CB_CR_SUB_SAMPLING);
String subSampling = null;
switch(ycbcr) {
case 1:
subSampling = "chroma image dimensions = luma image dimensions";
break;
case 2:
subSampling = "chroma image dimensions are " + "half the luma image dimensions";
break;
case 4:
subSampling = "chroma image dimensions are " + "1/4 the luma image dimensions";
break;
}
put("YCbCrSubSampling", subSampling);
putInt("YCbCrPositioning", firstIFD, IFD.Y_CB_CR_POSITIONING);
putInt("ReferenceBlackWhite", firstIFD, IFD.REFERENCE_BLACK_WHITE);
// bits per sample and number of channels
int[] q = firstIFD.getBitsPerSample();
int bps = q[0];
int numC = q.length;
if (photo == PhotoInterp.RGB_PALETTE || photo == PhotoInterp.CFA_ARRAY) {
numC = 3;
}
put("BitsPerSample", bps);
put("NumberOfChannels", numC);
}
use of loci.formats.tiff.IFDList in project bioformats by openmicroscopy.
the class BaseTiffReader method initMetadataStore.
/**
* Populates the metadata store using the data parsed in
* {@link #initStandardMetadata()} along with some further parsing done in
* the method itself.
*
* All calls to the active <code>MetadataStore</code> should be made in this
* method and <b>only</b> in this method. This is especially important for
* sub-classes that override the getters for pixel set array size, etc.
*/
protected void initMetadataStore() throws FormatException {
LOGGER.info("Populating OME metadata");
// the metadata store we're working with
MetadataStore store = makeFilterMetadata();
IFD firstIFD = ifds.get(0);
IFD exif = null;
if (ifds.get(0).containsKey(IFD.EXIF)) {
try {
IFDList exifIFDs = tiffParser.getExifIFDs();
if (exifIFDs.size() > 0) {
exif = exifIFDs.get(0);
}
tiffParser.fillInIFD(exif);
} catch (IOException e) {
LOGGER.debug("Could not read EXIF IFDs", e);
}
}
MetadataTools.populatePixels(store, this, exif != null);
// format the creation date to ISO 8601
String creationDate = getImageCreationDate();
String date = DateTools.formatDate(creationDate, DATE_FORMATS, ".");
if (creationDate != null && date == null) {
LOGGER.warn("unknown creation date format: {}", creationDate);
}
creationDate = date;
if (creationDate != null) {
store.setImageAcquisitionDate(new Timestamp(creationDate), 0);
}
if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
// populate Experimenter
String artist = firstIFD.getIFDTextValue(IFD.ARTIST);
if (artist != null) {
String firstName = null, lastName = null;
int ndx = artist.indexOf(' ');
if (ndx < 0)
lastName = artist;
else {
firstName = artist.substring(0, ndx);
lastName = artist.substring(ndx + 1);
}
String email = firstIFD.getIFDStringValue(IFD.HOST_COMPUTER);
store.setExperimenterFirstName(firstName, 0);
store.setExperimenterLastName(lastName, 0);
store.setExperimenterEmail(email, 0);
store.setExperimenterID(MetadataTools.createLSID("Experimenter", 0), 0);
}
store.setImageDescription(firstIFD.getComment(), 0);
// set the X and Y pixel dimensions
double pixX = firstIFD.getXResolution();
double pixY = firstIFD.getYResolution();
String unit = getResolutionUnitFromComment(firstIFD);
Length sizeX = FormatTools.getPhysicalSizeX(pixX, unit);
Length sizeY = FormatTools.getPhysicalSizeY(pixY, unit);
if (sizeX != null) {
store.setPixelsPhysicalSizeX(sizeX, 0);
}
if (sizeY != null) {
store.setPixelsPhysicalSizeY(sizeY, 0);
}
store.setPixelsPhysicalSizeZ(null, 0);
if (exif != null) {
if (exif.containsKey(IFD.EXPOSURE_TIME)) {
Object exp = exif.get(IFD.EXPOSURE_TIME);
if (exp instanceof TiffRational) {
Time exposure = new Time(((TiffRational) exp).doubleValue(), UNITS.SECOND);
for (int i = 0; i < getImageCount(); i++) {
store.setPlaneExposureTime(exposure, 0, i);
}
}
}
}
}
}
Aggregations