[comp.windows.x] XCopyPlane

envbvs@epb2.lbl.gov (Brian V. Smith) (11/01/89)

Ok, I give up.  Is XCopyPlane() broken on color Vaxstation 2000s (4-plane)?

I have a simple client which just displays a bitmap file in a window.
I call XReadBitmapFile() and create a GC with BlackPixel and WhitePixel
as foreground and background respectively.  Then, AFTER RECEIVING AN EXPOSE
EVENT, I just use XCopyPlane to display the exposed part of the pixmap.

It works fine on our monochrome Vaxstation 2000s, but not on the color.
Here is the important part of the program:

Display *disp;
int     width, height;
Pixmap  picture;
Window  win = (Window) 0;
GC      gc;
XGCValues gcval;

main()
	{
        if ((disp=XOpenDisplay("")) == NULL)
                {
                fprintf(stderr, "Couldn't open DISPLAY\n");
                exit(1);
                }
        if (XReadBitmapFile(disp,RootWindow(disp,0),file,
		&width,&height,&picture,NULL, NULL) != BitmapSuccess)
                {
                fprintf(stderr, "Bad bitmap file: %s\n", file);
                exit(1);
                }
        gcval.foreground=BlackPixel(disp,0);
        gcval.background=WhitePixel(disp,0);
        gcval.line_width = 1;
        gcval.function = copyfunc;
        if ((gc = XCreateGC(disp,RootWindow(disp,0),GCFunction|GCLineWidth|
		GCForeground|GCBackground,&gcval))==False)
                {
                fprintf(stderr,"Error in creating GC\n");
                exit(1);
                }
        win = XCreateSimpleWindow(disp,RootWindow(disp,0), 0, 0, 
			width, height, 1,
                        BlackPixel(disp,0), WhitePixel(disp,0));
        XStoreName(disp, win, "Xbitmap");
        XMapRaised(disp,win);

        XSelectInput(disp, win, ExposureMask|ButtonPressMask|KeyPressMask);
        for (;;)
                {
                XNextEvent(disp, &ev);
                if (ev.type == Expose || ev.type== GraphicsExpose)
                        drawPicture(0, ev.y, width, ev.height);
                }
        }

drawPicture(x, y, w, h)
        {
        XCopyPlane(disp, picture, win, gc, 0, y, w, h, 0, y, (unsigned
long) 1);
        XFlush(disp);
        }


_____________________________________
Brian V. Smith    (bvsmith@lbl.gov)
Lawrence Berkeley Laboratory
I don't speak for LBL, these non-opinions are all mine.

envbvs@epb2.lbl.gov (Brian V. Smith) (11/01/89)

I have a simple application that just displays a bitmap file on a window.
After calling XReadBitmapFile to get the data in a Pixmap, I use 
XCopyPlane to copy it into the window.
 
I call XCopyPlane AFTER RECEIVING AN EXPOSE EVENT ON THE WINDOW.
This works fine on monochrome Vaxstation II and 2000's, but not on
our color (4-plane) machines.  I made sure that the foreground/background
pixel values were good but to no avail.
Help!? 

_____________________________________
Brian V. Smith    (bvsmith@lbl.gov)
Lawrence Berkeley Laboratory
I don't speak for LBL, these non-opinions are all mine.


Here is the relevant part of the program:

------------------------------  cut  here ------------------------------
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

Display *disp;
int     width, height;
Pixmap  picture;
Window  win = (Window) 0;
GC      gc;
XGCValues gcval;

main(ac, av)
int ac;
char *av[];
        {
        char            *file;
        XExposeEvent    ev;
        if (ac < 2)
                file="-";       /* standard input */
        else
                file = av[1];
        if ((disp=XOpenDisplay("")) == NULL)
                {
                fprintf(stderr, "Couldn't open DISPLAY\n");
                exit(1);
                }
        if (XReadBitmapFile(disp,RootWindow(disp,0),file,
                &width,&height,&picture,NULL, NULL) != BitmapSuccess)
                {
                fprintf(stderr, "Bad bitmap file: %s\n", file);
                exit(1);
                }

        gcval.foreground=BlackPixel(disp,0);
        gcval.background=WhitePixel(disp,0);
        gcval.line_width = 1;
        gcval.function = GXcopy;
        if ((gc = XCreateGC(disp,RootWindow(disp,0),
                        GCFunction|GCLineWidth|
                        GCForeground|GCBackground,&gcval))
                    ==False)
                {
                fprintf(stderr,"Error in creating GC\n");
                exit(1);
                }
        win = XCreateSimpleWindow(disp,RootWindow(disp,0), 0, 0, width,
height, 0,
                        BlackPixel(disp,0), WhitePixel(disp,0));
        XStoreName(disp, win, "Xbitmap");
        XMapRaised(disp,win);

        XSelectInput(disp, win, ExposureMask|ButtonPressMask|KeyPressMask);
        for (;;)
                {
                XNextEvent(disp, &ev);
                if (ev.type == Expose || ev.type== GraphicsExpose)
                        drawPicture(0, ev.y, width, ev.height);
                }
        }

