8 Stimmen

Bildschirmfoto mit OpenGL und/oder X11

Ich versuche, einen Screenshot des Bildschirms oder eines Fensters zu machen. Ich habe es mit Funktionen von X11 versucht und es funktioniert gut. Das Problem ist, dass das Abrufen der Pixel von XImage eine Menge Zeit in Anspruch nimmt. Dann habe ich versucht, einige Antworten zu finden, wie man es mit OpenGL machen kann. Hier ist, was ich bekommen habe:

#include <stdlib.h>
#include <stdio.h>
#include <cstdio>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>

int main(int argc, char **argv)
{

int width=1200;
int height=800; 
//_____________________________----
 Display *dpy;
  Window root;
  GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  XVisualInfo *vi;
  GLXContext glc;

  dpy = XOpenDisplay(NULL);

  if ( !dpy ) {
    printf("\n\tcannot connect to X server\n\n");
    exit(0);
  }

  root = DefaultRootWindow(dpy);
  vi = glXChooseVisual(dpy, 0, att);

  if (!vi) {
    printf("\n\tno appropriate visual found\n\n");
    exit(0);
  }

glXMakeCurrent(dpy, root, glc);
  glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);

  printf("vendor: %s\n", (const char*)glGetString(GL_VENDOR));

//____________________________________________
glXMakeCurrent(dpy, root, glc);

glEnable(GL_DEPTH_TEST); 
GLubyte* pixelBuffer = new GLubyte[sizeof(GLubyte)*width*height*3*3];

glReadBuffer(GL_FRONT); 

GLint ReadBuffer;
glGetIntegerv(GL_READ_BUFFER,&ReadBuffer);
glPixelStorei(GL_READ_BUFFER,GL_RGB);

GLint PackAlignment;
glGetIntegerv(GL_PACK_ALIGNMENT,&PackAlignment); 
glPixelStorei(GL_PACK_ALIGNMENT,1);

glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_INT, pixelBuffer);

int i;

for (i=0;i<100;i++) printf("%u\n",((unsigned int *)pixelBuffer)[i]);

return 0;
}

Wenn ich das Programm ausführe, dann X Error of failed request: BadAccess (Zugriffsversuch auf private Ressource verweigert) Haupt-Opcode der fehlgeschlagenen Anfrage: 199 () Minor o Laufende Nummer der fehlgeschlagenen Anforderung: 20 Aktuelle Seriennummer im Ausgabestrom: 20

wenn ich die Zeile mit glXMakeCurrent(dpy, Root, glc); before glc = glXCreateContext(dpy, vi, NULL, GL_TRUE); auskommentiere, gibt es keine Fehler, aber alle Pixel sind 0.

Wie sollte ich dieses Problem angehen? Ich bin neu in openGL und vielleicht übersehe ich etwas wichtiges hier. Vielleicht gibt es auch einen anderen Weg, um Pixel vom Bildschirm oder einem bestimmten Fenster zu erhalten?

8voto

Piotr Praszmo Punkte 17533

Ich glaube nicht, dass das, was Sie vorhaben, möglich ist. Sie können nicht OpenGL verwenden, um Pixel aus Fenstern zu lesen, die Sie nicht besitzen und die wahrscheinlich nicht einmal OpenGL verwenden. Sie müssen sich an X11 halten.

Wenn Sie eine XImage können Sie rohe Pixel von ximage->data . Vergewissern Sie sich nur, dass Sie sie im richtigen Format lesen.

http://tronche.com/gui/x/xlib/graphics/images.html

4voto

Christian Punkte 141

Sie können XShmGetImage verwenden, aber Sie müssen zuerst die Erweiterungen des X11-Servers abfragen, um sicherzustellen, dass die MIT-SHM-Erweiterung verfügbar ist. Außerdem müssen Sie wissen, wie Sie ein gemeinsames Speichersegment einrichten und verwenden können.

Abfrage der Erweiterung:

http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavdevice/x11grab.c#l224

Das Bild erhalten:

http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavdevice/x11grab.c#l537

0voto

étale-cohomology Punkte 1706

Das folgende läuft einmal mit 140 fps auf meiner Plattform. xcb_image_get() (aufgerufen mit XCB_IMAGE_FORMAT_Z_PIXMAP ) speichert alle Pixel in ximg->data Pixel für Pixel. Auf meiner Plattform ist jedes Pixel 32 Bits, jeder Kanal ist 8 Bits, und es gibt 3 Kanäle (bis 8 Bits pro Pixel sind ungenutzt).

/*
gcc ss.c -o ss -lxcb -lxcb-image && ./ss
*/

#include <stdio.h>
#include <xcb/xcb_image.h>

xcb_screen_t* xcb_get_screen(xcb_connection_t* connection){
  const xcb_setup_t* setup = xcb_get_setup(connection);  // I think we don't need to free/destroy this!
  return xcb_setup_roots_iterator(setup).data;
}

void xcb_image_print(xcb_image_t* ximg){
  printf("xcb_image_print()  Printing a (%u,%u) `xcb_image_t` of %u bytes\n\n", ximg->height, ximg->width, ximg->size);
  for(int i=0; i < ximg->size; i += 4){
    printf(" ");
    printf("%02x", ximg->data[i+3]);
    printf("%02x", ximg->data[i+2]);
    printf("%02x", ximg->data[i+1]);
    printf("%02x", ximg->data[i+0]);
  }
  puts("\n");
}

int main(){
  // Connect to the X server
  xcb_connection_t* connection = xcb_connect(NULL, NULL);
  xcb_screen_t* screen         = xcb_get_screen(connection);

  // Get pixels!
  xcb_image_t* ximg = xcb_image_get(connection, screen->root, 0, 0, screen->width_in_pixels, screen->height_in_pixels, 0xffffffff, XCB_IMAGE_FORMAT_Z_PIXMAP);
  // ... Now all pixels are in ximg->data!

  xcb_image_print(ximg);

  // Clean-up
  xcb_image_destroy(ximg);
  xcb_disconnect(connection);
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X