home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!decwrl!sun-barr!newstop!sun!SLC.COM
- From: bruce@SLC.COM (Bruce Schuchardt)
- Newsgroups: comp.sources.x
- Subject: v08i075: xgrabsc -- make images of portions of the screen, Part01/02
- Message-ID: <140952@sun.Eng.Sun.COM>
- Date: 20 Aug 90 17:52:43 GMT
- Sender: news@sun.Eng.Sun.COM
- Lines: 2007
- Approved: argv@sun.com
-
- Submitted-by: bruce@SLC.COM (Bruce Schuchardt)
- Posting-number: Volume 8, Issue 75
- Archive-name: xgrabsc/part01
-
- There are a number of programs available for getting X-Windows
- screen dumps (e.g., xwd, xwps and DEC's session manager), but they
- all either write their output in an unusable format, or are restricted
- to dumps of single shell windows. I wrote xgrabsc in an effort to get
- around these restrictions.
-
- The main contribution of this program is its use of root-window
- rubberbanding to allow capture of arbitrary portions of the screen,
- and its multiple output formats (x-bitmap, x-pixmap, xwd, Postscript
- and puzzle formats).
-
- The Postscript dumps will use run-length encoding if it results in
- any savings in size. A typical xterm window dump on a mono system
- runs around 40K bytes. An xwd dump on the same screen will be around
- 650K bytes.
-
- The program should build easily enough. If you don't have imake,
- use simple.mak (i.e., make -f simple.mak). For building, you
- should only have to alter the makefiles if your include files or
- libraries are in a non-standard location (/usr/include/X11, /usr/
- lib).
-
- The makefiles will install xgrabsc in /usr/bin/X11 and the man page in
- /usr/man/man1. Change the makefile before installing if you don't like
- these locations.
-
-
- Please send comments, bugs and enhancements to bruce@slc.com.
-
-
- File Name Archive # Description
- -----------------------------------------------------------
- Imakefile 1 imake makefile
- README 1 this stuff
- cpyright.h 1 copyright notice
- patchlevel.h 2 current patch level
- simple.mak 2 simple 'make' makefile
- xgrabsc.c 1 program source
- xgrabsc.man 1 man page for xgrabsc
-
- -----------------CUT HERE---------------------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 2)."
- # Contents: README Imakefile cpyright.h xgrabsc.c xgrabsc.man
- # Wrapped by owner@spruce on Mon Aug 20 10:03:02 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(2167 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X*========================================================================
- X*
- X* Name - README
- X*
- X* Version: 1.3
- X*
- X* ccsid: @(#)README 1.3 - 8/20/90 09:55:04
- X* from: ccs/s.README
- X* date: 8/20/90 09:55:59
- X*
- X* Copyright (C) 1990, Bruce Schuchardt
- X* See either the man page or the file cpyright.h for full copyright
- X* information.
- X*
- X* Description: README for xgrabsc
- X*
- X*========================================================================
- X
- XThere are a number of programs available for getting X-Windows
- Xscreen dumps (e.g., xwd, xwps and DEC's session manager), but they
- Xall either write their output in an unusable format, or are restricted
- Xto dumps of single shell windows. I wrote xgrabsc in an effort to get
- Xaround these restrictions.
- X
- XThe main contribution of this program is its use of root-window
- Xrubberbanding to allow capture of arbitrary portions of the screen,
- Xand its multiple output formats (x-bitmap, x-pixmap, xwd, Postscript
- Xand puzzle formats).
- X
- XThe Postscript dumps will use run-length encoding if it results in
- Xany savings in size. A typical xterm window dump on a mono system
- Xruns around 40K bytes. An xwd dump on the same screen will be around
- X650K bytes.
- X
- XThe program should build easily enough. If you don't have imake,
- Xuse simple.mak (i.e., make -f simple.mak). For building, you
- Xshould only have to alter the makefiles if your include files or
- Xlibraries are in a non-standard location (/usr/include/X11, /usr/
- Xlib).
- X
- XThe makefiles will install xgrabsc in /usr/bin/X11 and the man page in
- X/usr/man/man1. Change the makefile before installing if you don't like
- Xthese locations.
- X
- X
- XPlease send comments, bugs and enhancements to bruce@slc.com.
- X
- X
- XManifest
- X--------
- XREADME this file
- X
- XImakefile Input for "imake" program
- Xsimple.mak Simpler input for standard "make"
- X
- Xcpyright.h Copyright notice for this software (READ IT)
- Xpatchlevel.h Current patch level
- Xxgrabsc.c Program source
- X
- Xxgrabsc.man Man page for xgrabsc
- X
- X
- X
- X+----------------------------+
- X| Bruce Schuchardt |
- X| Servio Corporation |
- X| bruce@slc.com |
- X+----------------------------+
- X
- END_OF_FILE
- if test 2167 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'Imakefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Imakefile'\"
- else
- echo shar: Extracting \"'Imakefile'\" \(944 characters\)
- sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
- X/*========================================================================
- X *
- X * Name - Imakefile
- X *
- X * Version: 1.3
- X *
- X * ccsid: @(#)Imakefile 1.3 - 8/20/90 09:54:45
- X * from: ccs/s.Imakefile
- X * date: 8/20/90 09:55:58
- X *
- X * Description: imake file to build xgrabsc. Use simple.mak if you
- X * don't have imake.
- X *
- X *========================================================================
- X */
- X
- X/* change INSTALL_PATH to the directory in which you want xgrabsc installed */
- XINSTALL_PATH = /usr/bin/X11
- X
- X/* change MAN_PATH to point to your man page top directory */
- XMAN_PATH = /usr/man
- X/* change MAN_EXT to the section for xgrabsc */
- XMAN_EXT = 1
- X
- X/* if you trust your optimizer, change 'g' to 'O' */
- XCDEBUGFLAGS = -g
- XLOCAL_LIBRARIES = $(XLIB)
- X
- XSimpleProgramTarget(xgrabsc)
- X
- Xinstall::
- X $(INSTALL) -c -s xgrabsc $(INSTALL_PATH)
- X $(INSTALL) -c -m 644 xgrabsc.man \
- X $(MAN_PATH)/man$(MAN_EXT)/xgrabsc.$(MAN_EXT)X
- END_OF_FILE
- if test 944 -ne `wc -c <'Imakefile'`; then
- echo shar: \"'Imakefile'\" unpacked with wrong size!
- fi
- # end of 'Imakefile'
- fi
- if test -f 'cpyright.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cpyright.h'\"
- else
- echo shar: Extracting \"'cpyright.h'\" \(1576 characters\)
- sed "s/^X//" >'cpyright.h' <<'END_OF_FILE'
- X#ifndef _COPYRIGHT_
- X#define _COPYRIGHT_
- X/*========================================================================
- X*
- X* Name - cpyright.h
- X*
- X* Version: 1.1
- X*
- X* ccsid: @(#)cpyright.h 1.1 - 8/16/90 09:12:34
- X* from: ccs/s.cpyright.h
- X* date: 8/20/90 09:56:00
- X*
- X* Description: copyright information for xgrabsc
- X*
- X*========================================================================
- X*
- X* Dithering and Halftoning code:
- X* Copyright 1989, 1990 Jim Frost
- X*
- X* All other code:
- X* Copyright (C) 1990 Bruce Schuchardt
- X*
- X* Permission to use, copy, modify, distribute, and sell this software
- X* and its documentation for any purpose is hereby granted without fee,
- X* provided that the above copyright notice appear in all copies and
- X* that both that copyright notice and this permission notice appear
- X* in supporting documentation. The author makes no representations
- X* about the suitability of this software for any purpose. It is
- X* provided "as is" without express or implied warranty.
- X*
- X* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- X* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- X* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- X* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- X* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- X* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
- X* USE OR PERFORMANCE OF THIS SOFTWARE.
- X*/
- X
- Xstatic char *XLoadImage_Copyright= "Copyright (C) 1989 Jim Frost";
- Xstatic char *Copyright = "Copyright (C) 1990 Bruce Schuchardt";
- X#endif
- X
- END_OF_FILE
- if test 1576 -ne `wc -c <'cpyright.h'`; then
- echo shar: \"'cpyright.h'\" unpacked with wrong size!
- fi
- # end of 'cpyright.h'
- fi
- if test -f 'xgrabsc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xgrabsc.c'\"
- else
- echo shar: Extracting \"'xgrabsc.c'\" \(38224 characters\)
- sed "s/^X//" >'xgrabsc.c' <<'END_OF_FILE'
- X/*========================================================================
- X *
- X * Name - xgrabsc.c
- X *
- X * Version: 1.4
- X *
- X * ccsid: @(#)xgrabsc.c 1.4 - 8/20/90 09:55:19
- X * from: ccs/s.xgrabsc.c
- X * date: 8/20/90 09:56:02
- X *
- X * Copyright (c) 1990 Bruce Schuchardt.
- X * Read the file cpyright.h for full copyright information.
- X *
- X *
- X * Description:
- X *
- X * xgrabsc - grab screen images and store in files
- X *
- X *========================================================================
- X */
- X
- X#include "cpyright.h"
- X#include "patchlevel.h"
- X
- X#include <stdio.h>
- X
- X#include <X11/Xos.h>
- X#include <X11/Xlib.h>
- X#include <X11/Xutil.h>
- X#include <X11/cursorfont.h>
- X#include <X11/Xatom.h>
- X#include <X11/XWDFile.h>
- X#ifndef CARD32
- X#include <X11/Xmd.h>
- X#endif
- X
- X#define MAX_CELLS 256
- X#define TRUE 1
- X#define FALSE 0
- X
- Xtypedef unsigned char byte;
- Xtypedef unsigned long dw;
- Xtypedef unsigned int word;
- X
- X
- X
- Xtypedef struct {
- X XImage *ximage;
- X word numcells;
- X word red[MAX_CELLS], green[MAX_CELLS], blue[MAX_CELLS];
- X byte used[MAX_CELLS];
- X} imageInfo;
- X
- X
- XDisplay *hDisplay;
- Xint hScreen;
- XWindow hRoot;
- Xint displayCells;
- Xchar *programName;
- Xchar *imageName;
- X
- Xint patchLevel = XGRABSC_PATCHLEVEL;
- Xint verbose;
- X
- Xword nr[MAX_CELLS], ng[MAX_CELLS], nb[MAX_CELLS];
- X
- X
- X
- X
- X
- X
- X/*
- X * Alter colors by setting or clearing bits in rgb values.
- X * This effectively reduces the depth of the image, causing the
- X * number of colors used to be reduced. Equivalent colors are
- X * merged in the image, and the used flags of remapped colors are
- X * cleared.
- X *
- X * The number of eliminated colormap entries is returned. The colormap
- X * is not compressed.
- X */
- XalterPlanes(image, modeIsAnd, bits)
- X imageInfo *image;
- X int modeIsAnd; /* if TRUE, combine mask with AND; if FALSE, use OR */
- X unsigned int bits;
- X{
- X int nc, cidx, ridx, h, w;
- X long p;
- X XImage *ximage = image->ximage;
- X long map[MAX_CELLS];
- X int remapCount;
- X word mask;
- X
- X if (ximage->depth <= 1)
- X return 0;
- X
- X mask = 0xFFFF ^ ((1 << (bits+8)) - 1);
- X if (!modeIsAnd)
- X mask = ~mask & 0xFFFF;
- X
- X if (verbose) {
- X fprintf(stderr, "%s: %s color with mask %x...", programName,
- X modeIsAnd? "ANDing" : "ORing", mask);
- X fflush(stderr);
- X }
- X
- X nc = image->numcells;
- X if (modeIsAnd)
- X for (cidx=0; cidx<nc; cidx++) {
- X nr[cidx] = image->red[cidx] & mask;
- X ng[cidx] = image->green[cidx] & mask;
- X nb[cidx] = image->blue[cidx] & mask;
- X }
- X else
- X for (cidx=0; cidx<nc; cidx++) {
- X nr[cidx] = image->red[cidx] | mask;
- X ng[cidx] = image->green[cidx] | mask;
- X nb[cidx] = image->blue[cidx] | mask;
- X }
- X
- X /* now eliminate redundant colors */
- X for (cidx=0; cidx<nc; cidx++)
- X map[cidx] = cidx;
- X remapCount = 0;
- X for (cidx=0; cidx<nc; cidx++)
- X if (image->used[cidx])
- X for (ridx=cidx+1; ridx<nc; ridx++)
- X if (image->used[ridx] &&
- X nr[cidx]==nr[ridx] &&
- X ng[cidx]==ng[ridx] &&
- X nb[cidx]==nb[ridx]) {
- X /* the colors match - remap this pixel to the one we're scanning with */
- X map[ridx] = cidx;
- X image->used[ridx] = FALSE;
- X remapCount++;
- X }
- X
- X memcpy(image->red, nr, nc*sizeof(word));
- X memcpy(image->green, ng, nc*sizeof(word));
- X memcpy(image->blue, nb, nc*sizeof(word));
- X
- X /* remap redundant pixels in the image */
- X if (remapCount)
- X for (h=0; h<ximage->height; h++)
- X for (w=0; w<ximage->width; w++) {
- X p = XGetPixel(ximage, w, h);
- X if (p != map[p])
- X XPutPixel(ximage, w, h, map[p]);
- X }
- X
- X if (verbose)
- X fprintf(stderr, " %d colors remapped\n", remapCount, nc);
- X return remapCount;
- X}
- X
- X
- X
- X
- X
- X/* Brighten or darken colors in the image by the given amount ('percent').
- X * The amount is an integer that, if less than 100 will darken the image
- X * and if greater than 100 will brighten the image. After modifying
- X * colors equivalent colors are merged (as in alterPlanes). The number
- X * of eliminated colors is returned.
- X */
- XbrightenColors(image, percent)
- X imageInfo *image;
- X int percent;
- X{
- X int nc, cidx, ridx, h, w;
- X long p;
- X XImage *ximage = image->ximage;
- X float adjustment;
- X long map[MAX_CELLS];
- X int remapCount;
- X dw new;
- X
- X if (ximage->depth <= 1)
- X return 0;
- X
- X if (verbose) {
- X fprintf(stderr, "%s: adjusting intensity by %d...", programName, percent);
- X fflush(stderr);
- X }
- X
- X adjustment = (float)percent / 100.0;
- X nc = image->numcells;
- X for (cidx=0; cidx<nc; cidx++) {
- X new = image->red[cidx] * adjustment;
- X if (new > (dw)0xFFFF) new = (dw)0xFFFF;
- X nr[cidx] = new;
- X new = image->green[cidx] * adjustment;
- X if (new > (dw)0xFFFF) new = (dw)0xFFFF;
- X ng[cidx] = new;
- X new = image->blue[cidx] * adjustment;
- X if (new > (dw)0xFFFF) new = (dw)0xFFFF;
- X nb[cidx] = new;
- X }
- X
- X /* now eliminate redundant colors */
- X for (cidx=0; cidx<nc; cidx++)
- X map[cidx] = cidx;
- X remapCount = 0;
- X for (cidx=0; cidx<nc; cidx++)
- X if (image->used[cidx])
- X for (ridx=cidx+1; ridx<nc; ridx++)
- X if (image->used[ridx] &&
- X nr[cidx]==nr[ridx] &&
- X ng[cidx]==ng[ridx] &&
- X nb[cidx]==nb[ridx]) {
- X map[ridx] = cidx;
- X image->used[ridx] = FALSE;
- X remapCount++;
- X }
- X
- X memcpy(image->red, nr, nc*sizeof(word));
- X memcpy(image->green, ng, nc*sizeof(word));
- X memcpy(image->blue, nb, nc*sizeof(word));
- X
- X /* remap redundant pixels in the image */
- X if (remapCount)
- X for (h=0; h<ximage->height; h++)
- X for (w=0; w<ximage->width; w++) {
- X p = XGetPixel(ximage, w, h);
- X if (p != map[p])
- X XPutPixel(ximage, w, h, map[p]);
- X }
- X
- X
- X if (verbose)
- X fprintf(stderr, " %d colors remapped\n", remapCount, nc);
- X
- X return remapCount;
- X}
- X
- X
- X
- X
- X
- X/*
- X * Compress the colors used in an XImage so that all pixel values are
- X * adjacent. Alters the rgb color tables and the XImage data values.
- X */
- XcompressColormap(image)
- X imageInfo *image;
- X{
- X XImage *ximage = image->ximage;
- X long map[MAX_CELLS];
- X int ncolors, w, h, m;
- X long p;
- X
- X if (ximage->depth <= 1 || image->numcells > MAX_CELLS)
- X return;
- X
- X if (verbose) {
- X fprintf(stderr, "%s: compressing colormap...", programName);
- X fflush(stderr);
- X }
- X ncolors = 0;
- X /* map[] is indexed by old pixel values. It delivers new, compressed,
- X * pixel values. */
- X for (m=0; m<MAX_CELLS; m++) map[m] = MAX_CELLS+1;
- X /* bludgeon through the whole image and remap each pixel value */
- X for (h=0; h<ximage->height; h++) {
- X for (w=0; w<ximage->width; w++) {
- X /* Get the pixel index and see if it has been used or not.
- X * Then remap the pixel */
- X p = XGetPixel(ximage, w, h);
- X if (map[p] == MAX_CELLS+1) {
- X map[p] = ncolors;
- X ncolors++;
- X }
- X if (p != map[p])
- X XPutPixel(ximage, w, h, map[p]);
- X }
- X }
- X /* now compress the color table */
- X memset(image->used, 0, MAX_CELLS);
- X for (m=0; m<MAX_CELLS; m++) {
- X if (map[m] != MAX_CELLS+1) {
- X p = map[m];
- X nr[p] = image->red[m];
- X ng[p] = image->green[m];
- X nb[p] = image->blue[m];
- X image->used[p] = TRUE;
- X }
- X }
- X memcpy(image->red, nr, ncolors*sizeof(word));
- X memcpy(image->green, ng, ncolors*sizeof(word));
- X memcpy(image->blue, nb, ncolors*sizeof(word));
- X image->numcells = ncolors;
- X if (verbose)
- X fprintf(stderr, " %d colors used\n", ncolors);
- X}
- X
- X
- X
- X
- X
- X/*
- X * Get the image bounded by the given rectangle.
- X * The associated colormap information is also extracted and returned.
- X * TRUE is returned if an image was successfully grabbed, and FALSE
- X * otherwise.
- X */
- XgetImage(xrect, image)
- X XRectangle *xrect;
- X imageInfo *image;
- X{
- X XImage *ximage;
- X int depth, ncolors, cmapSize, numCmaps;
- X int h, w;
- X long i;
- X XColor colors[MAX_CELLS];
- X Colormap *cmaps, cmap;
- X
- X if (xrect->width == 0 || xrect->height == 0)
- X return FALSE;
- X
- X depth = DefaultDepth(hDisplay, hScreen);
- X ximage = XGetImage(hDisplay, hRoot,
- X xrect->x, xrect->y, xrect->width, xrect->height, AllPlanes,
- X depth==1 ? XYPixmap : ZPixmap);
- X image->ximage = ximage;
- X
- X /* get the colormap info too */
- X
- X cmaps = XListInstalledColormaps(hDisplay, hRoot, &numCmaps);
- X if (numCmaps == 0)
- X cmap = DefaultColormap(hDisplay, hScreen);
- X else {
- X cmap = *cmaps;
- X if (numCmaps > 1)
- X printf(stderr,
- X "%s: more than one colormap found - using first encountered",
- X programName);
- X }
- X XFree(cmaps);
- X
- X ncolors = DisplayCells(hDisplay, hScreen);
- X /* this won't cut the mustard for DirectColor */
- X for (i=0; i<ncolors; i++)
- X colors[i].pixel = i;
- X
- X XQueryColors(hDisplay, cmap, colors, ncolors);
- X for (i=0; i<ncolors; i++) {
- X image->red[i] = colors[i].red;
- X image->green[i] = colors[i].green;
- X image->blue[i] = colors[i].blue;
- X }
- X
- X /* figure out which colormap entries are actually used by the image */
- X ncolors = cmapSize = 0;
- X memset(image->used, 0, MAX_CELLS);
- X for (h=0; h<ximage->height; h++)
- X for (w=0; w<ximage->width; w++) {
- X i = XGetPixel(ximage, w, h);
- X if (!image->used[i]) {
- X image->used[i] = TRUE;
- X if (i+1 > cmapSize) /* keep track of colormap size */
- X cmapSize = i+1;
- X ncolors++;
- X }
- X }
- X image->numcells = cmapSize;
- X if (verbose)
- X fprintf(stderr, "%s: image has %d colors\n", programName, ncolors);
- X
- X return TRUE;
- X}
- X
- X
- X
- X/*
- X * Let the user stretch a rectangle on the screen and return its values.
- X * It may be wise to grab the server before calling this routine. If the
- X * screen is allowed to change during XOR drawing video droppings may result.
- X */
- XgetRectangle(xrect)
- X XRectangle *xrect;
- X{
- X XEvent event;
- X unsigned int mask, x, y, rootx, rooty;
- X GC gc;
- X Cursor pointer;
- X int boxDrawn = False;
- X int rx, ry, rw, rh;
- X Window root, child;
- X int discarded;
- X
- X /* get some cursors for rectangle formation */
- X pointer = XCreateFontCursor(hDisplay, XC_crosshair);
- X
- X /* grab the pointer */
- X if (GrabSuccess != XGrabPointer(hDisplay, hRoot, False, ButtonPressMask,
- X GrabModeAsync, GrabModeAsync, hRoot, pointer, CurrentTime)) {
- X fprintf(stderr,"%s - could not grab pointer!\n", programName);
- X exit(3);
- X }
- X
- X /* create a graphics context to draw with */
- X gc = XCreateGC(hDisplay, hRoot, 0, NULL);
- X if (!gc) {
- X fprintf(stderr,"%s - could not get drawing resources\n", programName);
- X exit(3);
- X }
- X XSetSubwindowMode(hDisplay, gc, IncludeInferiors);
- X XSetForeground(hDisplay, gc, 255);
- X XSetFunction(hDisplay, gc, GXxor);
- X
- X /* get a button-press and pull out the root location */
- X XMaskEvent(hDisplay, ButtonPressMask, &event);
- X rootx = rx = event.xbutton.x_root;
- X rooty = ry = event.xbutton.y_root;
- X
- X /* get pointer motion events */
- X XChangeActivePointerGrab(hDisplay, ButtonMotionMask | ButtonReleaseMask,
- X pointer, CurrentTime);
- X
- X
- X /* MAKE_RECT converts the original root coordinates and the event root
- X * coordinates into a rectangle in xrect */
- X#define MAKE_RECT(etype) \
- X x = event.etype.x_root; \
- X y = event.etype.y_root; \
- X rw = x - rootx; \
- X if (rw < 0) rw = -rw; \
- X rh = y - rooty; \
- X if (rh < 0) rh = -rh; \
- X rx = x < rootx ? x : rootx; \
- X ry = y < rooty ? y : rooty
- X
- X /* loop to let the user drag a rectangle */
- X while (TRUE) {
- X XNextEvent(hDisplay, &event);
- X switch(event.type) {
- X case ButtonRelease:
- X if (boxDrawn) {
- X XDrawRectangle(hDisplay, hRoot, gc, rx, ry, rw, rh);
- X boxDrawn = False;
- X }
- X XFlush(hDisplay);
- X /* record the final location */
- X MAKE_RECT(xbutton);
- X /* release resources */
- X XFreeGC(hDisplay, gc);
- X XFreeCursor(hDisplay, pointer);
- X xrect->x = rx;
- X xrect->y = ry;
- X xrect->width = rw;
- X xrect->height = rh;
- X XUngrabPointer(hDisplay, CurrentTime);
- X if (verbose)
- X fprintf(stderr, "%s: rectangle is %d@%d, %dx%d\n", programName,
- X xrect->x, xrect->y, xrect->width, xrect->height);
- X return True;
- X case MotionNotify:
- X if (boxDrawn) {
- X XDrawRectangle(hDisplay, hRoot, gc, rx, ry, rw, rh);
- X boxDrawn = False;
- X }
- X /* discard incoming motion notifies while we handle this one */
- X discarded = False;
- X while (XCheckTypedEvent(hDisplay, MotionNotify, &event))
- X {}
- X MAKE_RECT(xmotion);
- X XDrawRectangle(hDisplay, hRoot, gc, rx, ry, rw, rh);
- X boxDrawn = True;
- X break;
- X }
- X }
- X}
- X
- X
- X
- X
- X/*
- X * convert a pixmap image into a bitmap image
- X */
- Xpixmap2bitmap(image)
- X imageInfo *image;
- X{
- X XImage *ximage = image->ximage;
- X int x, y;
- X word v, black, mid;
- X dw total, blackrgb, midrgb, lowDelta, l;
- X XImage *newImage;
- X byte *newBytes;
- X int usedCount;
- X
- X if (ximage->bits_per_pixel == 1 || image->numcells < 1)
- X return;
- X
- X /* get the darkest color */
- X blackrgb = 0x2FFFD; /* 3 * 0xFFFF == white */
- X usedCount = total = 0;
- X for (x=0; x<image->numcells; x++) {
- X if (image->used[x]) {
- X l = (unsigned)image->red[x]
- X +(unsigned)image->green[x]
- X +(unsigned)image->blue[x];
- X if (l <= blackrgb) {
- X black = x;
- X blackrgb = l;
- X }
- X total += l;
- X usedCount++;
- X }
- X }
- X /* now find the mid color and use it as the cut-off for black */
- X midrgb = total / usedCount;
- X lowDelta = 0x2FFFD;
- X for (x=0; x<image->numcells; x++) {
- X if (image->used[x]) {
- X l = (unsigned)image->red[x]
- X +(unsigned)image->green[x]
- X +(unsigned)image->blue[x];
- X l -= midrgb;
- X if (l < lowDelta) {
- X mid = x;
- X lowDelta = l;
- X }
- X }
- X }
- X midrgb = (unsigned)image->red[mid]
- X +(unsigned)image->green[mid]
- X +(unsigned)image->blue[mid];
- X
- X /* create a bitmap image */
- X x = (ximage->width + 7) / 8;
- X newBytes = (byte *)malloc(x * ximage->height);
- X memset(newBytes, 0, x * ximage->height);
- X newImage = XCreateImage(hDisplay, DefaultVisual(hDisplay, hScreen),
- X 1, XYBitmap, 0, newBytes, ximage->width, ximage->height,
- X 0, x);
- X if (!newImage) {
- X fprintf(stderr, "%s: unable to create bitmap for conversion\n",
- X programName);
- X XCloseDisplay(hDisplay);
- X exit(3);
- X }
- X /* pound the pixels into it */
- X for (y = 0; y < ximage->height; y++) {
- X for (x = 0; x < ximage->width; x++) {
- X v = XGetPixel(ximage, x, y);
- X l = (dw)image->red[v]+(dw)image->green[v]+(dw)image->blue[v];
- X XPutPixel(newImage, x, y, l<midrgb? 1 : 0);
- X }
- X }
- X free(ximage->data);
- X memcpy(ximage, newImage, sizeof(XImage));
- X free(newImage);
- X
- X image->numcells = 0;
- X}
- X
- X
- X
- X
- X
- X
- X
- X#define GRAYS 17 /* ((4 * 4) + 1) patterns for a good dither */
- X#define GRAYSTEP ((dw)(65536 * 3) / GRAYS)
- X
- Xstatic byte DitherBits[GRAYS][4] = {
- X 0xf, 0xf, 0xf, 0xf,
- X 0xe, 0xf, 0xf, 0xf,
- X 0xe, 0xf, 0xb, 0xf,
- X 0xa, 0xf, 0xb, 0xf,
- X 0xa, 0xf, 0xa, 0xf,
- X 0xa, 0xd, 0xa, 0xf,
- X 0xa, 0xd, 0xa, 0x7,
- X 0xa, 0x5, 0xa, 0x7,
- X 0xa, 0x5, 0xa, 0x5,
- X 0x8, 0x5, 0xa, 0x5,
- X 0x8, 0x5, 0x2, 0x5,
- X 0x0, 0x5, 0x2, 0x5,
- X 0x0, 0x5, 0x0, 0x5,
- X 0x0, 0x4, 0x0, 0x5,
- X 0x0, 0x4, 0x0, 0x1,
- X 0x0, 0x0, 0x0, 0x1,
- X 0x0, 0x0, 0x0, 0x0
- X};
- X
- Xstatic byte DitherRevBits[GRAYS][4] = { /* DitherBits with LSBFirst */
- X 0xf, 0xf, 0xf, 0xf,
- X 0x7, 0xf, 0xf, 0xf,
- X 0x7, 0xf, 0xd, 0xf,
- X 0x5, 0xf, 0xd, 0xf,
- X 0x5, 0xf, 0x5, 0xf,
- X 0x5, 0xb, 0x5, 0xf,
- X 0x5, 0xb, 0x5, 0xe,
- X 0x5, 0xa, 0x5, 0xe,
- X 0x5, 0xa, 0x5, 0xa,
- X 0x1, 0xa, 0x5, 0xa,
- X 0x1, 0xa, 0x4, 0xa,
- X 0x0, 0xa, 0x4, 0xa,
- X 0x0, 0xa, 0x0, 0xa,
- X 0x0, 0x2, 0x0, 0xa,
- X 0x0, 0x2, 0x0, 0x8,
- X 0x0, 0x0, 0x0, 0x8,
- X 0x0, 0x0, 0x0, 0x0
- X};
- X
- X/* halftone or dither a color image, changing it into a monochrome
- X * image
- X */
- Xpixmap2halftone(image, dither)
- X imageInfo *image;
- X int dither; /* if TRUE, dither instead of halftone */
- X{
- X XImage *ximage = image->ximage;
- X XImage *newImage;
- X byte *newBytes, *dp, *ditherBits;
- X word dindex; /* index into dither array */
- X dw color; /* pixel color */
- X word *index; /* index into dither array for a given pixel */
- X word x, y; /* random counters */
- X word x4, y4;
- X word w, h;
- X int reversed;
- X register byte *dp2;
- X register byte bits;
- X
- X if (verbose) {
- X fprintf(stderr, "%s: %sing image...", programName,
- X dither? "dither" : "halfton");
- X fflush(stderr);
- X }
- X
- X /* create a bitmap image */
- X w = (ximage->width + 7) / 8;
- X if (!dither) w *= 4;
- X h = dither? ximage->height : ximage->height * 4;
- X newBytes = (byte *)malloc(w * h);
- X memset(newBytes, 0, w * h);
- X newImage = XCreateImage(hDisplay, DefaultVisual(hDisplay, hScreen),
- X 1, XYBitmap, 0, newBytes,
- X ximage->width * (dither? 1 : 4),
- X ximage->height * (dither? 1 : 4),
- X 0, w);
- X if (!newImage) {
- X fprintf(stderr, "%s: unable to create bitmap for conversion\n",
- X programName);
- X XCloseDisplay(hDisplay);
- X exit(3);
- X }
- X
- X
- X /* if the number of possible pixels isn't very large, build an array
- X * which we index by the pixel value to find the dither array index
- X * by color brightness. we do this in advance so we don't have to do
- X * it for each pixel. things will break if a pixel value is greater
- X * than (1 << depth), which is bogus anyway. this calculation is done
- X * on a per-pixel basis if the colormap is too big.
- X */
- X
- X if (ximage->depth <= 16) {
- X index= (word *)malloc(sizeof(word) * MAX_CELLS);
- X if (index)
- X for (x= 0; x < image->numcells; x++) {
- X index[x] =
- X ((dw)(image->red[x])
- X + (dw)(image->green[x])
- X + (dw)(image->blue[x]) ) / GRAYSTEP;
- X if (index[x] >= GRAYS)
- X index[x] = GRAYS - 1;
- X }
- X }
- X else
- X index= NULL;
- X
- X /* dither each pixel
- X */
- X reversed = newImage->bitmap_bit_order == LSBFirst;
- X for (y= 0; y < ximage->height; y++) {
- X for (x= 0; x < ximage->width; x++) {
- X color = XGetPixel(ximage, x, y);
- X if (index)
- X dindex= index[color];
- X else {
- X dindex= ((dw)image->red[color]
- X +(dw)image->green[color]
- X +(dw)image->blue[color] ) / GRAYSTEP;
- X if (dindex >= GRAYS) /* catch rounding errors */
- X dindex= GRAYS - 1;
- X }
- X if (dither) {
- X if (DitherBits[dindex][y & 3] & (1 << (x & 3)))
- X XPutPixel(newImage, x, y, 1);
- X }
- X else { /* halftone */
- X /* loop for the four Y bits in the dither pattern, putting all
- X * four X bits in at once. if you think this would be hard to
- X * change to be an NxN dithering array, you're right, since we're
- X * banking on the fact that we need only shift the mask based on
- X * whether x is odd or not. an 8x8 array wouldn't even need that,
- X * but blowing an image up by 64x is probably not a feature.
- X */
- X ditherBits = reversed? &(DitherRevBits[dindex][0])
- X : &(DitherBits[dindex][0]);
- X x4 = x * 4;
- X y4 = y * 4;
- X for (h= 0; h < 4; h++) {
- X bits = ditherBits[h];
- X for (w=0; w < 4; w++)
- X XPutPixel(newImage, x4+w, y4+h, (bits >> 0) & 1);
- X }
- X }
- X }
- X if (dither)
- X dp += newImage->bytes_per_line;
- X else
- X dp += 4 * newImage->bytes_per_line;
- X }
- X if (verbose)
- X fputc('\n', stderr);
- X
- X free(ximage->data);
- X memcpy(ximage, newImage, sizeof(XImage));
- X free(newImage);
- X if (index)
- X free(index);
- X
- X image->numcells = 0;
- X}
- X
- X
- X
- X
- X
- X/* swap the bits in a byte */
- Xswapbits(b)
- X byte b;
- X{
- X byte b2;
- X
- X b2 = 0;
- X b2 |= (b & 0x01) << 7;
- X b2 |= (b & 0x02) << 5;
- X b2 |= (b & 0x04) << 3;
- X b2 |= (b & 0x08) << 1;
- X b2 |= (b & 0x10) >> 1;
- X b2 |= (b & 0x20) >> 3;
- X b2 |= (b & 0x40) >> 5;
- X b2 |= (b & 0x80) >> 7;
- X return b2;
- X}
- X
- X
- X
- X
- X/* swap the bytes in a long int */
- Xswapbytes(pDblw)
- X dw *pDblw;
- X {
- X union {
- X dw dbl;
- X byte bytes[4];
- X } cnv;
- X byte aByte;
- X
- X cnv.dbl = *pDblw;
- X aByte = cnv.bytes[0];
- X cnv.bytes[0] = cnv.bytes[3];
- X cnv.bytes[3] = aByte;
- X aByte = cnv.bytes[1];
- X cnv.bytes[1] = cnv.bytes[2];
- X cnv.bytes[2] = aByte;
- X *pDblw = cnv.dbl;
- X }
- X
- X
- X
- X/* swap some long ints */
- Xswapdws (bp, n)
- X register char *bp;
- X register unsigned n;
- X{
- X register char c;
- X register char *ep = bp + n;
- X register char *sp;
- X
- X while (bp < ep) {
- X sp = bp + 3;
- X c = *sp;
- X *sp = *bp;
- X *bp++ = c;
- X sp = bp + 1;
- X c = *sp;
- X *sp = *bp;
- X *bp++ = c;
- X bp += 2;
- X }
- X}
- X
- X
- X
- X/* swap some short ints */
- Xswapwords (bp, n)
- X register char *bp;
- X register unsigned n;
- X{
- X register char c;
- X register char *ep = bp + n;
- X
- X while (bp < ep) {
- X c = *bp;
- X *bp = *(bp + 1);
- X bp++;
- X *bp++ = c;
- X }
- X}
- X
- X
- X
- X
- X
- X/*
- X * Write an image in Postscript format
- X */
- XwritePostscript(image, outfile)
- X imageInfo *image;
- X{
- X XImage *ximage = image->ximage;
- X XImage *psimage;
- X double xdpi, ydpi, xscale, yscale;
- X byte b, *ptr, lmax;
- X int lm3;
- X int x, y, i;
- X int depth, bpl, spb;
- X int reverse;
- X int rle, firstrle;
- X byte rlecount, rlebyte;
- X dw rletotal;
- X long p;
- X
- X if (verbose)
- X fprintf(stderr, "%s: formatting Postscript output\n", programName);
- X
- X /* use depth as the number of bits in output samples */
- X depth = ximage->depth;
- X /* postscript only supports 1, 2, 4, or 8 */
- X if (depth > 8) depth = 8; /* max postscript bits/sample */
- X if (depth < 8 && depth > 4) depth = 8;
- X if (depth == 3) depth = 4;
- X
- X bpl = ((ximage->width * depth) + 7) / 8;
- X
- X if (depth == 1)
- X psimage = ximage;
- X else {
- X /* colors have to be changed to luminescence */
- X ptr = (byte *)malloc(ximage->height * bpl);
- X psimage = XCreateImage(hDisplay, DefaultVisual(hDisplay, hScreen),
- X depth, depth>1? ZPixmap : XYPixmap,
- X 0, ptr,
- X ximage->width, ximage->height,
- X 0, bpl);
- X if (!psimage) {
- X fprintf(stderr, "%s: could not create image for Postscript conversion\n",
- X programName);
- X exit(3);
- X }
- X }
- X
- X spb = 8 / psimage->bits_per_pixel; /* samples per byte */
- X
- X if (depth > 1) {
- X /* translate colors into luminescence */
- X lmax = (1 << psimage->bits_per_pixel) - 1;
- X lm3 = 3 * lmax;
- X for (y = 0; y < ximage->height; y++) {
- X for (x = 0; x < ximage->width; x++) {
- X p = XGetPixel(ximage, x, y);
- X i = (dw)image->red[p]+(dw)image->green[p]+(dw)image->blue[p];
- X i = (i * lmax) / lm3;
- X XPutPixel(psimage, x, y, i);
- X }
- X }
- X }
- X
- X /* see if the image will benefit from run-length encoding */
- X rlecount = 0xff;
- X rletotal = 0;
- X for (y=0; y<psimage->height; y++) {
- X for (x=0, ptr=(byte *)(psimage->data+(y * psimage->bytes_per_line));
- X x<psimage->width;
- X x+=spb, ptr++) {
- X b = *ptr;
- X if (b != rlebyte || rlecount == 0xff) {
- X rletotal += 2;
- X rlecount = 0;
- X rlebyte = b;
- X }
- X else
- X rlecount++;
- X }
- X }
- X rle = rletotal < psimage->height * bpl;
- X
- X fprintf(outfile, "%%!\n");
- X fprintf(outfile, "%%\n");
- X fprintf(outfile, "%% Xgrabsc Postscript dump of image '%s'\n", imageName);
- X fprintf(outfile, "%%\n");
- X fprintf(outfile, "%%\n");
- X
- X if (rle) {
- X fprintf(outfile, "%% run-length encoded. Savings = %d bytes\n",
- X (psimage->height * bpl - rletotal) * 2);
- X fprintf(outfile, "%%\n");
- X fprintf(outfile, "%%\n");
- X }
- X
- X /* standard inch procedure */
- X fputs("/inch {72 mul} def\n", outfile);
- X
- X /* define a string to hold image lines */
- X fprintf(outfile, "/picstr %d string def\n", bpl);
- X
- X /* define a string to hold run-length-encoded pairs */
- X if (rle)
- X fputs("/rlebuffer 2 string def\n", outfile);
- X
- X /* define the image plotting procedure */
- X fputs("/plotimage\n", outfile);
- X
- X /* parameters for the standard image procedure */
- X fprintf(outfile, " {%d %d %d [%d 0 0 -%d 0 %d]\n",
- X psimage->width, psimage->height, psimage->bits_per_pixel,
- X psimage->width, psimage->height, psimage->height);
- X
- X /* line reading function */
- X if (rle) {
- X fputs(" { currentfile rlebuffer readhexstring pop pop\n", outfile);
- X fputs(" /nsamples rlebuffer 0 get 1 add store\n", outfile);
- X fputs(" /lum rlebuffer 1 get store\n", outfile);
- X fputs(" /samples nsamples string store\n", outfile);
- X fputs(" 0 1 nsamples -1 add { samples exch lum put } for\n",
- X outfile);
- X fputs(" samples\n", outfile);
- X fputs(" }\n", outfile);
- X }
- X else
- X fputs(" {currentfile picstr readhexstring pop}\n", outfile);
- X
- X fputs(" image\n} def\n", outfile);
- X
- X
- X /* save context and move to a nice origin */
- X fputs("gsave\n", outfile);
- X
- X
- X /* scale the image */
- X xdpi = (((double)DisplayWidth(hDisplay,hScreen)) * 25.4) /
- X ((double)DisplayWidthMM(hDisplay,hScreen));
- X ydpi = (((double)DisplayHeight(hDisplay,hScreen)) * 25.4) /
- X ((double)DisplayHeightMM(hDisplay,hScreen));
- X xscale = ((double)psimage->width) / xdpi;
- X yscale = ((double)psimage->height) / ydpi;
- X if (xscale > 7.5) {
- X yscale *= 7.5 / xscale;
- X xscale = 7.5;
- X }
- X else if (yscale > 10.0) {
- X xscale *= 10.0 / yscale;
- X yscale = 10.0;
- X }
- X fprintf(outfile, "%1.2g inch %1.2g inch translate\n",
- X (8.5 - xscale) / 2.0, (11.0 - yscale) / 2.0);
- X fprintf(outfile, "%1.2g inch %1.2g inch scale\n", xscale, yscale);
- X
- X fputs("plotimage\n", outfile);
- X
- X
- X reverse = depth == 1? BlackPixel(hDisplay,hScreen)==1 : FALSE;
- X rletotal = 0;
- X rlecount = 0xff;
- X for (y=0; y<psimage->height; y++) {
- X for (x=0, ptr=(byte *)(psimage->data+(y * psimage->bytes_per_line));
- X x<psimage->width;
- X x+=spb, ptr++) {
- X b = *ptr;
- X if (reverse) b = ~b;
- X if (depth == 1 && psimage->bitmap_bit_order == LSBFirst)
- X b = swapbits(b);
- X if (rle) {
- X if (b != rlebyte || rlecount == 0xff) {
- X if (rletotal) /* == 0 first time through main loop */
- X fprintf(outfile, "%02x%02x", rlecount, rlebyte);
- X rletotal += 2;
- X if (rletotal % 200 == 0)
- X fputs("\n", outfile);
- X rlecount = 0;
- X rlebyte = b;
- X }
- X else
- X rlecount++;
- X }
- X else
- X fprintf(outfile, "%02x", b);
- X }
- X if (!rle)
- X fputs("\n", outfile);
- X }
- X if (rle && rletotal)
- X fprintf(outfile, "%02x%02x\n", rlecount, rlebyte);
- X
- X fputs("\n\n\ngrestore\nshowpage\n", outfile);
- X
- X
- X if (psimage != ximage) {
- X free(psimage->data);
- X free(psimage);
- X }
- X}
- X
- X
- X
- X
- X
- X
- X
- X
- X
- X/*
- X * Write an image in 'puzzle' format, suitable for loading with
- X * "puzzle -picture".
- X */
- XwritePuzzle(image, outfile)
- X imageInfo *image;
- X FILE *outfile;
- X{
- X XImage *ximage = image->ximage;
- X int nc, width, height, w, h, cidx;
- X dw swaptest = 1;
- X
- X if (verbose)
- X fprintf(stderr, "%s: formatting Puzzle output\n", programName);
- X
- X if (ximage->depth > 8) {
- X fprintf(stderr, "%s: Puzzle converter can't handle depth > 8 yet\n",
- X programName);
- X return;
- X }
- X
- X nc = image->numcells;
- X width = ximage->width;
- X height = ximage->height;
- X if (*(char *)&swaptest) {
- X swapbytes(&width);
- X swapbytes(&height);
- X }
- X fwrite(&width, 4, 1, outfile);
- X fwrite(&height, 4, 1, outfile);
- X fputc(nc, outfile);
- X for (cidx=0; cidx<nc; cidx++) {
- X fputc(image->red[cidx]>>8, outfile);
- X fputc(image->green[cidx]>>8, outfile);
- X fputc(image->blue[cidx]>>8, outfile);
- X }
- X for (h=0; h<ximage->height; h++)
- X if (ximage->bits_per_pixel == 8)
- X fwrite(ximage->data+(h*ximage->bytes_per_line),ximage->width,1,outfile);
- X else
- X /* this won't work if depth > 8 */
- X for (w=0; w<ximage->width; w++)
- X fputc(XGetPixel(ximage, w, h), outfile);
- X}
- X
- X
- X
- X
- X
- X
- X
- XwriteXWD(image, outfile)
- X imageInfo *image;
- X FILE *outfile;
- X{
- X XImage *ximage = image->ximage;
- X XWDFileHeader header;
- X Visual *visual = DefaultVisual(hDisplay, hScreen);
- X XColor color;
- X dw visMask = (visual->red_mask
- X | visual->green_mask
- X | visual->blue_mask);
- X dw swaptest = 1;
- X int i;
- X
- X if (verbose)
- X fprintf(stderr, "%s: formatting xwd output\n", programName);
- X
- X header.header_size = (CARD32)(sizeof(header)+strlen(imageName)+1);
- X header.file_version = (CARD32) XWD_FILE_VERSION;
- X header.pixmap_format = (CARD32)(ximage->depth>1? ZPixmap : XYPixmap);
- X header.pixmap_depth = (CARD32) ximage->depth;
- X header.pixmap_width = (CARD32) ximage->width;
- X header.pixmap_height = (CARD32) ximage->height;
- X header.xoffset = (CARD32) ximage->xoffset;
- X header.byte_order = (CARD32) ximage->byte_order;
- X header.bitmap_unit = (CARD32) ximage->bitmap_unit;
- X header.bitmap_bit_order = (CARD32) ximage->bitmap_bit_order;
- X header.bitmap_pad = (CARD32) ximage->bitmap_pad;
- X header.bits_per_pixel = (CARD32) ximage->bits_per_pixel;
- X header.bytes_per_line = (CARD32) ximage->bytes_per_line;
- X header.visual_class = (CARD32)visual->class;
- X header.red_mask = (CARD32)visual->red_mask;
- X header.green_mask = (CARD32)visual->green_mask;
- X header.blue_mask = (CARD32)visual->blue_mask;
- X header.bits_per_rgb = (CARD32)visual->bits_per_rgb;
- X header.colormap_entries = (CARD32)visual->map_entries;
- X header.ncolors = image->numcells;
- X header.window_width = (CARD32)ximage->width;
- X header.window_height = (CARD32)ximage->height;
- X header.window_x = 0;
- X header.window_y = 0;
- X header.window_bdrwidth = 0;
- X
- X if (*(char *) &swaptest)
- X swapdws(&header, sizeof(header));
- X
- X fwrite(&header, sizeof(header), 1, outfile);
- X fwrite(imageName, 1, strlen(imageName)+1, outfile);
- X
- X for (i=0; i<image->numcells; i++) {
- X color.pixel = i;
- X color.red = image->red[i];
- X color.green = image->green[i];
- X color.blue = image->blue[i];
- X color.flags = visMask;
- X color.pad = 0;
- X if (*(char *) &swaptest)
- X swapwords(&color, sizeof(XColor));
- X fwrite(&color, sizeof(XColor), 1, outfile);
- X }
- X
- X fwrite(ximage->data, ximage->height * ximage->bytes_per_line, 1, outfile);
- X}
- X
- X
- X
- X
- X
- X/*
- X * Write a monochrome image out in Bitmap format. XWriteBitmapToFile
- X * requires a Pixmap as input & we'd have to invent one before we could
- X * use it.
- X */
- X
- XwriteXYPixmap(image, outfile)
- X imageInfo *image;
- X FILE *outfile;
- X{
- X XImage *ximage = image->ximage;
- X int w, h;
- X byte b, *line;
- X int lcount;
- X int reverse = BlackPixel(hDisplay, hScreen) == 0;
- X int swap = ximage->bitmap_bit_order != LSBFirst;
- X
- X if (verbose)
- X fprintf(stderr, "%s: formatting Bitmap output\n", programName);
- X
- X if (ximage->depth != 1) {
- X fprintf(stderr, "%s: can't write polychrome images in XY bitmap format\n",
- X programName);
- X return;
- X }
- X
- X fprintf(outfile, "#define %s_width %d\n", imageName, ximage->width);
- X fprintf(outfile, "#define %s_height %d\n", imageName, ximage->height);
- X fprintf(outfile, "#define %s_x_hot 0\n", imageName);
- X fprintf(outfile, "#define %s_y_hot 0\n", imageName);
- X fprintf(outfile, "static char %s_bits[] = {\n", imageName);
- X lcount = 0;
- X fputs(" ", outfile);
- X for (h=0; h<ximage->height; h++) {
- X line = (byte *)(ximage->data + (h * ximage->bytes_per_line));
- X for (w=0; w<ximage->width; w+=8) {
- X b = line[w/8];
- X if (reverse) b = ~b;
- X if (swap) b = swapbits(b);
- X fprintf(outfile, " 0x%02x", b);
- X if (h<ximage->height || w+8<ximage->width)
- X fputc(',', outfile);
- X lcount++;
- X if (lcount >= 12) {
- X fputs("\n ", outfile);
- X lcount = 0;
- X }
- X }
- X }
- X fputs(" };\n", outfile);
- X}
- X
- X
- X
- X
- X
- X
- X
- X
- X/*
- X * Write a color image out in Pixmap format, suitable for loading with
- X * "xpd" or "xloadimage". Note that "xpd" usually fails miserably if
- X * the image is wider than 255 characters in the output file.
- X */
- XwriteZPixmap(image, outfile)
- X imageInfo *image;
- X FILE *outfile;
- X{
- X XImage *ximage = image->ximage;
- X int nc, width, height, w, h, cidx, cpp;
- X char mne[MAX_CELLS][3];
- X
- X if (verbose)
- X fprintf(stderr, "%s: formatting Pixmap output\n", programName);
- X
- X nc = image->numcells;
- X cpp = image->numcells <= 26? 1 : 2;
- X fprintf(outfile, "#define %s_format 1\n", imageName);
- X fprintf(outfile, "#define %s_width %d\n", imageName, ximage->width);
- X fprintf(outfile, "#define %s_height %d\n", imageName, ximage->height);
- X fprintf(outfile, "#define %s_ncolors %d\n", imageName, image->numcells);
- X fprintf(outfile, "#define %s_chars_per_pixel %d\n", imageName, cpp);
- X fprintf(outfile, "static char * %s_colors[] = {\n", imageName);
- X for (cidx=0; cidx<image->numcells; cidx++) {
- X if (cpp > 1) {
- X mne[cidx][0] = (char)(cidx / 10) + 'a';
- X mne[cidx][1] = (char)(cidx % 10) + '0';
- X mne[cidx][2] = '\0';
- X }
- X else {
- X mne[cidx][0] = (char)cidx + (cidx? 'A' : ' ');
- X mne[cidx][1] = '\0';
- X }
- X fprintf(outfile, "\"%s\", \"#%4.4x%4.4x%4.4x\"\n", mne[cidx],
- X image->red[cidx], image->green[cidx], image->blue[cidx]);
- X }
- X fputs("} ;\n", outfile);
- X fprintf(outfile, "static char * %s_pixels[] = {\n", imageName);
- X for (h=0; h<ximage->height; h++) {
- X fputs("\"", outfile);
- X for (w=0; w<ximage->width; w++)
- X fputs(mne[XGetPixel(ximage, w, h)], outfile);
- X fputs("\",\n", outfile);
- X }
- X fputs("} ;\n", outfile);
- X}
- X
- X
- X
- X
- X
- X
- X
- X
- Xmain(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X FILE *outfile;
- X char *outfileName;
- X XRectangle xrect;
- X imageInfo image;
- X int doAnd, doOr, depth;
- X int puzzle, xWD, brighten, postscript;
- X int forceBitmap, grabServer;
- X int dither, halftone;
- X int sleepSeconds;
- X int andBits, orBits;
- X char c;
- X char *ptr;
- X char *display;
- X int i, nr, nc;
- X extern char *optarg;
- X int brightenFactor;
- X
- X outfile = stdout;
- X outfileName = NULL;
- X programName = argv[0];
- X puzzle = FALSE;
- X xWD = FALSE;
- X brighten = FALSE;
- X forceBitmap = FALSE;
- X halftone = FALSE;
- X dither = FALSE;
- X grabServer = TRUE;
- X postscript = FALSE;
- X doAnd = FALSE;
- X doOr = FALSE;
- X sleepSeconds= 0;
- X display = NULL;
- X verbose = FALSE;
- X
- X while ((c = getopt(argc, argv, "d:no:s:v b:A:BDHO: PWZ")) != EOF)
- X switch (c) {
- X case 'd':
- X display = optarg;
- X break;
- X case 'n':
- X grabServer = FALSE;
- X break;
- X case 'o':
- X outfileName = optarg;
- X break;
- X case 's':
- X sleepSeconds = atoi(optarg);
- X if (sleepSeconds < 0) sleepSeconds = 0;
- X break;
- X case 'v':
- X verbose = TRUE;
- X break;
- X
- X
- X
- X
- X case 'A':
- X andBits = atoi(optarg);
- X doAnd = TRUE;
- X break;
- X case 'b':
- X brightenFactor = atoi(optarg);
- X if (brightenFactor <= 0) {
- X fprintf(stderr, "%s: brightening factor must be a positive number\n",
- X programName);
- X exit(3);
- X }
- X brighten = TRUE;
- X break;
- X case 'B':
- X forceBitmap = TRUE;
- X break;
- X case 'D':
- X dither = TRUE;
- X if (halftone) {
- X fprintf(stderr,
- X "%s: both dither and halftone requested. Ignoring halftone.",
- X programName);
- X halftone = FALSE;
- X }
- X break;
- X case 'H':
- X halftone = TRUE;
- X if (dither) {
- X fprintf(stderr,
- X "%s: both dither and halftone requested. Ignoring halftone.",
- X programName);
- X halftone = FALSE;
- X }
- X break;
- X case 'O':
- X orBits = atoi(optarg);
- X doOr = TRUE;
- X break;
- X
- X
- X
- X
- X case 'P':
- X postscript = TRUE;
- X if (xWD | puzzle) {
- X fprintf(stderr,
- X "%s: only one output format allowed. Using postscript.\n",
- X programName);
- X xWD = puzzle = FALSE;
- X }
- X break;
- X case 'W':
- X xWD = TRUE;
- X if (puzzle | postscript) {
- X fprintf(stderr,
- X "%s: can't do both puzzle and XWD output. Using XWD.\n",
- X programName);
- X puzzle = postscript = FALSE;
- X }
- X break;
- X case 'Z':
- X puzzle = TRUE;
- X if (xWD | postscript) {
- X fprintf(stderr,
- X "%s: only one output format allowed. Using puzzle.\n",
- X programName);
- X xWD = postscript = FALSE;
- X }
- X break;
- X }
- X
- X if (!display) display = (char *)getenv("DISPLAY");
- X hDisplay = XOpenDisplay(display);
- X if (!hDisplay) {
- X fprintf(stderr, "%s: could not open X display\n", programName);
- X exit(3);
- X }
- X hScreen = DefaultScreen(hDisplay);
- X hRoot = DefaultRootWindow(hDisplay);
- X
- X depth = DefaultDepth(hDisplay, hScreen);
- X if (DisplayCells(hDisplay, hScreen) > MAX_CELLS) {
- X fprintf(stderr, "%s: color table is too big for this program\n",
- X programName);
- X XCloseDisplay(hDisplay);
- X exit(3);
- X }
- X
- X /* sleep if asked to do so */
- X if (sleepSeconds)
- X sleep(sleepSeconds);
- X
- X /* grab the screen if asked to do so */
- X if (grabServer)
- X XGrabServer(hDisplay);
- X
- X /* let the user drag out a rectangle on the screen */
- X if (!getRectangle(&xrect)) {
- X XCloseDisplay(hDisplay);
- X exit(3);
- X }
- X
- X /* get the image bounded by the rectangle */
- X if (!getImage(&xrect, &image)) {
- X XCloseDisplay(hDisplay);
- X exit(3);
- X }
- X
- X if (grabServer) {
- X XUngrabServer(hDisplay);
- X XFlush(hDisplay);
- X }
- X
- X /* do color image processing/conversions */
- X if (depth >= 2) {
- X if (brighten)
- X brightenColors(&image, brightenFactor);
- X if (doAnd)
- X alterPlanes(&image, TRUE, andBits);
- X if (doOr)
- X alterPlanes(&image, FALSE, orBits);
- X
- X if (forceBitmap) {
- X pixmap2bitmap(&image);
- X depth = 1;
- X }
- X else if (halftone | dither)
- X pixmap2halftone(&image, dither);
- X else
- X compressColormap(&image);
- X }
- X
- X
- X /* open the output stream */
- X if (outfileName) {
- X outfile = fopen(outfileName, "w");
- X if (!outfile) {
- X fprintf(stderr, "%s: ", programName);
- X perror(outfileName);
- X exit(3);
- X }
- X ptr = rindex(outfileName, '.');
- X if (ptr) *ptr = '\0';
- X imageName = rindex(outfileName, '/');
- X if (imageName) imageName++;
- X else imageName = outfileName;
- X }
- X else
- X imageName = "unnamed"; /* default for image names */
- X
- X
- X /* garbage in --> garbage out */
- X if (postscript)
- X writePostscript(&image, outfile);
- X else if (xWD)
- X writeXWD(&image, outfile);
- X else if (puzzle)
- X writePuzzle(&image, outfile);
- X else if (image.ximage->depth <= 1)
- X writeXYPixmap(&image, outfile);
- X else
- X writeZPixmap(&image, outfile);
- X
- X XDestroyImage(image.ximage);
- X XCloseDisplay(hDisplay);
- X if (outfileName)
- X fclose(outfile);
- X
- X exit(0);
- X}
- X
- END_OF_FILE
- if test 38224 -ne `wc -c <'xgrabsc.c'`; then
- echo shar: \"'xgrabsc.c'\" unpacked with wrong size!
- fi
- # end of 'xgrabsc.c'
- fi
- if test -f 'xgrabsc.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'xgrabsc.man'\"
- else
- echo shar: Extracting \"'xgrabsc.man'\" \(7589 characters\)
- sed "s/^X//" >'xgrabsc.man' <<'END_OF_FILE'
- X.\"========================================================================
- X.\"
- X.\" Name - xgrabsc.man
- X.\"
- X.\" Version: 1.2
- X.\"
- X.\" ccsid: @(#)xgrabsc.man 1.2 - 8/17/90 09:07:01
- X.\" from: ccs/s.xgrabsc.man
- X.\" date: 8/20/90 09:56:03
- X.\"
- X.\" Copyright (C) 1990, Bruce Schuchardt
- X.\" See the end of this document for full copyright information.
- X.\"
- X.\" Description: Man page for xgrabsc
- X.\"
- X.\"========================================================================
- X.\"
- X.TH XGRABSC 1X
- X.\"
- X.SH NAME
- Xxgrabsc \- grab rectangular screen images and store in files
- X.\"
- X.SH SYNTAX
- X\fIxgrabsc\fR \ [options]
- X.\"
- X.SH DESCRIPTION
- X\fIxgrabsc\fR lets you grab arbitrary rectangular images from an
- XX server and writes them to standard output in a variety of formats.
- X.PP
- XCommand line options also allow reduction of colormaps, halftoning
- Xand dithering of color images, and direct mapping of color images
- Xto monochrome.
- X.PP
- XThe default output formats are X Pixmap for color images and X Bitmap for
- Xmonochrome bitmaps.
- X.SH OPTIONS
- X.TP 8
- X-d \fIdisplayName\fP
- XUse an alternate display.
- X.TP
- X-n
- XInhibit server grabs. Normally xgrabsc will "grab" the server so
- Xthat the screen is frozen while a rectangle is selected and the image
- Xis extracted. If the screen is not frozen, rubber-banding may cause
- Xvideo droppings on portions of the screen that are changing.
- X.TP
- X-o \fIoutput-file\fP
- XWrite output to \fIoutput-file\fP instead of standard output.
- X.TP
- X-s \fIseconds\fP
- XSleep for \fIseconds\fP seconds before commencing operation. This
- Xshould be used if you need some time to get the target image ready.
- X.TP
- X-v
- XDisplay processing information on standard error output (stderr).
- X.sp 3
- X.TP
- X-b \fIpercent\fR
- Xbrighten or darken the image by \fIpercent\fR. Percentages are given
- Xas integers. As in \fIxloadimage\fR, 100 is the base and a larger
- Xnumber will brighten the image while a smaller number will darken the
- Ximage.
- X.TP
- X-A \fIandBits\fR
- XClear all colormap bits up to the given plane. This has the effect of
- Xdarkening the image somewhat and shrinking the apparent depth of the image
- X(and, consequently, the size of the color table). \fIAndBits\fR should
- Xbe in the range [1-8] inclusive.
- X.TP
- X-O \fIorBits\fR
- XSet all colormap bits up to the given plane. This brightens the image
- Xsomewhat and also shrinks the apparent depth of the image. When
- Xboth \-A and \-O are specified, ANDing will occur before ORing.
- X.TP
- X-B
- XConvert the source color image to a monochrome bitmap. All colors
- Xfalling below the average color intensity are mapped to black. Others
- Xare mapped to white.
- X.TP
- X-D
- XConvert the source color image to a dithered monochrome bitmap.
- XThis is like halftoning, but resolution is sacrificed to keep the
- Xresulting image the same size as the original.
- X.TP
- X-H
- XConvert the source color image to a halftoned monchrome bitmap.
- XResolution is maintained by increasing the size of the image by
- Xa factor of four on both axes.
- X.sp 3
- X.TP
- X-P
- XWrite output in \fIPostscript\fP format. Output will be run-length-encoded
- Xif encoding will result in any savings. The number of bits per
- XPostscript sample is determined by the depth of the image.
- X.TP
- X-W
- XWrite output in \fIxwd\fP format.
- X.TP
- X-Z
- XWrite output in a format suitable for loading into the \fIpuzzle\fP
- Xprogram (see example below).
- X.sp 2
- X.SH PROCESSING ORDER
- XIt is helpful to know the order of processing when multiple processing
- Xoptions are given on the command line.
- X.PP
- XProcessing is done in five phases: 1) set up, 2) obtain image,
- X3) process colors, 4) poly->monochrome conversions, and 5) output conversion.
- X.PP
- XThe set-up phase includes processing command-line options, sleeping,
- Xconnecting to X-Windows, freezing the screen and grabbing the mouse.
- X.PP
- XAfter the mouse is grabbed, rubber-banding occurs until a mouse button
- Xis released. The image is then pulled from the screen and the mouse
- Xand screen are released.
- X.PP
- XIf the image is not monochrome, the color manipulation functions are
- Xthen applied in this order: brighten, AND, and OR.
- X.PP
- XOnly one polychrome to monochrome conversion is allowed. If none of
- Xthese is chosen, the color table of a polychrome image is compressed
- Xin preparation for output conversion.
- X.PP
- XThe output stream is then opened and the image is written in the selected
- Xoutput format.
- X.sp 2
- X.SH EXAMPLES
- XThe simplest form of use, giving X11 Bitmap or Pixmap output, is
- X.sp
- X.ti +5
- Xxgrabsc >outfile.xpm
- X.sp
- X.PP
- XTo write output in \fIPostscript\fP format and send to the printer,
- Xuse
- X.sp
- X.ti +5
- Xxgrabsc -P | lpr
- X.sp
- XIt is sometimes helpful to brighten an image somewhat before it is
- Xformatted for Postscript output. E.g., to brighten by 30%
- X.sp
- X.ti +5
- Xxgrabsc -Pb 130 | lpr
- X.sp
- X.PP
- XTo write output in \fIpuzzle\fP format and read into the puzzle
- Xprogram, use the commands
- X.sp
- X.ti +5
- Xxgrabsc -Z >outfile.pzl
- X.br
- X.ti +5
- Xpuzzle -picture outfile.pzl
- X.sp
- X.PP
- XTo have xgrabsc sleep for three seconds before rubber-banding, display
- Xprocessing information, and have the result displayed with xwud,
- X.sp
- X.ti +5
- Xxgrabsc -Wvs3 | xwud
- X.sp
- X.PP
- XTo grab an image from another server and then reduce the colormap
- Xto three bits by ANDing, use
- X.sp
- X.ti +5
- Xxgrabsc -dother:0.0 -A5 >outfile.xpm
- X.sp
- XYou will, of course, have to go to the other machine to select the
- Ximage with that machine's mouse.
- X.sp 2
- X.SH LIMITATIONS
- XColormaps larger than 256 entries are not currently supported.
- X.PP
- XThe default screen visual is used as the visual for the image.
- XVisuals are associated with particular windows, and xgrabsc pretends
- Xignorance about any windows but the root.
- X.PP
- XThis software has been tested with StaticGray and 8-plane PseudoColor
- Xon DECStations (using both UWS 2.2 and X11 Release 4). It has also
- Xbeen tested with 8-plane PseudoColor
- Xon Sun SparcStations using X11 Release 4.
- X.PP
- XX11 Pixmap format is rather verbose.
- XYou may want to run large images through the \fIcompress\fP utility
- Xbefore storing them in a file. E.g.,
- X.sp
- X.ti +5
- Xxgrabsc | compress >outfile.xpm.Z
- X.sp
- X.SH AUTHOR
- X.nf
- X+----------------------------+
- X| Bruce Schuchardt |
- X| Servio Corporation |
- X| bruce@slc.com |
- X+----------------------------+
- X.fi
- X.sp 2
- X.SH ACKNOWLEGEMENTS
- X.PP
- XSome of the source code for xgrabsc came from
- Xthe xloadimage project by Jim Frost (jimf@saber.com) and others. Jim's
- Xcopyright has been included both here and in the source code.
- X.PP
- XThe idea for using run-length encoding for Postscript output came from
- Xthe xwd2ps project by Robert Tatar and Craig A. McGowan.
- X.sp 2
- X.SH COPYRIGHT
- XCopyright (c) 1990 Bruce Schuchardt
- X.sp
- XHalftoning and Dithering code
- XCopyright (c) 1989, 1990 Jim Frost and others.
- X.PP
- X\fIXgrabsc\fR is copywritten material with a very loose copyright
- Xallowing unlimited modification and distribution if the copyright
- Xnotices are left intact. Various portions are copywritten by various
- Xpeople, but all use a modification of the MIT copyright notice.
- XPlease check the source for complete copyright information. The
- Xintent is to keep the source free, not to stifle its distribution, so
- Xplease write to me if you have any questions.
- X.pp
- XTHE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- XINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- XNO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- XCONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- XOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- XOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
- XUSE OR PERFORMANCE OF THIS SOFTWARE.
- X.s 2
- X.SH SEE ALSO
- XX(1X), xwud(1X), xwd2ps(1X), xloadimage(1X), xpm(1X), puzzle(1X),
- Xcompress(1), uncompress(1)
- END_OF_FILE
- if test 7589 -ne `wc -c <'xgrabsc.man'`; then
- echo shar: \"'xgrabsc.man'\" unpacked with wrong size!
- fi
- # end of 'xgrabsc.man'
- fi
- echo shar: End of archive 1 \(of 2\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Bruce Schuchardt Ph: (503) 629-8383
- Servio Logic bruce@servio.SLC.COM
- Beaverton, OR uunet!servio!bruce
-
- dan
- ----------------------------------------------------
- O'Reilly && Associates argv@sun.com / argv@ora.com
- Opinions expressed reflect those of the author only.
-