1---lua
2---imposition plan : Generic Booklet -- US letter paper -- 8.5 x 11
3---
4---It is said generic as it will try to determine
5---automatically how to fit the booklet onto US letter
6---paper sheets, scaling pages if necessary.
7---it is well suited for office documents for
8---which you do not care too much about resulting
9---imposition artefacts since it manages to save
10---paper!
11---
12-- print("Booklet")
13-- We output a booklet on US letter paper -- 8.5 x 11
14
15-- Interface notes .....
16---- Evidently PageCount, SourceWidth, and SourceHeight are
17---- passed to us from the C++ program when we are called.
18---- Evidently we are required to provide values for
19---- PageWidth, PageHeight, and Scale ... which are used by
20---- the C++ program after we return.  Scale defaults to 1.
21----
22---- Note that these Page-related names are unfortunate,
23---- because they do *not* correspond to the pages as defined
24---- by the source, or to the pages in the final booklet.
25---- Really PageHeight should be called SheetHeight and
26---- PageWidth should be called SheetWidth or something
27---- like that.
28----
29---- Note that we calculate our offsets and margins in
30----_real_ units, not scaled units.  That is significant
31---- PushRecord will scale its arguments, so we will need
32-----to descale the offsets in the call to PushRecord.
33
34-- Useful units, measured in local units (i.e. postscript points):
35inch = 72
36mm = inch / 25.4
37
38PageWidth = 8.5*inch
39PageHeight = 11*inch
40
41-- Turn on TopMode if you want to print the top side of each sheet
42-- Turn on BottomMode if you want to print the bottm side of each sheet
43-- Turn on TopMode and BottomMode if you want both, as for a duplex printer
44TopMode = 1
45BottomMode = 1
46-- Turn on BoStack if your non-duplex printer has the property
47-- that the first thing printed winds up at the bottom of the
48-- stack, face up.
49BoStack = 0
50
51print("PageCount",PageCount)
52
53-- Note that we need to distinguish
54----    the hw margins need to keep the printer happy
55----    the /added/ margins we need to apply here.
56-- Worst case is when the source
57-- material bleeds right to the edge of its bounding box.
58-- Conversely, if the source material has a lot of margin
59-- already built into it, we may not need any /extra/ margin
60-- at all, and we could set UsableHeight = PageHeight here.
61-- Similarly if Ydelta/2 is larger than the hwBottomMargin
62-- we shouldn't need to add any /add/ margin.
63
64hwTopMargin = 0.1*inch
65hwBottomMargin = 0.5*inch
66hwLeftMargin = 0.1*inch
67hwRightMargin = 0.1*inch
68
69srcMargin = 0
70addTopMargin = math.max(0, hwTopMargin - srcMargin)
71addBottomMargin = math.max(0, hwBottomMargin - srcMargin)
72addLeftMargin = math.max(0, hwLeftMargin - srcMargin)
73addRightMargin = math.max(0, hwRightMargin - srcMargin)
74
75-- When calculating wiggle room, assume paper will be used
76-- symmetrically.  This is a nontrivial assumption, since
77-- e.g. we could use a paper cutter to chop off one edge
78-- and not the other ... but that would be beyond the
79-- scope of this analysis.  Symmetry means that if we
80-- apply a margin to the recto page, we must apply the
81-- same margin to the verso page, even if the hardware
82-- would not require it.  Hence the factors of 2 here:
83
84UsableHeight = PageHeight - 2*addTopMargin - 2*addBottomMargin
85UsableWidth = PageWidth - 2*addLeftMargin - 2*addRightMargin
86
87if(SourceWidth <= SourceHeight)
88then
89        Scale = math.min(UsableHeight / (2*SourceWidth), UsableWidth / SourceHeight)
90        rot = 90
91        Ywiggle = 0.5 * math.max(0,  UsableHeight - 2*SourceWidth*Scale)
92        Xwiggle =       math.max(0,  UsableWidth - SourceHeight*Scale)
93        fudge = addTopMargin + 2*(addBottomMargin + Ywiggle)
94-- Apply a factor of /2 to Xwiggle here,
95-- because we want centering
96-- (not flush to right of sheet, i.e. bottom of page):
97-- Do not apply corresponding factor to Ywiggle, because
98-- we do want flush to top of sheet, i.e. right of page:
99        xof = addLeftMargin + SourceHeight*Scale + Xwiggle/2
100        yofRtop = SourceWidth*Scale + fudge
101        yofRbot = SourceWidth*Scale + fudge
102        yofVtop = addBottomMargin + Ywiggle
103        yofVbot = addBottomMargin + Ywiggle
104else
105        Scale = math.min(UsableHeight / (2*SourceHeight), UsableWidth / SourceWidth)
106        rot = 0
107        Ywiggle = 0.5 * math.max(0,  UsableHeight - 2*SourceHeight*Scale)
108        Xwiggle =       math.max(0,  UsableWidth - SourceWidth*Scale)
109        fudge = addTopMargin + 2*(addBottomMargin + Ywiggle)
110        xof = addLeftMargin + Xwiggle/2
111        yofRtop = SourceHeight*Scale + fudge
112        yofRbot = SourceHeight*Scale + fudge
113        yofVtop = addBottomMargin + Ywiggle
114        yofVbot = addBottomMargin + Ywiggle
115end
116
117do
118        rest = PageCount % 4
119        totp = PageCount
120        if rest ~= 0
121                then
122                totp = totp + ( 4 - rest)
123                end
124-- "inc" counts input pages skipped as well as pages actually used:
125        inc = 0
126-- "outc" counts output pages:
127        outc = 0;
128        count = 0
129        imax = totp/4
130        middle = totp/2
131        while count < imax
132                do
133--              We assume that podofoimpose will discard invalid records
134--              such as those with source page greater than PageCount
135--              print(totp, inc, outc, rot, xof, yofRtop, yofVtop, yofRbot, yofVbot)
136-- Top of sheet:   (8 1) ... (6 3)
137                if TopMode ~= 0
138                    then
139-- We did all the interesting calculations in real units (above).
140-- We convert to nasty descaled units at the last moment:
141                    PushRecord(totp - inc, outc + 1, rot, xof/Scale, yofVtop/Scale)
142                    PushRecord(inc + 1, outc + 1, rot, xof/Scale, yofRtop/Scale)
143                    outc = outc + 1
144                    end
145-- Bottom of sheet:
146                if BottomMode ~= 0
147                    then
148                    if BoStack ~= 0
149                        then
150-- Reversed bottom: (4 5) ... (2 7)
151                        PushRecord(middle - inc, outc + 1, rot, xof/Scale, yofVbot/Scale)
152                        PushRecord(middle + 1 + inc, outc + 1, rot, xof/Scale, yofRbot/Scale)
153                        else
154-- Normal bottom: (2 7) ... (4 5)
155                        PushRecord(inc + 2, outc + 1, rot, xof/Scale, yofVbot/Scale)
156                        PushRecord(totp-(inc + 1), outc + 1, rot, xof/Scale, yofRbot/Scale)
157                        end
158
159                    outc = outc + 1
160                    end
161
162                count = count + 1
163                inc = inc + 2
164                end
165end
166