如何使用java捕获其他应用程序的选定屏幕?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/464593/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:57:35  来源:igfitidea点击:

How to capture selected screen of other application using java?

javascreenshot

提问by

We are trying to develop a screen capture utility.

我们正在尝试开发屏幕捕获实用程序。

How do we capture selected screen of another application using Java? And how do we add a callout to the captured screen?

我们如何使用 Java 捕获另一个应用程序的选定屏幕?我们如何向捕获的屏幕添加标注?

回答by Clay Fowler

You will need to provide more specific information in order to receive meaningful help. To start with, Which operating systems does this need to work on? Do you need to capture the contents of individual windows or literally entire displays (you used the ambiguous term "selected screen of other application" in your original post). What specifically do you want to see when you "add callout to captured screen"?

您需要提供更具体的信息才能获得有意义的帮助。首先,这需要在哪些操作系统上运行?您是否需要捕获单个窗口的内容或字面上的整个显示(您在原始帖子中使用了含糊不清的术语“其他应用程序的选定屏幕”)。当您“将标注添加到捕获的屏幕”时,您特别想看到什么?

回答by Adam Paynter

Perhaps the java.awt.Robotclass would help with the screen shots, although I do not think it is capable of locating individual windows. As for these "call outs", the Robot class can also invoke mouse clicks and key presses, if that is what you mean.

也许java.awt.Robot类会对屏幕截图有所帮助,尽管我认为它不能定位单个窗口。至于这些“呼出”,Robot 类还可以调用鼠标点击和按键操作,如果这是您的意思的话。

回答by Steve McLeod

If you want to take a screenshot of a specific window of another non-Java application code, I think you'll have to write some native (i.e. non-Java) code. Interaction between Java apps and non-Java apps at such a level is difficult.

如果您想截取另一个非 Java 应用程序代码的特定窗口的屏幕截图,我认为您必须编写一些本机(即非 Java)代码。Java 应用程序和非 Java 应用程序之间在这种级别上的交互是困难的。

回答by John Gardner

Robot r = new Robot();
Toolkit t = Toolkit.getDefaultToolkit();
Dimension d = t.getScreenSize();
Image i = r.createScreenCapture( 0, 0, d.width, d.height );

should get you a whole image of the whole screen. not sure if that gets you the whole things if you have multiple monitors, though...

应该让你得到整个屏幕的完整图像。如果您有多个显示器,不确定这是否能让您了解全部内容,但是...

回答by Adam Paynter

Based on Prajakta's description of the project, I believe some explanation of manipulating a screen shot is in order (I think John did an excellent job of explaining how to capture the screen shot using the java.awt.Robot class). Remember, as Steve McLeod said, Java may not be able to automatically locate the location of the window you want to capture on the screen. This is important, because the Robot class needs to know this location, either automatically or manually from you.

根据Prajakta 对项目的描述,我相信对操作屏幕截图的一些解释是正确的(我认为 John 在解释如何使用 java.awt.Robot 类捕获屏幕截图方面做得很好)。请记住,正如Steve McLeod 所说,Java 可能无法自动定位您要在屏幕上捕获的窗口的位置。这很重要,因为 Robot 类需要知道这个位置,无论是自动还是手动告诉你。

Callouts, text, images, etc can be added to the screen shot via the Graphics2D object you receive when you call the createGraphics() method of the screen shot's BufferedImage. I highly recommend you check out the Graphics2D's APIto better understand what it is capable of. I also recommend finding some tutorials, perhaps starting with the the 2D Graphics Tutorial from Sun. The book entitled "Filthy Rich Clients" may also come in useful.

当您调用屏幕截图的BufferedImage的 createGraphics() 方法时,可以通过您收到的 Graphics2D 对象将标注、文本、图像等添加到屏幕截图中。我强烈建议您查看Graphics2D 的 API以更好地了解它的功能。我还建议您查找一些教程,也许从 Sun 的 2D 图形教程开始。题为“肮脏的富客户”的书也可能有用。

When you finally want to save this modified screen shot, you can use the one of the "write" methods of the ImageIOclass.

当您最终想要保存这个修改后的屏幕截图时,您可以使用ImageIO类的“写入”方法之一。

Here is a very simple, start-to-finish example. It is up to you to fill in whatever details necessary.

这是一个非常简单的、从头到尾的例子。您可以填写任何必要的详细信息。

I hope this help a little!

我希望这会有所帮助!

Robot robot = new Robot();

// The hard part is knowing WHERE to capture the screen shot from
BufferedImage screenShot = robot.createScreenCapture(x, y, width, height);
Graphics2D graphics = screenShot.createGraphics();

// Add a label to the screen shot
Color textColor = Color.RED;
graphics.setColor(textColor);
graphics.drawString("Some text", textX, textY);

// Save your screen shot with its label
ImageIO.save(screenShot, "png", new File("myScreenShot.png"));

回答by OscarRyz

Probably you can workaround Robot lack of ability to know the borders of the window, by allowing the user to select the area he wants to screen shot.

也许你可以通过允许用户选择他想要截屏的区域来解决机器人缺乏了解窗口边界的能力。

You have two approaches, if the option is fullscreen you don't need to worry, follow the Robot approach described before.

您有两种方法,如果选项是全屏的,您不必担心,请按照前面描述的机器人方法进行操作。

If the applicatin is for desired area:

