35

This question is similar to this one

Fastest method of screen capturing

but for linux/X11.

To be more specific, i need a method to capture the pixel images of one window (the programmatic equivalent of alt-print screen in windows) running on a X11 diplay.

Notes and requirements:

1) Even if a new window is placed on top of the window that is being captured, the pixel image should still point to the original application window without any occlusion

2) it is not needed that the application window to be seen by the user, i just need to store the pixel buffers/images for video purposes

other alternatives that i've explored are:

1) xvfb - it works but it does does CPU rendering, which is slow and wasteful of a good GPU

2) x11 inside many lxc - theoretically could work but is complex to setup, and i'm not sure it will scale well with many windows being captured

suggestions and ideas are welcome

Community
  • 1
  • 1
lurscher
  • 25,930
  • 29
  • 122
  • 185
  • 2
    if the window is covered, what you read is undefined. – BЈовић Nov 20 '12 at 19:22
  • 2
    Yes, CPU rendering is slow and wasteful, but is that performance unacceptably slow? Also, depending on the window manager you are using, if it is a compositing window manager you could look for a wm-specific API that could give you a pointer to an applications off-screen buffer. All that you have to do then is make a copy of the buffer before the application redraws itself. – Robert Mason Nov 20 '12 at 20:14
  • @RobertMason, that would work, and it would definitely constitute a valid answer if someone could suggest a window manager that 1) supports GPU acceleration rendering (i know zilch about x11 architecture, but i suppose that is done through extensions) and 2) supports that specific kind of API – lurscher Nov 20 '12 at 21:13
  • @RobertMason, the performance (of running apps inside xvfb) is not unacceptably slow, is just slow enough so that spending time looking for alternatives is worthwhile – lurscher Nov 20 '12 at 21:18
  • you can use wmctrl or xdotool to activate a window if that is acceptable, also xwininfo is useful for getting the window id for xwd (if you use xwd output it to > name.xwd and some image programs will be able to open it natively) – technosaurus Nov 29 '12 at 04:07
  • I wonder if an X11 solution would be best, since future Linux versions may not include it?: http://www.h-online.com/open/news/item/Ubuntu-to-abandon-X11-1131920.html – NoBugs Nov 29 '12 at 14:59

8 Answers8

11

This is possible using VirtualGL in a server with hardware acceleration. Basically just configure the server appropiately, then either on the same machine or on a machine in the same network, run

export DISPLAY=<your xvfb display>
vglrun <your_app>

This will have the following advantages:

1) your app will render using virtualGL, which will use the hardware

2) VirtualGL will display your 3D context inside the Xfvb display, which will only render the 2D widgets in CPU

3) configure Xvfb to render to a framebuffer

4) profit!

diffeomorphism
  • 991
  • 2
  • 10
  • 27
8

This is not possible with pure X11.

You can get what you want with compositing, but only on servers which support it (most modern ones do). This actually has nothing to do with window managers. A WM is just another client, albeit with some special abilities, but those are unrelated to compositing. You can use the same compositing API.

man xcomposite should get you started.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 1
    i've asked this on the compiz mailing list, but they don't think there is much point in doing it from the composite manager: http://lists.compiz.org/pipermail/dev/2012-November/thread.html#1545 i'll review xcompòsite and see where that leads – lurscher Nov 22 '12 at 19:34
  • 1
    Well, they seem to say more or less the same I'm saying, only in more detail. The code snippet uses functions from `xcomposite`. – n. m. could be an AI Nov 22 '12 at 19:52
5

I've seen comments saying this can't be done in X11 so there may be something I don't understand but i am able to capture my screen using the following code.

#include <X11/Xlib.h> //-lX11
#include <X11/Xutil.h>
#include <X11/Xmd.h> 
#include <X11/Xatom.h>
#include <jpeglib.h> //-ljpeg 

