java - 备份用Java绘制的图像

标签 java image backup draw undo-redo

在我的应用程序中,通过单击图像来标记图像上的内容。
这是通过将图像设置为 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
  • 能够通过按“重新启动步骤”重置回原始图像
  • 能够使用图像堆栈(即 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()));
    }
}

编辑图像:

Edited

按“重新启动步骤”后的图像:

Cleared

当图像堆栈为空时按“撤消最后一个”:

EmptyImageStack

注意:

关于java - 备份用Java绘制的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31605248/

相关文章:

mysql - 导入错误的 MySQL 转储时如何跳过行

amazon-web-services - 备份:Amazon S3或Glacier-很多小文件吗?

java - 如何: Backing up a Ontology?

java - 除了 Java 属性之外,还有其他方法可以保存树状数据吗?

java - 在android项目中放置并运行apk文件

javascript - 如何使用jCarousel放大 slider ?

javascript - 具有内部缩放功能的 css 图片库

c# Bitmap.Save 透明度不保存在 png 中

java - 带有自定义缓存管理器实现的 Spring 缓存抽象不起作用

java - TarsosDSP for Android AudioRecord 对象未从 LibGDX 项目内初始化