How to make impositions with pstops

If you don't know what an imposition is you can have a look at this page.

Note that you must normally design the imposition before you try to lay it out. If you fold the sheets yourself, just fold a sheet into a booklet, number the pages and unfold. There's your imposition. If the printer or book binder will fold for you, ask them for the imposition.

Pstops is a program that is part of psutils by Angus Duggan. Pstops is used to transfer pages from one PostScript file to another with the possibility to scale, rotate and relocate the pages and also collect several pages from the input file onto one page of the output file. And this is exactly what we want to do when doing an imposition.

Psutils also contains some other utilities that can perform simpler tasks, for example psbook, psnup and psresize, but pstops can do anything they can and some more.

The syntax for using pstops is pstops  where the pagespecifications is the key to how it works. We'll take a look at how they are built.

Pstops works with blocks of pages, the number of pages within each block (called "modulo" in the manpage for pstops) is specified as the first part of the page specifications. For example pstops 8:... will split the input file into blocks of 8 pages each.

Example for a 29 page file:

Page 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

Block |-1---|---2---|--3|---4-|

As you can see the last block only contains five pages. It's three pages short. We will refer to these three pages as (30), (31) and (32) where the paranthesis indicates that the page is "virtual". (I'm not sure if pstops will insert blank pages or just ignore them, the result of the output file is the same as if there had been blank pages.)

Pstops will process the file one block at a time, the page specifications will be repeated once for each block.

For each block pstops will then index the pages starting with zero and up to modulo-1, so we will get:

Index 0 1  2  3  4  5  6  7  0  1  2  3  4  5  6  7  0  1  2  3  4  5  6  7  0  1  2  3  4

Page 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

Block |-1---|---2---|--3|---4-|

and the empty pages (30), (31) and (32) will get index 5, 6 and 7. (That the index starts at zero is a real pain, as you probably will find out when you do this yourself.)

Now, for each page within the block we can scale, rotate and displace it. This will be done in the postscript workspace where the center (0;0) is the lower left corner of the page. Regardless the order on the command line the page will first be scaled, then rotated and/or shifted (as applicable); in that order.

For rotation we can use L (left), R (right) and U (upside-down). To rotate page 2 (index 1) to the left we continue our example command line pstops 8:1L...

Note that the rotation will be done around the center of the postscript coordinate system; the lower left corner. Rotating to the left will make the page end up landscape just to the left of the working space (thus outside the output page), we will have to move it to the right to get it back. Rotating to the right will make the page end up just below the working space (and outside the output page) so we will have to move it upwards to get it back. We will get to this relocation soon, but before that there is another parameter.

Note that pstops can not rotate the page in smaller angles than 90 degrees. (But since it uses postscript transformations to do the rotation the code could probably be changed to handle smaller angles.)

This next parameter is for scaling, indicated by the @ character. @0.7 for example means 70% scaling. For example pstops 8:1L@0.7.... Note that the scaling will take place before rotation, even though it comes after rotation on the command line.

Now it's time for the relocation, it is done with.

If we scale a page from A4 to A5 (using @0.7) and rotate it to the left we will have to move it to the right (positive X-axis) by the height of an A5 page (which is the same as the width of an A4 page). The height and width of the page can be referred to with letters "h" and "w" in the reloacting part. Note that this height and width is for the output page size (sheet size), the output page size can be specificed with the -p option but otherwise it is the same as the input page size (before any scaling). So by using -pa4 we can make sure that w means 210 mm and h means 297 mm.

We needed to shift our page 210 mm to the right, this means (1w,0). The complete specification this far would now be pstops -pa4 8:1L@0.7(1w,0) meaning "take the second page in the block, scale it 70%, rotate it to the left (counter clockwise) and move it back onto the page".

Note that for an 8 page imposition the above is not be what we would want to do, this example is more suitable for a 4-page imposition so we change the modulo from 8 to 4 from here on.