void CopyDesktopImage(std::string sFilePath_Name)
{  
    Display *dis=XOpenDisplay((char *)0);
    Screen *scr = XDefaultScreenOfDisplay(dis);
    Drawable drawable = XDefaultRootWindow(dis);

    XImage *image = XGetImage(dis, drawable, 0, 0, scr->width, scr->height, AllPlanes, ZPixmap);
    Save_XImage_to_JPG(image, sFilePath_Name.c_str(), 75);
    XDestroyImage(image);

    XCloseDisplay(dis); 
}

void Save_XImage_to_JPG(XImage *image, std::string FileName, int Quality)
{
    FILE* outfile = fopen(FileName.c_str(), "wb");
    if(outfile == NULL) return;

    jpeg_compress_struct cinfo;
    jpeg_error_mgr       jerr;

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width      = image->width;
    cinfo.image_height     = image->height;
    cinfo.input_components = image->bitmap_unit >> 3;
    cinfo.in_color_space   = JCS_EXT_BGRX;

    jpeg_set_defaults(&cinfo);
    /*set the quality [0..100]  */
    jpeg_set_quality(&cinfo, Quality, true);
    jpeg_start_compress(&cinfo, true);

    JSAMPROW row_pointer;          /* pointer to a single row */

    while (cinfo.next_scanline < cinfo.image_height) 
    {
        row_pointer = (JSAMPROW) &image->data[cinfo.next_scanline*image->bytes_per_line];
        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);

    fclose(outfile);
}
AtomClock
  • 96
  • 1
  • 6
  • You need to `#include ` and you need to place `#include ` before `#include `. It would help to post a fully working program, including the command to compile it. When I tried, it gives the error `undefined reference to `jpeg_std_error'` and there are plenty of other undefined reference errors. – Nav Oct 13 '22 at 14:43
3

You can use xwd(1) to dump a X11 window (and xwud(1) to display it). ImageMagick and the Netpbm tools know how to deal with the XWD format. But these are not especially fast. And they will not reveal hidden portions of a window.

kmkaplan
  • 18,655
  • 4
  • 51
  • 65
1

I'd grab the sources for gnome-screenshot, or some other existing open-source tool, and figure out how they do it.

You can find the sources Ubuntu uses here: http://packages.ubuntu.com/quantal/gnome-screenshot

But, don't forget to check the license before you cut and paste large sections of code!

ams
  • 24,923
  • 4
  • 54
  • 75
1

This is just a wild guess, but I presume you could use x11vnc with the -id [windowid] (http://www.karlrunge.com/x11vnc/x11vnc_opts.html#opt-id) option to stream that single window over VNC. This will show you the whole window, with the exact same positioning as in the main screen (you might lose some popup menus), even when it is covered. You can fetch the window coordinates from the true X11 screen.

vhdirk
  • 598
  • 1
  • 4
  • 12
0

Xpaint is a very old X11 utility built using the MIT Athena widget set. File > Take Snapshot will grab a window or mouse-selected rectangle from screen.

OR

MagiCapture is a screen capture and preview utility for the X Window System. A user may capture a single window, a single window with decorations, a rectangular region of the display, or the entire display itself. The user may save the captured image into a graphics file supported by the ImageMagick toolkit, which supports most (if not all) popular graphics formats. MagiCapture uses the GLIB and GTK+ libraries for the user interface and the ImageMagick and GdkMagick library for all graphics processing. Requires ImageMagick.

OR

Zscreen:- This Windows-only screen capture app has tons of features. It grabs a shot of the active window, a selected window, or the entire screen. Once you've got the image, automatically open it in your image editor or upload it to Twitpic, YFrog, Flickr, or one of several other supported services. ZScreen caches all your images, even ones on the clipboard, so there's always a history of your screenshots right at your fingertips.

Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
0

What you can do with a tricky hack in your local network is using the X remote capability open your X listen port and then using env var to set the export to X listen port then using XscreenCapture

AvengerMoJo
  • 118
  • 6