libx11 не может сделать снимок экрана в Fedora OS C - PullRequest
0 голосов
/ 18 июня 2019

Я не специалист по программированию на C и разработке ОС Linux, но у меня есть задача сделать скриншоты в Ubuntu и Fedora OS. После поиска в интернете я нашел много тем и вопросов о том, как это сделать с использованием языка Си и libX11. Наконец, я объединил все, что смог найти в одном методе, который делает снимок экрана и сохраняет его в файле .png.
У меня установлено две виртуальные машины - одна Ubuntu 18.04, вторая Fedora 30. Когда я запускаю свой код в Ubuntu - он отлично работает, когда я запускаю его в Fedora - у меня есть файл скриншота с черным содержимым. Мой код:

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <stdlib.h>

    int get_shift (int mask) {
        int shift = 0;
        while (mask) {
            if (mask & 1) break;
            shift++;
            mask >>=1;
        }
        return shift;
    }

   void takeScreenshot() {
    Display *d;
    int s;
    XImage *image;
    XShmSegmentInfo shminfo;
    d = XOpenDisplay(NULL);
    s = DefaultScreen(d);
    unsigned int width = DisplayWidth(d,s);
    unsigned int height = DisplayHeight(d,s);


    image = XShmCreateImage(d, 
        DefaultVisual(d,s), // Use a correct visual. Omitted for brevity     
        24,   // Determine correct depth from the visual. Omitted for brevity
        ZPixmap, NULL, &shminfo, width, height); 

    shminfo.shmid = shmget(IPC_PRIVATE,
        image->bytes_per_line * image->height,
        IPC_CREAT|0777);

    shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
    shminfo.readOnly = False;

    XShmAttach(d, &shminfo);

    XShmGetImage(d,
        RootWindow(d,s),
        image,
        0,
        0,
        AllPlanes);


    cairo_surface_t *surface;
    int stride;

    stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width);
    unsigned char *data = malloc(stride * height);

    int redShift = get_shift(image->red_mask);
    int greenShift = get_shift(image->green_mask);
    int blueShift = get_shift(image->blue_mask);

    printf("r_shift: %d; g_shift: %d; b_shift: %d\n",redShift, greenShift, blueShift);
    printf("byte order: %d\n", image->byte_order);
    printf("bytes per line: %d\n", image->bytes_per_line);
    printf("bites per pixel: %d\n", image->bits_per_pixel);
    printf("r_mask: %lu; g_mask: %lu; b_mask: %lu\n", image->red_mask, image->green_mask, image->blue_mask);
    printf("bitmap_bit_order: %d  bitmap_pad: %d format: %d xoffset: %d\n", image->bitmap_bit_order, image->bitmap_pad, image->format, image->xoffset);

    int x, y;
     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)>>redShift;
            unsigned char green = (image->green_mask & pixel)>>greenShift;
            unsigned char blue = (image->blue_mask & pixel)>>blueShift;

            data[y * stride + x * 4 + 0] = blue;
            data[y * stride + x * 4 + 1] = green;
            data[y * stride + x * 4 + 2] = red;   
        }
    }

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

    cairo_status_t surfaceStatus = cairo_surface_status(surface);

   const char *r = cairo_status_to_string (surfaceStatus);
   printf("%s\n", &r[0]);

    int writepngRes = cairo_surface_write_to_png(
                surface,
                "test.png");

    printf("surf status: %d; write result: %d\n", surfaceStatus, writepngRes);
    cairo_surface_destroy(surface);
}


    int main(int argc, char* argv[]) {
        takeScreenshot();
        return 0;
    }

И я строю этот код, используя следующую команду:
gcc code.c -o code.so -lXss -lX11 -lXext -fPIC -I/usr/include/cairo -lcairo

Настройка одинакова на обеих машинах, и я проверил, что битовая маска, порядок байтов и количество байтов на пиксель одинаковы для обеих систем. Я прошу предложения о том, как найти причину ошибки, может быть, совет, что отладить. Спасибо!
UPDATE:
Когда я запускаю этот код на обеих платформах, я вижу точно такой же вывод:

r_shift: 16; g_shift: 8; b_shift: 0
byte order: 0
bytes per line: 5464
bites per pixel: 32
r_mask: 16711680; g_mask: 65280; b_mask: 255
bitmap_bit_order: 0  bitmap_pad: 32 format: 2 xoffset: 0
no error has occurred
surf status: 0; write result: 0
...