use of loci.formats.tiff.IFD in project bioformats by openmicroscopy.
the class FlowSightReader method initFile.
/* (non-Javadoc)
* @see loci.formats.FormatReader#initFile(java.lang.String)
*/
@Override
protected void initFile(String id) throws FormatException, IOException {
super.initFile(id);
in = new RandomAccessInputStream(id);
tiffParser = new TiffParser(in);
tiffParser.setDoCaching(false);
tiffParser.setUse64BitOffsets(false);
final Boolean littleEndian = tiffParser.checkHeader();
if (littleEndian == null) {
throw new FormatException("Invalid FlowSight file");
}
final boolean little = littleEndian.booleanValue();
in.order(little);
LOGGER.info("Reading IFDs");
ifdOffsets = tiffParser.getIFDOffsets();
if (ifdOffsets.length < 2) {
throw new FormatException("No IFDs found");
}
LOGGER.info("Populating metadata");
/*
* The first IFD contains file-scope metadata
*/
final IFD ifd0 = tiffParser.getFirstIFD();
tiffParser.fillInIFD(ifd0);
int channelCount = ifd0.getIFDIntValue(CHANNEL_COUNT_TAG, 1);
final String channelNamesString = ifd0.getIFDStringValue(CHANNEL_NAMES_TAG);
if (channelNamesString != null) {
channelNames = channelNamesString.split("\\|");
if (channelNames.length != channelCount) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Channel count (%d) does not match number of " + "channel names (%d) in string \"%s\"", channelCount, channelNames.length, channelNamesString);
}
channelCount = channelNames.length;
}
LOGGER.debug("Found {} channels: {}", channelCount, channelNamesString.replace('|', ','));
}
final String channelDescsString = ifd0.getIFDStringValue(CHANNEL_DESCS_TAG);
if (channelDescsString != null) {
channelDescs = channelDescsString.split("\\|");
if (channelDescs.length != channelCount) {
throw new FormatException(String.format("Channel count (%d) does not match number of channel descriptions (%d) in string \"%s\"", channelCount, channelDescs.length, channelDescsString));
}
}
String xml = ifd0.getIFDTextValue(METADATA_XML_TAG);
xml = XMLTools.sanitizeXML(xml);
try {
Element xmlRoot = XMLTools.parseDOM(xml).getDocumentElement();
NodeList imagingNodes = xmlRoot.getElementsByTagName("Imaging");
if (imagingNodes.getLength() > 0) {
Element imagingNode = (Element) imagingNodes.item(0);
NodeList children = imagingNode.getChildNodes();
for (int child = 0; child < children.getLength(); child++) {
Node childNode = children.item(child);
String name = childNode.getNodeName();
if (name.startsWith("ChannelInUseIndicators")) {
channelCount = 0;
String text = childNode.getTextContent();
String[] tokens = text.split(" ");
for (String token : tokens) {
if (token.equals("1")) {
channelCount++;
}
}
}
}
}
} catch (ParserConfigurationException e) {
LOGGER.debug("Could not parse XML", e);
} catch (SAXException e) {
LOGGER.debug("Could not parse XML", e);
}
/*
* Scan the remaining IFDs
*
* Unfortunately, each image can have a different width and height
* and the images and masks have a different bit depth, so in the
* OME scheme of things, we get one series per plane.
*/
for (int idxOff = 1; idxOff < ifdOffsets.length; idxOff++) {
// TODO: Record the channel names
final long offset = ifdOffsets[idxOff];
final boolean first = (idxOff == 1);
final IFD ifd = tiffParser.getIFD(offset);
tiffParser.fillInIFD(ifd);
CoreMetadata ms = first ? core.get(0) : new CoreMetadata();
ms.rgb = false;
ms.interleaved = false;
ms.littleEndian = ifd0.isLittleEndian();
ms.sizeX = (int) ifd.getImageWidth() / channelCount;
ms.sizeY = (int) ifd.getImageLength();
ms.sizeZ = 1;
ms.sizeC = channelCount;
ms.sizeT = 1;
ms.indexed = false;
ms.dimensionOrder = "XYCZT";
ms.bitsPerPixel = ifd.getIFDIntValue(IFD.BITS_PER_SAMPLE);
ms.pixelType = (ms.bitsPerPixel == 8) ? FormatTools.UINT8 : FormatTools.UINT16;
ms.imageCount = channelCount;
ms.resolutionCount = 1;
ms.thumbnail = false;
ms.metadataComplete = true;
if (!first) {
core.add(ms);
}
}
/*
* Run through the metadata store, setting the channel names
* for all the series.
*/
final MetadataStore store = getMetadataStore();
MetadataTools.populatePixels(store, this);
if (channelNames != null && channelDescs != null) {
String[] maskDescs = new String[channelCount];
for (int i = 0; i < channelCount; i++) {
maskDescs[i] = channelDescs[i] + " Mask";
}
for (int series = 0; series < ifdOffsets.length - 1; series++) {
final boolean isMask = core.get(series).pixelType == FormatTools.UINT8;
String[] descs = isMask ? maskDescs : channelDescs;
for (int channel = 0; channel < channelCount; channel++) {
store.setChannelName(descs[channel], series, channel);
String cid = MetadataTools.createLSID("Channel", series, channel) + ":";
store.setChannelID(cid + channelNames[channel], series, channel);
}
}
}
}
use of loci.formats.tiff.IFD 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.IFD 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.IFD 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);
}
}
}
}
}
}
use of loci.formats.tiff.IFD in project bioformats by openmicroscopy.
the class FV1000Reader method getOptimalTileWidth.
// -- IFormatReader API methods --
/* @see loci.formats.IFormatReader#getOptimalTileWidth() */
@Override
public int getOptimalTileWidth() {
FormatTools.assertId(currentId, true, 1);
RandomAccessInputStream plane = getPlane(getSeries(), 0);
if (plane == null)
return super.getOptimalTileWidth();
try {
TiffParser tp = new TiffParser(plane);
IFD ifd = tp.getFirstIFD();
plane.close();
return (int) ifd.getTileWidth();
} catch (FormatException e) {
LOGGER.debug("Could not retrieve tile width", e);
} catch (IOException e) {
LOGGER.debug("Could not retrieve tile width", e);
}
return super.getOptimalTileWidth();
}
Aggregations