|
FileOpener |
|
package ij.io;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.GZIPInputStream;
import ij.gui.*;
import ij.process.*;
import ij.measure.*;
import ij.*;
/**
* Opens or reverts an image specified by a FileInfo object. Images can
* be loaded from either a file (directory+fileName) or a URL (url+fileName).
* Here is an example:
* <pre>
* public class FileInfo_Test implements PlugIn {
* public void run(String arg) {
* FileInfo fi = new FileInfo();
* fi.width = 256;
* fi.height = 254;
* fi.offset = 768;
* fi.fileName = "blobs.tif";
* fi.directory = "/Users/wayne/Desktop/";
* new FileOpener(fi).open();
* }
* }
* </pre>
*/
public class FileOpener {
private FileInfo fi;
private int width, height;
public FileOpener(FileInfo fi) {
this.fi = fi;
if (fi!=null) {
width = fi.width;
height = fi.height;
}
if (IJ.debugMode) IJ.log("FileOpener: "+fi);
}
/** Opens the image and displays it. */
public void open() {
open(true);
}
/** Opens the image. Displays it if 'show' is
true. Returns an ImagePlus object if successful. */
public ImagePlus open(boolean show) {
ImagePlus imp=null;
Object pixels;
ProgressBar pb=null;
ImageProcessor ip;
ColorModel cm = createColorModel(fi);
if (fi.nImages>1)
{return openStack(cm, show);}
switch (fi.fileType) {
case FileInfo.GRAY8:
case FileInfo.COLOR8:
case FileInfo.BITMAP:
pixels = readPixels(fi);
if (pixels==null) return null;
ip = new ByteProcessor(width, height, (byte[])pixels, cm);
imp = new ImagePlus(fi.fileName, ip);
break;
case FileInfo.GRAY16_SIGNED:
case FileInfo.GRAY16_UNSIGNED:
case FileInfo.GRAY12_UNSIGNED:
pixels = readPixels(fi);
if (pixels==null) return null;
ip = new ShortProcessor(width, height, (short[])pixels, cm);
imp = new ImagePlus(fi.fileName, ip);
break;
case FileInfo.GRAY32_INT:
case FileInfo.GRAY32_UNSIGNED:
case FileInfo.GRAY32_FLOAT:
case FileInfo.GRAY24_UNSIGNED:
case FileInfo.GRAY64_FLOAT:
pixels = readPixels(fi);
if (pixels==null) return null;
ip = new FloatProcessor(width, height, (float[])pixels, cm);
imp = new ImagePlus(fi.fileName, ip);
break;
case FileInfo.RGB:
case FileInfo.BGR:
case FileInfo.ARGB:
case FileInfo.BARG:
case FileInfo.RGB_PLANAR:
pixels = readPixels(fi);
if (pixels==null) return null;
ip = new ColorProcessor(width, height, (int[])pixels);
imp = new ImagePlus(fi.fileName, ip);
break;
case FileInfo.RGB48:
case FileInfo.RGB48_PLANAR:
Object[] pixelArray = (Object[])readPixels(fi);
if (pixelArray==null) return null;
ImageStack stack = new ImageStack(width, height);
stack.addSlice("Red", pixelArray[0]);
stack.addSlice("Green", pixelArray[1]);
stack.addSlice("Blue", pixelArray[2]);
imp = new ImagePlus(fi.fileName, stack);
imp = new CompositeImage(imp, 3);
imp.getProcessor().resetMinAndMax();
break;
}
imp.setFileInfo(fi);
setCalibration(imp);
if (fi.info!=null)
imp.setProperty("Info", fi.info);
if (show) imp.show();
return imp;
}
/** Opens a stack of images. */
ImagePlus openStack(ColorModel cm, boolean show) {
ImageStack stack = new ImageStack(fi.width, fi.height, cm);
long skip = fi.longOffset>0?fi.longOffset:fi.offset;
Object pixels;
try {
ImageReader reader = new ImageReader(fi);
InputStream is = createInputStream(fi);
if (is==null) return null;
IJ.resetEscape();
for (int i=1; i<=fi.nImages; i++) {
IJ.showStatus("Reading: " + i + "/" + fi.nImages);
if (IJ.escapePressed()) {
IJ.beep();
IJ.showProgress(1.0);
return null;
}
pixels = reader.readPixels(is, skip);
if (pixels==null) break;
stack.addSlice(null, pixels);
skip = fi.gapBetweenImages;
IJ.showProgress(i, fi.nImages);
}
is.close();
}
catch (Exception e) {
IJ.log("" + e);
}
catch(OutOfMemoryError e) {
IJ.outOfMemory(fi.fileName);
stack.trim();
}
IJ.showProgress(1.0);
if (stack.getSize()==0)
return null;
if (fi.sliceLabels!=null && fi.sliceLabels.length<=stack.getSize()) {
for (int i=0; i<fi.sliceLabels.length; i++)
stack.setSliceLabel(fi.sliceLabels[i], i+1);
}
ImagePlus imp = new ImagePlus(fi.fileName, stack);
if (fi.info!=null)
imp.setProperty("Info", fi.info);
if (show) imp.show();
imp.setFileInfo(fi);
setCalibration(imp);
ImageProcessor ip = imp.getProcessor();
if (ip.getMin()==ip.getMax()) // find stack min and max if first slice is blank
setStackDisplayRange(imp);
IJ.showProgress(1.0);
return imp;
}
void setStackDisplayRange(ImagePlus imp) {
ImageStack stack = imp.getStack();
double min = Double.MAX_VALUE;
double max = -Double.MAX_VALUE;
int n = stack.getSize();
for (int i=1; i<=n; i++) {
IJ.showStatus("Calculating stack min and max: "+i+"/"+n);
ImageProcessor ip = stack.getProcessor(i);
ip.resetMinAndMax();
if (ip.getMin()<min)
min = ip.getMin();
if (ip.getMax()>max)
max = ip.getMax();
}
imp.getProcessor().setMinAndMax(min, max);
imp.updateAndDraw();
}
/** Restores original disk or network version of image. */
public void revertToSaved(ImagePlus imp) {
Image img;
ProgressBar pb = IJ.getInstance().getProgressBar();
ImageProcessor ip;
String path = fi.directory + fi.fileName;
if (fi.fileFormat==fi.GIF_OR_JPG) {
// restore gif or jpg
img = Toolkit.getDefaultToolkit().createImage(path);
imp.setImage(img);
if (imp.getType()==ImagePlus.COLOR_RGB)
Opener.convertGrayJpegTo8Bits(imp);
return;
}
if (fi.fileFormat==fi.DICOM) {
// restore DICOM
ImagePlus imp2 = (ImagePlus)IJ.runPlugIn("ij.plugin.DICOM", path);
if (imp2!=null)
imp.setProcessor(null, imp2.getProcessor());
return;
}
if (fi.fileFormat==fi.BMP) {
// restore BMP
ImagePlus imp2 = (ImagePlus)IJ.runPlugIn("ij.plugin.BMP_Reader", path);
if (imp2!=null)
imp.setProcessor(null, imp2.getProcessor());
return;
}
if (fi.fileFormat==fi.PGM) {
// restore PGM
ImagePlus imp2 = (ImagePlus)IJ.runPlugIn("ij.plugin.PGM_Reader", path);
if (imp2!=null)
imp.setProcessor(null, imp2.getProcessor());
return;
}
if (fi.fileFormat==fi.ZIP_ARCHIVE) {
// restore ".zip" file
ImagePlus imp2 = (new Opener()).openZip(path);
if (imp2!=null)
imp.setProcessor(null, imp2.getProcessor());
return;
}
// restore PNG or another image opened using ImageIO
if (fi.fileFormat==fi.IMAGEIO) {
ImagePlus imp2 = (new Opener()).openUsingImageIO(path);
if (imp2!=null) imp.setProcessor(null, imp2.getProcessor());
return;
}
if (fi.nImages>1)
return;
ColorModel cm;
if (fi.url==null || fi.url.equals(""))
IJ.showStatus("Loading: " + path);
else
IJ.showStatus("Loading: " + fi.url + fi.fileName);
Object pixels = readPixels(fi);
if (pixels==null) return;
cm = createColorModel(fi);
switch (fi.fileType) {
case FileInfo.GRAY8:
case FileInfo.COLOR8:
case FileInfo.BITMAP:
ip = new ByteProcessor(width, height, (byte[])pixels, cm);
imp.setProcessor(null, ip);
break;
case FileInfo.GRAY16_SIGNED:
case FileInfo.GRAY16_UNSIGNED:
case FileInfo.GRAY12_UNSIGNED:
ip = new ShortProcessor(width, height, (short[])pixels, cm);
imp.setProcessor(null, ip);
break;
case FileInfo.GRAY32_INT:
case FileInfo.GRAY32_FLOAT:
ip = new FloatProcessor(width, height, (float[])pixels, cm);
imp.setProcessor(null, ip);
break;
case FileInfo.RGB:
case FileInfo.BGR:
case FileInfo.ARGB:
case FileInfo.RGB_PLANAR:
img = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width, height, (int[])pixels, 0, width));
imp.setImage(img);
break;
}
}
void setCalibration(ImagePlus imp) {
if (fi.fileType==FileInfo.GRAY16_SIGNED) {
if (IJ.debugMode) IJ.log("16-bit signed");
double[] coeff = new double[2];
coeff[0] = -32768.0;
coeff[1] = 1.0;
imp.getLocalCalibration().setFunction(Calibration.STRAIGHT_LINE, coeff, "gray value");
}
Properties props = decodeDescriptionString();
Calibration cal = imp.getCalibration();
if (fi.pixelWidth>0.0 && fi.unit!=null) {
cal.pixelWidth = fi.pixelWidth;
cal.pixelHeight = fi.pixelHeight;
cal.pixelDepth = fi.pixelDepth;
cal.setUnit(fi.unit);
}
if (fi.valueUnit!=null) {
int f = fi.calibrationFunction;
if ((f>=Calibration.STRAIGHT_LINE && f<=Calibration.RODBARD2 && fi.coefficients!=null)
|| f==Calibration.UNCALIBRATED_OD) {
boolean zeroClip = props!=null && props.getProperty("zeroclip", "false").equals("true");
cal.setFunction(f, fi.coefficients, fi.valueUnit, zeroClip);
}
}
if (fi.frameInterval!=0.0)
cal.frameInterval = fi.frameInterval;
if (props==null)
return;
cal.xOrigin = getDouble(props,"xorigin");
cal.yOrigin = getDouble(props,"yorigin");
cal.zOrigin = getDouble(props,"zorigin");
cal.info = props.getProperty("info");
cal.fps = getDouble(props,"fps");
cal.loop = getBoolean(props, "loop");
cal.frameInterval = getDouble(props,"finterval");
cal.setTimeUnit(props.getProperty("tunit", "sec"));
double displayMin = getDouble(props,"min");
double displayMax = getDouble(props,"max");
if (!(displayMin==0.0&&displayMax==0.0)) {
int type = imp.getType();
ImageProcessor ip = imp.getProcessor();
if (type==ImagePlus.GRAY8 || type==ImagePlus.COLOR_256)
ip.setMinAndMax(displayMin, displayMax);
else if (type==ImagePlus.GRAY16 || type==ImagePlus.GRAY32) {
if (ip.getMin()!=displayMin || ip.getMax()!=displayMax)
ip.setMinAndMax(displayMin, displayMax);
}
}
int stackSize = imp.getStackSize();
if (stackSize>1) {
int channels = (int)getDouble(props,"channels");
int slices = (int)getDouble(props,"slices");
int frames = (int)getDouble(props,"frames");
if (channels==0) channels = 1;
if (slices==0) slices = 1;
if (frames==0) frames = 1;
//IJ.log("setCalibration: "+channels+" "+slices+" "+frames);
if (channels*slices*frames==stackSize)
imp.setDimensions(channels, slices, frames);
}
}
/** Returns an IndexColorModel for the image specified by this FileInfo. */
public ColorModel createColorModel(FileInfo fi) {
if (fi.fileType==FileInfo.COLOR8 && fi.lutSize>0)
return new IndexColorModel(8, fi.lutSize, fi.reds, fi.greens, fi.blues);
else
return LookUpTable.createGrayscaleColorModel(fi.whiteIsZero);
}
/** Returns an InputStream for the image described by this FileInfo. */
public InputStream createInputStream(FileInfo fi) throws IOException, MalformedURLException {
InputStream is = null;
if (fi.inputStream!=null)
is = fi.inputStream;
else if (fi.url!=null && !fi.url.equals(""))
is = new URL(fi.url+fi.fileName).openStream();
else {
if (fi.directory.length()>0 && !fi.directory.endsWith(Prefs.separator))
fi.directory += Prefs.separator;
File f = new File(fi.directory + fi.fileName);
if (f==null || f.isDirectory() || !validateFileInfo(f, fi))
is = null;
else
is = new FileInputStream(f);
}
if (is!=null && (fi.fileName.endsWith(".gz")||fi.fileName.endsWith(".GZ")))
is = new GZIPInputStream(is);
return is;
}
static boolean validateFileInfo(File f, FileInfo fi) {
long offset = fi.longOffset>0?fi.longOffset:fi.offset;
long length = 0;
if (fi.width<=0 || fi.height<0) {
error("Width or height <= 0.", fi, offset, length);
return false;
}
if (offset>=0 && offset<1000)
return true;
if (offset<0) {
error("Offset is negative.", fi, offset, length);
return false;
}
if (fi.fileType==FileInfo.BITMAP || fi.compression!=FileInfo.COMPRESSION_NONE)
return true;
length = f.length();
long size = fi.width*fi.height*fi.getBytesPerPixel();
size = fi.nImages>1?size:size/4;
if (fi.height==1) size = 0; // allows plugins to read info of unknown length at end of file
if (offset+size>length) {
error("Offset + image size > file length.", fi, offset, length);
return false;
}
return true;
}
static void error(String msg, FileInfo fi, long offset, long length) {
IJ.error("FileOpener", "FileInfo parameter error. \n"
+msg + "\n \n"
+" Width: " + fi.width + "\n"
+" Height: " + fi.height + "\n"
+" Offset: " + offset + "\n"
+" Bytes/pixel: " + fi.getBytesPerPixel() + "\n"
+(length>0?" File length: " + length + "\n":"")
);
}
/** Reads the pixel data from an image described by a FileInfo object. */
Object readPixels(FileInfo fi) {
Object pixels = null;
try {
InputStream is = createInputStream(fi);
if (is==null)
return null;
ImageReader reader = new ImageReader(fi);
pixels = reader.readPixels(is);
is.close();
}
catch (Exception e) {
if (!Macro.MACRO_CANCELED.equals(e.getMessage())) {
CharArrayWriter caw = new CharArrayWriter();
PrintWriter pw = new PrintWriter(caw);
e.printStackTrace(pw);
String s = caw.toString();
if (IJ.getInstance()!=null)
new ij.text.TextWindow("Exception", s, 350, 250);
else
IJ.log(s);
}
}
return pixels;
}
Properties decodeDescriptionString() {
if (fi.description==null || fi.description.length()<7)
return null;
if (IJ.debugMode)
IJ.log("Image Description: " + new String(fi.description).replace('\n',' '));
if (!fi.description.startsWith("ImageJ"))
return null;
Properties props = new Properties();
InputStream is = new ByteArrayInputStream(fi.description.getBytes());
try {props.load(is); is.close();}
catch (IOException e) {return null;}
fi.unit = props.getProperty("unit","");
Double n = getNumber(props,"cf");
if (n!=null) fi.calibrationFunction = n.intValue();
double c[] = new double[5];
int count = 0;
for (int i=0; i<5; i++) {
n = getNumber(props,"c"+i);
if (n==null) break;
c[i] = n.doubleValue();
count++;
}
if (count>=2) {
fi.coefficients = new double[count];
for (int i=0; i<count; i++)
fi.coefficients[i] = c[i];
}
fi.valueUnit = props.getProperty("vunit");
n = getNumber(props,"images");
if (n!=null && n.doubleValue()>1.0)
fi.nImages = (int)n.doubleValue();
if (fi.nImages>1) {
double spacing = getDouble(props,"spacing");
if (spacing!=0.0)
fi.pixelDepth = spacing;
}
return props;
}
private Double getNumber(Properties props, String key) {
String s = props.getProperty(key);
if (s!=null) {
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {}
}
return null;
}
private double getDouble(Properties props, String key) {
Double n = getNumber(props, key);
return n!=null?n.doubleValue():0.0;
}
private boolean getBoolean(Properties props, String key) {
String s = props.getProperty(key);
return s!=null&&s.equals("true")?true:false;
}
}
|
FileOpener |
|