Skip to content
huzpsb edited this page Oct 25, 2026 · 1 revision

N-Up

Rearrange existing PDF pages (or images) into page grids — 2, 3, 4, 8, 9, 12 or 16 pages per sheet. The classic print-handout command; input page size is preserved.

n portrait landscape
2 1x2 2x1
3 1x3 3x1
4 2x2 2x2
8 2x4 4x2
9 3x3 3x3
12 3x4 4x3
16 4x4 4x4

Command line

pdfcpu2 nup [description] outFile n inFile | imageFiles...

<description> — defaults "di:595 842, form:A4, or:rd, bo:on, ma:3, enforce:on":

Entry Meaning
dim: / form: target sheet size (only one allowed; see Paper)
o: orientation rd right-down (default), dr, ld, dl — PDF input only
enforce: best-fit orientation of individual content
bo: border draw cell borders (default on)
ma: margin content margin in display units
pdfcpu2 nup out.pdf 4 in.pdf                      # 2x2 handout, A4
pdfcpu2 nup out.pdf 6 in.pdf --pages=3-           # pages 3.. into 3x2 grids
pdfcpu2 nup out.pdf 9 logo.jpg                    # 3x3 grid of one image
pdfcpu2 nup 'form:Tabloid' out.pdf 4 *.jpg        # images on Tabloid sheets
cat handout.pdf | pdfcpu2 nup - 4 - > handout4.pdf

Go API

package main

import (
	"context"

	"github.com/huzpsb/pdfcpu2/pkg/api"
	"github.com/huzpsb/pdfcpu2/pkg/pdfcpu/model"
)

func main() {
	ctx := context.Background()
	conf := model.NewDefaultConfiguration()

	// n + description string, like the CLI
	nup, err := api.PDFNUpConfig(4, "form:A4", conf)
	if err != nil {
		panic(err)
	}

	err = api.NUpFile(ctx, []string{"in.pdf"}, "out.pdf", nil, nup, conf)
	if err != nil {
		panic(err)
	}

	// Image input variant
	nupImg, _ := api.ImageNUpConfig(9, "", conf)
	_ = api.NUpFile(ctx, []string{"logo.jpg"}, "grid.pdf", nil, nupImg, conf)
}

Related: Grid (poster-style browsing grids), Booklet (imposition for binding).

Clone this wiki locally