[comp.sources.misc] pshalf - print PostScript pages two to a page

denise@cwi.nl.UUCP (Denise L. Draper) (08/22/87)

pshalf takes PostScript input generates PostScript output with
two input pages (rotated and approximately half size) to every 
output page.

Also included is a fix to TranScript(tm) psdit.

Enjoy,

Denise Draper		**DEI**			 denise@cwi.nl
Centrum voor Wiskunde en Informatica	..!seismo!mcvax!denise
--------------------------------------------------------------
#!/bin/sh
#
# This is a shar file.
# Cut off everything above the /bin/sh line.
# The rest of this file will extract:
#
# README Makefile pshalf.proto pshalf.ps pshalf.1.proto diffs.psdit squeeze.c
#
PATH=/bin:/usr/bin
echo "extracting: README (1168 bytes)"
if [ -s README ]
then
  echo will not overwrite README 1>&2
else
  sed -e 's/^X//' > README <<'!End-Of-README!'
X==
X== pshalf -- produce PostScript pages two to a (paper) page
X==
X
XTo make, set the variables in the Makefile, and make all.  To install,
Xmake install.  I install the postscript file pshalf.ps as well as the
Xshell script because it can be quite useful in its own right -- as a
Xtemplate for other programs, if nothing else.
X
XAs noted in the manual page, pshalf will not work with output produced
Xfrom standard Adobe psdit, because psdit does not obey the structuring
Xconventions -- it does not produce conforming PostScript.  (And naturally, 
Xpsroff was the first thing I tried to test pshalf with -- it took me a 
Xwhile to realize what was going on, arrgh!) The file diffs.psdit contains 
Xthe fixes to psdit and psdit.pro needed to make conforming output -- it 
Xreally was a fairly simple fix.
X
XThe included program squeeze is copywrited by Tomas Rokicki
X(rokicki@sushi.stanford.edu).  The rest is by me.  I make no restrictions 
Xon its use or reuse or modifications, or whathaveyou, but I would appreciate 
Xit if 1) my name stayed attached, and 2) improvements, bug fixes, etc., 
Xare sent to me.
X
XDenise Draper			 denise@cwi.nl
XCWI, Amsterdam		..!seismo!mcvax!denise
!End-Of-README!
fi
echo -n extracted: 
ls -l README | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
echo "extracting: Makefile (796 bytes)"
if [ -s Makefile ]
then
  echo will not overwrite Makefile 1>&2
else
  sed -e 's/^X//' > Makefile <<'!End-Of-Makefile!'
X#
X# Makefile for pshalf
X#
X# home for pshalf
XBINDIR=/usr/local
X#
X# home for pshalf.ps 
XPSDIR=/usr/local/lib/postscript
X#
XMANDIR=/usr/man/manl
XMANEXT=l
X
Xall:		pshalf pshalf.1
X
Xpshalf: 	pshalf.ps pshalf.proto squeeze
X		squeeze < pshalf.ps | sed -e '1d' -e 's/\(.*\)/print "\1"/' > tmp
X		sed -e '/PROLOG/r tmp' -e '/PROLOG/d' < pshalf.proto > pshalf
X		rm tmp
X		chmod +x pshalf
X
Xpshalf.1:	pshalf.1.proto Makefile
X		sed -e "s;PSDIR;$(PSDIR);" < pshalf.1.proto > pshalf.1
X
Xsqueeze:	squeeze.c
X		cc -O squeeze.c -o squeeze
X
Xinstall:	all
X		install -c pshalf $(BINDIR)
X		install -c pshalf.ps $(PSDIR)
X		install -c pshalf.1 $(MANDIR)/pshalf.$(MANEXT)
X
Xshar:		
X		shar README Makefile pshalf.proto pshalf.ps pshalf.1.proto \
X			diffs.psdit squeeze.c > sharfile
X
Xclean:
X		rm -f sharfile pshalf pshalf.1 squeeze
!End-Of-Makefile!
fi
echo -n extracted: 
ls -l Makefile | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
echo "extracting: pshalf.proto (1169 bytes)"
if [ -s pshalf.proto ]
then
  echo will not overwrite pshalf.proto 1>&2
