Commit 2397e946 authored by Andrey Filippov's avatar Andrey Filippov

More on JP4+Tiff reading with bioformatrs.

parent fb75351e
......@@ -8,4 +8,5 @@ attic
*.log
FOCUS-PSF*
src/main/resources/trained_model
bioformats
\ No newline at end of file
bioformats*.*
metadata*.*
......@@ -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>
......
......@@ -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;
......@@ -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;
......@@ -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.
}
......@@ -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);
}
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);
return readTiff(path, "STD_"); // null);
}
public ImagePlus readTiff(String path, String std ) { // std - include non-elphel properties with prefix std
// map input id string to input byte array
String inId = "inBytes" + suffix;
Location.mapFile(inId, new ByteArrayHandle(inBytes));
String inId = null;
inId = path;
// 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();
......@@ -153,13 +131,15 @@ public class EyesisTiff {
// TODO Auto-generated catch block
e.printStackTrace();
}
OMEXMLService service = null;
OMEXMLService service = null;
try {
service = factory.getInstance(OMEXMLService.class);
} catch (DependencyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
IMetadata omeMeta = null;
try {
omeMeta = service.createOMEXMLMetadata();
......@@ -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);
......@@ -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 {
......@@ -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) {
......@@ -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;
}
}
......@@ -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;
......@@ -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;
......@@ -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 = "";
......@@ -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) {
......@@ -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;
......@@ -399,14 +434,14 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener {
double [] xtraExif=new double[1]; // ExposureTime
// System.out.println("imp_src is "+((imp_src!=null)?"not ":"")+"null");
// System.out.println("imp_src is "+((imp_src!=null)?"not ":"")+"null");
try {
imp = openJpegOrGifUsingURL(url);
if (imp == null) {
IJ.showMessage("JP46 Reader Error", "Could not open the URL: " + url + " as JPEG/JP46");
} else {
if ((imp_src==null) && showImage) {
// System.out.println("show() 1");
// System.out.println("show() 1");
imp.show(); /* Shows before re-ordering*/
}
/// get rid of the "/towp/wait" if any - there is a chance to re-read the same image
......@@ -429,7 +464,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener {
if (reuse_imp) {
imp=imp_src;
} else if ((imp_src!=null) && showImage) { /* tried to reuse, but wrong size */
// System.out.println("show() 2");
// System.out.println("show() 2");
imp.show(); /* never did that before */
}
if ((xtraExif!=null) && !Double.isNaN(xtraExif[0])){
......@@ -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);
......@@ -1073,8 +1137,8 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener {
fi = imp.getFileInfo();
// testing
if ((ofi!=null) && (ofi.directory!=null) && (ofi.fileFormat ==FileInfo.TIFF)) {
/*
if ((ofi!=null) && (ofi.directory!=null) && (ofi.fileFormat == FileInfo.TIFF)) {
String path = ofi.directory + ofi.fileName;
EyesisTiff ET = new EyesisTiff();
ImagePlus imptiff = ET.readTiff(path);
......@@ -1093,6 +1157,7 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener {
Frame log = WindowManager.getFrame("Log");
if (log!=null) log.toFront();
}
*/
}
......
This diff is collapsed.
......@@ -29,74 +29,59 @@ import java.util.Hashtable;
//import ij.IJ;
import loci.formats.FormatException;
import loci.formats.tiff.IFD;
import loci.formats.tiff.IFDList;
import loci.formats.tiff.TiffParser;
import loci.formats.tiff.TiffRational;
public class ElphelMeta {
private Hashtable<String, String> property_table = null;
public ElphelMeta (TiffParser tiffParser, boolean scale) throws FormatException, IOException {
IFDList exifIFDs = tiffParser.getExifIFDs();
property_table = new Hashtable<String, String> ();
long[] maker_note = null;
if (exifIFDs.size() > 0) {
IFD exifIFD = exifIFDs.get(0);
tiffParser.fillInIFD(exifIFD);
if (exifIFD.containsKey(IFD.MAKER_NOTE)) {
maker_note = (long[]) exifIFD.get(IFD.MAKER_NOTE);
}
if (exifIFD.containsKey(IFD.EXPOSURE_TIME)) {
Object exp = exifIFD.get(IFD.EXPOSURE_TIME);
if (exp instanceof TiffRational) {
TiffRational texp = (TiffRational) exp;
double d = 1.0*texp.getNumerator()/texp.getDenominator();
property_table.put("EXPOSURE", String.format("%f",d));
}
}
if (exifIFD.containsKey(IFD.DATE_TIME_ORIGINAL)) {
String dt = exifIFD.get(IFD.DATE_TIME_ORIGINAL).toString();
if (exifIFD.containsKey(IFD.SUB_SEC_TIME_ORIGINAL)) {
dt += "."+exifIFD.get(IFD.SUB_SEC_TIME_ORIGINAL).toString();
}
property_table.put("DATE_TIME", dt);
}
// private Hashtable<String, String> property_table = null;
public static Hashtable<String, String> getMeta (Hashtable<String, String> property_table,
long[] maker_note,
double exposure,
String date_time,
boolean scale) throws FormatException, IOException {
if (property_table == null) {
property_table = new Hashtable<String, String> ();
}
// copied from JP4_Reader_cam
// Add GPS tags when there will be images to experiment (or while reimplementing JP4 reader)
double[] gains= new double[4];
double[] blacks= new double[4];
double[] blacks256= new double[4];
double[] gammas= new double[4];
long [] gamma_scales= new long[4]; /* now not used, was scale _after_ gamma is applied, 0x400(default) corresponds to 1.0 */
int i;
double[][] rgammas=new double[4][];
double min_gain;
long WOI_LEFT,WOI_WIDTH,WOI_TOP,WOI_HEIGHT,BAYER_MODE,DCM_HOR,DCM_VERT,BIN_HOR,BIN_VERT;
long COLOR_MODE=0;
long FLIPH=0;
long FLIPV=0;
long HEIGHT1=0;
long HEIGHT2=0;
long HEIGHT3=0;
long BLANK1=0;
long BLANK2=0;
boolean FLIPH1=false;
boolean FLIPV1=false;
boolean FLIPH2=false;
boolean FLIPV2=false;
boolean FLIPH3=false;
boolean FLIPV3=false;
boolean COMPOSITE=false;
boolean PORTRAIT=false;
boolean YTABLEFORC=false;
long QUALITY=0;
long CQUALITY=0;
long CORING_INDEX_Y=0;
long CORING_INDEX_C=0;
double [] satValue={255.0, 255.0, 255.0, 255.0};
if (maker_note !=null) {
if (!Double.isNaN(exposure)) {
property_table.put("EXPOSURE", String.format("%f",exposure));
}
if (date_time == null) {
property_table.put("DATE_TIME", date_time);
}
if (maker_note != null) {
// copied from JP4_Reader_cam
// Add GPS tags when there will be images to experiment (or while reimplementing JP4 reader)
double[] gains= new double[4];
double[] blacks= new double[4];
double[] blacks256= new double[4];
double[] gammas= new double[4];
long [] gamma_scales= new long[4]; /* now not used, was scale _after_ gamma is applied, 0x400(default) corresponds to 1.0 */
int i;
double[][] rgammas=new double[4][];
double min_gain;
long WOI_LEFT,WOI_WIDTH,WOI_TOP,WOI_HEIGHT,BAYER_MODE,DCM_HOR,DCM_VERT,BIN_HOR,BIN_VERT;
long COLOR_MODE=0;
long FLIPH=0;
long FLIPV=0;
long HEIGHT1=0;
long HEIGHT2=0;
long HEIGHT3=0;
long BLANK1=0;
long BLANK2=0;
boolean FLIPH1=false;
boolean FLIPV1=false;
boolean FLIPH2=false;
boolean FLIPV2=false;
boolean FLIPH3=false;
boolean FLIPV3=false;
boolean COMPOSITE=false;
boolean PORTRAIT=false;
boolean YTABLEFORC=false;
long QUALITY=0;
long CQUALITY=0;
long CORING_INDEX_Y=0;
long CORING_INDEX_C=0;
double [] satValue={255.0, 255.0, 255.0, 255.0};
for (i=0;i<4;i++) { /* r,g,gb,b */
gains[i]= maker_note[i]/65536.0;
blacks[i]=(maker_note[i+4]>>24)/256.0;
......@@ -193,7 +178,7 @@ public class ElphelMeta {
property_table.put("FLIPV2",FLIPV2?"1":"0");
property_table.put("FLIPV3",FLIPV3?"1":"0");
}
// If there are FLIPH, FLIPV - swap gains, gammas, blacks accordingly. later the images will be also flipped
// If there are FLIPH, FLIPV - swap gains, gammas, blacks accordingly. later the images will be also flipped
if (FLIPV!=0) {
swapArrayElements (gains, 1, 3);
swapArrayElements (gains, 0, 2);
......@@ -215,54 +200,57 @@ public class ElphelMeta {
swapArrayElements (gamma_scales,3, 2);
}
for (i=0;i<4;i++) rgammas[i]=elphel_gamma_calc (gammas[i], blacks[i], gamma_scales[i]);
} else {
return; // No MakerNote, return with nothing done
}
/**adjusting gains to have the result picture in the range 0..256 */
min_gain=2.0*gains[0];
for (i=0;i<4;i++) {
if (min_gain > gains[i]*(1.0-blacks[i])) min_gain = gains[i]*(1.0-blacks[i]);
}
property_table.put("GAIN",String.format("%f",min_gain)); // common gain
/**adjusting gains to have the result picture in the range 0..256 */
min_gain=2.0*gains[0];
for (i=0;i<4;i++) {
if (min_gain > gains[i]*(1.0-blacks[i])) min_gain = gains[i]*(1.0-blacks[i]);
}
property_table.put("GAIN",String.format("%f",min_gain)); // common gain
for (i=0;i<4;i++) gains[i]/=min_gain;
for (i=0;i<4;i++) blacks256[i]=256.0*blacks[i];
for (i=0;i<4;i++) gains[i]/=min_gain;
for (i=0;i<4;i++) blacks256[i]=256.0*blacks[i];
for (i=0;i<4;i++) {
if (maker_note !=null) {
if (scale) satValue[i]=((rgammas[i][255])-blacks256[i])/gains[i];
else satValue[i]=((rgammas[i][255])-blacks256[i]);
} else satValue[i]=255.0;
property_table.put("saturation_"+i,String.format("%f",satValue[i]));
for (i=0;i<4;i++) {
if (maker_note !=null) {
if (scale) satValue[i]=((rgammas[i][255])-blacks256[i])/gains[i];
else satValue[i]=((rgammas[i][255])-blacks256[i]);
} else satValue[i]=255.0;
property_table.put("saturation_"+i,String.format("%f",satValue[i]));
}
// swap satValue to match FLIPH,FLIPV again
if (FLIPV!=0) {
swapArrayElements (satValue, 1, 3);
swapArrayElements (satValue, 0, 2);
}
if (FLIPH!=0) {
swapArrayElements (satValue, 1, 0);
swapArrayElements (satValue, 3, 2);
}
for (i=0;i<4;i++) {
property_table.put("saturation_"+i,String.format("%f",satValue[i]));
}
}
// swap satValue to match FLIPH,FLIPV again
if (FLIPV!=0) {
swapArrayElements (satValue, 1, 3);
swapArrayElements (satValue, 0, 2);
}
if (FLIPH!=0) {
swapArrayElements (satValue, 1, 0);
swapArrayElements (satValue, 3, 2);
}
for (i=0;i<4;i++) {
property_table.put("saturation_"+i,String.format("%f",satValue[i]));
}
}
public Hashtable<String, String> getPropertyTable(){
return property_table;
}
// -- Helper methods --
void swapArrayElements (double[]arr,int i, int j) {
// public Hashtable<String, String> getPropertyTable(){
// return property_table;
// }
// -- Helper methods --
static void swapArrayElements (double[]arr,int i, int j) {
double tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
void swapArrayElements (long[]arr,int i, int j) {
static void swapArrayElements (long[]arr,int i, int j) {
long tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
......@@ -270,7 +258,7 @@ public class ElphelMeta {
/* reverses gamma calculations in the camera
returns double[] table , in the range 0.0..255.996
*/
double [] elphel_gamma_calc (double gamma, double black, long gamma_scale) {
static double [] elphel_gamma_calc (double gamma, double black, long gamma_scale) {
int i;
double x, black256 ,k;
int[] gtable = new int[257];
......
......@@ -27,15 +27,25 @@
*/
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.Hashtable;
import org.apache.commons.compress.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import loci.common.ByteArrayHandle;
import loci.common.Location;
import loci.formats.FormatException;
import loci.formats.in.MetadataLevel;
import loci.formats.in.TiffReader;
import loci.formats.meta.MetadataStore;
import loci.formats.tiff.IFD;
import loci.formats.tiff.IFDList;
import loci.formats.tiff.TiffRational;
/*
// non-IFD tags (for internal use)
......@@ -72,7 +82,9 @@ IFD.java public static final int MAKER_NOTE = 37500;
public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
// -- Constants --
public static final String ELPHEL_PROPERTY_PREFIX = "ELPHEL_";
public static final String CONTENT_FILENAME = "CONTENT_FILENAME";
/** Merge SubIFDs into the main IFD list. */
// protected transient boolean mergeSubIFDs = true; // false;
......@@ -89,7 +101,10 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
// public static final int IMAGEJ_TAG = 50839;
// -- Fields --
// private String inId = null; // to close Location.mapFile
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 String companionFile;
// private String description;
// private String calibrationUnit;
......@@ -102,12 +117,75 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
/** Constructs a new Tiff reader. */
public ElphelTiffReader() {
super(); // "Tagged Image File Format", ELPHEL_TIFF_SUFFIXES); // See if we can use TiffReader without its parent
mergeSubIFDs = true; // false;
/// mergeSubIFDs = true; // false;
LOGGER.info("ElphelTiffReader(), after supper(), mergeSubIFDs = true;");
}
// -- IFormatReader API methods --
@Override
public void setId(String id) throws FormatException, IOException {
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
// String cameraURL = "http://192.168.0.36:2323/img"; // for testing
// just testing - ignore file name and use camera URL
// id = cameraURL;
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;
}
@Override
protected void initFile(java.lang.String id)
......@@ -117,6 +195,8 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
LOGGER.info("Starting initFile() method");
super.initFile(id);
LOGGER.info("Ending initFile() method");
}
/* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */
......@@ -134,8 +214,14 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
@Override
public void close(boolean fileOnly) throws IOException {
LOGGER.info("close("+fileOnly+") before super");
super.close(fileOnly);
super.close(fileOnly); // curerent_id == null only during actual close?
LOGGER.info("close("+fileOnly+") after super");
if ((content_fileName != null) && file_initialized){
Location.mapFile(content_fileName, null);
file_initialized = false;
}
// HashMap<String,Object> dbg_loc = Location.getIdMap();
if (!fileOnly) {
// companionFile = null;
// description = null;
......@@ -156,8 +242,35 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
super.initStandardMetadata();
String comment = ifds.get(0).getComment(); // IMAGE_DESCRIPTION
LOGGER.info("initStandardMetadata() - after super()");
ElphelMeta elphelMeta = new ElphelMeta(tiffParser, true);
Hashtable<String, String> property_table = elphelMeta.getPropertyTable();
long[] maker_note = null;
double exposure = Double.NaN;
String date_time = null;
IFDList exifIFDs = tiffParser.getExifIFDs();
if (exifIFDs.size() > 0) {
IFD exifIFD = exifIFDs.get(0);
tiffParser.fillInIFD(exifIFD);
if (exifIFD.containsKey(IFD.MAKER_NOTE)) {
maker_note = (long[]) exifIFD.get(IFD.MAKER_NOTE);
}
if (exifIFD.containsKey(IFD.EXPOSURE_TIME)) {
Object exp = exifIFD.get(IFD.EXPOSURE_TIME);
if (exp instanceof TiffRational) {
TiffRational texp = (TiffRational) exp;
exposure = 1.0*texp.getNumerator()/texp.getDenominator();
}
}
if (exifIFD.containsKey(IFD.DATE_TIME_ORIGINAL)) {
date_time = exifIFD.get(IFD.DATE_TIME_ORIGINAL).toString();
if (exifIFD.containsKey(IFD.SUB_SEC_TIME_ORIGINAL)) {
date_time += "."+exifIFD.get(IFD.SUB_SEC_TIME_ORIGINAL).toString();
}
}
}
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));
......@@ -167,6 +280,7 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
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);
// check for ImageJ-style TIFF comment
boolean ij = checkCommentImageJ(comment);
// if (ij) parseCommentImageJ(comment);
......@@ -220,6 +334,22 @@ public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
populateMetadataStoreImageJ(store);
}
/**
* @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
*/
@Override
public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
throws FormatException, IOException
{
LOGGER.info("openBytes() - before super()");
super.openBytes(no, buf, x, y, w, h);
LOGGER.info("openBytes() - after super()");
return buf;
}
// -- Helper methods --
// Convert to Elphel-specific parameters
......
/**
** -----------------------------------------------------------------------------**
** ImagejJp4Tiff.java
**
** Uses loci.format compatible readers for Elphel 8/16 bpp monochrome Tiff and
** JP4 files to read/parse camera files in a single url read operation by
** buffering camera data with Location.mapFile()
**
**
** Copyright (C) 2019 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** ImagejJp4Tiff.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.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.compress.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ij.ImagePlus;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import loci.common.ByteArrayHandle;
import loci.common.Location;
import loci.common.services.DependencyException;
import loci.common.services.ServiceException;
import loci.common.services.ServiceFactory;
import loci.formats.ClassList;
import loci.formats.FormatException;
import loci.formats.IFormatReader;
import loci.formats.ImageReader;
import loci.formats.meta.IMetadata;
import loci.formats.services.OMEXMLService;
public class ImagejJp4Tiff {
// -- Constants --
private static final Logger LOGGER = LoggerFactory.getLogger(ClassList.class);
private static final boolean BYPASS_SERVICES = true;
// -- Fields --
private ImageReader reader = null;
private String content_fileName = "undefined"; // from Content-disposition
private URL url = null; // save here actual URL when reading file to memory
IMetadata omeMeta = null;
// -- Constructor --
public ImagejJp4Tiff() {
// Bypass readers.txt
ClassList<IFormatReader> classList = new ClassList<IFormatReader>(IFormatReader.class);
// classList.addClass(com.elphel.imagej.readers.ElphelTiffJp4Reader.class);
classList.addClass(com.elphel.imagej.readers.ElphelJp4Reader.class);
classList.addClass(com.elphel.imagej.readers.ElphelTiffReader.class);
if (!BYPASS_SERVICES) {
ServiceFactory factory = null;
try {
factory = new ServiceFactory();
} catch (DependencyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
OMEXMLService service = null;
try {
service = factory.getInstance(OMEXMLService.class);
} catch (DependencyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
omeMeta = service.createOMEXMLMetadata();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
reader = new ImageReader(classList);
if (!BYPASS_SERVICES) {
reader.setMetadataStore(omeMeta);
}
}
// -- API methods --
public ImagePlus readTiffJp4(String path) throws IOException, FormatException {
return readTiffJp4(path, "STD_"); // null);
}
public ImagePlus readTiffJp4(String path_url, String std ) throws IOException, FormatException { // std - include non-elphel properties with prefix std
// determine if it is a file or URL and read url to memory
// 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(path_url);
} catch (MalformedURLException e) {
LOGGER.warn("Bad URL: " + path_url);
}
if (url != null) {
LOGGER.info("Read "+ path_url +" to memory first");
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;
}
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 = path_url;
LOGGER.info("read '"+path_url+"' file directly");
}
reader.setId(content_fileName);
byte [] bytes = null;
ImagePlus imp= null;
bytes = reader.openBytes(0);
int bpp = reader.getBitsPerPixel();
boolean is_le = reader.isLittleEndian();
int bytes_per_pixel = (bpp + 7) / 9;
float [] pixels = new float [bytes.length/bytes_per_pixel];
if (bytes_per_pixel == 1) {
for (int i = 0; i < pixels.length; i++) {
pixels[i] = ((bytes[i])) & 0xff;
}
} else {
ByteBuffer bb = ByteBuffer.wrap(bytes);
if (is_le) {
bb.order( ByteOrder.LITTLE_ENDIAN);
} else {
bb.order( ByteOrder.BIG_ENDIAN);
}
for (int i = 0; i < pixels.length; i++) {
pixels[i] = ((bb.getShort())) & 0xffff;
}
}
ImageProcessor ip=new FloatProcessor(reader.getSizeX(), reader.getSizeY());
ip.setPixels(pixels);
ip.resetMinAndMax();
Hashtable<String, Object> meta_hash = reader.getGlobalMetadata();
String prefix = ElphelTiffReader.ELPHEL_PROPERTY_PREFIX;
String imageName = content_fileName; // 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(" ","_").replace("/","_")), meta_hash.get(key).toString());
}
}
encodeProperiesToInfo(imp);
Location.mapFile(content_fileName, null);
return imp;
}
// -- Helper methods --
public static 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;
}
}
# This document is a configuration file identifying all file format readers
# available to Bio-Formats, and the order in which they should be used.
# Please do not edit unless you know what you are doing, see
# https://docs.openmicroscopy.org/latest/bio-formats/developers/reader-guide.html
#Elphel readers
com.elphel.imagej.readers.ElphelTiffJp4Reader # tiff,jp4
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment