在 Java 中绘制的图像的备份
Backup for image that is drawn on in Java
在我的应用程序中,通过单击图像在图像上标记了一些东西。
这是通过将图像设置为 JLabel 的图标并添加 MousePressed 方法来完成的
我想为用户添加一个功能来重做最后一步,并且需要一个备份图像。
以下是代码示例:
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BuffImgTest {
private BufferedImage buffimg, scaledimg, backupscaledimg;
private Image img;
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BuffImgTest window = new BuffImgTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BuffImgTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
final JLabel label = new JLabel("");
label.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent arg0) {
Graphics graphics = scaledimg.getGraphics();
graphics.setColor(Color.RED);
graphics.drawString("Test", arg0.getX(), arg0.getY());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
}
});
label.setBounds(10, 34, 414, 201);
try {
buffimg = ImageIO.read(new File("test.jpg"));
scaledimg = getScaledImage(buffimg, label.getWidth(),
label.getHeight());
backupscaledimg = scaledimg;
// backupscaledimg=getScaledImage(buffimg,label.getWidth(),label.getHeight());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
} catch (Exception e) {
System.out.println(e);
}
frame.getContentPane().add(label);
JButton btnNewButton = new JButton("Restart Step");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
scaledimg = backupscaledimg;
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
}
});
btnNewButton.setBounds(111, 238, 89, 23);
frame.getContentPane().add(btnNewButton);
}
public static BufferedImage getScaledImage(BufferedImage image, int width,
int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double) width / imageWidth;
double scaleY = (double) height / imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(
scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(image, new BufferedImage(width, height,
image.getType()));
}
}
它没有按预期工作。
如果我使用注释行 backupscaledimg = getScaledImage(buffimg,label.getWidth(),label.getHeight());
而不是 backupscaledimg = scaledimg;
,它会按预期工作。
问题是我想在图片上做几步画东西,只能像第一次那样重做。据我所知,问题可能在于,命令 backupscaledimg = scaledimg
只是为 backupscaledimg 创建一个指向 scaledimg 的指针,这导致它们都发生了改变。
虽然我不想在每一步都保存一个新的图像文件。
有没有办法解决? (顺便在这里找到了缩放功能感谢匿名)
做了一些修改
- 使用 GridBagLayout
- 可以通过按 "Restart Step"
重置回原始图像
- 能够使用图像堆栈(即 BufferedImage 堆栈)撤消上次操作
示例代码:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BuffImgTest {
private BufferedImage scaledImg, originalScaledImg;
private JFrame frame;
private Stack<BufferedImage> imageStack = new Stack<>();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BuffImgTest window = new BuffImgTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BuffImgTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel(new GridBagLayout());
final JLabel imgLabel = new JLabel("");
imgLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent arg0) {
// Add current image to the image stack
imageStack.add(copyImage(scaledImg));
// Change the image
Graphics graphics = scaledImg.getGraphics();
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("Arial", Font.BOLD, 32));
graphics.drawString("TEST", arg0.getX(), arg0.getY());
// Update label
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
imgLabel.setSize(500, 500);
imgLabel.setPreferredSize(new Dimension(500, 500));
try {
BufferedImage buffImg = ImageIO.read(new File("test.jpg"));
scaledImg = getScaledImage(buffImg, imgLabel.getWidth(),
imgLabel.getHeight());
// Clone it first
originalScaledImg = copyImage(scaledImg);
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
} catch (Exception e) {
System.out.println(e);
}
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(20, 10, 10, 10);
panel.add(imgLabel, c);
JButton restartBtn = new JButton("Restart Step");
restartBtn.setFont(new Font("Arial", Font.ITALIC, 20));
restartBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// Clear the image stack
imageStack.clear();
// Reset the image
scaledImg = copyImage(originalScaledImg);
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(10, 10, 5, 10);
panel.add(restartBtn, c);
JButton undoBtn = new JButton("Undo Last");
undoBtn.setFont(new Font("Arial", Font.ITALIC, 20));
undoBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(imageStack.isEmpty()) {
JOptionPane.showMessageDialog(frame, "Cannot undo anymore!");
return;
}
// Get the previous image
scaledImg = copyImage(imageStack.pop());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 2;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(5, 10, 20, 10);
panel.add(undoBtn, c);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setSize(800, 800);
}
/** For copying image */
public static BufferedImage copyImage(BufferedImage source){
BufferedImage b = new BufferedImage(
source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
public static BufferedImage getScaledImage(BufferedImage image, int width,
int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double) width / imageWidth;
double scaleY = (double) height / imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(
scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(image, new BufferedImage(width, height,
image.getType()));
}
}
已编辑图像:
按下后的图像"Restart step":
图像堆栈为空时按"Undo Last":
注:
- 复制图片的代码来自this answer by APerson
在我的应用程序中,通过单击图像在图像上标记了一些东西。
这是通过将图像设置为 JLabel 的图标并添加 MousePressed 方法来完成的
我想为用户添加一个功能来重做最后一步,并且需要一个备份图像。
以下是代码示例:
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BuffImgTest {
private BufferedImage buffimg, scaledimg, backupscaledimg;
private Image img;
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BuffImgTest window = new BuffImgTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BuffImgTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
final JLabel label = new JLabel("");
label.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent arg0) {
Graphics graphics = scaledimg.getGraphics();
graphics.setColor(Color.RED);
graphics.drawString("Test", arg0.getX(), arg0.getY());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
}
});
label.setBounds(10, 34, 414, 201);
try {
buffimg = ImageIO.read(new File("test.jpg"));
scaledimg = getScaledImage(buffimg, label.getWidth(),
label.getHeight());
backupscaledimg = scaledimg;
// backupscaledimg=getScaledImage(buffimg,label.getWidth(),label.getHeight());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
} catch (Exception e) {
System.out.println(e);
}
frame.getContentPane().add(label);
JButton btnNewButton = new JButton("Restart Step");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
scaledimg = backupscaledimg;
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
}
});
btnNewButton.setBounds(111, 238, 89, 23);
frame.getContentPane().add(btnNewButton);
}
public static BufferedImage getScaledImage(BufferedImage image, int width,
int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double) width / imageWidth;
double scaleY = (double) height / imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(
scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(image, new BufferedImage(width, height,
image.getType()));
}
}
它没有按预期工作。
如果我使用注释行 backupscaledimg = getScaledImage(buffimg,label.getWidth(),label.getHeight());
而不是 backupscaledimg = scaledimg;
,它会按预期工作。
问题是我想在图片上做几步画东西,只能像第一次那样重做。据我所知,问题可能在于,命令 backupscaledimg = scaledimg
只是为 backupscaledimg 创建一个指向 scaledimg 的指针,这导致它们都发生了改变。
虽然我不想在每一步都保存一个新的图像文件。
有没有办法解决? (顺便在这里找到了缩放功能感谢匿名)
做了一些修改
- 使用 GridBagLayout
- 可以通过按 "Restart Step" 重置回原始图像
- 能够使用图像堆栈(即 BufferedImage 堆栈)撤消上次操作
示例代码:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BuffImgTest {
private BufferedImage scaledImg, originalScaledImg;
private JFrame frame;
private Stack<BufferedImage> imageStack = new Stack<>();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BuffImgTest window = new BuffImgTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BuffImgTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel(new GridBagLayout());
final JLabel imgLabel = new JLabel("");
imgLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent arg0) {
// Add current image to the image stack
imageStack.add(copyImage(scaledImg));
// Change the image
Graphics graphics = scaledImg.getGraphics();
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("Arial", Font.BOLD, 32));
graphics.drawString("TEST", arg0.getX(), arg0.getY());
// Update label
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
imgLabel.setSize(500, 500);
imgLabel.setPreferredSize(new Dimension(500, 500));
try {
BufferedImage buffImg = ImageIO.read(new File("test.jpg"));
scaledImg = getScaledImage(buffImg, imgLabel.getWidth(),
imgLabel.getHeight());
// Clone it first
originalScaledImg = copyImage(scaledImg);
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
} catch (Exception e) {
System.out.println(e);
}
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(20, 10, 10, 10);
panel.add(imgLabel, c);
JButton restartBtn = new JButton("Restart Step");
restartBtn.setFont(new Font("Arial", Font.ITALIC, 20));
restartBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// Clear the image stack
imageStack.clear();
// Reset the image
scaledImg = copyImage(originalScaledImg);
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(10, 10, 5, 10);
panel.add(restartBtn, c);
JButton undoBtn = new JButton("Undo Last");
undoBtn.setFont(new Font("Arial", Font.ITALIC, 20));
undoBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(imageStack.isEmpty()) {
JOptionPane.showMessageDialog(frame, "Cannot undo anymore!");
return;
}
// Get the previous image
scaledImg = copyImage(imageStack.pop());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 2;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(5, 10, 20, 10);
panel.add(undoBtn, c);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setSize(800, 800);
}
/** For copying image */
public static BufferedImage copyImage(BufferedImage source){
BufferedImage b = new BufferedImage(
source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
public static BufferedImage getScaledImage(BufferedImage image, int width,
int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double) width / imageWidth;
double scaleY = (double) height / imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(
scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(image, new BufferedImage(width, height,
image.getType()));
}
}
已编辑图像:
按下后的图像"Restart step":
图像堆栈为空时按"Undo Last":
注:
- 复制图片的代码来自this answer by APerson