Commit fb75351e authored by Andrey Filippov's avatar Andrey Filippov

Working on loci-compatible reader for camera files to use single-read

pass
parent 1338de2c
......@@ -7,4 +7,5 @@ NC393I
attic
*.log
FOCUS-PSF*
src/main/resources/trained_model
\ No newline at end of file
src/main/resources/trained_model
bioformats
\ No newline at end of file
......@@ -88,7 +88,7 @@
<dependency>
<groupId>ome</groupId>
<artifactId>loci_tools</artifactId>
<version>5.0.0</version>
<version>5.9.0</version>
</dependency>
</dependencies>
......
......@@ -4,12 +4,12 @@
**
** Writes Tiff files suitable for Emblend, preserve ImageJ Info data
** Uses bioformat library
**
**
**
** Copyright (C) 2012 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
**
** EyesisTiff.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
......@@ -31,24 +31,45 @@ 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.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import org.apache.log4j.Logger;
import ij.IJ;
import ij.ImagePlus;
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;
import loci.formats.tiff.TiffParser;
......@@ -56,13 +77,206 @@ import loci.formats.tiff.TiffRational;
import loci.formats.tiff.TiffSaver;
public class EyesisTiff {
// private static org.apache.log4j.Logger log= Logger.getLogger(EyesisTiff.class);
private static ClassList<IFormatReader> defaultClasses;
private static final Logger LOGGER = LoggerFactory.getLogger(ClassList.class);
public static ClassList<IFormatReader> getCustomReaderClasses() {
defaultClasses = null;
if (defaultClasses == null) {
try {
defaultClasses =
new ClassList<IFormatReader>(
EyesisTiff.class.getClassLoader().getResource("readers.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.
}
catch (IOException exc) {
defaultClasses = new ClassList<IFormatReader>(IFormatReader.class);
LOGGER.info("Could not parse class list; using default classes", exc);
}
}
// ClassList<IFormatReader> dc = defaultClasses;
LOGGER.info("Loaded "+defaultClasses.getClasses().length+" classes");
return defaultClasses;
}
// private static org.apache.log4j.Logger log= Logger.getLogger(EyesisTiff.class);
public EyesisTiff(){
// Please initialize the log4j system properly
}
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);
// 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();
} 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();
}
IMetadata omeMeta = null;
try {
omeMeta = service.createOMEXMLMetadata();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// final Class<? extends IFormatReader>[] defaultClasses =
// ImageReader.getDefaultReaderClasses().getClasses();
// final int currentHash = Arrays.hashCode(defaultClasses);
//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
ImageReader reader = new ImageReader(getCustomReaderClasses());
// BaseTiffReader reader = new BaseTiffReader("Base_tiff_reader","tiff");
reader.setMetadataStore(omeMeta);
try {
reader.setId(inId);
} catch (FormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// a lot of output for each unmatched format
//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 {
bytes = reader.openBytes(0);
} catch (FormatException e1) {
LOGGER.warn("Invalid image format, error "+e1);
} catch (IOException e1) {
LOGGER.warn("I/O error "+e1);
}
if (bytes != null) {
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();
// 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
}
// ImagePlus imp= makeArrays(pixels, width, height, title);
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return imp;
}
/*
* image width getSizeX()
image height getSizeY()
number of series per file getSeriesCount()
total number of images per series getImageCount()
number of slices in the current series getSizeZ()
number of timepoints in the current series getSizeT()
number of actual channels in the current series getSizeC()
number of channels per image getRGBChannelCount()
the ordering of the images within the current series getDimensionOrder()
whether each image is RGB isRGB()
whether the pixel bytes are in little-endian order isLittleEndian()
whether the channels in an image are interleaved isInterleaved()
the type of pixel data in this file getPixelType()
*/
public void savePNG_ARGB32(
ImagePlus imp,
String path
......@@ -71,12 +285,12 @@ public class EyesisTiff {
int height = imp.getHeight();
int [] pixels = (int []) imp.getProcessor().getPixels();
System.out.println("savePNG_ARGB32("+path+"): width="+width+", height="+height+" length="+pixels.length);
DataBufferInt buffer = new DataBufferInt(pixels, pixels.length);
int[] bandMasks = {0xFF0000, 0xFF00, 0xFF, 0xFF000000}; // ARGB (yes, ARGB, as the masks are R, G, B, A always) order
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, bandMasks, null);
ColorModel cm = ColorModel.getRGBdefault();
BufferedImage bimage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
try{
......@@ -124,7 +338,7 @@ public class EyesisTiff {
int IFDImageJByteCounts= 0xc696; // was array {12( if no slices, roi, etc.), bytes in info}
int IFDImageJInfo= 0xc697; // ImageJ info, starting with magic IJIJinfo,
byte [] ImageJInfoMagic={73,74,73,74,105,110,102,111,0,0,0,1};
byte [] ImageJInfoMagic={73,74,73,74,105,110,102,111,0,0,0,1};
int pixelsDenominator=1000;
String description=(imp.getProperty("description")!=null)?((String) imp.getProperty("description")):"Elphel Eyesis4pi";
......@@ -152,7 +366,7 @@ public class EyesisTiff {
}
}
// for (int i = 0; i < imagePixels[3].length; i++){
// imagePixels[3][i] = 1.0f - imagePixels[3][i];
// imagePixels[3][i] = 1.0f - imagePixels[3][i];
// }
int bw;
byte [] bytes;
......@@ -221,7 +435,7 @@ public class EyesisTiff {
default:
IJ.error("saveTiffARGBFloat32", "Unsupported output format mode ="+mode);
return;
}
}
// System.out.println("saveTiffARGBFloat32(): mode="+mode+" pixelType="+pixelType+" bw="+bw);
IFD ifd=new IFD();
ifd.put(new Integer(IFD.LITTLE_ENDIAN), new Boolean(false));
......@@ -229,7 +443,7 @@ public class EyesisTiff {
ifd.put(new Integer(IFD.IMAGE_WIDTH), imp.getWidth());
ifd.put(new Integer(IFD.IMAGE_LENGTH), imp.getHeight());
ifd.put(new Integer(IFD.SAMPLES_PER_PIXEL), 4);
ifd.putIFDValue(IFD.SOFTWARE, "Elphel Eyesis");
ifd.putIFDValue(IFD.SOFTWARE, "Elphel Eyesis");
ifd.putIFDValue(IFD.IMAGE_DESCRIPTION, description);
// copy some other data?
ifd.putIFDValue(IFD.COMPRESSION, 1); //TiffCompression.UNCOMPRESSED);
......@@ -251,7 +465,7 @@ public class EyesisTiff {
if (imp.getProperty("ImageFullLength")!=null){
ifd.putIFDValue(IFDImageFullLength, (long) Integer.parseInt((String) imp.getProperty("ImageFullLength")));
}
//TODO: Seems to match ImageJ Info, but it is not recognized :-(
//TODO: Seems to match ImageJ Info, but it is not recognized :-(
if (imageJTags && (imp.getProperty("Info")!=null) && (imp.getProperty("Info") instanceof String)){
int skipFirstBytes=2;
String info=(String) imp.getProperty("Info");
......@@ -269,7 +483,7 @@ public class EyesisTiff {
TiffSaver tiffSaver = new TiffSaver(path);
tiffSaver.setWritingSequentially(true);
tiffSaver.setLittleEndian(false);
tiffSaver.writeHeader();
tiffSaver.writeHeader();
// tiffSaver.writeIFD(ifd,0); //* SHould not write here, some fields are calculated during writeImage, that writes IFD too
// System.out.println("bytes.length="+bytes.length);
tiffSaver.writeImage(bytes,
......@@ -292,7 +506,7 @@ public class EyesisTiff {
int IFDImageJByteCounts= 0xc696; // was array {12( if no slices, roi, etc.), bytes in info}
int IFDImageJInfo= 0xc697; // ImageJ info, starting with magic IJIJinfo,
byte [] ImageJInfoMagic={73,74,73,74,105,110,102,111,0,0,0,1};
byte [] ImageJInfoMagic={73,74,73,74,105,110,102,111,0,0,0,1};
int pixelsDenominator=1000;
String description=(imp.getProperty("description")!=null)?((String) imp.getProperty("description")):"Elphel Eyesis4pi";
......@@ -311,7 +525,7 @@ public class EyesisTiff {
ifd.put(new Integer(IFD.IMAGE_WIDTH), imp.getWidth());
ifd.put(new Integer(IFD.IMAGE_LENGTH), imp.getHeight());
ifd.put(new Integer(IFD.SAMPLES_PER_PIXEL), 4);
ifd.putIFDValue(IFD.SOFTWARE, "Elphel Eyesis");
ifd.putIFDValue(IFD.SOFTWARE, "Elphel Eyesis");
ifd.putIFDValue(IFD.IMAGE_DESCRIPTION, description);
// copy some other data?
ifd.putIFDValue(IFD.COMPRESSION, 1); //TiffCompression.UNCOMPRESSED);
......@@ -334,7 +548,7 @@ public class EyesisTiff {
if (imp.getProperty("ImageFullLength")!=null){
ifd.putIFDValue(IFDImageFullLength, (long) Integer.parseInt((String) imp.getProperty("ImageFullLength")));
}
//TODO: Seems to match ImageJ Info, but it is not recognized :-(
//TODO: Seems to match ImageJ Info, but it is not recognized :-(
if (imageJTags && (imp.getProperty("Info")!=null) && (imp.getProperty("Info") instanceof String)){
int skipFirstBytes=2;
String info=(String) imp.getProperty("Info");
......@@ -343,7 +557,7 @@ public class EyesisTiff {
int index=0;
for (int i=0;i<ImageJInfoMagic.length;i++) bInfo[index++]=ImageJInfoMagic[i];
for (int i=skipFirstBytes;i<bInfoBody.length; i++) bInfo[index++]=bInfoBody[i]; // first 2 bytes {-2, -1} ???
/*
/*
StringBuffer sb=new StringBuffer("bInfo: ");
for (int i=0;i<bInfo.length;i++) sb.append(bInfo[i]+" ");
System.out.println(sb.toString());
......@@ -366,7 +580,7 @@ public class EyesisTiff {
TiffSaver tiffSaver = new TiffSaver(path);
tiffSaver.setWritingSequentially(true);
tiffSaver.setLittleEndian(false);
tiffSaver.writeHeader();
tiffSaver.writeHeader();
// tiffSaver.writeIFD(ifd,0); //* SHould not write here, some fields are calculated during writeImage, that writes IFD too
System.out.println("bytes.length="+bytes.length);
tiffSaver.writeImage(bytes,
......
......@@ -39,9 +39,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
......@@ -66,10 +69,15 @@ import ij.gui.GUI;
import ij.gui.GenericDialog;
import ij.io.FileInfo;
import ij.io.OpenDialog;
import ij.io.Opener;
import ij.plugin.frame.PlugInFrame;
import ij.process.ImageConverter;
import ij.process.ImageProcessor;
import ij.text.TextWindow;
import loci.common.RandomAccessInputStream;
import loci.formats.tiff.IFD;
import loci.formats.tiff.IFDList;
import loci.formats.tiff.TiffParser;
......@@ -1035,12 +1043,18 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener {
/* Modified from Opener.java */
ImagePlus openJpegOrGif(String dir, String name) {
ImagePlus imp = null;
boolean isTiff = false;
Image img = Toolkit.getDefaultToolkit().createImage(dir+name);
if (img!=null) {
try {
imp = new ImagePlus(name, img);
} catch (IllegalStateException e) {
return null; // error loading image
//java.lang.IllegalStateException: Error loading image
// Try TIFF
Opener opener=new Opener(); // Reads Tiff images
imp=opener.openImage("", dir+name);
if (imp == null) return null; // error loading image
isTiff = true;
}
if (imp.getType()==ImagePlus.COLOR_RGB) {
......@@ -1049,15 +1063,100 @@ public class JP46_Reader_camera extends PlugInFrame implements ActionListener {
IJ.showStatus("Converting to 32-bits");
new ImageConverter(imp).convertToGray32();
FileInfo fi = new FileInfo();
fi.fileFormat = FileInfo.GIF_OR_JPG;
FileInfo fi = imp.getFileInfo();
fi.fileName = name;
fi.directory = dir;
fi.fileFormat = isTiff?FileInfo.TIFF: FileInfo.GIF_OR_JPG; // even if set originally, it is lost after convertToGray32
imp.setFileInfo(fi);
FileInfo ofi = imp.getOriginalFileInfo();
fi = imp.getFileInfo();
// testing
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);
if (imptiff!=null) {
imptiff.show();
}
// IJ.error("TIFF Dumper", "File path not available or not TIFF file");
IJ.log("\\Clear");
IJ.log("PATH = "+path);
try {
dumpIFDs(path);
} catch(IOException e) {
IJ.error("Tiff Dumper", ""+e);
}
Frame log = WindowManager.getFrame("Log");
if (log!=null) log.toFront();
}
}
return imp;
}
public static void dumpIFDs(String path) throws IOException {
IJ.showStatus("Parsing IFDs");
RandomAccessInputStream in = new RandomAccessInputStream(path);
//TiffParser parser = new TiffParser(in);
TiffParser parser = new TiffParser(in);
IFDList ifdList = parser.getIFDs();
IJ.showStatus("");
for (IFD ifd : ifdList) {
for (Integer key : ifd.keySet()) {
int k = key.intValue();
String name = IFD.getIFDTagName(k)+String.format("(%d [0x%x])", k,k);
String value = prettyValue(ifd.getIFDValue(k), 0);
IJ.log(name + " = " + value);
}
}
in.close();
}
private static String prettyValue(Object value, int indent) {
if (!value.getClass().isArray()) return value.toString()+" ("+value.getClass().toString()+")";
char[] spaceChars = new char[indent];
Arrays.fill(spaceChars, ' ');
String spaces = new String(spaceChars);
StringBuilder sb = new StringBuilder();
sb.append("{\n");
for (int i=0; i<Array.getLength(value); i++) {
sb.append(spaces);
sb.append(" ");
Object component = Array.get(value, i);
sb.append(prettyValue(component, indent + 2));
sb.append("\n");
}
sb.append(spaces);
sb.append("}");
byte [] bstring=new byte [Array.getLength(value)];
for (int i=0;i<bstring.length;i++) {
try {
bstring[i]= (byte) Integer.parseInt(Array.get(value, i).toString());
} catch (NumberFormatException e) {
bstring[i] = 0;
}
}
// String astring=new String((byte []) value);
String astring="";
try {
astring = new String(bstring,"UTF-16");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sb.append("\n\""+astring+"\"");
return sb.toString();
}
@Override
public void setTitle (String title) {
imageTitle=title;
......
/**
**
** LwirCamera.java - Control/image acquisition for LWIR cameras
** (initially for Lepton 3.5 sensors, 103992 sesnor boards)
**
** Copyright (C) 2019 Elphel, Inc.
**
** -----------------------------------------------------------------------------**
**
** LwirCamera.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/>.
** -----------------------------------------------------------------------------**
**
*/
public class LwirCamera {
}
/**
** -----------------------------------------------------------------------------**
** ElphelTiffReader.java
**
** Parse Elphel MakerNote and other Exif fields for both Tiff and JP4
**
** 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.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);
}
}
// 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) {
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;
gammas[i]=((maker_note[i+4]>>16)&0xff)/100.0;
gamma_scales[i]=maker_note[i+4] & 0xffff;
property_table.put("gains_"+i,String.format("%f",gains[i]));
property_table.put("blacks_"+i,String.format("%f",blacks[i]));
property_table.put("gammas_"+i,String.format("%f",gammas[i]));
property_table.put("gamma_scales_"+i,String.format("%d",gamma_scales[i]));
}
if (maker_note.length>=14) {
COMPOSITE= ((maker_note[10] & 0xc0000000)!=0);
if (COMPOSITE) {
HEIGHT1= maker_note[11] & 0xffff;
BLANK1= (maker_note[11]>>16) & 0xffff;
HEIGHT2= maker_note[12] & 0xffff;
BLANK2= (maker_note[12]>>16) & 0xffff;
HEIGHT3=( maker_note[9]>>16) - HEIGHT1-BLANK1-HEIGHT2-BLANK2;
FLIPH1= (((maker_note[10] >> 24) & 1)!=0); // Same value as FLIP_H
FLIPV1= (((maker_note[10] >> 25) & 1)!=0); // Same value as FLIP_V
FLIPH2= (((maker_note[10] >> 26) & 1)!=0);
FLIPV2= (((maker_note[10] >> 27) & 1)!=0);
FLIPH3= (((maker_note[10] >> 28) & 1)!=0);
FLIPV3= (((maker_note[10] >> 29) & 1)!=0);
}
PORTRAIT= (((maker_note[13] >> 7) & 1)!=0);
YTABLEFORC=(((maker_note[13] >> 15) & 1)!=0);
QUALITY= (maker_note[13] & 0x7f);
CQUALITY= ((maker_note[13]>>8) & 0x7f);
if (CQUALITY==0) CQUALITY=QUALITY;
CORING_INDEX_Y= ((maker_note[13]>>16) & 0x7f);
CORING_INDEX_C= ((maker_note[13]>>24) & 0x7f);
if (CORING_INDEX_C==0) CORING_INDEX_C=CORING_INDEX_Y;
}
if (maker_note.length>=12) {
WOI_LEFT= maker_note[8]&0xffff;
WOI_WIDTH= maker_note[8]>>16;
WOI_TOP= maker_note[9]&0xffff;
WOI_HEIGHT= maker_note[9]>>16;
FLIPH= maker_note[10] & 1;
FLIPV= (maker_note[10]>> 1) & 1;
BAYER_MODE=(maker_note[10]>> 2) & 3;
COLOR_MODE=(maker_note[10]>> 4) & 0x0f;
DCM_HOR= (maker_note[10]>> 8) & 0x0f;
DCM_VERT= (maker_note[10]>>12) & 0x0f;
BIN_HOR= (maker_note[10]>>16) & 0x0f;
BIN_VERT= (maker_note[10]>>20) & 0x0f;
property_table.put("WOI_LEFT", String.format("%d",WOI_LEFT));
property_table.put("WOI_WIDTH", String.format("%d",WOI_WIDTH));
property_table.put("WOI_TOP", String.format("%d",WOI_TOP));
property_table.put("WOI_HEIGHT",String.format("%d",WOI_HEIGHT));
property_table.put("FLIPH", String.format("%d",FLIPH));
property_table.put("FLIPV", String.format("%d",FLIPV));
property_table.put("BAYER_MODE",String.format("%d",BAYER_MODE));
property_table.put("COLOR_MODE",((COLOR_MODE==2)?"JP46":((COLOR_MODE==5)?"JP4":((COLOR_MODE==0)?"MONO":"OTHER"))));
property_table.put("DCM_HOR", String.format("%d",DCM_HOR));
property_table.put("DCM_VERT", String.format("%d",DCM_VERT));
property_table.put("BIN_HOR", String.format("%d",BIN_HOR));
property_table.put("BIN_VERT", String.format("%d",BIN_VERT));
}
if (maker_note.length>=14) {
property_table.put("COMPOSITE",String.format("%d",COMPOSITE?1:0));
property_table.put("ORIENTATION",(PORTRAIT?"PORTRAIT":"LANDSCAPE" ));
property_table.put("ORIENTATION",(YTABLEFORC?"1":"0"));
property_table.put("QUALITY",String.format("%d",QUALITY)); //not full
property_table.put("CORING_INDEX_Y",String.format("%d",CORING_INDEX_Y));
property_table.put("CORING_INDEX_C",String.format("%d",CORING_INDEX_C));
}
if (maker_note.length>=16) {
long [] iTemps={
(maker_note[14]>> 0) & 0xffff,
(maker_note[14]>>16) & 0xffff,
(maker_note[15]>> 0) & 0xffff,
(maker_note[15]>>16) & 0xffff};
for (i=0;i<iTemps.length;i++) if (iTemps[i]!=0xffff){
double temperature=(iTemps[i]&0xfff)/16.0;
property_table.put("TEMPERATURE_"+i,""+temperature);
}
}
if (COMPOSITE) {
property_table.put("HEIGHT1",String.format("%d",HEIGHT1));
property_table.put("HEIGHT2",String.format("%d",HEIGHT2));
property_table.put("HEIGHT3",String.format("%d",HEIGHT3));
property_table.put("BLANK_ROWS1",String.format("%d",BLANK1));
property_table.put("BLANK_ROWS2",String.format("%d",BLANK2));
property_table.put("FLIPH1",FLIPH1?"1":"0");
property_table.put("FLIPH2",FLIPH2?"1":"0");
property_table.put("FLIPH3",FLIPH3?"1":"0");
property_table.put("FLIPV1",FLIPV1?"1":"0");
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 (FLIPV!=0) {
swapArrayElements (gains, 1, 3);
swapArrayElements (gains, 0, 2);
swapArrayElements (blacks, 1, 3);
swapArrayElements (blacks, 0, 2);
swapArrayElements (gammas, 1, 3);
swapArrayElements (gammas, 0, 2);
swapArrayElements (gamma_scales,1, 3);
swapArrayElements (gamma_scales,0, 2);
}
if (FLIPH!=0) {
swapArrayElements (gains, 1, 0);
swapArrayElements (gains, 3, 2);
swapArrayElements (blacks, 1, 0);
swapArrayElements (blacks, 3, 2);
swapArrayElements (gammas, 1, 0);
swapArrayElements (gammas, 3, 2);
swapArrayElements (gamma_scales,1, 0);
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
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]));
}
// 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) {
double tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
void swapArrayElements (long[]arr,int i, int j) {
long tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
/* 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) {
int i;
double x, black256 ,k;
int[] gtable = new int[257];
double[] rgtable =new double[256];
int ig;
black256=black*256.0;
k=1.0/(256.0-black256);
if (gamma < 0.13) gamma=0.13;
if (gamma >10.0) gamma=10.0;
for (i=0; i<257; i++) {
x=k*(i-black256);
if (x < 0.0 ) x=0.0;
ig= (int) (0.5+65535.0*Math.pow(x,gamma));
ig=(ig* (int) gamma_scale)/0x400;
if (ig > 0xffff) ig=0xffff;
gtable[i]=ig;
}
/* now gtable[] is the same as was used in the camera */
/* FPGA was using linear interpolation between elements of the gamma table, so now we'll reverse that process */
// double[] rgtable =new double[256];
int indx=0;
double outValue;
for (i=0; i<256; i++ ) {
outValue=128+(i<<8);
while ((gtable[indx+1]<outValue) && (indx<256)) indx++;
if (indx>=256) rgtable[i]=65535.0/256;
else if (gtable[indx+1]==gtable[indx]) rgtable[i]=i;
else rgtable[i]=indx+(1.0*(outValue-gtable[indx]))/(gtable[indx+1] - gtable[indx]);
}
return rgtable;
}
}
/**
** -----------------------------------------------------------------------------**
** ElphelTiffReader.java
**
** loci.format compatible reader for Elphel 8/16 bpp monochrome Tiff files with
** MakerNote
**
**
** 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.util.Hashtable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import loci.formats.FormatException;
import loci.formats.in.MetadataLevel;
import loci.formats.in.TiffReader;
import loci.formats.meta.MetadataStore;
/*
// non-IFD tags (for internal use)
public static final int LITTLE_ENDIAN = 0;
public static final int BIG_TIFF = 1;
public static final int REUSE = 3;
<MakerNote tag="0x927c" format="LONG" count="16" seq="26" dlen="64"/> 37500
package loci.formats.tiff;
IFD.java public static final int MAKER_NOTE = 37500;
* IFD data
{ 0=false, LITTLE_ENDIAN
1=false, BIG_TIFF
0x0100 256=160, ImageWidth
0x0101 257=120, ImageLength
0x0102 258= 16, BitsPerSample
0x0106 262= 1, PhotometricInterpretation
0x0129 297= [I@3d136141, PageNumber
0x8769 34665=242, ExifTag (A pointer to the Exif IFD.)
0x010e 270=[Ljava.lang.String;@640a5e9d, ImageDescription
0x010f 271=Elphel, Make
0xc62f 50735=00:0E:64:10:8F:15, CameraSerialNumber
0x0110 272=LEPTON35_15, Model
0x0111 273=557, StripOffsets
0x0131 305=https://git.elphel.com/Elphel/elphel393, Software
0x9211 37393=122, ImageNumber
0x0112 274=1, Orientation
0x0132 306=2019:05:06 14:41:51, DateTime
0x0115 277=1, SamplesPerPixel
0x0116 278=120, RowsPerStrip
0x0117 279=38400, StripByteCounts
0x00fe 254=0 NewSubfileType }
*/
public class ElphelTiffReader extends TiffReader{ // BaseTiffReader {
// -- Constants --
public static final String ELPHEL_PROPERTY_PREFIX = "ELPHEL_";
/** Merge SubIFDs into the main IFD list. */
// protected transient boolean mergeSubIFDs = true; // false;
/** Logger for this class. */
private static final Logger LOGGER =
LoggerFactory.getLogger(ElphelTiffReader.class);
// public static final String[] ELPHEL_TIFF_SUFFIXES =
// {"tif", "tiff"}; // , "tf2", "tf8", "btf"};
// public static final String[] COMPANION_SUFFIXES = {"xml", "txt"};
// public static final int IMAGEJ_TAG = 50839;
// -- Fields --
// private String companionFile;
// private String description;
// private String calibrationUnit;
// private Double physicalSizeZ;
// private Double timeIncrement;
// private Integer xOrigin, yOrigin;
// -- Constructor --
/** 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;
LOGGER.info("ElphelTiffReader(), after supper(), mergeSubIFDs = true;");
}
// -- IFormatReader API methods --
@Override
protected void initFile(java.lang.String id)
throws FormatException,
java.io.IOException
{
LOGGER.info("Starting initFile() method");
super.initFile(id);
LOGGER.info("Ending initFile() method");
}
/* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */
@Override
public String[] getSeriesUsedFiles(boolean noPixels) {
return super.getSeriesUsedFiles(noPixels);
// if (noPixels) {
// return companionFile == null ? null : new String[] {companionFile};
// }
// if (companionFile != null) return new String[] {companionFile, currentId};
// return new String[] {currentId};
}
/* @see loci.formats.IFormatReader#close(boolean) */
@Override
public void close(boolean fileOnly) throws IOException {
LOGGER.info("close("+fileOnly+") before super");
super.close(fileOnly);
LOGGER.info("close("+fileOnly+") after super");
if (!fileOnly) {
// companionFile = null;
// description = null;
// calibrationUnit = null;
// physicalSizeZ = null;
// timeIncrement = null;
// xOrigin = null;
// yOrigin = null;
}
}
// -- Internal BaseTiffReader API methods --
/* @see BaseTiffReader#initStandardMetadata() */
@Override
protected void initStandardMetadata() throws FormatException, IOException {
LOGGER.info("initStandardMetadata() - before super()");
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();
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");
}
// check for ImageJ-style TIFF comment
boolean ij = checkCommentImageJ(comment);
// if (ij) parseCommentImageJ(comment);
/*
// check for MetaMorph-style TIFF comment
boolean metamorph = checkCommentMetamorph(comment);
if (metamorph && level != MetadataLevel.MINIMUM) {
parseCommentMetamorph(comment);
}
put("MetaMorph", metamorph ? "yes" : "no");
// check for other INI-style comment
if (!ij && !metamorph && level != MetadataLevel.MINIMUM) {
parseCommentGeneric(comment);
}
*/
// check for another file with the same name
/*
if (isGroupFiles()) {
Location currentFile = new Location(currentId).getAbsoluteFile();
String currentName = currentFile.getName();
Location directory = currentFile.getParentFile();
String[] files = directory.list(true);
if (files != null) {
for (String file : files) {
String name = file;
if (name.indexOf(".") != -1) {
name = name.substring(0, name.indexOf("."));
}
if (currentName.startsWith(name) &&
checkSuffix(name, COMPANION_SUFFIXES))
{
companionFile = new Location(directory, file).getAbsolutePath();
break;
}
}
}
}
*/
}
/* @see BaseTiffReader#initMetadataStore() */
@Override
protected void initMetadataStore() throws FormatException {
super.initMetadataStore();
MetadataStore store = makeFilterMetadata();
// if (description != null) {
// store.setImageDescription(description, 0);
// }
populateMetadataStoreImageJ(store);
}
// -- Helper methods --
// Convert to Elphel-specific parameters
/**
* Checks the original metadata table for ImageJ-specific information
* to propagate into the metadata store.
*/
private void populateMetadataStoreImageJ(MetadataStore store) {
// TODO: Perhaps we should only populate the physical Z size if the unit is
// a known, physical quantity such as "micron" rather than "pixel".
// e.g.: if (calibrationUnit.equals("micron"))
/*
if (physicalSizeZ != null) {
double zDepth = physicalSizeZ.doubleValue();
if (zDepth < 0) zDepth = -zDepth;
store.setPixelsPhysicalSizeZ(new PositiveFloat(zDepth), 0);
}
if (timeIncrement != null) {
store.setPixelsTimeIncrement(timeIncrement, 0);
}
*/
}
//
private boolean checkCommentImageJ(String comment) {
return comment != null && comment.startsWith("ImageJ=");
}
}
# 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
# Could not find loci.formats.in.URLReader
# Could not find loci.formats.in.SlideBook6Reader
# "loci.formats.in.MicroCTReader" is not valid.
# Could not find loci.formats.in.CV7000Reader
# Could not find loci.formats.in.KLBReader
# java.lang.ClassNotFoundException: loci.formats.in.SlideBook6Reader
# at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_201]
#Elphel readers
com.elphel.imagej.readers.ElphelTiffReader # extensions same as TiffReader
loci.formats.in.FilePatternReader # pattern
##loci.formats.in.URLReader[type=external] # urlreader # Could not find loci.formats.in.URLReader
# readers for compressed/archive files
loci.formats.in.ZipReader # zip
# javax.imageio readers
loci.formats.in.APNGReader # png [javax.imageio]
loci.formats.in.JPEGReader # jpg, jpeg [javax.imageio]
# external readers with unique file extensions
##loci.formats.in.SlideBook6Reader[type=external] # sld # Could not find loci.formats.in.SlideBook6Reader
loci.formats.in.ScreenReader[type=external] # .screen
# standalone readers with unique file extensions
loci.formats.in.PGMReader # pgm
loci.formats.in.FitsReader # fits
loci.formats.in.PCXReader # pcx
loci.formats.in.GIFReader # gif
loci.formats.in.BMPReader # bmp
loci.formats.in.IPLabReader # ipl
loci.formats.in.IvisionReader # ipm
loci.formats.in.DeltavisionReader # dv, r3d
loci.formats.in.MRCReader # mrc, st, ali
loci.formats.in.GatanReader # dm3
loci.formats.in.GatanDM2Reader # dm2
loci.formats.in.ImarisReader # ims
loci.formats.in.OpenlabRawReader # raw
loci.formats.in.OMEXMLReader # ome
loci.formats.in.LIFReader # lif
loci.formats.in.AVIReader # avi
loci.formats.in.PictReader # pict, pct
loci.formats.in.SDTReader # sdt
loci.formats.in.SPCReader # spc
loci.formats.in.EPSReader # eps, epsi
loci.formats.in.SlidebookReader # sld
loci.formats.in.AliconaReader # al3d
loci.formats.in.MNGReader # mng
loci.formats.in.KhorosReader # xv
loci.formats.in.VisitechReader # html, xys
loci.formats.in.LIMReader # lim
loci.formats.in.PSDReader # psd
loci.formats.in.InCellReader # xdce
loci.formats.in.L2DReader # l2d
loci.formats.in.FEIReader # img
loci.formats.in.NAFReader # naf
loci.formats.in.MINCReader # mnc
loci.formats.in.QTReader # mov
loci.formats.in.MRWReader # mrw
loci.formats.in.TillVisionReader # vws
loci.formats.in.ARFReader # arf
loci.formats.in.CellomicsReader # c01
loci.formats.in.LiFlimReader # fli
loci.formats.in.TargaReader # tga
loci.formats.in.OxfordInstrumentsReader # top
loci.formats.in.VGSAMReader # dti
loci.formats.in.HISReader # his
loci.formats.in.WATOPReader # wat
loci.formats.in.SeikoReader # xqd, xqf
loci.formats.in.TopometrixReader # tfr, ffr, zfr, zfp, 2fl
loci.formats.in.UBMReader # pr3
loci.formats.in.QuesantReader # afm
loci.formats.in.BioRadGelReader # 1sc
loci.formats.in.RHKReader # sm2, sm3
loci.formats.in.MolecularImagingReader # stp
loci.formats.in.CellWorxReader # pnl, htd
loci.formats.in.Ecat7Reader # v
loci.formats.in.VarianFDFReader # fdf
loci.formats.in.AIMReader # aim
loci.formats.in.InCell3000Reader # frm
loci.formats.in.SpiderReader # spi
loci.formats.in.VolocityReader # mvd2
loci.formats.in.ImagicReader # hed
loci.formats.in.HamamatsuVMSReader # vms
loci.formats.in.CellSensReader # vsi
loci.formats.in.INRReader # inr
loci.formats.in.KodakReader # bip
loci.formats.in.VolocityClippingReader # acff
loci.formats.in.ZeissCZIReader # czi
loci.formats.in.SIFReader # sif
loci.formats.in.NDPISReader # ndpis
loci.formats.in.PovrayReader # df3
loci.formats.in.IMODReader # mod
loci.formats.in.FakeReader # fake
loci.formats.in.AFIReader # afi
loci.formats.in.ImspectorReader # msr
loci.formats.in.BioRadSCNReader # scn
loci.formats.in.ZeissLMSReader # lms
loci.formats.in.PQBinReader # bin
loci.formats.in.FlowSightReader # cif
loci.formats.in.IM3Reader # im3
loci.formats.in.I2IReader # i2i
loci.formats.in.SPEReader # spe
loci.formats.in.OIRReader # oir
##loci.formats.in.KLBReader # klb # Could not find loci.formats.in.KLBReader
##loci.formats.in.MicroCTReader # vff # "loci.formats.in.MicroCTReader" is not valid.
# multi-extension messes
loci.formats.in.JEOLReader # dat, img, par
loci.formats.in.NiftiReader # hdr, img, nii, nii.gz
loci.formats.in.AnalyzeReader # hdr, img
loci.formats.in.APLReader # apl, mtb, tnb
loci.formats.in.NRRDReader # nrrd, nhdr, pic
loci.formats.in.ICSReader # ics, ids
loci.formats.in.PerkinElmerReader # rec, ano, csv, htm, tim, zpo, 2, 3, ...
loci.formats.in.AmiraReader # am, amiramesh, grey, hx, labels, ...
loci.formats.in.ScanrReader # dat, xml, tif
loci.formats.in.BDReader # exp, tif
loci.formats.in.UnisokuReader # dat, hdr
loci.formats.in.PDSReader # hdr, img
loci.formats.in.FujiReader # inf, img
loci.formats.in.OperettaReader # xml, tif, tiff
loci.formats.in.InveonReader # hdr, ct.img, cat, ...
loci.formats.in.CellVoyagerReader # xml, tif
loci.formats.in.ColumbusReader # xml, tif
##loci.formats.in.CV7000Reader # wpi # Could not find loci.formats.in.CV7000Reader
# standard PIC reader must go last (it accepts any PIC)
loci.formats.in.BioRadReader # pic
# readers requiring third-party libraries
loci.formats.in.FV1000Reader # oib, oif, various [POI]
loci.formats.in.ZeissZVIReader # zvi [POI]
loci.formats.in.IPWReader # ipw [POI]
loci.formats.in.JPEG2000Reader # jp2, j2k [JAI-ImageIO]
loci.formats.in.JPXReader # jpx [JAI-ImageIO]
loci.formats.in.ND2Reader # nd2, jp2 [JAI-ImageIO]
loci.formats.in.PCIReader # cxd [POI]
loci.formats.in.ImarisHDFReader # ims [NetCDF]
loci.formats.in.CellH5Reader # ch5 [JHDF]
loci.formats.in.WlzReader # wlz [JWlz]
loci.formats.in.VeecoReader # hdf [NetCDF]
# TIFF-based readers with unique file extensions
loci.formats.in.ZeissLSMReader # lsm, mdb [MDB Tools]
loci.formats.in.SEQReader # seq
loci.formats.in.GelReader # gel
loci.formats.in.ImarisTiffReader # ims
loci.formats.in.FlexReader # flex [LuraWave]
loci.formats.in.SVSReader # svs
loci.formats.in.ImaconReader # fff
loci.formats.in.LEOReader # sxm
loci.formats.in.JPKReader # jpk
loci.formats.in.NDPIReader # ndpi
loci.formats.in.PCORAWReader # pcoraw
# TIFF-based readers with slow isThisType
loci.formats.in.OMETiffReader # tif
loci.formats.in.PyramidTiffReader # tif, tiff
loci.formats.in.MIASReader # tif
loci.formats.in.TCSReader # xml, tif
loci.formats.in.LeicaReader # lei, tif
loci.formats.in.NikonReader # nef, tif
loci.formats.in.FluoviewReader # tif
loci.formats.in.PrairieReader # xml, cfg, tif
loci.formats.in.MetamorphReader # stk, tif, nd, scan
loci.formats.in.MicromanagerReader # txt, tif
loci.formats.in.ImprovisionTiffReader # tif
loci.formats.in.MetamorphTiffReader # tif
loci.formats.in.NikonTiffReader # tif
loci.formats.in.PhotoshopTiffReader # tif
loci.formats.in.FEITiffReader # tif
loci.formats.in.SimplePCITiffReader # tif
loci.formats.in.NikonElementsTiffReader # tif
loci.formats.in.TrestleReader # tif
loci.formats.in.SISReader # tif
loci.formats.in.DNGReader # cr2, crw, jpg, thm, wav, tif?
loci.formats.in.ZeissTIFFReader # tif
loci.formats.in.LeicaSCNReader # scn
loci.formats.in.VectraReader # tif, tiff, qptiff
loci.formats.in.SlidebookTiffReader # tiff
loci.formats.in.IonpathMIBITiffReader # tif, tiff
# standard TIFF reader must go last (it accepts any TIFF)
loci.formats.in.TiffDelegateReader # tif, tiff
# standard text reader must go last (it accepts any plaintext)
loci.formats.in.TextReader # txt, csv
# non-TIFF readers with slow isThisType
loci.formats.in.BurleighReader # img
loci.formats.in.OpenlabReader # liff
loci.formats.in.DicomReader # dcm, dicom
loci.formats.in.SMCameraReader # (no extension)
loci.formats.in.SBIGReader # (no extension)
loci.formats.in.HRDGDFReader # (no extension)
loci.formats.in.HitachiReader # txt, tif, jpg, bmp
loci.formats.in.BrukerReader # fid, acqp
loci.formats.in.CanonRawReader # cr2, crw, jpg, thm, wav
loci.formats.in.OBFReader # obf, msr
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