Loading .gitignore +2 −1 Original line number Diff line number Diff line Loading @@ -8,4 +8,5 @@ attic *.log FOCUS-PSF* src/main/resources/trained_model bioformats No newline at end of file bioformats*.* metadata*.* pom.xml +2 −1 Original line number Diff line number Diff line Loading @@ -88,7 +88,8 @@ <dependency> <groupId>ome</groupId> <artifactId>loci_tools</artifactId> <version>5.9.0</version> <version>6.1.0-SNAPSHOT</version> <type>java-source</type> </dependency> </dependencies> Loading src/main/java/EyesisTiff.java +104 −72 Original line number Diff line number Diff line Loading @@ -31,21 +31,32 @@ import java.awt.image.ColorModel; import java.awt.image.DataBufferInt; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Hashtable; import java.util.Iterator; import java.util.Properties; import java.util.Set; import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.elphel.imagej.readers.ElphelTiffReader; //import org.apache.log4j.Logger; Loading @@ -55,20 +66,15 @@ import ij.WindowManager; import ij.io.FileInfo; import ij.process.FloatProcessor; import ij.process.ImageProcessor; import loci.common.ByteArrayHandle; 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.formats.ClassList; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.IFormatReader; import loci.formats.ImageReader; //import loci.formats.in.TiffReader; import loci.formats.meta.IMetadata; import loci.formats.meta.MetadataStore; import loci.formats.services.OMEXMLService; import loci.formats.tiff.IFD; import loci.formats.tiff.IFDList; Loading @@ -86,6 +92,7 @@ public class EyesisTiff { defaultClasses = new ClassList<IFormatReader>( EyesisTiff.class.getClassLoader().getResource("readers.txt").getFile(), // @param file Configuration file containing the list of classes. // EyesisTiff.class.getClassLoader().getResource("readers1.txt").getFile(), // @param file Configuration file containing the list of classes. IFormatReader.class, // @param base Base class to which all classes are assignable. null); // @param location Class indicating which package to search for the file. } Loading @@ -109,43 +116,14 @@ public class EyesisTiff { } public ImagePlus readTiff(String path) { // TiffReader tiffReader = new TiffReader(); // tiffReader.initFile(path); // read in entire file // TODO: add option to get URL //https://docs.openmicroscopy.org/bio-formats/5.9.2/developers/in-memory.html System.out.println("Reading file into memory from disk: "+path); File inputFile = new File(path); int fileSize = (int) inputFile.length(); DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(inputFile)); } catch (FileNotFoundException e) { System.out.println("File not found: "+path); return readTiff(path, "STD_"); // null); } byte[] inBytes = new byte[fileSize]; try { in.readFully(inBytes); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(fileSize + " bytes read."); // determine input file suffix String fileName = inputFile.getName(); int dot = fileName.lastIndexOf("."); String suffix = dot < 0 ? "" : fileName.substring(dot); public ImagePlus readTiff(String path, String std ) { // std - include non-elphel properties with prefix std String inId = null; inId = path; // map input id string to input byte array String inId = "inBytes" + suffix; Location.mapFile(inId, new ByteArrayHandle(inBytes)); // read data from byte array using ImageReader System.out.println(); System.out.println("Reading image data from memory..."); // ServiceFactory factory = null; try { factory = new ServiceFactory(); Loading @@ -153,6 +131,7 @@ public class EyesisTiff { // TODO Auto-generated catch block e.printStackTrace(); } OMEXMLService service = null; try { service = factory.getInstance(OMEXMLService.class); Loading @@ -160,6 +139,7 @@ public class EyesisTiff { // TODO Auto-generated catch block e.printStackTrace(); } IMetadata omeMeta = null; try { omeMeta = service.createOMEXMLMetadata(); Loading @@ -174,8 +154,13 @@ public class EyesisTiff { //https://www.javatips.net/api/libbio-formats-java-master/components/scifio/src/loci/formats/in/BaseTiffReader.java //https://docs.openmicroscopy.org/bio-formats/5.7.2/developers/reader-guide.html //https://docs.openmicroscopy.org/bio-formats/5.9.2/developers/java-library.html#file-reading-and-performance //defaultClasses = new ClassList<IFormatReader>(IFormatReader.class); // ClassList<IFormatReader> cl0 = getCustomReaderClasses(); // new ClassList<IFormatReader>(IFormatReader.class); ClassList<IFormatReader> classList = new ClassList<IFormatReader>(IFormatReader.class); classList.addClass(com.elphel.imagej.readers.ElphelTiffReader.class); ImageReader reader = new ImageReader(getCustomReaderClasses()); // BaseTiffReader reader = new BaseTiffReader("Base_tiff_reader","tiff"); // ImageReader reader = new ImageReader(classList); reader.setMetadataStore(omeMeta); try { reader.setId(inId); Loading @@ -187,32 +172,10 @@ public class EyesisTiff { //e.printStackTrace(); } /* read-end */ int seriesCount = reader.getSeriesCount(); int imageCount = reader.getImageCount(); int sizeX = reader.getSizeX(); int sizeY = reader.getSizeY(); int sizeZ = reader.getSizeZ(); int sizeC = reader.getSizeC(); int sizeT = reader.getSizeT(); int bpp = reader.getBitsPerPixel(); int pixelType = reader.getPixelType(); java.util.List<CoreMetadata> cmd = reader.getCoreMetadataList(); java.util.Hashtable<java.lang.String,java.lang.Object> gmd = reader.getGlobalMetadata(); MetadataStore mtds = reader.getMetadataStore(); IFormatReader ifr = reader.getReader(); IFormatReader[] ifrs = reader.getReaders(); // all available readers? // output some details System.out.println("Series count: " + seriesCount); System.out.println("First series:"); System.out.println("\tImage count = " + imageCount); System.out.println("\tSizeX = " + sizeX); System.out.println("\tSizeY = " + sizeY); System.out.println("\tSizeZ = " + sizeZ); System.out.println("\tSizeC = " + sizeC); System.out.println("\tSizeT = " + sizeT); System.out.println("\tbppT = " + bpp); System.out.println("\treader = " + ifr.toString()); System.out.println("\tpixelType = " + pixelType); // 3 byte [] bytes = null; ImagePlus imp= null; try { Loading Loading @@ -245,11 +208,26 @@ public class EyesisTiff { ImageProcessor ip=new FloatProcessor(reader.getSizeX(), reader.getSizeY()); ip.setPixels(pixels); ip.resetMinAndMax(); // imp = new ImagePlus(fileName, ip); // original jp46 reader had full path as title imp = new ImagePlus(path, ip); // original jp46 reader had full path as title Hashtable<String, Object> meta_hash = reader.getGlobalMetadata(); String prefix = ElphelTiffReader.ELPHEL_PROPERTY_PREFIX; String imageName = path; String imageNameKey = prefix+ElphelTiffReader.CONTENT_FILENAME; if (meta_hash.containsKey(imageNameKey)) { imageName = meta_hash.get(imageNameKey).toString(); } imp = new ImagePlus(imageName, ip); // original jp46 reader had full path as title // first - save all as properties, later - only ELPHEL_* for (String key:meta_hash.keySet()) { if (key.startsWith(prefix)) { imp.setProperty(key.substring(prefix.length()), meta_hash.get(key).toString()); } else if (std != null) { imp.setProperty(std+(key.replace(" ","_")), meta_hash.get(key).toString()); } } encodeProperiesToInfo(imp); } // ImagePlus imp= makeArrays(pixels, width, height, title); try { reader.close(); } catch (IOException e) { Loading Loading @@ -662,4 +640,58 @@ the type of pixel data in this file getPixelType() return sb.toString(); } // copied from JP46_Reader_camera.java public ImagePlus encodeProperiesToInfo(ImagePlus imp){ String info="<?xml version=\"1.0\" encoding=\"UTF-8\"?><properties>"; Set<Object> jp4_set; Properties jp4_prop; Iterator<Object> itr; String str; jp4_prop=imp.getProperties(); if (jp4_prop!=null) { jp4_set=jp4_prop.keySet(); itr=jp4_set.iterator(); while(itr.hasNext()) { str = (String) itr.next(); // if (!str.equals("Info")) info+="<"+str+">\""+jp4_prop.getProperty(str)+"\"</"+str+">"; if (!str.equals("Info")) info+="<"+str+">"+jp4_prop.getProperty(str)+"</"+str+">"; } } info+="</properties>\n"; imp.setProperty("Info", info); return imp; } public boolean decodeProperiesFromInfo(ImagePlus imp){ if (imp.getProperty("Info")==null) return false; String xml= (String) imp.getProperty("Info"); DocumentBuilder db=null; try { db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException e) { return false; } InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); Document doc = null; try { doc = db.parse(is); } catch (SAXException e) { return false; } catch (IOException e) { return false; } NodeList allNodes=doc.getDocumentElement().getElementsByTagName("*"); for (int i=0;i<allNodes.getLength();i++) { String name= allNodes.item(i).getNodeName(); String value=allNodes.item(i).getFirstChild().getNodeValue(); imp.setProperty(name, value); } return true; } } src/main/java/JP46_Reader_camera.java +72 −7 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.elphel.imagej.readers.ImagejJp4Tiff; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; Loading @@ -75,6 +77,7 @@ import ij.process.ImageConverter; import ij.process.ImageProcessor; import ij.text.TextWindow; import loci.common.RandomAccessInputStream; import loci.formats.FormatException; import loci.formats.tiff.IFD; import loci.formats.tiff.IFDList; import loci.formats.tiff.TiffParser; Loading @@ -96,7 +99,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { static File dir; public String camera_url = "http://192.168.0.236:8081/"; public String camera_url = "http://192.168.0.36:2323/"; public String camera_img = "bimg"; public String camera_img_new = "towp/wait/bimg"; // will always wait for the next image (repetitive acquisitions get new images) public String camera_jp46settings = ""; Loading Loading @@ -322,6 +325,10 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { if (demux) showImage=false; double [] xtraExif=new double[1]; // ExposureTime double [] lla = null; imp = openJpegOrGif(directory, fileName); imp.show(); if (imp != null) return imp; try { imp = openJpegOrGif(directory, fileName); if (imp == null) { Loading Loading @@ -390,7 +397,35 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { String arg, boolean scale, ImagePlus imp_src, boolean showImage) { boolean showImage) { // ImagePlus imptiff = (new EyesisTiff()).readTiff(url); ImagePlus imptiff = null; try { imptiff = (new ImagejJp4Tiff()).readTiffJp4(url); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (FormatException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (imptiff!=null) { imptiff.show(); if (imptiff.getType()==ImagePlus.COLOR_RGB) { checkGrayJpegTo32Bits(imptiff); } IJ.showStatus("Converting to 32-bits"); new ImageConverter(imptiff).convertToGray32(); FileInfo fi = imptiff.getFileInfo(); // fi.fileName = name; // fi.directory = dir; fi.fileFormat = FileInfo.TIFF; imptiff.setFileInfo(fi); return imptiff; } long[] ElphelMakerNote=null; ImagePlus imp = null; boolean reuse_imp=false; Loading Loading @@ -1042,6 +1077,35 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { /* Modified from Opener.java */ ImagePlus openJpegOrGif(String dir, String name) { // Testing new readers ImagePlus imptiff = null; // imptiff = (new EyesisTiff()).readTiff(dir+name); try { imptiff = (new ImagejJp4Tiff()).readTiffJp4(dir+name); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (FormatException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (imptiff!=null) { imptiff.show(); if (imptiff.getType()==ImagePlus.COLOR_RGB) { checkGrayJpegTo32Bits(imptiff); } IJ.showStatus("Converting to 32-bits"); new ImageConverter(imptiff).convertToGray32(); FileInfo fi = imptiff.getFileInfo(); fi.fileName = name; fi.directory = dir; fi.fileFormat = FileInfo.TIFF; imptiff.setFileInfo(fi); return imptiff; } ImagePlus imp = null; boolean isTiff = false; Image img = Toolkit.getDefaultToolkit().createImage(dir+name); Loading Loading @@ -1073,7 +1137,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { fi = imp.getFileInfo(); // testing /* if ((ofi!=null) && (ofi.directory!=null) && (ofi.fileFormat == FileInfo.TIFF)) { String path = ofi.directory + ofi.fileName; EyesisTiff ET = new EyesisTiff(); Loading @@ -1093,6 +1157,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { Frame log = WindowManager.getFrame("Log"); if (log!=null) log.toFront(); } */ } Loading src/main/java/com/elphel/imagej/readers/ElphelJp4Reader.java 0 → 100644 +299 −0 Original line number Diff line number Diff line /** ** -----------------------------------------------------------------------------** ** ElphelJp4Reader.java ** ** loci.format compatible reader for Elphel JP4 files ** ** ** Copyright (C) 2019 Elphel, Inc. ** ** -----------------------------------------------------------------------------** ** ** ElphelTiffReader.java 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 3 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/>. ** -----------------------------------------------------------------------------** ** */ package com.elphel.imagej.readers; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Date; import java.util.HashMap; import java.util.Hashtable; import org.apache.commons.compress.utils.IOUtils; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import loci.common.ByteArrayHandle; 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.formats.FormatException; import loci.formats.FormatTools; import loci.formats.in.ImageIOReader; import loci.formats.in.MetadataLevel; import loci.formats.services.EXIFService; //import loci.formats.services.EXIFService; import ome.xml.meta.MetadataStore; import ome.xml.model.primitives.Timestamp; //ElphelTiffReader public class ElphelJp4Reader extends ImageIOReader{ // -- Constants -- public static final String MAKER_NOTE = "Makernote"; public static final String SUB_SEC_TIME_ORIGINAL = "Sub-Sec Time Original"; public static final String EXPOSURE_TIME = "Exposure Time"; public static final String DATE_TIME_ORIGINAL = "Date/Time Original"; public static final String ELPHEL_PROPERTY_PREFIX = "ELPHEL_"; public static final String CONTENT_FILENAME = "CONTENT_FILENAME"; /** Logger for this class. */ private static final Logger LOGGER = LoggerFactory.getLogger(ElphelTiffReader.class); // -- Fields -- private URL url = null; // save here actual URL when reading file to memory private String content_fileName = null; // from Content-disposition private boolean file_initialized = false; private ElphelTiffReader elphelTiffReader = null; // private ImageReader helperReader; // -- Constructor -- /** Constructs a new Tiff reader. */ public ElphelJp4Reader() { super("JP4", new String[] {"jp4"}); // mergeSubIFDs = true; // false; suffixNecessary = true; // false suffixSufficient = true; // false; LOGGER.info("ElphelTiffReader(), after super()"); elphelTiffReader = new ElphelTiffReader(); } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(String, boolean) */ @Override public boolean isThisType(String name, boolean open) { if (open) { return super.isThisType(name, open); } return checkSuffix(name, getSuffixes()); } /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ @Override public boolean isThisType(RandomAccessInputStream stream) throws IOException { final int blockLen = 4; if (!FormatTools.validStream(stream, blockLen, false)) return false; byte[] signature = new byte[blockLen]; stream.read(signature); if (signature[0] != (byte) 0xff || signature[1] != (byte) 0xd8 || signature[2] != (byte) 0xff || (signature[3] & 0xf0) == 0) { return false; } return true; } @Override public void setId(String id) throws FormatException, IOException { // same as for tiff? LOGGER.debug("setId("+id+"). before super" ); file_initialized = false; if (Location.getIdMap().containsKey(id)) { LOGGER.debug("id '"+id+"' is already mapped" ); content_fileName = null; // id; // maybe set to null to handle externally? LOGGER.info("Starting initFile() method, read file directly"); super.setId(id); } else { // If URL, then read to memory, if normal file - use direct access url = null; // String mime = null; // use to select jp4/tiff later? Or to check it is correct content_fileName = null; try { url = new URL(id); } catch (MalformedURLException e) { LOGGER.warn("Bad URL: " + id); } if (url != null) { LOGGER.info("Starting initFile() method, read "+ id +" to memory first"); //https://www.rgagnon.com/javadetails/java-0487.html URLConnection connection = url.openConnection(); String content_disposition = connection.getHeaderField("Content-Disposition"); // raw = "attachment; filename=abc.jpg" if(content_disposition != null && content_disposition.indexOf("=") != -1) { content_fileName = content_disposition.split("=")[1]; //getting value after '=' // trim quotes content_fileName= content_fileName.substring(1, content_fileName.length()-1); } else { String mime = connection.getContentType(); int slash = mime.lastIndexOf("/"); String suffix = slash < 0 ? "" : mime.substring(slash+1); content_fileName = "unknown." + suffix; } // currentId = fileName; //??? // LOGGER.info("Mime type = "+mime); // https://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests //https://stackoverflow.com/questions/2295221/java-net-url-read-stream-to-byte InputStream is = url.openStream (); // byte[] inBytes = IOUtils.toByteArray(is); if (is != null) is.close(); LOGGER.info("Bytes read: "+ inBytes.length); Location.mapFile(content_fileName, new ByteArrayHandle(inBytes)); HashMap<String,Object> dbg_loc = Location.getIdMap(); super.setId(content_fileName); } else { // read file normally content_fileName = id; LOGGER.info("read file directly"); super.setId(id); } } //getReader // super.setId(id); LOGGER.debug("setId("+id+"). after super" ); file_initialized = true; } /* @see loci.formats.FormatReader#initFile(String) */ @Override protected void initFile(String id) throws FormatException, IOException { LOGGER.debug("initFile("+id+"), currentId="+currentId+", before super" ); try { super.initFile(id); // fails class_not_found } catch (IllegalArgumentException e) { throw new FormatException(e); } LOGGER.debug("initFile("+id+"), currentId="+currentId+", after super" ); // elphelTiffReader.setId(id); //error here - invalid tiff file // Below needs to be modified - EXIFService does not work with mapFile MetadataStore store = makeFilterMetadata(); LOGGER.info("Parsing JPEG EXIF data"); HashMap<String, String> tags = null; try { EXIFService exif = new ServiceFactory().getInstance(EXIFService.class); if (exif == null) { return; } exif.initialize(id); // Set the acquisition date Date date = exif.getCreationDate(); if (date != null) { Timestamp timestamp = new Timestamp(new DateTime(date)); store.setImageAcquisitionDate(timestamp, 0); } tags = exif.getTags(); for (String tagName : tags.keySet()) { addGlobalMeta(tagName, tags.get(tagName)); } //{Makernote=105455 131072 127570 300581 171508736 171508736 171508736 171508736 169869312 124780556 1118544 0 0 327779 648 1296, Sub-Sec Time Original=560439, Exposure Time=11167/500000 sec, Date/Time Original=2019:05:13 04:30:26} } catch (ServiceException e) { LOGGER.debug("Could not parse EXIF data", e); } catch (DependencyException e) { LOGGER.debug("Could not parse EXIF data", e); } long [] maker_note = null; double exposure = Double.NaN; String date_time = null; if (tags.containsKey(MAKER_NOTE)){ String [] smn = tags.get(MAKER_NOTE).split(" "); maker_note = new long[smn.length]; for (int i = 0; i < maker_note.length; i++) { maker_note[i] = Integer.parseInt(smn[i]); } } if (tags.containsKey(EXPOSURE_TIME)){ String [] s = tags.get(EXPOSURE_TIME).split("/"); exposure = 1.0 * Integer.parseInt(s[0]) / Integer.parseInt(s[1].split(" ")[0]); } if (tags.containsKey(DATE_TIME_ORIGINAL)){ date_time = tags.get(DATE_TIME_ORIGINAL); if (tags.containsKey(SUB_SEC_TIME_ORIGINAL)){ date_time += tags.get(SUB_SEC_TIME_ORIGINAL); } } Hashtable<String, String> property_table = ElphelMeta.getMeta( null, maker_note, exposure, date_time, true ); LOGGER.info("Created elphelMeta table, size="+property_table.size()); for (String key:property_table.keySet()) { addGlobalMeta(ELPHEL_PROPERTY_PREFIX+key,property_table.get(key)); } MetadataLevel level = getMetadataOptions().getMetadataLevel(); if (level != MetadataLevel.MINIMUM) { // Integer[] tags = ifds.get(0).keySet().toArray(new Integer[0]); // LOGGER.info("initStandardMetadata() - got "+tags.length+" tags"); } addGlobalMeta(ELPHEL_PROPERTY_PREFIX+CONTENT_FILENAME,content_fileName); } /* @see loci.formats.IFormatReader#close(boolean) */ @Override public void close(boolean fileOnly) throws IOException { HashMap<String,Object> dbg_loc = Location.getIdMap(); String saveCurrentId = currentId; currentId = null; LOGGER.info("close("+fileOnly+") before super"); super.close(fileOnly); // curerent_id == null only during actual close? LOGGER.info("close("+fileOnly+") after super"); currentId = saveCurrentId; if ((content_fileName != null) && file_initialized){ Location.mapFile(content_fileName, null); file_initialized = false; } dbg_loc = Location.getIdMap(); if (!fileOnly) { // companionFile = null; // description = null; // calibrationUnit = null; // physicalSizeZ = null; // timeIncrement = null; // xOrigin = null; // yOrigin = null; } } } Loading
.gitignore +2 −1 Original line number Diff line number Diff line Loading @@ -8,4 +8,5 @@ attic *.log FOCUS-PSF* src/main/resources/trained_model bioformats No newline at end of file bioformats*.* metadata*.*
pom.xml +2 −1 Original line number Diff line number Diff line Loading @@ -88,7 +88,8 @@ <dependency> <groupId>ome</groupId> <artifactId>loci_tools</artifactId> <version>5.9.0</version> <version>6.1.0-SNAPSHOT</version> <type>java-source</type> </dependency> </dependencies> Loading
src/main/java/EyesisTiff.java +104 −72 Original line number Diff line number Diff line Loading @@ -31,21 +31,32 @@ import java.awt.image.ColorModel; import java.awt.image.DataBufferInt; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Hashtable; import java.util.Iterator; import java.util.Properties; import java.util.Set; import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.elphel.imagej.readers.ElphelTiffReader; //import org.apache.log4j.Logger; Loading @@ -55,20 +66,15 @@ import ij.WindowManager; import ij.io.FileInfo; import ij.process.FloatProcessor; import ij.process.ImageProcessor; import loci.common.ByteArrayHandle; 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.formats.ClassList; import loci.formats.CoreMetadata; import loci.formats.FormatException; import loci.formats.IFormatReader; import loci.formats.ImageReader; //import loci.formats.in.TiffReader; import loci.formats.meta.IMetadata; import loci.formats.meta.MetadataStore; import loci.formats.services.OMEXMLService; import loci.formats.tiff.IFD; import loci.formats.tiff.IFDList; Loading @@ -86,6 +92,7 @@ public class EyesisTiff { defaultClasses = new ClassList<IFormatReader>( EyesisTiff.class.getClassLoader().getResource("readers.txt").getFile(), // @param file Configuration file containing the list of classes. // EyesisTiff.class.getClassLoader().getResource("readers1.txt").getFile(), // @param file Configuration file containing the list of classes. IFormatReader.class, // @param base Base class to which all classes are assignable. null); // @param location Class indicating which package to search for the file. } Loading @@ -109,43 +116,14 @@ public class EyesisTiff { } public ImagePlus readTiff(String path) { // TiffReader tiffReader = new TiffReader(); // tiffReader.initFile(path); // read in entire file // TODO: add option to get URL //https://docs.openmicroscopy.org/bio-formats/5.9.2/developers/in-memory.html System.out.println("Reading file into memory from disk: "+path); File inputFile = new File(path); int fileSize = (int) inputFile.length(); DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(inputFile)); } catch (FileNotFoundException e) { System.out.println("File not found: "+path); return readTiff(path, "STD_"); // null); } byte[] inBytes = new byte[fileSize]; try { in.readFully(inBytes); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(fileSize + " bytes read."); // determine input file suffix String fileName = inputFile.getName(); int dot = fileName.lastIndexOf("."); String suffix = dot < 0 ? "" : fileName.substring(dot); public ImagePlus readTiff(String path, String std ) { // std - include non-elphel properties with prefix std String inId = null; inId = path; // map input id string to input byte array String inId = "inBytes" + suffix; Location.mapFile(inId, new ByteArrayHandle(inBytes)); // read data from byte array using ImageReader System.out.println(); System.out.println("Reading image data from memory..."); // ServiceFactory factory = null; try { factory = new ServiceFactory(); Loading @@ -153,6 +131,7 @@ public class EyesisTiff { // TODO Auto-generated catch block e.printStackTrace(); } OMEXMLService service = null; try { service = factory.getInstance(OMEXMLService.class); Loading @@ -160,6 +139,7 @@ public class EyesisTiff { // TODO Auto-generated catch block e.printStackTrace(); } IMetadata omeMeta = null; try { omeMeta = service.createOMEXMLMetadata(); Loading @@ -174,8 +154,13 @@ public class EyesisTiff { //https://www.javatips.net/api/libbio-formats-java-master/components/scifio/src/loci/formats/in/BaseTiffReader.java //https://docs.openmicroscopy.org/bio-formats/5.7.2/developers/reader-guide.html //https://docs.openmicroscopy.org/bio-formats/5.9.2/developers/java-library.html#file-reading-and-performance //defaultClasses = new ClassList<IFormatReader>(IFormatReader.class); // ClassList<IFormatReader> cl0 = getCustomReaderClasses(); // new ClassList<IFormatReader>(IFormatReader.class); ClassList<IFormatReader> classList = new ClassList<IFormatReader>(IFormatReader.class); classList.addClass(com.elphel.imagej.readers.ElphelTiffReader.class); ImageReader reader = new ImageReader(getCustomReaderClasses()); // BaseTiffReader reader = new BaseTiffReader("Base_tiff_reader","tiff"); // ImageReader reader = new ImageReader(classList); reader.setMetadataStore(omeMeta); try { reader.setId(inId); Loading @@ -187,32 +172,10 @@ public class EyesisTiff { //e.printStackTrace(); } /* read-end */ int seriesCount = reader.getSeriesCount(); int imageCount = reader.getImageCount(); int sizeX = reader.getSizeX(); int sizeY = reader.getSizeY(); int sizeZ = reader.getSizeZ(); int sizeC = reader.getSizeC(); int sizeT = reader.getSizeT(); int bpp = reader.getBitsPerPixel(); int pixelType = reader.getPixelType(); java.util.List<CoreMetadata> cmd = reader.getCoreMetadataList(); java.util.Hashtable<java.lang.String,java.lang.Object> gmd = reader.getGlobalMetadata(); MetadataStore mtds = reader.getMetadataStore(); IFormatReader ifr = reader.getReader(); IFormatReader[] ifrs = reader.getReaders(); // all available readers? // output some details System.out.println("Series count: " + seriesCount); System.out.println("First series:"); System.out.println("\tImage count = " + imageCount); System.out.println("\tSizeX = " + sizeX); System.out.println("\tSizeY = " + sizeY); System.out.println("\tSizeZ = " + sizeZ); System.out.println("\tSizeC = " + sizeC); System.out.println("\tSizeT = " + sizeT); System.out.println("\tbppT = " + bpp); System.out.println("\treader = " + ifr.toString()); System.out.println("\tpixelType = " + pixelType); // 3 byte [] bytes = null; ImagePlus imp= null; try { Loading Loading @@ -245,11 +208,26 @@ public class EyesisTiff { ImageProcessor ip=new FloatProcessor(reader.getSizeX(), reader.getSizeY()); ip.setPixels(pixels); ip.resetMinAndMax(); // imp = new ImagePlus(fileName, ip); // original jp46 reader had full path as title imp = new ImagePlus(path, ip); // original jp46 reader had full path as title Hashtable<String, Object> meta_hash = reader.getGlobalMetadata(); String prefix = ElphelTiffReader.ELPHEL_PROPERTY_PREFIX; String imageName = path; String imageNameKey = prefix+ElphelTiffReader.CONTENT_FILENAME; if (meta_hash.containsKey(imageNameKey)) { imageName = meta_hash.get(imageNameKey).toString(); } imp = new ImagePlus(imageName, ip); // original jp46 reader had full path as title // first - save all as properties, later - only ELPHEL_* for (String key:meta_hash.keySet()) { if (key.startsWith(prefix)) { imp.setProperty(key.substring(prefix.length()), meta_hash.get(key).toString()); } else if (std != null) { imp.setProperty(std+(key.replace(" ","_")), meta_hash.get(key).toString()); } } encodeProperiesToInfo(imp); } // ImagePlus imp= makeArrays(pixels, width, height, title); try { reader.close(); } catch (IOException e) { Loading Loading @@ -662,4 +640,58 @@ the type of pixel data in this file getPixelType() return sb.toString(); } // copied from JP46_Reader_camera.java public ImagePlus encodeProperiesToInfo(ImagePlus imp){ String info="<?xml version=\"1.0\" encoding=\"UTF-8\"?><properties>"; Set<Object> jp4_set; Properties jp4_prop; Iterator<Object> itr; String str; jp4_prop=imp.getProperties(); if (jp4_prop!=null) { jp4_set=jp4_prop.keySet(); itr=jp4_set.iterator(); while(itr.hasNext()) { str = (String) itr.next(); // if (!str.equals("Info")) info+="<"+str+">\""+jp4_prop.getProperty(str)+"\"</"+str+">"; if (!str.equals("Info")) info+="<"+str+">"+jp4_prop.getProperty(str)+"</"+str+">"; } } info+="</properties>\n"; imp.setProperty("Info", info); return imp; } public boolean decodeProperiesFromInfo(ImagePlus imp){ if (imp.getProperty("Info")==null) return false; String xml= (String) imp.getProperty("Info"); DocumentBuilder db=null; try { db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException e) { return false; } InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); Document doc = null; try { doc = db.parse(is); } catch (SAXException e) { return false; } catch (IOException e) { return false; } NodeList allNodes=doc.getDocumentElement().getElementsByTagName("*"); for (int i=0;i<allNodes.getLength();i++) { String name= allNodes.item(i).getNodeName(); String value=allNodes.item(i).getFirstChild().getNodeValue(); imp.setProperty(name, value); } return true; } }
src/main/java/JP46_Reader_camera.java +72 −7 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.elphel.imagej.readers.ImagejJp4Tiff; import ij.IJ; import ij.ImageJ; import ij.ImagePlus; Loading @@ -75,6 +77,7 @@ import ij.process.ImageConverter; import ij.process.ImageProcessor; import ij.text.TextWindow; import loci.common.RandomAccessInputStream; import loci.formats.FormatException; import loci.formats.tiff.IFD; import loci.formats.tiff.IFDList; import loci.formats.tiff.TiffParser; Loading @@ -96,7 +99,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { static File dir; public String camera_url = "http://192.168.0.236:8081/"; public String camera_url = "http://192.168.0.36:2323/"; public String camera_img = "bimg"; public String camera_img_new = "towp/wait/bimg"; // will always wait for the next image (repetitive acquisitions get new images) public String camera_jp46settings = ""; Loading Loading @@ -322,6 +325,10 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { if (demux) showImage=false; double [] xtraExif=new double[1]; // ExposureTime double [] lla = null; imp = openJpegOrGif(directory, fileName); imp.show(); if (imp != null) return imp; try { imp = openJpegOrGif(directory, fileName); if (imp == null) { Loading Loading @@ -390,7 +397,35 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { String arg, boolean scale, ImagePlus imp_src, boolean showImage) { boolean showImage) { // ImagePlus imptiff = (new EyesisTiff()).readTiff(url); ImagePlus imptiff = null; try { imptiff = (new ImagejJp4Tiff()).readTiffJp4(url); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (FormatException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (imptiff!=null) { imptiff.show(); if (imptiff.getType()==ImagePlus.COLOR_RGB) { checkGrayJpegTo32Bits(imptiff); } IJ.showStatus("Converting to 32-bits"); new ImageConverter(imptiff).convertToGray32(); FileInfo fi = imptiff.getFileInfo(); // fi.fileName = name; // fi.directory = dir; fi.fileFormat = FileInfo.TIFF; imptiff.setFileInfo(fi); return imptiff; } long[] ElphelMakerNote=null; ImagePlus imp = null; boolean reuse_imp=false; Loading Loading @@ -1042,6 +1077,35 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { /* Modified from Opener.java */ ImagePlus openJpegOrGif(String dir, String name) { // Testing new readers ImagePlus imptiff = null; // imptiff = (new EyesisTiff()).readTiff(dir+name); try { imptiff = (new ImagejJp4Tiff()).readTiffJp4(dir+name); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (FormatException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (imptiff!=null) { imptiff.show(); if (imptiff.getType()==ImagePlus.COLOR_RGB) { checkGrayJpegTo32Bits(imptiff); } IJ.showStatus("Converting to 32-bits"); new ImageConverter(imptiff).convertToGray32(); FileInfo fi = imptiff.getFileInfo(); fi.fileName = name; fi.directory = dir; fi.fileFormat = FileInfo.TIFF; imptiff.setFileInfo(fi); return imptiff; } ImagePlus imp = null; boolean isTiff = false; Image img = Toolkit.getDefaultToolkit().createImage(dir+name); Loading Loading @@ -1073,7 +1137,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { fi = imp.getFileInfo(); // testing /* if ((ofi!=null) && (ofi.directory!=null) && (ofi.fileFormat == FileInfo.TIFF)) { String path = ofi.directory + ofi.fileName; EyesisTiff ET = new EyesisTiff(); Loading @@ -1093,6 +1157,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener { Frame log = WindowManager.getFrame("Log"); if (log!=null) log.toFront(); } */ } Loading
src/main/java/com/elphel/imagej/readers/ElphelJp4Reader.java 0 → 100644 +299 −0 Original line number Diff line number Diff line /** ** -----------------------------------------------------------------------------** ** ElphelJp4Reader.java ** ** loci.format compatible reader for Elphel JP4 files ** ** ** Copyright (C) 2019 Elphel, Inc. ** ** -----------------------------------------------------------------------------** ** ** ElphelTiffReader.java 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 3 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/>. ** -----------------------------------------------------------------------------** ** */ package com.elphel.imagej.readers; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Date; import java.util.HashMap; import java.util.Hashtable; import org.apache.commons.compress.utils.IOUtils; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import loci.common.ByteArrayHandle; 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.formats.FormatException; import loci.formats.FormatTools; import loci.formats.in.ImageIOReader; import loci.formats.in.MetadataLevel; import loci.formats.services.EXIFService; //import loci.formats.services.EXIFService; import ome.xml.meta.MetadataStore; import ome.xml.model.primitives.Timestamp; //ElphelTiffReader public class ElphelJp4Reader extends ImageIOReader{ // -- Constants -- public static final String MAKER_NOTE = "Makernote"; public static final String SUB_SEC_TIME_ORIGINAL = "Sub-Sec Time Original"; public static final String EXPOSURE_TIME = "Exposure Time"; public static final String DATE_TIME_ORIGINAL = "Date/Time Original"; public static final String ELPHEL_PROPERTY_PREFIX = "ELPHEL_"; public static final String CONTENT_FILENAME = "CONTENT_FILENAME"; /** Logger for this class. */ private static final Logger LOGGER = LoggerFactory.getLogger(ElphelTiffReader.class); // -- Fields -- private URL url = null; // save here actual URL when reading file to memory private String content_fileName = null; // from Content-disposition private boolean file_initialized = false; private ElphelTiffReader elphelTiffReader = null; // private ImageReader helperReader; // -- Constructor -- /** Constructs a new Tiff reader. */ public ElphelJp4Reader() { super("JP4", new String[] {"jp4"}); // mergeSubIFDs = true; // false; suffixNecessary = true; // false suffixSufficient = true; // false; LOGGER.info("ElphelTiffReader(), after super()"); elphelTiffReader = new ElphelTiffReader(); } // -- IFormatReader API methods -- /* @see loci.formats.IFormatReader#isThisType(String, boolean) */ @Override public boolean isThisType(String name, boolean open) { if (open) { return super.isThisType(name, open); } return checkSuffix(name, getSuffixes()); } /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */ @Override public boolean isThisType(RandomAccessInputStream stream) throws IOException { final int blockLen = 4; if (!FormatTools.validStream(stream, blockLen, false)) return false; byte[] signature = new byte[blockLen]; stream.read(signature); if (signature[0] != (byte) 0xff || signature[1] != (byte) 0xd8 || signature[2] != (byte) 0xff || (signature[3] & 0xf0) == 0) { return false; } return true; } @Override public void setId(String id) throws FormatException, IOException { // same as for tiff? LOGGER.debug("setId("+id+"). before super" ); file_initialized = false; if (Location.getIdMap().containsKey(id)) { LOGGER.debug("id '"+id+"' is already mapped" ); content_fileName = null; // id; // maybe set to null to handle externally? LOGGER.info("Starting initFile() method, read file directly"); super.setId(id); } else { // If URL, then read to memory, if normal file - use direct access url = null; // String mime = null; // use to select jp4/tiff later? Or to check it is correct content_fileName = null; try { url = new URL(id); } catch (MalformedURLException e) { LOGGER.warn("Bad URL: " + id); } if (url != null) { LOGGER.info("Starting initFile() method, read "+ id +" to memory first"); //https://www.rgagnon.com/javadetails/java-0487.html URLConnection connection = url.openConnection(); String content_disposition = connection.getHeaderField("Content-Disposition"); // raw = "attachment; filename=abc.jpg" if(content_disposition != null && content_disposition.indexOf("=") != -1) { content_fileName = content_disposition.split("=")[1]; //getting value after '=' // trim quotes content_fileName= content_fileName.substring(1, content_fileName.length()-1); } else { String mime = connection.getContentType(); int slash = mime.lastIndexOf("/"); String suffix = slash < 0 ? "" : mime.substring(slash+1); content_fileName = "unknown." + suffix; } // currentId = fileName; //??? // LOGGER.info("Mime type = "+mime); // https://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests //https://stackoverflow.com/questions/2295221/java-net-url-read-stream-to-byte InputStream is = url.openStream (); // byte[] inBytes = IOUtils.toByteArray(is); if (is != null) is.close(); LOGGER.info("Bytes read: "+ inBytes.length); Location.mapFile(content_fileName, new ByteArrayHandle(inBytes)); HashMap<String,Object> dbg_loc = Location.getIdMap(); super.setId(content_fileName); } else { // read file normally content_fileName = id; LOGGER.info("read file directly"); super.setId(id); } } //getReader // super.setId(id); LOGGER.debug("setId("+id+"). after super" ); file_initialized = true; } /* @see loci.formats.FormatReader#initFile(String) */ @Override protected void initFile(String id) throws FormatException, IOException { LOGGER.debug("initFile("+id+"), currentId="+currentId+", before super" ); try { super.initFile(id); // fails class_not_found } catch (IllegalArgumentException e) { throw new FormatException(e); } LOGGER.debug("initFile("+id+"), currentId="+currentId+", after super" ); // elphelTiffReader.setId(id); //error here - invalid tiff file // Below needs to be modified - EXIFService does not work with mapFile MetadataStore store = makeFilterMetadata(); LOGGER.info("Parsing JPEG EXIF data"); HashMap<String, String> tags = null; try { EXIFService exif = new ServiceFactory().getInstance(EXIFService.class); if (exif == null) { return; } exif.initialize(id); // Set the acquisition date Date date = exif.getCreationDate(); if (date != null) { Timestamp timestamp = new Timestamp(new DateTime(date)); store.setImageAcquisitionDate(timestamp, 0); } tags = exif.getTags(); for (String tagName : tags.keySet()) { addGlobalMeta(tagName, tags.get(tagName)); } //{Makernote=105455 131072 127570 300581 171508736 171508736 171508736 171508736 169869312 124780556 1118544 0 0 327779 648 1296, Sub-Sec Time Original=560439, Exposure Time=11167/500000 sec, Date/Time Original=2019:05:13 04:30:26} } catch (ServiceException e) { LOGGER.debug("Could not parse EXIF data", e); } catch (DependencyException e) { LOGGER.debug("Could not parse EXIF data", e); } long [] maker_note = null; double exposure = Double.NaN; String date_time = null; if (tags.containsKey(MAKER_NOTE)){ String [] smn = tags.get(MAKER_NOTE).split(" "); maker_note = new long[smn.length]; for (int i = 0; i < maker_note.length; i++) { maker_note[i] = Integer.parseInt(smn[i]); } } if (tags.containsKey(EXPOSURE_TIME)){ String [] s = tags.get(EXPOSURE_TIME).split("/"); exposure = 1.0 * Integer.parseInt(s[0]) / Integer.parseInt(s[1].split(" ")[0]); } if (tags.containsKey(DATE_TIME_ORIGINAL)){ date_time = tags.get(DATE_TIME_ORIGINAL); if (tags.containsKey(SUB_SEC_TIME_ORIGINAL)){ date_time += tags.get(SUB_SEC_TIME_ORIGINAL); } } Hashtable<String, String> property_table = ElphelMeta.getMeta( null, maker_note, exposure, date_time, true ); LOGGER.info("Created elphelMeta table, size="+property_table.size()); for (String key:property_table.keySet()) { addGlobalMeta(ELPHEL_PROPERTY_PREFIX+key,property_table.get(key)); } MetadataLevel level = getMetadataOptions().getMetadataLevel(); if (level != MetadataLevel.MINIMUM) { // Integer[] tags = ifds.get(0).keySet().toArray(new Integer[0]); // LOGGER.info("initStandardMetadata() - got "+tags.length+" tags"); } addGlobalMeta(ELPHEL_PROPERTY_PREFIX+CONTENT_FILENAME,content_fileName); } /* @see loci.formats.IFormatReader#close(boolean) */ @Override public void close(boolean fileOnly) throws IOException { HashMap<String,Object> dbg_loc = Location.getIdMap(); String saveCurrentId = currentId; currentId = null; LOGGER.info("close("+fileOnly+") before super"); super.close(fileOnly); // curerent_id == null only during actual close? LOGGER.info("close("+fileOnly+") after super"); currentId = saveCurrentId; if ((content_fileName != null) && file_initialized){ Location.mapFile(content_fileName, null); file_initialized = false; } dbg_loc = Location.getIdMap(); if (!fileOnly) { // companionFile = null; // description = null; // calibrationUnit = null; // physicalSizeZ = null; // timeIncrement = null; // xOrigin = null; // yOrigin = null; } } }