drawPicture(x, y, w, h)
        {
        XCopyPlane(disp, picture, win, gc, 0, y, w, h, 0, y, (unsigned
long) 1);
        XFlush(disp);
        }

mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) (11/01/89)

> I have a simple client which just displays a bitmap file in a window.
> I call XReadBitmapFile() and create a GC with BlackPixel and
> WhitePixel as foreground and background respectively.  Then, AFTER
> RECEIVING AN EXPOSE EVENT, I just use XCopyPlane to display the
> exposed part of the pixmap.

Good, you've avoided the first problem.  (But you've already created
another, probably without realizing it.)

>        gcval.foreground=BlackPixel(disp,0);
>        gcval.background=WhitePixel(disp,0);

Not that it's related to your problem, but this sort of assumption is a
common headache of mine.  Not everybody runs black-on-white!

>        XMapRaised(disp,win);

>        XSelectInput(disp, win, ExposureMask|ButtonPressMask|KeyPressMask);
>        for (;;)
> [...read events and redraw stuff upon an Expose event...]

Suppose the server generates Expose events from the MapRaised before it
acts on the SelectInput?  Guess what that will do...

By the way, you needn't XFlush after drawing; XNextEvent will flush for
you if necessary.

Why is there a difference?  I can only guess, and it wouldn't even be
an informed guess, because I've never even seen a DEC server.  So your
guess is at least as good as and probably better than mine.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

envbvs@epb2.lbl.gov (Brian V. Smith) (11/02/89)

In article <8911010656.AA19525@Larry.McRCIM.McGill.EDU>,
mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) writes:
< 
< Good, you've avoided the first problem.  (But you've already created
< another, probably without realizing it.)
< 
< >        gcval.foreground=BlackPixel(disp,0);
< >        gcval.background=WhitePixel(disp,0);
< 
< Not that it's related to your problem, but this sort of assumption is a
< common headache of mine.  Not everybody runs black-on-white!
<

I wanted to use black and white as to simplify the problem for debugging
purposes. At least I didn't use 1 and 0! 8-)
 
< >        XMapRaised(disp,win);
< 
< >        XSelectInput(disp, win, ExposureMask|ButtonPressMask|KeyPressMask);
< >        for (;;)
< > [...read events and redraw stuff upon an Expose event...]
< 
< Suppose the server generates Expose events from the MapRaised before it
< acts on the SelectInput?  Guess what that will do...
< 

You're right - I should reverse the XMapRaised and XSelectInput.  
But that isn't the problem.  Read on.

< By the way, you needn't XFlush after drawing; XNextEvent will flush for
< you if necessary.

Right again.  I wasn't leaving anything to chance since it wasn't working.
 
< Why is there a difference?  I can only guess, and it wouldn't even be
< an informed guess, because I've never even seen a DEC server.  So your
< guess is at least as good as and probably better than mine.

The problem is that the Xqdss server (color vaxstation)s has several
bugs related to this and other problems (stippling, for example).
Several people have given me some ideas and I thank all who have responded.

One fix is to apply a patch file available on expo.lcs.mit.edu (18.30.0.212)
that has been available since Sep 2, which fixes these problems.
The other is to use DECwindows UWS2.1, which, as some claim is faster anyway.

The patch file on expo (contrib/Xqdss.patch1.Z) seems to fix the problem.
Thanks again to all who responded to my problem.

Maybe we'll try UWS2.1 (if we can figure out how to use our existing
fonts 8-)  )
_____________________________________
Brian V. Smith    (bvsmith@lbl.gov)
Lawrence Berkeley Laboratory
I don't speak for LBL, these non-opinions are all mine.

scott@graft.Berkeley.EDU (Scott Silvey) (07/10/90)

I am trying to turn a window's image into an X11 bitmap.  I want to write this
  bitmap out to a file using XWriteBitmapFile().

However, I can't find any way to do this using XCopyPlanes or XGet/PutImage if
  the window is on a color display (multiple planes).  There is apparently 
  no way for me to copy the information from the window to a single plane 
  bitmap short of checking each and every pixel one at a time.  

Here are the two methods I've tried:

1) [XCopyPlane()]  The Xlib manual says that XCopyPlane() doesn't care if the
  depth of it's two drawables is different, however, when I try the following 
  line, XCopyPlane() generates a BadMatch error (Invalid parameter attribues):

  	XCopyPlane(display, 
	     	   window, 			/* 8 bits deep */
             	   bitmap, 			/* 1 bit deep */
		   gc,				/* GC with function GXor */
	    	   0, 0, width, height, 0, 0,	/* width, height == 300 */
  	     	   plane_mask);			/* only 1 bit set */

