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

chris@hwcs.UUCP (08/26/87)

Thanks to Denise Draper for posting this useful program.  We had a few
problems making it work with the tpscript ditroff->postscript converter
posted to the net a while back; unfortunately, we don't have the
original tpscript sources, having hacked at it extensively ourselves, but
I indicate the necessary changes below.

Our version of "awk" (4.2 bsd) couldn't handle the script correctly
(probably a tokeniser bug, but I couldn't be bothered to chase it);
parenthesising the "++outpages" as shown below fixes the problem and
won't break anyone else's awk (I sincerely hope!).

Also, the rotation+translate+scale operation given in Denise's pshalf.ps
is wrong - having translated the page corner to the correct place, she then
moves it by the following scale operation!  After trying to work out the
correct sequence of operations for a while, I gave up and just worked out
the PostScript matrix for the linear transformation.

Finally, a "save" is needed at the end of the pshalf prolog, otherwise the
first restore following will lose the contents of the HfDict dictionary,
undoing all the good work.  This leaves an extra save object on the stack,
and hence chews up some memory, but I don't feel like writing the code
to do a pop if and only if the stack is non-empty and has a save object
at the top.

Changes to pshalf distribution (context diff format):
----
diff -rc ./pshalf.proto /usr/src/local/pshalf/pshalf.proto
*** ./pshalf.proto	Wed Aug 26 10:14:31 1987
--- /usr/src/local/pshalf/pshalf.proto	Tue Aug 25 14:20:23 1987
***************
*** 21,27
  /^%%Page:/		{ if( firsthalf ) {
  				if( outpages != 0 )
  					print "HfDict begin ep end"
! 				print "%%Page: ? " ++outpages
  				print "HfDict begin bp end"
  			  } else {
  				print "HfDict begin hp end"

--- 21,27 -----
  /^%%Page:/		{ if( firsthalf ) {
  				if( outpages != 0 )
  					print "HfDict begin ep end"
! 				print "%%Page: ? " (++outpages)
  				print "HfDict begin bp end"
  			  } else {
  				print "HfDict begin hp end"
diff -rc ./pshalf.ps /usr/src/local/pshalf/pshalf.ps
*** ./pshalf.ps	Wed Aug 26 10:14:41 1987
--- /usr/src/local/pshalf/pshalf.ps	Wed Aug 26 10:25:09 1987
***************
*** 57,67
  /Y y2 y1 sub def
  					% Now modify D to create OD
  90 rotate 				% (draw pictures to understand)
! 	% I think this is the correct translate, but it doesn't work right
! % y1 x1 sub x2 y1 add neg translate	% (y1-x1), -(x2+y1)
! 	% this one works
! y1 x1 sub   x2 neg translate
! X Y div     Y X 2 mul div scale		% X/Y, (Y/2)/X  -- maybe should be square?
  matrix currentmatrix /O1D exch def 	% matrix for 1st halfpage
  
  X 0 translate 				% (move over by (already scaled) page width)

--- 57,73 -----
  /Y y2 y1 sub def
  					% Now modify D to create OD
  90 rotate 				% (draw pictures to understand)
! % Need to translate the page and scale it; the naive translation gets
! % messed up by a subsequent scaling, so after hacking around with
! % diagrams and linear equations, we derive the transformation:
! %	x' = (Y/2X)*x +     0*y + (y1 - x1*(Y/2X))
! %	y' =      0*x + (X/Y)*y + (-x2 - y1*(X/Y))
! /XY X Y div def
! /Y2X Y X 2 mul div def
! /Tx y1 x1 Y2X mul sub def
! /Ty x2 y1 XY mul add neg def 
! [ Y2X 0 0 XY Tx Ty ] concat
! 
  matrix currentmatrix /O1D exch def 	% matrix for 1st halfpage
  
  X 0 translate 				% (move over by (already scaled) page width)
***************
*** 84,90
  /hp { 					% HalfPage: go to 2nd halfpage
    grestore gsave			%
    O2D setmatrix nclip 			%
!   T concat } def			%
  
  /ep { 					% EndPage: print the real, composite page
    showpage grestore 			%

--- 90,97 -----
  /hp { 					% HalfPage: go to 2nd halfpage
    grestore gsave			%
    O2D setmatrix nclip 			%
!   T concat
! } def					%
  
  /ep { 					% EndPage: print the real, composite page
    showpage grestore 			%
***************
*** 97,99
  end					% HfDict
  /showpage /newpath load def
  

--- 104,107 -----
  end					% HfDict
  /showpage /newpath load def
  
+ save

---

Changes to tpscript (src/tpscript subdirectory of net distribution) --
sorry, no originals available for context diff, but there are only two
places to change:

pcom.c:
Change declarations of "page" and "home" postscript routines in array
pcom1tab near line 90 to:
----
	"/page { showpage } def",
	/* routine to initialise a path */
	"/home { restore save newpath 0 pgtop moveto } def",
----
This ensures that (i) "showpage" is used to display pages, not "copypage"
(pshalf assumes this, and the PostScript manual deprecates use of
"copypage") and (ii) the end-of-page and start-of-page processing are
properly separated so that each page is a separate, stand-alone, entity.

tpscript.c:
Routine page(), at or near line 950, should read
----

page(n)
register int	n;
{
	hpos = 0; vpos = 0;
	/* for each page except the first, print the previous one */
	if(!firstpage)
		fprintf(postr, "\npage");
	if(n >= 0)		/* beginning of a new page */
		fprintf(postr, "\n%%%%Page: %d %d\nhome\n", n, ++npages);
	if (firstpage)
		firstpage = FALSE;
	else
	{
		setfont(TRUE);
		resetspcl();		/* it forgets definitions on next page */
	}
}
----
Again, this ensures that the %%Page: comment correctly separates the document
into stand-alone pages.
-- 
	Chris Miller, Heriot-Watt University, Edinburgh
	chris@cs.hw.ac.uk	<EUROPE>!ukc!hwcs!chris   chris@hwcs.uucp
	chris@uk.ac.hw.cs