// // ImageInfo.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.tools; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Hashtable; import java.util.StringTokenizer; import loci.common.ByteArrayHandle; import loci.common.DataTools; import loci.common.DebugTools; import loci.common.Location; import loci.common.RandomAccessInputStream; import loci.common.services.DependencyException; import loci.common.services.ServiceException; import loci.common.services.ServiceFactory; import loci.common.xml.XMLTools; import loci.formats.ChannelFiller; import loci.formats.ChannelMerger; import loci.formats.ChannelSeparator; import loci.formats.DimensionSwapper; import loci.formats.FilePattern; import loci.formats.FileStitcher; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.IFormatReader; import loci.formats.ImageReader; import loci.formats.ImageTools; import loci.formats.MetadataTools; import loci.formats.MinMaxCalculator; import loci.formats.MissingLibraryException; import loci.formats.gui.AWTImageTools; import loci.formats.gui.BufferedImageReader; import loci.formats.gui.ImageViewer; import loci.formats.in.DefaultMetadataOptions; import loci.formats.in.MetadataLevel; import loci.formats.in.MetadataOptions; import loci.formats.in.OMETiffReader; import loci.formats.meta.MetadataRetrieve; import loci.formats.meta.MetadataStore; import loci.formats.services.OMEXMLService; import loci.formats.services.OMEXMLServiceImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ImageInfo is a utility class for reading a file * and reporting information about it. * * <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/tools/ImageInfo.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/tools/ImageInfo.java;hb=HEAD">Gitweb</a></dd></dl> */ public class ImageInfo { // -- Constants -- private static final Logger LOGGER = LoggerFactory.getLogger(ImageInfo.class); private static final String NEWLINE = System.getProperty("line.separator"); // -- Fields -- private String id = null; private boolean printVersion = false; private boolean pixels = true; private boolean doCore = true; private boolean doMeta = true; private boolean filter = true; private boolean thumbs = false; private boolean minmax = false; private boolean merge = false; private boolean stitch = false; private boolean group = true; private boolean separate = false; private boolean expand = false; private boolean omexml = false; private boolean normalize = false; private boolean fastBlit = false; private boolean autoscale = false; private boolean preload = false; private boolean ascii = false; private boolean usedFiles = true; private boolean omexmlOnly = false; private boolean validate = true; private String omexmlVersion = null; private int start = 0; private int end = Integer.MAX_VALUE; private int series = 0; private int xCoordinate = 0, yCoordinate = 0, width = 0, height = 0; private String swapOrder = null, shuffleOrder = null; private String map = null; private String format = null; private IFormatReader reader; private IFormatReader baseReader; private MinMaxCalculator minMaxCalc; private DimensionSwapper dimSwapper; private BufferedImageReader biReader; private Double[] preGlobalMin = null, preGlobalMax = null; private Double[] preKnownMin = null, preKnownMax = null; private Double[] prePlaneMin = null, prePlaneMax = null; private boolean preIsMinMaxPop = false; // -- ImageInfo methods -- public boolean parseArgs(String[] args) { id = null; printVersion = false; pixels = true; doCore = true; doMeta = true; filter = true; thumbs = false; minmax = false; merge = false; stitch = false; group = true; separate = false; expand = false; omexml = false; normalize = false; fastBlit = false; autoscale = false; preload = false; usedFiles = true; omexmlOnly = false; validate = true; omexmlVersion = null; start = 0; end = Integer.MAX_VALUE; series = 0; xCoordinate = 0; yCoordinate = 0; width = 0; height = 0; swapOrder = null; shuffleOrder = null; map = null; if (args == null) return false; for (int i=0; i<args.length; i++) { if (args[i].startsWith("-")) { if (args[i].equals("-nopix")) pixels = false; else if (args[i].equals("-version")) printVersion = true; else if (args[i].equals("-nocore")) doCore = false; else if (args[i].equals("-nometa")) doMeta = false; else if (args[i].equals("-nofilter")) filter = false; else if (args[i].equals("-thumbs")) thumbs = true; else if (args[i].equals("-minmax")) minmax = true; else if (args[i].equals("-merge")) merge = true; else if (args[i].equals("-stitch")) stitch = true; else if (args[i].equals("-nogroup")) group = false; else if (args[i].equals("-separate")) separate = true; else if (args[i].equals("-expand")) expand = true; else if (args[i].equals("-omexml")) omexml = true; else if (args[i].equals("-normalize")) normalize = true; else if (args[i].equals("-fast")) fastBlit = true; else if (args[i].equals("-autoscale")) autoscale = true; else if (args[i].equals("-novalid")) validate = false; else if (args[i].equals("-debug")) { DebugTools.enableLogging("DEBUG"); } else if (args[i].equals("-omexml-only")) { omexmlOnly = true; omexml = true; DebugTools.enableLogging("OFF"); } else if (args[i].equals("-preload")) preload = true; else if (args[i].equals("-ascii")) ascii = true; else if (args[i].equals("-nousedfiles")) usedFiles = false; else if (args[i].equals("-xmlversion")) omexmlVersion = args[++i]; else if (args[i].equals("-crop")) { StringTokenizer st = new StringTokenizer(args[++i], ","); xCoordinate = Integer.parseInt(st.nextToken()); yCoordinate = Integer.parseInt(st.nextToken()); width = Integer.parseInt(st.nextToken()); height = Integer.parseInt(st.nextToken()); } else if (args[i].equals("-range")) { try { start = Integer.parseInt(args[++i]); end = Integer.parseInt(args[++i]); } catch (NumberFormatException exc) { } } else if (args[i].equals("-series")) { try { series = Integer.parseInt(args[++i]); } catch (NumberFormatException exc) { } } else if (args[i].equals("-swap")) { swapOrder = args[++i].toUpperCase(); } else if (args[i].equals("-shuffle")) { shuffleOrder = args[++i].toUpperCase(); } else if (args[i].equals("-map")) map = args[++i]; else if (args[i].equals("-format")) format = args[++i]; else { LOGGER.error("Found unknown command flag: {}; exiting.", args[i]); return false; } } else { if (id == null) id = args[i]; else { LOGGER.error("Found unknown argument: {}; exiting.", args[i]); return false; } } } return true; } public void printUsage() { String fmt = reader instanceof ImageReader ? "any" : reader.getFormat(); String[] s = { "To test read a file in " + fmt + " format, run:", " showinf file [-nopix] [-nocore] [-nometa] [-thumbs] [-minmax] ", " [-merge] [-nogroup] [-stitch] [-separate] [-expand] [-omexml]", " [-normalize] [-fast] [-debug] [-range start end] [-series num]", " [-swap inputOrder] [-shuffle outputOrder] [-map id] [-preload]", " [-crop x,y,w,h] [-autoscale] [-novalid] [-omexml-only]", " [-format Format]", "", " -version: print the library version and exit", " file: the image file to read", " -nopix: read metadata only, not pixels", " -nocore: do not output core metadata", " -nometa: do not parse format-specific metadata table", " -nofilter: do not filter metadata fields", " -thumbs: read thumbnails instead of normal pixels", " -minmax: compute min/max statistics", " -merge: combine separate channels into RGB image", " -nogroup: force multi-file datasets to be read as individual files", " -stitch: stitch files with similar names", " -separate: split RGB image into separate channels", " -expand: expand indexed color to RGB", " -omexml: populate OME-XML metadata", " -normalize: normalize floating point images*", " -fast: paint RGB images as quickly as possible*", " -debug: turn on debugging output", " -range: specify range of planes to read (inclusive)", " -series: specify which image series to read", " -swap: override the default input dimension order", " -shuffle: override the default output dimension order", " -map: specify file on disk to which name should be mapped", " -preload: pre-read entire file into a buffer; significantly", " reduces the time required to read the images, but", " requires more memory", " -crop: crop images before displaying; argument is 'x,y,w,h'", " -autoscale: used in combination with '-fast' to automatically adjust", " brightness and contrast", " -novalid: do not perform validation of OME-XML", "-omexml-only: only output the generated OME-XML", " -format: read file with a particular reader (e.g., ZeissZVI)", "", "* = may result in loss of precision", "" }; for (int i=0; i<s.length; i++) LOGGER.info(s[i]); } public void setReader(IFormatReader reader) { this.reader = reader; } public void createReader() { if (reader != null) return; // reader was set programmatically if (format != null) { // create reader of a specific format type try { Class<?> c = Class.forName("loci.formats.in." + format + "Reader"); reader = (IFormatReader) c.newInstance(); } catch (ClassNotFoundException exc) { LOGGER.warn("Unknown reader: {}", format); LOGGER.debug("", exc); } catch (InstantiationException exc) { LOGGER.warn("Cannot instantiate reader: {}", format); LOGGER.debug("", exc); } catch (IllegalAccessException exc) { LOGGER.warn("Cannot access reader: {}", format); LOGGER.debug("", exc); } } if (reader == null) reader = new ImageReader(); baseReader = reader; } public void mapLocation() throws IOException { if (map != null) Location.mapId(id, map); else if (preload) { RandomAccessInputStream f = new RandomAccessInputStream(id); int len = (int) f.length(); LOGGER.info("Caching {} bytes:", len); byte[] b = new byte[len]; int blockSize = 8 * 1024 * 1024; // 8 MB int read = 0, left = len; while (left > 0) { int r = f.read(b, read, blockSize < left ? blockSize : left); read += r; left -= r; float ratio = (float) read / len; int p = (int) (100 * ratio); LOGGER.info("\tRead {} bytes ({}% complete)", read, p); } f.close(); ByteArrayHandle file = new ByteArrayHandle(b); Location.mapFile(id, file); } } public void configureReaderPreInit() throws FormatException, IOException { if (omexml) { reader.setOriginalMetadataPopulated(true); try { ServiceFactory factory = new ServiceFactory(); OMEXMLService service = factory.getInstance(OMEXMLService.class); reader.setMetadataStore( service.createOMEXMLMetadata(null, omexmlVersion)); } catch (DependencyException de) { throw new MissingLibraryException(OMEXMLServiceImpl.NO_OME_XML_MSG, de); } catch (ServiceException se) { throw new FormatException(se); } } // check file format if (reader instanceof ImageReader) { // determine format ImageReader ir = (ImageReader) reader; if (new Location(id).exists()) { LOGGER.info("Checking file format [{}]", ir.getFormat(id)); } } else { // verify format LOGGER.info("Checking {} format [{}]", reader.getFormat(), reader.isThisType(id) ? "yes" : "no"); } LOGGER.info("Initializing reader"); if (stitch) { reader = new FileStitcher(reader, true); Location f = new Location(id); String pat = null; if (!f.exists()) { ((FileStitcher) reader).setUsingPatternIds(true); pat = id; } else { pat = FilePattern.findPattern(f); } if (pat != null) id = pat; } if (expand) reader = new ChannelFiller(reader); if (separate) reader = new ChannelSeparator(reader); if (merge) reader = new ChannelMerger(reader); minMaxCalc = null; if (minmax || autoscale) reader = minMaxCalc = new MinMaxCalculator(reader); dimSwapper = null; if (swapOrder != null || shuffleOrder != null) { reader = dimSwapper = new DimensionSwapper(reader); } reader = biReader = new BufferedImageReader(reader); reader.close(); reader.setNormalized(normalize); reader.setMetadataFiltered(filter); reader.setGroupFiles(group); MetadataOptions metaOptions = new DefaultMetadataOptions(doMeta ? MetadataLevel.ALL : MetadataLevel.MINIMUM); reader.setMetadataOptions(metaOptions); } public void configureReaderPostInit() { if (swapOrder != null) dimSwapper.swapDimensions(swapOrder); if (shuffleOrder != null) dimSwapper.setOutputOrder(shuffleOrder); } public void checkWarnings() { if (!normalize && (reader.getPixelType() == FormatTools.FLOAT || reader.getPixelType() == FormatTools.DOUBLE)) { LOGGER.warn(""); LOGGER.warn("Java does not support " + "display of unnormalized floating point data."); LOGGER.warn("Please use the '-normalize' option " + "to avoid receiving a cryptic exception."); } if (reader.isRGB() && reader.getRGBChannelCount() > 4) { LOGGER.warn(""); LOGGER.warn("Java does not support merging more than 4 channels."); LOGGER.warn("Please use the '-separate' option " + "to avoid losing channels beyond the 4th."); } } public void readCoreMetadata() throws FormatException, IOException { if (!doCore) return; // skip core metadata printout // read basic metadata LOGGER.info(""); LOGGER.info("Reading core metadata"); LOGGER.info("{} = {}", stitch ? "File pattern" : "Filename", stitch ? id : reader.getCurrentFile()); if (map != null) LOGGER.info("Mapped filename = {}", map); if (usedFiles) { String[] used = reader.getUsedFiles(); boolean usedValid = used != null && used.length > 0; if (usedValid) { for (int u=0; u<used.length; u++) { if (used[u] == null) { usedValid = false; break; } } } if (!usedValid) { LOGGER.warn("************ invalid used files list ************"); } if (used == null) { LOGGER.info("Used files = null"); } else if (used.length == 0) { LOGGER.info("Used files = []"); } else if (used.length > 1) { LOGGER.info("Used files:"); for (int u=0; u<used.length; u++) LOGGER.info("\t{}", used[u]); } else if (!id.equals(used[0])) { LOGGER.info("Used files = [{}]", used[0]); } } int seriesCount = reader.getSeriesCount(); LOGGER.info("Series count = {}", seriesCount); MetadataStore ms = reader.getMetadataStore(); MetadataRetrieve mr = ms instanceof MetadataRetrieve ? (MetadataRetrieve) ms : null; for (int j=0; j<seriesCount; j++) { reader.setSeries(j); // read basic metadata for series #i int imageCount = reader.getImageCount(); boolean rgb = reader.isRGB(); int sizeX = reader.getSizeX(); int sizeY = reader.getSizeY(); int sizeZ = reader.getSizeZ(); int sizeC = reader.getSizeC(); int sizeT = reader.getSizeT(); int pixelType = reader.getPixelType(); int validBits = reader.getBitsPerPixel(); int effSizeC = reader.getEffectiveSizeC(); int rgbChanCount = reader.getRGBChannelCount(); boolean indexed = reader.isIndexed(); boolean falseColor = reader.isFalseColor(); byte[][] table8 = reader.get8BitLookupTable(); short[][] table16 = reader.get16BitLookupTable(); int[] cLengths = reader.getChannelDimLengths(); String[] cTypes = reader.getChannelDimTypes(); int thumbSizeX = reader.getThumbSizeX(); int thumbSizeY = reader.getThumbSizeY(); boolean little = reader.isLittleEndian(); String dimOrder = reader.getDimensionOrder(); boolean orderCertain = reader.isOrderCertain(); boolean thumbnail = reader.isThumbnailSeries(); boolean interleaved = reader.isInterleaved(); boolean metadataComplete = reader.isMetadataComplete(); // output basic metadata for series #i String seriesName = mr == null ? null : mr.getImageName(j); LOGGER.info("Series #{}{}{}:", new Object[] {j, seriesName == null ? " " : " -- ", seriesName == null ? "" : seriesName}); LOGGER.info("\tImage count = {}", imageCount); LOGGER.info("\tRGB = {} ({}) {}", new Object[] {rgb, rgbChanCount, merge ? "(merged)" : separate ? "(separated)" : ""}); if (rgb != (rgbChanCount != 1)) { LOGGER.warn("\t************ RGB mismatch ************"); } LOGGER.info("\tInterleaved = {}", interleaved); StringBuilder sb = new StringBuilder(); sb.append("\tIndexed = "); sb.append(indexed); sb.append(" ("); sb.append(!falseColor); sb.append(" color"); if (table8 != null) { sb.append(", 8-bit LUT: "); sb.append(table8.length); sb.append(" x "); sb.append(table8[0] == null ? "null" : "" + table8[0].length); } if (table16 != null) { sb.append(", 16-bit LUT: "); sb.append(table16.length); sb.append(" x "); sb.append(table16[0] == null ? "null" : "" + table16[0].length); } sb.append(")"); LOGGER.info(sb.toString()); if (table8 != null && table16 != null) { LOGGER.warn("\t************ multiple LUTs ************"); } LOGGER.info("\tWidth = {}", sizeX); LOGGER.info("\tHeight = {}", sizeY); LOGGER.info("\tSizeZ = {}", sizeZ); LOGGER.info("\tSizeT = {}", sizeT); sb.setLength(0); sb.append("\tSizeC = "); sb.append(sizeC); if (sizeC != effSizeC) { sb.append(" (effectively "); sb.append(effSizeC); sb.append(")"); } int cProduct = 1; if (cLengths.length == 1 && FormatTools.CHANNEL.equals(cTypes[0])) { cProduct = cLengths[0]; } else { sb.append(" ("); for (int i=0; i<cLengths.length; i++) { if (i > 0) sb.append(" x "); sb.append(cLengths[i]); sb.append(" "); sb.append(cTypes[i]); cProduct *= cLengths[i]; } sb.append(")"); } LOGGER.info(sb.toString()); if (cLengths.length == 0 || cProduct != sizeC) { LOGGER.warn("\t************ C dimension mismatch ************"); } if (imageCount != sizeZ * effSizeC * sizeT) { LOGGER.info("\t************ ZCT mismatch ************"); } LOGGER.info("\tThumbnail size = {} x {}", thumbSizeX, thumbSizeY); LOGGER.info("\tEndianness = {}", little ? "intel (little)" : "motorola (big)"); LOGGER.info("\tDimension order = {} ({})", dimOrder, orderCertain ? "certain" : "uncertain"); LOGGER.info("\tPixel type = {}", FormatTools.getPixelTypeString(pixelType)); LOGGER.info("\tValid bits per pixel = {}", validBits); LOGGER.info("\tMetadata complete = {}", metadataComplete); LOGGER.info("\tThumbnail series = {}", thumbnail); if (doMeta) { LOGGER.info("\t-----"); int[] indices; if (imageCount > 6) { int q = imageCount / 2; indices = new int[] { 0, q - 2, q - 1, q, q + 1, q + 2, imageCount - 1 }; } else if (imageCount > 2) { indices = new int[] {0, imageCount / 2, imageCount - 1}; } else if (imageCount > 1) indices = new int[] {0, 1}; else indices = new int[] {0}; int[][] zct = new int[indices.length][]; int[] indices2 = new int[indices.length]; sb.setLength(0); for (int i=0; i<indices.length; i++) { zct[i] = reader.getZCTCoords(indices[i]); indices2[i] = reader.getIndex(zct[i][0], zct[i][1], zct[i][2]); sb.append("\tPlane #"); sb.append(indices[i]); sb.append(" <=> Z "); sb.append(zct[i][0]); sb.append(", C "); sb.append(zct[i][1]); sb.append(", T "); sb.append(zct[i][2]); if (indices[i] != indices2[i]) { sb.append(" [mismatch: "); sb.append(indices2[i]); sb.append("]"); sb.append(NEWLINE); } else sb.append(NEWLINE); } LOGGER.info(sb.toString()); } } } public void initPreMinMaxValues() throws FormatException, IOException { // get a priori min/max values preGlobalMin = preGlobalMax = null; preKnownMin = preKnownMax = null; prePlaneMin = prePlaneMax = null; preIsMinMaxPop = false; if (minmax) { int sizeC = reader.getSizeC(); preGlobalMin = new Double[sizeC]; preGlobalMax = new Double[sizeC]; preKnownMin = new Double[sizeC]; preKnownMax = new Double[sizeC]; for (int c=0; c<sizeC; c++) { preGlobalMin[c] = minMaxCalc.getChannelGlobalMinimum(c); preGlobalMax[c] = minMaxCalc.getChannelGlobalMaximum(c); preKnownMin[c] = minMaxCalc.getChannelKnownMinimum(c); preKnownMax[c] = minMaxCalc.getChannelKnownMaximum(c); } prePlaneMin = minMaxCalc.getPlaneMinimum(0); prePlaneMax = minMaxCalc.getPlaneMaximum(0); preIsMinMaxPop = minMaxCalc.isMinMaxPopulated(); } } public void printMinMaxValues() throws FormatException, IOException { // get computed min/max values int sizeC = reader.getSizeC(); Double[] globalMin = new Double[sizeC]; Double[] globalMax = new Double[sizeC]; Double[] knownMin = new Double[sizeC]; Double[] knownMax = new Double[sizeC]; for (int c=0; c<sizeC; c++) { globalMin[c] = minMaxCalc.getChannelGlobalMinimum(c); globalMax[c] = minMaxCalc.getChannelGlobalMaximum(c); knownMin[c] = minMaxCalc.getChannelKnownMinimum(c); knownMax[c] = minMaxCalc.getChannelKnownMaximum(c); } Double[] planeMin = minMaxCalc.getPlaneMinimum(0); Double[] planeMax = minMaxCalc.getPlaneMaximum(0); boolean isMinMaxPop = minMaxCalc.isMinMaxPopulated(); // output min/max results LOGGER.info(""); LOGGER.info("Min/max values:"); for (int c=0; c<sizeC; c++) { LOGGER.info("\tChannel {}:", c); LOGGER.info("\t\tGlobal minimum = {} (initially {})", globalMin[c], preGlobalMin[c]); LOGGER.info("\t\tGlobal maximum = {} (initially {})", globalMax[c], preGlobalMax[c]); LOGGER.info("\t\tKnown minimum = {} (initially {})", knownMin[c], preKnownMin[c]); LOGGER.info("\t\tKnown maximum = {} (initially {})", knownMax[c], preKnownMax[c]); } StringBuilder sb = new StringBuilder(); sb.append("\tFirst plane minimum(s) ="); if (planeMin == null) sb.append(" none"); else { for (int subC=0; subC<planeMin.length; subC++) { sb.append(" "); sb.append(planeMin[subC]); } } sb.append(" (initially"); if (prePlaneMin == null) sb.append(" none"); else { for (int subC=0; subC<prePlaneMin.length; subC++) { sb.append(" "); sb.append(prePlaneMin[subC]); } } sb.append(")"); LOGGER.info(sb.toString()); sb.setLength(0); sb.append("\tFirst plane maximum(s) ="); if (planeMax == null) sb.append(" none"); else { for (int subC=0; subC<planeMax.length; subC++) { sb.append(" "); sb.append(planeMax[subC]); } } sb.append(" (initially"); if (prePlaneMax == null) sb.append(" none"); else { for (int subC=0; subC<prePlaneMax.length; subC++) { sb.append(" "); sb.append(prePlaneMax[subC]); } } sb.append(")"); LOGGER.info(sb.toString()); LOGGER.info("\tMin/max populated = {} (initially {})", isMinMaxPop, preIsMinMaxPop); } public void readPixels() throws FormatException, IOException { String seriesLabel = reader.getSeriesCount() > 1 ? (" series #" + series) : ""; LOGGER.info(""); int num = reader.getImageCount(); if (start < 0) start = 0; if (start >= num) start = num - 1; if (end < 0) end = 0; if (end >= num) end = num - 1; if (end < start) end = start; LOGGER.info("Reading{} pixel data ({}-{})", new Object[] {seriesLabel, start, end}); int sizeX = reader.getSizeX(); int sizeY = reader.getSizeY(); if (width == 0) width = sizeX; if (height == 0) height = sizeY; int pixelType = reader.getPixelType(); BufferedImage[] images = new BufferedImage[end - start + 1]; long s = System.currentTimeMillis(); long timeLastLogged = s; for (int i=start; i<=end; i++) { if (!fastBlit) { images[i - start] = thumbs ? biReader.openThumbImage(i) : biReader.openImage(i, xCoordinate, yCoordinate, width, height); } else { byte[] b = thumbs ? reader.openThumbBytes(i) : reader.openBytes(i, xCoordinate, yCoordinate, width, height); Object pix = DataTools.makeDataArray(b, FormatTools.getBytesPerPixel(pixelType), FormatTools.isFloatingPoint(pixelType), reader.isLittleEndian()); Double min = null, max = null; if (autoscale) { Double[] planeMin = minMaxCalc.getPlaneMinimum(i); Double[] planeMax = minMaxCalc.getPlaneMaximum(i); if (planeMin != null && planeMax != null) { min = planeMin[0]; max = planeMax[0]; for (int j=1; j<planeMin.length; j++) { if (planeMin[j].doubleValue() < min.doubleValue()) { min = planeMin[j]; } if (planeMax[j].doubleValue() > max.doubleValue()) { max = planeMax[j]; } } } } else if (normalize) { min = new Double(0); max = new Double(1); } if (normalize) { if (pix instanceof float[]) { pix = DataTools.normalizeFloats((float[]) pix); } else if (pix instanceof double[]) { pix = DataTools.normalizeDoubles((double[]) pix); } } images[i - start] = AWTImageTools.makeImage(ImageTools.make24Bits(pix, sizeX, sizeY, reader.isInterleaved(), false, min, max), sizeX, sizeY, FormatTools.isSigned(pixelType)); } if (images[i - start] == null) { LOGGER.warn("\t************ Failed to read plane #{} ************", i); } if (reader.isIndexed() && reader.get8BitLookupTable() == null && reader.get16BitLookupTable() == null) { LOGGER.warn("\t************ no LUT for plane #{} ************", i); } // check for pixel type mismatch int pixType = AWTImageTools.getPixelType(images[i - start]); if (pixType != pixelType && pixType != pixelType + 1 && !fastBlit) { LOGGER.info("\tPlane #{}: pixel type mismatch: {}/{}", new Object[] {i, FormatTools.getPixelTypeString(pixType), FormatTools.getPixelTypeString(pixelType)}); } else { // log number of planes read every second or so long t = System.currentTimeMillis(); if (i == end || (t - timeLastLogged) / 1000 > 0) { int current = i - start + 1; int total = end - start + 1; int percent = 100 * current / total; LOGGER.info("\tRead {}/{} planes ({}%)", new Object[] { current, total, percent }); timeLastLogged = t; } } } long e = System.currentTimeMillis(); LOGGER.info("[done]"); // output timing results float sec = (e - s) / 1000f; float avg = (float) (e - s) / images.length; LOGGER.info("{}s elapsed ({}ms per plane)", sec, avg); if (minmax) printMinMaxValues(); // display pixels in image viewer if (ascii) { for (int i=0; i<images.length; i++) { final BufferedImage img = images[i]; LOGGER.info(""); LOGGER.info("Image #{}:", i); LOGGER.info(new AsciiImage(img).toString()); } } else { LOGGER.info(""); LOGGER.info("Launching image viewer"); ImageViewer viewer = new ImageViewer(); viewer.setImages(reader, images); viewer.setVisible(true); } } public void printGlobalMetadata() { LOGGER.info(""); LOGGER.info("Reading global metadata"); Hashtable<String, Object> meta = reader.getGlobalMetadata(); String[] keys = MetadataTools.keys(meta); for (String key : keys) { LOGGER.info("{}: {}", key, meta.get(key)); } } public void printOriginalMetadata() { String seriesLabel = reader.getSeriesCount() > 1 ? (" series #" + series) : ""; LOGGER.info(""); LOGGER.info("Reading{} metadata", seriesLabel); Hashtable<String, Object> meta = reader.getSeriesMetadata(); String[] keys = MetadataTools.keys(meta); for (int i=0; i<keys.length; i++) { LOGGER.info("{}: {}", keys[i], meta.get(keys[i])); } } public void printOMEXML() throws MissingLibraryException, ServiceException { LOGGER.info(""); MetadataStore ms = reader.getMetadataStore(); if (baseReader instanceof ImageReader) { baseReader = ((ImageReader) baseReader).getReader(); } if (baseReader instanceof OMETiffReader) { ms = ((OMETiffReader) baseReader).getMetadataStoreForDisplay(); } OMEXMLService service; try { ServiceFactory factory = new ServiceFactory(); service = factory.getInstance(OMEXMLService.class); } catch (DependencyException de) { throw new MissingLibraryException(OMEXMLServiceImpl.NO_OME_XML_MSG, de); } String version = service.getOMEXMLVersion(ms); if (version == null) LOGGER.info("Generating OME-XML"); else { LOGGER.info("Generating OME-XML (schema version {})", version); } if (ms instanceof MetadataRetrieve) { if (omexmlOnly) { DebugTools.enableLogging("INFO"); } String xml = service.getOMEXML((MetadataRetrieve) ms); LOGGER.info("{}", XMLTools.indentXML(xml, true)); if (omexmlOnly) { DebugTools.enableLogging("OFF"); } if (validate) { service.validateOMEXML(xml); } } else { LOGGER.info("The metadata could not be converted to OME-XML."); if (omexmlVersion == null) { LOGGER.info("The OME-XML Java library is probably not available."); } else { LOGGER.info("{} is probably not a legal schema version.", omexmlVersion); } } } /** * A utility method for reading a file from the command line, * and displaying the results in a simple display. */ public boolean testRead(String[] args) throws FormatException, ServiceException, IOException { DebugTools.enableLogging("INFO"); boolean validArgs = parseArgs(args); if (!validArgs) return false; if (printVersion) { LOGGER.info("Version: {}", FormatTools.VERSION); LOGGER.info("VCS revision: {}", FormatTools.VCS_REVISION); LOGGER.info("Build date: {}", FormatTools.DATE); return true; } createReader(); if (id == null) { printUsage(); return false; } mapLocation(); configureReaderPreInit(); // initialize reader long s = System.currentTimeMillis(); reader.setId(id); long e = System.currentTimeMillis(); float sec = (e - s) / 1000f; LOGGER.info("Initialization took {}s", sec); configureReaderPostInit(); checkWarnings(); readCoreMetadata(); reader.setSeries(series); initPreMinMaxValues(); // read pixels if (pixels) readPixels(); // read format-specific metadata table if (doMeta) { printGlobalMetadata(); printOriginalMetadata(); } // output and validate OME-XML if (omexml) printOMEXML(); if (!pixels) { reader.close(); } return true; } // -- Main method -- public static void main(String[] args) throws Exception { if (!new ImageInfo().testRead(args)) System.exit(1); } }