Java - 窗口图像
有谁知道如何在Java中捕获屏幕截图(不是它自己的屏幕,而是桌面上的任何其他窗口,并且它们不一定必须是活动窗口)在 Windows 中?这里有很多关于这个类似主题的帖子,但我还没有找到答案。
我尝试过使用 JNA,但在几次尝试后陷入困境。例如...
public class Main {
public static void main(String[] args) {
Main m = new Main();
List<WindowInfo> list = m.getWindows();
for (int i=0;i<list.size();i++)
{
WindowInfo info = list.get(i);
System.out.println(info.getTitle());
}
WindowInfo wi = list.get(0);
W32API.HDC hdcSrc = User32.instance.GetWindowDC(wi.getHwnd());
W32API.HDC hdcMemory = Gdi32.instance.CreateCompatibleDC(hdcSrc);
//W32API.HBITMAP hBitmapMemory = Gdi32.instance.CreateCompatibleBitmap(hdcSrc, int width, int height);
int width = wi.getRect().right - wi.getRect().left;
int height = wi.getRect().bottom - wi.getRect().top;
W32API.HBITMAP hBitmapMemory = Gdi32.instance.CreateCompatibleBitmap(hdcSrc, width, height);
W32API.HANDLE hOld = Gdi32.instance.SelectObject(hdcMemory, hBitmapMemory);
Gdi32.instance.BitBlt(hdcMemory, 0, 0, width, height, hdcSrc, width+2, height+2, 0x00CC0020);
/* # now how do we convert to a BufferedImage??? */
// clean up
Gdi32.instance.SelectObject(hdcMemory, hOld);
Gdi32.instance.DeleteDC(hdcMemory);
Gdi32.instance.DeleteObject(hBitmapMemory);
User32.instance.ReleaseDC(wi.getHwnd(), hdcSrc);
}
/**
*
* @return
*/
private List<WindowInfo> getWindows() {
final List<WindowInfo> list = new ArrayList<WindowInfo>();
User32.instance.EnumWindows(new WndEnumProc() {
public boolean callback(int hWnd, int lParam) {
if (User32.instance.IsWindowVisible(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);
if (title!=null&&title.length()>0) {
list.add(new WindowInfo(hWnd, r, title));
}
}
return true;
}
}, 0);
Collections.sort(list, new Comparator<WindowInfo>() {
public int compare(WindowInfo o1, WindowInfo o2) {
int i1 = (o1.getTitle()!=null&&o1.getTitle().length()>0?o1.getTitle():" ").charAt(0);
int i2 = (o2.getTitle()!=null&&o2.getTitle().length()>0?o2.getTitle():" ").charAt(0);
return i1 - i2;
}
});
return list;
}
}
我也尝试过“PrintWindow()”API 的等效项...
Graphics g = form.CreateGraphics();
Bitmap bmp = new Bitmap(form.Size.Width, form.Size.Height, g);
Graphics memoryGraphics = Graphics.FromImage(bmp);
IntPtr dc = memoryGraphics.GetHdc();
bool success = PrintWindow(form.Handle, dc, 0);
memoryGraphics.ReleaseHdc(dc);
// bmp now contains the screenshot
或者我必须使用 JNI 或任何其他工具吗?
Does anyone know how to capture a screen shot in Java (not it's own screen, but any other window on the desktop and they don't necessarily have to be the active window) in Windows? There are a number of threads here on this similar subject, but I have yet to find an answer.
I've tried using JNA, but became stuck after a few attempts. For example...
public class Main {
public static void main(String[] args) {
Main m = new Main();
List<WindowInfo> list = m.getWindows();
for (int i=0;i<list.size();i++)
{
WindowInfo info = list.get(i);
System.out.println(info.getTitle());
}
WindowInfo wi = list.get(0);
W32API.HDC hdcSrc = User32.instance.GetWindowDC(wi.getHwnd());
W32API.HDC hdcMemory = Gdi32.instance.CreateCompatibleDC(hdcSrc);
//W32API.HBITMAP hBitmapMemory = Gdi32.instance.CreateCompatibleBitmap(hdcSrc, int width, int height);
int width = wi.getRect().right - wi.getRect().left;
int height = wi.getRect().bottom - wi.getRect().top;
W32API.HBITMAP hBitmapMemory = Gdi32.instance.CreateCompatibleBitmap(hdcSrc, width, height);
W32API.HANDLE hOld = Gdi32.instance.SelectObject(hdcMemory, hBitmapMemory);
Gdi32.instance.BitBlt(hdcMemory, 0, 0, width, height, hdcSrc, width+2, height+2, 0x00CC0020);
/* # now how do we convert to a BufferedImage??? */
// clean up
Gdi32.instance.SelectObject(hdcMemory, hOld);
Gdi32.instance.DeleteDC(hdcMemory);
Gdi32.instance.DeleteObject(hBitmapMemory);
User32.instance.ReleaseDC(wi.getHwnd(), hdcSrc);
}
/**
*
* @return
*/
private List<WindowInfo> getWindows() {
final List<WindowInfo> list = new ArrayList<WindowInfo>();
User32.instance.EnumWindows(new WndEnumProc() {
public boolean callback(int hWnd, int lParam) {
if (User32.instance.IsWindowVisible(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);
if (title!=null&&title.length()>0) {
list.add(new WindowInfo(hWnd, r, title));
}
}
return true;
}
}, 0);
Collections.sort(list, new Comparator<WindowInfo>() {
public int compare(WindowInfo o1, WindowInfo o2) {
int i1 = (o1.getTitle()!=null&&o1.getTitle().length()>0?o1.getTitle():" ").charAt(0);
int i2 = (o2.getTitle()!=null&&o2.getTitle().length()>0?o2.getTitle():" ").charAt(0);
return i1 - i2;
}
});
return list;
}
}
I've also tried the equivalent of "PrintWindow()" API...
Graphics g = form.CreateGraphics();
Bitmap bmp = new Bitmap(form.Size.Width, form.Size.Height, g);
Graphics memoryGraphics = Graphics.FromImage(bmp);
IntPtr dc = memoryGraphics.GetHdc();
bool success = PrintWindow(form.Handle, dc, 0);
memoryGraphics.ReleaseHdc(dc);
// bmp now contains the screenshot
Or do I have to use JNI, or any other tool?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个工作示例。
被捕获的应用程序无法最小化,但它不需要具有焦点或位于顶部(即可见)。
相关 C# 线程、MSDN 文章 中提供的代码捕获图像 和 jmemoryeditorw 提供了必要的部分。
该代码使用 GetDC 和 GetClientRect 来捕获窗口的客户区域。如果您想捕获包括窗口装饰在内的整个窗口,可以用 GetWindowDC 和 GetWindowRect 替换它们。
我必须定义一些未包含在 platform.jar 中的额外函数(可以在 JNA 网站上找到)。
Here's a working example.
The application being captured can't be minimized but it doesn't need to have focus or be on top (i.e. visible).
The code provided in the related C# thread, the MSDN article Capturing an Image and jmemoryeditorw provided the necessary pieces.
The code uses GetDC and GetClientRect to capture the client area of the window. They can be replaced by GetWindowDC and GetWindowRect if you want to capture the whole window including window decorations.
I had to define some extra functions that weren't included in platform.jar (which can be found on the JNA website).
使用java.awt.Robot.createScreenCapture()。
下面是一个示例:
代码最初是从此处窃取的。
Use
java.awt.Robot.createScreenCapture()
.Here's an example:
Code originally stolen from here.
对于你原来的问题,就这样吧。
在 Windows 中捕获非活动窗口非常简单,仅当窗口在捕获时可见时,才使用机器人类。 如果您想避免该要求,则必须使用 DWM API。
使用普通的 Windows API(Vista 之前的版本),您可以使用 GetWindowRect(handle,RECT),其中句柄是窗口的处理程序你想要捕捉。这将为您提供一个 RECT 对象(我假设您正在使用 JNA),这是您应该编写的代码序列:
但是!仅当您的窗口当前可见时,此功能才起作用。如果它被最小化,你会在java中得到一些异常(因为它有负的 x 和 y )。如果它部分隐藏,您还将截取其上方的其他窗口。
您无法在没有 dwm(桌面 Windows 管理器)的机器上解决问题,因为它有一个 API,允许不同的窗口在实际绘制到屏幕上之前写入临时缓冲区。
然而,在 XP 和未运行 DWM 的计算机上,您将不得不使用我给您的代码。
另外,您可以看看以下问题:
链接文本
编辑:
这是一个有趣的指南(虽然是 C# 语言,但您可以使用应用相同原理的 JNA+Java),它将让您更好地理解 DWM 以及如何使用它来完成您想要的事情。
链接文本
编辑编辑
刚刚看到您有一个指向我给您的 C# 指南的链接。仅仅重写 Java/JNA 代码似乎有什么问题?
编辑编辑编辑
为了回答您的附加问题(如何将 BitBit 转换为 BufferedImage ),这里有一个人在他的开源项目中做到了这一点。这是一件很棒的工作,值得他欣赏:
http://code.google.com/p /jmemoryeditorw/
您可能会注意到,如果您运行该程序,它将为您提供所有进程以及...它们的图标。 如果您深入研究代码,您将看到它们如何从 BitBit 转换为 BufferedImages。
干杯,我不得不说,这是一个非常好的问题。
For your original question, here it goes.
Capturing an inactive window in Windows is pretty straightforward, using the robot class, ONLY and ONLY if the window is visible at the moment of capturing. If you want to avoid that requirement, you HAVE to use the DWM API.
Using the normal Windows API (pre Vista), you can use GetWindowRect(handle,RECT) where handle is a handler to the window you want to capture. This will get you a RECT object (I assume you are using JNA), here is the sequence of code you should write:
However!! This will work as a charm ONLY if your window is currently visible. If it is minimized, you will get some exception in java (because it has negative x and y ). And if it is partially hidden, you will also screenshot the other windows that are on top of it.
You can't solve your problem on boxes that don't have dwm (Desktop Windows Manager) as it has an API that allows different windows to write to a temp buffer before they actually are painted to the screen.
On XP and non - running DWM machines, however, you are stuck with the code I gave you.
Additionally , you can take a look at the following question:
link text
Edit:
Here is an interesting guide (in C#, though, but you can use JNA+Java applying the same principles) that will give you a better understanding of the DWM and how to use it to do EXACTLY what you want.
link text
EditEdit
Just saw you have a link to the same guide in C# that I gave you. What seems to be the problem in just rewriting the code for Java/JNA?
EditEditEdit
To answer your additional question (how to convert your BitBit to a BufferedImage ), here is a guy who did it in his Open Source project. It is a nice piece of work and give him some appreciation:
http://code.google.com/p/jmemoryeditorw/
You might notice that if you run the program, it will give you all the processes and also...their Icons. If you dig in the code, you will see how they are converted from BitBit to BufferedImages.
Cheers and I have to say, a very nice question.