There are occasions when you might want to print more than one page of a PostScript document on a piece of paper. For example, you may have a collection of slides for a presentation, and you may want to print them out in condensed form for a kind of digest hand-out. This kind of printing, where two pages are printed side-by-side on a piece of paper is called “two-up,” for the two pages facing up. This idea generalizes readily to any number of pages (though, of course, legibility goes down quickly as the number of pages goes up). In its general form, it is called “n-up.”
What is necessary to print in two-up mode? First, we need to translate and rotate each page into the right location of the page, then we need to make sure that the page fits in the new area reserved for it (we will need to scale it down to about half its original size). If we place the two pages side by side, we will get proper two-up form.
The code I will present here will place the odd pages on the left (as you’re looking at the page in landscape orientation) and the even pages on the right. You could do it the other way around, if that makes more sense to you.
Here is the code we must wrap around the odd pages:
gsave 504 30 translate % Position page in middle of region 90 rotate % Aim it in the right direction .5 .5 scale % make it small enough % original page code here... grestore
And here is the code for the even pages:
gsave 504 426 translate % Position page in middle of region 90 rotate % Aim it in the right direction .5 .5 scale % make it small enough % original page code here... grestore
Now, you will notice that I used some curious numbers in the translate command. The reason I chose these particular numbers was that I wanted to center each page in its half of the page. I knew I was going to scale by 0.5, so I computed how much white-space was left and added in the appropriate fudge-factor to center the pages.
You may also notice that I wrap a gsave and a grestore around the page and the additional code? The reason for this is that each page must leave the state of the printer unchanged when it has been printed. If you permanently change the state, that state change will be in affect for all subsequent pages. By following this rule, you make the pages independent of order. Some print servers must shuffle page order in order to print the document correctly; since my pages are independent (at least as far as my code is concerned), they will print correctly.
Now comes the hard part of recognizing where the pages begin. The technique is essentially the same as what we used for galley proofs, so I will spare you the logic here. Essentially, we will look for %%Page: comments. We will, however, need to keep track of whether the current page is an odd page or an even page and insert the correct translation code. Also, as before, we must be careful about inserting grestores before subsequent pages and before the %%Trailer or %%EOF comments.
Here is the PERL script to do the job:
#!/usr/local/bin/perl $flag = 0; # We have not yet found a page $even = 0; # First page is an odd page $page = 1; # Start at page #1 $pages = 1; # Allow %%Pages comment while (<>) { if (/^%%Pages:/ && $pages) { print "%%Pages: (atend)\n"; $pages = 0; } elsif (/^%%Page:/) { # We have found a page if ($flag) { print "restore\n"; # restore if it isn't the first } $flag = 1; if ($even) { # Translate for even pages print "save\n"; # gsave print "504 426 translate\n"; $even = 0; $page++; } else { # Translate for odd pages printf("%%%%Page: %d %d\n", $page, $page); print "save /showpage {} def\n"; print "504 30 translate\n"; $even = 1; } # Code to rotate and shrink print "90 rotate .5 .5 scale\n"; } elsif (/^%%Trail/) { # Cleanup if a %%Trailer is found if ($flag) { print "restore\n"; } print $_; printf("%%%%Pages: %d\n", $page); $flag = 0; } elsif (/^%%EOF/) { # Cleanup if an %%EOF is found if ($flag) { print "restore\n"; } print $_; $flag = 0; } else { print; } }
Note the basic similarity with the script for the galley proofs. There are some additions, however. Because we are taking two pages and printing them on one page, we need to modify the page numbers. The %%Pages: comment specifies how many pages are in the document. If you specify "%%Pages: (atend)", you are specifying that you do not know the exact number of pages, but you will give the information later.
An additional complication is the use of save
and restore rather than gsave
grestore. These operators save the
entire state of the printer and restore it just as gsave and grestore
work with the graphics state. In fact, an implicit gsave is done
by save; and an implicit grestore is done by restore. The reason these
are used is so that I can redefine showpage
to a do-nothing procedure (/showpage {} def
) for the odd pages.
This trick prevents the page from being ejected when the odd page does
its end of page routines. Unfortunately, this trick only works if the document
calls showpage by name. If the document bound showpage up or calls some
of the lower level operators, this program would need to be more sophisticated.