【问题标题】:Making a screenshot using Xlib and Cairo libs [fail]使用 Xlib 和 Cairo 库制作屏幕截图 [失败]
【发布时间】:2013-03-19 18:37:02
【问题描述】:

我正在尝试使用 Xlib 和 Cairo 制作屏幕截图,但我不确定这样做是否好,“stride”真的让我很困惑.

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <cairo.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

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

    int x, y;

    Display *disp;
    Window root;
    XWindowAttributes watts;
    XImage *image;
    cairo_surface_t *surface;
    unsigned int width;
    unsigned int height;
    int stride;

    disp = XOpenDisplay(NULL);
    root = DefaultRootWindow(disp);
    XGetWindowAttributes(disp, root, &watts);
    width = watts.width;
    height = watts.height;

    image = XGetImage(disp, root, watts.x, watts.y, width, height, AllPlanes, ZPixmap);
    stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width);
    unsigned char *data = malloc(width * height * 3);

    for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x) {

            unsigned long pixel = XGetPixel(image, x, y);

            unsigned char red = (image->red_mask & pixel);
            unsigned char green = (image->green_mask & pixel) >> 8;
            unsigned char blue = (image->blue_mask & pixel) >> 16;

            data[(y * width + x) * 3] = red;
            data[(y * width + x) * 3 + 1] = green;
            data[(y * width + x) * 3 + 2] = blue;
        }


    surface = cairo_image_surface_create_for_data(
            data,
            CAIRO_FORMAT_RGB24,
            width, height,
            stride);

    cairo_surface_write_to_png(
            surface,
            "test.png");


    cairo_surface_destroy(surface);
    free(data);

    return (EXIT_SUCCESS);
}

当我编译并运行程序时,一切似乎都运行良好。然而,这是生成的图像:

一团糟对吗? 我可能做错了什么?

【问题讨论】:

    标签: png screenshot x11 cairo xlib


    【解决方案1】:

    与其做所有这些复杂的魔法,不如让 cairo 为你做:

    #include <cairo.h>
    #include <cairo-xlib.h>
    #include <X11/Xlib.h>
    
    int main(int argc, char** argv) {
        Display *disp;
        Window root;
        cairo_surface_t *surface;
        int scr;
    
        disp = XOpenDisplay(NULL);
        scr = DefaultScreen(disp);
        root = DefaultRootWindow(disp);
    
        surface = cairo_xlib_surface_create(disp, root, DefaultVisual(disp, scr),
                DisplayWidth(disp, scr), DisplayHeight(disp, scr));
        cairo_surface_write_to_png(
                surface,
                "test.png");
        cairo_surface_destroy(surface);
    
        return 0;
    }
    

    【讨论】:

    • 非常感谢这个答案,我打算把我的代码改成这个,似乎更容易一些。
    • 嗨@Uli。我发现您的评论对于我正在部署的概念证明非常有用。您能否指出我需要链接到您的代码并获得可执行文件的库?谢谢
    • 使用 pkg-config: pkg-config --libs --cflags cairo x11
    【解决方案2】:

    TFM:

    CAIRO_FORMAT_RGB24
        each pixel is a 32-bit quantity, with the upper 8 bits unused
    

    TFM:

    stride = cairo_format_stride_for_width (format, width);
    data = malloc (stride * height);
    

    因此,正确的指数计算是

    data[y * stride + x * 4 + 0] = blue;
    data[y * stride + x * 4 + 1] = green;
    data[y * stride + x * 4 + 2] = red;    /* yes, in this order */
    

    此外,蒙版是从图像中提取的,而移位是硬编码的,这完全没有意义。计算掩码的偏移量。

    【讨论】:

    • 您应该使用不同的索引计算,因为像素大小是 32 位而不是 24。请参阅更新。
    • 那是因为您没有使用正确的班次,和/或使用了错误的 R、G 和 B 顺序。
    • 您应该计算正确的指针,将其转换为 uint32_t* 并执行 *p = red
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多