|
RoiDecoder |
|
package ij.io;
import ij.gui.*;
import java.io.*;
import java.util.*;
import java.net.*;
/* ImageJ/NIH Image 64 byte ROI outline header
2 byte numbers are big-endian signed shorts
0-3 "Iout"
4-5 version (>=217)
6-7 roi type
8-9 top
10-11 left
12-13 bottom
14-15 right
16-17 NCoordinates
18-33 x1,y1,x2,y2 (straight line)
34-35 line width (unused)
36-39 ShapeRoi size (type must be 1 if this value>0)
40-63 reserved (zero)
64-67 x0, y0 (polygon)
68-71 x1, y1
etc.
*/
/** Decodes an ImageJ, NIH Image or Scion Image ROI. */
public class RoiDecoder {
private final int polygon=0, rect=1, oval=2, line=3, freeline=4, polyline=5, noRoi=6, freehand=7, traced=8, angle=9, point=10;
private byte[] data;
private String path;
private InputStream is;
private String name;
private int size;
/** Constructs an RoiDecoder using a file path. */
public RoiDecoder(String path) {
this.path = path;
}
/** Constructs an RoiDecoder using a byte array. */
public RoiDecoder(byte[] bytes, String name) {
is = new ByteArrayInputStream(bytes);
this.name = name;
this.size = bytes.length;
}
/** Returns the ROI. */
public Roi getRoi() throws IOException {
if (path!=null) {
File f = new File(path);
size = (int)f.length();
if (size>500000)
throw new IOException("This is not an ImageJ ROI");
name = f.getName();
is = new FileInputStream(path);
}
data = new byte[size];
int total = 0;
while (total<size)
total += is.read(data, total, size-total);
is.close();
if (getByte(0)!=73 || getByte(1)!=111) //"Iout"
throw new IOException("This is not an ImageJ ROI");
int type = getByte(6);
int top= getShort(8);
int left = getShort(10);
int bottom = getShort(12);
int right = getShort(14);
int width = right-left;
int height = bottom-top;
int n = getShort(16);
if (name.endsWith(".roi"))
name = name.substring(0, name.length()-4);
boolean isComposite = getInt(36)>0;
if (isComposite)
return getShapeRoi();
Roi roi = null;
switch (type) {
case rect:
roi = new Roi(left, top, width, height);
break;
case oval:
roi = new OvalRoi(left, top, width, height);
break;
case line:
int x1 = (int)getFloat(18);
int y1 = (int)getFloat(22);
int x2 = (int)getFloat(26);
int y2 = (int)getFloat(30);
roi = new Line(x1, y1, x2, y2);
//IJ.write("line roi: "+x1+" "+y1+" "+x2+" "+y2);
break;
case polygon: case freehand: case traced: case polyline: case freeline: case angle: case point:
//IJ.write("type: "+type);
//IJ.write("n: "+n);
//IJ.write("rect: "+left+","+top+" "+width+" "+height);
if (n==0) break;
int[] x = new int[n];
int[] y = new int[n];
int base1 = 64;
int base2 = base1+2*n;
int xtmp, ytmp;
for (int i=0; i<n; i++) {
xtmp = getShort(base1+i*2);
if (xtmp<0) xtmp = 0;
ytmp = getShort(base2+i*2);
if (ytmp<0) ytmp = 0;
x[i] = left+xtmp;
y[i] = top+ytmp;
//IJ.write(i+" "+getShort(base1+i*2)+" "+getShort(base2+i*2));
}
if (type==point) {
roi = new PointRoi(x, y, n);
break;
}
int roiType;
if (type==polygon)
roiType = Roi.POLYGON;
else if (type==freehand)
roiType = Roi.FREEROI;
else if (type==traced)
roiType = Roi.TRACED_ROI;
else if (type==polyline)
roiType = Roi.POLYLINE;
else if (type==freeline)
roiType = Roi.FREELINE;
else if (type==angle)
roiType = Roi.ANGLE;
else
roiType = Roi.FREEROI;
roi = new PolygonRoi(x, y, n, roiType);
break;
default:
throw new IOException("Unrecognized ROI type: "+type);
}
roi.setName(name);
return roi;
}
public Roi getShapeRoi() throws IOException {
int type = getByte(6);
if (type!=rect)
throw new IllegalArgumentException("Invalid composite ROI type");
int top= getShort(8);
int left = getShort(10);
int bottom = getShort(12);
int right = getShort(14);
int width = right-left;
int height = bottom-top;
int n = getInt(36);
ShapeRoi roi = null;
float[] shapeArray = new float[n];
int base = 64;
for(int i=0; i<n; i++) {
shapeArray[i] = getFloat(base);
base += 4;
}
roi = new ShapeRoi(shapeArray);
roi.setName(name);
return roi;
}
int getByte(int base) {
return data[base]&255;
}
int getShort(int base) {
int b0 = data[base]&255;
int b1 = data[base+1]&255;
int n = (short)((b0<<8) + b1);
if (n<-5000)
n = (b0<<8) + b1; // assume n>32767 and unsigned
return n;
}
int getInt(int base) {
int b0 = data[base]&255;
int b1 = data[base+1]&255;
int b2 = data[base+2]&255;
int b3 = data[base+3]&255;
return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
}
float getFloat(int base) {
return Float.intBitsToFloat(getInt(base));
}
}
|
RoiDecoder |
|