Cómo subir una imagen de 32 bits a un pixmap del lado del servidor

Estoy intentando crear un pixmap RGBA del lado del servidor desde el búfer del lado del cliente CreatePixmap y CreateImage funcionan bien para 32 y 24 bits, pero XPutImage da como resultado un error de coincidencia devuelto por el servidor

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 

el servidor admite pixmaps de 32 bits (salida xdpyinfo: https://gist.github.com/2582961 ). Mismo comportamiento en ubuntu 12.04 (versión X.Org: 1.11.3) y OSX con X.app (versión X.Org: 1.10.3)

¿Por qué falla el siguiente código?

 #include  #include  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); } } 

Actualización: Parece que finalmente obtuve la respuesta: usar GC asociado con pixmap en lugar de DefaultGC (que tiene profundidad de ventana raíz)

 #include  #include  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); } } 

Bueno, su código funciona para imágenes de 32 bits si solo crea un GC que pasa un argumento dibujable en 32 bits. XCreateGC (dpy, drawable, 0, 0), donde drawable puede ser un pixmap con una profundidad de 32 bits. Funciona perfecto conmigo.

El problema es con DefaultGC() que devuelve un GC con profundidad de bits de la pantalla predeterminada del sistema. Si miras la línea 53 de tu primera pasta, verás que esto es 24:

Profundidad de la ventana raíz: 24 planos.

En la línea 63 ves que usa 0x22 como predeterminado, que se muestra con más detalle en la línea 64 a 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 

Probablemente podrías hacer esto un poco mejor, pero para empezar puedes probar esto:

Nota: Esto utiliza imágenes del sistema, por lo que probablemente solo admita una profundidad de 24 o 32

 #include  #include  #include  #include  #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; }