【问题标题】:Select, Copy and Paste Images选择、复制和粘贴图像
【发布时间】:2014-10-28 02:10:12
【问题描述】:

我希望我的应用程序做什么:

1 - 选择图像区域并获取坐标。下面的代码应该这样做:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

public class ScreenCaptureRectangle {

Rectangle captureRect;

ScreenCaptureRectangle(final BufferedImage screen) {
    final BufferedImage screenCopy = new BufferedImage(
            screen.getWidth(),
            screen.getHeight(),
            screen.getType());
    final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
    JScrollPane screenScroll = new JScrollPane(screenLabel);

    screenScroll.setPreferredSize(new Dimension(
            (int)(screen.getWidth()/3),
            (int)(screen.getHeight()/3)));

    JPanel panel = new JPanel(new BorderLayout());
    panel.add(screenScroll, BorderLayout.CENTER);

    final JLabel selectionLabel = new JLabel(
            "Drag a rectangle in the screen shot!");
    panel.add(selectionLabel, BorderLayout.SOUTH);

    repaint(screen, screenCopy);
    screenLabel.repaint();

    screenLabel.addMouseMotionListener(new MouseMotionAdapter() {

        Point start = new Point();

        @Override
        public void mouseMoved(MouseEvent me) {
            start = me.getPoint();
            repaint(screen, screenCopy);
            selectionLabel.setText("Start Point: " + start);
            screenLabel.repaint();
        }

        @Override
        public void mouseDragged(MouseEvent me) {
            Point end = me.getPoint();
            captureRect = new Rectangle(start,
                    new Dimension(end.x-start.x, end.y-start.y));
            repaint(screen, screenCopy);
            screenLabel.repaint();
            selectionLabel.setText("Rectangle: " + captureRect);
        }
    });

    JOptionPane.showMessageDialog(null, panel);

    System.out.println("Rectangle of interest: " + captureRect);
}

public void repaint(BufferedImage orig, BufferedImage copy) {
    Graphics2D g = copy.createGraphics();
    g.drawImage(orig,0,0, null);
    if (captureRect!=null) {
        g.setColor(Color.RED);
        g.draw(captureRect);
        g.setColor(new Color(255,255,255,150));
        g.fill(captureRect);
    }
    g.dispose();
}

public static void main(String[] args) throws Exception {
    Robot robot = new Robot();
    final Dimension screenSize = Toolkit.getDefaultToolkit().
            getScreenSize();
    final BufferedImage screen = robot.createScreenCapture(
            new Rectangle(screenSize));

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new ScreenCaptureRectangle(screen);
        }
    });
}
}

2 - 获取坐标并将其用于 getSubimage 方法。

double w  = captureRect.getWidth();
double h  = captureRect.getHeight();
double x  = captureRect.getX();
double y  = captureRect.getY();

int W = (int) w;
int H = (int) h;
int X = (int) x;
int Y = (int) y;

BufferedImage selectImg = screen.getSubimage(x, y, w, h);

3 - 此代码创建一个新图像文件并复制所选图像。

BufferedImage img = new BufferedImage ( 5000, 5000, BufferedImage.TYPE_INT_RGB );
img.createGraphics().drawImage(selectImg, 0, 0, null);
File final_image = new File("C:/Final.jpg");
ImageIO.write(img, "jpeg", final_image);

app的理念是:
- 选择图像的一个区域。
- 复制该图像并粘贴到其他文件中。 (当我按下任何按钮时)
- 程序将继续运行,直到我按下另一个按钮。
- 我复制程序的每张图片都会粘贴到最后一张的旁边。

我想我已经接近解决方案了。谁能帮我“连接零件”?

【问题讨论】:

  • “当我按下任何底部时” - 你的意思是“按钮”吗?
  • “我复制程序的每个图像都会粘贴到最后一个图像旁边” - 我假设这意味着在屏幕上,或者你的意思是文件应该按顺序命名?
  • 是的,你是对的。它意味着在同一屏幕上。我只想要一个图像文件。非常感谢。我想了解你做了什么,但它是完美的

标签: java image copy-paste


【解决方案1】:

先看看:

您需要将已有的概念转化为连贯可行的解决方案。也就是说,在您需要的区域之间提供功能(选择区域并保存文件),以便它们干净地协同工作......

