[comp.windows.open-look] Grayscale Image Display under OpenWindows 2.0

leue@galen.crd.ge.com (Bill Leue) (05/01/91)

I'm writing a simple Xview application to display an 8-bit grayscale
image in a window.  I'm also trying to implement control over contrast
and brightness using two sliders which update the colormap.

This application ALMOST works correctly, but I'm stuck on two (related)
bugs.  I wonder if someone out there has some experience in this area
that they'd like to share.

My general approach has been to use a 256-slot long Control Colormap
Segment, with 256 - CMS_CONTROL_COLORS reserved for a grayscale ramp,
and the remaining (4) slots reserved for the "3D look" standard map.
This is (I think) the way you're supposed to do it, as per section
20.5 of the O'Reilly XView Programming Manual, as revised for OW 2.0.
After creating a Control Cms and attching it to the canvas, I make an XImage
struct and use XPutImage to display the data.

The first problem is that the grayscale ramp seems to overlap the control
colors, since I see some pixels in the image which have colors from the
frame and root background.

The second problem is that I don't know how to update the colormap when
I want to change the contrast or brightness.  In the SunView version upon
which this program is based, I used pw_putcolormap() to perform the remapping.
Is there an Xview equivalent?  If so, then I still have the problem of
not knowing how to find out what the CONTROL part of the segment is -- there
doesn't seem to be any Xview call to fetch the contents of the complete
color map as opposed to only the grayscale ramp part of it.  Any clues?

Here's some pieces of code that illustrate the relevant areas.

1) ------------------- Inital setup of the colormap and canvas:

#define NCOLORS (256 - CMS_CONTROL_COLORS)

Xv_singlecolor colors[NCOLORS];
Cms cms;

    for (i=0; i<NCOLORS; i++) {
        colors[i].red = 
        colors[i].blue = 
        colors[i].green = i;		/* make grayscale ramp */
    }

    cms = (Cms)xv_create(NULL, CMS,
        CMS_SIZE, NCOLORS + CMS_CONTROL_COLORS,
        CMS_TYPE, XV_DYNAMIC_CMS,
        CMS_CONTROL_CMS, TRUE,
        CMS_COLORS,   colors,
        NULL);

    canvas = xv_create(frame, CANVAS,
        WIN_X, 0,
        WIN_Y, 0,
        XV_WIDTH, ncol,
        XV_HEIGHT, nrow,
        CANVAS_WIDTH, ncol,
        CANVAS_HEIGHT, nrow,
        CANVAS_AUTO_EXPAND, FALSE,
        CANVAS_AUTO_SHRINK, FALSE,
        CANVAS_X_PAINT_WINDOW, TRUE,
        WIN_CONSUME_EVENTS,
        WIN_IN_TRANSIT_EVENTS,
        WIN_MOUSE_BUTTONS,
        LOC_DRAG, 0,
        CANVAS_REPAINT_PROC, show_image,
        WIN_DYNAMIC_VISUAL, TRUE,
        WIN_CMS, cms,
        0);

2)   ------------------   Load Image Bits from stdin:

char *image_bits, *bp;

    imsiz = ncol*nrow;
    image_bits = (char *)malloc(imsiz);
    if (image_bits == NULL) {
        fprintf(stderr, "Error - Can't Allocate Image Buffer\n");
        exit(1);
    }    
    bp = image_bits;;
    for (i=0;i<imsiz;i++) *bp++ = getchar();


3) -----------------------  Image Display:  (this is the canvas repaint proc):

void show_image(canvas, paint_window, dpy, xwin, xrects)
    Canvas canvas;
    Xv_Window paint_window;
    Display *dpy;
    Window xwin;
    Xv_xrectlist *xrects;
{

    Drawable dwbl;
    GC gc ;
    XImage ximage, *image = &ximage ;

    dwbl = (Drawable)xv_get(canvas_paint_window(canvas), XV_XID);
    gc = DefaultGC (dpy, DefaultScreen (dpy)) ;

    image->width = ncol ;
    image->height = nrow ;
    image->xoffset = 0 ;
    image->format = ZPixmap ;
    image->data = image_bits ;
    image->byte_order = MSBFirst ;
    image->bitmap_unit = 32 ;
    image->bitmap_bit_order = LSBFirst ;
    image->bitmap_pad = 32 ;
    image->depth = 8 ;
    image->bytes_per_line = ncol ;
    image->bits_per_pixel = 8 ;
    image->red_mask = 255 ;
    image->green_mask = 255 ;
    image->blue_mask = 255 ;

    XPutImage (dpy, dwbl, gc, image, 0, 0, 0, 0, ncol, nrow) ;
}

That should give you an idea of what I'm doing.  In addition to the code
shown, I've tried a whole bunch of other things, such as using XColor
structs instead of Xv_singlecolor (no difference), shortening the grayscale
ramp, etc.  None of these changes made any difference in the right direction.
The frustrating part is that the image is actually there and looks fine,
except for those few pixels which seem to get into the CONTROl part of
the map segment.  Do I have to add an offset to each pixel to insure that
the pixel values don't fall into the bottom of the colormap segment, where
the control values are?  If so, this seems like an ugly and expensive
solution, IMHO.

I'd appreciate any help.  You might want to send email rather than burning
up net bandwidth.  I'll summarize any results.

Thanks!
-Bill Leue
leue@crd.ge.com