5

これは、はるかに大きな研究プロジェクトのサブプロジェクトです。アクティブなウィンドウ (ブラウザー) のスクリーンショットを 100 ミリ秒ごとに取得しようとしています。これは、OpenCV 処理のためにメモリに保存されます。同様の質問からスクリーンショットを撮る解決策を見つけました。現在、コードを使用して使用できるかどうかを確認しています。次のスニペットは、デスクトップ全体のスクリーンショットまたは特定のウィンドウのスクリーンショットを撮るときに機能しているようですが、GTK ウィンドウでは機能しません。Debian Squeeze で Iceweasel と 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 GetFocus への賭けが適切に機能していないため、X 関数の 1 つ (XGetInputFocus、XGetWindowAttributes、XGetImage) が失敗したと思われます。私が見逃しているのは何ですか、またはこれに代わるものはありますか? 重要な場合は、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() であると確信しています。

4

1 に答える 1

7

私はまだ何の答えも得ていないので、一日の大半を解決策を探すのに費やしているので、どうやってこれを機能させることができたかを共有したいと思っていました. システムは KDE 4.4.5 を実行する Debian Squeeze です。どうやら 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およびKDEアプリで動作します。これに関する投稿はほとんどないように思われるため、誰かがこれで立ち往生するのを助けることができることを本当に願っています.

于 2012-11-30T20:53:44.753 に答える