How to convert an A4 size PDF to a PDF booklet?

Tags: merge documentsbookletN-upiText 5The best questions on stack overflow

I need a variation on the example given in answer to the following question: How to convert an existing A4 PDF document to an A3 booklet? I have more or less the same requirement, but I don't want the consecutive pages to appear side by side on the same page. I want page 4 and 1 on one page and page 2 and 3 on another page. So, when I print these pages on single sheet of paper, I can fold that paper into a booklet with page 2 on the back of page 1 and page 4 on the back of page 3.

Posted on StackOverflow on Dec 23, 2015 by Anil Kumar

When a book is printed, the machines that print the pages actually print on much larger pages, and that larger page is then usually cut and folded. You'll see that most books have a total number of pages that is dividable by 16. For instance, when I wrote my "iText in Action" books, extra pages with advertisements for other books were added so that the total number of pages would be a multiple of 16.

This shows how pages are typically printed:

How book pages are printed
How book pages are printed

(The image was taken from a blog entitled "Page counts explained")

We can easily convert a document with A4 pages to a document with pages 8 times the size of A4, where we add 8 pages of the original document to a single page in the new document, organized the way is shown in the above image. This is done in the MakeBooklet example:

public void manipulatePdf(String src, String dest)
    throws IOException, DocumentException {
    // Creating a reader
    PdfReader reader = new PdfReader(src);
    // step 1
    Rectangle pagesize = new Rectangle(
        PageSize.A4.getWidth() * 4,
        PageSize.A4.getHeight() * 2);
    Document document = new Document(pagesize);
    // step 2
    PdfWriter writer
        = PdfWriter.getInstance(document, new FileOutputStream(dest));
    // step 3
    document.open();
    // step 4
    PdfContentByte canvas = writer.getDirectContent();
    float a4_width = PageSize.A4.getWidth();
    float a4_height = PageSize.A4.getHeight();
    int n = reader.getNumberOfPages();
    int p = 1;
    PdfImportedPage page;
    while ((p - 1) / 16 <= n / 16) {
        addPage(canvas, reader, p + 3, 0);
        addPage(canvas, reader, p + 12, a4_width);
        addPage(canvas, reader, p + 15, a4_width * 2);
        addPage(canvas, reader, p, a4_width * 3);
        AffineTransform at = AffineTransform.getRotateInstance(-Math.PI);
        at.concatenate(AffineTransform.getTranslateInstance(0, -a4_height * 2));
        canvas.saveState();
        canvas.concatCTM(at);
        addPage(canvas, reader, p + 4, -a4_width);
        addPage(canvas, reader, p + 11, -a4_width * 2);
        addPage(canvas, reader, p + 8, -a4_width * 3);
        addPage(canvas, reader, p + 7, -a4_width * 4);
        canvas.restoreState();
        document.newPage();
        addPage(canvas, reader, p + 1, 0);
        addPage(canvas, reader, p + 14, a4_width);
        addPage(canvas, reader, p + 13, a4_width * 2);
        addPage(canvas, reader, p + 2, a4_width * 3);
        canvas.saveState();
        canvas.concatCTM(at);
        addPage(canvas, reader, p + 6, -a4_width);
        addPage(canvas, reader, p + 9, -a4_width * 2);
        addPage(canvas, reader, p + 10, -a4_width * 3);
        addPage(canvas, reader, p + 5, -a4_width * 4);
        canvas.restoreState();
        document.newPage();
        p += 16;
    }
    // step 5
    document.close();
    reader.close();
}
 
public void addPage(PdfContentByte canvas, PdfReader reader, int p, float x) {
    if (p > reader.getNumberOfPages()) return;
    PdfImportedPage page = canvas.getPdfWriter().getImportedPage(reader, p);
    canvas.addTemplate(page, x, 0);
}

In the manipulatePdf() method, we create a loop in which we add 2 pages. On each page, we add 8 pages of the original PDF, but we add these on very specific places. For the bottom row of 4 pages, we introduce a translation (we move a4_width to the right for every new page). Then we introduce a rotation to add the top row of pages (they need to be upside-down).

That's fun isn't it? Actually, it's just a matter of Math (and Math is always fun). You can find the result here: book16.pdf

Your question is less fun because it's so simple. You don't even need to rotate your pages! Take a look at the MakeBookletA3 example:

public void manipulatePdf(String src, String dest)
    throws IOException, DocumentException {
    // Creating a reader
    PdfReader reader = new PdfReader(src);
    // step 1
    Rectangle pagesize = new Rectangle(
        PageSize.A4.getWidth() * 2,
        PageSize.A4.getHeight());
    Document document = new Document(pagesize);
    // step 2
    PdfWriter writer
        = PdfWriter.getInstance(document, new FileOutputStream(dest));
    // step 3
    document.open();
    // step 4
    PdfContentByte canvas = writer.getDirectContent();
    float a4_width = PageSize.A4.getWidth();
    int n = reader.getNumberOfPages();
    int p = 1;
    PdfImportedPage page;
    while ((p - 1) / 4 <= n / 4) {
        addPage(canvas, reader, p + 3, 0);
        addPage(canvas, reader, p, a4_width);
        document.newPage();
        addPage(canvas, reader, p + 1, 0);
        addPage(canvas, reader, p + 2, a4_width);
        document.newPage();
        p += 4;
    }
    // step 5
    document.close();
    reader.close();
}
 
public void addPage(PdfContentByte canvas,
        PdfReader reader, int p, float x) {
    if (p > reader.getNumberOfPages()) return;
    PdfImportedPage page = canvas.getPdfWriter().getImportedPage(reader, p);
    canvas.addTemplate(page, x, 0);
}

Now we only create 2 pages in the loop, and we add 2 old pages to every new page. The result: book4.pdf