这是一个更大的研究项目的子项目。我试图每隔100ms拍摄一个活动窗口(浏览器)的屏幕截图,然后将其存储在内存中以供OpenCV处理。我从类似的问题中找到了截取屏幕截图的解决方案,我正在使用代码来查看是否可以使用它。在拍摄整个桌面截图或特定的窗口截图时,以下代码段似乎正在工作,但它不适用于GTK窗口。我试图截取Iceweasel& amp; Debian Squeeze上的Nautilus,它根本不起作用。我是X11中的总菜鸟,并且不知道如何检查错误,或者我是否缺少GTK,因为这似乎适用于QT窗口。
typedef int (*handler)(Display *, XErrorEvent *);
int handleX11Error(Display *d, XErrorEvent *er)
{
std::cout << "X11 Error: " << er->error_code << std::endl;
}
int main()
{
std::cout << "Sleeping 5 seconds" << std::endl;
// we may need to sleep if we want to focus another window.
sleep(5);
std::cout << "taking screenshot" << std::endl;
Display *display = XOpenDisplay(NULL);
//Window root = DefaultRootWindow(display);
XWindowAttributes gwa;
int revert = RevertToNone;
Window active;
XErrorEvent *error;
handler myHandler = &handleX11Error;
XSetErrorHandler(myHandler);
// X11 - Get Window that has focus
XGetInputFocus(display,&active,&revert);
//XGetWindowAttributes(display, root, &gwa);
if (!XGetWindowAttributes(display, active, &gwa))
std::cout << "XGetWindowAttributes failed" << std::endl;
int width = gwa.width;
int height = gwa.height;
//XImage *image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap);
XImage *image = XGetImage(display,active, 0,0 , width,height,XAllPlanes(), ZPixmap);
unsigned char *array = new unsigned char[width * height * 3];
CImg<unsigned char> pic(array,width,height,1,3);
for (int x = 0; x < width; x++){
for (int y = 0; y < height ; y++){
pic(x,y,0) = (XGetPixel(image,x,y) & image->red_mask ) >> 16;
pic(x,y,1) = (XGetPixel(image,x,y) & image->green_mask ) >> 8;
pic(x,y,2) = XGetPixel(image,x,y) & image->blue_mask;
}
}
delete[] array;
pic.save_png("blah.png");
std::cout << "Finished" << std::endl;
return 0;
}
以上代码适用于完整的桌面屏幕截图或QT。我没有得到任何错误(不知道我是否正确处理它们)。只是几个字节的空白图片,这让我觉得其中一个X函数失败了(XGetInputFocus,XGetWindowAttributes,XGetImage),我对XGetFocus的赌注没有正常工作。 我错过了什么,或者,有替代方案吗? 请注意,如果它有任何重要性,我正在运行KDE(4.4.5)。
更新:
我尝试使用Qt4截取屏幕截图,虽然它工作正常,但在尝试从X11获取焦点窗口时会遇到同样的问题:
int main(int argc, char **argv)
{
sleep(5);
Display *display = XOpenDisplay(NULL);
int revert = RevertToNone;
Window active;
XGetInputFocus(display,&active,&revert);
QApplication app(argc, argv);
QPixmap pixmap = QPixmap::grabWindow(active);
pixmap.save("test.png","PNG");
QPushButton quit("Quit");
quit.resize(75, 30);
quit.setFont(QFont("Times", 18, QFont::Bold));
QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));
quit.show();
return app.exec();
}
因此我确信,XGetInputFocus()以某种方式失败了。
答案 0 :(得分:7)
由于我还没有得到任何答案,并且我已经花了一整天的时间寻找解决方案,我想我会分享我是如何设法让这个工作的。 该系统是Debian Squeeze,运行KDE 4.4.5。 显然,KDE和GTK应用程序不能很好地相互配合。一般来说,在stackoverflow和互联网上引用其他帖子中的人,非kde应用程序可能不会尊重_NET_WM_STATE,或者它可能是其他的东西,我真的不知道。但是我尝试过的GTK应用程序无法使用所有Qt4应用程序所使用的代码,这暗示了与某种形式的报告相关的问题。在网络上发现了一些罕见的(我真的很少见)解决方案,可能会遍历X11窗口树以找到活动窗口,但这对我来说似乎太复杂了,而且我读到了人们没有获得成功结果的帖子。 我想出的是(在网上找到的片段片段)如下使用xdo(Debian上的libxdo):
Display *display = XOpenDisplay(NULL);
Window active;
XWindowAttributes gwa;
// Use xdo to find the active window - care on the display !
xdo_t* xdocontext = xdo_new(0);
xdo_window_get_active(xdocontext, &active);
if(active){
XGetWindowAttributes(display, active, &gwa);
XImage *image = XGetImage(display,active, 0,0 , gwa.width,gwa.height,XAllPlanes(), ZPixmap);
unsigned char *array = new unsigned char[gwa.width * gwa.height * 3];
CImg<unsigned char> pic(array,gwa.width,gwa.height,1,3);
for (int x = 0; x < gwa.width; x++){
for (int y = 0; y < gwa.height ; y++){
pic(x,y,0) = (XGetPixel(image,x,y) & image->red_mask ) >> 16;
pic(x,y,1) = (XGetPixel(image,x,y) & image->green_mask ) >> 8;
pic(x,y,2) = XGetPixel(image,x,y) & image->blue_mask;
}
}
delete[] array;
pic.save_png("blah.png");
} else std::cout << "xdo failed to get active window" << std::endl;
以上适用于GTK&amp; KDE应用程序,我真的希望它可以帮助有人坚持这个,因为这个帖子似乎很少。