Xlib 应用被覆盖遮挡或者移出屏幕时,获取窗口截图
Posted 柴承训
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xlib 应用被覆盖遮挡或者移出屏幕时,获取窗口截图相关的知识,希望对你有一定的参考价值。
在https://www.cnblogs.com/chaichengxun/p/15409996.html这篇文章里已经讲过,如果应用窗口位于屏幕外或者被遮挡,xlib不能获取完整的应用窗口截屏,如下
今天就拉解决这个问题。
用到的头文件:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
用到的库:
-lXlib -lXcomposite -lXrender
代码:
static Display *xdisplay = 0; Display *disp() { if (!xdisplay) xdisplay = XOpenDisplay(NULL); return xdisplay; } XImage* GetDrawableThumbnail(Drawable src_drawable, Visual* visual, int src_width, int src_height) { XRenderPictFormat* format = XRenderFindVisualFormat(disp(), visual); if (!format) { cout <<"XRenderFindVisualFormat() failed"; return NULL; } XRenderPictureAttributes pa; pa.subwindow_mode = IncludeInferiors; Picture src = XRenderCreatePicture(disp(), src_drawable, format, CPSubwindowMode, &pa); if (!src) { cout << "XRenderCreatePicture() failed"; return NULL; } Pixmap dst_pixmap = XCreatePixmap(disp(), src_drawable, src_width, src_height, format->depth); if (!dst_pixmap) { cout << "XCreatePixmap() failed"; XRenderFreePicture(disp(), src); return NULL; } Picture dst = XRenderCreatePicture(disp(), dst_pixmap, format, 0, NULL); if (!dst) { cout << "XRenderCreatePicture() failed"; XFreePixmap(disp(), dst_pixmap); XRenderFreePicture(disp(), src); return NULL; } XRenderColor transparent = {0}; XRenderFillRectangle(disp(), PictOpSrc, dst, &transparent, 0, 0, src_width, src_height); XTransform xform = { { { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0) }, { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0) }, { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(1) } } }; XRenderSetPictureTransform(disp(), src, &xform); XRenderSetPictureFilter(disp(), src, FilterBest, NULL, 0); XRenderComposite(disp(), PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, src_width, src_height); XImage* image = XGetImage(disp(), dst_pixmap, 0, 0, src_width, src_height, AllPlanes, ZPixmap); return image; }
将XImage转换成QPixmap:
void AppListSelDlg::GetPixmap(unsigned long win, QPixmap &pixmap) { Display *display_ = disp(); XCompositeRedirectWindow(display_, win, CompositeRedirectAutomatic); Pixmap src_pixmap = XCompositeNameWindowPixmap(display_, win); if (!src_pixmap) { printf("XCompositeNameWindowPixmap() failed"); return; } XWindowAttributes attr; if (!XGetWindowAttributes(display_, win, &attr)) { printf( "XGetWindowAttributes() failed"); XFreePixmap(display_, src_pixmap); return ; } XImage* pImage = XCompcap::GetDrawableThumbnail(src_pixmap, attr.visual, attr.width, attr.height); QImage image = QImage((const uchar *)(pImage->data), pImage->width, pImage->height, pImage->bytes_per_line, QImage::Format_RGB32); pixmap = QPixmap::fromImage(image); XDestroyImage(pImage); XFreePixmap(display_, src_pixmap); }
是否可以检测窗口遮挡
使用AWT,我想通过在隐藏窗口时停止绘制到屏幕来保存像flash一样的资源。但首先,我需要一种方法来检测Frame是否被一个或多个其他窗口完全覆盖。 Windows可能不是来自同一个应用程序,所以我不能只是总结他们的形状。
所以问题是,是否可以检测窗口是否被其他应用程序的其他窗口覆盖?
答案
一切皆有可能只需要一些创造力和努力工作:)
我希望你知道Java可以调用本机Windows API(这不是非常高性能的vise,但我们只有这种方式),为此我们可以使用JNA lib,这将使我们能够访问本机共享库。
我已经做了一些快速的概念检查,这个代码只检查活动窗口是否完全覆盖了java应用程序窗口,但是你可以迭代可见窗口并计算区域,JNA也提供了访问权限。
对于我的演示项目,我使用了这些JNA依赖项:
compile("net.java.dev.jna", "jna", "4.5.0")
compile("net.java.dev.jna", "jna-platform", "4.5.0")
我的主要课程:
package com.sauliuxx.inc;
import com.sauliuxx.inc.workers.ActiveWindowChecker;
import com.sun.jna.platform.win32.WinDef;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* The type App.
*/
public class App extends Frame implements ActionListener {
private final String title = "Demo123";
private Label sizeLabel;
private Label positionLabel;
private Label visibleLabel;
BlockingQueue<WinDef.RECT> q =
new LinkedBlockingQueue<>();
private App() {
this.setTitle(title);
this.setLayout(new BorderLayout());
this.setSize(500, 500);
Panel infoPanel = new Panel();
sizeLabel = new Label(this.getSize().height + " X " + this.getSize().width);
infoPanel.add(sizeLabel);
positionLabel = new Label("X: " + this.getLocation().getX() + " Y: " + this.getLocation().getY());
infoPanel.add(positionLabel);
visibleLabel = new Label(this.isVisible() ? "true" : "false");
infoPanel.add(visibleLabel);
this.add(infoPanel, BorderLayout.PAGE_END);
Timer timer = new Timer(250, this);
timer.start();
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.addComponentListener(new ComponentListener() {
@Override
public void componentResized(ComponentEvent componentEvent) {
sizeLabel.setText(componentEvent.getComponent().getSize().height + " X " + componentEvent.getComponent().getSize().width);
}
@Override
public void componentMoved(ComponentEvent componentEvent) {
positionLabel.setText("X: " + componentEvent.getComponent().getLocation().getX() + " Y: " + componentEvent.getComponent().getLocation().getY());
}
@Override
public void componentShown(ComponentEvent componentEvent) {
visibleLabel.setText("true");
}
@Override
public void componentHidden(ComponentEvent componentEvent) {
visibleLabel.setText("false");
}
});
ActiveWindowChecker awcDeamon = new ActiveWindowChecker(q);
awcDeamon.setDaemon(true);
awcDeamon.start();
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
WinDef.RECT rect = null;
try {
rect = q.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (this.isActive()) {
System.out.println("action");
} else {
//System.out.println("rect = " + (rect != null ? rect : ""));
//System.out.println("frame = [(" + (int)this.getLocation().getX() + "," + (int)this.getLocation().getY() + ") (" + this.getSize().width + "," + this.getSize().height + ")]");
// x and y windows to compare top left point
int rxTop = rect == null ? 0: rect.left;
int ryTop = rect == null ? 0:rect.top;
int fxTop = (int) this.getLocation().getX();
int fyTop = (int) this.getLocation().getY();
// bottom right points
int rxBottom = rect == null ? 0: rect.right;
int ryBottom = rect == null ? 0: rect.bottom;
int fxBottom = fxTop + this.getSize().width;
int fyBottom = fyTop + this.getSize().height;
if ((rxTop >= fxTop || ryTop >= fyTop) || (rxBottom <= fxBottom || ryBottom <= fyBottom))
{
System.out.println("Not covered by active window.");
}
else{
System.out.println("Covered by active window.");
}
}
}
/**
* The entry point of application.
*
* @param args the input arguments
*/
public static void main(String... args) {
if (!System.getProperty("os.name").contains("Windows")) {
System.err.println("ERROR: Only implemented on Windows");
System.exit(1);
}
java.awt.EventQueue.invokeLater(() -> new App().setVisible(true));
}
}
我的工人班:
package com.sauliuxx.inc.workers;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import java.util.concurrent.BlockingQueue;
/**
* The type Active window checker.
*/
public class ActiveWindowChecker extends Thread {
private static final int MAX_TITLE_LENGTH = 1024;
private final BlockingQueue<WinDef.RECT> queue;
/**
* Instantiates a new Active window checker.
*
* @param q the q
*/
public ActiveWindowChecker(BlockingQueue<WinDef.RECT> q) {
this.queue = q;
}
@Override
public void run() {
Exception ex = null;
while (ex == null) {
char[] buffer = new char[MAX_TITLE_LENGTH * 2];
WinDef.HWND hwnd = User32.INSTANCE.GetForegroundWindow();
User32.INSTANCE.GetWindowText(hwnd, buffer, MAX_TITLE_LENGTH);
System.out.println("Active window title: " + Native.toString(buffer));
WinDef.RECT rect = new WinDef.RECT();
User32.INSTANCE.GetWindowRect(hwnd, rect);
try {
queue.put(rect);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
ex = e;
}
}
}
}
以上是关于Xlib 应用被覆盖遮挡或者移出屏幕时,获取窗口截图的主要内容,如果未能解决你的问题,请参考以下文章