下面的例子是截图,允许你选择一个区域,点击保存,文件将被保存。该示例检查当前目录中已有多少文件并将计数增加 1,这样您就不会覆盖现有文件...

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ScreenImage {

    public static void main(String[] args) {
        new ScreenImage();
    }

    public ScreenImage() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                try {
                    Robot robot = new Robot();
                    final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                    final BufferedImage screen = robot.createScreenCapture(new Rectangle(screenSize));

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane(screen));
                    frame.setSize(400, 400);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (AWTException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage master;

        public TestPane(BufferedImage image) {
            this.master = image;
            setLayout(new BorderLayout());
            final ImagePane imagePane = new ImagePane(image);
            add(new JScrollPane(imagePane));

            JButton btnSave = new JButton("Save");
            add(btnSave, BorderLayout.SOUTH);

            btnSave.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        BufferedImage img = imagePane.getSubImage();
                        master = append(master, img);
                        File save = new File("Capture.png");
                        ImageIO.write(master, "png", save);
                        imagePane.clearSelection();
                        JOptionPane.showMessageDialog(TestPane.this, save.getName() + " was saved", "Saved", JOptionPane.INFORMATION_MESSAGE);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                        JOptionPane.showMessageDialog(TestPane.this, "Failed to save capture", "Error", JOptionPane.ERROR_MESSAGE);
                    }
                }

                public BufferedImage append(BufferedImage master, BufferedImage sub) {

                    // Create a new image which can hold both background and the
                    // new image...
                    BufferedImage newImage = new BufferedImage(
                                    master.getWidth() + sub.getWidth(),
                                    Math.max(master.getHeight(), sub.getHeight()),
                                    BufferedImage.TYPE_INT_ARGB);
                    // Get new image's Graphics context
                    Graphics2D g2d = newImage.createGraphics();
                    // Draw the old background
                    g2d.drawImage(master, 0, 0, null);
                    // Position and paint the new sub image...
                    int y = (newImage.getHeight() - sub.getHeight()) / 2;
                    g2d.drawImage(sub, master.getWidth(), y, null);
                    g2d.dispose();

                    return newImage;

                }

            });

        }

    }

    public class ImagePane extends JPanel {

        private BufferedImage background;
        private Rectangle selection;

        public ImagePane(BufferedImage img) {
            background = img;
            MouseAdapter ma = new MouseAdapter() {

                private Point clickPoint;

                @Override
                public void mousePressed(MouseEvent e) {
                    clickPoint = e.getPoint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point dragPoint = e.getPoint();

                    int x = Math.min(clickPoint.x, dragPoint.x);
                    int y = Math.min(clickPoint.y, dragPoint.y);
                    int width = Math.abs(clickPoint.x - dragPoint.x);
                    int height = Math.abs(clickPoint.y - dragPoint.y);

                    selection = new Rectangle(x, y, width, height);
                    repaint();

                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        public void clearSelection() {
            selection = null;
            repaint();
        }

        public BufferedImage getSubImage() {

            BufferedImage img = null;
            if (selection != null) {

                img = background.getSubimage(selection.x, selection.y, selection.width, selection.height);

            }
            return img;

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(background.getWidth(), background.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - background.getWidth()) / 2;
            int y = (getHeight() - background.getHeight()) / 2;
            g2d.drawImage(background, x, y, this);
            if (selection != null) {
                Color stroke = UIManager.getColor("List.selectionBackground");
                Color fill = new Color(stroke.getRed(), stroke.getGreen(), stroke.getBlue(), 128);
                g2d.setColor(fill);
                g2d.fill(selection);
                g2d.setColor(stroke);
                g2d.draw(selection);
            }
            g2d.dispose();
        }

    }

}

所以除了渲染选择之外,最难的部分是生成结果图像...

基本上,这是通过创建一个新的BufferedImage 并将旧图像和新的子图像一起绘制来完成的。

public BufferedImage append(BufferedImage master, BufferedImage sub) {

    // Create a new image which can hold both background and the
    // new image...
    BufferedImage newImage = new BufferedImage(
                    master.getWidth() + sub.getWidth(),
                    Math.max(master.getHeight(), sub.getHeight()),
                    BufferedImage.TYPE_INT_ARGB);
    // Get new image's Graphics context
    Graphics2D g2d = newImage.createGraphics();
    // Draw the old background
    g2d.drawImage(master, 0, 0, null);
    // Position and paint the new sub image...
    int y = (newImage.getHeight() - sub.getHeight()) / 2;
    g2d.drawImage(sub, master.getWidth(), y, null);
    g2d.dispose();

    return newImage;

}

该示例将之前的(主)图像替换为此处创建的图像,因此它会不断将新图像附加到它的末尾...

【讨论】:

  • 再次感谢您。我试图研究你指出的主题,但它们都是英文的,而且更难理解。对于大人物,您是否指出这本书 [Java: How to program - Deitel] ? (有葡萄牙语版本)
  • 我会尽快更新示例,将图像复制回屏幕。你不读的书对你没有帮助。没有一本书会告诉你一切。但是,由于 API 最近发生了一些变化,请尝试获取一个相当最新的版本;)
  • 哈哈你说得对。我会学习更多的编程。只是为了澄清这个想法:程序应该将图像的每个选定区域粘贴到另一个文件图像中。一个在另一个旁边。这个想法是像我们使用字符串一样连接图像。 (:
  • 所以您不希望将新剪辑也添加到屏幕/UI 中?只是为了文件?
  • @MadProgrammer 可以编写您想要的所有功能,但是,恕我直言,最好先尝试一下,Marco。正如您所说,使用当前答案,您已接近最终解决方案。
【解决方案2】:

您需要更多监听器来按下和释放按钮。mouseMoved 中的一些行也更好地放置在 mousePressed 中。
您可能希望在释放鼠标时更新您的captureRect(在mouseReleased 方法中)。
然后,您只需将其写入文件即可。您可以根据需要调整其他内容。

为了清楚起见,最好在你的 UI 中添加一个保存按钮。

public class ScreenCaptureRectangle {

    Rectangle captureRect;
    Point start = new Point();
    SimpleDateFormat sdf;

    ScreenCaptureRectangle(final BufferedImage screen) {
        sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        final BufferedImage screenCopy = new BufferedImage(
                screen.getWidth(),
                screen.getHeight(),
                screen.getType());
        final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
        JScrollPane screenScroll = new JScrollPane(screenLabel);

        screenScroll.setPreferredSize(new Dimension(
                (int) (screen.getWidth() / 3),
                (int) (screen.getHeight() / 3)));

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(screenScroll, BorderLayout.CENTER);
        JButton btnSave = new JButton("SAVE");
        btnSave.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                double w = captureRect.getWidth();
                double h = captureRect.getHeight();
                double x = captureRect.getX();
                double y = captureRect.getY();

                int W = (int) w;
                int H = (int) h;
                int X = (int) x;
                int Y = (int) y;

                BufferedImage selectImg = screen.getSubimage(X, Y, W, H);
                try {
                    String fName = generateFileName();
                    if (fName != null) {
                        File f = new File(fName);
                        if (f.createNewFile()) {
                            ImageIO.write(selectImg, "jpg", f);
                        }
                    }
                } catch (IOException ex) {
                    Logger.getLogger(ScreenCaptureRectangle.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        panel.add(btnSave, BorderLayout.AFTER_LAST_LINE);

        final JLabel selectionLabel = new JLabel(
                "Drag a rectangle in the screen shot!");
        panel.add(selectionLabel, BorderLayout.SOUTH);

        repaint(screen, screenCopy);
        screenLabel.repaint();

        screenLabel.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent me) {
                Point end = me.getPoint();
                captureRect = new Rectangle(start,
                        new Dimension(end.x - start.x, end.y - start.y));
                repaint(screen, screenCopy);
                screenLabel.repaint();
                selectionLabel.setText("Rectangle: " + captureRect);
            }

        });

        screenLabel.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent me) {
                start = me.getPoint();
                repaint(screen, screenCopy);
                selectionLabel.setText("Start Point: " + start);
                screenLabel.repaint();
            }

            @Override
            public void mouseReleased(MouseEvent me) {
                int endX = me.getX();
                int endY = me.getY();
                if (endX > start.x && endY > start.y) {
                    captureRect = new Rectangle(start.x, start.y, endX-start.x, endY-start.y);
                    System.out.println("Rectangle of interest: " + captureRect);
                }
            }

        });

        JOptionPane.showMessageDialog(null, panel);
    }

    private String generateFileName() {
        return new StringBuilder("screencrop_").append(sdf.format(new Date())).append(".jpg").toString();
    }

    public void repaint(BufferedImage orig, BufferedImage copy) {
        Graphics2D g = copy.createGraphics();
        g.drawImage(orig, 0, 0, null);
        if (captureRect != null) {
            g.setColor(Color.RED);
            g.draw(captureRect);
            g.setColor(new Color(255, 255, 255, 150));
            g.fill(captureRect);
        }
        g.dispose();
    }

    public static void main(String[] args) throws Exception {
        Robot robot = new Robot();
        final Dimension screenSize = Toolkit.getDefaultToolkit().
                getScreenSize();
        final BufferedImage screen = robot.createScreenCapture(
                new Rectangle(screenSize));

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ScreenCaptureRectangle(screen);
            }
        });
    }
}

【讨论】:

  • 谢谢你,Yohanes。这真的很好。对不起我的英语不好。我想说的是:将所有选定区域放在同一个文件图像上。一个在另一个旁边。
  • 我的建议是:制作一个ListRectangles,并添加一个按钮Capture。每次单击Capture 时,都会将所选内容的新Rectangle 添加到List。当您点击按钮Save 时,您将迭代这些矩形并获得总大小(这将取决于您希望如何组合它们),然后像您想要的那样在一个BufferedImage 中绘制每个子图像。当您尝试此操作时遇到更多问题时,请稍后再问(我认为在新帖子中会更好)。祝你好运!
  • 嗨,Yohanes。我按照你说的做了,但列表的长度有限。所以我找到了这段代码: [code] ArrayList al = new ArrayList(); al.add(新矩形(x, y, w, h)); [/code] 但它不起作用。你能帮我吗?
  • 我在 Facebook 上找到了你。我们可以在那里谈谈吗?或在电子邮件中?更容易
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多