Index: xc/ChangeLog =================================================================== RCS file: /cvs/xorg/xc/ChangeLog,v retrieving revision 1.494 diff -u -2 -0 -r1.494 ChangeLog --- xc/ChangeLog 30 Oct 2004 20:33:43 -0000 1.494 +++ xc/ChangeLog 31 Oct 2004 02:08:51 -0000 @@ -1,20 +1,39 @@ +2004-10-30 Roland Mainz + * xc/programs/Imakefile + * xc/programs/pclcomp/README + * xc/programs/pclcomp/pclcomp.c + * xc/programs/pclcomp/pclcomp.man + * xc/programs/pclcomp/printer.note + * xc/programs/xpr/Imakefile + * xc/programs/xpr/lncmd.h + * xc/programs/xpr/pmp.h + * xc/programs/xpr/x2jet.c + * xc/programs/xpr/x2pmp.c + * xc/programs/xpr/xdpr.man + * xc/programs/xpr/xdpr.script + * xc/programs/xpr/xpr.c + * xc/programs/xpr/xpr.h + * xc/programs/xpr/xpr.man + Bugzilla #631: Uploading "xpr" and "pclcomp" as they are needed + for the RASTER and PCL drivers on some platforms. + 2004-10-30 Alan Coopersmith * xc/config/util/mdepend.cpp: Add -d flag for compilers like the Sun C compilers that produce dependency lists themselves. To use with the Sun compilers, add to host.def: # define UseCCMakeDepend YES # define DependFlags -cc $(CC) -d -xM (Sun bug id #4245688 - fix by Alan Coopersmith) * xc/programs/Xserver/hw/xfree86/loader/elfloader.c: Add Solaris to the platforms on which mprotect is run to set execute permissions when necessary. (Sun bug id #6175128 - fix by Alan Coopersmith) * xc/programs/xclock/Imakefile,Clock.c,ClockP.h,xclock.c: Internationalize digital output (Sun bug id #4119396 - fix by Steve Swales), add -bgpixmap option to set XPM file as background (originally from STSF project version of xclock by Alan Coopersmith) * xc/programs/xmodmap/handle.c,pf.c xmodmap was printing line numbers which are one too low in error messages (Xorg bugzilla #1739, Sun bug id 4637857 - fix by Sam Lau) Index: xc/programs/Imakefile =================================================================== RCS file: /cvs/xorg/xc/programs/Imakefile,v retrieving revision 1.10 diff -u -2 -0 -r1.10 Imakefile --- xc/programs/Imakefile 20 Oct 2004 04:37:06 -0000 1.10 +++ xc/programs/Imakefile 31 Oct 2004 02:09:05 -0000 @@ -22,41 +22,41 @@ #endif #if BuildXKBlib XKBSRCDIRS = setxkbmap xkbcomp xkbevd xkbprint xkbutils #endif #if BuildScreenSaverLibrary SCREENSAVESRCDIR = beforelight #endif #if BuildXF86VidModeLibrary XVIDTUNESRCDIR = xvidtune #endif #if BuildXF86DGALibrary XF86DGASRCDIR = xf86dga #endif #if BuildXAServer XASSRCDIR = Xaserver #endif #if BuildLBX LBXPROXYSRCDIR = lbxproxy #endif #if BuildXprintClients - XPSRCDIRS = xplsprinters xprehashprinterlist xphelloworld + XPSRCDIRS = xplsprinters xprehashprinterlist xphelloworld xpr #endif PROXYMGRSRCDIR = proxymngr RSTARTSRCDIR = rstart SMPROXYSRCDIR = smproxy TWMSRCDIR = twm XCONSOLESRCDIR = xconsole XDMSRCDIR = xdm XFINDPROXYSRCDIR = xfindproxy XFWPSRCDIR = xfwp #if BuildXF86VidModeLibrary XGAMMASRCDIR = xgamma #endif #if BuildXvLibrary XVINFOSRCDIR = xvinfo #endif XHOSTSRCDIR = xhost #if BuildPlugin && BuildXaw XRXSRCDIR = xrx #endif XSMSRCDIR = xsm @@ -83,40 +83,44 @@ /* makepsres should be considered as part of the DPS libraries */ #if BuildDPSLibraries MAKEPSRESDIR = makepsres #endif /* on the other hand, the following are independent clients */ #if BuildDPSClients DPSCLIENTDIRS = dpsinfo dpsexec texteroids #endif #if BuildDBElib && BuildXprintClients DBECLIENTDIRS = xdbedizzy #endif XPMCLIENTDIRS = cxpm sxpm #if BuildGLXLibrary GLXCLIENTDIRS = glxinfo glxgears #endif +#if XpRasterDDX + XPRASTERFILTERDIRS = pclcomp +#endif + XLOADDIR = xload #if BuildRandRLibrary XRANDRDIR = xrandr #endif #if BuildXcursorgen XCURSORGENDIR = xcursorgen #endif #if BuildFontconfigLibrary FCDIRS = fc-cache fc-list #endif #if 0 FCLANGDIR = fc-lang #endif #if BuildXDriInfo XDRIINFO = xdriinfo #endif @@ -129,27 +133,27 @@ SUBDIRS = $(XSSRCDIR) #else SUBDIRS = \ appres bdftopcf bitmap \ $(SCREENSAVESRCDIR) editres $(FCDIRS) $(FCLANGDIR) fslsfonts fstobdf \ iceauth ico listres luit \ $(MAKEPSRESDIR) $(DPSCLIENTDIRS) $(DBECLIENTDIRS) \ $(MKCFMSRCDIR) \ mkfontdir $(MKFONTSCALEDIR) oclock $(PROXYMGRSRCDIR) \ $(RGBSRCDIR) $(RSTARTSRCDIR) showfont \ $(SMPROXYSRCDIR) $(TWMSRCDIR) viewres x11perf xauth xbiff xcalc \ xclipboard xclock \ xcmsdb $(XCONSOLESRCDIR) xditview $(XDMSRCDIR) xdpyinfo \ $(XF86DGASRCDIR) xedit xev xeyes xfd xfontsel $(XFSSRCDIR) xfsinfo \ $(XFINDPROXYSRCDIR) $(XFWPSRCDIR) $(XGAMMASRCDIR) xgc $(XHOSTSRCDIR) \ $(XINITSRCDIR) $(XKBSRCDIRS) xkill $(XLOADDIR) xlogo xlsatoms \ xlsclients xlsfonts xmag xman xmessage xmh xmodmap $(XMORE) xprop \ xrdb xrefresh $(XRXSRCDIR) xset \ xsetroot $(XSMSRCDIR) xstdcmap $(XINPUTCLIENTDIRS) \ $(XTERMSRCDIR) $(XTRAPCLIENTDIRS) $(XVIDTUNESRCDIR) xwd xwininfo xwud \ - $(XPMCLIENTDIRS) $(XVINFOSRCDIR) \ + $(XPMCLIENTDIRS) $(XVINFOSRCDIR) $(XPRASTERFILTERDIRS) \ $(XSSRCDIR) $(XASSRCDIR) $(LBXPROXYSRCDIR) $(XPSRCDIRS) $(SCRIPTSDIR) \ $(GLXCLIENTDIRS) $(XRANDRDIR) $(XCURSORGENDIR) $(XDRIINFO) #endif MakeSubdirs($(SUBDIRS)) DependSubdirs($(SUBDIRS)) Index: xc/programs/pclcomp/README =================================================================== RCS file: xc/programs/pclcomp/README diff -N xc/programs/pclcomp/README --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/pclcomp/README 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,42 @@ + + + This is pclcomp -- An HP-PCL compression filter. It reads in +PCL graphics files, and outputs compressed PCL files which may be sent +directly to printers that support the compressions. A partial list of +printer support is included. + + Why use pclcomp? + + 1) PCL files are much smaller ( up to 90% ). + + 2) Graphics printing on a LaserJet (IIP or III) is faster. + + + If you have a LaserJet II that does not support compression, you can +still compress the files for storage, and decompress them while printing. + + I wrote this program for testing. This is NOT an HP product. It will +NOT be supported by HP, but rather myself, in my spare time, if need be. + + If you need real support for driver development, then call Hewlett- +Packard directly, preferably the ISV support group at the Boise Division. + + You may use parts of this code within your drivers to support compression +if you wish. + + I did what I think is a reasonable job to make the program work for +most possible PCL files. Please feel free to send comments, complaints +or suggestions to me at tony@sdd.hp.com. If you have a file that does +not survive the filter intact, please e-mail me the file and describe the +problem. + + This filter runs under UNIX and MS-DOS and hopefully anything else that +supports ANSI-C. To compile under HP-UX: + +cc -Aa -O pclcomp.c -o pclcomp + + + Please direct all compliments and praise to: tony@sdd.hp.com + + + -- Tony Parkhurst Index: xc/programs/pclcomp/pclcomp.c =================================================================== RCS file: xc/programs/pclcomp/pclcomp.c diff -N xc/programs/pclcomp/pclcomp.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/pclcomp/pclcomp.c 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,3012 @@ +/* +** Pclcomp -- PCL compression filter. +** +** If you have any problems or errors to report, please send them to me: +** +** Tony Parkhurst +** +** Email address: tony@sdd.hp.com -or- hp-sdd!tony +** +** Please send a copy of the file that is causing the problem, and the +** version of pclcomp you are using. +** +** All suggestions and requests are welcome. +*/ + +/* + *************************************************************************** + * + * $Source: /disc/44/cgtriton/tony/filters/pclcomp/RCS/pclcomp.c,v $ + * $Date: 92/04/13 11:55:36 $ + * $Revision: 1.48 $ + * + * Description: Compresses pcl graphics files. + * + * Author: Tony Parkhurst + * Created: 890427 + * Language: C + * + * (c) Copyright 1989, Hewlett-Packard Company, all rights reserved. + * + *************************************************************************** + */ + + +/* + *************************************************************************** + * + * $Log: pclcomp.c,v $ + * Revision 1.48 92/04/13 11:55:36 11:55:36 tony (Tony Parkhurst) + * Fixed problem with reseting rasterwidth when *r#U follows a *v6W. + * + * Revision 1.47 92/04/06 16:07:54 16:07:54 tony (Tony Parkhurst) + * Removed special case to force first row to be other than mode 3. + * + * Revision 1.46 92/03/11 15:50:06 15:50:06 tony (Tony Parkhurst) + * Fixed a bug with Uncompress_3() when input goes past expect width. + * (This was mainly a problem if the offsets went over the end.) + * + * Also, fixed some semantic errors (null statements) that lint caught. + * + * Revision 1.45 92/02/13 14:15:54 14:15:54 tony (Tony Parkhurst) + * Replaced mode 1 compress routine. + * + * Revision 1.44 92/02/13 11:14:08 11:14:08 tony (Tony Parkhurst) + * Replaced mode 3 compression routine (cleaner version) + * Changed some function names for clarity. + * Added comments for worst case conditions. + * + * Revision 1.43 92/02/10 13:47:30 13:47:30 tony (Tony Parkhurst) + * Added AppleTalk sequence to pass thru. (plus fixed dither sequence). + * + * Revision 1.42 92/02/10 13:38:16 13:38:16 tony (Tony Parkhurst) + * Changed download dither matrix sequence to *m#W. + * + * Revision 1.41 92/01/14 13:54:43 13:54:43 tony (Tony Parkhurst) + * Changed some comments. Added compression ratio to verbose mode. + * + * Revision 1.40 92/01/14 13:20:32 13:20:32 tony (Tony Parkhurst) + * Added code to deal with implicit end of graphics + * (which zeros the seed rows). + * + * Revision 1.39 91/09/13 13:56:28 13:56:28 tony (Tony Parkhurst) + * Added code to disable zerostrip in mode 2. + * + * Revision 1.38 91/09/10 15:47:28 15:47:28 tony (Tony Parkhurst) + * Added include file for isdigit() + * + * Revision 1.37 91/09/10 15:08:23 15:08:23 tony (Tony Parkhurst) + * Clamped horizontal offsets to raster widths. + * + * Revision 1.36 91/09/10 15:04:15 15:04:15 tony (Tony Parkhurst) + * Re-vamped fraction parsing. + * + * Revision 1.35 91/09/10 14:03:40 14:03:40 tony (Tony Parkhurst) + * Fixed potential problem with fractions. + * Removed obsolete invert flag. + * Cleaned up some comments. + * + * Revision 1.34 91/09/10 13:21:48 13:21:48 tony (Tony Parkhurst) + * Fixed problems with data gaps (0W instead of 0V0V0W) + * Fixed problems with horizontal offsets and mode 3 compression. + * Added option to strip horizontal offsets (zero value must be white). + * + * Revision 1.33 91/07/18 15:18:43 15:18:43 tony (Tony Parkhurst) + * Replaced mode 2 compression routine. Works better now. + * + * Revision 1.32 91/07/08 11:27:24 11:27:24 tony (Tony Parkhurst) + * Enhanced the strip algorithm for merged graphics. + * (Also cleaned up some comments, couple of statements.) + * + * Revision 1.31 91/05/30 15:18:51 15:18:51 tony (Tony Parkhurst) + * Oops, fixed it right this time. + * + * Revision 1.30 91/05/30 15:06:20 15:06:20 tony (Tony Parkhurst) + * Added fix for negative value for *r#U. + * + * Revision 1.29 91/05/03 10:12:30 10:12:30 tony (Tony Parkhurst) + * Small changes. + * + * Revision 1.28 91/04/30 09:41:24 09:41:24 tony (Tony Parkhurst) + * Now puts stdin and stdout in binary mode for MSDOS. + * Changes courtesy of Mike Slomin. + * Changed usage message a bit. + * + * Revision 1.27 91/04/23 15:48:05 15:48:05 tony (Tony Parkhurst) + * Added handling of plus_sign in value fields. + * + * Revision 1.26 91/04/23 09:47:11 09:47:11 tony (Tony Parkhurst) + * Pass thru unknown modes. + * + * Revision 1.25 91/04/18 11:09:27 11:09:27 tony (Tony Parkhurst) + * Added parse for fractions in values (i.e. (s16.67H) + * + * Revision 1.24 91/04/10 14:16:30 14:16:30 tony (Tony Parkhurst) + * strips text and control codes between *rA and *rB w/ -s option + * + * Revision 1.23 91/04/05 14:53:25 14:53:25 tony (Tony Parkhurst) + * Added fixed for deskjet + * Also added a stripping feature. + * + * Revision 1.22 91/04/05 08:48:53 08:48:53 tony (Tony Parkhurst) + * Added some error checkin on output for MS-DOS users. + * + * Revision 1.21 91/04/04 12:53:32 12:53:32 tony (Tony Parkhurst) + * Replaced parser. + * Now handles combined escape sequences. + * Now handles downloads. + * Now combines mode changes with data. + * + * Revision 1.20 91/04/04 08:02:12 08:02:12 tony (Tony Parkhurst) + * Removed some test code. + * + * Revision 1.19 91/03/25 14:38:48 14:38:48 tony (Tony Parkhurst) + * Changed defaults. + * + * Revision 1.18 91/03/25 14:31:22 14:31:22 tony (Tony Parkhurst) + * Re-worked memory allocation stuff for funky input files. + * + * Revision 1.17 91/03/25 13:50:19 13:50:19 tony (Tony Parkhurst) + * Use command line args for file w/o -i or -o. + * + * Revision 1.16 91/03/04 14:23:15 14:23:15 tony (Tony Parkhurst) + * Fixed to allow ONLY mode 3 if the user really wants it. + * + * Revision 1.15 91/03/04 14:08:23 14:08:23 tony (Tony Parkhurst) + * Added an exit(0) at the end of main. + * fixed up some zerostrip stuff. + * made mode 3 the highest priority mode. + * + * Revision 1.14 91/02/20 13:57:27 13:57:27 tony (Tony Parkhurst) + * Changed priority a bit. + * Added some zerostripping for mode 2. + * + * Revision 1.13 91/02/06 15:31:00 15:31:00 tony (Tony Parkhurst) + * oops. + * + * Revision 1.12 91/02/06 14:41:28 14:41:28 tony (Tony Parkhurst) + * fixed usage message + * + * Revision 1.11 91/02/06 14:38:10 14:38:10 tony (Tony Parkhurst) + * Added file input and output for MS-DOS. + * + * Revision 1.10 91/02/05 17:49:23 17:49:23 tony (Tony Parkhurst) + * Fixed problem with zero stripped input. + * + * Revision 1.9 91/02/05 16:11:39 16:11:39 tony (Tony Parkhurst) + * Removed delay code and bitfield stuff. + * + * Revision 1.8 91/02/05 11:04:53 11:04:53 tony (Tony Parkhurst) + * Added io delay stuff for testing. + * + * Revision 1.7 91/02/05 10:28:32 10:28:32 tony (Tony Parkhurst) + * Fix for someone specifing ONLY mode 3. + * + * Revision 1.6 91/01/29 14:13:09 14:13:09 tony (Tony Parkhurst) + * Updated some comments. + * + * Revision 1.5 91/01/29 13:26:24 13:26:24 tony (Tony Parkhurst) + * Cleaned up, revamped a bit. + * + * Revision 1.4 89/11/09 15:59:16 15:59:16 tony (Tony Parkhurst) + * Fix for esc * r U coming after esc * r A. + * + * Revision 1.3 89/10/24 11:31:12 11:31:12 tony (Tony Parkhurst) + * Added parsing of *rC + * + * Revision 1.2 89/10/13 09:56:46 09:56:46 tony (Tony Parkhurst) + * Completely revamped by Greg G. + * + * Revision 1.1 89/06/15 13:57:46 13:57:46 tony (Tony Parkhurst) + * Initial revision + * + * + *************************************************************************** + */ + +static const char copyr[]= + "Copyright (c) 1991, Hewlett-Packard Company, all rights reserved."; + +static const char author[]="Tony Parkhurst"; + +static const char rcs_id[]="$Header: pclcomp.c,v 1.48 92/04/13 11:55:36 tony Exp $"; + +static const char rev_id[]="$Revision: 1.48 $"; + + +/* + * Input and output formats are HP pcl. + * + * Imaging files ("Configure Image Data") are supported. + * + * Pclcomp does not take advantage of Y-Offset for blank areas. + * This is because Y-Offset creates white areas, but we don't do enough + * parsing to determine what value "white" has. An application that + * can assume white values could make use of this sequence. + * + * Pclcomp does not do any of the block compression modes (4-8). + * + * An additional enhancement would be to compare all the planes in a + * multi-plane file (color) and if nothing changed, using mode 3, just + * output a single *b0W. + * + * + * Usage: pclcomp [-v] [-0] [-1] [-2] [-3] [-z] [-n###] < infile > outfile + * + * Pclcomp will do graphics compression based on compression modes 0, 1, 2 + * and 3. (Mode 0 is uncompressed). Pclcomp will accept all modes, and + * will attempt to optimize by selecting the best output mode for each + * row (or plane) of data. By default, pclcomp will use all 4 modes, but + * the user may restrict which output modes to use with the -0123 options. + * For example, to use pclcomp for output to a PaintJet which only knows + * modes 0 and 1 (the XL also understands modes 2 and 3), one would use: + * + * pclcomp -01 < infile > outfile + * + * Note: Mode 0 should always be allowed. None of the other modes is + * guaranteed to be better than mode 0 in all cases. + * + * The 'v' option tells the number of rows (planes) of data input and output + * in the different modes (to stderr). + * + * By default, pclcomp does zero "stripping" which is useful for PaintJet + * files using only modes 0 and 1, the PaintJet (and other PCL printers) + * will do zero "filling". + * NOTE: Use the 'z' option to disable zero stripping. + * + * The 'n' option is to change the default number of pixels in a picture. + * The proper way to set the pixel width is with the source raster width + * sequence , but soo many applications just assume the default, + * which is different on different printers, so I am providing this + * command line option to set a new default. One could also change the + * DEFAULT constant below (make sure it is a multiple of 8). + * Currently it is set to 8" at 300 dpi (2400). + */ + +#include +#include +#include + +#ifdef MSDOS +#include +#endif + + +#define Get_Character() getchar() + +#define MIN(x,y) ( ((x) < (y)) ? (x) : (y) ) + +#define TRUE 1 +#define FALSE 0 + +#define ESC 27 + +#define DEFAULT 2400 /* default width in pixels (multiple of 8) */ + +#define MAXMODES 4 +#define MAXPLANES 8 +#define MAXBYTES 60000 /* now mostly meaningless, just a big number */ + +unsigned char *seed_row[MAXPLANES]; +unsigned char *new_row; +unsigned char *out_row[MAXMODES]; +unsigned int out_size[MAXMODES]; + +char memflag = FALSE; /* set when memory has been allocated */ + + +char mode0=FALSE, + mode1=FALSE, + mode2=FALSE, + mode3=FALSE; + +unsigned char num_planes=1; +unsigned char curr_plane=0; + +char imaging = FALSE; /* not imaging, so no lockout */ + +char verbose = FALSE; + +unsigned char inmode = 0; /* input compression mode */ +unsigned char outmode = 0; /* output compression mode */ + +unsigned int rasterwidth=DEFAULT/8; /* width of picture, in bytes */ +unsigned int rpix = DEFAULT; /* width of picture, in pixels */ + +unsigned char zerostrip= TRUE; /* strip trailing zeros */ + +unsigned int inuse[4]={0,0,0,0}, outuse[4] = {0,0,0,0}; + +char widthwarning = FALSE; /* for trucation warning */ +char firstrow = TRUE; /* to prevent mode 3 from being first */ + + +struct { /* this will hold the data for the */ + unsigned char model; /* configuring of image processing */ + unsigned char pix_mode; + unsigned char inx_bits; + unsigned char red; + unsigned char green; + unsigned char blue; + short wr; + short wg; + short wb; + short br; + short bg; + short bb; +} imdata; + +extern unsigned char *malloc(); + +char *filein = NULL, *fileout = NULL; + +/* +** These variables are for the new parser. +** The new parser handles more sequences, and also deals with combined +** escape sequences better. +*/ + +int parameter; +int group_char; +int terminator; +int old_terminator; +int value; +float fvalue; /* fractional value */ +int scanf_count; +char in_sequence = FALSE; +char pass_seq; +char plus_sign; /* for relative values */ + + +/* dummy buffer */ +char buf[BUFSIZ]; + +/* +** If the printer is a DeskJet, then we must handle *rB differently +** Option '-d' will turn on this mode. +*/ + +char deskjet = FALSE; + + +/* +** Many drivers it seems put *rB*rA between each and every row +** of data. This defeats compression mode 3 on a DeskJet, and also +** makes the PaintJet (not XL) quite slow. This next flag "-s" on the +** command line, will attempt to do a reasonable job of stripping +** out the excess commands. +** +** The in_graphics flag will be used to strip unwanted control chars from +** the file. It will also be used to spot implicit end of graphics. +*/ + +char strip_seq = FALSE; +char in_graphics = FALSE; + + +/* +** Just for certain special cases, it would be nice to append an E reset +** to the end of the job. Specify with "-r". +*/ + +char reset_seq = FALSE; + + +char *progname; /* to hold the program name for verbose */ + +/* +** Even though the horizontal offset command *b#X is obsolete, many +** drivers still use it, and it causes some interesting problems with +** mode 3 compression, so pclcomp needs to deal with it in some hopefully +** intelligent fashion, and they will get stripped if -x is used. +*/ + +int horiz_offset = 0; + +char strip_offsets = FALSE; + + +static float Get_Frac(); /* instead of scanf */ + + + +/* +****************************************************************************** +** +** Main program. +** +****************************************************************************** +*/ + +main(argc, argv) +int argc; +char *argv[]; +{ + int c,j; + extern char *optarg; + extern int optind; + + progname = argv[0]; + +#ifdef MSDOS + setmode(fileno(stdin), O_BINARY); /* Place stdin and stdout in */ + setmode(fileno(stdout), O_BINARY); /* binary mode. (Mike Slomin)*/ +#endif + + /* parse up the args here */ + + while ((c = getopt(argc, argv, "0123drsvzn:i:o:sx")) != EOF ) + switch(c){ + case '0': + mode0 = TRUE; + break; + case '1': + mode1 = TRUE; + break; + case '2': + mode2 = TRUE; + break; + case '3': + mode3 = TRUE; + break; + case 'd': + deskjet = TRUE; + break; + case 'r': + reset_seq = TRUE; + break; + case 's': + strip_seq = TRUE; + break; + case 'v': + verbose = TRUE; + break; + case 'x': + strip_offsets = TRUE; + break; + case 'z': + zerostrip = FALSE; + break; + case 'n': + rpix = atoi(optarg); /* new default */ + rasterwidth = (rpix + 7) / 8; /* round up */ + break; + + case 'i': + filein = optarg; + break; + case 'o': + fileout = optarg; + break; + + case '?': + default: + fprintf(stderr, + "Usage: %s [-0123drsvxz] [-n###] [infile [outfile]]\n", + argv[0]); + exit(-1); + }; + + if ( verbose ) + { + fprintf(stderr, "%s: %s\n", argv[0], rev_id); + } + + + if ( ! ( mode0 || mode1 || mode2 || mode3) ) /* any modes on? */ + mode0 = /* mode1 = */ mode2 = mode3 = TRUE; /* 3 modes by default */ + + /* + ** Check to see if any file args were given on the command line. + ** Ones that were not preceded by a "-i" or "-o". + */ + + if ( filein == NULL && optind < argc && argv[optind] != NULL ) + filein = argv[optind++]; + + if ( fileout == NULL && optind < argc && argv[optind] != NULL ) + fileout = argv[optind++]; + + /* + ** Now open files for stdin and stdout if provided by the user. + */ + + if ( filein != NULL ) /* new input file */ + + if ( freopen( filein, "rb", stdin ) == NULL ) + { + fprintf(stderr,"Unable to open %s for input.\n",filein); + exit(-42); + } + + if ( fileout != NULL ) /* new output file */ + + if ( freopen( fileout, "wb", stdout ) == NULL ) + { + fprintf(stderr, "Unable to open %s for output.\n", + fileout); + exit(-43); + } + + + /* + ** + ** This is the pcl input parsing loop. + ** + */ + + while( ( c = getchar() ) != EOF ) + { + + /* Ignore all chars until an escape char */ + + /* + ** If we are in graphics, toss it if strip_seq is set. + */ + + if ( c != ESC ) + { + /* + ** Simply pass thru the character if not stripping + ** or not in graphics. + */ + + if ( !strip_seq || !in_graphics ) + putchar(c); /* pass it thru */ + + /* + ** If we are in graphics and we are not stripping, + ** then this character implies an end raster graphics, + ** and the seed rows need to be zeroed. + */ + + if ( in_graphics && !strip_seq ) + { + zero_seeds(); + in_graphics = FALSE; /* fell out */ + } + + continue; /* pop to the top of the loop */ + } + + /* + ** Now we have an escape sequence, get the parameter char. + */ + + parameter = getchar(); + + if ( parameter == EOF ) /* oops */ + { + putchar ( ESC ); + fprintf(stderr, "Warning: File ended with .\n"); + break; /* unexpected end of input */ + } + + /* + ** Now check to see if it is a two character sequence. + */ + + if ( parameter >= '0' && parameter <= '~' ) + { + putchar ( ESC ); + putchar ( parameter ); /* pass it thru */ + + /* + ** If the second character is an E, then we + ** and the printer do a reset. + */ + + if ( parameter == 'E' ) + { + free_mem(); + curr_plane = 0; + num_planes = 1; + imaging = FALSE; + inmode = 0; + outmode = 0; + in_graphics = FALSE; + + /* can't do this if user gave value with -n. + rasterwidth = DEFAULT/8; + rpix = DEFAULT; + */ + } + + continue; /* return to the top */ + } + + /* + ** Now check to make sure that the parameter character is + ** within range. + */ + + if ( parameter < '!' || parameter > '/' ) + { + putchar ( ESC ); + putchar ( parameter ); + + fprintf(stderr, "Warning: Invalid escape sequence.\n"); + + continue; + } + + /* + ** We are only interested in certain parameters, so pass + ** the rest of the sequences. + */ + + /* + ** For the moment, we are only interested in '*' (graphics) + ** '(' and ')' (downloads). Although we do not do anything + ** with downloads, we need to pass the binary data thru + ** untouched. + ** Oops, '&' is handled too. + */ + + if ( parameter != '*' && parameter != '(' + && parameter != ')' && parameter != '&' ) + { + + /* + ** If the "stripper" is active, we need to suspend + ** it till graphics are re-started. + */ + + if ( strip_seq && !in_graphics ) + { + curr_plane = 0; + free_mem(); /* force re-start */ + } + + /* + ** Pass thru the sequence intact. + */ + + putchar ( ESC ); + putchar ( parameter ); + Flush_To_Term(); /* flush rest of seq. */ + continue; + } + + + /* + ** Parameter character is in range, look for a valid group char + */ + + group_char = getchar(); + + if ( group_char == EOF ) /* oops, ran out of input */ + { + putchar ( ESC ); + putchar ( parameter ); + + fprintf(stderr, "Warning: Incomplete escape sequence.\n"); + break; + } + + /* + ** See if in proper range. If it isn't, it is not an error + ** because the group character is optional for some sequences. + ** For the moment, we are not interested in those sequences, + ** so pass them thru. + */ + + if ( group_char < '`' || group_char > '~' ) + { + + /* + ** If the "stripper" is active, we need to suspend + ** it till graphics are re-started. + */ + + if ( strip_seq && !in_graphics ) + { + curr_plane = 0; + free_mem(); /* force re-start */ + } + + /* + ** Pass thru the sequence intact. + */ + + putchar ( ESC ); + putchar ( parameter ); + putchar ( group_char ); + if ( group_char < '@' || group_char > '^' ) + Flush_To_Term(); /* pass rest of seq. */ + continue; + } + + /* + ** Now we have a valid group character, decide if we want + ** to deal with this escape sequence. + ** + ** Sequences we want do deal with include: + ** + ** *r ** graphics + ** *b ** graphics + ** *v ** graphics + ** + ** Sequences we must pass thru binary data: + ** + ** *c ** pattern + ** *m ** download dither + ** *t ** obsolete + ** (f ** download char set + ** (s ** download char + ** )s ** download font + ** &a ** logical page + ** &b ** AppleTalk stuff + ** &l ** obsolete + ** + */ + + if ( ( parameter == '*' + && group_char != 'r' && group_char != 'b' + && group_char != 'v' && group_char != 'c' + && group_char != 't' && group_char != 'm' ) + || ( parameter == '&' + && group_char != 'a' && group_char != 'l' + && group_char != 'b' ) + || ( parameter == '(' + && group_char != 'f' && group_char != 's' ) + || ( parameter == ')' && group_char != 's' ) ) + { + /* + ** Definately not interested in the sequence. + */ + + /* + ** If the "stripper" is active, we need to suspend + ** it till graphics are re-started. + */ + + if ( strip_seq && !in_graphics ) + { + curr_plane = 0; + free_mem(); /* force re-start */ + } + + /* + ** Pass thru the sequence intact. + */ + + putchar ( ESC ); + putchar ( parameter ); + putchar ( group_char ); + Flush_To_Term(); + continue; + } + + + /* + ** If the sequence is &a#H, it will have gotten past + ** the above, but we need to suspend the "stripper" if + ** it is active, because the CAP is getting moved. + ** + ** The *p#X/Y sequences will have been filtered + ** thru just above (*p is not a needed group). + */ + + if ( strip_seq && parameter != '*' && !in_graphics ) + { + curr_plane = 0; + free_mem(); /* force re-start */ + } + + + /* + ** Now set up a pass thru flag so we can ignore the entire + ** sequences of some of these. + */ + + if ( parameter != '*' ) + pass_seq = TRUE; + + else if ( group_char == 'c' || group_char == 't' + || group_char == 'm' ) + + pass_seq = TRUE; + else + pass_seq = FALSE; + + + /* + ** Now we have a sequence that we are definately interested in. + ** + ** Get the value field and terminator, and loop until final + ** terminator is found. + */ + + do + { + /* first see if the value has a plus sign */ + + scanf_count = scanf(" + %d", &value ); + + if ( scanf_count == 1 ) + + plus_sign = TRUE; + else + { + plus_sign = FALSE; + + scanf_count = scanf(" %d", &value ); + + if ( scanf_count == 0 ) + value = 0; /* by default */ + } + + /* + ** I wonder if I will get bitten by a trailing + ** space character right here? + */ + + terminator = getchar(); + + /* + ** Check for a fractional component. + */ + + fvalue = 0.0; + + if ( terminator == '.' ) + { + fvalue = Get_Frac(); + + /* + ** Now get real terminator. + */ + + terminator = getchar(); + } + + + if ( terminator == EOF ) /* barf */ + { + fprintf(stderr, + "Warning: Incomplete sequence at EOF.\n"); + break; + } + + /* + ** If the pass_seq flag is set, then just pass + ** it thru to stdout until a 'W' is found. + */ + + if ( pass_seq ) + { + /* + ** If not in sequence, then we output esc + ** otherwise, output the saved terminator. + */ + + if ( !in_sequence ) + { + in_sequence = TRUE; + putchar ( ESC ); + putchar ( parameter ); + putchar ( group_char ); + } else + { + putchar ( old_terminator ); + } + + /* now pass the value */ + + if ( plus_sign ) + putchar('+'); + + /* + ** See if there was a non-zero fraction. + */ + + if ( fvalue != 0.0 ) + { + if ( value < 0 ) + { + putchar('-'); + value = -value; + } + + fvalue += value; + + printf("%g", fvalue); + + } else if ( scanf_count ) + printf("%0d", value); + + /* + ** We save the terminator, because we may + ** need to change it to upper case. + */ + + old_terminator = terminator; + + /* if binary data, pass it thru */ + + if ( terminator == 'W' ) /* aha */ + { + putchar ( terminator ); + in_sequence = FALSE; /* terminates */ + Flush_Bytes ( value ); /* pass data */ + } + + continue; + } + + /* + ** Ok, this is a sequence we want to pay attention to. + ** + ** Do_Graphics returns TRUE if we need to pass seq. + ** + ** Note: Do_Graphics modifies the parser vars such + ** as in_sequence. This is because it may + ** have to output stuff directly. + */ + + if ( Do_Graphics ( group_char, value, terminator ) ) + { + /* + ** If not in sequence, then we output esc + ** otherwise, output the saved terminator. + */ + + if ( !in_sequence ) + { + in_sequence = TRUE; + putchar ( ESC ); + putchar ( parameter ); + putchar ( group_char ); + } else + { + putchar ( old_terminator ); + } + + /* now pass the value */ + + if ( plus_sign ) + putchar('+'); + + /* + ** See if there was a non-zero fraction. + */ + + if ( fvalue != 0.0 ) + { + if ( value < 0 ) + { + putchar('-'); + value = -value; + } + + fvalue += value; + + printf("%g", fvalue); + + } else if ( scanf_count ) + printf("%0d", value); + + /* + ** We save the terminator, because we may + ** need to change it to upper case. + */ + + old_terminator = terminator; + } + + } while ( terminator >= '`' && terminator <= '~' ); + + /* + ** The oppsite test (above) may be more appropriate. That is, + ** !(terminator >= '@' && terminator <= '^'). + */ + + /* + ** If we were in a sequence, then we must terminate it. + ** If it was lower case, then it must be uppered. + */ + + if ( in_sequence ) + { + putchar ( terminator & 0xdf ); /* a ==> A */ + in_sequence = FALSE; + } + } + + + /* + ** If the user wants a reset, give him one. + */ + + if ( reset_seq ) + { + putchar ( ESC ); + putchar ( 'E' ); + } + + + /* + ** Finished up, so print stats and close output file. + */ + + + + if ( verbose ) + { + long inpos, outpos; + + for(j = 0; j < 4; j++) + fprintf(stderr,"Rows in mode %1d: %d\n", j, inuse[j]); + for(j = 0; j < 4; j++) + fprintf(stderr,"Rows out mode %1d: %d\n", j, outuse[j]); + + inpos = ftell(stdin); + outpos = ftell(stdout); + + /* + ** If the input or output is a pipe, then ftell returns a + ** -1. Don't bother telling the user about it. + */ + + if ( inpos > 0 && outpos > 0 ) + { + + fprintf(stderr, "Input size: %ld bytes\n", inpos ); + fprintf(stderr, "Output size: %ld bytes\n", outpos ); + + if ( inpos > outpos ) + fprintf(stderr, "Compression: %ld%%\n", + (long)(99L - 100L*outpos/inpos)); + else if ( outpos > inpos ) + fprintf(stderr, "Expansion: %ld%%\n", + (long)(100L*outpos/inpos - 100L)); + else + fprintf(stderr, "No compression.\n"); + } + } + + fclose(stdout); + + exit(0); +} + + +/* +** Do_Graphics() takes the graphics escape sequence and performs the +** necessary functions. +** TRUE is returned if the escape sequence needs to be passed to the output. +*/ + +int Do_Graphics( group, num, terminator ) +int group, num, terminator; +{ + /* first look at vW */ + + if ( group == 'v' ) + + if ( terminator != 'W' ) + + return ( TRUE ); /* pass it thru */ + else + { + if ( !in_sequence ) + { + putchar ( ESC ); + putchar ( parameter ); + putchar ( group ); + } else + putchar ( old_terminator ); + + in_sequence = FALSE; /* terminating */ + + printf("%0d", num); + putchar ( terminator ); + + free_mem(); /* reset memory */ + + imaging++; + + fread(&imdata, MIN(num, 18), 1, stdin); + fwrite(&imdata, MIN(num, 18), 1, stdout); + + num -= MIN(num, 18); + + /* copy rest of unknown data */ + + if ( num > 0 ) + Flush_Bytes(num); + + + switch(imdata.pix_mode){ + case 0x00: + rasterwidth = (rpix + 7)/8; + num_planes = imdata.inx_bits; + break; + case 0x01: + rasterwidth = rpix*imdata.inx_bits/8; + break; + case 0x02: + rasterwidth = (rpix + 7)/8; + num_planes =imdata.red + imdata.green + + imdata.blue; + break; + case 0x03: + rasterwidth = (imdata.red + + imdata.green + + imdata.blue)*rpix/8; + break; + } + + return ( FALSE ); + } + + /* + ** Now deal with *r stuff + */ + + if ( group == 'r' ) + { + switch ( terminator ) + { + case 'A': + case 'a': + + /* Enter graphics mode, enable stripping */ + + in_graphics = TRUE; + + /* if user wants to strip redundant seq */ + if ( strip_seq && memflag ) + return( FALSE ); + + curr_plane=0; + zero_seeds(); /* may allocate mem */ + break; + + case 'C': + case 'c': + + /* Exit graphics, disable stripping */ + + in_graphics = FALSE; + + if ( strip_seq ) + return( FALSE ); + + inmode = 0; + outmode = 0; + + free_mem(); + curr_plane=0; + break; + + case 'B': + case 'b': + + /* Exit graphics, disable stripping */ + + in_graphics = FALSE; + + if ( strip_seq ) + return( FALSE ); + + if ( deskjet ) /* B resets modes on DJ */ + { + inmode = 0; + outmode = 0; + } + free_mem(); + curr_plane=0; + break; + + case 'S': + case 's': + + /* free mem in case widths changed */ + free_mem(); + + rpix = num; + + if (imaging){ + switch(imdata.pix_mode) + { + case 0x00: + rasterwidth=(rpix+7)/8; + break; + case 0x01: + rasterwidth = + rpix*imdata.inx_bits/8; + break; + case 0x02: + rasterwidth=(rpix+7)/8; + break; + case 0x03: + rasterwidth = + (imdata.red + + imdata.green + + imdata.blue)*rpix/8; + break; + } + } else + rasterwidth = (num + 7) / 8; + break; + + case 'T': + case 't': + break; + + case 'U': + case 'u': + curr_plane=0; + free_mem(); /* if ESC*rA came first */ + + /* num can be negative */ + + if ( num < 0 ) + num_planes= -num; + else + num_planes = num; + + /* + ** This turns off imaging mode, + ** so we must recalculate rasterwidth, + ** (which is number of bytes needed), + ** based on normal raster transfer. + */ + + imaging = FALSE; /* goes off */ + rasterwidth = (rpix + 7) / 8; + + break; + + default: + break; + } + + return ( TRUE ); /* pass sequence on */ + + } /* group r */ + + /* + ** Last and final group 'b'. All the graphics data comes thru here. + */ + + + switch ( terminator ) + { + case 'm': + case 'M': + inmode = num; + return ( FALSE ); /* we do NOT pass this */ + break; + + /* + ** *b#X is obsolete, but I need to use it. + ** In addition, they will not get passed thru. + */ + + case 'x': + case 'X': + /* + ** Compute in bytes, rounding down. + */ + + horiz_offset = num / 8; + + if ( horiz_offset < 0 ) /* just in case */ + horiz_offset = 0; + + if ( strip_offsets || horiz_offset == 0 ) + return ( FALSE ); /* do not pass seq */ + + break; + + case 'y': + case 'Y': + /* zero only if allocated */ + if ( memflag ) + zero_seeds(); + break; + + case 'W': + if(!memflag) + zero_seeds(); /* get memory */ + + /* fire up sequence */ + + if ( !in_sequence ) + { + putchar ( ESC ); + putchar ( parameter ); + putchar ( group ); + } else + putchar ( old_terminator ); + + in_sequence = FALSE; /* terminating */ + + /* + ** Check to see if we are expecting another plane. + */ + + if(curr_plane < num_planes) + { + /* + ** If the input file does not have all the + ** expected planes (i.e., *b0W instead + ** of *b0V*b0V*b0W), then + ** special handling is needed. + */ + + if( curr_plane + 1 < num_planes ) + { + Process_Gap ( num ); + + } else /* don't worry, be happy */ + + Process(num, 'W'); + + } else /* oops, too many planes of data */ + + Process_extra(num,'W'); + + curr_plane=0; + + /* + ** If we were not already in graphics, then we are + ** now (implied start of raster graphics). + */ + + in_graphics = TRUE; + + return ( FALSE ); + + break; + + case 'V': + if(!memflag) + zero_seeds(); /* get memory */ + + /* + ** If curr_plane is the last plane, this should + ** be a 'W', not a 'V'. I could change it, + ** then I would fix Process_extra() to not output + ** anything as the 'W' was already sent. + */ + + if( curr_plane < num_planes ) + { + /* fire up sequence */ + + if ( !in_sequence ) + { + putchar ( ESC ); + putchar ( parameter ); + putchar ( group ); + } else + putchar ( old_terminator ); + + in_sequence = FALSE; /* terminating */ + + + Process(num, 'V'); + curr_plane++; + } else + Process_extra(num,'V'); + + /* + ** If we were not already in graphics, then we are + ** now (implied start of raster graphics). + */ + + in_graphics = TRUE; + + return ( FALSE ); + + break; + + default: + break; + } + + return ( TRUE ); /* pass sequence */ +} + + +/* +** Flush_To_Term() simply passes thru input until a valid terminator +** character is found. This is for unwanted escape sequences. +*/ + +Flush_To_Term() +{ + int c; + + do + { + c = getchar(); + + if ( c == EOF ) /* this is a problem */ + return; + + putchar ( c ); + + } while ( c < '@' || c > '^' ); +} + + +/* +** Flush_Bytes() simply transfers so many bytes directly from input to output. +** This is used to pass thru binary data that we are not interested in so that +** it will not confuse the parser. I.e. downloads. +*/ + +Flush_Bytes( num ) +unsigned int num; +{ + int bnum; + + while ( num > 0 ) + { + bnum = MIN ( BUFSIZ, num ); + + fread( buf, 1, bnum, stdin ); + + if ( fwrite( buf, 1, bnum, stdout ) < bnum ) + + /* check for error and exit */ + + if ( ferror(stdout) ) + { + perror("Output error"); + exit(-2); + } + + num -= bnum; + } +} + + + + +/*----------------------------------------*/ + +/* +** Zero_seeds() will allocate and initialize memory. +** If memory has already been allocated, then it will just initialize it. +*/ + + +zero_seeds() +{ + int r; + + /* first allocate and init seed_rows for number of planes. */ + + for ( r = 0; r < num_planes ; r++) + { + if(!memflag) + { + seed_row[r] = (unsigned char *) malloc(rasterwidth); + + if ( seed_row[r] == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(-3); + } + } + + /* zero seeds for mode 3 */ + + memset(seed_row[r], 0, rasterwidth); + } + + + if(!memflag) + { + new_row = (unsigned char *) malloc(rasterwidth); + + if ( new_row == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(-3); + } + + for(r=0; r rasterwidth ) + + horiz_offset = rasterwidth; + + /* + ** Zero out horiz_offset bytes in new_row. + */ + + if ( horiz_offset ) + + memset ( new_row, 0, horiz_offset ); + + + switch ( inmode ) { + + case 0: + if ( !widthwarning && inbytes > rasterwidth ) + { + /* This is likely to result in data truncation. */ + widthwarning = TRUE; + fprintf(stderr,"Warning: Input pixel width exceeds expected width.\n"); + } + + Uncompress_0( inbytes, rasterwidth - horiz_offset, + new_row + horiz_offset); + break; + case 1: + Uncompress_1( inbytes, rasterwidth - horiz_offset, + new_row + horiz_offset); + break; + case 2: + Uncompress_2( inbytes, rasterwidth - horiz_offset, + new_row + horiz_offset); + break; + case 3: + memcpy(new_row, seed_row[curr_plane], rasterwidth); + + if ( horiz_offset ) + memset ( new_row, 0, MIN( horiz_offset, rasterwidth ) ); + + Uncompress_3(inbytes, rasterwidth - horiz_offset, + new_row + horiz_offset); + break; + + default: /* unknown mode? */ + + /* Don't know what to do about seed rows, pass stuff thru */ + + fprintf(stderr, "%s: Unsupported compression mode %d.\n", + progname, inmode ); + + ChangeMode(inmode); /* go to that mode */ + + /* *b has already been output */ + + printf("%1d%c", inbytes, terminator); + + Flush_Bytes( inbytes ); + + firstrow = TRUE; /* pop it out of mode 3 */ + + /* Go ahead and clear the seed rows if present */ + if ( memflag ) + zero_seeds(); + + return; + + } + + /* + ** We need to account for the horizontal offset, but if strip_offsets + ** is on, then assume that zero is white. + */ + + if ( strip_offsets ) + horiz_offset = 0; + + + if ( mode0 ) + /* actually, this is redundant since new_row is mode 0 */ + out_size[0] = Compress_0( new_row + horiz_offset, out_row[0], + rasterwidth - horiz_offset ); + else + out_size[0] = MAXBYTES+1; + + if ( mode1 ) + out_size[1] = Compress_1( new_row + horiz_offset, out_row[1], + rasterwidth - horiz_offset ); + else + out_size[1] = MAXBYTES+1; + + if ( mode2 ) + out_size[2] = Compress_2( new_row + horiz_offset, out_row[2], + rasterwidth - horiz_offset ); + else + out_size[2] = MAXBYTES+1; + + if ( mode3 ) + out_size[3] = Compress_3( seed_row[curr_plane] + horiz_offset, + new_row + horiz_offset, out_row[3], + rasterwidth - horiz_offset ); + else + out_size[3] = MAXBYTES+1; + + + /* + ** Obsolete comment: + ** + ** Now determine which mode will give the best output. Note that it + ** takes 5 bytes to change modes, so we penalize all modes that are + ** not the current output by 5 bytes. This is to discourage changing + ** unless the benifit is worth it. The exception to this rule is + ** mode 3. We want to encourage going to mode 3 because of the seed + ** row behaviour. That is, if we have a simple picture that does + ** not change much, and say each of the sizes for modes 1 and 2 always + ** comes out to 4 bytes of data, then if we add 5 to mode 3 each time, + ** it would never get selected. But, we remove the penalty, and if + ** mode 3 is selected (0 bytes of data needed for mode 3), then each + ** succesive row only needs 0 bytes of data. For a 300 dpi A size + ** picture with 3 data planes, this could be a savings of 37k bytes. + */ + + /* + ** With the new parser, the output to change modes is now only + ** 2 bytes, since it gets combined with the *b#W sequence. + ** So, I decided to ignore the switching penalty. + */ + +#if 0 + /* + ** Due to a possible bug in PaintJet XL, don't allow mode 3 to be + ** selected for the first row of output. But do allow it if the + ** user has no other mode selected. + */ + + /* + ** Turns out that the PaintJet XL bug only happens after a Y-offset, + ** which was not being taken care of here anyway, and since + ** the one known driver that took advantage of this bug broke with + ** this code, I am now removing it. + */ + + if ( firstrow && (mode0 || mode1 || mode2) ) + { + out_size[3] = MAXBYTES+1; /* disable mode 3 for now */ + + if ( terminator == 'W' ) /* last plane? */ + firstrow = FALSE; /* no longer first row */ + } +#endif + + minmode = 3; + + if ( out_size[2] < out_size[minmode] ) + minmode = 2; + + if ( out_size[1] < out_size[minmode] ) + minmode = 1; + + if ( out_size[0] < out_size[minmode] ) + minmode = 0; + + + /* I may remove this sometime */ + if ( minmode != outmode ) + if ( out_size[minmode] == out_size[outmode] ) + minmode = outmode; + + + outuse[minmode]++; + + if ( outmode != minmode ) + ChangeMode( minmode ); + + /* *b has already been output */ + + printf("%1d%c", out_size[minmode], terminator); + + if ( fwrite( out_row[minmode], 1, out_size[minmode], stdout) < + out_size[minmode] ) + + /* check for error and exit */ + + if ( ferror(stdout) ) + { + perror("Output error"); + exit(-2); + } + + + memcpy(seed_row[curr_plane], new_row, rasterwidth); + + /* + ** Now clear horizontal offset for next plane. + */ + + horiz_offset = 0; + +} + + +/* +** Process_Gap() is to handle the case where less planes are sent for a +** row than we are expecting. For example, if we are expecting 3 planes +** per row, and the driver decides to take a short cut for blank areas and +** send only the final 'W' ( *b0W instead of the complete *b0V +** *b0V *b0W), then we have to do some special handling for mode +** 3 seed rows. +** +** The terminator is not needed as a parameter since we know that it must +** be 'W' to get into this routine. +*/ + +Process_Gap(bytes) +int bytes; +{ + char save0, save1, save2, save3; + + /* + ** If the input file does not have all the expected planes + ** (i.e., *b0W instead ** of *b0V*b0V*b0W), + ** then special handling is needed. + ** + ** 4 cases are handled: + ** + ** input mode output mode extra action + ** ---------- ----------- ------------ + ** + ** non-3 non-3 zero seeds + ** + ** 3 3 do nothing + ** + ** non-3 3 zero seeds & extra output + ** + ** 3 non-3 extra output + ** + ** Note: We don't know what the output + ** mode will be before we call Process(), + ** so we must force the modes. + */ + + /* + ** Save output modes in case we need to manipulate them. + */ + + save0 = mode0; + save1 = mode1; + save2 = mode2; + save3 = mode3; + + + if ( inmode != 3 ) + { + /* + ** Force output to non-3 + ** to do as little as possible. + */ + + if ( mode0 || mode1 || mode2 ) + { + mode3 = FALSE; + + Process(bytes, 'W'); + + mode3 = save3; /* restore mode 3 */ + + zero_upper( curr_plane + 1); + + } else /* mode 3 is only one allowed for output */ + { + /* + ** We must output more info. + */ + + Process( bytes, 'V' ); /* convert to plane */ + + curr_plane++; + + while ( curr_plane < num_planes ) + { + /* + ** Restart graphics data sequence. + */ + + putchar ( ESC ); + putchar ( '*' ); + putchar ( 'b' ); + + /* + ** Call Process() with 0 bytes instead + ** of just doing output because we + ** need Process() to zero the appropriate + ** seed rows, and to use mode 3 to clear + ** the seed rows in the output (printer). + */ + + if ( curr_plane + 1 == num_planes ) + + Process(0, 'W'); /* last plane */ + else + Process(0, 'V'); + + curr_plane++; + } + } + } else /* inmode == 3 */ + { + /* + ** Inmode is 3, so make outmode be 3 so we can do nothing. + */ + + if ( mode3 ) /* is mode 3 allowed? */ + { + mode0 = + mode1 = + mode2 = FALSE; + + Process(bytes, 'W'); + + mode0 = save0; /* restore modes */ + mode1 = save1; + mode2 = save2; + + } else /* ooops, no mode 3 */ + { + /* + ** We must output more info. + */ + + Process( bytes, 'V' ); /* convert to plane */ + + curr_plane++; + + while ( curr_plane < num_planes ) + { + /* + ** Restart graphics data sequence. + */ + + putchar ( ESC ); + putchar ( '*' ); + putchar ( 'b' ); + + /* + ** Call Process() with 0 bytes instead + ** of just doing output because we + ** need Process() to use the seed rows + ** to create non-mode3 data. + */ + + if ( curr_plane + 1 == num_planes ) + + Process(0, 'W'); /* last plane */ + else + Process(0, 'V'); + + curr_plane++; + } + } + } +} + + +/* +** Process_extra() is to handle the extra planes. That is, for PaintJets, +** when sending 3 planes of data using *b#V, many drivers send a +** fourth plane as *b0W to terminate the row, instead of the recommended +** 'W' as the 3rd plane. This routine handles the extra without disturbing +** the mode 3 seed rows. +** +** In the future, this routine could be used to strip out the 4th plane. +*/ + +Process_extra(bytes, terminator) +int bytes; +char terminator; +{ + int i; + + /* toss any excess data */ + + for(i = 0; i < bytes; i++) + getchar(); + + /* last plane? force move down to next row */ + + if(terminator == 'W') + { + /* *b has already been output */ + printf("0W"); + + firstrow = FALSE; /* not on first row anymore */ + + } + +} + +/* +** ChangeMode() simply outputs the sequence to change compression modes. +*/ + +ChangeMode(newmode) +int newmode; +{ + /* + ** *b have already been output. + ** terminator is 'm' instead of 'M' since will be followed by 'W' + */ + printf("%1dm", newmode); + outmode = newmode; +} + + +/*-----------------------------------------------------------------------*\ + | | + | Function Name: Uncompress_0 | + | | + | Description: | + | | + | This is the routine that handles a Mode 0 graphics block transfer | + | to the Formatter Module. | + | | +\*-----------------------------------------------------------------------*/ + +/* FUNCTION */ + +Uncompress_0(input_bytes, output_bytes, address) + +unsigned int + input_bytes, /* Count of bytes to be read. */ + output_bytes; /* Count of bytes to be stored. */ + +unsigned char + *address; /* Pointer to where to store bytes. */ + +{ + /* LOCAL VARIABLES */ + + unsigned char + *store_ptr; /* Pointer to where to store the byte. */ + + unsigned int + read_bytes, /* Local copy of input_bytes. */ + write_bytes; /* Local copy of output_bytes. */ + + /* CODE */ + + /* Initialize the local variables. */ + + read_bytes = input_bytes; + write_bytes = output_bytes; + store_ptr = address; + + + /* transfer the lesser of available bytes or available room */ + + Transfer_Block( MIN(write_bytes,read_bytes), store_ptr); + + /* now zero fill or throw excess data away */ + + if ( read_bytes > write_bytes ) + Discard_Block(read_bytes - write_bytes); /* throw excess */ + else { + store_ptr += read_bytes; /* adjust pointer */ + write_bytes -= read_bytes; /* zero fill count */ + + memset(store_ptr, 0, write_bytes); + } + + return ( input_bytes ); +} + + +/*-----------------------------------------------------------------------*\ + | | + | Function Name: Uncompress_1 | + | | + | Description: | + | | + | This is the routine that handles a Mode 1 graphics block transfer | + | to the Formatter Module. Mode 1 graphics is a compacted mode. | + | The data in Mode 1 is in pairs. The first byte is a replicate | + | count and the second byte is the data. The data byte is stored | + | then replicated the replicate count. Therefore a replicate count | + | of 0 means the data byte is stored once. The input byte count | + | must be an even amount for the data to be in byte pairs. | + | | +\*-----------------------------------------------------------------------*/ + +/* FUNCTION */ + +Uncompress_1(input_bytes, output_bytes, address) + +unsigned int + input_bytes, /* Count of bytes to be read. */ + output_bytes; /* Count of bytes to be stored. */ + +unsigned char + *address; /* Pointer to where to store bytes. */ + +{ + /* LOCAL VARIABLES */ + + unsigned char + *store_ptr, /* Pointer to where to store the byte. */ + input_char; /* Byte to be replicated. */ + + unsigned int + read_bytes, /* Local copy of input_bytes. */ + write_bytes; /* Local copy of output_bytes. */ + + int + replicate_count; /* Number of times to replicate data. */ + + /* CODE */ + + /* Initialize the local variables. */ + + read_bytes = input_bytes; + write_bytes = output_bytes; + store_ptr = address; + + /* Check for an even input count. */ + + if ((read_bytes % 2) == 0) + { + /* Even so input data is in pairs as required. So store the data. */ + + while ((read_bytes != 0) && (write_bytes != 0)) + { + /* First get the replicate count and the byte to store. */ + + replicate_count = (unsigned char) Get_Character(); + input_char = Get_Character(); + read_bytes -= 2; + + /* Since write_bytes was 0 there is room to store the byte. */ + + *store_ptr++ = input_char; + write_bytes--; + + /* Now make sure there is room for the replicated data. */ + + if (replicate_count > write_bytes) + { + /* Too much so limit to the room available. */ + + replicate_count = write_bytes; + } + + /* Update the amount to be written. */ + + write_bytes -= replicate_count; + + /* Then replicate it. */ + + while (replicate_count != 0) + { + /* Store the byte the decrement the count. */ + + *store_ptr++ = input_char; + + replicate_count--; + } + } + + } + /* Discard any left over input. */ + /* OR */ + /* Discard all of the input data as odd byte count. */ + + Discard_Block(read_bytes); + + read_bytes = store_ptr - address; /* how much was done? */ + + /* zero fill if needed */ + memset(store_ptr, 0, write_bytes); + + return(read_bytes); +} + + +/*-----------------------------------------------------------------------*\ + | | + | Function Name: Uncompress_2 | + | | + | Description: | + | | + | This is the routine that handles a Mode 2 graphics block transfer | + | to the Formatter Module. Mode 2 graphics is a compacted mode. | + | The data in Mode 2 is of one of two types. The first type is a | + | class type and the second type is a data type. The class type is | + | a single byte which is a combination of replicate count and a sub | + | mode. There are two sub modes within mode 2, sub mode 0 and sub | + | mode 1. These sub modes are flagged by the MSB of the class type | + | byte. If the MSB = 0 then the replicate count is the value of the | + | class type byte. In sub mode 0 the replicate count ranges from 1 | + | to 127. In sub mode 0 the next byte and then the replicate count | + | of bytes are of the data type and stored. If the MSB = 1 then the | + | sub mode is 1 and the replicate count is the negative value of the | + | class type. In sub mode 1 the replicate count is stored in 2s | + | compliment form and ranges from -1 to -127. In sub mode 1 the | + | next byte is of the data type and is stored. That data byte is | + | then replicated and stored the replicate count. If the class type | + | byte is 128 then there is no data type byte. | + | | +\*-----------------------------------------------------------------------*/ + +/* FUNCTION */ + +Uncompress_2(input_bytes, output_bytes, address) + +unsigned int + input_bytes, /* Count of bytes to be read. */ + output_bytes; /* Count of bytes to be stored. */ + +unsigned char + *address; /* Pointer to where to store bytes. */ + +{ + /* LOCAL VARIABLES */ + + unsigned char + *store_ptr, /* Pointer to where to store the byte. */ + input_char, /* Byte to be replicated. */ + sub_mode; /* Flag if sub mode is 0 or 1. */ + + unsigned int + read_bytes, /* Local copy of input_bytes. */ + write_bytes; /* Local copy of output_bytes. */ + + int + replicate_count; /* Number of times to replicate data. */ + + /* CODE */ + + /* Initialize the local variables. */ + + read_bytes = input_bytes; + write_bytes = output_bytes; + store_ptr = address; + + while ((read_bytes > 1) && (write_bytes != 0)) + { + /* First get the class type byte and the first data type byte. */ + + replicate_count = Get_Character(); + + /* First check that this not an ignore class type. */ + + if (replicate_count != 128) + { + /* Not ignore so get the data class byte. */ + + input_char = Get_Character(); + read_bytes -= 2; + + /* Since write_bytes wasn't 0 there is room to store the byte. */ + + *store_ptr++ = input_char; + write_bytes--; + + /* Determine the sub mode. */ + + if (replicate_count > 128) + { + /* Sub mode 1. */ + + sub_mode = 1; + /* replicate count was unsigned char */ + replicate_count = 256 - replicate_count; + } + else + { + /* Sub mode 0. */ + + sub_mode = 0; + + /* See if there is enoungh input left for the data byte count. */ + + if (replicate_count > read_bytes) + { + /* Too many data bytes so limit to the input left. */ + + replicate_count = read_bytes; + } + } + + /* Now make sure there is room for the replicated data. */ + + if (replicate_count > write_bytes) + { + /* Too much so limit to the room available. */ + + replicate_count = write_bytes; + } + + /* Update the amount to be written. */ + + write_bytes -= replicate_count; + + /* Then replicate it. */ + + if (sub_mode == 0) + { + /* Sub mode 0 so get the replicate count of data bytes. */ + + Transfer_Block(replicate_count, store_ptr); + + read_bytes -= replicate_count; + + /* Find the last byte stored. */ + + store_ptr += replicate_count; + } + else + { + /* Sub mode 1 so just duplicate the original byte. */ + + while (replicate_count != 0) + { + /* Store the byte the decrement the count. */ + + *store_ptr++ = input_char; + + replicate_count--; + } + } + } + else + { + /* Ignore class so don't get the data class byte. */ + + read_bytes--; + } + } + + /* Now discard any left over input. */ + + Discard_Block(read_bytes); + + read_bytes = store_ptr - address; + + /* zero fill if needed */ + memset(store_ptr, 0, write_bytes); + + + return(read_bytes); +} + + +/*-----------------------------------------------------------------------*\ + | | + | Function Name: Uncompress_3 | + | | + | Description: | + | | + | This is the routine that handles a Mode 3 graphics block transfer | + | to the Formatter Module. Mode 3 graphics is a compacted mode. | + | Mode 3 data is a difference from one row to the next. In order to | + | work, each row must be saved to be a seed for the next. This | + | mode is used in conjuction with other compaction modes when the | + | data remains fairly constant between pairs of rows. | + | The data is in the form: | + | []<1 to 8 replacement bytes> | + | The command byte is in the form: | + | Bits 5-7: Number of bytes to replace (1 - 8) | + | Bits 0-4: Relative offset from last byte. | + | (If the offset is 31, then add the following bytes for offset | + | until an offset byte of less then 255 (but inclusive) | + | | +\*-----------------------------------------------------------------------*/ + +/* FUNCTION */ + +Uncompress_3(input_bytes, output_bytes, address) + +unsigned int + input_bytes, /* Count of bytes to be read. */ + output_bytes; /* Count of bytes to be stored. */ + +unsigned char + *address; /* Pointer to where to store bytes. */ + +{ + /* LOCAL VARIABLES */ + + unsigned char + *store_ptr; /* Pointer to where to store the byte. */ + + unsigned int + read_bytes, /* Local copy of input_bytes. */ + write_bytes; /* Local copy of output_bytes. */ + + unsigned int + replace, /* number of bytes to replace, 1-8 */ + offset; /* relative offset */ + + unsigned char command; + + /* CODE */ + + /* Initialize the local variables. */ + + read_bytes = input_bytes; + write_bytes = output_bytes; + store_ptr = address; + + /* + ** read_bytes has to be at least 2 to be valid + */ + + while ( read_bytes > 1 && write_bytes > 0 ) + { + + /* start by getting the command byte */ + + command = Get_Character(); + + replace = (command >> 5) + 1; + offset = command & 0x1f; + + read_bytes--; + + /* + ** Sometimes offsets go past the end. If so, bail. + */ + + if ( offset >= write_bytes ) + break; + + write_bytes -= offset; + store_ptr += offset; + + /* + ** If the first offset value is 31, then we must + ** get more offsets until we encounter a byte value + ** less than 255 (even if it's 0). + */ + + if ( offset == 31 ) /* get more offsets */ + + do{ + offset = Get_Character(); + + read_bytes--; + + /* + ** Check for pre-mature finish + */ + + if ( read_bytes == 0 ) + return; + + /* + ** Check for excessive offset. + */ + + if ( offset >= write_bytes ) + { + /* + ** Resetting write_bytes is needed + ** to get out of outer loop so + ** that the call to Discard_Block() + ** is made at the end. + */ + + write_bytes = 0; + break; + } + + write_bytes -= offset; + store_ptr += offset; + + } while (offset == 255); /* 255 = keep going */ + + /* now do the byte replacement */ + + while ( replace-- && write_bytes > 0 && read_bytes > 0 ) + { + *store_ptr++ = Get_Character(); + read_bytes--; + write_bytes--; + } + } + + /* + ** Don't do any zero fill with mode 3, + ** and discard any leftover input. + */ + + Discard_Block(read_bytes); + + return; +} + + +Discard_Block(count) +unsigned int count; +{ + while ( count-- ) + getchar(); +} + +Transfer_Block( count, dest ) +unsigned int count; +unsigned char *dest; +{ + fread(dest, 1, count, stdin); +} + + +/* +** Compress_0() does mode 0 compression (which is a no compression). +*/ + +Compress_0(src, dest, count) +unsigned char *src, *dest; +int count; +{ + memcpy(dest, src, count); + + if ( zerostrip ) + while ( count && dest[count-1] == 0 ) + count--; + + return(count); + +} + + + +/* +****************************************************************************** +** +** Compress_1() does PCL compression mode 1 on the data. +** This mode is run length encoding. +** +** Given an input byte count of n, then the worst case output size +** would be 2 * n. +** +****************************************************************************** +*/ + +Compress_1(src, dest, count) +unsigned char *src, *dest; +register int count; +{ + unsigned char *outptr = dest, *inptr = src; + + unsigned char data; /* data values to match */ + + unsigned char temp; + + int repcount; /* repeat count */ + + + /* + ** "count" is the number of bytes in "src" to compress + ** into "dest". + */ + + while ( count ) + { + data = *inptr++; /* get value to work with */ + count--; + + repcount = 0; /* no repeats yet */ + + /* + ** Look for successive bytes that match "data". + */ + + while ( count && *inptr == data ) + { + repcount++; + inptr++; + count--; + } + + /* + ** Now if we are out of data (count == 0), then + ** if the repeated byte was zero, then we can ignore it + ** unless the user disabled zero stripping. + */ + + if ( count == 0 && data == 0 && zerostrip ) + break; /* done */ + + /* + ** Now output the repeat count and the value. + ** + ** If the repeat count exceeds 255, then we must send + ** more repeat-value pairs. + ** + ** Each time thru the loop, repcount needs to be decremented + ** to keep in sync. That is, if repcount == 256, then the + ** first time thru the loop, <255> are output, then + ** repcount is now 1. So the next time thru the loop, + ** repcount needs to be adjusted to 0 so that the next pair + ** is <0> . Thus, 1 data plus 255 repeats of data + ** plus 1 data + 0 repeats of data ==> 257 total bytes + ** of "data", which is what a repcount of 256 means. + */ + + do + { + temp = MIN(repcount, 255); + + *outptr++ = temp; + + repcount -= temp; + + *outptr++ = data; + + } while ( repcount-- ); + } + + return ( outptr - dest ); /* size of compressed data */ +} + + +/* +****************************************************************************** +** +** Compress_2() does PCL compression mode 2 on the data. +** This mode is a combination of modes 0 and 1. +** +** Given an input byte count of n, then the worst case output size +** would be n + (n + 127)/128. +** +****************************************************************************** +*/ + +Compress_2(src, dest, count) +unsigned char *src, *dest; +register int count; +{ + unsigned char *outptr, *inptr; + unsigned char *saveptr; + + unsigned char data; /* data byte */ + unsigned char lastbyte; /* last byte */ + int repcount; /* repeat count */ + int litcount; /* literal count */ + + /* + ** src points to the input data. + ** dest points to the output buffer. + ** count is the number of input bytes. + */ + + inptr = src; + outptr = dest; + + /* + ** Start loop thru data. Check for possible repeat at beginning. + */ + + while ( count ) + { + data = *inptr++; /* get value to work with */ + count--; + + repcount = 0; /* no repeat count yet */ + + + /* + ** Check for repeat, since we are not in the middle + ** of a literal run, it does not have to be more than + ** two bytes of similar data. + */ + + while ( count && *inptr == data ) + { + repcount++; + inptr++; + count--; + } + + /* + ** Now, if we are out of data (count == 0), then + ** if the repeated byte was zero, then ignore it + ** completely (don't bother outputing the trailing zeros). + ** + ** To always strip zero's, simply remove the "zerostrip" + ** from the test. + */ + + if ( count == 0 && data == 0 && zerostrip) + break; /* done */ + + + /* + ** If there was a repeat (repcount > 0), then we + ** can output the command here, otherwise, we + ** need to go into literal run mode. + ** + ** Note: This is a while loop because the repeat count + ** may actually be greater than 127. + */ + + if ( repcount >= 1 ) /* repeat mode */ + { + while (repcount > 127) + { + *outptr++ = 129; /* count 127 */ + *outptr++ = data; /* value */ + repcount-= 128; /* offset */ + } + + if (repcount > 0) + { + *outptr++ = 256 - repcount; /* count */ + *outptr++ = data; /* value */ + + /* + ** Now pop to the top of the loop + ** looking for more repeat counts. + */ + + continue; /* top of loop */ + } + + /* + ** Special case: If we have arrived at this point, + ** then repcount is now equal to 0. This means + ** that when we entered this section, repcount + ** was a multiple of 128 (i.e. 128 :-). + ** + ** This means that there were 129 identical bytes, + ** so the output does a replicate of 127 which + ** gives 128 bytes, and we now have one byte left + ** over which should NOT be output as a repeat + ** run, rather it should be merged into the following + ** literal run (if it exists). + ** + ** So, we will simply fall thru to the next section + ** of code which assumes that we are working on + ** a literal run. + */ + + } + + /* + ** Literal run: At this point, the current data byte + ** does NOT match the following byte. We will transfer + ** these non-identical bytes until: + ** + ** 1) we run out of input data (count == 0). + ** 2) we run out of room in this output block (128) + ** 3) we come across a value which occurs at least + ** three times in a row. A value occuring only + ** twice in a row does NOT justify dropping + ** out of a literal run. + ** + ** Special case: If we run out of room in the output block + ** (which is 128 bytes), the last two values are the same, + ** AND there is more input, it makes sense to restart + ** the repeat detector in case the following bytes are + ** repeats of the two. A simple check of the following + ** byte will determine this. + ** (This case falls out with the test for triples below). + ** + ** Special case: If we run out of room in the output block + ** (which is 128 bytes), the last value is the same as + ** the next one on the input, then it is better to let + ** that byte be used in a possible replicate run following + ** the literal run. If the last byte matches ONLY the + ** following byte, (and not the one after that,) it is + ** a wash, but for best results, we will test the + ** following two bytes. + ** + */ + + litcount = 0; + saveptr = outptr++; /* save location of the command byte */ + + *outptr++ = data; /* save the first byte. */ + + lastbyte = data; /* remember for testing */ + + while ( count && litcount < 127 ) + { + data = *inptr++; + count--; + litcount++; + *outptr++ = data; + + /* + ** Test to see if this byte matched the last one. + ** If so, check the next one for a triple. + */ + + if ( lastbyte == data && count && *inptr == data ) + { + /* + ** We have a triple, adjust accordingly. + ** + ** Add two bytes back onto the input. + */ + + count += 2; + inptr -= 2; + outptr -= 2; + litcount -= 2; + + break; /* out of loop */ + } + + lastbyte = data; /* save data byte */ + } + + /* + ** Check the special case number 2 above. + */ + + if ( litcount == 127 && count > 1 && data == *inptr + && data == inptr[1] ) + { + /* Restore the last byte to the input stream */ + + count += 1; + inptr -= 1; + outptr -= 1; + litcount -= 1; + } + + + /* + ** Save the literal run count. + */ + + *saveptr = litcount; + + /* + ** Now go back to the top and look for repeats. + */ + } + + count = outptr - dest; /* for return value */ + + return ( count ); +} + + + +/* +****************************************************************************** +** +** Compress_3() does PCL compression mode 3 on the data. +** This mode is delta row encoding. +** +** Given an input byte count of n, then the worst case output size +** would be n + (n + 7)/8 +** +****************************************************************************** +*/ + +Compress_3(seed, new, dest, count) +unsigned char *seed, *new, *dest; +register int count; +{ + unsigned char *sptr=seed, *nptr=new, *dptr=dest; + unsigned char *saveptr; + + int delta, xfer; + unsigned char command; + + + /* + ** "count" is the number of bytes of data in "new" that need to + ** be compressed into "dest" using "seed" as the basis for diffs. + */ + + while ( count > 0 ) + { + delta = 0; /* position counter */ + + /* + ** Hunt through the data until the new data is different + ** from the seed data. + */ + + while ( *sptr == *nptr && delta < count ) + { + delta++; + sptr++; + nptr++; + } + + /* + ** Either a difference has been found, or we ran out of data. + */ + + if ( delta >= count ) /* too far */ + break; /* done */ + + count -= delta; + + /* + ** Now set up the output with the command byte[s]. + ** (leaving the actual byte copy count till last.) + */ + + /* + ** The first command byte can only hold up to 31. + ** If the delta is larger, then following bytes will + ** be needed. + */ + + saveptr = dptr++; /* save the address for command byte */ + + command = MIN(delta, 31); + + /* + ** Any remaining count follows. + ** + ** If count is 31, then a following byte must be given, + ** even if 0. Same holds if 255 is given in succesive bytes. + */ + + if ( command == 31 ) + { + delta -= command; /* adjust for first count */ + + do { + xfer = MIN(delta,255); + + delta -= xfer; + + *dptr++ = xfer; + + } while ( xfer == 255 ); + + + } + + + /* + ** Now transfer up to 8 bytes, stopping when the new byte + ** matches the seed byte. One could make a case for + ** transfering a matching byte too (if stuck in the middle + ** of the 8 bytes), but it does not impact the worst case, + ** and in the long run, the compression will not be as good. + ** Also, we need to make sure that we don't overrun count. + ** ("count" is checked first so we don't reference past the + ** end of the memory block). + */ + + for ( xfer = 0; + count && *sptr != *nptr && xfer < 8; + xfer++) + { + *dptr++ = *nptr++; /* transfer byte */ + sptr++; /* bump seed pointer too */ + count--; + } + + /* + ** Now xfer is the number of bytes transfered, but the + ** number range is 3 bits (0-7), so decrement and merge + ** it into the command byte and put it in the data. + */ + + command += ((xfer - 1) << 5); + + *saveptr = command; + + } + + return ( dptr - dest ); +} + + +/*----------------------------------------------------------------------*\ + * This is here in case *rU is sent after *r#A, in which case * + * we must deallocate the memory to provide for a different amount of * + * planes when graphics are sent. * +\*----------------------------------------------------------------------*/ + +free_mem() +{ + int r; + + + if ( !memflag ) + return; /* no memory to free */ + + free(new_row); + + for(r = MAXMODES -1; r >= 0; r--) + free(out_row[r]); + + for(r = num_planes - 1; r >= 0; r--) + free(seed_row[r]); + + memflag = FALSE; +} + +/* +** Get_Frac() simply gets the fractional part of a value. This is here +** because scanf() will consume a trailing 'e' or 'E', which is a problem +** in PCL. +*/ + +static float Get_Frac() +{ + float result = 0.0; + int c; + float position = 10.0; + + while ( (c = getchar()) != EOF ) + { + /* + ** Do we have a digit? + */ + + if ( !isdigit(c) ) /* not a digit */ + { + ungetc( c, stdin ); /* put it back */ + break; /* quit */ + } + + result += ((c - '0') / position); + + position *= 10.0; + } + + return ( result ); +} Index: xc/programs/pclcomp/pclcomp.man =================================================================== RCS file: xc/programs/pclcomp/pclcomp.man diff -N xc/programs/pclcomp/pclcomp.man --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/pclcomp/pclcomp.man 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,155 @@ +.TH PCLCOMP 1 +.SH NAME +pclcomp \- Compress PCL graphics files. +.SH SYNOPSIS +.B pclcomp +[ +.B "-0123drsvxz" +] +[ +.B "-n" +.I num +] +[ +.I infile +[ +.I outfile +]] +.br +.SH DESCRIPTION +.PP +.B Pclcomp +compresses (or decompresses) HP-PCL (Printer Control Language) graphics data. +The supported compression modes are 0 (uncompressed), 1, 2 and 3. +.B Pclcomp +will read files using any of the modes 0 through 3, and will output using the +modes which will give the best compression. This compressed version of +the file may be sent directly to a PCL compatible printer, thus reducing +I/O bandwidth. Pictures may also be saved in compressed form, reducing +disk usage. +In addition, PCL "imaging" files for the PaintJet XL are also supported. +.PP +The options to +.B pclcomp +control the compression modes. By default, +.B pclcomp +will use modes 0, 2 and 3, but the user may restrict which output +modes it uses by specifying them on the command line with the +.B -0, +.B -1, +.B -2 +and +.B -3 +options. To decompress a file, simply specify +.B -0 +as the only mode to use for output. Mode 0 ( +.B -0 +) should always be allowed since modes 1, 2 and 3 cannot be guaranteed to +be better than mode 0 for all types of pictures. +.PP +The +.B -z +option disables the zero "strip" feature. Since most printers do +zero "filling", +.B pclcomp, +by default, "strips" the trailing zeros of each row (or plane) of data. +Some printers or programs may require that zero "stripping" be disabled. +.PP +By default, +.B pclcomp +expects the input raster width to be 2400 pixels (8" at 300 dpi), and if it is +different (e.g. PaintJet), then the raster width should be specified by +the Source Raster Width escape sequence +.I (*r#S). +However, many applications do not set the width and assume a default, therefore, +the user may use the +.B -n +option to +.B pclcomp +to specify a new default raster width. For PaintJet (8" at 180 dpi), the +number should be 1440. If the PCL file contains the Source Raster Width +escape sequence, it will override this default. If +.B pclcomp +thinks that more data is coming in than the specified width, it will +generate a warning, and continue processing (and perhaps truncating) data. +.PP +The +.B -x +option will cause +.B pclcomp +to remove any horizontal offset sequences from the data. Only use this +option if white is defined to be zero (as with LaserJets). This will +shrink the data more if modes 2 or 3 are used. +.PP +The +.B -r +option causes +.B pclcomp +to append a +reset sequence +.I "(E)" +to the end of the job. +.PP +Use the +.B "-d" +option to +.B pclcomp +if the output is to be sent to a DeskJet printer. +.PP +Some applications erroneously send +.I "*rB" +and +.I "*rA" +sequences between every row of graphics data. The +.B -s +option to +.B pclcomp +will "strip" all +.I "*rB" +sequences, and all +.I "*rA" +sequences after the first occurrence of this sequence. +In addition, text and control characters residing between +.I "*rA" +and +.I "*rB" +sequences will be discarded. +While this will work +well +for many jobs, it may have problems on multi-page or complex jobs. +.PP +The +.B -v +option simply gives statistics to +.I stderr +about which compression modes were used. +.SH EXAMPLES +.nf +To compress a PCL file for LaserJet III, use: + pclcomp infile outfile + +To compress a PCL file for the PaintJet (A size page at 180 dpi), use: + pclcomp -01 -n 1440 infile outfile + +To compress a PCL file for DeskJet, use: + pclcomp -d012 infile outfile + +To fully decompress a PCL file, use: + pclcomp -0z < infile > outfile +.fi +.SH WARNINGS +.PP +The +.B -z +option can cause the output to be larger than the input. +.PP +The +.B -s +option is useful, but it can cause erroneous output. +.PP +The +.B -x +option can cause black areas on the left side of the picture on color +printers. +.SH AUTHOR +Tony Parkhurst, Hewlett-Packard, San Diego Division (tony@sdd.hp.com) Index: xc/programs/pclcomp/printer.note =================================================================== RCS file: xc/programs/pclcomp/printer.note diff -N xc/programs/pclcomp/printer.note --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/pclcomp/printer.note 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,31 @@ + + +Here is a list of HP printers and the compression modes they support: + + + +Printer Modes +------- ----- + +LaserJet 0 +LaserJet+ 0 +LaserJet 500 0 +LaserJet 2000 0 +LaserJet II 0 +LaserJet IID 0 +LaserJet IIP 0 1 2 +LaserJet III 0 1 2 3 +LaserJet IIID 0 1 2 3 +LaserJet IIISi 0 1 2 3 +LaserJet IIIP 0 1 2 3 5 (Method 5 is not supported by pclcomp) + +DeskJet 0 1 2 +DeskJet+ 0 1 2 +DeskJet 500 0 1 2 3 +DeskJet 500 C 0 1 2 3 9 (Method 9 is not supported by pclcomp) + +PaintJet 0 1 +PaintJet XL 0 1 2 3 + + +Mode 0 is uncompressed graphics data. Index: xc/programs/xpr/Imakefile =================================================================== RCS file: xc/programs/xpr/Imakefile diff -N xc/programs/xpr/Imakefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/Imakefile 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,11 @@ +XCOMM $XConsortium: Imakefile,v 1.9 91/07/17 00:46:26 gildea Exp $ + DEPLIBS = $(DEPXMULIB) $(DEPXLIB) +LOCAL_LIBRARIES = $(XMULIB) $(XLIB) + DEFINES = -DNOINLINE + + SRCS = xpr.c x2pmp.c x2jet.c + OBJS = xpr.o x2pmp.o x2jet.o + +ComplexProgramTarget(xpr) +InstallScript(xdpr,$(BINDIR)) +InstallManPage(xdpr,$(MANDIR)) Index: xc/programs/xpr/lncmd.h =================================================================== RCS file: xc/programs/xpr/lncmd.h diff -N xc/programs/xpr/lncmd.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/lncmd.h 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,52 @@ +/* $XConsortium: lncmd.h,v 10.8 94/04/17 20:44:03 rws Exp $ */ +/* + +Copyright (c) 1985 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ + + +/* lncmd.h - Command sequences DEC printers, in particular LN0x laser + printers */ + +/* +#define LN_RIS "\033c" Obsolete; causes LN03+ problems +*/ +#define LN_STR "\033[!p" +#define LN_SSU "\033[%d I" +#define LN_PUM_SET "\033[11h" +#define LN_PFS "\033[%s J" +#define LN_DECSLRM "\033[%d;%ds" +#define LN_HPA "\033[%d`" +#define LN_VPA "\033[%dd" +#define LN_SIXEL_GRAPHICS "\033P%d;%d;%dq" +#define LN_ST "\033\\" +#define LN_DECOPM_SET "\033[?52h" +#define LN_DECOPM_RESET "\033[?52I" +#define LN_SGR "\033[1%dm" +#define LN_PUM "\033[11I" +#define LN_LNM "\033[20h" Index: xc/programs/xpr/pmp.h =================================================================== RCS file: xc/programs/xpr/pmp.h diff -N xc/programs/xpr/pmp.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/pmp.h 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,66 @@ +/* + * $XConsortium: pmp.h,v 1.5 91/02/19 22:13:33 converse Exp $ + */ + +/* Written by Jose' J. Capo' */ +/* (jjc@comet.lcs.mit.edu), June 1987 */ + +/* WARNING!!!: Include this header after the standard headers (like */ + /* ) of the following might cause another header to */ + /* redefine BUFSIZ */ +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif + +#define MAX_FRAME_LEN 512 +#define MAX_VECTOR_LEN 65535 + +#define DBG(cond) if (dbg cond) +#define DEBUG(cond) if (debug cond) +#define min(a,b) ((a) < (b)? (a) : (b)) + +#define pel2inch(pels) ((float) ((pels) / PPI)) +#define ppmask(rounded,thickness) (0x20 * (rounded) + (thickness)) + + +#define min(a,b) ((a) < (b)? (a) : (b)) +#define lo(x) ((x) & 0xFF) +#define hi(x) (((x) & 0xFF00) >>8) +#define hi2(x) (((x) & 0xFF0000) >>16) +#define p_wput(w, f) {\ + (void) putc(hi(w), (f)); \ + (void) putc(lo(w), (f));\ + } +#define PMP(f, len) { fprintf(f, "\033[C"); \ + p_putlh(f, len);\ + } +#define p_putlh(f, w) {\ + (void) putc(lo(w), (f));\ + (void) putc(hi(w), (f)); \ + } + +/* hi-lo 2-byte integer */ +/* int hl2int(unsigned char *) */ +#define hl2int(hl2) ((int) (0x100 * *(hl2) + *((hl2)+1))) + +/* putlh2(FILE *, int) */ +#define puthl2(i, f) { (void) putc(hi((i)), (f));\ + (void) putc(lo((i)), (f));\ + } + +/* hi-lo 3-byte integer */ +/* long hl3long(unsigned char *) */ +#define hl3long(hl3) ((long) (0x10000 * *(hl3) + \ + 0x100 * *((hl3)+1) + *((hl3)+2))) + +/* puthl3(FILE *, long) */ +#define puthl3(l, f) { (void) putc(hi2((l)), (f));\ + (void) putc(hi((l)), (f));\ + (void) putc(lo((l)), (f));\ + } + +/* int int2sgn(int) */ +#define int2sgn(i) (((i) > 0x8000 - 1)? (i)- 0x10000: (i)) + +/* int long3sgn(long) */ +#define long3sgn(l) (((l) > 0x800000 - 1)? (l) - 0x1000000 : (l)) Index: xc/programs/xpr/x2jet.c =================================================================== RCS file: xc/programs/xpr/x2jet.c diff -N xc/programs/xpr/x2jet.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/x2jet.c 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,1577 @@ +/* $XConsortium: x2jet.c,v 1.6 94/04/17 20:44:03 rws Exp $ */ + +/* -*-C-*- +******************************************************************************** +* +* File: x2jet.c +* RCS: x2jet.c,v 1.23 89/07/17 12:02:51 lori Exp +* Description: xpr support for HP LaserJet and PaintJet printers +* Author: Larry Rupp, HP Graphics Technology Division +* Created: Fri Jul 15 15:22:26 1988 +* Modified: Thu Sep 15 11:59:34 1988 (Larry Rupp) ler@hpfcler +* Tue Dec 6 10:04:43 PST 1988 (Marc Ayotte) marca@hp-pcd +* Language: C +* Package: N/A +* Status: Released to MIT +* +* (c) Copyright 1988, Hewlett-Packard Company. +* +******************************************************************************** +*/ + + + + + +/******************************************************** + +Copyright (c) 1988 by Hewlett-Packard Company + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that +Hewlett-Packard not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +********************************************************/ +/* + +Copyright (c) 1988 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ + + +#include +#include +#include + +#include "xpr.h" + +#ifdef NLS16 +#ifndef NLS +#define NLS +#endif +#endif + +#ifndef NLS +#define catgets(i, sn,mn,s) (s) +#else /* NLS */ +#define NL_SETN 2 /* set number */ +#include + +extern char *catgets(); +extern nl_catd nlmsg_fd; + +#endif /* NLS */ + +#ifndef TRUE +# define FALSE 0 +# define TRUE 1 +#endif + +/* default printable page area (inches) */ +#define STDWIDTH 8.0 +#define STDHEIGHT 10.5 + +/* header & trailer character cell size (centipoints) */ +#define CHARWIDTH 720 +#define CHARHEIGHT 1200 + +#define XWDHEADERSIZE (sizeof(XWDFileHeader)) +#define XCOLORSIZE (sizeof(XColor)) + + +typedef struct { long width, height; } Area; +typedef struct { long x, y; } Location; + + +static Area limit; /* image clip limits (dots) */ +static Area page; /* printable page size (centipoints) */ + +static Location headerloc; /* centipoint location of header string */ +static Location trailerloc; /* centipoint location of trailer string */ +static Location imageloc; /* centipoint location of image */ + +static int headerlimit; /* number of chars which will printed for */ +static int trailerlimit; /* the image's header/trailer strings */ + +static XWDFileHeader xwd_header; + +static XColor *xwd_colors; + +static char *xwd_image; + +static unsigned long Z_pixel_mask; + +static int true_scale; + +extern char *progname; + +void fatal_err(); +void fatal_err2(); + +/* Computes the centipoint width of one printer dot. */ +#define dot_centipoints(s,d) ((7200.0 * s) / d) + + +void set_image_limits (scale, density, orient, print_area) +int scale, density; +enum orientation orient; +Area print_area; +{ + Area print_dots; + double dotsize; + + /* Set dotsize to the centipoint width of one printer dot. */ + dotsize = dot_centipoints(scale, density); + + if (orient == PORTRAIT) { + print_dots.width = print_area.width / dotsize; + print_dots.height = print_area.height / dotsize; + } else { + print_dots.height = print_area.width / dotsize; + print_dots.width = print_area.height / dotsize; + } + + limit.width = (print_dots.width < xwd_header.pixmap_width) + ? print_dots.width : xwd_header.pixmap_width; + limit.height = (print_dots.height < xwd_header.pixmap_height) + ? print_dots.height : xwd_header.pixmap_height; + + if ((limit.width != xwd_header.pixmap_width) + || (limit.height != xwd_header.pixmap_height)) + fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,1, "%s: Warning: %ld x %ld image clipped to %ld x %ld.\n")), + progname, + xwd_header.pixmap_width, xwd_header.pixmap_height, + limit.width, limit.height); +} + + + +void set_header_trailer_limits (header, trailer, printwidth) +char *header, *trailer; +long printwidth; +{ + /* Determine the number of header and trailer characters + * that will fit into the available printing area. + */ + headerlimit = header ? (((strlen(header) * CHARWIDTH) <= printwidth) + ? strlen(header) : (printwidth / CHARWIDTH)) + : 0; + if (header && headerlimit != strlen(header)) { + fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,2, + "%s: Warning: Header string clipped to %d characters.\n")), + progname, headerlimit); + header[headerlimit] = '\0'; + } + + trailerlimit = trailer ? (((strlen(trailer) * CHARWIDTH) <= printwidth) + ? strlen(trailer) : (printwidth / CHARWIDTH)) + : 0; + if (trailer && trailerlimit != strlen(trailer)) { + fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,3, + "%s: Warning: Trailer string clipped to %d characters.\n")), + progname, trailerlimit); + trailer[headerlimit] = '\0'; + } +} + + +void set_print_locations (scale, density, top, left, + header, trailer, orient, position_on_page) +int scale, density; +int top, left; +char *header, *trailer; +enum orientation orient; +int position_on_page; +{ + Area image; + double dotsize; + + /* Set dotsize to the centipoint width of one printer dot. */ + dotsize = dot_centipoints(scale, density); + + /* Compute the centipoint size of the clipped image area. */ + if (orient == PORTRAIT) { + image.width = limit.width * dotsize; + image.height = limit.height * dotsize; + } else { + image.height = limit.width * dotsize; + image.width = limit.height * dotsize; + } + + if (position_on_page) { + /* set vertical positions */ + imageloc.y = (top >= 0) + ? top * 24 + ((header) ? CHARHEIGHT : 0) + : ((page.height - ((header) ? CHARHEIGHT : 0) + - image.height - ((trailer) ? CHARHEIGHT : 0)) / 2) + + ((header) ? CHARHEIGHT : 0); + headerloc.y = imageloc.y - CHARHEIGHT / 4; + trailerloc.y = imageloc.y + image.height + (3 * CHARHEIGHT) / 4; + + /* set horizontal positions */ + if (left >= 0) + headerloc.x = imageloc.x = trailerloc.x = left * 24; + else { + headerloc.x = (page.width - headerlimit * CHARWIDTH) / 2; + imageloc.x = (page.width - image.width) / 2; + trailerloc.x = (page.width - trailerlimit * CHARWIDTH) / 2; + } + } +} + + +int scale_raster (density, orient, print_area) +int density; +enum orientation orient; +Area print_area; +{ + Area image; + int h_scale, v_scale; + + /* Set the image dimensions to the number of centipoints that would be + * required for printing at the selected density. + */ + if (orient == PORTRAIT) { + image.width = xwd_header.pixmap_width * 7200 / density; + image.height = xwd_header.pixmap_height * 7200 / density; + } else { + image.height = xwd_header.pixmap_width * 7200 / density; + image.width = xwd_header.pixmap_height * 7200 / density; + } + + /* Calculate the maximum image multiplier along + * the horizontal and vertical dimensions. + */ + h_scale = print_area.width / image.width; + v_scale = print_area.height / image.height; + + /* If the image can be expanded, return the lesser of the horizontal and + * vertical multipliers. Otherwise, the image will not completely fit + * the available print area, so just return 1 as the expansion factor. + */ + return (((h_scale > 0) && (v_scale > 0)) + ? ((h_scale= 0) ? width * 24 : STDWIDTH * 7200; + page.height = (height >= 0) ? height * 24 : STDHEIGHT * 7200; + + /* Paintjet Xl has a mechanical form feed, not a strip feed. It has + * a slop of about 1/4 to 1/2 of an inch at the top and bottom. + * deduct it from the page height. + */ + if (device == PJETXL) + page.height = page.height - 7200; + + /* Determine the area usable for the image. This area will be smaller + * than the total printable area if margins or header/trailer strings + * have been specified. Margins, like width and height discussed above, + * are expressed in 300ths of an inch and must be converted to centipoints. + * Header and trailer strings each reduce the available image height + * by 1/6 inch, or 1200 centipoints (aka CHARHEIGHT). + */ + usable.width = page.width - ((left > 0) ? (left * 24) : 0); + usable.height = page.height - ((top > 0) ? (top * 24) : 0) + - ((header) ? CHARHEIGHT : 0) + - ((trailer) ? CHARHEIGHT : 0); + + /* Quit here if there is no usable image space. */ + if ((usable.width <= 0) || (usable.height <= 0)) { + fatal_err((catgets(nlmsg_fd,NL_SETN,4, + "No space available on page for image."))); + } + + /* Determine image orientation. The orientation will only be changed if + * it was not specified by a command line option. Portrait mode will be + * used if either the usable printing area or the image area are square. + * Portrait mode will also be used if the long dimensions of the usable + * printing area and the image area match, otherwise landscape mode is + * used. Portrait mode really means "don't rotate" and landscape mode + * means "rotate". + */ + if (*orient == UNSPECIFIED) { + if ((usable.width == usable.height) + || (xwd_header.pixmap_width == xwd_header.pixmap_height)) + *orient = PORTRAIT; + else + *orient = ((usable.width < usable.height) + == (xwd_header.pixmap_width < xwd_header.pixmap_height)) + ? PORTRAIT : LANDSCAPE; + } + + /* Set the dots-per-inch print density if it was not specified */ + if (*density <= 0) { + switch(device) { + case LJET: *density = 300; + break; + case PJET: *density = 90; + break; + case PJETXL: *density = 180; + break; + } + } + + /* Fit image to available area if scale was not specified */ + if (*scale <= 0) + *scale = scale_raster(*density, *orient, usable); + + /* Determine image clipping limits */ + set_image_limits(*scale, *density, *orient, usable); + + /* Determine header/trailer string length clipping */ + set_header_trailer_limits(header, trailer, usable.width); + + /* Calculate locations for page layout */ + set_print_locations(*scale, *density, top, left, + header, trailer, *orient, position_on_page); + +} + + +unsigned short fullintensity; + +#define BLACK 1 +#define WHITE 0 +#define EMPTY -1 +#define MAX_PJ_COLOR 16 + +#define RGBmatch(r,g,b,i) (r == i) && (g == i) && (b == i) + + +/* Colormap array is used to map from the Xcolor array (xwd_colors) index + * numbers into a pjcolor index number. This style of mapping is done when + * interpreting non-Direct/TrueColor visual types. + */ +long *colormap; + + +/* Pjcolor array is used to hold the scaled RGB triple values + * programmed into the printer. + */ +long pjcolor[MAX_PJ_COLOR]; + + +static int color_warning_given = FALSE; + + +/* Global visual type indicator, used to select color interpretation method. */ +char Direct_or_TrueColor; + + +typedef struct { + unsigned long Rmask, Gmask, Bmask; + int Rshift, Gshift, Bshift; +} RGBshiftmask; + + +/* Color index element definition, these are linked into a circular list + * for interpretation of DirectColor or TrueColor visual types. + */ +typedef struct colorindex { + long index; + long pjcolor_index; + struct colorindex *next; +} COLORINDEX; + + +/* Global data for color interpretation. This structure serves as a home + * for the color index lists (only used when processing DirectColor or + * TrueColor visual types). It also holds color processing switches and a + * pointer to the output file to reduce parameter passing overhead. + */ +struct { + int PaintJet; + int Invert; + unsigned int CutOff; + FILE *OutFile; + COLORINDEX *indexchain, *freechain; + RGBshiftmask sm; +} color; + + +void setup_RGBshiftmask (sm, rmask, gmask, bmask) +RGBshiftmask *sm; +unsigned long rmask, gmask, bmask; +{ + sm->Rmask = rmask; sm->Gmask = gmask; sm->Bmask = bmask; + sm->Rshift = 0; sm->Gshift = 0; sm->Bshift = 0; + + if (!rmask) + fatal_err((catgets(nlmsg_fd,NL_SETN,5, "red mask for visual is zero."))); + if (!gmask) + fatal_err((catgets(nlmsg_fd,NL_SETN,6, "green mask for visual is zero."))); + if (!bmask) + fatal_err((catgets(nlmsg_fd,NL_SETN,7, "blue mask for visual is zero."))); + + for (; !(rmask & 1); sm->Rshift++) + rmask >>= 1; + for (; !(gmask & 1); sm->Gshift++) + gmask >>= 1; + for (; !(bmask & 1); sm->Bshift++) + bmask >>= 1; +} + + + +void swap_black_and_white () +{ + /* Reverse black and white in the Xcolor structure array. */ + + XColor *color; + int n; + + for (n=xwd_header.ncolors, color=xwd_colors; n>0; n--, color++) + if (RGBmatch((color->red & fullintensity), (color->green & fullintensity), + (color->blue & fullintensity), fullintensity)) + color->red = color->green = color->blue = 0; + else if (RGBmatch(color->red, color->green, color->blue, 0)) + color->red = color->green = color->blue = fullintensity; +} + + +void reset_color_mapping () +{ + int n; + long *cmap; + COLORINDEX *splice; + + for (n=0; nnext; + color.indexchain->next = color.freechain; + color.freechain = splice; + color.indexchain = NULL; + } + } else if (color.PaintJet) + for (n=xwd_header.ncolors, cmap=colormap; n>0; n--, cmap++) + *cmap = EMPTY; +} + + +#define Intensity(r,g,b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) + + +void prepare_color_mapping (invert, paintjet, cutoff, out) +int invert, paintjet; +unsigned int cutoff; +FILE *out; +{ + int n; + long *cmap; + XColor *xcolor; + + for (n = xwd_header.bits_per_rgb, fullintensity = 0; n > 0; n--) + fullintensity = (fullintensity << 1) | 1; + for (n = sizeof(short) * 8 - xwd_header.bits_per_rgb; n > 0; n--) + fullintensity = (fullintensity << 1); + + Direct_or_TrueColor = (xwd_header.visual_class == DirectColor + || xwd_header.visual_class == TrueColor); + color.PaintJet = paintjet; + color.Invert = invert; + color.CutOff = cutoff; + color.OutFile = out; + color.indexchain = NULL; + color.freechain = NULL; + + if (Direct_or_TrueColor) + setup_RGBshiftmask(&color.sm, xwd_header.red_mask, + xwd_header.green_mask, xwd_header.blue_mask); + else { + if (!(colormap = (long *) malloc(xwd_header.ncolors * sizeof(long)))) + fatal_err((catgets(nlmsg_fd,NL_SETN,24, + "Could not allocate memory for X-to-printer colormap."))); + + /* For PaintJet, color map assignment will be done one line at a time. + * So for now just interchange the Xcolor structure's black and white + * if the -rv command line option was specified. + */ + if (paintjet && invert) + swap_black_and_white(); + + /* For LaserJet, map each color to black or white based upon the + * combined intensity of the RGB components. Note that the normal + * non-reversed (-rv) LaserJet mapping will represent light areas + * of the screen as black on the paper. + */ + if (!paintjet) + for (n=xwd_header.ncolors, xcolor=xwd_colors, cmap=colormap; n>0; + n--, xcolor++, cmap++) + *cmap = (Intensity(xcolor->red, xcolor->green, xcolor->blue) < cutoff) + ? (invert ? BLACK : WHITE) + : (invert ? WHITE : BLACK); + } + reset_color_mapping(); +} + + +/* On a PaintJet printer, the programmable color intensity ranges are: + * + * red: 4..90 green: 4..88 blue: 6..85 + * + * The following macros map the 0..65535 intensity ranges of X colors + * into the PaintJet's ranges. + */ + +#define fixred(x) (x / 762 + 4) +#define fixgreen(x) (x / 780 + 4) +#define fixblue(x) (x / 829 + 6) + +#define is_grey(r,g,b) ((r == g) && (r == b)) + + + +void select_grey (level, r, g, b) +int level, *r, *g, *b; +{ + /* Forced selection of a grey. This is done since the PaintJet does + * not do very well when picking greys, they tend to become pink! + */ + if (level > 66) { /* white */ + *r = 90; *g = 88; *b = 85; + } else if (level > 35) { + *r = 43; *g = 43; *b = 45; + } else if (level > 21) { + *r = 25; *g = 25; *b = 33; + } else if (level > 15) { + *r = 15; *g = 16; *b = 18; + } else if (level > 11) { + *r = 14; *g = 14; *b = 18; + } else if (level > 6) { + *r = 6; *g = 7; *b = 8; + } else { /* black */ + *r = 4; *g = 4; *b = 6; + } +} + + +long find_nearest_programmed_color (); + +int load_printer_color (index, nearmatch, device) /* for non Direct/TrueColor */ +long index; +int nearmatch; +enum device device; +{ + int n, red, blue, green, xred, xgreen, xblue; + long compositeRGB; + + if (colormap[index] != EMPTY) + /* printer has already been programmed for this color index */ + return(1); /* "success" */ + else { + xred = xwd_colors[index].red; + xgreen = xwd_colors[index].green; + xblue = xwd_colors[index].blue; + /* determine the scaled RGB PaintJet color values */ + if (device == PJET) { + red = fixred(xred); + green = fixgreen(xgreen); + blue = fixblue(xblue); + if (is_grey(xred, xgreen, xblue)) /* assist grey selection */ + select_grey(red, &red, &green, &blue); + } + compositeRGB = (red << 16) | (green << 8) | blue; + /* search for a matching or unused PaintJet mapping entry */ + for (n=0; nindex == i) { + color.indexchain = current; + return(current->pjcolor_index); /* found */ + } + current = current->next; + } while (current != start); + + return(-1); /* not found */ +} + + +/* Calculate the individual and composite printer RGB values. (Only the + * composite value is set for monochrome output.) + */ +void select_printer_color (index, red, green, blue, compositeRGB, device) +long index; +int *red, *green, *blue; +long *compositeRGB; +enum device device; +{ + int xred, xgreen, xblue; + + xred = xwd_colors[((index & color.sm.Rmask) >> color.sm.Rshift)].red; + xgreen = xwd_colors[((index & color.sm.Gmask) >> color.sm.Gshift)].green; + xblue = xwd_colors[((index & color.sm.Bmask) >> color.sm.Bshift)].blue; + + if (color.PaintJet) { + if (color.Invert) { + if (RGBmatch((xred & fullintensity), (xgreen & fullintensity), + (xblue & fullintensity), fullintensity)) + xred = xgreen = xblue = 0; + else if (RGBmatch(xred, xgreen, xblue, 0)) + xred = xgreen = xblue = fullintensity; + } + /* determine the scaled RGB PaintJet color values */ + if (device == PJET) { + *red = fixred(xred); + *green = fixgreen(xgreen); + *blue = fixblue(xblue); + if (is_grey(xred, xgreen, xblue)) /* assist grey selection */ + select_grey(*red, red, green, blue); + } + if (device == PJETXL) { + *red = xred >> 8; + *green = xgreen >> 8; + *blue = xblue >> 8; + } + *compositeRGB = (*red << 16) | (*green << 8) | *blue; + } else /* monochrome */ + *compositeRGB = (Intensity(xred, xgreen, xblue) < color.CutOff) + ? (color.Invert ? BLACK : WHITE) + : (color.Invert ? WHITE : BLACK); +} + + + +/* Search for a color matching the compositeRGB value in the array of + * colors already programmed into the printer. Returns 1 if found, + * 0 otherwise. The matching array index is returned in pindex. + */ +int color_already_in_printer (compositeRGB, pindex) +long compositeRGB, *pindex; +{ + int n; + + for (n=0; n> 16 & 0xFF) - (y >> 16 & 0xFF); + long g = (x >> 8 & 0xFF) - (y >> 8 & 0xFF); + long b = (x & 0xFF) - (y & 0xFF); + + return(r*r + g*g + b*b); +} + + + +long find_nearest_programmed_color (compositeRGB) +long compositeRGB; +{ + int n, nearest = 0; + long neardiff = composite_diff(pjcolor[0], compositeRGB); + long diff; + + for (n=1; nnext; + } + + /* put index values in the new cell */ + new->index = cindex; + new->pjcolor_index = pindex; + + /* link the new cell into the chain */ + if (color.indexchain == NULL) + new->next = new; + else { + new->next = color.indexchain->next; + color.indexchain->next = new; + } + /* leave head pointer at the new cell */ + color.indexchain = new; +} + + + +int load_printer_color_DT (index, nearmatch, device) /* for Direct/TrueColor */ +long index; +int nearmatch; +enum device device; +{ + int pjred, pjgreen, pjblue; + long compositeRGB; + long pindex; + + if (lookup_color_index(index) >= 0) + return(1); /* "success" */ + else { + select_printer_color(index, &pjred, &pjgreen, &pjblue, &compositeRGB, + device); + if (color_already_in_printer(compositeRGB, &pindex)) { + add_index_to_chain(index, pindex); + return(1); /* success */ + } else if (program_new_printer_color(pjred, pjgreen, pjblue, + compositeRGB, &pindex)) { + add_index_to_chain(index, pindex); + return(1); /* success */ + } else if (nearmatch) { + add_index_to_chain(index, find_nearest_programmed_color(compositeRGB)); + return(0); /* failure, sorta... */ + } + } + return(0); /* failure */ +} + + +int load_line_colors (line, length, nearmatch, device) +long *line; +int length, nearmatch; +enum device device; +{ + int result = 1; /* initialized to "success" */ + + for (; length>0; length--, line++) { + result &= Direct_or_TrueColor + ? load_printer_color_DT(*line, nearmatch, device) + : load_printer_color(*line, nearmatch, device); + if (!(nearmatch || result)) + break; + } + return(result); +} + + + +void download_colors (line, length, device) +long *line; +int length; +enum device device; +{ + /* For the first attempt at loading the colors for a line only exact + * color matches are accepted. If this fails, the closest colors are + * accepted on the second attempt. + * + * Note: The first "if" test below bypasses the initial color loading + * attempt for monochrome output (which will only come here for Direct + * or TrueColor mono). This forces reset_color_mapping which is + * necessary to keep the color index chain down to a tolerable length. + */ + if (!color.PaintJet || !load_line_colors(line, length, FALSE, device)) { + reset_color_mapping(); + if (!load_line_colors(line, length, TRUE, device) && + !color_warning_given) { + fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,9, + "%s: Warning: Cannot print all image colors.\n")), + progname); + color_warning_given = TRUE; + } + } +} + + +void validate_visual() +{ + int depth = xwd_header.pixmap_depth; + char *errmsg = catgets(nlmsg_fd,NL_SETN,25, + "%d bit deep %s bitmap not supported.\n"); + + switch (xwd_header.visual_class) { + case GrayScale: + if (depth > 8) fatal_err2(errmsg, depth, "GrayScale"); break; + case StaticGray: + if (depth > 8) fatal_err2(errmsg, depth, "StaticGray"); break; + case PseudoColor: + if (depth > 8) fatal_err2(errmsg, depth, "PseudoColor"); break; + case StaticColor: + if (depth > 8) fatal_err2(errmsg, depth, "StaticColor"); break; + case DirectColor: + case TrueColor: + if (depth != 12 && depth != 24) + fatal_err2(errmsg, depth, (xwd_header.visual_class == DirectColor) + ? "DirectColor" : "TrueColor"); + break; + default: + fatal_err2((catgets(nlmsg_fd,NL_SETN,26, + "visual class #%d not supported.\n")), xwd_header.visual_class); + } +} + +void read_xwd_data (in) +FILE *in; +{ +# define WINDOW_NAME_ALLOC 32 + unsigned long swaptest = 1; + int window_name_size; + int image_size; + int n; + char window_name [WINDOW_NAME_ALLOC]; + + /* Read in XWDFileHeader structure */ + if (fread((char*) &xwd_header, 1, XWDHEADERSIZE, in) != XWDHEADERSIZE) + fatal_err((catgets(nlmsg_fd,NL_SETN,10, + "Could not read xwd file's header."))); + + if (*(char *) &swaptest) + _swaplong((char *) &xwd_header, XWDHEADERSIZE); + + validate_visual(); + + /* Skip over window name */ + window_name_size = xwd_header.header_size - XWDHEADERSIZE; + while (window_name_size > 0) { + n = window_name_size > WINDOW_NAME_ALLOC + ? WINDOW_NAME_ALLOC : window_name_size; + if (fread(window_name, 1, n, in) != n) + fatal_err((catgets(nlmsg_fd,NL_SETN,11, + "Could not read xwd file's window name."))); + window_name_size -= n; + } + + /* Allocate space for xwd color structures */ + if (!(xwd_colors = (XColor*) malloc(sizeof(XColor) * xwd_header.ncolors))) + fatal_err((catgets(nlmsg_fd,NL_SETN,12, + "Could not allocate memory for xwdfile color table."))); + + /* Read in xwd color structures */ + for (n = 0; n < xwd_header.ncolors; n++) + if (fread(&xwd_colors[n], 1, XCOLORSIZE, in) != XCOLORSIZE) + fatal_err((catgets(nlmsg_fd,NL_SETN,13, + "Could not read xwd file's color table."))); + + if (*(char *) &swaptest) { + for (n = 0; n < xwd_header.ncolors; n++) { + _swaplong((char *) &xwd_colors[n].pixel, sizeof(long)); + _swapshort((char *) &xwd_colors[n].red, 3 * sizeof(short)); + } + } + + /* Allocate space for xwd image */ + if (xwd_header.pixmap_format == ZPixmap) + image_size = 1; + else if (xwd_header.pixmap_format == XYPixmap) + image_size = xwd_header.pixmap_depth; + else + fatal_err((catgets(nlmsg_fd,NL_SETN,14, + "Image in xwd file is not in Z or XY pixmap format."))); + image_size *= xwd_header.bytes_per_line * xwd_header.pixmap_height; + if (!(xwd_image = malloc(image_size))) + fatal_err((catgets(nlmsg_fd,NL_SETN,15, + "Could not allocate memory for xwd file's image."))); + + /* Read in xwd image */ + if (fread(xwd_image, 1, image_size, in) != image_size) + fatal_err((catgets(nlmsg_fd,NL_SETN,16, + "Could not read xwd file's image."))); + +} + + +write_image_prefix (out, scale, density, header, device, position_on_page, + initial_formfeed, orient, gamma, render, slide) +FILE *out; +int scale, density; +char *header; +enum device device; +int position_on_page, initial_formfeed; +enum orientation orient; +float gamma; +int render; +int slide; +{ + if (initial_formfeed) + fprintf(out,"\014"); + + /* Write out header & positioning commands */ + if (header) { + if (position_on_page) + fprintf(out,"\033&a%dH\033&a%dV", + /* headerloc x & y are written in decipoints */ + (int) headerloc.x / 10, (int) headerloc.y / 10); + fprintf(out,"%s\n", header); + } + + /* Prepare printer for raster graphics: */ + + /* Write image positioning commands */ + if (position_on_page) + fprintf(out,"\033&a%dH\033&a%dV", + /* imageloc x & y are written in decipoints */ + (int) imageloc.x / 10, (int) imageloc.y / 10); + + /* If doing transparencies, tell the printer before raster graphics */ + if (slide && device != LJET) + fprintf(out, "\033&k3W"); + + /* Set printer resolution */ + fprintf(out,"\033*t%dR", density); + + /* + * do device dependent escape sequences + */ + if (device == PJET) { + /* Enable all four "planes" for PaintJet */ + fprintf(out,"\033*r4U"); + + /* Set picture width for PaintJet */ + fprintf(out,"\033*r%dS", + ((int) (orient == PORTRAIT) ? limit.width : limit.height) + * scale); + } + + /* Enable various options for PaintJet XL */ + if (device == PJETXL) { + double dotsize; + int n; + + /* Speed up printing by telling that there + * will be no negative positioning + */ + fprintf(out, "\033&a1N"); + + if (gamma > 0.009) + fprintf(out, "\033*t%.2fI", gamma); + + if (render > 0) + fprintf(out, "\033*t%dJ", render); + + if (Direct_or_TrueColor) + /* Enable direct by pixel for PaintJet XL */ + fwrite("\033*v6W\000\003\010\010\010\010", 1, 11, out); + else { + /* Enable index by pixel for PaintJet XL */ + fwrite("\033*v6W\000\001\010\010\010\010", 1, 11, out); + + /* Program the palette */ + for (n = 0; n < xwd_header.ncolors; n++) { + fprintf(out,"\033*v%dA", (xwd_colors[n].red >> 8)); + fprintf(out,"\033*v%dB", (xwd_colors[n].green >> 8)); + fprintf(out,"\033*v%dC", (xwd_colors[n].blue >> 8)); + fprintf(out,"\033*v%dI", n); + } + } + + /**************************************** + * * + * PaintJet XL will do its own scaling * + * * + * Set picture width for PaintJet XL * + ****************************************/ + fprintf(out,"\033*r%dS", + ((int) (orient == PORTRAIT) ? xwd_header.pixmap_width + : xwd_header.pixmap_height)); + fprintf(out,"\033*r%dT", + ((int) (orient == PORTRAIT) ? xwd_header.pixmap_height + : xwd_header.pixmap_width)); + + dotsize = dot_centipoints(scale, density); + + fprintf(out,"\033*t%dH", + (int)(((orient == PORTRAIT) ? xwd_header.pixmap_width + : xwd_header.pixmap_height) + * dotsize / 10)); + + fprintf(out,"\033*t%dV", + (int)(((orient == PORTRAIT) ? xwd_header.pixmap_height + : xwd_header.pixmap_width) + * dotsize / 10)); + } + + /* Switch to raster graphics mode */ + if (device != PJETXL) + fprintf(out,"\033*r1A"); + else + fprintf(out,"\033*r3A"); + +} + + +write_image_suffix (out, trailer, position_on_page, slide, render, device) +FILE *out; +char *trailer; +int position_on_page; +int slide, render; +enum device device; +{ + /* Exit raster graphics mode */ + if (device == PJETXL) + fprintf(out,"\033*rC"); + else + fprintf(out,"\033*rB"); + + /* If doing transparencies, tell it to stop */ + if (slide && device != LJET) + fprintf(out, "\033&k1W"); + + if (device == PJETXL) { + /* If selected a rendering algorithm, tell it to stop */ + if (render) + fprintf(out, "\033*t3J"); + fprintf(out, "\033&a0N"); + } + + /* Write out trailer & positioning commands */ + if (trailer) { + if (position_on_page) + fprintf(out,"\033&a%dH\033&a%dV", + /* trailerloc x & y are written in decipoints */ + (int) trailerloc.x / 10, (int) trailerloc.y / 10); + fprintf(out,"%s\n", trailer); + } +} + + +unsigned long Z_image_pixel (x, y) +int x, y; +{ + int pixel_bytes, offset; + unsigned char *image; + unsigned long pixel; + + pixel_bytes = xwd_header.bits_per_pixel >> 3; + offset = ((xwd_header.bits_per_pixel == 4) ? (x / 2) + : ((xwd_header.bits_per_pixel == 1) ? (x / 8) + : (x * pixel_bytes))) + + (y * xwd_header.bytes_per_line); + + image = (unsigned char *) &xwd_image[offset]; + + switch (pixel_bytes) { + case 0: /* pixel per nibble or bit per pixel packing */ + if (xwd_header.bits_per_pixel == 1) { + if (xwd_header.byte_order == MSBFirst) + pixel = *image >> (7 - (x % 8)); + else + pixel = *image >> (x % 8); + } else { /* xwd_header.bits_per_pixel == 4 */ + if (xwd_header.byte_order == MSBFirst) + pixel = (x & 1) ? *image : (*image >> 4); + else + pixel = (x & 1) ? (*image >> 4) : *image; + } + break; + case 1: + pixel = *image; + break; + case 2: + pixel = (xwd_header.byte_order == MSBFirst) + ? ((unsigned long)*image << 8 | *(image + 1)) + : (*image | (unsigned long)*(image + 1) << 8); + break; + case 3: + pixel = (xwd_header.byte_order == MSBFirst) + ? ((unsigned long)*image << 16 | + (unsigned long)*(image + 1) << 8 | + (unsigned long)*(image + 2)) + : (*image | + (unsigned long)*(image + 1) << 8 | + (unsigned long)*(image + 2) << 16); + break; + case 4: + pixel = (xwd_header.byte_order == MSBFirst) + ? ((unsigned long)*image << 24 | + (unsigned long)*(image+1) << 16 | + (unsigned long)*(image+2) << 8 | + *(image+3)) + : (*image | + (unsigned long)*(image+1) << 8 | + (unsigned long)*(image+2) << 16 | + (unsigned long)*(image+3) << 24); + break; + } + return (pixel & Z_pixel_mask); +} + + +unsigned long XY_image_pixel (x, y) +int x, y; +{ + int plane_start, line_start, bytes_per_bitmap_unit, bitmap_unit_start, + byte_within_bitmap_unit, offset, byte_mask; + + plane_start = (xwd_header.pixmap_depth - 1) * xwd_header.pixmap_height + * xwd_header.bytes_per_line; + line_start = xwd_header.bytes_per_line * y; + bytes_per_bitmap_unit = xwd_header.bitmap_unit >> 3; + bitmap_unit_start = (x / xwd_header.bitmap_unit) * bytes_per_bitmap_unit; + byte_within_bitmap_unit = (xwd_header.byte_order == MSBFirst) + ? (x % xwd_header.bitmap_unit) >> 3 + : bytes_per_bitmap_unit - ((x % xwd_header.bitmap_unit) >> 3) - 1; + + offset = plane_start + line_start + bitmap_unit_start + + byte_within_bitmap_unit; + + byte_mask = (xwd_header.bitmap_bit_order == MSBFirst) + ? 0x80 >> (x % 8) : 0x01 << (x % 8); + + return(xwd_image[offset] & byte_mask ? 1 : 0); +} + + +void direct_by_pixel(out, line, length, device) +FILE *out; +long *line; +int length; +enum device device; +{ + int red, green, blue; + long compositeRGB; + + fprintf(out, "\033*b%dW", length * 3); + for (; length>0; length--, line++) { + select_printer_color(*line, &red, &green, &blue, &compositeRGB, device); + fprintf(out, "%c%c%c", (char) red, (char) green, (char) blue); + } +} + + +void index_by_pixel(out, line, length) +FILE *out; +long *line; +int length; +{ + register int n; + long *lp; + char *line_pixels; + register char *lc; + + if (!(line_pixels = malloc(length))) + fatal_err((catgets(nlmsg_fd,NL_SETN,17, + "Could not allocate raster line memory."))); + + for (n=0, lc=line_pixels, lp=line; n 0) { + bit = (*lc++ >> p) & 0x01; + e = scale; + while (e--) { + byte = (byte << 1) | bit; + bytebits++; + if (bytebits == 8) { + *rl++ = byte; + bytebits = 0; + } + } + } + if (bytebits) + *rl = byte << (8 - bytebits); + } + + e = scale; + while (e--) { + for (p=0; p=0; y--) + *lp++ = Z_image_pixel(x,y); + + write_raster_line(out, scale, device, line, width); + } +} + + +void write_portrait_XY_image (out, scale, device) +FILE *out; +int scale; +enum device device; +{ + int x, y; + int width = limit.width; + int height = limit.height; + long *line, *lp; + + if (!(line = (long *) malloc(width * sizeof(long)))) + fatal_err((catgets(nlmsg_fd,NL_SETN,20, + "Could not allocate memory for image line buffer."))); + + for (y=0; y=0; y--) + *lp++ = XY_image_pixel(x,y); + + write_raster_line(out, scale, device, line, width); + } +} + + +void write_Z_image (out, scale, orient, device) +FILE *out; +int scale; +enum orientation orient; +enum device device; +{ + if (orient == PORTRAIT) { + write_portrait_Z_image(out, scale, device); + } else + write_landscape_Z_image(out, scale, device); +} + + + +void write_XY_image (out, scale, orient, device) +FILE *out; +int scale; +enum orientation orient; +enum device device; +{ + if (xwd_header.pixmap_depth > 1) + fatal_err((catgets(nlmsg_fd,NL_SETN,22, + "XY format image, multiplane images must be Z format."))); + + if (orient == PORTRAIT) { + write_portrait_XY_image(out, scale, device); + } else + write_landscape_XY_image(out, scale, device); +} + + + +void write_image (out, scale, orient, device) +FILE *out; +int scale; +enum orientation orient; +enum device device; +{ + switch (xwd_header.pixmap_format) { + case XYPixmap: + write_XY_image(out, scale, orient, device); break; + case ZPixmap: + write_Z_image(out, scale, orient, device); break; + default: + fatal_err((catgets(nlmsg_fd,NL_SETN,23, "image not in XY or Z format."))); + } +} + + +void x2jet(in, out, scale, density, width, height, left, top, + header, trailer, orient, invert, + initial_formfeed, position_on_page, slide, + device, cutoff, gamma, render) +FILE *in, *out; +int scale, density; +int width, height, left, top; /* in 300ths of an inch */ +char *header, *trailer; +enum orientation orient; +int invert, initial_formfeed, position_on_page, slide; +enum device device; +unsigned int cutoff; +float gamma; +int render; +{ + int paintjet = FALSE; + + true_scale = scale; + + if (device != LJET) + paintjet = TRUE; + + read_xwd_data(in); + + Z_pixel_mask = ~(0xFFFFFFFFL << xwd_header.pixmap_depth); + + prepare_color_mapping(invert, paintjet, cutoff, out); + + scale_and_orient_image(&scale, &density, width, height, left, top, + header, trailer, + &orient, position_on_page, device); + + write_image_prefix(out, scale, density, header, device, position_on_page, + initial_formfeed, orient, gamma, render, slide); + + write_image(out, scale, orient, device); + + write_image_suffix(out, trailer, position_on_page, slide, render, device); + + fclose(out); +} + + +void fatal_err (s) +char * s; +{ + fprintf(stderr, "%s: %s\n", progname, s); + exit(1); +} + +void fatal_err2 (s, a1, a2, a3) +char *s; +char *a1, *a2, *a3; +{ + fprintf(stderr, "%s: ", progname); + fprintf(stderr, s, a1, a2, a3); + exit(1); +} Index: xc/programs/xpr/x2pmp.c =================================================================== RCS file: xc/programs/xpr/x2pmp.c diff -N xc/programs/xpr/x2pmp.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/x2pmp.c 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,363 @@ +/* + * $XConsortium: x2pmp.c,v 1.13 91/07/25 17:56:32 rws Exp $ + */ + +/* x2pmp.c: Translate xwd window dump format into PMP format for the + * IBM 3812 PagePrinter. + */ +#include +#include +#include +#include +#include +#include + +#include "pmp.h" +#include "xpr.h" + +#define max_(a, b) (a) > (b) ? (a) : (b) +#define min_(a, b) (a) < (b) ? (a) : (b) +#define abs_(a) (a) < 0 ? -(a) : (a) + +static void leave(); +static bits_set(); +static unsigned char *magnification_table(); + +/* global variables set by main() and used by x2pmp() */ +extern char *progname; +extern int debug; + +static plane = 0; +#define FONT_HEIGHT 40 +#define FONT_HEIGHT_PIXELS (FONT_HEIGHT*75/PPI) +#define FONT_WIDTH 24 + +void x2pmp(in, out, scale, p_width, p_length, x_pos, y_pos, + head, foot, orient, invert) +FILE *in, *out; +int scale; +int p_width, p_length, x_pos, y_pos; /* in pels (units of PPI) */ +char *head, *foot; +enum orientation orient; +int invert; +{ + unsigned char *buffer, *win_name; + unsigned int win_name_size, width, height, ncolors; + unsigned int buffer_size, one_plane_size, byte_width, fixed_width; + int no_of_bits; + unsigned long swaptest = 1; + XWDFileHeader header; + + /* Read header from file */ + if (fread((char *)&header, sizeof(header), 1, in) != 1) + if (feof(in)) + return; + else + leave("fread"); + if (*(char *) &swaptest) + _swaplong((char *) &header, sizeof(header)); + + if (header.file_version != XWD_FILE_VERSION) { + fprintf(stderr,"%s: file format version %d, not %d\n", progname, + header.file_version, XWD_FILE_VERSION); + } + + win_name_size = abs_(header.header_size - sizeof(header)); + if ((win_name = (unsigned char *) + calloc(win_name_size, (unsigned) sizeof(char))) == NULL) + leave("Can't calloc window name storage."); + + /* Read window name from file */ + if (fread((char *) win_name, sizeof(char), (int) win_name_size, in) != + win_name_size) + leave("Unable to read window name from dump file."); + DEBUG(>= 1) + fprintf(stderr,"win_name =%s\n", win_name); + + width = header.pixmap_width; + height = header.pixmap_height; + fixed_width = 8 * (byte_width = header.bytes_per_line); + one_plane_size = byte_width * height; + buffer_size = one_plane_size * + ((header.pixmap_format == ZPixmap)? header.pixmap_depth: 1); + + /* Determine orientation and scale if not specified */ + if (orient == UNSPECIFIED) + orient = (fixed_width <= height)? PORTRAIT: LANDSCAPE; + if (scale <= 0) { + int real_height = height; + if (head) real_height += FONT_HEIGHT_PIXELS << 1; + if (foot) real_height += FONT_HEIGHT_PIXELS << 1; + switch(orient) { + case PORTRAIT: + case UPSIDE_DOWN: + scale = min_((p_width - 2*x_pos) / fixed_width, + (p_length - 2*y_pos) / real_height); + break; + case LANDSCAPE: + case LANDSCAPE_LEFT: + scale = min_((p_length - 2*y_pos) / fixed_width, + (p_width - 2*x_pos) / real_height); + break; + } + if (scale <= 0) + leave("PixMap doesn't fit on page."); + else DEBUG(>1) + fprintf(stderr, "scaling by %d to yield %d x %d image\n", + scale, fixed_width*scale, height*scale); + } + + ncolors = header.ncolors; + if (ncolors) { + int i; + XColor *colors = (XColor *)malloc((unsigned) (header.ncolors * sizeof(XColor))); + + if (fread((char *)colors, sizeof(XColor), ncolors, in) != ncolors) + leave("Unable to read colormap from dump file."); + + if (*(char *) &swaptest) { + for (i = 0; i < ncolors; i++) { + _swaplong((char *) &colors[i].pixel, (long)sizeof(long)); + _swapshort((char *) &colors[i].red, (long) (3 * sizeof(short))); + } + } + if (ncolors == 2 && INTENSITY(&colors[0]) > INTENSITY(&colors[1])) + invert = !invert; + free( colors ); + } + + invert = !invert; /* 3812 puts ink (i.e. black) on 1-bits */ + + if ((buffer = (unsigned char *) calloc(buffer_size, 1)) == NULL) + leave("Can't calloc data buffer."); + bzero((char *) buffer, (int) buffer_size); + + /* Read bitmap from file */ + if (fread((char *) buffer, sizeof(char), (int) buffer_size, in) + != buffer_size) + leave("Unable to read pixmap from dump file."); + + if (header.bitmap_bit_order == LSBFirst) + { + unsigned char bitswap[256], *bp; + int c; + for(c = 256; c--;) { + bitswap[c] = ((c & 01) << 7) + ((c & 02) << 5) + ((c & 04) << 3) + + ((c & 010) << 1) + ((c & 020) >> 1) + ((c & 040) >> 3) + + ((c & 0100) >> 5) + ((c & 0200) >> 7); + if (invert) + bitswap[c] = ~bitswap[c]; + } + /* Here's where we do the bitswapping. */ + for(bp = buffer+buffer_size; bp-- > buffer;) + *bp = bitswap[*bp]; + } + else if (invert) { + unsigned char *bp; + for(bp = buffer+buffer_size; bp-- > buffer;) + *bp = ~*bp; + } + + /* we don't want the last bits up to the byte/word alignment set */ + if (no_of_bits = fixed_width - width) { + int i, j, mask = ~bits_set(no_of_bits % 8); + for(i = 0; i < height; i++) { + unsigned char *s = buffer + (i+1) * byte_width ; + + for(j = no_of_bits / 8; j--;) + *--s = 0; + *--s &= mask; + } + } + + DEBUG(>= 1) + fprintf(stderr,"read %d bytes for a %d (%d bytes) x %d image\n", + buffer_size, (int) width, byte_width, (int) height); + /* Scale the bitmap */ + if (scale > 1) { + unsigned char *tbl = magnification_table(scale); + unsigned char *scale_buf; + int i, j, k; + + if ((scale_buf = (unsigned char *) + calloc((unsigned) (buffer_size *= scale*scale), sizeof(char))) + == NULL) + leave("Can't calloc scaled buffer."); + for(i = 0; i < height; i++) { + unsigned char *src, *ss; + src = buffer + i * byte_width ; + ss = scale_buf + i * scale * scale * byte_width; + for(j = 0; j < byte_width; j++) { + unsigned char *dst = ss+j*scale; + unsigned char *expansion = tbl+scale*src[j]; + for(k = 0; k < scale; k++, dst += byte_width*scale) { + bcopy((char *) expansion, (char *) dst, scale); + } + } + } + free((char *) buffer); + free((char *) tbl); + buffer = scale_buf; + byte_width *= scale; + width *= scale; + fixed_width *= scale; + height *= scale; + one_plane_size *= scale*scale; + } + DEBUG(==3) { + int i, j, k; + unsigned char *s; + + fprintf(stderr, "dumping %d x %d grid\n", fixed_width, height); + for(i = 0; i < height; i++) { + s = buffer + i * byte_width ; + for(j = 0; j < byte_width; j++) + for(k = 8; k--;) + (void) putc((s[j] & 1<> 1, + y_pos - FONT_HEIGHT ); + fprintf(out, "%s\n", head); + } + if (foot != NULL) { + p_move_abs( out, x_pos + (width - strlen(foot)*FONT_WIDTH) >> 1, + y_pos + height + (FONT_HEIGHT << 1) ); + fprintf(out, "%s\n", foot); + } + p_move_abs(out, x_pos, y_pos); + p_bitmap(out, height, fixed_width, (unsigned long) one_plane_size, + buffer + plane * one_plane_size); + free((char *) win_name); + free((char *) buffer); +} + +static unsigned char *magnification_table(scale) +int scale; +{ + unsigned char *tbl; + int c; + + if ((tbl = (unsigned char *) + calloc((unsigned) (scale*256), sizeof(char))) == NULL) + leave("Can't calloc magnification table."); + bzero((char *) tbl, scale*256); + for(c = 256; c--;) { + int b = c, bit; + unsigned char *entry = tbl+c*scale; + + while (b) { + int i, last, mask; + bit = 1; + mask = b; + while (! (mask & 1)) { + bit++; + mask = mask >> 1; + } + last = scale*(bit-1); + for(i = scale*bit; i-- > last ;) + entry[(scale - 1) - i / 8] |= 1 << (i % 8); + b &= ~(1 << bit-1); + } + } + return tbl; +} + +/* returns 2^n-1, i.e. a number with bits n-1 through 0 set. + * (zero for n == 0) */ +static bits_set(n) +int n; +{ + int ans = 0; + while(n--) + ans |= 1 << n; + return ans; +} + +static void leave(s) +char *s; +{ + extern int errno; + + fprintf(stderr, "\n%s: ", progname); + if (errno != 0) + perror(s); + else + fprintf(stderr, "%s", s); + fprintf(stderr, "\n"); + exit(1); +} + +/* move to coordinates x, y (in pels) */ +p_move_abs(p, x, y) +FILE *p; +int x, y; +{ + if (x >= 0) { + PMP(p, 3); + (void) putc('\340', p); + p_wput(x, p); + } + if (y >= 0) { + PMP(p, 3); + (void) putc('\341', p); + p_wput(y, p); + } +} + +/* save current cursor position into (printer) register reg */ +p_save_cursor(p, reg) +FILE *p; +int reg; +{ + PMP(p, 1); + (void) putc(reg + '\200', p); +} + +/* restore current cursor position from (printer) register reg */ +p_restore_cursor(p, reg) +FILE *p; +int reg; +{ + PMP(p, 1); + (void) putc(reg + '\220', p); +} + +/* set the page orientation to orient (see pmp.h) */ +p_set_orientation(p, orient) +FILE *p; +enum orientation orient; +{ + PMP(p, 2); + fprintf(p, "\322%c", (int) orient); +} + +/* generate bitmap */ +p_bitmap(p, h, w, buflen, buf) +FILE *p; +unsigned int h, w; +unsigned long buflen; +unsigned char *buf; +{ + PMP(p, 9); + (void) fwrite("\365\0", 1, 2, p); + puthl2(h, p); + puthl2(w, p); + puthl3(buflen, p); + + while(buflen) { + int len; + + len = min(buflen, MAX_VECTOR_LEN); + PMP(p, len); + (void) fwrite((char *) buf, 1, len, p); + buf += len; + buflen -= len; + } + (void) fflush(p); +} Index: xc/programs/xpr/xdpr.man =================================================================== RCS file: xc/programs/xpr/xdpr.man diff -N xc/programs/xpr/xdpr.man --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/xdpr.man 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,137 @@ +.\" $XConsortium: xdpr.man,v 1.15 94/04/17 20:44:04 gildea Exp $ +.TH XDPR 1 "Release 6" "X Version 11" +.SH NAME +xdpr \- dump an X window directly to a printer +.SH SYNOPSIS +.B xdpr +[ +.I filename +] +[ +.B \-display +.I host:display +] +[ +.B \-P\fIprinter\fP +] +[ +.B \-device +.I devtype +] +[ +.I option +\&.\|.\|. +] + +.SH DESCRIPTION +.I Xdpr +uses the commands +.I xwd, +.I xpr, +and +.I lpr +or +.I lp +to dump an X window, process it for a particular printer type, and +print it out on the printer of your choice. This is the easiest way +to get a printout of a window. \fIXdpr\fP by default will print the +largest possible representation of the window on the output page. +.PP +The options for \fIxdpr\fP are the same as those for \fIxpr\fP, +\fIxwd\fP, and \fIlpr\fP or \fIlp\fP. +The most commonly-used options are described +below; see the manual pages for these commands for +more detailed descriptions of the many options available. +.SH OPTIONS +.TP +.I filename +Specifies a file containing a window dump (created by \fIxwd\fP) to be +printed instead of selecting an X window. +.TP +.B \-P\fIprinter\fP +Specifies a printer to send the output to. If a printer name is not +specified here, \fIxdpr\fP (really, \fIlpr\fP or \fIlp\fP) +will send your output to the +printer specified by the \fIPRINTER\fP environment variable. +Be sure that type of the printer matches the type specified +with the \fI\-device\fP option. +.TP +.B \-display \fIhost:display\fP[\fI.screen\fP] +.cm .IB host : display +Normally, +.I xdpr +gets the host and display number to use from the environment +variable ``DISPLAY.'' +One can, however, specify them explicitly; see \fIX\fP(1). +.TP +.B \-device \fIdevtype\fP +Specifies the device on which the file will be printed. Currently supported: +.RS 12 +.PD 0 +.TP +.B la100 +Digital LA100 +.TP +.B ljet +\s-1HP\s+1 LaserJet series and other monochrome PCL devices +such as ThinkJet, QuietJet, RuggedWriter, \s-1HP\s+12560 series, +and \s-1HP\s+12930 series printers +.TP +.B ln03 +Digital LN03 +.TP +.B pjet +HP PaintJet (color mode) +.TP +.B pjetxl +HP HP PaintJet XL Color Graphics Printer (color mode) +.TP +.B pp +IBM PP3812 +.TP +.B ps +PostScript printer +.PD +.RE +.IP +The default is PostScript. +\fB\-device lw\fP (LaserWriter) is equivalent to \fB\-device ps\fP and is +provided only for backwards compatibility. +.TP +.B \-help +This option displays the list of options known to +.I xdpr. +.PP +Any other arguments +will be passed to the +.I xwd, +.I xpr, +and +.I lpr +or +.I lp +commands as appropriate for each. +.SH SEE ALSO +.IR xwd (1), +.IR xpr (1), +.IR lpr (1), +.IR lp (1), +.IR xwud (1), +.IR X (1) +.SH ENVIRONMENT +.TP 10 +DISPLAY +which display to use by default. +.TP 10 +PRINTER +which printer to use by default. +.SH COPYRIGHT +Copyright ([\d,\s]*) X Consortium +.br +See \fIX(1)\fP for a full statement of rights and permissions. +.SH AUTHORS +Paul Boutin, MIT Project Athena +.br +Michael R. Gretzinger, MIT Project Athena +.br +Jim Gettys, MIT Project Athena Index: xc/programs/xpr/xdpr.script =================================================================== RCS file: xc/programs/xpr/xdpr.script diff -N xc/programs/xpr/xdpr.script --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/xdpr.script 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,166 @@ +#! /bin/sh +# Copyright 1985,1988 Massacusetts Institute of Technology. +# $XConsortium: xdpr.script /main/10 1995/12/08 11:10:59 swick $ +# origin: William Kucharski, Solbourne Computer, Inc. 3/24/90 +# translated from csh script xdpr.script "paul 4/12/88" + +# initialize variables + +display="$DISPLAY" +header= +bsdlprv= +lprv= +out= +svlprv= +trailer= +xprv= +xwdv= + +usage="Usage: xdpr [filename] [-out filename ] \ +[-display host:display] [[-Pprinter] | [-dprinter]] [-device devtype] \ +[{-root | -id | -name }] [-nobdrs] [-xy] \ +[-scale scale] [-height inches] [-width inches] [-left inches] \ +[-top inches] [-split n] [-header string] [-trailer string] \ +[-landscape] [-portrait] [-rv] [-compact] [-noff] [-frame] \ +[-plane number] [-gray number] [-psfig] [-density dpi] \ +[-cutoff level] [-noposition] [-gamma correction] [-render algorithm] \ +[-slide] [-add value] [-help]" + +# Guess if we are BSD or System V + +if [ -x /usr/ucb/lpr -o -x /usr/bin/lpr -o -x /bin/lpr -o -x /usr/bsd/lpr ] +then + LP=lpr + BSD=1 +elif [ -x /usr/bin/lp -o -x /bin/lp ] +then + LP=lp + BSD=0 +else + LP=lpr + BSD=1 +fi + +# parse arguments... + +while [ $1 ]; do + case "$1" in + +# ...arguments interpreted by xdpr itself... + + -help) + echo $usage; + exit 0;; + +# ...arguments to xwd... + + -nobdrs|-root|-xy|-frame) + xwdv="$xwdv $1";; + -display) + display=$2 + xwdv="$xwdv $1 $2"; + shift;; + -id|-name) + xwdv="$xwdv $1 $2"; + shift;; + -out|-add) + out=true + xwdv="$xwdv $1 $2"; + shift;; + +# ...arguments to xpr... + + -scale|-height|-width|-left|-top|-split|-device) + xprv="$xprv $1 $2"; + shift;; + -plane|-gray|-density|-cutoff|-gamma|-render) + xprv="$xprv $1 $2"; + shift;; + -header) + shift; + header="$1";; + -trailer) + shift; + trailer="$1";; + -landscape|-portrait|-rv|-compact|-noff|-psfig|-noposition|-slide) + xprv="$xprv $1";; + +# ...arguments to lp[r]... + + -P*|-#?*|-C?*|-J?*|-h|-m) + bsdlprv="$lprv $1";; + + -d*|-H*|-q*|-n*|-o*|-w) + svlprv="$svlprv $1";; + +# ...disallow other arguments; print usage message + + -*) + echo "xdpr: Unknown option $1"; + echo $usage; + exit 1;; + +# ...input filename... + + *) + if [ ! "$infile" ]; then + infile=true + xprv="$xprv $1" + else + echo "xdpr: Invalid argument "$1"" + echo $usage + exit 1 + fi + esac + shift +done + +# quit if there is no DISPLAY specified + +if [ ! "$display" ]; then + echo "xdpr: DISPLAY variable must be set or a display specified." + exit +fi + +# Command lines: + +# Set up lp[r] options... + +if [ $BSD -eq 0 ] +then + lprv=$svlprv +else + lprv=$bsdlprv +fi + +# disallow concurrent input and -out arguments +if [ "$out" -a "$infile" ]; then + echo "xdpr: -out cannot be used if an input file is also specified." + exit 0 +fi + +# dump only +if [ "$out" ]; then + if [ "$xprv" -o "$lprv" ]; then + echo "xdpr: The following arguments will be ignored:" + echo $xprv $lprv + fi + xwd $xwdv + exit 0 +fi + +# print only +if [ "$infile" ]; then + if [ "$xwdv" ]; then + echo "xdpr: The following arguments will be ignored:" + echo $xwdv + fi + xpr -header "$header" -trailer "$trailer" $xprv | $LP $lprv + exit 0 +fi + +# dump & print (default) +xwd $xwdv | xpr -header "$header" -trailer "$trailer" $xprv | $LP $lprv +exit 0 + +# EOF Index: xc/programs/xpr/xpr.c =================================================================== RCS file: xc/programs/xpr/xpr.c diff -N xc/programs/xpr/xpr.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/xpr.c 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,1915 @@ +/* $XConsortium: xpr.c,v 1.59 94/10/14 21:22:08 kaleb Exp $ */ +/* + +Copyright (c) 1985 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ + +/* + * XPR - process xwd(1) files for various printers + * + * Author: Michael R. Gretzinger, MIT Project Athena + * + * Modified by Marvin Solomon, Univeristy of Wisconsin, to handle Apple + * Laserwriter (PostScript) devices (-device ps). + * Also accepts the -compact flag that produces more compact output + * by using run-length encoding on white (1) pixels. + * This version does not (yet) support the following options + * -append -dump -noff -nosixopt -split + * + * Changes + * Copyright 1986 by Marvin Solomon and the University of Wisconsin + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the names of Marvin Solomon and + * the University of Wisconsin not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * Neither Marvin Solomon nor the University of Wisconsin + * makes any representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Modified by Bob Scheifler for 2x2 grayscale, then ... + * Modified by Angela Bock and E. Mike Durbin, Rich Inc., to produce output + * using 2x2, 3x3, or 4x4 grayscales. This version modifies the grayscale + * conversion option of -gray to accept an input of 2, 3, or 4 to signify + * the gray level desired. The output is produced, using 5, 10, or 17-level + * gray scales, respectively. + * + * Modifications by Larry Rupp, Hewlett-Packard Company, to support HP + * LaserJet, PaintJet, and other PCL printers. Added "ljet" and "pjet" + * to devices recognized. Also added -density, -cutoff, and -noposition + * command line options. + * + */ + +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include "lncmd.h" +#include "xpr.h" +#include +#include +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef NLS16 +#ifndef NLS +#define NLS +#endif +#endif + +#ifndef NLS +#define catgets(i, sn,mn,s) (s) +#else /* NLS */ +#define NL_SETN 1 /* set number */ +#include + +nl_catd nlmsg_fd; +#endif /* NLS */ + +int debug = 0; + +#define W_MAX 2400 +#define H_MAX 3150 +#define W_MARGIN 75 +#define H_MARGIN 37 +#define W_PAGE 2550 +#define H_PAGE 3225 + +#ifdef NOINLINE +#define min(x,y) (((x)<(y))?(x):(y)) +#endif /* NOINLINE */ + +#define F_PORTRAIT 1 +#define F_LANDSCAPE 2 +#define F_DUMP 4 +#define F_NOSIXOPT 8 +#define F_APPEND 16 +#define F_NOFF 32 +#define F_REPORT 64 +#define F_COMPACT 128 +#define F_INVERT 256 +#define F_GRAY 512 +#define F_NPOSITION 1024 +#define F_SLIDE 2048 + +#define DEFAULT_CUTOFF ((unsigned int) (0xFFFF * 0.50)) + +char *infilename = NULL; +char *progname; + +char *convert_data(); + +typedef struct _grayRec { + int level; + int sizeX, sizeY; /* 2x2, 3x3, 4x4 */ + unsigned long *grayscales; /* pointer to the encoded pixels */ +} GrayRec, *GrayPtr; + +unsigned long grayscale2x2[] = + {0, 1, 9, 11, 15}; +unsigned long grayscale3x3[] = + {0, 16, 68, 81, 325, 341, 349, 381, 383, 511}; +unsigned long grayscale4x4[] = + {0, 64, 4160, 4161, 20545, 21057, 23105, + 23113, 23145, 24169, 24171, 56939, 55275, 55279, + 57327, 65519, 65535}; + +GrayRec gray2x2 = {sizeof(grayscale2x2)/sizeof(long), 2, 2, grayscale2x2}; +GrayRec gray3x3 = {sizeof(grayscale3x3)/sizeof(long), 3, 3, grayscale3x3}; +GrayRec gray4x4 = {sizeof(grayscale4x4)/sizeof(long), 4, 4, grayscale4x4}; + +main(argc, argv) +char **argv; +{ + unsigned long swaptest = 1; + XWDFileHeader win; + register unsigned char (*sixmap)[]; + register int i; + register int iw; + register int ih; + register int sixel_count; + char *w_name; + int scale, width, height, flags, split; + int left, top; + int top_margin, left_margin; + int hpad; + char *header, *trailer; + int plane; + int density, render; + unsigned int cutoff; + float gamma; + GrayPtr gray; + char *data; + long size; + enum orientation orientation; + enum device device; + XColor *colors = (XColor *)NULL; + + if (!(progname = argv[0])) + progname = "xpr"; +#ifdef NLS + nlmsg_fd = catopen("xpr", 0); +#endif + parse_args (argc, argv, &scale, &width, &height, &left, &top, &device, + &flags, &split, &header, &trailer, &plane, &gray, + &density, &cutoff, &gamma, &render); + + if (device == PP) { + x2pmp(stdin, stdout, scale, + width >= 0? inch2pel((float)width/300.0): X_MAX_PELS, + height >= 0? inch2pel((float)height/300.0): Y_MAX_PELS, + left >= 0? inch2pel((float)left/300.0): inch2pel(0.60), + top >= 0? inch2pel((float)top/300.0): inch2pel(0.70), + header, trailer, + (flags & F_PORTRAIT)? PORTRAIT: + ((flags & F_LANDSCAPE)? LANDSCAPE: UNSPECIFIED), + (flags & F_INVERT)); + exit(0); + } else if ((device == LJET) || (device == PJET) || (device == PJETXL)) { + x2jet(stdin, stdout, scale, density, width, height, left, top, + header, trailer, + (flags & F_PORTRAIT)? PORTRAIT: + ((flags & F_LANDSCAPE)? LANDSCAPE: UNSPECIFIED), + (flags & F_INVERT), + ((flags & F_APPEND) && !(flags & F_NOFF)), + !(flags & F_NPOSITION), + (flags & F_SLIDE), + device, cutoff, gamma, render); + exit(0); + } + + /* read in window header */ + fullread(0, (char *)&win, sizeof win); + if (*(char *) &swaptest) + _swaplong((char *) &win, (long)sizeof(win)); + + if (win.file_version != XWD_FILE_VERSION) { + fprintf(stderr,"xpr: file format version missmatch.\n"); + exit(1); + } + if (win.header_size < sizeof(win)) { + fprintf(stderr,"xpr: header size is too small.\n"); + exit(1); + } + + w_name = malloc((unsigned)(win.header_size - sizeof win)); + fullread(0, w_name, (int) (win.header_size - sizeof win)); + + if(win.ncolors) { + XWDColor xwdcolor; + colors = (XColor *)malloc((unsigned) (win.ncolors * sizeof(XColor))); + for (i = 0; i < win.ncolors; i++) { + fullread(0, (char*)&xwdcolor, (int) sizeof xwdcolor); + colors[i].pixel = xwdcolor.pixel; + colors[i].red = xwdcolor.red; + colors[i].green = xwdcolor.green; + colors[i].blue = xwdcolor.blue; + colors[i].flags = xwdcolor.flags; + } + if (*(char *) &swaptest) { + for (i = 0; i < win.ncolors; i++) { + _swaplong((char *) &colors[i].pixel, (long)sizeof(long)); + _swapshort((char *) &colors[i].red, (long) (3 * sizeof(short))); + } + } + if ((win.ncolors == 2) && + (INTENSITY(&colors[0]) > INTENSITY(&colors[1]))) + flags ^= F_INVERT; + } + if (plane >= (long)win.pixmap_depth) { + fprintf(stderr,"xpr: plane number exceeds image depth\n"); + exit(1); + } + size = win.bytes_per_line * win.pixmap_height; + if (win.pixmap_format == XYPixmap) + size *= win.pixmap_depth; + data = malloc((unsigned)size); + fullread(0, data, (int)size); + if ((win.pixmap_depth > 1) || (win.byte_order != win.bitmap_bit_order)) { + data = convert_data(&win, data, plane, gray, colors, flags); + size = win.bytes_per_line * win.pixmap_height; + } + if (win.bitmap_bit_order == MSBFirst) { + _swapbits((unsigned char *)data, size); + win.bitmap_bit_order = LSBFirst; + } + if (flags & F_INVERT) + _invbits((unsigned char *)data, size); + + /* calculate orientation and scale */ + setup_layout(device, (int) win.pixmap_width, (int) win.pixmap_height, + flags, width, height, header, trailer, &scale, &orientation); + + if (device == PS) { + iw = win.pixmap_width; + ih = win.pixmap_height; + } else { + /* calculate w and h cell count */ + iw = win.pixmap_width; + ih = (win.pixmap_height + 5) / 6; + hpad = (ih * 6) - win.pixmap_height; + + /* build pixcells from input file */ + sixel_count = iw * ih; + sixmap = (unsigned char (*)[])malloc((unsigned)sixel_count); + build_sixmap(iw, ih, sixmap, hpad, &win, data); + } + + /* output commands and sixel graphics */ + if (device == LN03) { +/* ln03_grind_fonts(sixmap, iw, ih, scale, &pixmap); */ + ln03_setup(iw, ih, orientation, scale, left, top, + &left_margin, &top_margin, flags, header, trailer); + ln03_output_sixels(sixmap, iw, ih, (flags & F_NOSIXOPT), split, + scale, top_margin, left_margin); + ln03_finish(); + } else if (device == LA100) { + la100_setup(iw, ih, scale); + la100_output_sixels(sixmap, iw, ih, (flags & F_NOSIXOPT)); + la100_finish(); + } else if (device == PS) { + ps_setup(iw, ih, orientation, scale, left, top, + flags, header, trailer, w_name); + ps_output_bits(iw, ih, flags, orientation, &win, data); + ps_finish(); + } else { + fprintf(stderr, "xpr: device not supported\n"); + } + + /* print some statistics */ + if (flags & F_REPORT) { + fprintf(stderr, "Name: %s\n", w_name); + fprintf(stderr, "Width: %d, Height: %d\n", win.pixmap_width, + win.pixmap_height); + fprintf(stderr, "Orientation: %s, Scale: %d\n", + (orientation==PORTRAIT) ? "Portrait" : "Landscape", scale); + } + if (((device == LN03) || (device == LA100)) && (flags & F_DUMP)) + dump_sixmap(sixmap, iw, ih); + exit(0); +} + +usage() +{ + fprintf(stderr, "usage: %s [options] [file]\n", progname); + fprintf(stderr, " -append -noff -output \n"); + fprintf(stderr, " -compact\n"); + fprintf(stderr, " -device {ln03 | la100 | ps | lw | pp | ljet | pjet | pjetxl}\n"); + fprintf(stderr, " -dump\n"); + fprintf(stderr, " -gamma \n"); + fprintf(stderr, " -gray {2 | 3 | 4}\n"); + fprintf(stderr, " -height -width \n"); + fprintf(stderr, " -header -trailer \n"); + fprintf(stderr, " -landscape -portrait\n"); + fprintf(stderr, " -left -top \n"); + fprintf(stderr, " -noposition\n"); + fprintf(stderr, " -nosixopt\n"); + fprintf(stderr, " -plane \n"); + fprintf(stderr, " -psfig\n"); + fprintf(stderr, " -render \n"); + fprintf(stderr, " -report\n"); + fprintf(stderr, " -rv\n"); + fprintf(stderr, " -scale \n"); + fprintf(stderr, " -slide\n"); + fprintf(stderr, " -split \n"); + exit(1); +} + +parse_args(argc, argv, scale, width, height, left, top, device, flags, + split, header, trailer, plane, gray, density, cutoff, gamma, render) +register int argc; +register char **argv; +int *scale; +int *width; +int *height; +int *left; +int *top; +enum device *device; +int *flags; +int *split; +char **header; +char **trailer; +int *plane; +GrayPtr *gray; +int *density; +unsigned int *cutoff; +float *gamma; +int *render; +{ + register char *output_filename; + register int f; + register int len; + register int pos; +#ifdef X_NOT_STDC_ENV + double atof(); + int atoi(); +#endif + + output_filename = NULL; + *device = PS; /* default */ + *flags = 0; + *scale = 0; + *split = 1; + *width = -1; + *height = -1; + *top = -1; + *left = -1; + *header = NULL; + *trailer = NULL; + *plane = -1; + *gray = (GrayPtr)NULL; + *density = 0; + *cutoff = DEFAULT_CUTOFF; + *gamma = -1.0; + *render = 0; + + for (argc--, argv++; argc > 0; argc--, argv++) { + if (argv[0][0] != '-') { + infilename = *argv; + continue; + } + len = strlen(*argv); + switch (argv[0][1]) { + case 'a': /* -append */ + if (!bcmp(*argv, "-append", len)) { + argc--; argv++; + if (argc == 0) usage(); + output_filename = *argv; + *flags |= F_APPEND; + } else + usage(); + break; + + case 'c': /* -compact | -cutoff */ + if (len <= 2 ) + usage(); + if (!bcmp(*argv, "-compact", len)) { + *flags |= F_COMPACT; + } else if (!bcmp(*argv, "-cutoff", len)) { + argc--; argv++; + if (argc == 0) usage(); + *cutoff = min((atof(*argv) / 100.0 * 0xFFFF), 0xFFFF); + } else + usage(); + break; + + case 'd': /* -density | -device | -dump */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-dump", len)) { + *flags |= F_DUMP; + } else if (len <= 3) { + usage(); + } else if (!bcmp(*argv, "-density", len)) { + argc--; argv++; + if (argc == 0) usage(); + *density = atoi(*argv); + } else if (!bcmp(*argv, "-device", len)) { + argc--; argv++; + if (argc == 0) usage(); + len = strlen(*argv); + if (len < 2) + usage(); + if (!bcmp(*argv, "ln03", len)) { + *device = LN03; + } else if (!bcmp(*argv, "la100", len)) { + *device = LA100; + } else if (!bcmp(*argv, "ps", len)) { + *device = PS; + } else if (!bcmp(*argv, "lw", len)) { + *device = PS; + } else if (!bcmp(*argv, "pp", len)) { + *device = PP; + } else if (!bcmp(*argv, "ljet", len)) { + *device = LJET; + } else if (!bcmp(*argv, "pjet", len)) { + *device = PJET; + } else if (!bcmp(*argv, "pjetxl", len)) { + *device = PJETXL; + } else + usage(); + } else + usage(); + break; + + case 'g': /* -gamma | -gray */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-gamma", len)) { + argc--; argv++; + if (argc == 0) usage(); + *gamma = atof(*argv); + } else if (!bcmp(*argv, "-gray", len) || + !bcmp(*argv, "-grey", len)) { + argc--; argv++; + if (argc == 0) usage(); + switch (atoi(*argv)) { + case 2: + *gray = &gray2x2; + break; + case 3: + *gray = &gray3x3; + break; + case 4: + *gray = &gray4x4; + break; + default: + usage(); + } + *flags |= F_GRAY; + } else + usage(); + break; + + case 'h': /* -height | -header */ + if (len <= 3) + usage(); + if (!bcmp(*argv, "-height", len)) { + argc--; argv++; + if (argc == 0) usage(); + *height = (int)(300.0 * atof(*argv)); + } else if (!bcmp(*argv, "-header", len)) { + argc--; argv++; + if (argc == 0) usage(); + *header = *argv; + } else + usage(); + break; + + case 'l': /* -landscape | -left */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-landscape", len)) { + *flags |= F_LANDSCAPE; + } else if (!bcmp(*argv, "-left", len)) { + argc--; argv++; + if (argc == 0) usage(); + *left = (int)(300.0 * atof(*argv)); + } else + usage(); + break; + + case 'n': /* -nosixopt | -noff | -noposition */ + if (len <= 3) + usage(); + if (!bcmp(*argv, "-nosixopt", len)) { + *flags |= F_NOSIXOPT; + } else if (!bcmp(*argv, "-noff", len)) { + *flags |= F_NOFF; + } else if (!bcmp(*argv, "-noposition", len)) { + *flags |= F_NPOSITION; + } else + usage(); + break; + + case 'o': /* -output */ + if (!bcmp(*argv, "-output", len)) { + argc--; argv++; + if (argc == 0) usage(); + output_filename = *argv; + } else + usage(); + break; + + case 'p': /* -portrait | -plane */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-portrait", len)) { + *flags |= F_PORTRAIT; + } else if (!bcmp(*argv, "-plane", len)) { + argc--; argv++; + if (argc == 0) usage(); + *plane = atoi(*argv); + } else if (!bcmp(*argv, "-psfig", len)) { + *flags |= F_NPOSITION; + } else + usage(); + break; + + case 'r': /* -render | -report | -rv */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-rv", len)) { + *flags |= F_INVERT; + } else if (len <= 3) { + usage(); + } else if (!bcmp(*argv, "-render", len)) { + argc--; argv++; + if (argc == 0) usage(); + *render = atoi(*argv); + } else if (!bcmp(*argv, "-report", len)) { + *flags |= F_REPORT; + } else + usage(); + break; + + case 's': /* -scale | -slide | -split */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-scale", len)) { + argc--; argv++; + if (argc == 0) usage(); + *scale = atoi(*argv); + } else if (!bcmp(*argv, "-slide", len)) { + *flags |= F_SLIDE; + } else if (!bcmp(*argv, "-split", len)) { + argc--; argv++; + if (argc == 0) usage(); + *split = atoi(*argv); + } else + usage(); + break; + + case 't': /* -top | -trailer */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-top", len)) { + argc--; argv++; + if (argc == 0) usage(); + *top = (int)(300.0 * atof(*argv)); + } else if (!bcmp(*argv, "-trailer", len)) { + argc--; argv++; + if (argc == 0) usage(); + *trailer = *argv; + } else + usage(); + break; + + case 'w': /* -width */ + if (!bcmp(*argv, "-width", len)) { + argc--; argv++; + if (argc == 0) usage(); + *width = (int)(300.0 * atof(*argv)); + } else + usage(); + break; + + default: + usage(); + break; + } + } + + if (infilename) { + f = open(infilename, O_RDONLY|O_BINARY, 0); + if (f < 0) { + fprintf(stderr, "xpr: error opening \"%s\" for input\n", + infilename); + perror(""); + exit(1); + } + dup2(f, 0); + close(f); + } else + infilename = "stdin"; + + if (output_filename != NULL) { + if (!(*flags & F_APPEND)) { + f = open(output_filename, O_CREAT|O_WRONLY|O_TRUNC, 0664); + } else { + f = open(output_filename, O_WRONLY, 0); + } + if (f < 0) { + fprintf(stderr, "xpr: error opening \"%s\" for output\n", + output_filename); + perror("xpr"); + exit(1); + } + if (*flags & F_APPEND) { + pos = lseek(f, 0, 2); /* get eof position */ + if ((*flags & F_NOFF) && + !(*device == LJET || *device == PJET || *device == PJETXL)) + pos -= 3; /* set position before trailing */ + /* formfeed and reset */ + lseek(f, pos, 0); /* set pointer */ + } + dup2(f, 1); + close(f); + } +} + +setup_layout(device, win_width, win_height, flags, width, height, + header, trailer, scale, orientation) +enum device device; +int win_width; +int win_height; +int flags; +int width; +int height; +char *header; +char *trailer; +int *scale; +enum orientation *orientation; +{ + register int w_scale; + register int h_scale; + register int iscale = *scale; + register int w_max; + register int h_max; + + if (header != NULL) win_height += 75; + if (trailer != NULL) win_height += 75; + + /* check maximum width and height; set orientation and scale*/ + if (device == LN03 || device == PS) { + if ((win_width < win_height || (flags & F_PORTRAIT)) && + !(flags & F_LANDSCAPE)) { + *orientation = PORTRAIT; + w_max = (width > 0)? width : W_MAX; + h_max = (height > 0)? height : H_MAX; + w_scale = w_max / win_width; + h_scale = h_max / win_height; + *scale = min(w_scale, h_scale); + } else { + *orientation = LANDSCAPE; + w_max = (width > 0)? width : H_MAX; + h_max = (height > 0)? height : W_MAX; + w_scale = w_max / win_width; + h_scale = h_max / win_height; + *scale = min(w_scale, h_scale); + } + } else { /* device == LA100 */ + *orientation = PORTRAIT; + *scale = W_MAX / win_width; + } + if (*scale == 0) *scale = 1; + if (*scale > 6) *scale = 6; + if (iscale > 0 && iscale < *scale) *scale = iscale; +} + +char * +convert_data(win, data, plane, gray, colors, flags) + register XWDFileHeader *win; + char *data; + int plane; + register GrayPtr gray; + XColor *colors; + int flags; +{ + XImage in_image_struct, out_image_struct; + register XImage *in_image, *out_image; + register int x, y; + + if ((win->pixmap_format == XYPixmap) && (plane >= 0)) { + data += win->bytes_per_line * win->pixmap_height * + (win->pixmap_depth - (plane + 1)); + win->pixmap_format = XYBitmap; + win->pixmap_depth = 1; + return data; + } + + /* initialize the input image */ + + in_image = &in_image_struct; + in_image->byte_order = win->byte_order; + in_image->bitmap_unit = win->bitmap_unit; + in_image->bitmap_bit_order = win->bitmap_bit_order; + in_image->depth = win->pixmap_depth; + in_image->bits_per_pixel = win->bits_per_pixel; + in_image->format = win->pixmap_format, + in_image->xoffset = win->xoffset, + in_image->data = data; + in_image->width = win->pixmap_width; + in_image->height = win->pixmap_height; + in_image->bitmap_pad = win->bitmap_pad; + in_image->bytes_per_line = win->bytes_per_line; + in_image->red_mask = win->red_mask; + in_image->green_mask = win->green_mask; + in_image->blue_mask = win->blue_mask; + in_image->obdata = NULL; + if (!XInitImage(in_image)) { + fprintf(stderr,"xpr: bad input image header data.\n"); + exit(1); + } + if ((flags & F_GRAY) && (in_image->depth > 1) && (plane < 0)) { + win->pixmap_width *= gray->sizeX; + win->pixmap_height *= gray->sizeY; + } + win->xoffset = 0; + win->pixmap_format = XYBitmap; + win->byte_order = LSBFirst; + win->bitmap_unit = 8; + win->bitmap_bit_order = LSBFirst; + win->bitmap_pad = 8; + win->pixmap_depth = 1; + win->bits_per_pixel = 1; + win->bytes_per_line = (win->pixmap_width + 7) >> 3; + + out_image = &out_image_struct; + out_image->byte_order = win->byte_order; + out_image->bitmap_unit = win->bitmap_unit; + out_image->bitmap_bit_order = win->bitmap_bit_order; + out_image->depth = win->pixmap_depth; + out_image->bits_per_pixel = win->bits_per_pixel; + out_image->format = win->pixmap_format; + out_image->xoffset = win->xoffset, + out_image->width = win->pixmap_width; + out_image->height = win->pixmap_height; + out_image->bitmap_pad = win->bitmap_pad; + out_image->bytes_per_line = win->bytes_per_line; + out_image->red_mask = 0; + out_image->green_mask = 0; + out_image->blue_mask = 0; + out_image->obdata = NULL; + out_image->data = malloc((unsigned)out_image->bytes_per_line * + out_image->height); + if (!XInitImage(out_image)) { + fprintf(stderr,"xpr: bad output image header data.\n"); + exit(1); + } + + if ((in_image->depth > 1) && (plane > 0)) { + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) + XPutPixel(out_image, x, y, + (XGetPixel(in_image, x, y) >> plane) & 1); + } else if (plane == 0) { + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) + XPutPixel(out_image, x, y, XGetPixel(in_image, x, y)); + } else if ((in_image->depth > 1) && + ((win->visual_class == TrueColor) || + (win->visual_class == DirectColor))) { + XColor color; + int direct = 0; + unsigned long rmask, gmask, bmask; + int rshift = 0, gshift = 0, bshift = 0; + + rmask = win->red_mask; + while (!(rmask & 1)) { + rmask >>= 1; + rshift++; + } + gmask = win->green_mask; + while (!(gmask & 1)) { + gmask >>= 1; + gshift++; + } + bmask = win->blue_mask; + while (!(bmask & 1)) { + bmask >>= 1; + bshift++; + } + if ((win->ncolors == 0) || (win->visual_class == DirectColor)) + direct = 1; + if (flags & F_GRAY) { + register int ox, oy; + int ix, iy; + unsigned long bits; + for (y = 0, oy = 0; y < in_image->height; y++, oy += gray->sizeY) + for (x = 0, ox = 0; x < in_image->width; x++, ox += gray->sizeX) + { + color.pixel = XGetPixel(in_image, x, y); + color.red = (color.pixel >> rshift) & rmask; + color.green = (color.pixel >> gshift) & gmask; + color.blue = (color.pixel >> bshift) & bmask; + if (!direct) { + color.red = colors[color.red].red; + color.green = colors[color.green].green; + color.blue = colors[color.blue].blue; + } + bits = gray->grayscales[(int)(gray->level * + INTENSITY(&color)) / + (INTENSITYPER(100) + 1)]; + for (iy = 0; iy < gray->sizeY; iy++) + for (ix = 0; ix < gray->sizeX; ix++, bits >>= 1) + XPutPixel(out_image, ox + ix, oy + iy, bits); + } + } else { + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) { + color.pixel = XGetPixel(in_image, x, y); + color.red = (color.pixel >> rshift) & rmask; + color.green = (color.pixel >> gshift) & gmask; + color.blue = (color.pixel >> bshift) & bmask; + if (!direct) { + color.red = colors[color.red].red; + color.green = colors[color.green].green; + color.blue = colors[color.blue].blue; + } + XPutPixel(out_image, x, y, + INTENSITY(&color) > HALFINTENSITY); + } + } + } else if (flags & F_GRAY) { + register int ox, oy; + int ix, iy; + unsigned long bits; + + if (win->ncolors == 0) { + fprintf(stderr, "no colors in data, can't remap\n"); + exit(1); + } + for (x = 0; x < win->ncolors; x++) { + register XColor *color = &colors[x]; + + color->pixel = gray->grayscales[(gray->level * INTENSITY(color)) / + (INTENSITYPER(100) + 1)]; + } + for (y = 0, oy = 0; y < in_image->height; y++, oy += gray->sizeY) + for (x = 0, ox = 0; x < in_image->width; x++, ox += gray->sizeX) { + bits = colors[XGetPixel(in_image, x, y)].pixel; + for (iy = 0; iy < gray->sizeY; iy++) + for (ix = 0; ix < gray->sizeX; ix++, bits >>= 1) + XPutPixel(out_image, ox + ix, oy + iy, bits); + } + } else { + if (win->ncolors == 0) { + fprintf(stderr, "no colors in data, can't remap\n"); + exit(1); + } + for (x = 0; x < win->ncolors; x++) { + register XColor *color = &colors[x]; + color->pixel = (INTENSITY(color) > HALFINTENSITY); + } + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) + XPutPixel(out_image, x, y, + colors[XGetPixel(in_image, x, y)].pixel); + } + free(data); + return (out_image->data); +} + +dump_sixmap(sixmap, iw, ih) +register unsigned char (*sixmap)[]; +int iw; +int ih; +{ + register int i, j; + register unsigned char *c; + + c = (unsigned char *)sixmap; + fprintf(stderr, "Sixmap:\n"); + for (i = 0; i < ih; i++) { + for (j = 0; j < iw; j++) { + fprintf(stderr, "%02X ", *c++); + } + fprintf(stderr, "\n\n"); + } +} + +build_sixmap(iw, ih, sixmap, hpad, win, data) +int ih; +int iw; +unsigned char (*sixmap)[]; +int hpad; +XWDFileHeader *win; +char *data; +{ + int iwb = win->bytes_per_line; + unsigned char *line[6]; + register unsigned char *c; + register int i, j; +#ifdef NOINLINE + register int w; +#endif + register int sixel; + unsigned char *buffer = (unsigned char *)data; + + c = (unsigned char *)sixmap; + + + while (--ih >= 0) { + for (i = 0; i <= 5; i++) { + line[i] = buffer; + buffer += iwb; + } + if ((ih == 0) && (hpad > 0)) { + unsigned char *ffbuf; + + ffbuf = (unsigned char *)malloc((unsigned)iwb); + for (j = 0; j < iwb; j++) + ffbuf[j] = 0xFF; + for (; --hpad >= 0; i--) + line[i] = ffbuf; + } + +#ifndef NOINLINE + for (i = 0; i < iw; i++) { + sixel = extzv(line[0], i, 1); + sixel |= extzv(line[1], i, 1) << 1; + sixel |= extzv(line[2], i, 1) << 2; + sixel |= extzv(line[3], i, 1) << 3; + sixel |= extzv(line[4], i, 1) << 4; + sixel |= extzv(line[5], i, 1) << 5; + *c++ = sixel; + } +#else + for (i = 0, w = iw; w > 0; i++) { + for (j = 0; j <= 7; j++) { + sixel = ((line[0][i] >> j) & 1); + sixel |= ((line[1][i] >> j) & 1) << 1; + sixel |= ((line[2][i] >> j) & 1) << 2; + sixel |= ((line[3][i] >> j) & 1) << 3; + sixel |= ((line[4][i] >> j) & 1) << 4; + sixel |= ((line[5][i] >> j) & 1) << 5; + *c++ = sixel; + if (--w == 0) break; + } + } +#endif + } +} + +build_output_filename(name, device, oname) +register char *name, *oname; +enum device device; +{ + while (*name && *name != '.') *oname++ = *name++; + switch (device) { + case LN03: bcopy(".ln03", oname, 6); break; + case LA100: bcopy(".la100", oname, 7); break; + } +} + +/* +ln03_grind_fonts(sixmap, iw, ih, scale, pixmap) +unsigned char (*sixmap)[]; +int iw; +int ih; +int scale; +struct pixmap (**pixmap)[]; +{ +} +*/ + +ln03_setup(iw, ih, orientation, scale, left, top, left_margin, top_margin, + flags, header, trailer) +int iw; +int ih; +enum orientation orientation; +int scale; +int left; +int top; +int *left_margin; +int *top_margin; +int flags; +char *header; +char *trailer; +{ + register int i; + register int lm, tm, xm; + char buf[256]; + register char *bp = buf; + + if (!(flags & F_APPEND)) { + sprintf(bp, LN_STR); bp += 4; + sprintf(bp, LN_SSU, 7); bp += 5; + sprintf(bp, LN_PUM_SET); bp += sizeof LN_PUM_SET - 1; + } + + if (orientation == PORTRAIT) { + lm = (left > 0)? left : (((W_MAX - scale * iw) / 2) + W_MARGIN); + tm = (top > 0)? top : (((H_MAX - scale * ih * 6) / 2) + H_MARGIN); + sprintf(bp, LN_PFS, "?20"); bp += 7; + sprintf(bp, LN_DECOPM_SET); bp += sizeof LN_DECOPM_SET - 1; + sprintf(bp, LN_DECSLRM, lm, W_PAGE - lm); bp += strlen(bp); + } else { + lm = (left > 0)? left : (((H_MAX - scale * iw) / 2) + H_MARGIN); + tm = (top > 0)? top : (((W_MAX - scale * ih * 6) / 2) + W_MARGIN); + sprintf(bp, LN_PFS, "?21"); bp += 7; + sprintf(bp, LN_DECOPM_SET); bp += sizeof LN_DECOPM_SET - 1; + sprintf(bp, LN_DECSLRM, lm, H_PAGE - lm); bp += strlen(bp); + } + + if (header != NULL) { + sprintf(bp, LN_VPA, tm - 100); bp += strlen(bp); + i = strlen(header); + xm = (((scale * iw) - (i * 30)) / 2) + lm; + sprintf(bp, LN_HPA, xm); bp += strlen(bp); + sprintf(bp, LN_SGR, 3); bp += strlen(bp); + bcopy(header, bp, i); + bp += i; + } + if (trailer != NULL) { + sprintf(bp, LN_VPA, tm + (scale * ih * 6) + 75); bp += strlen(bp); + i = strlen(trailer); + xm = (((scale * iw) - (i * 30)) / 2) + lm; + sprintf(bp, LN_HPA, xm); bp += strlen(bp); + sprintf(bp, LN_SGR, 3); bp += strlen(bp); + bcopy(trailer, bp, i); + bp += i; + } + + sprintf(bp, LN_HPA, lm); bp += strlen(bp); + sprintf(bp, LN_VPA, tm); bp += strlen(bp); + sprintf(bp, LN_SIXEL_GRAPHICS, 9, 0, scale); bp += strlen(bp); + sprintf(bp, "\"1;1"); bp += 4; /* Pixel aspect ratio */ + write(1, buf, bp-buf); + *top_margin = tm; + *left_margin = lm; +} + + +ln03_finish() +{ + char buf[256]; + register char *bp = buf; + + sprintf(bp, LN_DECOPM_RESET); bp += sizeof LN_DECOPM_SET - 1; + sprintf(bp, LN_LNM); bp += 5; + sprintf(bp, LN_PUM); bp += 5; + sprintf(bp, LN_PFS, "?20"); bp += 7; + sprintf(bp, LN_SGR, 0); bp += strlen(bp); + sprintf(bp, LN_HPA, 1); bp += strlen(bp); + sprintf(bp, LN_VPA, 1); bp += strlen(bp); + + + write(1, buf, bp-buf); + +} + +/*ARGSUSED*/ +la100_setup(iw, ih, scale) +{ + char buf[256]; + register char *bp; + int lm, tm; + + bp = buf; + lm = ((80 - (int)((double)iw / 6.6)) / 2) - 1; + if (lm < 1) lm = 1; + tm = ((66 - (int)((double)ih / 2)) / 2) - 1; + if (tm < 1) tm = 1; + sprintf(bp, "\033[%d;%ds", lm, 81-lm); bp += strlen(bp); + sprintf(bp, "\033[?7l"); bp += 5; + sprintf(bp, "\033[%dd", tm); bp += strlen(bp); + sprintf(bp, "\033[%d`", lm); bp += strlen(bp); + sprintf(bp, "\033P0q"); bp += 4; + write(1, buf, bp-buf); +} + +#define LA100_RESET "\033[1;80s\033[?7h" + +la100_finish() +{ + write(1, LA100_RESET, sizeof LA100_RESET - 1); +} + +#define COMMENTVERSION "PS-Adobe-1.0" + +#ifdef XPROLOG +/* for debugging, get the prolog from a file */ +dump_prolog(flags) { + char *fname=(flags & F_COMPACT) ? "prolog.compact" : "prolog"; + FILE *fi = fopen(fname,"r"); + char buf[1024]; + + if (fi==NULL) { + perror(fname); + exit(1); + } + while (fgets(buf,1024,fi)) fputs(buf,stdout); + fclose(fi); +} + +#else /* XPROLOG */ +/* postscript "programs" to unpack and print the bitmaps being sent */ + +char *ps_prolog_compact[] = { + "%%Pages: 1", + "%%EndProlog", + "%%Page: 1 1", + "", + "/bitgen", + " {", + " /nextpos 0 def", + " currentfile bufspace readhexstring pop % get a chunk of input", + " % interpret each byte of the input", + " {", + " flag { % if the previous byte was FF", + " /len exch def % this byte is a count", + " result", + " nextpos", + " FFstring 0 len getinterval % grap a chunk of FF's", + " putinterval % and stuff them into the result", + " /nextpos nextpos len add def", + " /flag false def", + " }{ % otherwise", + " dup 255 eq { % if this byte is FF", + " /flag true def % just set the flag", + " pop % and toss the FF", + " }{ % otherwise", + " % move this byte to the result", + " result nextpos", + " 3 -1 roll % roll the current byte back to the top", + " put", + " /nextpos nextpos 1 add def", + " } ifelse", + " } ifelse", + " } forall", + " % trim unused space from end of result", + " result 0 nextpos getinterval", + " } def", + "", + "", + "/bitdump % stk: width, height, iscale", + " % dump a bit image with lower left corner at current origin,", + " % scaling by iscale (iscale=1 means 1/300 inch per pixel)", + " {", + " % read arguments", + " /iscale exch def", + " /height exch def", + " /width exch def", + "", + " % scale appropriately", + " width iscale mul height iscale mul scale", + "", + " % data structures:", + "", + " % allocate space for one line of input", + " /bufspace 36 string def", + "", + " % string of FF's", + " /FFstring 256 string def", + " % for all i FFstring[i]=255", + " 0 1 255 { FFstring exch 255 put } for", + "", + " % 'escape' flag", + " /flag false def", + "", + " % space for a chunk of generated bits", + " /result 4590 string def", + "", + " % read and dump the image", + " width height 1 [width 0 0 height neg 0 height]", + " { bitgen }", + " image", + " } def", + 0 +}; + +char *ps_prolog[] = { + "%%Pages: 1", + "%%EndProlog", + "%%Page: 1 1", + "", + "/bitdump % stk: width, height, iscale", + "% dump a bit image with lower left corner at current origin,", + "% scaling by iscale (iscale=1 means 1/300 inch per pixel)", + "{", + " % read arguments", + " /iscale exch def", + " /height exch def", + " /width exch def", + "", + " % scale appropriately", + " width iscale mul height iscale mul scale", + "", + " % allocate space for one scanline of input", + " /picstr % picstr holds one scan line", + " width 7 add 8 idiv % width of image in bytes = ceiling(width/8)", + " string", + " def", + "", + " % read and dump the image", + " width height 1 [width 0 0 height neg 0 height]", + " { currentfile picstr readhexstring pop }", + " image", + "} def", + 0 +}; + +dump_prolog(flags) { + char **p = (flags & F_COMPACT) ? ps_prolog_compact : ps_prolog; + while (*p) printf("%s\n",*p++); +} +#endif /* XPROLOG */ + +#define PAPER_WIDTH 85*30 /* 8.5 inches */ +#define PAPER_LENGTH 11*300 /* 11 inches */ + +static int +points(n) +{ + /* scale n from pixels (1/300 inch) to points (1/72 inch) */ + n *= 72; + return n/300; +} + +static char * +escape(s) +char *s; +{ + /* make a version of s in which control characters are deleted and + * special characters are escaped. + */ + static char buf[200]; + char *p = buf; + + for (;*s;s++) { + if (*s < ' ' || *s > 0176) continue; + if (*s==')' || *s=='(' || *s == '\\') { + sprintf(p,"\\%03o",*s); + p += 4; + } + else *p++ = *s; + } + *p = 0; + return buf; +} + +ps_setup(iw, ih, orientation, scale, left, top, + flags, header, trailer, name) +int iw; +int ih; +enum orientation orientation; +int scale; +int left; +int top; +int flags; +char *header; +char *trailer; +char *name; +{ + char hostname[256]; +#ifdef WIN32 + char *username; +#else + struct passwd *pswd; +#endif + long clock; + int lm, bm; /* left (bottom) margin */ + + /* calculate margins */ + if (orientation==PORTRAIT) { + lm = (left > 0)? left : ((PAPER_WIDTH - scale * iw) / 2); + bm = (top > 0)? (PAPER_LENGTH - top - scale * ih) + : ((PAPER_LENGTH - scale * ih) / 2); + } else { /* orientation == LANDSCAPE */ + lm = (top > 0)? (PAPER_WIDTH - top - scale * ih) + : ((PAPER_WIDTH - scale * ih) / 2); + bm = (left > 0)? (PAPER_LENGTH - left - scale * iw) + : ((PAPER_LENGTH - scale * iw) / 2); + } + printf ("%%!%s\n", COMMENTVERSION); + printf ("%%%%BoundingBox: %d %d %d %d\n", + (flags & F_NPOSITION) ? points(lm) : 0, + (flags & F_NPOSITION) ? points(bm) : 0, + points(iw * scale), points(ih * scale)); + (void) XmuGetHostname (hostname, sizeof hostname); +#ifdef WIN32 + username = getenv("USERNAME"); + printf ("%%%%Creator: %s:%s\n", hostname, + username ? username : "unknown"); +#else + pswd = getpwuid (getuid ()); + printf ("%%%%Creator: %s:%s (%s)\n", hostname, + pswd->pw_name, pswd->pw_gecos); +#endif + printf ("%%%%Title: %s (%s)\n", infilename,name); + printf ("%%%%CreationDate: %s", + (time (&clock), ctime (&clock))); + printf ("%%%%EndComments\n"); + + dump_prolog(flags); + + if (orientation==PORTRAIT) { + if (header || trailer) { + printf("gsave\n"); + printf("/Times-Roman findfont 15 scalefont setfont\n"); + /* origin at bottom left corner of image */ + printf("%d %d translate\n",points(lm),points(bm)); + if (header) { + char *label = escape(header); + printf("%d (%s) stringwidth pop sub 2 div %d moveto\n", + points(iw*scale), label, points(ih*scale) + 10); + printf("(%s) show\n",label); + } + if (trailer) { + char *label = escape(trailer); + printf("%d (%s) stringwidth pop sub 2 div -20 moveto\n", + points(iw*scale), label); + printf("(%s) show\n",label); + } + printf("grestore\n"); + } + /* set resolution to device units (300/inch) */ + printf("72 300 div dup scale\n"); + /* move to lower left corner of image */ + if (!(flags & F_NPOSITION)) + printf("%d %d translate\n",lm,bm); + /* dump the bitmap */ + printf("%d %d %d bitdump\n",iw,ih,scale); + } else { /* orientation == LANDSCAPE */ + if (header || trailer) { + printf("gsave\n"); + printf("/Times-Roman findfont 15 scalefont setfont\n"); + /* origin at top left corner of image */ + printf("%d %d translate\n",points(lm),points(bm + scale * iw)); + /* rotate to print the titles */ + printf("-90 rotate\n"); + if (header) { + char *label = escape(header); + printf("%d (%s) stringwidth pop sub 2 div %d moveto\n", + points(iw*scale), label, points(ih*scale) + 10); + printf("(%s) show\n",label); + } + if (trailer) { + char *label = escape(trailer); + printf("%d (%s) stringwidth pop sub 2 div -20 moveto\n", + points(iw*scale), label); + printf("(%s) show\n",label); + } + printf("grestore\n"); + } + /* set resolution to device units (300/inch) */ + printf("72 300 div dup scale\n"); + /* move to lower left corner of image */ + if (!(flags & F_NPOSITION)) + printf("%d %d translate\n",lm,bm); + /* dump the bitmap */ + printf("%d %d %d bitdump\n",ih,iw,scale); + } +} + +char *ps_epilog[] = { + "", + "showpage", + "%%Trailer", + 0 +}; + +ps_finish() +{ + char **p = ps_epilog; + + while (*p) printf("%s\n",*p++); +} + +ln03_alter_background(sixmap, iw, ih) +unsigned char (*sixmap)[]; +int iw; +int ih; +{ + register unsigned char *c, *stopc; + register unsigned char *startc; + register int n; + + c = (unsigned char *)sixmap; + stopc = c + (iw * ih); + n = 0; + while (c < stopc) { + switch (*c) { + case 0x08: case 0x11: case 0x04: case 0x22: + case 0x20: case 0x21: case 0x24: case 0x00: + if (n == 0) startc = c; + n++; + break; + + default: + if (n >= 2) { + while (n-- > 0) *startc++ = 0x00; + } else { + n = 0; + } + break; + } + c++; + } +} + +ln03_output_sixels(sixmap, iw, ih, nosixopt, split, scale, top_margin, + left_margin) +unsigned char (*sixmap)[]; +int iw; +int ih; +int nosixopt; +int split; +int top_margin; +int left_margin; +{ + unsigned char *buf; + register unsigned char *bp; + int i; + int j; + register int k; + register unsigned char *c; + register int lastc; + register int count; + char snum[6]; + register char *snp; + + bp = (unsigned char *)malloc((unsigned)(iw*ih+512)); + buf = bp; + count = 0; + lastc = -1; + c = (unsigned char *)sixmap; + split = ih / split; /* number of lines per page */ + + iw--; /* optimization */ + for (i = 0; i < ih; i++) { + for (j = 0; j <= iw; j++) { + if (!nosixopt) { + if (*c == lastc && j < iw) { + count++; + c++; + continue; + } + if (count >= 3) { + bp--; + count++; + *bp++ = '!'; + snp = snum; + while (count > 0) { + k = count / 10; + *snp++ = count - (k * 10) + '0'; + count = k; + } + while (--snp >= snum) *bp++ = *snp; + *bp++ = (~lastc & 0x3F) + 0x3F; + } else if (count > 0) { + lastc = (~lastc & 0x3F) + 0x3F; + do { + *bp++ = lastc; + } while (--count > 0); + } + } + lastc = *c++; + *bp++ = (~lastc & 0x3F) + 0x3F; + } + *bp++ = '-'; /* New line */ + lastc = -1; + if ((i % split) == 0 && i != 0) { + sprintf((char *)bp, LN_ST); bp += sizeof LN_ST - 1; + *bp++ = '\f'; + sprintf((char *)bp, LN_VPA, top_margin + (i * 6 * scale)); + bp += strlen((char *)bp); + sprintf((char *)bp, LN_HPA, left_margin); + bp += strlen((char *)bp); + sprintf((char *)bp, LN_SIXEL_GRAPHICS, 9, 0, scale); + bp += strlen((char *)bp); + sprintf((char *)bp, "\"1;1"); bp += 4; + } + } + + sprintf((char *)bp, LN_ST); bp += sizeof LN_ST - 1; + write(1, (char *)buf, bp-buf); +} + +/*ARGSUSED*/ +la100_output_sixels(sixmap, iw, ih, nosixopt) +unsigned char (*sixmap)[]; +int iw; +int ih; +int nosixopt; +{ + unsigned char *buf; + register unsigned char *bp; + int i; + register int j, k; + register unsigned char *c; + register int lastc; + register int count; + char snum[6]; + + bp = (unsigned char *)malloc((unsigned)(iw*ih+512)); + buf = bp; + count = 0; + lastc = -1; + c = (unsigned char *)sixmap; + + for (i = 0; i < ih; i++) { + for (j = 0; j < iw; j++) { + if (*c == lastc && (j+1) < iw) { + count++; + c++; + continue; + } + if (count >= 2) { + bp -= 2; + count = 2 * (count + 1); + *bp++ = '!'; + k = 0; + while (count > 0) { + snum[k++] = (count % 10) + '0'; + count /= 10; + } + while (--k >= 0) *bp++ = snum[k]; + *bp++ = (~lastc & 0x3F) + 0x3F; + count = 0; + } else if (count > 0) { + lastc = (~lastc & 0x3F) + 0x3F; + do { + *bp++ = lastc; + *bp++ = lastc; + } while (--count > 0); + } + lastc = (~*c & 0x3F) + 0x3F; + *bp++ = lastc; + *bp++ = lastc; + lastc = *c++; + } + *bp++ = '-'; /* New line */ + lastc = -1; + } + + sprintf((char *)bp, LN_ST); bp += sizeof LN_ST - 1; + *bp++ = '\f'; + write(1, (char *)buf, bp-buf); +} + +#define LINELEN 72 /* number of CHARS (bytes*2) per line of bitmap output */ + +ps_output_bits(iw, ih, flags, orientation, win, data) +int iw; +int ih; +int flags; +XWDFileHeader *win; +enum orientation orientation; +char *data; +{ + unsigned long swaptest = 1; + int iwb = win->bytes_per_line; + register int i; + int bytes; + unsigned char *buffer = (unsigned char *)data; + register int ocount=0; + extern char hex1[],hex2[]; + static char hex[] = "0123456789abcdef"; + + if (orientation == LANDSCAPE) { + /* read in and rotate the entire image */ + /* The Postscript language has a rotate operator, but using it + * seem to make printing (at least on the Apple Laserwriter + * take about 10 times as long (40 minutes for a 1024x864 full-screen + * dump)! Therefore, we rotate the image here. + */ + int ocol = ih; + int owidth = (ih+31)/32; /* width of rotated image, in bytes */ + int oheight = (iw+31)/32; /* height of rotated image, in scanlines */ + register char *p, *q; + char *obuf; + unsigned char *ibuf; + owidth *= 4; + oheight *= 32; + + /* Allocate buffer for the entire rotated image (output). + * Owidth and Oheight are rounded up to a multiple of 32 bits, + * to avoid special cases at the boundaries + */ + obuf = malloc((unsigned)(owidth*oheight)); + if (obuf==0) { + fprintf(stderr,"xpr: cannot allocate %d bytes\n",owidth*oheight); + exit(1); + } + bzero(obuf,owidth*oheight); + + ibuf = (unsigned char *)malloc((unsigned)(iwb + 3)); + for (i=0;i 0); + +} + +/* copied from lib/X/XPutImage.c */ + +_swapbits (b, n) + register unsigned char *b; + register long n; +{ + do { + *b = _reverse_byte[*b]; + b++; + } while (--n > 0); + +} + +_swapshort (bp, n) + register char *bp; + register long n; +{ + register char c; + register char *ep = bp + n; + do { + c = *bp; + *bp = *(bp + 1); + bp++; + *bp = c; + bp++; + } + while (bp < ep); +} + +_swaplong (bp, n) + register char *bp; + register long n; +{ + register char c; + register char *ep = bp + n; + register char *sp; + do { + sp = bp + 3; + c = *sp; + *sp = *bp; + *bp++ = c; + sp = bp + 1; + c = *sp; + *sp = *bp; + *bp++ = c; + bp += 2; + } + while (bp < ep); +} + +/* Dump some bytes in hex, with bits in each byte reversed + * Ocount is number of chacters that have been written to the current + * output line. It's new value is returned as the result of the function. + * Ocount is ignored (and the return value is meaningless) if compact==0. + */ +int +ps_putbuf(s, n, ocount, compact) +register unsigned char *s; /* buffer to dump */ +register int n; /* number of BITS to dump */ +register int ocount; /* position on output line for next char */ +int compact; /* if non-zero, do compaction (see below) */ +{ + register int ffcount = 0; + extern char hex1[],hex2[]; + static char hex[] = "0123456789abcdef"; +#define PUT(c) { putchar(c); if (++ocount>=LINELEN) \ + { putchar('\n'); ocount=0; }} + + if (compact) { + /* The following loop puts out the bits of the image in hex, + * compressing runs of white space (represented by one bits) + * according the the following simple algorithm: A run of n + * 'ff' bytes (i.e., bytes with value 255--all ones), where + * 1<=n<=255, is represented by a single 'ff' byte followed by a + * byte containing n. + * On a typical dump of a full screen pretty much covered by + * black-on-white text windows, this compression decreased the + * size of the file from 223 Kbytes to 63 Kbytes. + * Of course, another factor of two could be saved by sending + * the bytes 'as is' rather than in hex, using some sort of + * escape convention to avoid problems with control characters. + * Another popular encoding is to pack three bytes into 4 'sixels' + * as in the LN03, etc, but I'm too lazy to write the necessary + * PostScript code to unpack fancier representations. + */ + while (n--) { + if (*s == 0xff) { + if (++ffcount == 255) { + PUT('f'); PUT('f'); + PUT('f'); PUT('f'); + ffcount = 0; + } + } + else { + if (ffcount) { + PUT('f'); PUT('f'); + PUT(hex[ffcount >> 4]); + PUT(hex[ffcount & 0xf]); + ffcount = 0; + } + PUT(hex1[*s]); + PUT(hex2[*s]); + } + s++; + } + if (ffcount) { + PUT('f'); PUT('f'); + PUT(hex[ffcount >> 4]); + PUT(hex[ffcount & 0xf]); + ffcount = 0; + } + } + else { /* no compaction: just dump the image in hex (bits reversed) */ + while (n--) { + putchar(hex1[*s]); + putchar(hex2[*s++]); + } + putchar('\n'); + } + return ocount; +} + +ps_bitrot(s,n,col,owidth,obuf) +unsigned char *s; +register int n; +int col; +register int owidth; +char *obuf; +/* s points to a chunk of memory and n is its width in bits. + * The algorithm is, roughly, + * for (i=0;i=0) { + if (--b < 0) { + iword = *iwordp++; + b = 31; + } + if (iword & 1) { + *(int *)opos |= mask; + } + opos += owidth; + iword >>= 1; + } +} + +/* fullread() is the same as read(), except that it guarantees to + read all the bytes requested. */ + +fullread (file, data, nbytes) + int file; + char *data; + int nbytes; + { + int bytes_read; + while ((bytes_read = read(file, data, nbytes)) != nbytes) { + if (bytes_read < 0) { + perror ("error while reading standard input"); + return; + } + else if (bytes_read == 0) { + fprintf (stderr, "xpr: premature end of file\n"); + return; + } + nbytes -= bytes_read; + data += bytes_read; + } + } + +/* mapping tables to map a byte in to the hex representation of its + * bit-reversal + */ +char hex1[]="084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f\ +084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f\ +084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f\ +084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f"; + +char hex2[]="000000000000000088888888888888884444444444444444cccccccccccccccc\ +2222222222222222aaaaaaaaaaaaaaaa6666666666666666eeeeeeeeeeeeeeee\ +111111111111111199999999999999995555555555555555dddddddddddddddd\ +3333333333333333bbbbbbbbbbbbbbbb7777777777777777ffffffffffffffff"; + Index: xc/programs/xpr/xpr.h =================================================================== RCS file: xc/programs/xpr/xpr.h diff -N xc/programs/xpr/xpr.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/xpr.h 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,33 @@ +#ifndef X_NOT_STDC_ENV +#include +#else +char *malloc(), *realloc(), *calloc(); +#endif +#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ +char *malloc(), *realloc(), *calloc(); +#endif /* macII */ + +/* 3812 PagePrinter macros */ +#define PPI 240 +#define inch2pel(inches) ((int) ((inches) * PPI)) +#define DEFAULT_WIDTH 8.5 +#define X_MAX_PELS inch2pel(DEFAULT_WIDTH) +#define DEFAULT_LENGTH 11 +#define Y_MAX_PELS inch2pel(DEFAULT_LENGTH) + +#define INTENSITY(color) (30L*(int)(color)->red + \ + 59L*(int)(color)->green + \ + 11L*(int)(color)->blue) + +#define INTENSITYPER(per) (((1<<16)-1)*((long)per)) +#define HALFINTENSITY INTENSITYPER(50) + +enum orientation { + UNSPECIFIED = -1, + PORTRAIT = 0, + LANDSCAPE = 1, + UPSIDE_DOWN = 2, + LANDSCAPE_LEFT = 3 + }; + +enum device {LN01, LN03, LA100, PS, PP, LJET, PJET, PJETXL}; Index: xc/programs/xpr/xpr.man =================================================================== RCS file: xc/programs/xpr/xpr.man diff -N xc/programs/xpr/xpr.man --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ xc/programs/xpr/xpr.man 31 Oct 2004 02:09:20 -0000 @@ -0,0 +1,338 @@ +.\" $XConsortium: xpr.man,v 1.22 94/04/17 20:44:06 gildea Exp $ +.TH XPR 1 "Release 6" "X Version 11" +.SH NAME +xpr \- print an X window dump +.SH SYNOPSIS +.B xpr +[ +.B \-device +.I devtype +] [ +.B \-scale +.I scale +] [ +.B \-height +.I inches +] [ +.B \-width +.I inches +] [ +.B \-left +.I inches +] [ +.B \-top +.I inches +] [ +.B \-header +.I string +] [ +.B \-trailer +.I string +] [ +.B \-landscape +] [ +.B \-portrait +] [ +.B \-plane +.I number +] [ +.B \-gray +] [ +.B \-rv +] [ +.B \-compact +] [ +.B \-output +.I filename +] [ +.B \-append +.I filename +] [ +.B \-noff +] [ +.B \-split +.I n +] [ +.B \-psfig +] [ +.B \-density +.I dpi +] [ +.B \-cutoff +.I level +] [ +.B \-noposition +] [ +.B \-gamma +.I correction +] [ +.B \-render +.I algorithm +] [ +.B \-slide +] [ +.I filename +] +.SH DESCRIPTION + +.I xpr +takes as input a window dump file produced by +.IR xwd(1) +and formats it for output on PostScript printers, the Digital LN03 or LA100, +the IBM PP3812 page printer, the HP LaserJet (or other PCL printers), +or the HP PaintJet. If no file +argument is given, the standard input is used. By default, \fIxpr\fP +prints the largest possible representation of the window on the +output page. Options allow the user to add headers and trailers, +specify margins, adjust the scale and orientation, and append +multiple window dumps to a single output file. Output is to +standard output unless +.B \-output +is specified. +.sp 1 +.ne 8 +.B Command Options +.sp 1 +.IP "\fB\-device\fP \fIdevtype\fP" +Specifies the device on which the file will be printed. Currently supported: +.RS 12 +.PD 0 +.TP +.B la100 +Digital LA100 +.TP +.B ljet +\s-1HP\s+1 LaserJet series and other monochrome PCL devices +such as ThinkJet, QuietJet, RuggedWriter, \s-1HP\s+12560 series, +and \s-1HP\s+12930 series printers +.TP +.B ln03 +Digital LN03 +.TP +.B pjet +HP PaintJet (color mode) +.TP +.B pjetxl +HP HP PaintJet XL Color Graphics Printer (color mode) +.TP +.B pp +IBM PP3812 +.TP +.B ps +PostScript printer +.PD +.RE +.IP +The default is PostScript. +\fB-device lw\fP (LaserWriter) is equivalent to -device ps and is +provided only for backwards compatibility. +.IP "\fB\-scale\fP \fIscale\fP" +Affects the size of the window on the page. The PostScript, LN03, and HP +printers are able to +translate each bit in a window pixel map into a grid of a specified size. +For example each bit might translate into a 3x3 grid. This would be +specified by \fB\-scale\fP \fI3\fP. By default a window is printed +with the largest scale that will fit onto the page for the specified +orientation. +.IP "\fB\-height\fP \fIinches\fP" +Specifies the maximum height of the page. +.IP "\fB\-width\fP \fIinches\fP" +Specifies the maximum width of the page. +.IP "\fB\-left\fP \fIinches\fP" +Specifies the left margin in inches. Fractions +are allowed. By default the window is centered in the page. +.IP "\fB\-top\fP \fIinches\fP" +Specifies the top margin for the picture in inches. Fractions are +allowed. +.IP "\fB\-header\fP \fIstring\fP" +Specifies a header string to be printed above the window. +.IP "\fB\-trailer\fP \fIstring\fP" +Specifies a trailer string to be printed below the window. +.IP "\fB\-landscape\fP" +Forces the window to printed in landscape mode. By default +a window is printed such that its longest side follows the long side of +the paper. +.IP "\fB\-plane\fP \fInumber\fP" +Specifies which bit plane to use in an image. The default is to use the +entire image and map values into black and white based on color intensities. +.IP "\fB\-gray\fP \fI 2 | 3 | 4\fP" +Uses a simple 2x2, 3x3, or 4x4 gray scale conversion on a color image, +rather than mapping to strictly black and white. This doubles, +triples, or quadruples the effective width and height of the image. +.IP "\fB\-portrait\fP" +Forces the window to be printed in portrait mode. By default +a window is printed such that its longest side follows the long side of +the paper. +.IP "\fB\-rv\fP" +Forces the window to be printed in reverse video. +.IP "\fB\-compact\fP" +Uses simple run-length encoding for compact representation of windows +with lots of white pixels. +.IP "\fB\-output\fP \fIfilename\fP" +Specifies an output file name. If this option is not specified, standard +output is used. +.IP "\fB\-append\fP \fIfilename\fP" +Specifies a filename previously produced by \fIxpr\fP to which the window +is to be appended. +.IP "\fB\-noff\fP" +When specified in conjunction with \fB\-append\fP, the window will appear +on the same page as the previous window. +.IP "\fB\-split\fP \fIn\fP" +This option allows the user to split a window onto several pages. +This might be necessary for very large windows that would otherwise +cause the printer to overload and print the page in an obscure manner. +.IP "\fB\-psfig\fP" +Suppress translation of the PostScript picture to the center of the page. +.IP "\fB\-density\fP \fIdpi\fP" +Indicates what dot-per-inch density should be used by the HP printer. +.IP "\fB\-cutoff\fP \fIlevel\fP" +Changes the intensity level where colors are mapped to either black or +white for monochrome output on a LaserJet printer. +The \fIlevel\fP is expressed as percentage of +full brightness. Fractions are allowed. +.IP "\fB\-noposition\fP" +This option causes header, trailer, and image positioning command +generation to be bypassed for LaserJet, PaintJet and +PaintJet XL printers. +.IP "\fB\-gamma\fP \fIcorrection\fP" +This changes the intensity of the colors printed by +PaintJet XL printer. The \fIcorrection\fP is +a floating point value in the range 0.00 to 3.00. +Consult the operator's manual to determine the correct value for +the specific printer. +.IP "\fB\-render\fP \fIalgorithm\fP" +This allows PaintJet XL printer to render the +image with the best quality versus performance tradeoff. +Consult the operator's manual to determine which \fIalgorithm\fPs +are available. +.IP "\fB\-slide\fP" +This option allows overhead transparencies to be printed +using the PaintJet and PaintJet XL printers. + +.SH SEE ALSO +xwd(1), xwud(1), X(1) +.SH LIMITATIONS + +The current version of \fIxpr\fP can generally print out on the LN03 +most X windows that are not larger than two-thirds of the screen. +For example, it will be able to print out a large Emacs window, but +it will usually fail when trying to print out the entire screen. The +LN03 has memory limitations that can cause it to incorrectly print +very large or complex windows. The two most common errors +encountered are ``band too complex'' and ``page memory exceeded.'' +In the first case, a window may have a particular six pixel row that +contains too many changes (from black to white to black). This will +cause the printer to drop part of the line and possibly parts of the +rest of the page. The printer will flash the number `1' on its front +panel when this problem occurs. A possible solution to this problem +is to increase the scale of the picture, or to split the picture onto +two or more pages. The second problem, ``page memory exceeded,'' +will occur if the picture contains too much black, or if the picture +contains complex half-tones such as the background color of a +display. When this problem occurs the printer will automatically +split the picture into two or more pages. It may flash the number +`5' on its from panel. There is no easy solution to this problem. +It will probably be necessary to either cut and paste, or to rework the +application to produce a less complex picture. + +There are several limitations on the LA100 support: +the picture will always be printed in +portrait mode, there is no scaling, +and the aspect ratio will be slightly off. + +Support for PostScript output currently cannot handle the \fB-append\fP, +\fB-noff\fP or \fB-split\fP options. + +The \fB-compact\fP option is +.I only +supported for PostScript output. +It compresses white space but not black space, so it is not useful for +reverse-video windows. + +For color images, should map directly to PostScript image support. + +.SH "HP PRINTERS" + +If no \fB\-density\fP is specified on the command line 300 dots per inch +will be assumed for \fIljet\fP and 90 dots per inch for \fIpjet\fP. +Allowable \fIdensity\fP values for a LaserJet printer are 300, 150, 100, +and 75 dots per inch. Consult the operator's manual to determine densities +supported by other printers. + +If no \fB\-scale\fP is specified the image will be expanded to fit the +printable page area. + +The default printable page area is 8x10.5 inches. Other paper sizes can +be accommodated using the \fB\-height\fP and \fB\-width\fP options. + +Note that a 1024x768 image fits the default printable area when processed +at 100 dpi with scale=1, the same image can also be printed using 300 dpi +with scale=3 but will require considerably more data be transferred to the +printer. + +\fIxpr\fP may be tailored for use with monochrome PCL printers other than +the LaserJet. To print on a ThinkJet (\s-1HP\s+12225A) \fIxpr\fP could be +invoked as: +.sp +.RS 4 +xpr -density 96 -width 6.667 \fIfilename\fP +.RE +.sp +or for black-and-white output to a PaintJet: +.sp +.RS 4 +xpr -density 180 \fIfilename\fP +.RE + +The monochrome intensity of a pixel is computed as 0.30*R + 0.59*G ++ 0.11*B. +If a pixel's computed intensity is less than the \fB\-cutoff\fP +level it will print as white. This maps light-on-dark display images +to black-on-white hardcopy. The default cutoff intensity is 50% of full +brightness. Example: specifying \fB\-cutoff 87.5\fP moves the +white/black intensity point to 87.5% of full brightness. + +A LaserJet printer must be configured with sufficient memory to handle the +image. For a full page at 300 dots per inch approximately 2MB of printer +memory is required. + +Color images are produced on the PaintJet +at 90 dots per inch. The +PaintJet is limited to sixteen colors from its 330 color palette on each +horizontal print line. \fIxpr\fP will issue a warning message if more than +sixteen colors are encountered on a line. \fIxpr\fP will program the +PaintJet for the first sixteen colors encountered on each line and use the +nearest matching programmed value for other colors present on the line. + +Specifying the \fB\-rv\fP, reverse video, option for the PaintJet will +cause black and white to be interchanged on the output image. No other +colors are changed. + +Multiplane images must be recorded by \fIxwd\fP in \fIZPixmap\fP format. +Single plane (monochrome) images may be in either \fIXYPixmap\fP or +\fIZPixmap\fP format. + +Some PCL printers do not recognize image positioning commands. Output for +these printers will not be centered on the page and header and trailer +strings may not appear where expected. + +The \fB\-gamma\fP and \fB-render\fP options are supported only on +the PaintJet XL printers. + +The \fB\-slide\fP option is not supported for LaserJet printers. + +The \fB\-split\fP option is not supported for HP printers. + +The \fB\-gray\fP option is not supported for HP or IBM printers. +.br +Copyright 1986, Marvin Solomon and the University of Wisconsin. +.br +Copyright 1988, Hewlett Packard Company. +.br +See \fIX(1)\fP for a full statement of rights and permissions. +.SH AUTHORS +Michael R. Gretzinger, MIT Project Athena, +Jose Capo, MIT Project Athena (PP3812 support), +Marvin Solomon, University of Wisconsin, +Bob Scheifler, MIT, Angela Bock and E. Mike Durbin, Rich Inc. (grayscale), +Larry Rupp, HP (HP printer support).