Java 为什么BuffereImage输出看起来与Linux平台上JFrame窗口中的屏幕不同?

Java 为什么BuffereImage输出看起来与Linux平台上JFrame窗口中的屏幕不同?,java,linux,swing,jframe,bufferedimage,Java,Linux,Swing,Jframe,Bufferedimage,我正在从事一个项目,该项目需要捕获屏幕GUI(例如JFrame)的图像数据。不知何故,我的应用程序适用于windows和Mac操作系统,但对于Linux,它不能提供与屏幕GUI相同的图像输出 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.image.BufferedImage; import java.awt.event.ActionListener;

我正在从事一个项目,该项目需要捕获屏幕GUI(例如JFrame)的图像数据。不知何故,我的应用程序适用于windows和Mac操作系统,但对于Linux,它不能提供与屏幕GUI相同的图像输出

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.File;

class jframeExample {

public static BufferedImage getImageData(
        Component component) {

    BufferedImage image = new BufferedImage(
            component.getWidth(),
            component.getHeight(),
            BufferedImage.TYPE_INT_RGB
    );
    component.printAll( image.createGraphics() );
    return image;
}

public static void main(String[] args){

    Runnable r = new Runnable() {
        public void run() {
            final JFrame f = new JFrame("JFrame Border");
            f.setLayout(new BorderLayout());
            f.setLocation(500,300);
            f.setSize(560, 420);
            f.getContentPane().setBackground(Color.BLUE);

            JMenuItem screenshot =
                    new JMenuItem("TakeSnapshot");
            screenshot.addActionListener(
                    new ActionListener(){
                        public void actionPerformed(ActionEvent ae) {
                            BufferedImage imageOutput = getImageData(f);
                            try {
                                // write the image as a PNG
                                ImageIO.write(
                                        imageOutput,
                                        "png",
                                        new File("CapturedImage.png"));
                            } catch(Exception e) {
                                e.printStackTrace();
                            }
                        }
                    } );
            JMenu menu = new JMenu("Menu");
            menu.add(screenshot);
            JMenuBar menuBar = new JMenuBar();
            menuBar.add(menu);
            f.setJMenuBar(menuBar);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setVisible(true);

        }
    };
    SwingUtilities.invokeLater(r);
 }
}
上面的代码将为GUI提供菜单选项,以将其捕获为图像输出。你们可以看到屏幕上的图形用户界面和它的图像输出作为附件。生成的图像和屏幕上的图形用户界面并没有什么不同。请参见JFrame边框的左/右边缘,它与contentPane蓝色重叠

如何获得与屏幕GUI完全相同的图像,或调整左/右边框,使其不与contentPane区域重叠?我使用LookAndFeel类尝试了几个选项,但还没有获得任何成功。如有任何帮助/建议,将不胜感激



Swing不会绘制整个框架。框架是操作系统的一个小部件

尝试使用

当帧被指定为组件时,它将使用
Robot
类拍摄图像。否则将使用Swing喷漆。

快速修复 尝试改变

BufferedImage imageOutput = getImageData(f); 

这可能也适用于Linux(我目前无法测试它),并且可以很容易地解决您的问题。

解决方案 或者,您可以使用
机器人
Robot
具有更兼容的屏幕捕获功能,但这意味着对代码进行了严重修改。你可以在我答案的最下面找到密码。让我解释一下所有变化的原因。。。

  • Robot
    是执行屏幕捕获所需的类。它可以捕获整个桌面或屏幕的一部分。在本例中,我们将让它通过查找桌面上相应的XY坐标来捕获应用程序的蓝色部分<代码>机器人在这种情况下需要是静态的,因为您正试图通过
    main()
    方法访问它。因此,
    Robot
    变量需要位于
    main()
    方法之外,以便
    JMenuItem
    ActionListener
    可以访问它。

  • 如果您通过菜单执行屏幕捕获,则该菜单将出现在屏幕捕获中,因为您没有给菜单消失的时间。因此,需要增加延迟。同时,此延迟需要在单独的线程中发生,否则您的菜单将冻结。。。我创建新线程的方式称为Lambda表达式。这只是一个简单的方法,可以轻松创建一个新线程,并立即启动,仅此而已。它的工作原理如下:
    newthread(()->{/*dosomething*/}.start();


  • 下一步是查找屏幕蓝色部分的坐标。这是一个简单的
    getLocationOnScreen()
    ,位于框架的上下文窗格上(或者您希望捕获的组件)。

  • 现在,屏幕截图可以由
    Robot
    创建,并使用以前的代码保存到文件中
  • 就这些!如果您有任何问题,请发表评论,我稍后会再查看


    代码
    我想要输出完整的GUI,而不仅仅是JFrame的内容。它应该有边框、标题栏和所有内容。我对使用Robot.createScreenCapture()有点怀疑方法读取屏幕像素时,它解决了上面的示例,但如果我想通过不与当前GUI交互来捕获图像,并且假设JFrame窗口GUI上有其他GUI窗口,那么捕获的图像将不仅仅是JFrame GUI,它将只是屏幕上的矩形部分,无论此时显示什么已报告为错误:
    BufferedImage imageOutput = getImageData(f.getContentPane());
    
    import java.awt.AWTException;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Rectangle;
    import java.awt.Robot;
    import java.awt.image.BufferedImage;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    import javax.swing.*;
    import javax.imageio.ImageIO;
    import java.io.File;
    
    class jframeExample {
    
    public static BufferedImage getImageData(
            Component component) {
    
        BufferedImage image = new BufferedImage(
                component.getWidth(),
                component.getHeight(),
                BufferedImage.TYPE_INT_RGB
        );
        component.printAll( image.createGraphics() );
        return image;
    }
    
    static Robot robot = null;
    
    public static void main(String[] args){
    
        Runnable r = new Runnable() {
            public void run() {
                try {
                    if(robot == null) robot = new Robot();
                } catch (AWTException e1) {
                    e1.printStackTrace();
                }
                final JFrame f = new JFrame("JFrame Border");
                f.setLayout(new BorderLayout());
                f.setLocation(500,300);
                f.setSize(560, 420);
                f.getContentPane().setBackground(Color.BLUE);
    
    
                JMenuItem screenshot =
                        new JMenuItem("TakeSnapshot");
                screenshot.addActionListener(
                        new ActionListener(){
                            public void actionPerformed(ActionEvent ae) {
                                new Thread(() -> {
                                    try {
                                        Thread.sleep(100);
                                    } catch (InterruptedException e1) {
                                        e1.printStackTrace();
                                    }
                                    int screenshotX = f.getContentPane().getLocationOnScreen().x;
                                    int screenshotY = f.getContentPane().getLocationOnScreen().y;
                                    int screenshotWidth = f.getContentPane().getWidth();
                                    int screenshotHeight = f.getContentPane().getHeight();
                                    BufferedImage imageOutput = robot.createScreenCapture(new Rectangle(screenshotX, screenshotY, screenshotWidth, screenshotHeight));
                                    try {
                                        // write the image as a PNG
                                        ImageIO.write(
                                                imageOutput,
                                                "png",
                                                new File("CapturedImage.png"));
                                    } catch(Exception e) {
                                        e.printStackTrace();
                                    }
                                }).start();
                            }
                        } );
                JMenu menu = new JMenu("Menu");
                menu.add(screenshot);
                JMenuBar menuBar = new JMenuBar();
                menuBar.add(menu);
                f.setJMenuBar(menuBar);
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
     }
    }