[comp.lang.postscript] Shar for new version of bbfig

cosell@bbn.com (Bernie Cosell) (06/28/90)

Here 'tis.  Comments, bugs, complaints, suggestions, etc, go to me.

  /Bernie\

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#       INSTALLATION
#       bbfig
#       bb.ps
#       bbfig.l
# This archive created: Wed Jun 27 21:55:27 EDT 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'INSTALLATION'
then
    echo shar: "will not over-write existing file 'INSTALLATION'"
else
    echo -n "Extracting INSTALLATION: "
    sed 's/^X//' <<\SHAR_EOF > 'INSTALLATION'
XTo install bbfig:
X
XMake the bbfig shell script executable and put it in a suitable
Xdirectory.  Put the file bb.ps in that *same* directory.  If this
Xis not possible or is inconvenient, put bb.ps whereever you please
Xand edit the shell script to define BBPSDIR.
X
XIf you run across a PostScript file that manages to confuse bbfig,
Xplease send it along to me and I'll see if I can figure out what is
Xgoing wrong.  Thanks.
X
X
XBernie Cosell  [cosell@bbn.com]
X27June90
SHAR_EOF
    if [ `wc -c <INSTALLATION` -ne      462 ]
    then
	echo "***Trouble in transmission***   Check file!"
    else
	echo OK
    fi
fi
if test -f 'bbfig'
then
    echo shar: "will not over-write existing file 'bbfig'"
else
    echo -n "Extracting bbfig: "
    sed 's/^X//' <<\SHAR_EOF > 'bbfig'
X#! /bin/sh
X
X# Script to stick bounding box finder in front of a postscript file
X#    Adapted from Ned's original
X
X# $Header: bbfig,v 1.3 90/06/27 21:54:49 cosell Exp $
X
X# BBPSDIR=<wherever>  # Define this if bb.ps doesn't live in same
X                      #   directory as bbfig
X
Xif [ ! -f ${BBPSDIR=`dirname $0`}/bb.ps ]
Xthen
X    echo >&2 "Can't locate bb.ps"
X    exit 1
Xfi
X
Xcase $# in
X    0)    cat $BBPSDIR/bb.ps -
X	  ;;
X    *)    cat $BBPSDIR/bb.ps "$@"
X	  ;;
Xesac
SHAR_EOF
    if [ `wc -c <bbfig` -ne      470 ]
    then
	echo "***Trouble in transmission***   Check file!"
    else
	echo OK
    fi
fi
if test -f 'bb.ps'
then
    echo shar: "will not over-write existing file 'bb.ps'"
else
    echo -n "Extracting bb.ps: "
    sed 's/^X//' <<\SHAR_EOF > 'bb.ps'
