【问题标题】:Why does theBufferedImage output look different than on screen in the JFrame window on Linux platform?为什么在 Linux 平台的 JFrame 窗口中,BufferedImage 输出看起来与屏幕上的不同?
【发布时间】:2016-08-09 19:29:32
【问题描述】:

我正在开发一个需要捕获屏幕 GUI 图像数据的项目(例如 JFrame)。不知何故,我的应用程序适用于 Windows 和 Mac OS,但对于 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,以将其捕获为图像输出。您可以看到屏幕上的 GUI 和它的图像输出作为附件。生成的图像与屏幕上的 GUI 略有不同。查看 JFrame 边框的左/右边缘,它与 contentPane 蓝色重叠。

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

On-Screen GUI
CapturedImage

【问题讨论】:

标签: java linux swing jframe bufferedimage


【解决方案1】:

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

尝试使用Screen Image

当框架被指定为组件时,它将使用Robot 类来拍摄图像。否则就是会使用 Swing 绘画。

【讨论】:

    【解决方案2】:

    快速修复

    尝试改变...

    BufferedImage imageOutput = getImageData(f); 
    

    BufferedImage imageOutput = getImageData(f.getContentPane());
    

    这可能也适用于 Linux(我目前无法对其进行测试),并且可以轻松解决您的问题。

    解决方案

    您也可以使用Robot 类。 Robot 具有更兼容的屏幕捕获功能,但这意味着对您的代码进行严重更改。您可以在我的答案的最底部找到代码。让我解释一下所有变化的原因......

    1. Robot 是执行屏幕捕获所需的类。它可以捕获整个桌面或屏幕的一部分。在这种情况下,我们将通过在桌面上找出相应的 XY 坐标,让它捕获应用程序的蓝色部分。 Robot 在这种情况下需要是静态的,因为您正试图通过 main() 方法访问它。因此Robot 变量需要在main() 方法之外,以便JMenuItemActionListener 可以访问它。

    2. 如果您通过菜单执行屏幕截图,该菜单将出现在屏幕截图中,因为您没有给菜单时间消失。结果,需要添加延迟。同时,这种延迟需要发生在一个单独的线程中,否则你的菜单会冻结……我创建新线程的方式称为 Lambda 表达式。这只是一种轻松创建立即启动的新线程的简单方法,仅此而已。它的工作原理是这样的:new Thread(() -> { /* Do something */ }.start();

    3. 接下来是找到屏幕蓝色部分的坐标。这是一个简单的getLocationOnScreen() 在框架的上下文窗格(或您希望捕获的任何组件)。

    4. 现在屏幕截图可以由Robot 创建并使用您之前的代码保存到文件中。

    就是这样!如果您有任何问题,请发表评论,我稍后会回来查看。


    代码

    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);
     }
    }
    

    【讨论】:

    • 我想要完整的 GUI 输出,而不仅仅是 JFrame 的内容。它应该有边框、标题栏等等。我对在读取屏幕像素时使用 Robot.createScreenCapture() 方法有点怀疑,它解决了上面的示例,但如果我想通过不与当前 GUI 交互来捕获图像并假设 JFrame 窗口顶部还有其他 GUI 窗口GUI 然后捕获的图​​像将不仅仅是 JFrame GUI,它只是屏幕上的矩形部分,无论当时显示什么。
    猜你喜欢
    • 2015-03-25
    • 2022-06-16
    • 1970-01-01
    • 2020-07-21
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 1970-01-01
    相关资源
    最近更新 更多