Some additional notes on the relocation. Using w and h as units give quite a coarse adjustment. Also, if the height and width of the pages are not multiples of the height and width of the sheets (like on the A-series papers) you can not use it but must use PostScript points, centimeters or inches, for example pstops -pa4 4:1L@0.7(21.0cm,0) would give the same result as above. This is also needed if you want to adjust for creep and similar.

The next page on this side of the sheet is added with a + sign (meaning it will end up on the same page in the output), for example pstops -pa4 4:1L@0.7(1w,0)+2L@0.7(1w,0.5h)...

A comma as separator will start on a new page in the output file, thus when we are finished with the front of the sheet we use a comma instead of + before the first page of the back.

pstops -pa4 4:1L@0.7(1w,0)+2L@0.7(1w,0.5h),0R@0.7(0,1h)+3R@0.7(0,0.5h)

Note that the order of pages within one output page is not critical, it does not matter in which order the pages are processed since they are each handled separately.

When I built command lines by hand I used an approach like this:

Page 1 0R(0,1h) + Page 4 3R(0,0.5h) , Page 2 1L(1w,0) + Page 3 2L(1w,0.5h)

just to make sure I was consistent in relocation and didn't mix page numbers with page indexes (remember, first page is not index 1 but index 0).

Below are some examples of impositions. Note that you may have to quote the page specifications depending on the shell you use.

Examples to be inserted
Note that all of the above examples are made for duplex printing with sheets turned over along the long edge. If your printer can not handle duplex just make one run for the front of the sheets and a second for the back (split the page specifikation at the comma, that is make one run with the part before the comma for fronts and one run with the part after the comma for backs).

If your printer does tumbling instead of turning duplex you can either adjust the imposition or use pstops to rotate the even pages of the file pstops 2:0,1U(w,h) infile.ps outfile.ps. This example will turn every second page upside down.

If you need to do manual duplex and depending on if your printer takes papers from the top or the bottom you might need to first print the odd pages reverse and then the even pages forward to avoid having to rearrange the pages between printing front and back.

Psselect can be used to select even and odd pages in forward or reverse order (see manpage for psselect). Of course pstops can do the same, but the syntax for psselect is easier.

Now there is a feature we have yet not looked at: Reverse page referral. What does that mean then?

Well, by using a - sign before the page index you will not get the page from the current block but the "opposite" block. Let's look at our sample file again.

Index 0 1  2  3  4  5  6  7  0  1  2  3  4  5  6  7  0  1  2  3  4  5  6  7  0  1  2  3  4

Page 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

Block |-1---|---2---|--3|---4-|

When processing block 1 (pages 1-8), if you use page index 2 you will get page 3. But if you use page index -2 you will get page 27!

And when processing block number two the same references will get you page 11 and page 19.

Note: If the number of blocks is odd there will be no difference for the block in the middle.

This can be used for special cases, like for example for making a magazine. If you are going to make a 16 page magazine from the example file

Index 0 1  2  3  0  1  2  3  0  1  2  3  0  1  2  3

Page 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16

Block |1|-2-|-3-|-4-|

You would use four 4-page signatures inserted into eachother. The "outer" signature should have pages 1, 2, 15 and 16. Well, by selecting page indexes 0, 1, -2 and -3 you will get those pages. For the second you should have pages 2, 3, 13 and 14. Well, just select 2, 3, -0 and -1.

One glitch though is that with this setup you will get twice the number of pages you want, because you will process pages from each block twice. For the first block you take pages 1 and 16 for one side, 2 and 15 for the other, but then you will have to take also pages 3 and 4 from that block and 13 and 14 from the last block. This means you will make two sheets while processing each block.

But that can be prevented by using 2-page blocks!

Index  0  1  0  1  0  1  0  1  0  1  0  1  0  1  0  1 Page   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16

Block |--1--|--2--|--3--|--4--|--5--|--6--|--7--|--8--|

