Подтвердить что ты не робот

Как загрузить 32-разрядное изображение на серверную pixmap

Я пытаюсь создать растровую карту RGBA на стороне сервера из клиентского буфера. CreatePixmap и CreateImage работают нормально для 32 и 24 бит, но XPutImage приводит к ошибке совпадения, возвращаемой сервером

X Error of failed request:  BadMatch (invalid parameter attributes)
  Major opcode of failed request:  72 (X_PutImage)
  Serial number of failed request:  8
  Current serial number in output stream:  8

сервер поддерживает 32-разрядные pixmaps (вывод xdpyinfo: https://gist.github.com/2582961). Такое же поведение на ubuntu 12.04 (версия X.Org: 1.11.3) и OSX с X.app(версия X.Org: 1.10.3)

Почему следующий код не работает?

#include     <stdlib.h>
#include     <X11/Xlib.h>

int main(int argc, char **argv)
{
    int width = 100;
    int height = 100;
    int depth = 32; // works fine with depth = 24
    int bitmap_pad = 32; // 32 for 24 and 32 bpp, 16, for 15&16
    int bytes_per_line = 0; // number of bytes in the client image between the start of one scanline and the start of the next
    Display *display=XOpenDisplay(0);
    unsigned char *image32=(unsigned char *)malloc(width*height*4);
    XImage *img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, image32, width, height, bitmap_pad, bytes_per_line);
    Pixmap p = XCreatePixmap(display, XDefaultRootWindow(display), width, height, depth);
    XPutImage(display, p, DefaultGC(display, 0), img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
    XEvent ev;
    while (1) {
       XNextEvent(display, &ev);
    }
}

Обновление: Похоже, что я наконец получил ответ: используйте GC, связанный с pixmap вместо DefaultGC (который имеет глубину корневого окна)

#include     <stdlib.h>
#include     <X11/Xlib.h>

int main(int argc, char **argv)
{
    int width = 100;
    int height = 100;
    int depth = 32; // works fine with depth = 24
    int bitmap_pad = 32; // 32 for 24 and 32 bpp, 16, for 15&16
    int bytes_per_line = 0; // number of bytes in the client image between the start of one scanline and the start of the next
    Display *display=XOpenDisplay(0);
    unsigned char *image32=(unsigned char *)malloc(width*height*4);
    XImage *img = XCreateImage(display, CopyFromParent, depth, ZPixmap, 0, image32, width, height, bitmap_pad, bytes_per_line);
    Pixmap p = XCreatePixmap(display, XDefaultRootWindow(display), width, height, depth);
    XGCValues gcvalues;
    GC gc = XCreateGC(display, p, 0, &gcvalues);
    XPutImage(display, p, gc, img, 0, 0, 0, 0, width, height); // 0, 0, 0, 0 are src x,y and dst x,y
    XEvent ev;
    while (1) {
       XNextEvent(display, &ev);
    }
}
4b9b3361

Ответ 1

Хорошо, ваш код работает для 32-битных изображений, если вы просто создаете GC, передающий аргумент drawable on, который имеет 32 бита. XCreateGC (dpy, drawable, 0, 0), где drawable может быть pixmap с глубиной 32 бит. Он отлично работает со мной.

Ответ 2

Проблема заключается в DefaultGC(), который возвращает GC с битовой глубиной системного экрана по умолчанию. Если вы посмотрите на строку 53 вашей пасты, вы увидите, что это 24:

глубина корневого окна: 24 плоскости

В строке 63 вы видите, что он использует 0x22 по умолчанию, который более подробно показан в строках с 64 по 70:

  visual:
    visual id: 0x22
    class: TrueColor
    depth: 24 planes
    available colormap entries: 256 per subfield
    red, green, blue masks: 0xff0000, 0xff00, 0xff
    significant bits in color specification: 8 bits

Возможно, вы могли бы сделать это немного лучше, но в начале вы можете попробовать следующее:

Примечание. Это использует системные визуальные эффекты, которые, скорее всего, поддерживают только глубину 24 или 32.

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


#ifdef DEBUG
int dbg = 1;
#else
int dbg = 0;
#endif

/* Return a GC based on depth */
int gc_depth(int depth, Display *dpy, Window scr, Window root, GC *gc)
{
        Window win;
        Visual *visual;
        XVisualInfo vis_info;
        XSetWindowAttributes win_attr;
        unsigned long win_mask;

        if(!XMatchVisualInfo(dpy, scr, depth, TrueColor, &vis_info)) {
                fprintf(stderr,
                        " * ERR: %d depth not supported\n",
                        depth
                );
                return 1;
        }

        visual = vis_info.visual;

        win_attr.colormap = XCreateColormap(dpy, root, visual, AllocNone);
        win_attr.background_pixel = 0;
        win_attr.border_pixel = 0;

        win_mask = CWBackPixel | CWColormap | CWBorderPixel;

        win = XCreateWindow(
                        dpy, root,
                        0, 0,
                        100, 100,        /* dummy size */
                        0, depth,
                        InputOutput, visual,
                        win_mask, &win_attr);
        /* To flush out any errors */
        if (dbg) XSync(dpy, True);

        *gc = XCreateGC(dpy, win, 0, 0);
        if (dbg) XSync(dpy, True);

        XDestroyWindow(dpy, win);
        if (dbg) XSync(dpy, True);

        return 0;
}

int main(void)
{
        int w = 100;
        int h = 100;
        int depth = 32;
        int bitmap_pad = 32;
        int bpl = 0;

        Display *dpy;
        Window root;
        Window scr;
        GC gc;
        int root_depth;

        Pixmap pm;
        XImage *img;
        unsigned char *buf_img;

        if(!(dpy = XOpenDisplay(NULL))) {
                fprintf(stderr,
                        " * ERR: Failed to open display.\n");
                return 1;
        }

#ifdef DEBUG
        /* To get errors in order, slows down
         * One can also define int _Xdebug = 1;
         * */
        XSynchronize(dpy, True);
#endif

        root = XDefaultRootWindow(dpy);
        scr  = XDefaultScreen(dpy);

        if ((buf_img = malloc(w * h * 4)) == NULL) {
                fprintf(stderr,
                        " * ERR: Unable to alloacte %d bytes\n",
                        w * h * 4);
                return 1;
        }

        root_depth = DefaultDepth(dpy, scr);

        fprintf(stderr,
                "Default depth: %d\n",
                root_depth);

        /* This should be doen more nice */
        if (depth != root_depth) {
               if (gc_depth(depth, dpy, scr, root, &gc) != 0)
                        return 1;
        } else {
                gc = DefaultGC(dpy, 0);
        }

        img = XCreateImage(
                        dpy, CopyFromParent,
                        depth, ZPixmap,
                        0, (char *)buf_img,
                        w, h,
                        bitmap_pad, bpl);
        /* To flush out any errors */
        if (dbg) XSync(dpy, True);

        pm = XCreatePixmap(
                        dpy, root,
                        w, h,
                        depth);
        if (dbg) XSync(dpy, True);

        XPutImage(
                dpy, pm,
                gc, img,
                0, 0,
                0, 0,
                w, h);
        if (dbg) XSync(dpy, True);

        XFreePixmap(dpy, pm);
        XDestroyImage(img);
        XFreeGC(dpy, gc);
        if (dbg) XSync(dpy, True);

        fprintf(stderr,
                "OK!\n");

        return 0;
}