如果申请适用于所需区域:

  1. Start desired application.

  2. Take a full screen of the desktop.

  3. Create a full screen app using the screenshot as the background, ONLY to allow the user to select the area where to capture the image ( you start with an small square and let the user drag until he creates the desired screen capture )

  4. Pass this information to Robot and take the screenshots from that area.

  1. 启动所需的应用程序。

  2. 全屏桌面。

  3. 使用屏幕截图作为背景创建一个全屏应用程序,仅允许用户选择捕获图像的区域(您从一个小方块开始,让用户拖动直到他创建所需的屏幕截图)

  4. 将此信息传递给 Robot 并从该区域截取屏幕截图。

Something like this:

像这样的东西:

alt text http://img136.imageshack.us/img136/8622/screencapturebb3.png

替代文字 http://img136.imageshack.us/img136/8622/screencapturebb3.png

If you don't like the option to use a full screenshot as background, you can use a transparent window.

如果您不喜欢使用完整屏幕截图作为背景的选项,您可以使用透明窗口

And do the same : - )

并做同样的事情:-)

Aaahhh second option is to try to identify borders analyzing the images, but honestly , I don't think it worth it.

Aaahhh 第二种选择是尝试识别分析图像的边界,但老实说,我认为这不值得。

There's a third option, but is a secret.

还有第三种选择,但这是一个秘密。

回答by Interpreter

回答by wutzebaer

With this code i could make screens of certain windows in windows10, dont forget the dependency.

使用此代码,我可以在 windows10 中制作某些窗口的屏幕,不要忘记依赖项。

Credits go to: Windows: how to get a list of all visible windows?

积分转到:Windows:如何获取所有可见窗口的列表?

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>4.5.0</version>
</dependency>

Code:

代码:

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.imageio.ImageIO;

import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;

public class Main {
    public static void main(String[] args) throws AWTException, IOException {

        int hWnd = User32.instance.FindWindowA(null, "Minesweeper X");
        WindowInfo w = getWindowInfo(hWnd);
        User32.instance.SetForegroundWindow(w.hwnd);
        BufferedImage createScreenCapture = new Robot().createScreenCapture(new Rectangle(w.rect.left, w.rect.top, w.rect.right - w.rect.left, w.rect.bottom - w.rect.top));
        ImageIO.write(createScreenCapture, "png", new File("screen.png"));

        // listAllWindows();
    }

    private static void listAllWindows() throws AWTException, IOException {
        final List<WindowInfo> inflList = new ArrayList<WindowInfo>();
        final List<Integer> order = new ArrayList<Integer>();
        int top = User32.instance.GetTopWindow(0);
        while (top != 0) {
            order.add(top);
            top = User32.instance.GetWindow(top, User32.GW_HWNDNEXT);
        }

        User32.instance.EnumWindows(new WndEnumProc() {
            public boolean callback(int hWnd, int lParam) {
                WindowInfo info = getWindowInfo(hWnd);
                inflList.add(info);
                return true;
            }

        }, 0);
        Collections.sort(inflList, new Comparator<WindowInfo>() {
            public int compare(WindowInfo o1, WindowInfo o2) {
                return order.indexOf(o1.hwnd) - order.indexOf(o2.hwnd);
            }
        });
        for (WindowInfo w : inflList) {
            System.out.println(w);
        }
    }

    public static  WindowInfo getWindowInfo(int hWnd) {
        RECT r = new RECT();
        User32.instance.GetWindowRect(hWnd, r);
        byte[] buffer = new byte[1024];
        User32.instance.GetWindowTextA(hWnd, buffer, buffer.length);
        String title = Native.toString(buffer);
        WindowInfo info = new WindowInfo(hWnd, r, title);
        return info;
    }

    public static interface WndEnumProc extends StdCallLibrary.StdCallCallback {
        boolean callback(int hWnd, int lParam);
    }

    public static interface User32 extends StdCallLibrary {
        public static final String SHELL_TRAY_WND = "Shell_TrayWnd";
        public static final int WM_COMMAND = 0x111;
        public static final int MIN_ALL = 0x1a3;
        public static final int MIN_ALL_UNDO = 0x1a0;

        final User32 instance = (User32) Native.loadLibrary("user32", User32.class);

        boolean EnumWindows(WndEnumProc wndenumproc, int lParam);

        boolean IsWindowVisible(int hWnd);

        int GetWindowRect(int hWnd, RECT r);

        void GetWindowTextA(int hWnd, byte[] buffer, int buflen);

        int GetTopWindow(int hWnd);

        int GetWindow(int hWnd, int flag);

        boolean ShowWindow(int hWnd);

        boolean BringWindowToTop(int hWnd);

        int GetActiveWindow();

        boolean SetForegroundWindow(int hWnd);

        int FindWindowA(String winClass, String title);

        long SendMessageA(int hWnd, int msg, int num1, int num2);

        final int GW_HWNDNEXT = 2;
    }

    public static class RECT extends Structure {
        public int left, top, right, bottom;

        @Override
        protected List<String> getFieldOrder() {
            List<String> order = new ArrayList<>();
            order.add("left");
            order.add("top");
            order.add("right");
            order.add("bottom");
            return order;
        }
    }

    public static class WindowInfo {
        int hwnd;
        RECT rect;
        String title;

        public WindowInfo(int hwnd, RECT rect, String title) {
            this.hwnd = hwnd;
            this.rect = rect;
            this.title = title;
        }

        public String toString() {
            return String.format("(%d,%d)-(%d,%d) : \"%s\"", rect.left, rect.top, rect.right, rect.bottom, title);
        }
    }
}