2) [XGetImage() / XPutImage()]  For XGetImage() on the type XYPixmap, the Xlib
  manual says that the depth of the returned image is equal to the number of
  planes requested in the plane mask.  So, I tried to use XGetImage() and
  XPutImage() with type XYPixmap, but this also generates a BadMatch error:

	image = XGetImage(display, 
			  window, 	       /* 8 bits deep */
			  0, 0, width, height, /* width, height == 300 */
			  plane_mask, 	       /* 1 bit set */
			  XYPixmap);

	XPutImage(display, 
		  bitmap, 		       /* 1 bit deep */
		  gc,  			       /* GC with function GXor */
		  image,  		       /* image from XGetImage */
		  0, 0, 0, 0,  
		  width, height);	       /* width, height == 300 */

The one thing I CAN get to work is to do an XGetImage() and then query each and
  every pixel using XGetPixel.  For each pixel that is not the
background color,
  I do and XDrawPoint() on the bitmap.  This is dog-slow though, doing two
  X operations per pixel (what if I have a megapixel image?!).

It really suprised me to find that there is no supported way to copy data 
  between pixmaps of different depth (or actually from a multiplane pixmap to a
  bitmap).  Am I right this deficiency here?  Or am I missing something
obvious?
  Will there be more support for these sort of operations in future X releases?

Thanks a lot for your help if you answer these questions ...

Scott

scott@graft.Berkeley.EDU (Scott Silvey) (07/10/90)

In article <26023@pasteur.Berkeley.EDU>, scott@graft.Berkeley.EDU (Scott
Silvey) writes:
|> The one thing I CAN get to work is to do an XGetImage() and then
query each and
|>   every pixel using XGetPixel().  For each pixel that is not the
background color,
|>   I do and XDrawPoint() on the bitmap.  This is dog-slow though, doing two
|>   X operations per pixel (what if I have a megapixel image?!).

I know I could use XDrawPoints(), cutting down the number of X operations by
  50 percent, but there is still one XGetPixel() call per point.

Scott

scott@graft.Berkeley.EDU (Scott Silvey) (07/10/90)

 
In article <26023@pasteur.Berkeley.EDU>, scott@graft.Berkeley.EDU (Scott
Silvey) writes:
|>   	XCopyPlane(display, 
|> 	     	   window, 			/* 8 bits deep */
|>                 bitmap, 			/* 1 bit deep */
|> 		   gc,				/* GC with function GXor */
|> 	    	   0, 0, width, height, 0, 0,	/* width, height == 300 */
|>   	     	   plane_mask);			/* only 1 bit set */
|> 
|> 
|> 	XPutImage(display, 
|> 		  bitmap, 		       /* 1 bit deep */
|> 		  gc,  			       /* GC with function GXor */
|> 		  image,  		       /* image from XGetImage */
|> 		  0, 0, 0, 0,  
|> 		  width, height);	       /* width, height == 300 */
|> 

Oh, there was a question about the gc.  I used the following calls to
  create the gc:

	gc = XCreateGC(display, bitmap, NULL, 0);
	XSetFunction(display, gc, GXor);

Thanks,

Scott

rws@EXPO.LCS.MIT.EDU (Bob Scheifler) (07/10/90)

    There is apparently 
    no way for me to copy the information from the window to a single plane 
    bitmap short of checking each and every pixel one at a time.

You are wrong.

    The Xlib manual says that XCopyPlane() doesn't care if the
    depth of it's two drawables is different, however, when I try the following 
    line, XCopyPlane() generates a BadMatch error (Invalid parameter attribues)

One of the causes of BadMatch is if the two drawables are on different screens.
You don't give any hint about what system you're running on, what release
you're using (how do you expect any help?).  Perhaps you're running on a
3/60 or other dual-screen server, and created the bitmap on a different screen?
Submitting a complete but stripped-down program is always more likely to get
help than code fragments, the bug is almost always somewhere you don't think it
is (else you would have found it :-).

    So, I tried to use XGetImage() and
    XPutImage() with type XYPixmap, but this also generates a BadMatch error:

This sounds like you have created the gc with the wrong depth.

    Or am I missing something obvious?

I have no idea what you're missing.  The following works just fine for me:

#include <X11/Xlib.h>

