import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.*;
import java.util.*;
import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;
import ij.gui.*;
/**
* Warp is a plugin filter for ImageJ that warps an image
* along a straight line selection.
* The warping code has been taken from the AlexWarp applet
* and rewritten for ImageJ by Ulf Dittmer.
* It is hereby released under the same terms as ImageJ.
*/
public class Warp_ implements PlugInFilter, MouseListener {
int mPixels[], mOldPixels[];
int mWidth, mHeight;
boolean smooth = true;
final int kHOffset = 0;
final int kVOffset = 0;
ImagePlus imp;
ImageProcessor ip;
static Vector images = new Vector();
public Warp_() { }
public int setup (String _arg, ImagePlus _imp) {
this.imp = _imp;
IJ.register(Warp_.class);
return DOES_ALL;
}
public void run (ImageProcessor _ip) {
Integer id = new Integer(imp.getID());
ImageWindow win = WindowManager.getCurrentImage().getWindow();
if (images.contains(id)) {
images.removeElement(id);
IJ.log("Warp OFF for " + win.getTitle());
} else {
win.getCanvas().addMouseListener(this);
images.addElement(id);
IJ.log("Warp ON for " + win.getTitle());
}
}
public void mousePressed (MouseEvent e) {}
public void mouseClicked (MouseEvent e) {}
public void mouseEntered (MouseEvent e) {}
public void mouseExited (MouseEvent e) {}
public void mouseReleased (MouseEvent e) {
if ((Toolbar.getToolId() != Toolbar.LINE)
|| (! images.contains(new Integer(imp.getID()))))
return;
Roi roi = imp.getRoi();
if (roi==null || roi.getType()!=Roi.LINE)
return;
this.ip = imp.getProcessor();
int x1=0, y1=0, x2=0, y2=0;
Line lineRoi = (Line) roi;
x1 = lineRoi.x1;
y1 = lineRoi.y1;
x2 = lineRoi.x2;
y2 = lineRoi.y2;
Undo.reset();
Undo.setup(Undo.FILTER, imp);
mWidth = ip.getWidth();
mHeight = ip.getHeight();
IJ.showStatus("Warping...");
mPixels = new int[mWidth * mHeight];
mOldPixels = new int[mWidth * mHeight];
for (int x=0; x= kVOffset + mHeight)
y = (kVOffset + mHeight) - 1;
} else
if (dy == 0) {
if (x < kHOffset)
x = kHOffset;
if (x >= kHOffset + mWidth)
x = (kHOffset + mWidth) - 1;
} else {
double slope = (double)dy / (double)dx;
if (x < kHOffset) {
x = kHOffset;
y = from.y + (int)(slope * (double)(x - from.x));
}
if (x >= kHOffset + mWidth) {
x = (kHOffset + mWidth) - 1;
y = from.y + (int)(slope * (double)(x - from.x));
}
if (y < kVOffset) {
y = kVOffset;
x = from.x + (int)((double)(y - from.y) / slope);
}
if (y >= kVOffset + mHeight) {
y = (kVOffset + mHeight) - 1;
x = from.x + (int)((double)(y - from.y) / slope);
}
}
return new Point(x, y);
}
class ImageWarper extends Thread {
Warp_ parent;
Point mFromPoint, mToPoint;
int mFromPixels[], mToPixels[];
int mWidth, mHeight;
MyColor col;
boolean smooth;
ImageWarper (Warp_ _parent, int fromPixels[], int toPixels[], int w, int h, Point fromPoint, Point toPoint, boolean _smooth) {
parent = _parent;
smooth = _smooth;
mFromPixels = fromPixels;
mToPixels = toPixels;
mFromPoint = fromPoint;
mToPoint = toPoint;
mWidth = w;
mHeight = h;
col = new MyColor();
}
public void run() {
WarpPixels();
parent.DoneWithWarping();
}
void WarpPixels() {
int dx = mToPoint.x - mFromPoint.x;
int dy = mToPoint.y - mFromPoint.y;
int dist = (int)Math.sqrt(dx * dx + dy * dy) * 2;
Rectangle r = new Rectangle();
Point ne = new Point(0, 0);
Point nw = new Point(0, 0);
Point se = new Point(0, 0);
Point sw = new Point(0, 0);
System.arraycopy(mFromPixels, 0, mToPixels, 0, mWidth * mHeight);
if (dist == 0) {
return;
} else {
SetRect(r, mFromPoint.x - dist, mFromPoint.y - dist, mFromPoint.x, mFromPoint.y);
ClipRect(r, mWidth, mHeight);
SetPt(ne, r.x, r.y);
SetPt(nw, r.x + r.width, r.y);
SetPt(se, r.x, r.y + r.height);
SetPt(sw, mToPoint.x, mToPoint.y);
WarpRegion(r, nw, ne, sw, se);
SetRect(r, mFromPoint.x, mFromPoint.y - dist, mFromPoint.x + dist, mFromPoint.y);
ClipRect(r, mWidth, mHeight);
SetPt(ne, r.x, r.y);
SetPt(nw, r.x + r.width, r.y);
SetPt(se, mToPoint.x, mToPoint.y);
SetPt(sw, r.x + r.width, r.y + r.height);
WarpRegion(r, nw, ne, sw, se);
SetRect(r, mFromPoint.x - dist, mFromPoint.y, mFromPoint.x, mFromPoint.y + dist);
ClipRect(r, mWidth, mHeight);
SetPt(ne, r.x, r.y);
SetPt(nw, mToPoint.x, mToPoint.y);
SetPt(se, r.x, r.y + r.height);
SetPt(sw, r.x + r.width, r.y + r.height);
WarpRegion(r, nw, ne, sw, se);
SetRect(r, mFromPoint.x, mFromPoint.y, mFromPoint.x + dist, mFromPoint.y + dist);
ClipRect(r, mWidth, mHeight);
SetPt(ne, mToPoint.x, mToPoint.y);
SetPt(nw, r.x + r.width, r.y);
SetPt(se, r.x, r.y + r.height);
SetPt(sw, r.x + r.width, r.y + r.height);
WarpRegion(r, nw, ne, sw, se);
return;
}
}
void WarpRegion (Rectangle fromRect, Point nw, Point ne, Point sw, Point se) {
int dx = fromRect.width;
int dy = fromRect.height;
double invDX = 1.0D / (double)dx;
double invDY = 1.0D / (double)dy;
boolean doInterpolate = smooth && (imp.getType() == ImagePlus.COLOR_RGB);
for (int a = 0; a < dx; a++) {
double aa = (double)a * invDX;
double x1 = (double)ne.x + (double)(nw.x - ne.x) * aa;
double y1 = (double)ne.y + (double)(nw.y - ne.y) * aa;
double x2 = (double)se.x + (double)(sw.x - se.x) * aa;
double y2 = (double)se.y + (double)(sw.y - se.y) * aa;
double xin = x1;
double yin = y1;
double dxin = (x2 - x1) * invDY;
double dyin = (y2 - y1) * invDY;
int toPixel = fromRect.x + a + fromRect.y * mWidth;
for (int b = 0; b < dy; b++) {
if (doInterpolate) {
mToPixels[toPixel] = interpolatePixel(xin, yin);
} else {
if (xin < 0.0D)
xin = 0.0D;
if (xin >= (double)mWidth)
xin = mWidth - 1;
if (yin < 0.0D)
yin = 0.0D;
if (yin >= (double)mHeight)
yin = mHeight - 1;
mToPixels[toPixel] = mFromPixels[(int)xin + (int)yin * mWidth];
}
xin += dxin;
yin += dyin;
toPixel += mWidth;
}
}
}
private final int interpolatePixel (double d, double d1) {
int i = (int)d;
int j = (int)d1;
double d2 = d - (double)i - 0.5D;
double d3 = d1 - (double)j - 0.5D;
double d4 = d2 <= 0.0D ? d2 + 1.0D : 1.0D - d2;
double d5 = d3 <= 0.0D ? d3 + 1.0D : 1.0D - d3;
int k = d2 <= 0.0D ? i - 1 : i + 1;
int l = d3 <= 0.0D ? j - 1 : j + 1;
double d6 = 1.0D - d4;
double d7 = 1.0D - d5;
col.reset();
col.add(getPixel(i, j), d4 * d5);
col.add(getPixel(k, j), d6 * d5);
col.add(getPixel(i, l), d4 * d7);
col.add(getPixel(k, l), d6 * d7);
col.add(getPixel(i, j));
col.times(0.5D);
return col.toInt();
}
private final int getPixel (int i, int j) {
if (i < 0)
i = 0;
if (i >= mWidth)
i = mWidth - 1;
if (j < 0)
j = 0;
if (j >= mHeight)
j = mHeight - 1;
return mFromPixels[i + j * mWidth];
}
void ClipRect (Rectangle r, int w, int h) {
if (r.x < 0) {
r.width += r.x;
r.x = 0;
}
if (r.y < 0) {
r.height += r.y;
r.y = 0;
}
if (r.x + r.width >= w)
r.width = w - r.x - 1;
if (r.y + r.height >= h)
r.height = h - r.y - 1;
}
void SetRect (Rectangle r, int left, int top, int right, int bottom) {
r.x = left;
r.y = top;
r.width = right - left;
r.height = bottom - top;
}
void SetPt (Point pt, int x, int y) {
pt.x = x;
pt.y = y;
}
}
class MyColor {
double red, green, blue;
MyColor() { }
void add (int i) {
red += (i & 0xff0000) >> 16;
green += (i & 0xff00) >> 8;
blue += i & 0xff;
}
void add (int i, double d) {
red += (double)((i & 0xff0000) >> 16) * d;
green += (double)((i & 0xff00) >> 8) * d;
blue += (double)(i & 0xff) * d;
}
void times (double d) {
red *= d;
green *= d;
blue *= d;
}
int toInt() {
return 0xff000000 | (int)red << 16 | (int)green << 8 | (int)blue;
}
void reset() {
red = green = blue = 0.0D;
}
}
}