Table of Contents
PaperJam is a tool for transform PDF files. It can re-order pages, scale and rotate them, put multiple pages on a single sheet, draw cropmarks, and many other tricks.
PaperJam takes an input file, splits it to a list of pages, applies a sequence of commands on this list, and finally writes the results to an output file.
For each page, PaperJam tracks two sets of dimensions: the width and height of the physical page (paper), and the image box, which is a rectangle on the physical page containing all useful contents. Initially, the physical page is equal to the CropBox of the PDF page and the image box to its ArtBox (which is optional and it defaults to the CropBox). Further commands can modify these dimensions.
PaperJam takes a list of commands separated by spaces, like this:
paperjam 'common scaleto("a4") nup(2, hspace=5mm)' in.pdf out.pdf
Each command starts with its identifier (a sequence of alphanumeric characters, underscores, and dashes, which begins with a letter). Then come arguments enclosed in parentheses. All arguments can be written as name=value (where the name is an identifier). For some of them, the name can be omitted and the meaning follows from the position in the argument list (hence these are called positional arguments).
There are several types of arguments:
Several commands apply other commands on a subset of pages. This is usually described by a pipeline like:
{ 1: rotate(90), 2: flip(h) flip(v) } { 1..10: common } { 1 2, 11..20, 30..21 }
The pipeline is enclosed in curly braces. It consists of one or more stages separated by commas. Each stage has one or more page selectors (page numbers or ranges) and an optional list of commands to apply on these pages (separated from the selectors by a colon).
When a range is written backwards (the first page number is greater than the second one), the pages are processed in reverse order.
When a paper format is expected, it is given either by its width and height
(the corresponding arguments are usually called w and h), or by the standard
name of the format (called paper). PaperJam currently uses the libpaper library
for parsing the names. You can call paperconf -a
to get the list of known names.
Many commands take a specification of margins on all sides of an image. You can set either a common value for all margins, or two values for vertical and horizontal margins, or separate values for all margins. You can also combine these ways: for example you can set a horizontal, top, and bottom margin.
More formally, there are 7 arguments controlling margins: common, horizontal, vertical, left, right, top, and bottom. Horizontal and vertical default to common, left and right default to horizontal, top and bottom default to vertical.
Multiple commands involve positioning an image on a larger page. The image is placed according to a two-letter position specification (usually an argument called pos). The first letter specifies vertical placement: t for top, c for center, b for bottom. The second one horizontal placement: l for left, c for center, r for right.
PaperJam knows the following commands and arguments. Positional arguments have their names enclosed in square brackets.
Add blank page(s) after each page.
Applies commands on a sub-set of pages:
apply { 1: rotate(90), 2: flip(h) }
Takes a pipeline. For each input page, it finds the pipeline stage matching the page index (its position in the input document, starting with 1) and applies the commands in the stage on the page. If no stage matches, the page is left unchanged. If multiple stages match, the first one wins.
Prepares booklets (also known as signatures) for book binding. With no argument, it re-orders pages in the document, so that a subsequent nup(2) produces the correct booklet layout: two pages on one sheet and when the document is printed double-sided and folded in half, you have a booklet. If the number of input pages is not divisible by 4, blank pages are added.
Suppress page contents drawn outside the image box.
Use a common page size and image box for all pages. More specifically, the new page width and height are set to the maximum of all page widths and heights and the new image box to the minimal rectangle containing all image boxes.
Draw cropping marks around the image box.
000000
(black).
Draw debugging information on each page: a red rectangle around the page, a green rectangle around the image box.
Expand paper around the image. Recalculates paper size and the position of the image on the paper, so that the distance between each edge of the image box and the corresponding edge of the paper increases by the given amount.
If a paper size is given, scale and translate the image to fit on the paper (with given margins). If no paper is given, set the paper size and the position of the image according to the margins.
If the paper and the image have different aspect ratios, the pos argument controls the position of the image on the paper.
Flip pages horizontally or vertically.
Define a new image box by dimensions of margins around it. More technically, the new image box is calculated from the page box by shrinking it by the appropriate margin on each side.
Merge all pages to one by placing them one over another. (The first page is drawn first.)
Act on n-tuples of pages. The document is split to n-tuples (the partial n-tuple at the end is padded with blank pages, whose size matches the first page of the n-tuple). A pipeline is then run separately for each n-tuple, selecting pages from the tuple and applying commands on them.
More specifically, the stages of the pipeline are processed from the left to the right. Each stage forms a temporary document by taking the selected pages from the n-tuple (numbered from 1 to n). Then it applies the commands on this document and appends the result to the end of the output of the whole modulo.
Negative page numbers can be also used, which adresses pages in the "mirror-image tuple". Page number -i in tuple j corresponds to page i in the j-th tuple from the end of the document.
Arguments:
For example, the following command rotates every other page:
modulo(2) { 1, 2: rotate(180) }
While this command skips every other page:
modulo(2) { 1 }
Shift contents on the page. Paper size does not change, the image box moves.
Combine multiple pages to one (n-up printing). Allows detailed control over the parameters, but if only a subset of the parameters is given (in the most trivial case, just the number of pages to put on a single sheet), the remaining parameters are adjusted to maximize coverage of the sheet.
For example, when the input document is typeset on A4 paper,
nup(2)
rotates pages by 90 degrees, scales them to 70.7% size,
and puts them side-by-side. On the same input, nup(4)
produces
the same as nup(2,2)
, that is a two-by-two grid of pages scaled
to 50%.
Technically, nup first splits the input document to n-tuples of pages (padding the last incomplete n-tuple with blank pages of the size of the first page of that n-tuple). For each n-tuple, it creates an output page, splits it to a grid-like arrangement of tiles, and scales and/or rotates each page to fit in its tile.
Place image on a given paper. Sets a new paper size and translates the image box according to the given position.
Rotate the page clockwise by multiples of 90 degrees.
Scale the page by a given factor.
Scale the entire page to a given size.
Selects a subset of pages and optionally applies commands on them.
The select command gets a pipeline. It processes the pipeline stages from the left to the right. For each stage, it assembles a temporary document containing the selected pages, applies the stage’s commands on it, and appends the resulting document to the output of the whole select command.
For example, the following command selects pages 1, 10 to 19, and 20 to 29 in reverse order. The rest of the document is discarded.
select { 1 10..19 29..20 }
This has the same effect:
select { 1, 10..19, 29..20 }
This selects two pages and rotates them differently:
select { 1: rotate(90), 2: rotate(-90) }
The following examples show that the formation of temporary documents can make a difference sometimes:
select { 1..10 common, 21..30 common } select { 1..10 21..30 common } select { 1..10 21..30 } common select { 1..10, 21..30 } common
The first command forms two temporary documents and applies common to each of them separately (therefore pages 1 to 10 will have one common size and pages 21 to 30 another). The remaining three commands give the same result. The second command forms a single temporary document with 20 pages and applies common to all of it at once. The third command forms a single temporary document, which immediately becomes the result of select, to which the final common is applied. And the fourth command forms two temporary documents, concatenates them to the result of select, and finally applies common.
Slices the image to several smaller pages. Each page receives a part of the original image, gluing the parts together produces the original image.
PaperJam was written by Martin Mares. It can be distributed and used under the terms of the GNU General Public License version 2 or any later version.
I conceived the idea of a document processor like PaperJam when struggling with pre-press formatting in the early 2000s. At that time, the basic ideas behind the language were born, but everything was deeply rooted in the then standard PostScript world. After some years, I managed to convince a student of mine Ales Snuparek to implement my ideas as his bachelor’s project. He wrote the program PsPdfTool for transforming both PostScript and PDF documents, which turned out to be terribly useful.
In the 2010s, limitations of the old design became clear and many PDF documents were using features not known to PsPdfTool (most prominently object streams). After several years of pondering, I became fond of the QPDF library and wrote PaperJam as a modern successor of PsPdfTool.