jim@athsys.uucp (Jim Becker) (09/01/88)
Please excuse the following source posting to comp.windows.x, but
I my stuff isn't complex enough for comp.sources.x to accept it..
The following is a program that clips arbitrary areas of the X
display and saves them in Sun raster format, which is FrameMaker
and other compatible. See intro comment for further details.
-Jim Becker
--skip or snip--
/*
* snap.c -- Screen snapshot program for SUN raster images (SUN ONLY!)
*
* Snap is utility that allows the user to select (crop) a portion of an
* X window display and save the bitmap image in a FrameMaker compatible
* picture format. (FrameMaker is probabily trademarked by Frame, Inc.).
*
* The "snap" program functions from the command line, and is best if run
* in a small window located away from the section(s) of the screen to be
* snapshot. It has been written to poll for keyboard keys being held
* down, and checks for the keys about three times a second. When it
* notices a key of import has been depressed, the appropriate action is
* taken. This polling behavior has been done for our requirements, as
* we need to have snapshots of the current pointer and popups correct.
*
* Selection of the portion of the screen to snapshot is done by using a
* "guide window". This is a heavy bordered empty window that frames the
* portion of the screen that is the current subject of the capture
* operation. This window is resized and positioned using the standard
* window manager, and it's content is captured in the snapshot. Note
* that it must be "behind" the windows of interest when the snapshot is
* taken, else it will obscure the image to be captured. The snapshot(s)
* taken will contain the entire area within the borders of the guide
* window.
*
* Command line invokation of the program is simple, "snap [ <prefix> ]"
* is used to start it. The <prefix> is the optional name that is used
* for the stored images. Files that are created by snap are named using
* the convention "<prefix>.Snn", where "nn" is the numeric photo number.
* Multiple images can be captured during the run of the snap program,
* and it appends the photo count to the name. The default <prefix> is
* "Snap", yielding names "Snap.S01", "Snap.S02" etc. This makes it easy
* to slide through all the names when Importing them into FrameMaker.
*
* All program selection is via the mechanism of holding down keys, and
* the keys that are held down are fairly obscure ones on the Sun keyboard.
* Most programs ignore these keys, but beware of editors and such that may
* try to interpret these keys. "It seemed fine in all my tests.. (FLW)".
*
* The keys of interest are as follows:
*
* ALTERNATE -- Snapshot the screen image
*
* R13 -- Bring guide window to front
*
* R15 -- Push guide window to back
*
* R3 -- Exit the snap program
*
*
* The key depression is not registered immediately, but as soon as
* it is noticed a message is printed to the program startup window.
* In addition, snapshots ring the terminal bell upon completion. Note
* that there is a delay in place after the snapshot before the next,
* but the auto-winder is working. Watch out for multiple like shots.
*
* To build: cc -o snap snap.c -lX11 -lm -lpixrect
*
* Created on a Sun -- only for a Sun !!
*
* Right2Copy (R2C) 1988 -- Athena Systems, Inc.
*
* Rev Date Who Reason
* --- ----- --- ------
* V1.0 08/16 Jim Becker Initial creation
* 08/23 Jim Becker Cleaned up and released to X
*
*/
#include <ctype.h>
#include <stdio.h>
#include <pixrect/pixrect_hs.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#define ICON_NAME "*Snapper*"
#define DEFAULT_NAME "Snap"
#define SLEEP_DURATION 300000
#define PLACE 100
#define SIZE 400
#define BW 5
#define MIN(a,b) ((a) < (b) ? (a) : (b) )
#define MAX(a,b) ((a) > (b) ? (a) : (b) )
#define TRUE 1
#define FALSE 0
Display *mdisplay;
Window mroot, oroot;
GC mdefaultgc;
int dwidth, dheight;
int x, y;
int wwidth, wheight;
int ww = BW;
char name[100];
int count;
struct pixrect *screen;
/*
* init program - create guide window and place
*/
init()
{
XSizeHints xsize;
int screenno;
if( (mdisplay = XOpenDisplay( NULL ) ) == NULL ) {
printf("Can't grab display !!\n" );
exit(1);
}
if( (screen = pr_open( "/dev/fb" ) ) == NULL ) {
printf("Can't grab pixrect screen !!\n");
exit(1);
}
screenno = DefaultScreen(mdisplay);
mroot = RootWindow(mdisplay,screenno);
dwidth = DisplayWidth( mdisplay,screenno);
dheight = DisplayHeight(mdisplay,screenno);
mdefaultgc = DefaultGC(mdisplay,screenno);
XSetSubwindowMode( mdisplay, mdefaultgc, IncludeInferiors );
oroot = XCreateSimpleWindow( mdisplay, mroot, PLACE,PLACE,SIZE,SIZE,
ww,1, WhitePixel(mdisplay,screenno));
if( oroot == NULL ) {
printf("Can't open viewing window!\n");
exit(1);
}
XChangeProperty( mdisplay, oroot, XA_WM_NAME, XA_STRING, 8,
PropModeReplace, ICON_NAME, sizeof(ICON_NAME)-1 );
xsize.x = 0;
xsize.y = 0;
xsize.width = SIZE;
xsize.height = SIZE;
xsize.min_width = 0;
xsize.min_height= 0;
xsize.max_width = dwidth;
xsize.max_height= dheight;
xsize.flags = USPosition | USSize;
XSetNormalHints( mdisplay, oroot, &xsize );
x = PLACE;
y = PLACE;
wheight = SIZE;
wwidth = SIZE;
XSelectInput( mdisplay, oroot, StructureNotifyMask );
XMapWindow( mdisplay, oroot );
}
/*
* terminate program
*/
term()
{
XDestroyWindow( mdisplay, oroot );
XCloseDisplay( mdisplay );
pr_close( screen );
}
/*
* handle resize of guide window
*/
resetsize( cevent )
XConfigureEvent *cevent;
{
/* get new location and size */
x = MAX(cevent->x,0);
y = MAX(cevent->y,0);
wwidth = cevent->width;
wheight = cevent->height;
/* crop to size of the physical screen */
if( (x + wwidth + ww*2) > dwidth )
wwidth = dwidth - x - ww*2;
if( (y + wheight + ww*2) > dheight )
wheight = dheight - y - ww*2;
}
/*
* ugly polling of the keymap for special keys.
*
* (Have checked return code to determine these key combos).
*/
checkkeymap( done )
short *done;
{
char keys[32];
char buffer[100];
XQueryKeymap( mdisplay, keys );
if( keys[3] & 0x04 ) { /* check for the "Alternate" key */
/* determine name of new file */
sprintf(buffer, "%s.S%02d", name, ++count);
printf("Save to file '%s'...", buffer );
fflush(stdout);
if( savecurrenttodisk( buffer ) )
printf(".done.\n");
else
printf(".Error saving!!\n");
XBell( mdisplay, 100 );
return;
}
else
if( keys[14] & 0x80 ) { /* check for the R13 key */
printf("Window to front.\n");
XRaiseWindow( mdisplay, oroot );
}
else
if( keys[15] & 0x02 ) { /* check for the R15 key */
printf("Window to back.\n");
XLowerWindow( mdisplay, oroot );
}
else
if( keys[3] & 0x40 ) { /* check for the R3 key */
printf("Done snapping.\n");
*done = TRUE;
}
else
return FALSE;
return TRUE;
}
/*
* clip the current location and store the frame buffer to disk
*/
savecurrenttodisk( filename )
char *filename;
{
FILE *out;
struct pixrect *clip;
colormap_t *colormap = NULL;
int type = RT_BYTE_ENCODED; /* RLL encoded */
int copy_flag = TRUE;
out = fopen( filename, "w" );
if( out == NULL )
return FALSE;
clip = pr_region( screen, x+ww, y+ww, wwidth, wheight );
pr_dump( clip, out, colormap, type, copy_flag );
fclose( out );
pr_destroy( clip );
return TRUE;
}
/*
* === MAINLINE ===
*/
main( argc, argv )
int argc;
char **argv;
{
XEvent xevent;
XButtonEvent *bevent = &xevent.xbutton;
short done = FALSE;
/* get the name prefix from the user or default */
if( argc >= 2 )
strcpy( name, *++argv );
else
strcpy( name, DEFAULT_NAME );
/* initalize program, exits if error */
init();
/* loop until exit key is sensed */
while( !done ) {
while( XPending( mdisplay ) ) {
XNextEvent( mdisplay, &xevent );
switch( xevent.type ) {
case ConfigureNotify:
resetsize( &xevent );
break;
}
}
/* check (poll) for keys. if found let user up before repeat */
if( checkkeymap( &done ) && !done )
sleep(1);
else
usleep(SLEEP_DURATION);
}
term();
exit(0);
}