【发布时间】:2018-10-18 05:59:00
【问题描述】:
我有一个 Java 应用程序,用户可以在其中裁剪原始自身的子图像。通过在原始图像上绘制一个矩形来选择裁剪区域。然后可以对角调整矩形的大小。到目前为止,一切正常!
用户还可以选择将矩形的纵横比锁定为 4:3。我可以通过将宽度设置为 w = h / 4 * 3;
但是,当涉及到以锁定比例调整大小时,矩形的行为很奇怪,并且在从 西北角 拖动时不再静止(参见下面的 gif)。西南角也有同样的问题,但这可以通过将高度设置为 h = w / 3 * 4; 来解决,但我不知道如何在数学上为 西北角。我为实验提供了一个可复制粘贴的演示:
public class CropDemo {
public static void main(String[] args) {
CropPanel cropPanel = new CropPanel();
cropPanel.setPreferredSize(new Dimension(640, 480));
JFrame jFrame = new JFrame("Crop Panel");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.getContentPane().add(cropPanel);
jFrame.setResizable(false);
jFrame.pack();
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
}
class CropPanel extends JPanel {
private static final long serialVersionUID = 1L;
private boolean fixedRatio = true;
private Rectangle rectangle;
private Point clickPoint;
private static final int HOVERING = 0;
private static final int MOVING = 1;
private static final int RESIZING = 2;
public CropPanel() {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
MouseAdapter mouseHandler = new MouseAdapter() {
private Point startPoint = null;
@Override
public void mouseClicked(MouseEvent e) {
if (rectangle != null && getCursorState() == HOVERING) {
rectangle = null;
repaint();
}
}
@Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
startPoint = e.getPoint();
}
@Override
public void mouseMoved(MouseEvent e) {
if (rectangle != null) {
Point mouse = e.getPoint();
int width = rectangle.x + rectangle.width;
int height = rectangle.y + rectangle.height;
final int off = 5;
if (mouse.x > rectangle.x - off && mouse.x < width + off && mouse.y > rectangle.y - off
&& mouse.y < height + off) {
if (mouse.x <= rectangle.x + off && mouse.y >= height - off) {
setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
} else if (mouse.x >= width - off && mouse.y >= height - off) {
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
} else if (mouse.x <= rectangle.x + off && mouse.y <= rectangle.y + off) {
setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
} else if (mouse.x >= width - off && mouse.y <= rectangle.y + off) {
setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (clickPoint != null) {
Point mouse = e.getPoint();
if (getCursorState() == MOVING) {
int dx = rectangle.x + mouse.x - clickPoint.x;
int dy = rectangle.y + mouse.y - clickPoint.y;
rectangle.setLocation(dx, dy);
clickPoint = e.getPoint();
} else if (getCursorState() == RESIZING) {
int dx = mouse.x - startPoint.x;
int dy = mouse.y - startPoint.y;
int height = rectangle.height;
int width = rectangle.width;
int x = 0;
int y = 0;
int w = 0;
int h = 0;
switch (getCursor().getType()) {
case Cursor.SW_RESIZE_CURSOR:
x = mouse.x + dx;
y = rectangle.y;
w = width - dx;
h = height + dy;
if (fixedRatio) {
h = w / 3 * 4;
}
break;
case Cursor.SE_RESIZE_CURSOR:
x = rectangle.x;
y = rectangle.y;
w = width + dx;
h = height + dy;
if (fixedRatio) {
w = h / 4 * 3;
}
break;
case Cursor.NW_RESIZE_CURSOR:
x = mouse.x + dx;
y = mouse.y + dy;
w = width - dx;
h = height - dy;
// This is where I'm lost
// something else needs to be done
if (fixedRatio) {
w = h / 4 * 3;
}
break;
case Cursor.NE_RESIZE_CURSOR:
x = rectangle.x;
y = mouse.y + dy;
w = width + dx;
h = height - dy;
if (fixedRatio) {
w = h / 4 * 3;
}
break;
}
rectangle.setBounds(x, y, w, h);
startPoint = mouse;
} else {
int x = Math.min(clickPoint.x, mouse.x);
int y = Math.min(clickPoint.y, mouse.y);
int w = Math.max(clickPoint.x - mouse.x, mouse.x - clickPoint.x);
int h = Math.max(clickPoint.y - mouse.y, mouse.y - clickPoint.y);
if (rectangle == null) {
rectangle = new Rectangle(x, y, w, h);
} else {
rectangle.setBounds(x, y, w, h);
}
}
repaint();
}
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
Graphics2D graphics2D = (Graphics2D) g.create();
if (rectangle != null) {
Area fill = new Area(new Rectangle(new Point(0, 0), getSize()));
fill.subtract(new Area(rectangle));
if (clickPoint != null) {
graphics2D.setColor(new Color(0, 0, 0, 0));
} else {
graphics2D.setColor(new Color(0, 0, 0, 200));
}
int x = rectangle.x;
int y = rectangle.y;
int w = rectangle.width;
int h = rectangle.height;
graphics2D.fill(fill);
graphics2D.setColor(Color.WHITE);
graphics2D.setStroke(
new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 6 }, 0));
graphics2D.drawRect(x, y, w, h);
if (w >= 30 && h >= 30) {
graphics2D.setStroke(new BasicStroke(3));
graphics2D.drawLine(x + 1, y + 1, x + 8, y + 1);
graphics2D.drawLine(x + 1, y + 1, x + 1, y + 8);
graphics2D.drawLine(x + w - 1, y + 1, x + w - 8, y + 1);
graphics2D.drawLine(x + w - 1, y + 1, x + w - 1, y + 8);
graphics2D.drawLine(x + 1, y + h - 1, x + 8, y + h - 1);
graphics2D.drawLine(x + 1, y + h - 1, x + 1, y + h - 8);
graphics2D.drawLine(x + w - 1, y + h - 1, x + w - 8, y + h - 1);
graphics2D.drawLine(x + w - 1, y + h - 1, x + w - 1, y + h - 8);
}
}
graphics2D.dispose();
g.dispose();
}
private int getCursorState() {
switch (getCursor().getType()) {
case Cursor.CROSSHAIR_CURSOR:
return HOVERING;
case Cursor.MOVE_CURSOR:
return MOVING;
case Cursor.SW_RESIZE_CURSOR:
case Cursor.SE_RESIZE_CURSOR:
case Cursor.NW_RESIZE_CURSOR:
case Cursor.NE_RESIZE_CURSOR:
case Cursor.N_RESIZE_CURSOR:
case Cursor.S_RESIZE_CURSOR:
case Cursor.W_RESIZE_CURSOR:
case Cursor.E_RESIZE_CURSOR:
return RESIZING;
default:
return -1;
}
}
}
【问题讨论】:
-
+1 表示有用的 .gif 和详细问题,但如果您能提供一个最小、完整且可验证的示例,那就太好了:stackoverflow.com/help/mcve
-
感谢您的意见。我已经编辑了我的代码以涵盖一个可运行的示例。
标签: java image resize crop aspect-ratio