XImage Transparency

Glynn Clements glynn at gclements.plus.com
Fri Jul 27 20:53:38 PDT 2007


Gheorghe, Gelu wrote:

> So the only way to get TRUE transparency (ie. I can see what's
> underneath it) is by pulling in this XRender library which may not
> necessarily work with Solaris / my version of the X server (which is
> 3.6 11)?
> 
> From what I understand, masking only 'masks' it (ie. matches that
> part you don't want to the background colour).

First, are you asking for transparency or translucency (aka
alpha-blending)?

If you want translucency, you need to either use XRender (which may
not be available on all platforms), or implement your own
read-modify-write cycle (XGetImage, blend source and destination in
the client, XPutImage).

Transparency (masking) is where each pixel is either set to a specific
colour (fully opaque) or left untouched (fully transparent).

If you set a clip mask for a GC, any bits (pixels) which are zero in
the mask Pixmap will be left untouched by all drawing operations which
use that GC. IOW, whatever was on the screen beforehand will still be
there afterwards.

You can achieve the same result using and-or or and-xor. The first AND
operation has all bits clear for each pixel which you want to modify
and all bits set for each pixel which is to be left untouched. The
second OR/XOR operation has the destination value in each pixel which
is to be modified and all bits zero for each pixel which is to be left
untouched.

> I need it to be transparent and I need the mask to be dynamic as the
> XImage is 1000x1000 and constructed in real time, and there is a
> possibility it might be moving and I have to see the previous XImage
> through the current one.
> 
> What about the following method ? 
> 
>       /*  Fill in the pixmap with our bg color: */ 
>       XSetFunction(dpy, gc, GXcopy); 
>       XSetForeground(dpy, gc, bg); 
>       XFillRectangle(dpy, new, gc, 0, 0, width, height); 
> 
>       /*  Erase the parts not covered by the mask: */ 
>       XSetFunction(dpy, gc, GXand); 
>       XSetForeground(dpy, gc, 0); 
>       XSetBackground(dpy, gc, ~0); 
>       XCopyPlane(dpy, mask, new, gc, 0, 0, width, height, 0, 0, 1L); 
> 
>       /*  Copy in the "original" pixmap, but only those parts that 
>        *  have a valid mask bit: 
>        */ 
>       XSetFunction(dpy, gc, GXor); 
>       XCopyArea(dpy, image, new, gc, 0, 0, width, height, 0, 0); 

Sort of, but not quite. Try this:

	XSetFunction(dpy, gc, GXand); 
	XSetBackground(dpy, gc, ~0UL);
	XSetForeground(dpy, gc, 0UL);
	XCopyPlane(dpy, mask, new, gc, 0, 0, width, height, 0, 0, 1L); 

	XSetFunction(dpy, gc, GXor);
	XCopyArea(dpy, image, new, gc, 0, 0, width, height, 0, 0); 

This assumes that both mask and image have been converted from XImages
to Pixmaps, and that the image has zeroes where masked You could skip
converting the image and replace the XCopyArea() with XPutImage().

This approach is preferable to using a clip mask if the mask changes
regularly. Actually, if the server implements the clip mask using
spans, it may be preferable regardless.

-- 
Glynn Clements <glynn at gclements.plus.com>



More information about the xorg mailing list