%! % bb.ps -- % % Prints a file, but keeps track of bounding box info, and prints the box at % the end (around the figure.) % % $Header: bb.ps,v 1.10 90/06/27 10:47:22 cosell Exp $ % RCS log info at end 50 dict /$BoundingBox exch def $BoundingBox begin /xdef { exch def } def /xstore { exch store } def /addcoords { exch 4 -1 roll add 3 1 roll add } def % % Stubs of old functions. % /-stroke /stroke load def /-fill /fill load def /-eofill /eofill load def /-image /image load def /-show /show load def /-awidthshow /awidthshow load def /-showpage /showpage load def /-restore /restore load def /-imagemask /imagemask load def end % $BoundingBox % % New Functions. --- These go into the user dict to intercept the calls % /stroke { $BoundingBox begin gsave initmatrix (stroke called\n) traceprint %%DEBUG { strokepath % Make sure to take line width into account. 0 setlinejoin flattenpath } stopped { % strokepath often hits a limitcheck. (Can't set up a strokepath\n) traceprint % DEBUG grestore % Restore the original path gsave } if includepath % Accumulate it into our box. grestore -stroke end % $BoundingBox } def /fill { $BoundingBox begin gsave (fill called\n) traceprint %%DEBUG includepath grestore -fill end % $BoundingBox } def /eofill { $BoundingBox begin gsave (eofill called\n) traceprint %%DEBUG includepath grestore -eofill end % $BoundingBox } def % % Text is implemented by reducing everything to an `awidthshow'. % /show { $BoundingBox begin (show called\n) traceprint %%DEBUG 0 0 0 0 0 % Extra parameters for awidthshow 6 -1 roll % Bring the string back up awidthshow end % $BoundingBox } def /widthshow { $BoundingBox begin (widthshow called\n) traceprint %%DEBUG 0 0 % Extra parameters for awidthshow 3 -1 roll % Bring the string back up. awidthshow end % $BoundingBox } def /ashow { $BoundingBox begin (ashow called\n) traceprint %%DEBUG 0 0 0 6 3 roll awidthshow end % $BoundingBox } def % This does all of the work of the text-rendering operators % What it does, is compute, basically brute force, what 'charpath' % would have given us virtually for free, if 'show' were the only % operator that we needed to do. /awidthshow { $BoundingBox begin gsave 6 (awidthshow:) debug %%DEBUG currentpoint 2 copy /@starty xdef /@startx xdef 2 index stringwidth % Get the natural length of the string addcoords % Add to the start to get the end. 2 index length % How many characters? dup % Add the offsets to each character 6 index mul exch 5 index mul addcoords 5 index 3 index chcount % How many padding characters? dup % Add the offsets for each pad. 9 index mul exch 8 index mul addcoords /@endy xdef /@endx xdef % We now have the left and right edges (in user coords) % of the text. Now we need only correct for the vertical % displacements needed for the font and we can get the % top and bottom edges of the enclosing box fontheight % Get the height and depth of the current font. @startx @starty addcoords /@starty xdef /@startx xdef @endx @endy addcoords /@endy xdef /@endx xdef newpath @startx @starty moveto @endx @starty lineto @endx @endy lineto @startx @endy lineto closepath includepath grestore -awidthshow end % $BoundingBox } def % % `image': % % Assume here that the image lands in the unit square. % /image { $BoundingBox begin (image called\n) traceprint %%DEBUG gsave newpath 0 0 moveto 1 0 rlineto 1 1 rlineto -1 0 rlineto closepath includepath grestore -image end % $BoundingBox } def /imagemask { $BoundingBox begin (imagemask called\n) traceprint %%DEBUG gsave newpath 0 0 moveto 1 0 rlineto 1 1 rlineto -1 0 rlineto closepath includepath grestore -imagemask end % $BoundingBox } def % Just define this one out of existence /framedevice { pop pop pop pop } def % Handle restoring VM --- this is all OK, except that we have to % hang onto the bb info we collected while in the about-to-be-discarded % environment /restore { $BoundingBox begin bbox-llx bbox-lly bbox-urx bbox-ury 5 -1 roll -restore /bbox-ury xstore /bbox-urx xstore /bbox-lly xstore /bbox-llx xstore end % $BoundingBox } def % % `showpage': % % Just draw the box around the figure and print the page, and then initialize % the bounding box variables again. % $BoundingBox begin /temp-string 10 string def end % $BoundingBox /showpage { $BoundingBox begin initgraphics (showpage\n) traceprint % DEBUG dump-bbox % DEBUG /bbox-llx round_down /bbox-lly round_down /bbox-ury round_up /bbox-urx round_up bbox-llx bbox-lly moveto % Make the box bbox-llx bbox-ury lineto bbox-urx bbox-ury lineto bbox-urx bbox-lly lineto closepath bwstroke % Draw the box. % Print the size of the bounding box both above and below the actual box 0 setgray /Courier findfont 10 scalefont setfont 100 100 moveto bbox-llx bbox-lly 12 sub moveto (%%BoundingBox: ) -show bbox-llx temp-string cvs -show ( ) -show bbox-lly temp-string cvs -show ( ) -show bbox-urx temp-string cvs -show ( ) -show bbox-ury temp-string cvs -show bbox-llx bbox-ury 12 add moveto (%%BoundingBox: ) -show bbox-llx temp-string cvs -show ( ) -show bbox-lly temp-string cvs -show ( ) -show bbox-urx temp-string cvs -show ( ) -show bbox-ury temp-string cvs -show init -showpage tracedump %% DEBUG end % $BoundingBox } def % % BoundingBox functions: % % We accumulate the information about the bounding box into four variables. % The data is stored in default coordinates. % $BoundingBox begin /init { /bbox-llx 99999 store /bbox-lly 99999 store /bbox-urx -99999 store /bbox-ury -99999 store } def /bbox-llx 0 def /bbox-lly 0 def /bbox-urx 0 def /bbox-ury 0 def % % - `includepath' - % % Incorporates the bounding box of the path into the bounding box info. % ... Gets the bounding box in default coords /includepath { (Adding a path: ) traceprint %%DEBUG gsave initmatrix { 0 setlinejoin flattenpath } stopped { (Couldn't flatten the path\n) traceprint % DEBUG grestore gsave initmatrix } if pathbbox 4 2 roll % Just so we get lower-left first 2 copy dump-coord %%DEBUG dup bbox-lly lt { /bbox-lly xstore } { pop } ifelse dup bbox-llx lt { /bbox-llx xstore } { pop } ifelse (; ) traceprint 2 copy dump-coord (\n) traceprint %%DEBUG dup bbox-ury gt { /bbox-ury xstore } { pop } ifelse dup bbox-urx gt { /bbox-urx xstore } { pop } ifelse dump-bbox %%DEBUG grestore } def % % A nice black-and white line drawing function. % /bwstroke { 0 setlinewidth % Thinnest possible lines 1 setgray % White first [5] 0 setdash % Only half the line gsave -stroke grestore 0 setgray % Then black [5] 5 setdash % On the other half -stroke } def % % Stuff for text. % % % char-code string `chcount' occurs % % Counts the number of times a character appears in a string. % /chcount { 0 exch { 2 index eq { 1 add } if } forall exch pop } def % % - `fontheight' heightx heighty depthx depthy % % Returns the offsets to the lowest point and highest point in the current % font. % /fontheight { currentfont begin /FontBBox load aload pop exch pop 0 exch FontMatrix transform 4 2 roll exch pop 0 exch FontMatrix transform end } def % key round_{down|up} - These will round the value of the given key % up or down, as appropriate, to the nearest integer /round_up { dup load ceiling cvi store } def /round_down { dup load floor cvi store } def % key binddefinition - this will do a 'bind' on the procedure given by 'key' /binddefinition { dup where { exch 2 copy get bind put } { undefined } ifelse } def % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % Debugging utilities % /$tracedict where { % Trace package loaded... do the tracing pop % This is a debugging function to print out what is going on. % Format ... n debug ... % (that is, the 'n' args will be *left* on the stack!) /debug { traceprint (\n) traceprint dup 1 add % Now total number of args (including arg count) copy { ( ) traceprint trace= (\n) traceprint } repeat pop % Remove the extra copy of the arg count } def % Print out a coordinate on the stack: x y --- /dump-coord { (\() traceprint exch trace= (, ) traceprint trace= (\)) traceprint } def % Print out bb's current notion of its bounding box /dump-bbox { (Bounding Box: ) traceprint bbox-llx bbox-lly dump-coord (; ) traceprint bbox-urx bbox-ury dump-coord (\n) traceprint } def tracebegin %% DEBUG } { % No trace package loaded, so don't trace. Stub out the various calls /traceprint { pop } def /dump-coord { pop pop } def /dump-bbox { } def /debug { pop pop } def /tracedump { } def } ifelse % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % Bind everything /xdef binddefinition /xstore binddefinition /addcoords binddefinition /stroke binddefinition /fill binddefinition /eofill binddefinition /show binddefinition /widthshow binddefinition /ashow binddefinition /awidthshow binddefinition /image binddefinition /showpage binddefinition /init binddefinition /includepath binddefinition /bwstroke binddefinition /chcount binddefinition /fontheight binddefinition /debug binddefinition /dump-coord binddefinition /dump-bbox binddefinition % Start it up. init end % $BoundingBox % end of bb.ps % $Log: bb.ps,v $ % Revision 1.10 90/06/27 10:47:22 cosell % Added a bunch of improvements from Joe Pallas at stanford. % % Revision 1.9 90/06/26 10:50:20 cosell % Stack got botched in the 'debug' stub % % Revision 1.8 90/06/25 09:34:51 cosell % Minor bug in 'restore' % % Revision 1.7 90/06/25 09:29:58 cosell % Added code to catch and deal with 'restore'. Thanks to Frank % Jensen for finding this one % % Revision 1.6 90/06/25 09:23:26 cosell % Small bugfix in the text-handling stuff % % Revision 1.5 90/06/10 09:04:02 cosell % Changed the printed string to explictly say "%%BoundingBox" % % Revision 1.4 90/06/10 08:55:39 cosell % Added 'bind' machinery to insulate this package from later redefinitions % of things we need from the systemdict. % % Revision 1.3 90/06/10 08:28:53 cosell % Added debugging hooks. They don't affect anything (and don't do % anything) in the normal use of bbfig. But if the 'trace' package % is loaded ahead of this, it'll print out some helpful info. Probably % I'll end up removing all of this if/when I really get the package % up to snuff. % % Revision 1.2 90/05/25 12:08:24 cosell % Major improvements and tuneups: fixed it to really use its private % discionary, and the most importnat: it now computes the bounding box % in *default* coords % % Revision 1.1 90/05/23 08:18:54 cosell % Initial revision % This is Ned Bachelder's original version