Selection rectangle "roi" working.
This commit is contained in:
parent
c1498adc1f
commit
bcc46597c9
1 changed files with 234 additions and 219 deletions
|
|
@ -19,11 +19,11 @@ import javax.swing.border.*;
|
|||
*/
|
||||
public class Editor
|
||||
extends JComponent
|
||||
implements MouseListener, MouseMotionListener
|
||||
{
|
||||
// Given from input image
|
||||
BufferedImage img;
|
||||
double imgScale; // coordinates per bitmap pixel
|
||||
Rectangle imgRec;
|
||||
|
||||
// What we choose
|
||||
double rotation; // radians
|
||||
|
|
@ -32,30 +32,29 @@ public class Editor
|
|||
int side;
|
||||
|
||||
// other
|
||||
// AffineTransform t;
|
||||
CropFrame mask;
|
||||
AffineTransform screenToCoord;
|
||||
AffineTransform coordToScreen;
|
||||
boolean dirty = true;
|
||||
// CropFrame mask;
|
||||
|
||||
public Editor(BufferedImage img) {
|
||||
this.img = img;
|
||||
int w = img.getWidth();
|
||||
int h = img.getHeight();
|
||||
imgScale = 1d / Math.sqrt(w * w + h * h);
|
||||
imgRec = new Rectangle(0, 0, w, h);
|
||||
|
||||
resize(imgScale * 680);
|
||||
roi = new Rect();
|
||||
roi.top = 0.5f;
|
||||
roi.bottom = -0.5f;
|
||||
roi.left = -0.5f;
|
||||
roi.right = 0.5f;
|
||||
|
||||
rescale(imgScale * 680);
|
||||
/*
|
||||
Dimension size = new Dimension(680, 680);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
|
||||
roi = new Rect();
|
||||
roi.top = 0.5;
|
||||
roi.bottom = -0.5;
|
||||
roi.left = -0.5;
|
||||
roi.right = 0.5;
|
||||
|
||||
|
||||
rotation = 0.0;
|
||||
|
||||
Rectangle initialMask = new Rectangle(100, 100, 200, 200);
|
||||
|
|
@ -67,18 +66,21 @@ public class Editor
|
|||
add(mask);
|
||||
|
||||
SelectionEditor ml = new SelectionEditor();
|
||||
addMouseListener(ml);
|
||||
addMouseMotionListener(ml);
|
||||
*/
|
||||
addMouseListener(this);
|
||||
addMouseMotionListener(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void resize(double newScale) {
|
||||
void rescale(double newScale) {
|
||||
|
||||
scale = newScale;
|
||||
side = (int)Math.round(scale / imgScale);
|
||||
Dimension size = new Dimension(side, side);
|
||||
dirty = true;
|
||||
roi.cache = null;
|
||||
System.out.println("Side: " + side);
|
||||
setSize(size);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
|
|
@ -91,67 +93,53 @@ public class Editor
|
|||
protected void paintComponent(Graphics g1) {
|
||||
super.paintComponent(g1);
|
||||
|
||||
if (dirty) {
|
||||
System.out.println("Recalculating");
|
||||
AffineTransform screenToCoord = new AffineTransform();
|
||||
screenToCoord.translate(side/2d, side/2d);
|
||||
screenToCoord.scale(side, -side);
|
||||
|
||||
AffineTransform coordToScreen = new AffineTransform();
|
||||
coordToScreen.scale(1d/side, -1d/side);
|
||||
coordToScreen.translate(-side/2d, -side/2d);
|
||||
|
||||
this.screenToCoord = coordToScreen;
|
||||
this.coordToScreen = screenToCoord;
|
||||
|
||||
|
||||
dirty = false;
|
||||
} else {
|
||||
// System.out.println("using cached transform");
|
||||
}
|
||||
|
||||
Graphics2D g = (Graphics2D)g1;
|
||||
AffineTransform orig = g.getTransform();
|
||||
|
||||
AffineTransform screenToCoord = new AffineTransform();
|
||||
screenToCoord.translate(side/2d, side/2d);
|
||||
screenToCoord.scale(side, side);
|
||||
|
||||
g.transform(screenToCoord);
|
||||
g.transform(this.coordToScreen);
|
||||
|
||||
AffineTransform imageToCoord = new AffineTransform();
|
||||
imageToCoord.rotate(rotation * Math.PI / 180d);
|
||||
imageToCoord.scale(imgScale * scale, imgScale * scale);
|
||||
imageToCoord.scale(imgScale, -imgScale);
|
||||
imageToCoord.translate(-img.getWidth()/2d, -img.getHeight()/2d);
|
||||
|
||||
g.drawImage(img, imageToCoord, this);
|
||||
|
||||
// Crosshair
|
||||
/*
|
||||
g.setStroke(new BasicStroke(0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f, new float[] { 0.005f, 0.005f }, 0));
|
||||
g.draw(new Line2D.Double(-0.5, 0, 0.5, 0));
|
||||
g.draw(new Line2D.Double(0, -0.5, 0, 0.5));
|
||||
|
||||
*/
|
||||
g.setTransform(orig);
|
||||
|
||||
g.setXORMode(Color.white); //Color of line varies
|
||||
g.setStroke(new BasicStroke(0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f, new float[] { 5f, 5f }, 0));
|
||||
g.draw(new Rectangle2D.Double(100, 100, 200, 200));
|
||||
|
||||
|
||||
g.draw(roi.getScreenRectangle());
|
||||
// roi.cache = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private class SelectionEditor extends MouseInputAdapter {
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
mask.setLocation(x, y);
|
||||
mask.setSize(1, 1);
|
||||
mask.repaint();
|
||||
}
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
mask.updateFrame(e.getX(), e.getY());
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
mask.updateFrame(e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
JComponent createControlPanel() {
|
||||
|
|
@ -203,7 +191,7 @@ public class Editor
|
|||
int value = zoomSlider.getValue();
|
||||
if (value != previousValue) {
|
||||
previousValue = value;
|
||||
resize(value * 0.01);
|
||||
rescale(value * 0.01);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -228,201 +216,174 @@ public class Editor
|
|||
reader.setInput(iis, true);
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
// param.setSourceSubsampling(8, 8, 0, 0);
|
||||
BufferedImage raw = reader.read(0, param);
|
||||
final BufferedImage raw = reader.read(0, param);
|
||||
|
||||
Editor x = new Editor(raw);
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
Editor x = new Editor(raw);
|
||||
|
||||
JFrame frame = new JFrame("Editor");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
JFrame frame = new JFrame("Editor");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
Container c = frame.getContentPane();
|
||||
c.setLayout(new BorderLayout());
|
||||
c.add(x.createControlPanel(), BorderLayout.EAST);
|
||||
c.add(new JScrollPane(x), BorderLayout.CENTER);
|
||||
Container c = frame.getContentPane();
|
||||
c.setLayout(new BorderLayout());
|
||||
c.add(x.createControlPanel(), BorderLayout.EAST);
|
||||
c.add(new JScrollPane(x), BorderLayout.CENTER);
|
||||
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
final int resizeBand = 3;
|
||||
boolean isDragging = false;
|
||||
Stroke stroke = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f, new float[] { 5f, 5f }, 0);
|
||||
|
||||
static class CropFrame extends JComponent implements MouseListener, MouseMotionListener {
|
||||
|
||||
/**
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int resizeBand = 6;
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
Stroke stroke = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f, new float[] { 5f, 5f }, 0);
|
||||
|
||||
public CropFrame()
|
||||
{
|
||||
setOpaque(false);
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int r = findRegion(e.getX(), e.getY());
|
||||
if (r < 8) {
|
||||
edge = r;
|
||||
isDragging = true;
|
||||
} else {
|
||||
isDragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 1------(5)-------2
|
||||
// | |
|
||||
// | |
|
||||
// (8) (6)
|
||||
// | |
|
||||
// | |
|
||||
// 4------(7)-------3
|
||||
//
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g); //paints the background and image
|
||||
|
||||
// Draw a rectangle on top of the image.
|
||||
// g.setColor(Color.WHITE);
|
||||
g.setXORMode(Color.white); //Color of line varies
|
||||
((Graphics2D)g).setStroke(stroke);
|
||||
//depending on image colors
|
||||
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if (isDragging) {
|
||||
updateFrame(e.getPoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
if (isDragging) {
|
||||
updateFrame(e.getPoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean is(int who, int alt0, int alt1, int alt2) {
|
||||
return who == alt0 || who == alt1 || who == alt2;
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
int[] oppositeX = new int[] { NE, N, NW, W, SW, S, SE, E };
|
||||
int[] oppositeY = new int[] { SW, S, SE, E, NE, N, NW, W };
|
||||
Cursor[] cursors = new Cursor[] {
|
||||
Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
|
||||
};
|
||||
String[] edgeName = new String[] { "NW", "N", "NE", "E", "SE", "S", "SW", "W" };
|
||||
static final int NW = 0;
|
||||
static final int N = 1;
|
||||
static final int NE = 2;
|
||||
static final int E = 3;
|
||||
static final int SE = 4;
|
||||
static final int S = 5;
|
||||
static final int SW = 6;
|
||||
static final int W = 7;
|
||||
int edge = SE;
|
||||
Rectangle frame = new Rectangle();
|
||||
|
||||
void updateFrame(Point p) {
|
||||
frame = roi.getScreenRectangle();
|
||||
if (is(edge, NW, W, SW)) {
|
||||
frame.width += frame.x - p.x;
|
||||
frame.x = p.x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
if (is(edge, NE, E, SE)) {
|
||||
frame.width = p.x - frame.x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
int r = findRegion(e.getX(), e.getY());
|
||||
if (r < 8) {
|
||||
edge = r;
|
||||
}
|
||||
if (is(edge, NW, N, NE)) {
|
||||
frame.height += frame.y - p.y;
|
||||
frame.y = p.y;
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
updateFrame(e.getX() + getX(), e.getY() + getY());
|
||||
if (is(edge, SW, S, SE)) {
|
||||
frame.height = p.y - frame.y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
updateFrame(e.getX() + getX(), e.getY() + getY());
|
||||
if (frame.width < 0) {
|
||||
frame.x += frame.width;
|
||||
frame.width = -frame.width;
|
||||
edge = oppositeX[edge];
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean is(int who, int alt0, int alt1, int alt2) {
|
||||
return who == alt0 || who == alt1 || who == alt2;
|
||||
}
|
||||
int[] oppositeX = new int[] { NE, N, NW, W, SW, S, SE, E };
|
||||
int[] oppositeY = new int[] { SW, S, SE, E, NE, N, NW, W };
|
||||
Cursor[] cursors = new Cursor[] {
|
||||
Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR),
|
||||
Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
|
||||
};
|
||||
String[] edgeName = new String[] { "NW", "N", "NE", "E", "SE", "S", "SW", "W" };
|
||||
static final int NW = 0;
|
||||
static final int N = 1;
|
||||
static final int NE = 2;
|
||||
static final int E = 3;
|
||||
static final int SE = 4;
|
||||
static final int S = 5;
|
||||
static final int SW = 6;
|
||||
static final int W = 7;
|
||||
int edge = SE;
|
||||
Rectangle frame = new Rectangle();
|
||||
|
||||
void updateFrame(int x, int y) {
|
||||
getBounds(frame);
|
||||
if (is(edge, NW, W, SW)) {
|
||||
frame.width += frame.x - x;
|
||||
frame.x = x;
|
||||
}
|
||||
if (is(edge, NE, E, SE)) {
|
||||
frame.width = x - frame.x;
|
||||
}
|
||||
if (is(edge, NW, N, NE)) {
|
||||
frame.height += frame.y - y;
|
||||
frame.y = y;
|
||||
}
|
||||
if (is(edge, SW, S, SE)) {
|
||||
frame.height = y - frame.y;
|
||||
}
|
||||
if (frame.width < 0) {
|
||||
frame.x += frame.width;
|
||||
frame.width = -frame.width;
|
||||
edge = oppositeX[edge];
|
||||
}
|
||||
if (frame.height < 0) {
|
||||
frame.y += frame.height;
|
||||
frame.height = -frame.height;
|
||||
edge = oppositeY[edge];
|
||||
}
|
||||
setBounds(frame);
|
||||
repaint();
|
||||
if (frame.height < 0) {
|
||||
frame.y += frame.height;
|
||||
frame.height = -frame.height;
|
||||
edge = oppositeY[edge];
|
||||
}
|
||||
roi.setScreenRectangle(frame);
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
boolean within(int x, int target) {
|
||||
return x >= target - resizeBand && x <= target + resizeBand;
|
||||
}
|
||||
|
||||
int findRegion(int ex, int ey) {
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
int c = 8;
|
||||
int findRegion(int ex, int ey) {
|
||||
Rectangle r = roi.getScreenRectangle();
|
||||
int c = 8;
|
||||
|
||||
if (ex > (w - resizeBand)) {
|
||||
if (ey > (h - resizeBand)) {
|
||||
c = SE;
|
||||
} else if (ey < resizeBand) {
|
||||
c = NE;
|
||||
} else {
|
||||
c = E;
|
||||
}
|
||||
} else if (ex < resizeBand) {
|
||||
if (ey > (h - resizeBand)) {
|
||||
c = SW;
|
||||
} else if (ey < resizeBand) {
|
||||
c = NW;
|
||||
} else {
|
||||
c = W;
|
||||
}
|
||||
if (within(ex, r.x + r.width)) {
|
||||
if (within(ey, r.y + r.height)) {
|
||||
c = SE;
|
||||
} else if (within(ey, r.y)) {
|
||||
c = NE;
|
||||
} else {
|
||||
if (ey > (h - resizeBand)) {
|
||||
c = S;
|
||||
} else if (ey < resizeBand) {
|
||||
c = N;
|
||||
} else {
|
||||
c = 8;
|
||||
}
|
||||
c = E;
|
||||
}
|
||||
} else if (within(ex, r.x)) {
|
||||
if (within(ey, r.y + r.height)) {
|
||||
c = SW;
|
||||
} else if (within(ey, r.y)) {
|
||||
c = NW;
|
||||
} else {
|
||||
c = W;
|
||||
}
|
||||
} else {
|
||||
if (within(ey, r.y + r.height)) {
|
||||
c = S;
|
||||
} else if (within(ey, r.y)) {
|
||||
c = N;
|
||||
} else {
|
||||
c = 8;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
setCursor(cursors[findRegion(e.getX(), e.getY())]);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
setCursor(cursors[findRegion(e.getX(), e.getY())]);
|
||||
}
|
||||
|
||||
static void log(String x) {
|
||||
|
|
@ -430,11 +391,65 @@ public class Editor
|
|||
}
|
||||
|
||||
|
||||
static class Rect {
|
||||
double top;
|
||||
double left;
|
||||
double bottom;
|
||||
double right;
|
||||
class Rect {
|
||||
float top;
|
||||
float left;
|
||||
float bottom;
|
||||
float right;
|
||||
Rectangle cache = null;
|
||||
|
||||
public void setScreenRectangle(Rectangle frame) {
|
||||
Point2D.Float screenTopLeft = new Point2D.Float(frame.x, frame.y);
|
||||
Point2D.Float coordTopLeft = new Point2D.Float();
|
||||
Point2D.Float screenBottomRight = new Point2D.Float(frame.x + frame.width, frame.y + frame.height);
|
||||
Point2D.Float coordBottomRight = new Point2D.Float();
|
||||
|
||||
if (dirty) {
|
||||
new Exception().printStackTrace(System.out);
|
||||
}
|
||||
screenToCoord.transform(screenTopLeft, coordTopLeft);
|
||||
screenToCoord.transform(screenBottomRight, coordBottomRight);
|
||||
|
||||
top = coordTopLeft.y;
|
||||
left = coordTopLeft.x;
|
||||
bottom = coordBottomRight.y;
|
||||
right = coordBottomRight.x;
|
||||
// System.out.println("rect: " + left + ", " + top + ", " + right + ", " + bottom);
|
||||
Rectangle stored = calculateScreenRectangle();
|
||||
Rectangle delta = new Rectangle();
|
||||
delta.x = frame.x - stored.x;
|
||||
delta.y = frame.y - stored.y;
|
||||
delta.width = frame.width - stored.width;
|
||||
delta.height = frame.height - stored.height;
|
||||
System.out.println("delta: " + delta);
|
||||
cache = frame;
|
||||
}
|
||||
|
||||
Rectangle calculateScreenRectangle() {
|
||||
Point2D.Float coordTopLeft = new Point2D.Float(left, top);
|
||||
Point2D.Float screenTopLeft = new Point2D.Float();
|
||||
Point2D.Float coordBottomRight = new Point2D.Float(right, bottom);
|
||||
Point2D.Float screenBottomRight = new Point2D.Float();
|
||||
|
||||
coordToScreen.transform(coordTopLeft, screenTopLeft);
|
||||
if (dirty) {
|
||||
new Exception().printStackTrace(System.out);
|
||||
}
|
||||
coordToScreen.transform(coordBottomRight, screenBottomRight);
|
||||
|
||||
int x = Math.round(screenTopLeft.x);
|
||||
int y = Math.round(screenTopLeft.y);
|
||||
int w = Math.round(screenBottomRight.x - screenTopLeft.x);
|
||||
int h = Math.round(screenBottomRight.y - screenTopLeft.y);
|
||||
return new Rectangle(x, y, w, h);
|
||||
}
|
||||
|
||||
public Rectangle getScreenRectangle() {
|
||||
if (cache == null) {
|
||||
cache = calculateScreenRectangle();
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue