Java : 如何进行图像处理(平移、缩放、翻转和旋转)?
Java : How to do image manipulation (pan, zoom, flip and rotate)?
出于个人兴趣,我正在制作一个图像查看器应用程序。我正在使用 JPanel
来显示 bufferedImage
。
Objective - 我想操纵图像并为用户提供缩放、平移、翻转或旋转图像的选项。
我现在可以缩放、平移和旋转。但问题是它与您在 Microsoft Edge.
中打开 .pdf 文件时看到的不一样
我添加了以下代码:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ZoomAndPan1 extends JPanel {
BufferedImage img;
private boolean init = true;
private int zoomLevel = 0;
private int minZoomLevel = -20;
private int maxZoomLevel = 10;
private double zoomMultiplicationFactor = 1.2;
private Point dragStartScreen;
private Point dragEndScreen;
private AffineTransform coordTransform = new AffineTransform();
public ZoomAndPan1() throws IOException {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
dragStartScreen = e.getPoint();
dragEndScreen = null;
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
pan(e);
}
});
this.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
zoom(e);
}
}
});
img = ImageIO.read(new File("file.path"));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int x = (int) (this.size().getWidth() - (img.getWidth() * .2)) / 2;
int y = (int) (this.size().getHeight() - (img.getHeight() * .2)) / 2;
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.scale(.2, .2);
if (init) {
g2.setTransform(at);
init = false;
coordTransform = g2.getTransform();
} else {
g2.setTransform(coordTransform);
}
g2.drawImage(img, 0, 0, this);
g2.dispose();
}
private void pan(MouseEvent e) {
try {
dragEndScreen = e.getPoint();
Point2D.Float dragStart = transformPoint(dragStartScreen);
Point2D.Float dragEnd = transformPoint(dragEndScreen);
double dx = dragEnd.getX() - dragStart.getX();
double dy = dragEnd.getY() - dragStart.getY();
coordTransform.translate(dx, dy);
dragStartScreen = dragEndScreen;
dragEndScreen = null;
repaint();
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
private void zoom(MouseWheelEvent e) {
try {
int wheelRotation = e.getWheelRotation();
Point p = e.getPoint();
if (wheelRotation > 0) {
if (zoomLevel < maxZoomLevel) {
zoomLevel++;
Point2D p1 = transformPoint(p);
coordTransform.scale(1 / zoomMultiplicationFactor, 1 / zoomMultiplicationFactor);
Point2D p2 = transformPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
repaint();
}
} else {
if (zoomLevel > minZoomLevel) {
zoomLevel--;
Point2D p1 = transformPoint(p);
coordTransform.scale(zoomMultiplicationFactor, zoomMultiplicationFactor);
Point2D p2 = transformPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
repaint();
}
}
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
private Point2D.Float transformPoint(Point p1) throws NoninvertibleTransformException {
AffineTransform inverse = coordTransform.createInverse();
Point2D.Float p2 = new Point2D.Float();
inverse.transform(p1, p2);
return p2;
}
public Dimension getPreferredSize() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return new Dimension(screenSize.width, screenSize.height);
}
public static void main(String[] args) {
try {
JFrame frame = new JFrame("Zoom and Pan ");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new ZoomAndPan1(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(ZoomAndPan1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
这段代码可以做以下事情:
按 CTRL + 鼠标滚动缩放 in/out
鼠标拖动时平移图像。
限制:
Return 缩小时居中。
平移不受 Jpanel
或 viewport
边界的限制。
我想实现这个:
不幸的是,代码是这样的:
如何解决这个问题?
提前谢谢你..
这是一个演示我建议的简单程序,即将大图像设置为 JLabel
的图标,JLabel
是 JScrollPane
的可滚动客户端。请注意,我将 JScrollPane
的首选大小设置为 800 x 600 像素,因为默认行为是使 JScrollPane
与其可滚动客户端的大小相同。图像尺寸为 2312 x 1536 像素,这意味着它比我的电脑屏幕大。因此,如果我不设置首选大小,当您 运行 程序时 JFrame
会溢出屏幕。您没有看到所有 JFrame
。这是故意的,这样您就可以看到图像是如何滚动的。图片的 URL 是 https://unsplash.com/photos/l68Z6eF2peA. And here is the code, which is a MCVE
顺便说一句,我下载了图像并将其保存在我命名为 worldmap.jpg
的文件中
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class ScrolImg implements Runnable {
private JFrame frame;
/* Start 'Runnable' interface methods. */
public void run() {
showGui();
}
/* End 'Runnable' interface methods. */
private JScrollPane createMainPanel() {
Icon ico = new ImageIcon("worldmap.jpg");
JLabel label = new JLabel(ico);
JScrollPane scrollPane = new JScrollPane(label);
scrollPane.setPreferredSize(new Dimension(800, 600));
return scrollPane;
}
private void showGui() {
frame = new JFrame("ScrolImg");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
ScrolImg instance = new ScrolImg();
EventQueue.invokeLater(instance);
}
}
希望这段代码能帮助您完成项目。
终于可以控制pan功能了..
我用这个侦听器替换了我的平移功能。它应用与将图像放入标签中相同的概念。而且我负担不起使用标签,因为我会在图像本身上写字,所以这就是我所做的。
//map - represents the container or component the image was drawn.
//then I added a ScrollPane on map..
map.setAutoscrolls(true);
add(new JScrollPane(map));
MouseAdapter ma = new MouseAdapter() {
private Point origin;
@Override
public void mousePressed(MouseEvent e) {
origin = new Point(e.getPoint());
System.out.println("click");
}
@Override
public void mouseDragged(MouseEvent e) {
if (origin != null) {
JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, map);
if (viewPort != null) {
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = viewPort.getViewRect();
view.x += deltaX;
view.y += deltaY;
map.scrollRectToVisible(view);
}
}
}
};
出于个人兴趣,我正在制作一个图像查看器应用程序。我正在使用 JPanel
来显示 bufferedImage
。
Objective - 我想操纵图像并为用户提供缩放、平移、翻转或旋转图像的选项。
我现在可以缩放、平移和旋转。但问题是它与您在 Microsoft Edge.
中打开 .pdf 文件时看到的不一样我添加了以下代码:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ZoomAndPan1 extends JPanel {
BufferedImage img;
private boolean init = true;
private int zoomLevel = 0;
private int minZoomLevel = -20;
private int maxZoomLevel = 10;
private double zoomMultiplicationFactor = 1.2;
private Point dragStartScreen;
private Point dragEndScreen;
private AffineTransform coordTransform = new AffineTransform();
public ZoomAndPan1() throws IOException {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
dragStartScreen = e.getPoint();
dragEndScreen = null;
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
pan(e);
}
});
this.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
zoom(e);
}
}
});
img = ImageIO.read(new File("file.path"));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int x = (int) (this.size().getWidth() - (img.getWidth() * .2)) / 2;
int y = (int) (this.size().getHeight() - (img.getHeight() * .2)) / 2;
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.scale(.2, .2);
if (init) {
g2.setTransform(at);
init = false;
coordTransform = g2.getTransform();
} else {
g2.setTransform(coordTransform);
}
g2.drawImage(img, 0, 0, this);
g2.dispose();
}
private void pan(MouseEvent e) {
try {
dragEndScreen = e.getPoint();
Point2D.Float dragStart = transformPoint(dragStartScreen);
Point2D.Float dragEnd = transformPoint(dragEndScreen);
double dx = dragEnd.getX() - dragStart.getX();
double dy = dragEnd.getY() - dragStart.getY();
coordTransform.translate(dx, dy);
dragStartScreen = dragEndScreen;
dragEndScreen = null;
repaint();
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
private void zoom(MouseWheelEvent e) {
try {
int wheelRotation = e.getWheelRotation();
Point p = e.getPoint();
if (wheelRotation > 0) {
if (zoomLevel < maxZoomLevel) {
zoomLevel++;
Point2D p1 = transformPoint(p);
coordTransform.scale(1 / zoomMultiplicationFactor, 1 / zoomMultiplicationFactor);
Point2D p2 = transformPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
repaint();
}
} else {
if (zoomLevel > minZoomLevel) {
zoomLevel--;
Point2D p1 = transformPoint(p);
coordTransform.scale(zoomMultiplicationFactor, zoomMultiplicationFactor);
Point2D p2 = transformPoint(p);
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
repaint();
}
}
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
}
}
private Point2D.Float transformPoint(Point p1) throws NoninvertibleTransformException {
AffineTransform inverse = coordTransform.createInverse();
Point2D.Float p2 = new Point2D.Float();
inverse.transform(p1, p2);
return p2;
}
public Dimension getPreferredSize() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return new Dimension(screenSize.width, screenSize.height);
}
public static void main(String[] args) {
try {
JFrame frame = new JFrame("Zoom and Pan ");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new ZoomAndPan1(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(ZoomAndPan1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
这段代码可以做以下事情:
按 CTRL + 鼠标滚动缩放 in/out
鼠标拖动时平移图像。
限制:
Return 缩小时居中。
平移不受
Jpanel
或viewport
边界的限制。
我想实现这个:
不幸的是,代码是这样的:
如何解决这个问题?
提前谢谢你..
这是一个演示我建议的简单程序,即将大图像设置为 JLabel
的图标,JLabel
是 JScrollPane
的可滚动客户端。请注意,我将 JScrollPane
的首选大小设置为 800 x 600 像素,因为默认行为是使 JScrollPane
与其可滚动客户端的大小相同。图像尺寸为 2312 x 1536 像素,这意味着它比我的电脑屏幕大。因此,如果我不设置首选大小,当您 运行 程序时 JFrame
会溢出屏幕。您没有看到所有 JFrame
。这是故意的,这样您就可以看到图像是如何滚动的。图片的 URL 是 https://unsplash.com/photos/l68Z6eF2peA. And here is the code, which is a MCVE
顺便说一句,我下载了图像并将其保存在我命名为 worldmap.jpg
的文件中import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class ScrolImg implements Runnable {
private JFrame frame;
/* Start 'Runnable' interface methods. */
public void run() {
showGui();
}
/* End 'Runnable' interface methods. */
private JScrollPane createMainPanel() {
Icon ico = new ImageIcon("worldmap.jpg");
JLabel label = new JLabel(ico);
JScrollPane scrollPane = new JScrollPane(label);
scrollPane.setPreferredSize(new Dimension(800, 600));
return scrollPane;
}
private void showGui() {
frame = new JFrame("ScrolImg");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
ScrolImg instance = new ScrolImg();
EventQueue.invokeLater(instance);
}
}
希望这段代码能帮助您完成项目。
终于可以控制pan功能了..
我用这个侦听器替换了我的平移功能。它应用与将图像放入标签中相同的概念。而且我负担不起使用标签,因为我会在图像本身上写字,所以这就是我所做的。
//map - represents the container or component the image was drawn.
//then I added a ScrollPane on map..
map.setAutoscrolls(true);
add(new JScrollPane(map));
MouseAdapter ma = new MouseAdapter() {
private Point origin;
@Override
public void mousePressed(MouseEvent e) {
origin = new Point(e.getPoint());
System.out.println("click");
}
@Override
public void mouseDragged(MouseEvent e) {
if (origin != null) {
JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, map);
if (viewPort != null) {
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = viewPort.getViewRect();
view.x += deltaX;
view.y += deltaY;
map.scrollRectToVisible(view);
}
}
}
};