Как создать изображение XCB с шириной и высотой, отличными от подключенного окна?

#c #linux #x11 #xlib #xcb

Вопрос:

Я работаю с X11 XCB api.

Когда я пытаюсь создать окно и создать xcb_image_t структуру xcb_image_create_native , оно возвращается NULL , если только выделенный мной массив пикселей не имеет точно такого же размера, как массив пикселей для созданного мной окна.

Ниже приведен самый маленький пример, который я мог бы привести. Если я изменю все экземпляры «ширина» и «высота», чтобы они были равны «window_width» и «window_height», программа будет работать идеально, однако, если я изменю «ширину и высоту» на что-либо другое, xcb_image_create_native вернется NULL .

Я компилирую gcc и связываюсь с -lxcb -lxcb-image .

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

int main(void)
{
    
    // Just setting up the window
    int window_width = 480;
    int window_height = 480;
    xcb_connection_t *c = xcb_connect(NULL, NULL);
    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
    xcb_drawable_t window = screen->root;
    
    xcb_gcontext_t gcontext = xcb_generate_id(c);

    uint32_t gc_values[] = { screen->black_pixel, 1};
    uint32_t gc_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
    xcb_create_gc(c,
            gcontext,
            window,
            gc_mask,
            gc_values);

    window = xcb_generate_id(c);
    uint32_t window_values[] = { screen->white_pixel, XCB_EVENT_MASK_EXPOSURE };
    uint32_t window_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;

    xcb_create_window(c,
            XCB_COPY_FROM_PARENT,
            window,
            screen->root,
            0,
            0,
            window_width,
            window_height,
            10,
            XCB_WINDOW_CLASS_INPUT_OUTPUT,
            screen->root_visual,
            window_mask,
            window_values);
    
    xcb_map_window(c, window);
    
    int byte_depth = screen->root_depth/8;
    int width = 50;
    int height = 50;
    int bytes = byte_depth * width * height;
    
    // The part that messes up.
    void *base = malloc(bytes);
    uint8_t *data = (uint8_t *)base;

    // This function always returns NULL unless width amp; height are the same as window_width amp; window height
    xcb_image_t *image = xcb_image_create_native(c,
                            width,
                            height,
                            XCB_IMAGE_FORMAT_XY_PIXMAP,
                            screen->root_depth,
                            base,
                            bytes,
                            data);
    if (!image)
    {
        fprintf(stderr, "No imagen");
    }
    else
    {
        xcb_image_put(c,
                window,
                gcontext,
                image,
                0, 0,
                0);
    }
    sleep(2);
    return 0;
}

 

Возможно ли вообще создать изображение XCB с размером, отличным от размера окна? И если да, то что я делаю не так?

Я также попытался выяснить, что происходит не так, посмотрев исходный код xcb_image.c, и хотя я смог разобраться в основах происходящего, я не понимаю этого достаточно, чтобы понять, как это работает таким образом.

https://opensource.apple.com/source/X11libs/X11libs-60/xcb-util/xcb-util-0.3.6/image/xcb_image.c.auto.html
https://code.woboq.org/qt5/include/xcb/xcb_image.h.html

Я действительно ценю любую помощь.

Ответ №1:

Вы уверены, что выделяете достаточно байтов? Как правило, в библиотеке изображений начало линий сканирования должно быть выровнено по 32-битной границе. Это означает, что если длина (в байтах) строки сканирования не делится на 4, вам необходимо добавить заполнение.

Глядя на исходный код xcb, похоже, что xcb_image требуется достаточно места, чтобы чередовать пиксели в один бит на линию сканирования, а затем добавлять отступы для правильного выравнивания.

Это немного усложняет вычисления размера, но приводит к тому, что 24-битное изображение размером 480×480 не требует заполнения, а 24-битное изображение размером 50×50 требует в общей сложности 2100 байт заполнения.

К счастью, чтобы избежать всего этого, вы можете позволить xcb выделить правильный размер для данных изображения. Просто позвони xcb_image_create_native с base=NULL , bytes=0 и data=NULL . Затем вы можете найти указатель на выделенные данные изображения в image->data

Не забудьте позвонить xcb_image_destroy(image) , когда закончите. Это будет free как image->data и image