// // LociForm.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.data.bio; import java.awt.Image; import java.awt.BorderLayout; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.rmi.RemoteException; import java.net.URL; import java.util.Hashtable; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.filechooser.FileFilter; import loci.formats.*; import loci.formats.gui.GUITools; import visad.*; import visad.data.*; import visad.java2d.DisplayImplJ2D; import visad.util.*; /** * LociForm is the VisAD data adapter for images handled by the Bio-Formats * package (loci.formats). It works by wrapping a loci.formats.IFormatReader * and/or loci.formats.IFormatWriter object. */ public class LociForm extends Form implements FormBlockReader, FormFileInformer, FormProgressInformer, MetadataReader { // -- Static fields -- private static int formCount = 0; // -- Fields -- /** Reader to use for open-related functions. */ protected IFormatReader reader; /** Writer to use for save-related functions. */ protected IFormatWriter writer; /** Percent complete for current operation. */ protected double percent; /** File filters for reader formats. */ protected FileFilter[] rFilters; /** File filters for writer formats. */ protected FileFilter[] wFilters; // -- Constructor -- /** Constructs a new LociForm that handles anything from loci.formats. */ public LociForm() { this(new ImageReader(), new ImageWriter()); } /** Constructs a new LociForm that handles the given reader. */ public LociForm(IFormatReader reader) { this(reader, null); } /** Constructs a new LociForm that handles the given writer. */ public LociForm(IFormatWriter writer) { this(null, writer); } /** Constructs a new LociForm that handles the given reader/writer pair. */ public LociForm(IFormatReader reader, IFormatWriter writer) { super("LociForm" + formCount++); this.reader = reader; this.writer = writer; } // -- LociForm API methods -- /** Gets the IFormatReader backing this form's reading capabilities. */ public IFormatReader getReader() { return reader; } /** Gets the IFormatWriter backing this form's writing capabilities. */ public IFormatWriter getWriter() { return writer; } /** Sets the frames per second to use when writing files. */ public void setFrameRate(int fps) { if (writer == null) return; writer.setFramesPerSecond(fps); } /** * A utility method for test reading a file from the command line, * and displaying the results in a simple display. */ public void testRead(String[] args) throws VisADException, IOException { if (reader == null) return; String className = getClass().getName(); String format = reader.getFormat(); if (args == null || args.length < 1) { System.out.println("To test read a file in " + format + " format, run:"); System.out.println(" java " + className + " in_file"); return; } String id = args[0]; // check type System.out.print("Checking " + format + " format "); System.out.println(isThisType(id) ? "[yes]" : "[no]"); // read pixels System.out.print("Reading " + id + " pixel data "); Data data = open(args[0]); System.out.println("[done]"); System.out.println("MathType =\n" + data.getType()); // extract types FunctionType ftype = (FunctionType) data.getType(); RealTupleType domain = ftype.getDomain(); RealType[] xy = domain.getRealComponents(); RealType time = null; if (xy.length == 1) { // assume multiple images over time time = xy[0]; ftype = (FunctionType) ftype.getRange(); domain = ftype.getDomain(); xy = domain.getRealComponents(); } MathType range = ftype.getRange(); RealType[] values = range instanceof RealType ? new RealType[] {(RealType) range} : ((RealTupleType) range).getRealComponents(); // configure display DisplayImpl display = new DisplayImplJ2D("display"); ScalarMap timeMap = null; if (time != null) { timeMap = new ScalarMap(time, Display.Animation); display.addMap(timeMap); } display.addMap(new ScalarMap(xy[0], Display.XAxis)); display.addMap(new ScalarMap(xy[1], Display.YAxis)); ScalarMap colorMap = null; if (values.length == 2 || values.length == 3) { // do separate mappings to Red, Green and Blue display.addMap(new ScalarMap(values[0], Display.Red)); display.addMap(new ScalarMap(values[1], Display.Green)); if (values.length == 3) { display.addMap(new ScalarMap(values[2], Display.Blue)); } } else { // use the first component only colorMap = new ScalarMap(values[0], Display.RGB); display.addMap(colorMap); } DataReferenceImpl ref = new DataReferenceImpl("ref"); ref.setData(data); display.addReference(ref); display.getGraphicsModeControl().setScaleEnable(true); // pop up frame JFrame frame = new JFrame(format + " Results"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JPanel p = new JPanel(); frame.setContentPane(p); p.setLayout(new BorderLayout()); p.add(display.getComponent()); if (timeMap != null) { AnimationWidget aw = new AnimationWidget(timeMap); p.add(BorderLayout.SOUTH, aw); } if (colorMap != null) { RangeWidget rw = new RangeWidget(colorMap); LabeledColorWidget lcw = new LabeledColorWidget(colorMap); p.add(BorderLayout.NORTH, rw); p.add(BorderLayout.EAST, lcw); } frame.pack(); frame.setLocation(300, 300); frame.setVisible(true); } /** Gets file filters for use with formats supported for reading. */ public FileFilter[] getReaderFilters() { if (reader == null) return null; if (rFilters == null) rFilters = GUITools.buildFileFilters(reader); return rFilters; } /** Gets file filters for use with formats supported for writing. */ public FileFilter[] getWriterFilters() { if (writer == null) return null; if (wFilters == null) wFilters = GUITools.buildFileFilters(writer); return wFilters; } // -- FormNode API methods -- /** * Opens an existing image file from the given filename. * * @return VisAD Data object containing image data */ public DataImpl open(String id) throws BadFormException, IOException, VisADException { percent = 0; int nImages = getBlockCount(id); FieldImpl[] fields = new FieldImpl[nImages]; for (int i=0; i<nImages; i++) { fields[i] = (FieldImpl) open(id, i); percent = (double) (i+1) / nImages; } DataImpl data; if (nImages == 1) data = fields[0]; else { // combine data stack into index function RealType index = RealType.getRealType("index"); FunctionType indexFunction = new FunctionType(index, fields[0].getType()); Integer1DSet indexSet = new Integer1DSet(nImages); FieldImpl indexField = new FieldImpl(indexFunction, indexSet); indexField.setSamples(fields, false); data = indexField; } close(); percent = Double.NaN; return data; } /** Saves a VisAD Data object at the given location. */ public void save(String id, Data data, boolean replace) throws BadFormException, IOException, RemoteException, VisADException { if (writer == null) throw new BadFormException("No writer"); percent = 0; FlatField[] fields = DataUtility.getImageFields(data); try { initHandler(writer, id); for (int i=0; i<fields.length; i++) { Image image; if (fields[i] instanceof ImageFlatField) { image = ((ImageFlatField) fields[i]).getImage(); } else image = DataUtility.extractImage(fields[i], false); writer.saveImage(image, i == fields.length - 1); percent = (double) (i+1) / fields.length; } } catch (FormatException exc) { throw new BadFormException(exc); } percent = Double.NaN; } /** * Adds data to an existing image file. * * @exception BadFormException Always thrown (this method not * implemented). */ public void add(String id, Data data, boolean replace) throws BadFormException { throw new BadFormException("LociForm.add"); } /** * Opens an existing image file from the given URL. * * @return VisAD data object containing image data * @exception UnimplementedException Always thrown (this method not * implemented). */ public DataImpl open(URL url) throws BadFormException, IOException, VisADException { throw new UnimplementedException("LociForm.open(URL)"); } /** Returns the data forms that are compatible with a data object. */ public FormNode getForms(Data data) { return null; } // -- FormBlockReader API methods -- /** Obtains the specified image from the given image file. */ public DataImpl open(String id, int block_number) throws BadFormException, IOException, VisADException { if (reader == null) throw new BadFormException("No reader"); BufferedImage image; try { initHandler(reader, id); image = reader.openImage(block_number); } catch (FormatException exc) { throw new BadFormException(exc); } int width = image.getWidth(), height = image.getHeight(); int num = image.getRaster().getNumBands(); RealType x = RealType.getRealType("ImageElement"); RealType y = RealType.getRealType("ImageLine"); RealType[] v = new RealType[num]; for (int i=0; i<num; i++) v[i] = RealType.getRealType("value" + i); RealTupleType domain = new RealTupleType(x, y); RealTupleType range = new RealTupleType(v); FunctionType fieldType = new FunctionType(domain, range); Linear2DSet fieldSet = new Linear2DSet(domain, 0, width - 1, width, height - 1, 0, height); ImageFlatField field = new ImageFlatField(fieldType, fieldSet); field.setImage(image); return field; } /** Determines the number of images in the given image file. */ public int getBlockCount(String id) throws BadFormException, IOException, VisADException { if (reader == null) throw new BadFormException("No reader"); initHandler(reader, id); return reader.getImageCount(); } /** Closes any open files. */ public void close() throws BadFormException, IOException, VisADException { if (reader == null) throw new BadFormException("No reader"); reader.close(); } // -- FormFileInformer API methods -- /** Checks if the given string is a valid filename for an image file. */ public boolean isThisType(String name) { if (reader == null) return false; return reader.isThisType(name); } /** Checks if the given block is a valid header for an image file. */ public boolean isThisType(byte[] block) { if (reader == null) return false; return reader.isThisType(block); } /** Returns the default file suffixes for this file format. */ public String[] getDefaultSuffixes() { if (reader != null) return reader.getSuffixes(); if (writer != null) return writer.getSuffixes(); return null; } // -- FormProgressInformer API methods -- /** Gets the percentage complete of the form's current operation. */ public double getPercentComplete() { return percent; } // -- MetadataReader API methods -- /** * Obtains the specified metadata field's value for the given file. * * @param field the name associated with the metadata field * @return the value, or null if the field doesn't exist */ public Object getMetadataValue(String id, String field) throws BadFormException, IOException, VisADException { if (reader == null) throw new BadFormException("No reader"); initHandler(reader, id); return reader.getMetadataValue(field); } /** * Obtains the hashtable containing the metadata field/value pairs from * the given image file. * * @param id the filename * @return the hashtable containing all metadata from the file */ public Hashtable getMetadata(String id) throws BadFormException, IOException, VisADException { if (reader == null) throw new BadFormException("No reader"); initHandler(reader, id); return reader.getMetadata(); } // -- Main method -- public static void main(String[] args) throws Exception { new LociForm().testRead(args); } // -- Helper methods -- public void initHandler(IFormatHandler h, String id) throws BadFormException, IOException { try { h.setId(id); } catch (FormatException exc) { throw new BadFormException(exc); } } }