else
  sed -e 's/^X//' > pshalf.proto <<'!End-Of-pshalf.proto!'
X#!/bin/sh
X#
X# pshalf <files>
X#
X# Make Postscript output two pages to a page (rotated, approx 1/2 size).
X#
X# reads stdin or files, writes stdout.  Takes miminally conforming PostScript 
X# input and produces minimally conforming PostScript output.
X#
X# Caveat: the output has mungled around with the showpage operator, which
X# means that it cannot be used as input to any other program that must
X# capture the showpage operator (for example psdraft, or pshalf itself).
X#
X# Written by Denise Draper	denise@cwi.nl
X#
X
Xawk '
XBEGIN			{ firsthalf = 1; outpages = 0 }
X/^%%Pages:/		{ next }
X/^%%PageFonts:/		{ next }
X/^%%Page:/		{ if( firsthalf ) {
X				if( outpages != 0 )
X					print "HfDict begin ep end"
X				print "%%Page: ? " ++outpages
X				print "HfDict begin bp end"
X			  } else {
X				print "HfDict begin hp end"
X			  }
X			  firsthalf = 1 - firsthalf
X			  next
X			}
X/^%%EndProlog/		{ 
Xprint "% --Pshalf, by Denise Draper--"
XPROLOG
Xprint "% --End Pshalf--"
Xprint "%%Pages: (atend)"
Xprint "%%EndProlog"
X			  next
X			}
X/^%%Trailer/		{ if( outpages != 0 )
X				print "HfDict begin ep end"
X			  print "%%Trailer"
X			  print "%%Pages: " outpages
X			  next
X			}
X			{ print $0 } ' $@
!End-Of-pshalf.proto!
fi
echo -n extracted: 
ls -l pshalf.proto | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
echo "extracting: pshalf.ps (3125 bytes)"
if [ -s pshalf.ps ]
then
  echo will not overwrite pshalf.ps 1>&2
else
  sed -e 's/^X//' > pshalf.ps <<'!End-Of-pshalf.ps!'
