forms.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