tforms.ps - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tforms.ps (6060B)
       ---
            1 %
            2 % Procedures that let you print any number of pages on each sheet of paper. It's
            3 % far from perfect and won't handle everything (eg. it's not recursive), but should
            4 % be good enough for now. Assumes the default page coordinate system has been set
            5 % up before setupforms is called. lastpage makes certain the last page is printed,
            6 % and should be called immediately after the %%Trailer comment.
            7 %
            8 % Three lines of code needed for page image clipping have been commented out for
            9 % now. It works, but can really slow things down on some versions of PostScript.
           10 % Uncomment them if you want to clip pages.
           11 %
           12 
           13 /setupforms {
           14     /formsperpage exch def
           15 
           16     /currentform 0 def
           17     /slop 5 def
           18     /min {2 copy gt {exch} if pop} def
           19 
           20 %
           21 % Save the current environment so the real showpage can be restored when we're all
           22 % done. Occasionally helps when a banner page is included with the job.
           23 %
           24 
           25     /saveobj save def
           26 
           27 %
           28 % Number of rows and columns we'll need - may exchange them later.
           29 %
           30 
           31     /columns formsperpage sqrt ceiling cvi def
           32     /rows formsperpage columns div ceiling cvi def
           33 
           34 %
           35 % Slop leaves a little room around the edge so page images can be outlined and have
           36 % the borders show up. Distance is in default coordinates, so we need to figure out
           37 % how it maps into user coordinates.
           38 %
           39 
           40     6 array defaultmatrix
           41     6 array currentmatrix
           42     6 array invertmatrix
           43     6 array concatmatrix
           44     /tempmatrix exch def
           45 
           46     0 slop tempmatrix dtransform dup mul exch dup mul add sqrt
           47     /slop exch def
           48 
           49 %
           50 % Determine how big the image area is, using the clipping path bounding box minus
           51 % a little and leave the coordinates of the lower left corner of the clipping path
           52 % on the stack. Also temporarily set the size of each page (ie. formheight and
           53 % formwidth) from the clipping path - just in case old software uses this stuff.
           54 % Only works for coordinate systems that have been rotated by a multiple of 90
           55 % degrees.
           56 %
           57 
           58     newpath clippath pathbbox
           59     2 index sub dup /formheight exch def slop 2 mul sub /pageheight exch def
           60     2 index sub dup /formwidth exch def slop 2 mul sub /pagewidth exch def
           61 
           62 %
           63 % New translators all store the size of each page in default coordinates in the
           64 % pagebbox array and it can be different than the size determined by the clipping
           65 % path. If we can find pagebbox use it to set the real dimensions of each page.
           66 % Leaves the coordinates of the lower left corner on the stack, (either from
           67 % pagebbox or clippath) so four numbers are there when we're done.
           68 %
           69 
           70     userdict /gotpagebbox known userdict /pagebbox known and {
           71         newpath
           72         pagebbox 0 get pagebbox 1 get tempmatrix transform moveto
           73         pagebbox 0 get pagebbox 3 get tempmatrix transform lineto
           74         pagebbox 2 get pagebbox 3 get tempmatrix transform lineto
           75         pagebbox 2 get pagebbox 1 get tempmatrix transform lineto
           76         closepath pathbbox
           77         2 index sub /formheight exch def
           78         2 index sub /formwidth exch def
           79     } {2 copy} ifelse
           80 
           81 %
           82 % Top two numbers are the displacement from the job's origin to the lower left
           83 % corner of each page image when we finish setting up the new coordinate system.
           84 %
           85 
           86     /ycorner exch def
           87     /xcorner exch def
           88 
           89 %
           90 % The two numbers left on the stack are the coordinates of the lower left corner
           91 % of the clipping path. Go there and then up a bit so page images can be outlined.
           92 %
           93 
           94     translate
           95     slop slop translate
           96 
           97 %
           98 % If the page is wider than high we may be able to do better if we exchange rows
           99 % and columns. Won't make a difference in the current orientation or if rows and
          100 % columns are the same.
          101 %
          102 
          103     pagewidth pageheight gt {
          104         rows columns /rows exch def /columns exch def
          105     } if
          106 
          107 %
          108 % Find the orientation and scaling that makes things as large as possible. More
          109 % than what's really needed. First calculation essentially finds the minimum of
          110 % 1/rows and 1/columns.
          111 %
          112 
          113     pagewidth formwidth columns mul div pageheight formheight rows mul div min
          114     pageheight formwidth columns mul div pagewidth formheight rows mul div min
          115 
          116     2 copy lt {
          117         rotation 1 eq {
          118             landscape {
          119                 0 pageheight translate
          120                 -90 rotate
          121             }{
          122                 pagewidth 0 translate
          123                 90 rotate
          124             } ifelse
          125         }{
          126             landscape {
          127                 pagewidth 0 translate
          128                 90 rotate
          129             }{
          130                 0 pageheight translate
          131                 -90 rotate
          132             } ifelse
          133         } ifelse
          134         pagewidth pageheight /pagewidth exch def /pageheight exch def
          135         exch
          136     } if
          137 
          138 %
          139 % Second number from the top is the best choice. Scale so everything will fit on
          140 % the current page, go back to the original origin, and then get ready for the
          141 % first page - which goes in the upper left corner.
          142 %
          143 
          144     pop dup dup scale
          145     xcorner neg ycorner neg translate
          146     0 rows 1 sub formheight mul translate
          147 
          148 %
          149 % Try to center everything on the page - scaling we used is on top of the stack.
          150 %
          151 
          152     dup pagewidth exch div formwidth columns mul sub 2 div
          153     exch pageheight exch div formheight rows mul sub 2 div translate
          154 
          155 %
          156 % Redefine showpage.
          157 %
          158 
          159     /!PreForms~showpage~ /showpage load def                % save current showpage
          160 
          161     /showpage {
          162         saveobj restore
          163 %        initclip
          164         formsperpage 1 gt {
          165             gsave .1 setlinewidth outlineform stroke grestore
          166         } if
          167         formwidth 0 translate
          168         /currentform currentform 1 add def
          169         currentform columns mod 0 eq {
          170             columns formwidth mul neg formheight neg translate
          171         } if
          172         currentform formsperpage mod 0 eq {
          173             gsave !PreForms~showpage~ grestore
          174             currentform columns mod formwidth mul neg
          175             formsperpage columns idiv formheight mul translate
          176             /currentform 0 def
          177         } if
          178 %        outlineform clip newpath
          179         /saveobj save def
          180     } bind def
          181 
          182     /outlineform {
          183         newpath
          184         xcorner ycorner moveto
          185         formwidth 0 rlineto
          186         0 formheight rlineto
          187         formwidth neg 0 rlineto
          188         closepath
          189     } bind def
          190 
          191     /lastpage {
          192         formsperpage 1 gt {
          193             currentform 0 ne {
          194                 /saveobj save def
          195                 0 1 formsperpage currentform sub formsperpage mod {
          196                     pop showpage
          197                 } for
          198                 saveobj restore
          199             } if
          200             saveobj restore
          201             saveobj restore
          202         } if
          203     } def
          204 
          205 %
          206 % Clip the first page image and save the environment we just set up, including
          207 % the redefined showpage.
          208 %
          209 
          210 %   outlineform clip
          211     newpath
          212     /saveobj save def
          213 } def