X%! 
X% bb.ps --
X% 
X% Prints a file, but keeps track of bounding box info, and prints the box at
X% the end (around the figure.)
X% 
X% $Header: bb.ps,v 1.10 90/06/27 10:47:22 cosell Exp $
X% RCS log info at end
X
X50 dict /$BoundingBox exch def
X
X$BoundingBox begin
X
X/xdef {
X	exch def
X} def
X
X/xstore {
X	exch store
X} def
X
X/addcoords {
X	exch
X	4 -1 roll add
X	3 1 roll add
X} def
X
X% 
X% Stubs of old functions.
X% 
X
X/-stroke /stroke load def
X/-fill /fill load def
X/-eofill /eofill load def
X/-image /image load def
X/-show /show load def
X/-awidthshow /awidthshow load def
X/-showpage /showpage load def
X/-restore  /restore load def
X/-imagemask /imagemask load def
X
Xend % $BoundingBox
X
X% 
X% New Functions.   --- These go into the user dict to intercept the calls
X% 
X
X/stroke {
X        $BoundingBox begin
X	gsave
X	initmatrix
X	(stroke called\n) traceprint %%DEBUG
X	{
X	 	strokepath	% Make sure to take line width into account.
X		0 setlinejoin
X		flattenpath
X	} stopped {		% strokepath often hits a limitcheck.
X		(Can't set up a strokepath\n) traceprint % DEBUG
X		grestore	% Restore the original path
X		gsave
X	} if
X	includepath			% Accumulate it into our box.
X	grestore
X
X	-stroke
X	end % $BoundingBox
X} def
X
X/fill {
X        $BoundingBox begin
X	gsave
X	(fill called\n) traceprint %%DEBUG
X	includepath
X	grestore
X
X	-fill
X	end % $BoundingBox
X} def
X
X/eofill {
X        $BoundingBox begin
X	gsave
X	(eofill called\n) traceprint %%DEBUG
X	includepath
X	grestore
X
X	-eofill
X	end % $BoundingBox
X} def
X
X% 
X% Text is implemented by reducing everything to an `awidthshow'.
X% 
X
X/show {
X        $BoundingBox begin
X	(show called\n) traceprint %%DEBUG
X	0 0 0 0 0		% Extra parameters for awidthshow
X	6 -1 roll		% Bring the string back up
X	awidthshow
X	end % $BoundingBox
X} def
X
X/widthshow {
X        $BoundingBox begin
X        (widthshow called\n) traceprint %%DEBUG
X	0 0			% Extra parameters for awidthshow
X	3 -1 roll		% Bring the string back up.
X	awidthshow
X	end % $BoundingBox
X} def
X
X/ashow {
X        $BoundingBox begin
X        (ashow called\n) traceprint %%DEBUG
X	0 0 0 
X	6 3 roll
X	awidthshow
X	end % $BoundingBox
X} def
X
X
X% This does all of the work of the text-rendering operators
X%   What it does, is compute, basically brute force, what 'charpath'
X%   would have given us virtually for free, if 'show' were the only
X%   operator that we needed to do.
X
X/awidthshow {
X	$BoundingBox begin
X	gsave
X	6 (awidthshow:) debug %%DEBUG
X	currentpoint
X	2 copy /@starty xdef /@startx xdef
X	2 index stringwidth	% Get the natural length of the string
X	addcoords			% Add to the start to get the end.
X
X	2 index length		% How many characters?
X
X	dup			% Add the offsets to each character
X	6 index mul
X	exch 5 index mul
X	addcoords
X
X	5 index 3 index
X	chcount		% How many padding characters?
X
X	dup			% Add the offsets for each pad.
X	9 index mul
X	exch 8 index mul
X	addcoords
X
X	/@endy xdef /@endx xdef
X
X	% We now have the left and right edges (in user coords)
X	% of the text.  Now we need only correct for the vertical
X	% displacements needed for the font and we can get the
X	% top and bottom edges of the enclosing box
X
X	fontheight		% Get the height and depth of the current font.
X	
X	@startx @starty addcoords
X	/@starty xdef /@startx xdef
X	@endx @endy addcoords
X	/@endy xdef /@endx xdef
X	newpath
X	@startx @starty moveto
X	@endx @starty lineto
X	@endx @endy lineto
X	@startx @endy lineto
X	closepath
X        includepath
X	grestore
X
X	-awidthshow
X	end % $BoundingBox
X} def
X
X% 
X% `image':
X% 
X% Assume here that the image lands in the unit square.
X% 
X
X/image {
X        $BoundingBox begin
X        (image called\n) traceprint %%DEBUG
X	gsave
X	newpath
X	0 0 moveto
X	1 0 rlineto
X	1 1 rlineto
X	-1 0 rlineto
X	closepath
X	includepath
X	grestore
X
X	-image
X	end % $BoundingBox
X} def
X
X/imagemask
X{
X    $BoundingBox begin
X    (imagemask called\n) traceprint %%DEBUG
X    gsave
X    newpath
X    0 0 moveto
X    1 0 rlineto
X    1 1 rlineto
X    -1 0 rlineto
X    closepath
X    includepath
X    grestore
X
X    -imagemask
X    end % $BoundingBox
X} def
X
X% Just define this one out of existence
X/framedevice { pop pop pop pop } def
X
X% Handle restoring VM --- this is all OK, except that we have to
X% hang onto the bb info we collected while in the about-to-be-discarded
X% environment
X
X/restore
X{
X    $BoundingBox begin
X    bbox-llx bbox-lly bbox-urx bbox-ury 
X    5 -1 roll
X    -restore
X    /bbox-ury xstore /bbox-urx xstore
X    /bbox-lly xstore /bbox-llx xstore
X    end % $BoundingBox
X} def
X
X    
X% 
X% `showpage':
X% 
X% Just draw the box around the figure and print the page, and then initialize
X% the bounding box variables again.
X% 
X
X$BoundingBox begin
X/temp-string 10 string def
Xend % $BoundingBox
X
X/showpage {
X	$BoundingBox begin
X	initgraphics
X
X        (showpage\n) traceprint % DEBUG
X	dump-bbox  % DEBUG
X
X        /bbox-llx round_down
X	/bbox-lly round_down
X	/bbox-ury round_up
X	/bbox-urx round_up
X
X	bbox-llx bbox-lly moveto		% Make the box
X	bbox-llx bbox-ury lineto
X	bbox-urx bbox-ury lineto
X	bbox-urx bbox-lly lineto
X	closepath
X
X	bwstroke			% Draw the box.
X
X% Print the size of the bounding box both above and below the actual box
X	0 setgray
X	/Courier findfont 10 scalefont setfont
X	100 100 moveto
X	bbox-llx bbox-lly 12 sub moveto
X	(%%BoundingBox: ) -show
X	bbox-llx temp-string cvs -show ( ) -show
X	bbox-lly temp-string cvs -show ( ) -show
X	bbox-urx temp-string cvs -show ( ) -show
X	bbox-ury temp-string cvs -show
X
X        bbox-llx bbox-ury 12 add moveto
X	(%%BoundingBox: ) -show
X	bbox-llx temp-string cvs -show ( ) -show
X	bbox-lly temp-string cvs -show ( ) -show
X	bbox-urx temp-string cvs -show ( ) -show
X	bbox-ury temp-string cvs -show
X
X	init
X	-showpage
X	tracedump        %% DEBUG
X	end % $BoundingBox
X} def
X
X% 
X% BoundingBox functions:
X% 
X% We accumulate the information about the bounding box into four variables.
X% The data is stored in default coordinates.
X% 
X
X$BoundingBox begin
X
X/init {
X	/bbox-llx 99999 store
X	/bbox-lly 99999 store
X	/bbox-urx -99999 store
X	/bbox-ury -99999 store
X} def
X
X/bbox-llx 0 def
X/bbox-lly 0 def
X/bbox-urx 0 def
X/bbox-ury 0 def
X
X% 
X% - `includepath' -
X% 
X% Incorporates the bounding box of the path into the bounding box info.
X%   ... Gets the bounding box in default coords
X
X/includepath {
X        (Adding a path: ) traceprint %%DEBUG
X	gsave
X        initmatrix
X	{
X		0 setlinejoin
X		flattenpath
X	} stopped {
X		(Couldn't flatten the path\n) traceprint % DEBUG
X		grestore
X		gsave
X		initmatrix
X	} if
X	pathbbox
X        4 2 roll    % Just so we get lower-left first
X	2 copy dump-coord %%DEBUG
X	dup bbox-lly lt {	
X		/bbox-lly xstore
X	} {
X		pop
X	} ifelse
X	dup bbox-llx lt {
X		/bbox-llx xstore
X	} {
X		pop
X	} ifelse
X
X	(; ) traceprint 2 copy dump-coord (\n) traceprint %%DEBUG
X	dup bbox-ury gt {
X		/bbox-ury xstore
X	} {
X		pop
X	} ifelse
X	dup bbox-urx gt {
X		/bbox-urx xstore
X	} {
X		pop
X	} ifelse
X	dump-bbox  %%DEBUG
X	grestore
X} def
X
X% 
X% A nice black-and white line drawing function.
X% 
X
X/bwstroke {
X	0 setlinewidth			% Thinnest possible lines
X	1 setgray			% White first
X	[5] 0 setdash			% Only half the line
X	gsave -stroke grestore
X	0 setgray			% Then black
X	[5] 5 setdash			% On the other half
X	-stroke
X} def
X
X% 
X% Stuff for text.
X% 
X
X% 
X% char-code string `chcount' occurs
X% 
X% Counts the number of times a character appears in a string.
X% 
X
X/chcount {
X	0 exch
X	{
X		2 index eq {
X			1 add
X		} if
X	} forall
X	exch pop
X} def
X
X% 
X% - `fontheight' heightx heighty depthx depthy
X% 
X% Returns the offsets to the lowest point and highest point in the current
X% font.
X% 
X
X/fontheight {
X	currentfont begin
X	/FontBBox load aload pop
X	exch pop 0 exch
X	FontMatrix transform
X	4 2 roll
X	exch pop 0 exch
X	FontMatrix transform
X	end
X} def
X
X% key round_{down|up} -  These will round the value of the given key
X%                         up or down, as appropriate, to the nearest integer
X/round_up   { dup load ceiling cvi store } def
X/round_down { dup load floor   cvi store } def
X
X% key binddefinition - this will do a 'bind' on the procedure given by 'key'
X/binddefinition
X{
X    dup where
X    {  
X        exch
X        2 copy
X        get bind put
X    }     
X    { undefined } ifelse
X} def  
X
X% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 
X%
X%   Debugging utilities
X%
X
X/$tracedict where
X{  % Trace package loaded... do the tracing
X    pop
X% This is a debugging function to print out what is going on.
X%  Format <argn> <argn-1> ... <arg1> n <string> debug <argn> ... <arg1>
X%    (that is, the 'n' args will be *left* on the stack!)
X/debug
X{
X    traceprint (\n) traceprint 
X    dup 1 add   % Now total number of args (including arg count) 
X    copy
X    {
X        (    ) traceprint 
X	trace=
X        (\n) traceprint
X    } repeat
X    pop    % Remove the extra copy of the arg count
X} def
X
X% Print out a coordinate on the stack:  x y --- 
X/dump-coord
X{
X    (\() traceprint exch trace= (, ) traceprint trace= (\)) traceprint
X} def
X
X% Print out bb's current notion of its bounding box
X
X/dump-bbox
X{
X    (Bounding Box: ) traceprint
X    bbox-llx bbox-lly dump-coord
X    (; ) traceprint
X    bbox-urx bbox-ury dump-coord
X    (\n) traceprint
X} def
X
Xtracebegin %% DEBUG
X
X}
X{ % No trace package loaded, so don't trace.  Stub out the various calls
X
X/traceprint { pop } def
X/dump-coord { pop pop } def
X/dump-bbox { } def
X/debug { pop  pop } def
X/tracedump { } def
X
X} ifelse
X
X% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 
X
X% Bind everything
X
X/xdef binddefinition
X/xstore binddefinition
X/addcoords binddefinition
X/stroke binddefinition
X/fill binddefinition
X/eofill binddefinition
X/show binddefinition
X/widthshow binddefinition
X/ashow binddefinition
X/awidthshow binddefinition
X/image binddefinition
X/showpage binddefinition
X/init binddefinition
X/includepath binddefinition
X/bwstroke binddefinition
X/chcount binddefinition
X/fontheight binddefinition
X
X/debug binddefinition
X/dump-coord binddefinition
X/dump-bbox binddefinition
X
X% Start it up.
X
Xinit
X
Xend % $BoundingBox
X
X%  end of bb.ps
X
X% $Log:	bb.ps,v $
X% Revision 1.10  90/06/27  10:47:22  cosell
X% Added a bunch of improvements from Joe Pallas at stanford.
X% 
X% Revision 1.9  90/06/26  10:50:20  cosell
X% Stack got botched in the 'debug' stub
X% 
X% Revision 1.8  90/06/25  09:34:51  cosell
X% Minor bug in 'restore'
X% 
X% Revision 1.7  90/06/25  09:29:58  cosell
X% Added code to catch and deal with 'restore'.  Thanks to Frank
X% Jensen for finding this one
X% 
X% Revision 1.6  90/06/25  09:23:26  cosell
X% Small bugfix in the text-handling stuff
X% 
X% Revision 1.5  90/06/10  09:04:02  cosell
X% Changed the printed string to explictly say "%%BoundingBox"
X% 
X% Revision 1.4  90/06/10  08:55:39  cosell
X% Added 'bind' machinery to insulate this package from later redefinitions
X% of things we need from the systemdict.
X% 
X% Revision 1.3  90/06/10  08:28:53  cosell
X% Added debugging hooks.  They don't affect anything (and don't do
X% anything) in the normal use of bbfig.  But if the 'trace' package
X% is loaded ahead of this, it'll print out some helpful info.  Probably
X% I'll end up removing all of this if/when I really get the package
X% up to snuff.
X% 
X% Revision 1.2  90/05/25  12:08:24  cosell
X% Major improvements and tuneups:  fixed it to really use its private
X% discionary, and the most importnat: it now computes the bounding box
X% in *default* coords
X%
X% Revision 1.1  90/05/23  08:18:54  cosell
X% Initial revision
X%   This is Ned Bachelder's original version
SHAR_EOF
    if [ `wc -c <bb.ps` -ne    11233 ]
    then
	echo "***Trouble in transmission***   Check file!"
    else
	echo OK
    fi
fi
if test -f 'bbfig.l'
then
    echo shar: "will not over-write existing file 'bbfig.l'"
else
    echo -n "Extracting bbfig.l: "
    sed 's/^X//' <<\SHAR_EOF > 'bbfig.l'
X.TH BBFIG LOCAL
X.SH NAME
Xbbfig \- calculate bounding boxes in PostScript
X.SH SYNTAX
X.B bbfig
X[ file \&.\|.\|. ]
X.SH USAGE
X.I Bbfig
Xshould be piped into 
X.I psprint
Xor the equivalant.
X.SH DESCRIPTION
XThe concatenation of the list of files, or standard input 
Xif no file names are supplied, is
Xassumed to be a PostScript program for which the bounding box is desired.
X.I Bbfig
Xprepends code that
Xcalculates the bounding box,
Xand places the result on standard output.
XThe actual
Xcalculation is done in the PostScript printer; the output is
Xin the form of a dashed line demarcating the bounding box and
Xand the corresponding 
X.B %%BoundingBox 
Xheader line printed just below the box.
XThe
X.B %%BoundingBox
Xline
Xshould be added to the header of the PostScript file.
X.SH BUGS
X.I Bbfig
Xis known to be confused by images and clipping paths. If the box
Xaround the figure clearly is not the minimal one, a ruler is the
Xbest bet for calculating the correct box.  Remember that the 
Xbounding box values are in PostScript points (72 to the inch)
Xrelative to an origin at the lower left corner of the page, and 
Xthat (a,b) is the lower left hand corner of the bounding box, and
X(c,d) is the upper right corner.
X.SH Author
XNed Batchelder, modified by Bernie Cosell [cosell@bbn.com]
SHAR_EOF
    if [ `wc -c <bbfig.l` -ne     1266 ]
    then
	echo "***Trouble in transmission***   Check file!"
    else
	echo OK
    fi
fi
echo "End of Archive"
exit 0