package ij.plugin;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.io.*;
import java.awt.*;
import java.io.*;
import java.util.Properties;
/** This plugin opens a multi-page TIFF file as a virtual stack. It
implements the File/Import/TIFF Virtual Stack command. */
public class FileInfoVirtualStack extends VirtualStack implements PlugIn {
FileInfo[] info;
int nImages;
/* Default constructor. */
public FileInfoVirtualStack() {}
/* Constructs a FileInfoVirtualStack from a FileInfo object. */
public FileInfoVirtualStack(FileInfo fi) {
info = new FileInfo[1];
info[0] = fi;
open(true);
}
/* Constructs a FileInfoVirtualStack from a FileInfo
object and displays it if 'show' is true. */
public FileInfoVirtualStack(FileInfo fi, boolean show) {
info = new FileInfo[1];
info[0] = fi;
open(show);
}
public void run(String arg) {
OpenDialog od = new OpenDialog("Open TIFF", arg);
String name = od.getFileName();
if (name==null) return;
if (name.endsWith(".zip")) {
IJ.error("Virtual Stack", "ZIP compressed stacks not supported");
return;
}
String dir = od.getDirectory();
TiffDecoder td = new TiffDecoder(dir, name);
if (IJ.debugMode) td.enableDebugging();
IJ.showStatus("Decoding TIFF header...");
try {info = td.getTiffInfo();}
catch (IOException e) {
String msg = e.getMessage();
if (msg==null||msg.equals("")) msg = ""+e;
IJ.error("TiffDecoder", msg);
return;
}
if (info==null || info.length==0) {
IJ.error("Virtual Stack", "This does not appear to be a TIFF stack");
return;
}
if (IJ.debugMode)
IJ.log(info[0].debugInfo);
open(true);
}
void open(boolean show) {
FileInfo fi = info[0];
int n = fi.nImages;
if (info.length==1 && n>1) {
info = new FileInfo[n];
long size = fi.width*fi.height*fi.getBytesPerPixel();
for (int i=0; i<n; i++) {
info[i] = (FileInfo)fi.clone();
info[i].nImages = 1;
info[i].longOffset = fi.getOffset() + i*(size + fi.gapBetweenImages);
}
}
nImages = info.length;
FileOpener fo = new FileOpener(info[0] );
ImagePlus imp = fo.open(false);
Properties props = fo.decodeDescriptionString(fi);
ImagePlus imp2 = new ImagePlus(fi.fileName, this);
imp2.setFileInfo(fi);
if (imp!=null && props!=null) {
setBitDepth(imp.getBitDepth());
imp2.setCalibration(imp.getCalibration());
imp2.setOverlay(imp.getOverlay());
if (fi.info!=null)
imp2.setProperty("Info", fi.info);
int channels = getInt(props,"channels");
int slices = getInt(props,"slices");
int frames = getInt(props,"frames");
if (channels*slices*frames==nImages) {
imp2.setDimensions(channels, slices, frames);
if (getBoolean(props, "hyperstack"))
imp2.setOpenAsHyperStack(true);
}
if (channels>1 && fi.description!=null) {
int mode = CompositeImage.COMPOSITE;
if (fi.description.indexOf("mode=color")!=-1)
mode = CompositeImage.COLOR;
else if (fi.description.indexOf("mode=gray")!=-1)
mode = CompositeImage.GRAYSCALE;
imp2 = new CompositeImage(imp2, mode);
}
}
if (show) imp2.show();
}
int getInt(Properties props, String key) {
Double n = getNumber(props, key);
return n!=null?(int)n.doubleValue():1;
}
Double getNumber(Properties props, String key) {
String s = props.getProperty(key);
if (s!=null) {
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {}
}
return null;
}
boolean getBoolean(Properties props, String key) {
String s = props.getProperty(key);
return s!=null&&s.equals("true")?true:false;
}
/** Deletes the specified image, were 1<=n<=nImages. */
public void deleteSlice(int n) {
if (n<1 || n>nImages)
throw new IllegalArgumentException("Argument out of range: "+n);
if (nImages<1) return;
for (int i=n; i<nImages; i++)
info[i-1] = info[i];
info[nImages-1] = null;
nImages--;
}
/** Returns an ImageProcessor for the specified image,
were 1<=n<=nImages. Returns null if the stack is empty.
*/
public ImageProcessor getProcessor(int n) {
if (n<1 || n>nImages)
throw new IllegalArgumentException("Argument out of range: "+n);
if (IJ.debugMode) IJ.log("FileInfoVirtualStack: "+n+", "+info[n-1].getOffset());
//if (n>1) IJ.log(" "+(info[n-1].getOffset()-info[n-2].getOffset()));
info[n-1].nImages = 1; // why is this needed?
FileOpener fo = new FileOpener(info[n-1]);
ImagePlus imp = fo.open(false);
if (imp!=null)
return imp.getProcessor();
else {
int w=getWidth(), h=getHeight();
IJ.log("Read error or file not found ("+n+"): "+info[n-1].directory+info[n-1].fileName);
switch (getBitDepth()) {
case 8: return new ByteProcessor(w, h);
case 16: return new ShortProcessor(w, h);
case 24: return new ColorProcessor(w, h);
case 32: return new FloatProcessor(w, h);
default: return null;
}
}
}
/** Returns the number of images in this stack. */
public int getSize() {
return nImages;
}
/** Returns the label of the Nth image. */
public String getSliceLabel(int n) {
if (n<1 || n>nImages)
throw new IllegalArgumentException("Argument out of range: "+n);
if (info[0].sliceLabels==null || info[0].sliceLabels.length!=nImages)
return null;
else
return info[0].sliceLabels[n-1];
}
public int getWidth() {
return info[0].width;
}
public int getHeight() {
return info[0].height;
}
}