main()
{
    Display *dpy;
    Pixmap pix, bit;
    GC gc8, gc1;
    XImage *img;

    dpy = XOpenDisplay(0);
    pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), 32, 32, 8);
    bit = XCreatePixmap(dpy, DefaultRootWindow(dpy), 32, 32, 1);
    gc8 = XCreateGC(dpy, pix, 0, 0);
    gc1 = XCreateGC(dpy, bit, 0, 0);
    XFillRectangle(dpy, pix, gc8, 0, 0, 32, 32);
    XSetForeground(dpy, gc8, 1);
    XDrawLine(dpy, pix, gc8, 0, 0, 32, 32);
    XCopyPlane(dpy, pix, bit, gc1, 0, 0, 32, 32, 0, 0, 1);
    XWriteBitmapFile(dpy, "/tmp/rws1", bit, 32, 32, 15, 15);
    img = XGetImage(dpy, pix, 0, 0, 32, 32, 1, XYPixmap);
    XPutImage(dpy, bit, gc1, img, 0, 0, 0, 0, 32, 32);
    XWriteBitmapFile(dpy, "/tmp/rws2", bit, 32, 32, 15, 15);
    XCloseDisplay(dpy);
}

lemke@ncd.COM (Dave Lemke) (07/10/90)

  From:  uunet!ucbvax.berkeley.edu!pasteur!graft!scott  (Scott Silvey)
  Date:  9 Jul 90 22:13:49 GMT

  I am trying to turn a window's image into an X11 bitmap.  I want to write thi
s
    bitmap out to a file using XWriteBitmapFile().
  
  However, I can't find any way to do this using XCopyPlanes or XGet/PutImage i
f
    the window is on a color display (multiple planes).  There is apparently 
    no way for me to copy the information from the window to a single plane 
    bitmap short of checking each and every pixel one at a time.  
  
  Here are the two methods I've tried:
  
  1) [XCopyPlane()]  The Xlib manual says that XCopyPlane() doesn't care if the
    depth of it's two drawables is different, however, when I try the following
 
    line, XCopyPlane() generates a BadMatch error (Invalid parameter attribues)
:
  
    	XCopyPlane(display, 
  	     	   window, 			/* 8 bits deep */
               	   bitmap, 			/* 1 bit deep */
  		   gc,				/* GC with function GXor */
  	    	   0, 0, width, height, 0, 0,	/* width, height == 300 */
    	     	   plane_mask);			/* only 1 bit set */

is the GC's depth the same as the destination bitmap's? (it inherits 
the depth from the drawable used when its created.  this requirement
is stated under XCreateGC(), possibly not the most obvious place.)

  
  2) [XGetImage() / XPutImage()]  For XGetImage() on the type XYPixmap, the Xli
b
    manual says that the depth of the returned image is equal to the number of
    planes requested in the plane mask.  So, I tried to use XGetImage() and
    XPutImage() with type XYPixmap, but this also generates a BadMatch error:
  
  	image = XGetImage(display, 
  			  window, 	       /* 8 bits deep */
  			  0, 0, width, height, /* width, height == 300 */
  			  plane_mask, 	       /* 1 bit set */
  			  XYPixmap);
  
  	XPutImage(display, 
  		  bitmap, 		       /* 1 bit deep */
  		  gc,  			       /* GC with function GXor */
  		  image,  		       /* image from XGetImage */
  		  0, 0, 0, 0,  
  		  width, height);	       /* width, height == 300 */

probably the GC's depth again.

Dave Lemke				ARPA: lemke@ncd.com
Network Computing Devices, Inc. 	UUCP: {uunet,ardent,mips}!lupine!lemke

shuda@PRC.Unisys.COM (Lester Shuda) (07/12/90)

In article <9007101642.AA12606@hansen.com> lemke@ncd.COM (Dave Lemke) writes:
>
>  From:  uunet!ucbvax.berkeley.edu!pasteur!graft!scott  (Scott Silvey)
>  Date:  9 Jul 90 22:13:49 GMT
>
>  I am trying to turn a window's image into an X11 bitmap.  I want to write thi
>s
>    bitmap out to a file using XWriteBitmapFile().
>  
>  However, I can't find any way to do this using XCopyPlanes or XGet/PutImage i
>f
>    the window is on a color display (multiple planes).  There is apparently 
>    no way for me to copy the information from the window to a single plane 
>    bitmap short of checking each and every pixel one at a time.  
>  
	If you just want to use XWriteBitmapFile(), just use the window
	as the Drawable argument. If you want to actually copy
	into an intermediate Pixmap, create a multiple plane Pixmap (same
	depth as your source window) and then use XCopyArea to copy into 
	that. You may then use this Pixmap as an argument to 
	XWriteBitmapFile. I haven't been able to get XWriteBitmapFile to 
	work with actual bitmaps (i.e. 1 bit deep Pixmaps).




*************************************************************************
* Les Shuda                             net: shuda@prc.unisys.com       *
* L. Shuda Consulting			phone: (215) 648-2524           *