Page 1 & 16 means index 0 and -1 Page 2 & 15 means index 1 and -0 Page 3 & 14 means index 0 and -1 Page 4 & 15 means index 1 and -0

(Before I found this out I used the previous approach and used psselect to select half of the pages.)

Now, doing all these calculations by hand is time consuming, and very prone to small errors. You will most likely need a "dummy" file to test on. I have made a small perl script called mkpsfile to make such a dummy file. It takes two parameters, number of pages and optionally the page size (default is A4). The page size can be custom defined in postscript points. The script will print a box around each page and a large page number. The margin for the box is by default 20 points from the edge but that can be changed with the switch -m.

You can find mkpsfile here.

To make things even easier I wrote a script called impose that can do many kind of impositions. The impositions are defined in separate files, thus you can have any number of impositions and name them whatever you want.

Impositions are defined by a grid. You define the number of rows and columns and for each cell you tell which page goes there (both on front and back of the sheet), how it shall be rotated (left, right, upsidedown), adjusted within the cell (NW, NE, SE, SW) and you may also specify how much creepage it shall be adusted for and in what direction ("llldd" means adjust 3 times defined creepage to the left and 2 times down). All impositions are designed for sideways turning of the sheet, but as mentioned above pstops can be used to rearrange the file for tumbling.

Here's a link to impose and the template for impositions.

Two sample impositions: 16-page imposition and two eight page sheets inserted.

When doing an imposition you tell impose which imposition to use, the sheet size and the input file. Impose will try to get the page size from the input file (it will use the %%BoundingBox comment, when using pslatex it always matched the page size but I've realised that's not always true) and will calculate the correct page positions according to imposition, pagesize, sheetsize and defined creepage amount.

From impose you get an output file ready for duplex printing, although the file has no signature numbers or spine collation bars (which are handy when gathering the signatures). There is a third script, sign, that can add signature numbers and collation bars. The location of those are defined in the imposition, so from the input file, the used imposition and the printer margin (to offset the signature number so it will be visible) it will sign the pages. It will only sign the odd pages so you have to design impositions where the marks shall be on the front side.

Here's the sign script.

As a final adjustment before printing you can use a command line like pstops 2:0(xoff_front,yoff_front),1(xoff_back,yoff_back) to adjust the file for printer misalignment. To find out the misalignment you should print 3-4 sheets and find out an average, since most printers are not consistent in the sheet feed.

Since pstops can not rotate smaller increments than 90 degrees we can not compensate for pages that get slightly tilted during folding.

Now we have tools to handle many kinds of impositions, but not all. For some kind of impositions the impose and sign scripts do not work. When impose doesn't make it we'll have to make up the page specifications by hand, and for signing strange impositions we might need to modify the sign script.

In some cases you might want signatures of different sizes in a book, for example you might be able to print A3 on a laserprinter but only A4 on your color inkjet. If you then want some pages in color you would need to make some signatures on A4 sheets but the majority on A3. Using psselect you can modify you original input document and split it into two parts. If you extract 4 pages for a 4-page signature you will have to insert 8 blank pages to get an empty 8-page signature there. When printing you can skip the "empty" signature (using psselect) after signing.

Some of the scripts have a bit of a hairy command line, however they are really not intended to be used as is. You would normally wrap them into a shell script.

Additional note: There is a patch for pstops that can make the relocation sheet dependant. It would be suitable for creep adjustment when doing for example a magazine imposition (you would then be able to adjust creep differentely for each sheet). You can find the patch here.

Any improvements to my scripts are welcome. I learned parameter and option parsing as I wrote these scripts. And I'm no programmer, nor am I very good at perl. Maybe perl isn't the best language for this stuff, but the scripts work for me.

Improvements I know would be good:


 * Include support for all ghostscript standard page sizes (mkpsfile and impose)
 * Consistent use of options
 * Better parsing to find page size of input file (impose)
 * More options for sign script (font size, bar width, number of steps)

Contributed by Peter Nermander