↑ Writing ↑


Static X/Y Plot Hardcopies and PRINT Buttons

September 4, 1992

Private Message to Jeff: The pointed barbs of ignorance you aim at me are blunted by my shield of knowledge. Besides, while I was vactioning at a luxury, seaside resort with one of the founders of our company, you were exploring the barren wastelands of Oregon and Washington, obviously preferring the company of the spotted owl to that of our revered founder, a fact that I brought to his attention and that he promised to remember when the next round of executive promotions comes up. Should one of our vice presidents retire anytime soon, I fully expect to kiss the XSAR project goodbye!

I have verified that we can implement the static X/Y plot hardcopy generator as described in the CDR: using code borrowed from the UNIX print-screen utilities, xwd and xpr, retrieve the X/Y plot's bit-map image from the X server, convert the image to PostScript, and print it. To test this approach, I implemented a PRINT button, a capability now needed for XSAR.

xwd and xpr

On UNIX systems, a screen dump is usually created by the xwd(1) program. xwd allows the user to select a window or region on the screen that is to be dumped. It then retrieves the bit-map image of the window or region from the X server and writes it out to a file. xpr(1) is used to print a screen dump. xpr reads the xwd-generated screen dump, converts the image to PostScript, and writes the resulting output to a file, which can then be spooled to a printer.

The source code and an executable for the VMS version of xwd were already available in the DECWindows examples directory. I obtained the xpr source code from the MIT X11R4 distribution and ported it to the VAX (a non-trivial task, thanks to the use of undocumented Xlib routines not available under VMS). Once I had xwd and xpr working, I cut and pasted the source code for these programs to produce two subroutine packages, xwd_util.c and xpr_util.c, that together perform the screen dump function. For performance reasons, I eliminated the intermediate dump file; the memory-resident image data gathered by the xwd routines is passed directly to the xpr routines.

The PRINT Button

Using the new xwd and xpr routines, I added a print screen command to my Tcl-based WIMP program:

    wmp_print [name] [-output file] [-root] [-xpr options]

This command generates a PostScript screen dump of an arbitrary widget (specified by its name) or of the entire screen. The xpr options allow you to control gray-scale representation, size scaling, and other attributes of the screen dump. For example, the Print 2x2 button on the Min-Max form:

Example Form

(Oops! I lost a couple of buttons!)

is defined as follows in WIMP:

    wmp_button Print_2 -label "Print 2x2" -parent control_row -command {wmp_print minmax_form -output minmax_2 -xpr "-gray 2 -scale 1"}

The WIMP command assigned to the button prints the minmax_form widget, which is the top-level, row-column widget of the form. The PostScript dump of the form's image is written to a file, minmax_2.ps. The first xpr option, "-gray 2", specifies 2x2 dithering to represent 5 levels of gray; the default is to generate a black-and-white image. A screen dump with 3x3 dithering is also attached. The other xpr option, "-scale 1", specifies a one pixel-to-one pixel rendering of the form; by default, the screen image is enlarged or reduced to fill the entire page.

The code fragment in wmp_print that does the printing is fairly simple:

    char  *output_file ;		/* Output file name. */
    char  *xpr_options ;		/* UNIX-like XPR options. */
    void  *xwd_image ;			/* XWD-generated image. */
    Widget  top_level ;			/* Application shell. */
    Widget  w ;				/* Widget to dump. */
    Window  window_to_dump ;


    if (w == NULL)			/* Entire screen? */
        window_to_dump = DefaultRootWindow (XtDisplay (top_level)) ;
    else				/* Partial screen. */
        window_to_dump = XtWindow (w) ;

					/* Get screen image. */
    xwd_get_window (top_level, window_to_dump, &xwd_image) ;

					/* Convert to PostScript. */
    xpr_print_window (top_level, xwd_image, output_file, xpr_options) ;


The following times were measured for the generation of the attached screen dumps:

    2x2 image:  ~15 seconds
    3x3 image:  ~30 seconds

Screen capture takes less than a second; the remainder of the time is spend converting the image to PostScript and outputting it to a file. The code that writes the hex dump of the image to the PostScript file looks inefficient, so some speed tuning in this department may be possible. The gray-scale dithering obviously affects the timing. Size scaling, on the other hand, doesn't affect the timing of the dump or the size of the output file; the scaling of the image is performed by the PostScript printer. xpr has a "-compact" option that uses run-length encoding for white pixels to produce smaller PostScript files (50% or more in the case of the Min-Max form), but these compressed files take longer to print.

Two alternatives for more quickly generating screen dumps come to mind. First, rather than going directly to PostScript, a program like Dynamic Display could save the raw image data in an xwd intermediate file and spawn a separate xpr process to convert the image to PostScript. Unfortunately, generating the xwd file is itself rather slow, although speed tuning (e.g., pre-sizing the output file) might help.

A second alternative would be to write a print server. When a PRINT button is pushed, the display program would capture the screen and send its image across a network connection to the print server. The print server could then, at its own leisure, convert the image to PostScript without holding up the display program. This approach assumes that transferring an image over the network would be faster than writing it to an intermediate file.

After The Fact Note: The XSAR Requirements Document, which I believe came from the Italian Space Agency (Agenzia Spaziale Italiana), specified that our GUIs generate PostScript files to be printed on Hewlett-Packard laser printers fitted out with PostScript interpreter cartridges. We complied. When our system was installed at the Jet Propulsion Laboratory, it was notable for how very long it took to print out a page, especially compared to all the other ASI and European Space Agency equipment. They, of course, bypassed the PostScript altogether and utilized the HP printers' native Printer Command Language (PCL). When the complaint about our system's performance came through, it was a simple matter to specify the "-device ljet" option ("ljet" for HP LaserJets) to xpr in order to generate PCL directly instead of PostScript. Voilà: speedy print-outs!

Static Plots

As you can see, the xwd_get_window() and xpr_print_window() functions could be used by XSAR's hardcopy-generating, X/Y plot program. In fact, if there were a means of determining when the fields on a page were fully populated (*), a generic page snap program could be written that would work with both ADT- and GDT-defined pages. And, if the Dynamic/Static Display program had a way of accepting artificial input (e.g., simulated PRINT button presses), it could be used to generate static page snaps, saving us the trouble of writing one or more separate programs. Oh, well ... time to wake up!

(*) Come to think of it, doesn't the static display program have this same problem when automatically stepping from major frame to major frame!

Alex Measday  /  E-mail