X%!
X%   pshalf - put postscript page descriptions, two to a page (rotated,
X%   and approx half size).
X%
X%   Include this prolog (after any other prologs), and surround page 
X%   descriptions with the calls:
X%
X%   HfDict begin bp end
X%	... 1st page description
X%   HfDict begin hp end
X%	... 2nd page description
X%   HfDict begin ep end
X%   HfDict begin bp end
X%	... 3rd page description
X%   etc.
X%
X%   The 2nd half of the page may be skipped by leaving out hp,
X%   and the first half skipped by `Hfdict begin bp hp end'
X%
X%   CAVEAT(S): This will (probably) not work if the input pages redefine 
X%   showpage. The graphics should always work if the input pages are 
X%   contained entirely between bp and ep pairs.  If, however, there is a 
X%   prolog outside of this, then any paths defined in the prolog remain
X%   in `prolog coordinates'.  If a clipping path is defined in the prolog,
X%   it is ignored entirely.
X%
X%   Written by Denise Draper		denise@cwi.nl
X
X					% Make our own dict, to minimize name 
X/HfDict 20 dict def			% space conflict.
XHfDict begin 				% (We must simply hope that the dict 
X					% name itself provides no conflict.)
X% 
X%  Create the needed transformation matrices
X 
Xgsave
X 
X%  If there is a prolog, there may be some global modification to the CTM.
X%  This is tricky since it is necessary that the order of modifications be
X%  theirmods(ourmods(default)  or, in matrix notation, TOD 
X
X/T					% find T
Xmatrix currentmatrix			% TD
Xmatrix defaultmatrix			% D    -1
Xmatrix invertmatrix			% --> D
Xmatrix concatmatrix			% --> T
Xdef
X
Xinitgraphics				% set CTM to D
Xclippath pathbbox			% get coordinates of edges, to define O
X/y2 exch def
X/x2 exch def
X/y1 exch def
X/x1 exch def
X
X/X x2 x1 sub def 			% define x and y page lengths
X/Y y2 y1 sub def
X					% Now modify D to create OD
X90 rotate 				% (draw pictures to understand)
X	% I think this is the correct translate, but it doesn't work right
X% y1 x1 sub x2 y1 add neg translate	% (y1-x1), -(x2+y1)
X	% this one works
Xy1 x1 sub   x2 neg translate
XX Y div     Y X 2 mul div scale		% X/Y, (Y/2)/X  -- maybe should be square?
Xmatrix currentmatrix /O1D exch def 	% matrix for 1st halfpage
X
XX 0 translate 				% (move over by (already scaled) page width)
Xmatrix currentmatrix /O2D exch def 	% matrix for 2nd halfpage
X
Xgrestore 				%---- end matrix calculations
X
X/nclip { 				% Make a default clipping path 
X  initclip newpath 			% (used in OD (e.g. halfpage) space)
X  x1 y1 moveto x1 y2 lineto 		%
X  x2 y2 lineto x2 y1 lineto		%
X  closepath clip newpath } def		%
X
X/bp {  					% BeginPage: starts a new real page 
X  gsave 				% input page goes to first halfpage
X  O1D setmatrix nclip 			%
X  T concat 				% now we have TOD
X} def					%
X
X/hp { 					% HalfPage: go to 2nd halfpage
X  grestore gsave			%
X  O2D setmatrix nclip 			%
X  T concat } def			%
X
X/ep { 					% EndPage: print the real, composite page
X  showpage grestore 			%
X} bind def 				% _bound_ to the _real_ showpage operator.
X
X%
X% In userdict, replace the definition of showpage, so that any
X% reference to showpage in the user's input doesn't have any effect.
X%
Xend					% HfDict
X/showpage /newpath load def
X
!End-Of-pshalf.ps!
fi
echo -n extracted: 
ls -l pshalf.ps | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
echo "extracting: pshalf.1.proto (1754 bytes)"
if [ -s pshalf.1.proto ]
then
  echo will not overwrite pshalf.1.proto 1>&2
else
  sed -e 's/^X//' > pshalf.1.proto <<'!End-Of-pshalf.1.proto!'
X.TH PSHALF 1 "1987" 
X.ds PS P\s-2OST\s+2S\s-2CRIPT\s+2
X.SH NAME
Xpshalf \- reduce size of \*(PS input
X.SH SYNOPSIS
X.B pshalf
X[
X.I files
X]
X.SH DESCRIPTION
X.I Pshalf
Xtakes (minimally conforming) \*(PS input and produces 
X(minimally conforming) \*(PS output, with two
Xinput pages mapped to each output page (each rotated and
Xapproximately half size).
XIf no 
X.I files
Xare specified, the standard input is used.
X.I Pshalf
Xwill usually be used as a filter after some other command
Xthat produces \*(PS output, for example:
X.IP
Xpsroff \-t \fI<other args>\fR | pshalf | lpr \-P\fI<\*(PSprinter>\fR
X.IP
Xenscript \-p \- \fI<other args>\fR | pshalf | lpr \-P\fI<\*(PSprinter>\fR
X.PP
X(with the \fB-r2\fR flag to enscript, this produces four-fold output,
Xwhich is actually still quite legible.)
X.SH CAVEAT
X.I Pshalf
Xchanges the
X.I showpage
Xprocedure in \*(PS.
XAs a result
X.I pshalf
Xcannot be used with any other program that must also
Xaffect the 
X.I showpage
Xprocedure, for example
X.IR psdraft (1),
Xor 
X.I pshalf
Xitself.
X.PP
X.I Pshalf
Xdoes not work with the standard version of
X.IR psroff (1),
Xbecause that version (actually
X.IR psdit )
Xdoes not obey the \*(PS structuring conventions.
X(On our system, this bug in
X.I
Xpsdit
Xhas been fixed.)
X.SH FILES
XPSDIR/pshalf.ps	The verbose version of the \*(PS program
X.SH "SEE ALSO"
Xenscript(1), psroff(1), psgrind(1)
X.SH AUTHOR
XDenise Draper \(em denise@cwi.nl
X.br
XCentrum voor Wiskunde en Informatica, Amsterdam
X.SH BUGS
XIf the input \*(PS program establishes paths in its prolog,
Xthese paths will remain in the original (unrotated, unshrunk)
Xcoordinate system.  The exception is the clipping path \(em
Xany clipping path established in the prolog is simply ignored.
X.SH NOTES
X\*(PS is a trademark of Adobe Systems Incorporated.
!End-Of-pshalf.1.proto!
fi
echo -n extracted: 
ls -l pshalf.1.proto | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
echo "extracting: diffs.psdit (2833 bytes)"
if [ -s diffs.psdit ]
then
  echo will not overwrite diffs.psdit 1>&2
else
  sed -e 's/^X//' > diffs.psdit <<'!End-Of-diffs.psdit!'
X
X------- psdit.c -------
X*** /tmp/d05706	Fri Aug 21 14:49:09 1987
X--- psdit.c	Fri Aug 21 14:48:00 1987
X***************
X*** 861,870 ****
X      output = 1;
X      FlushShow(0);
X      if (!firstpage) {
X! 	printf("\n%d p",n);
X      }
X      firstpage = FALSE;
X!     printf ("\n%%%%Page: %d %d\n", n, ++pageno, n);
X      for (i = 0; i <= nfonts; i++) {
X  	if (fontdelta[i] != 0) {
X  	    sayload (i, fontname[i].name, (char *) 0);
X--- 861,870 ----
X      output = 1;
X      FlushShow(0);
X      if (!firstpage) {
X! 	printf("\nep");
X      }
X      firstpage = FALSE;
X!     printf ("\n%%%%Page: %d %d\nbp\n", n, ++pageno, n);
X      for (i = 0; i <= nfonts; i++) {
X  	if (fontdelta[i] != 0) {
X  	    sayload (i, fontname[i].name, (char *) 0);
X***************
X*** 955,961 ****
X  private t_trailer()
X  {
X      FlushShow(0);
X!     printf("\n%d p",pageno);
X      printf("\n%%%%Trailer\n");
X      printf("xt\n");
X  }
X--- 955,962 ----
X  private t_trailer()
X  {
X      FlushShow(0);
X!     if( !firstpage )
X! 	printf("\nep\n");
X      printf("\n%%%%Trailer\n");
X      printf("xt\n");
X  }
X
X------- psdit.pro -------
X*** /tmp/d05598	Fri Aug 21 14:43:22 1987
X--- psdit.pro	Thu Aug 20 18:17:56 1987
X***************
X*** 5,16 ****
X
X  /$DITroff 140 dict def $DITroff begin
X  /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
X! /xi {0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
X!   /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F
X!   /pagesave save def}def
X- /PB{save /psv exch def currentpoint translate 
X-   resolution 72 div dup neg scale 0 0 moveto}def
X- /PE{psv restore}def
X  /arctoobig 90 def /arctoosmall .05 def
X  /m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
X  /tan{dup sin exch cos div}def
X--- 5,12 ----
X
X  /$DITroff 140 dict def $DITroff begin
X  /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
X! /xi {0 72 11 mul translate 72 resolution div dup neg scale 
X!   /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F }def
X  /arctoobig 90 def /arctoosmall .05 def
X  /m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
X  /tan{dup sin exch cos div}def
X***************
X*** 45,51 ****
X  /MXY{moveto}def
X  /cb{pop}def	% action on unknown char -- nothing for now
X  /n{}def/w{}def
X! /p{pop showpage pagesave restore /pagesave save def}def
X  /abspoint{currentpoint exch pop add exch currentpoint pop add exch}def
X  /distance{dup mul exch dup mul add sqrt}def
X  /dstroke{currentpoint stroke moveto}def
X--- 41,49 ----
X  /MXY{moveto}def
X  /cb{pop}def	% action on unknown char -- nothing for now
X  /n{}def/w{}def
X! /bp{/psv save def 0 0 moveto} def
X! /ep{showpage psv restore}def
X! 
X  /abspoint{currentpoint exch pop add exch currentpoint pop add exch}def
X  /distance{dup mul exch dup mul add sqrt}def
X  /dstroke{currentpoint stroke moveto}def
!End-Of-diffs.psdit!
fi
echo -n extracted: 
ls -l diffs.psdit | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
echo "extracting: squeeze.c (3011 bytes)"
if [ -s squeeze.c ]
then
  echo will not overwrite squeeze.c 1>&2
else
  sed -e 's/^X//' > squeeze.c <<'!End-Of-squeeze.c!'
X/*
X *   This is dvips, a freely redistributable PostScript driver
X *   for dvi files.  It is (C) Copyright 1987 by Tomas Rokicki.
X *   You may modify and use this program to your heart's content,
X *   so long as you send modifications to Tomas Rokicki.  It can
X *   be included in any distribution, commercial or otherwise, so
X *   long as the banner string defined in structures.h is not
X *   modified (except for the version number) and this banner is
X *   printed on program invocation, or can be printed on program
X *   invocation with the -? option.
X */
X/*
X *   This routine squeezes a PostScript file down to it's
X *   minimum.  We parse and then output it.
X */
X#include "stdio.h"
X#define LINELENGTH (70)
Xstatic int linepos = 0 ;
Xstatic int instring ;
Xstatic int lastspecial = 1 ;
X/*
X *   This next routine writes out a `special' character.  In this case,
X *   we simply put it out, since any special character terminates the
X *   preceding token.
X */
Xspecialout(c)
Xchar c ;
X{
X   if (linepos + 1 > LINELENGTH) {
X      putchar('\n') ;
X      linepos = 0 ;
X   }
X   putchar(c) ;
X   linepos++ ;
X   lastspecial = 1 ;
X}
Xstrout(s)
Xchar *s ;
X{
X   if (linepos + strlen(s) > LINELENGTH) {
X      putchar('\n') ;
X      linepos = 0 ;
X   }
X   linepos += strlen(s) ;
X   while (*s != 0)
X      putchar(*s++) ;
X   lastspecial = 1 ;
X}
Xcmdout(s, space)
Xchar *s ;
Xint space ;
X{
X   int l ;
X
X   l = strlen(s) ;
X   if (linepos + l + 1 > LINELENGTH) {
X      putchar('\n') ;
X      linepos = 0 ;
X      lastspecial = 1 ;
X   }
X   if (! lastspecial && space) {
X      putchar(' ') ;
X      linepos++ ;
X   }
X   while (*s != 0) {
X      putchar(*s++) ;
X   }
X   linepos += l ;
X   lastspecial = 0 ;
X}
Xchar buf[1000] ;
Xmain() {
X   int c, space ;
X   char *b ;
X   char seeking ;
X
X   printf("%%!\n") ;
X   while (1) {
X      c = getchar() ;
X      if (c==EOF)
X         break ;
X      if (c=='%') {
X         while ((c=getchar())!='\n') ;
X      }
X      if (c <= ' ')
X         continue ;
X      space = 1 ;
X      switch (c) {
Xcase '{' :
Xcase '}' :
Xcase '[' :
Xcase ']' :
X         specialout(c) ;
X         break ;
Xcase '<' :
Xcase '(' :
X         if (c=='(')
X            seeking = ')' ;
X         else
X            seeking = '>' ;
X         b = buf ;
X         *b++ = c ;
X         do {
X            c = getchar() ;
X            *b++ = c ;
X            if (c=='\\')
X               *b++ = getchar() ;
X         } while (c != seeking) ;
X         *b++ = 0 ;
X         strout(buf) ;
X         break ;
Xcase '/':
X	 space = 0 ;
X	/*FALLTHROUGH*/
Xdefault:
X         b = buf ;
X         while ((c>='A'&&c<='Z')||(c>='a'&&c<='z')||
X                (c>='0'&&c<='9')||(c=='/')||(c=='@')||(c=='-')||
X		(c=='.')||(c=='#')||(c=='_')||(c=='$')||(c=='&')) {
X            *b++ = c ;
X            c = getchar() ;
X         }
X         if (b == buf) {
X            fprintf(stderr, "Oops!  Missed a case: %c.\n", c) ;
X            exit(1) ;
X         }
X         *b++ = 0 ;
X         ungetc(c, stdin) ;
X         cmdout(buf,space) ;
X      }
X   }
X   if (linepos != 0)
X      putchar('\n') ;
X   exit(0) ;
X}
!End-Of-squeeze.c!
fi
echo -n extracted: 
ls -l squeeze.c | awk '{ printf "  %s (%d bytes)\n", $8, $4 }'
exit