@junglo/impose
v0.1.0
Published
PDF imposition SDK: impose(pdfBytes, options) → print-ready saddle-stitch booklets and folded signatures. Pure TypeScript, pdf-lib only, runs in browser/Bun/Deno/Node.
Maintainers
Readme
@junglo/impose
PDF imposition as a pure function: impose(pdfBytes, options) → booklet PDF.
Takes PDF bytes from any source and returns an imposed PDF — pages reordered and placed N-up so they read in order after duplex printing and folding. Saddle-stitch booklets up to print-shop signature sheets (e.g. 70×100 cm). No I/O, no global state, no server: runs in the browser, Bun, Deno and Node with a single runtime dependency (pdf-lib). Vector content passes through untouched — nothing is rasterized.
PDF generation is deliberately out of scope: produce your PDF with anything (Paged.js, a layout tool, an export button) and pass the bytes in.
Install
bun add @junglo/impose # or npm/pnpm/yarnUse
import { impose } from "@junglo/impose";
const result = await impose(pdfBytes, {
mode: "saddle", // fold the whole stack once (zine style)
sheet: "A4", // A4 | A3 | Letter | { width, height, unit }
pagesPerSide: 2, // 2 | 4 | 8 | 16
flip: "short-edge", // duplex flip your printer will use
});
result.pdf; // Uint8Array — print-ready
result.sheets; // physical sheets of paper
result.blanksAdded; // padding pages appended to fill the last sheet
result.layout; // page→slot map: drive a preview UI without renderingBrowser (e.g. behind a "print as zine" button — all client-side):
const bytes = new Uint8Array(await file.arrayBuffer());
const { pdf } = await impose(bytes, { mode: "saddle", sheet: "A4", pagesPerSide: 2, flip: "short-edge" });
const url = URL.createObjectURL(new Blob([pdf], { type: "application/pdf" }));Preview without rendering — the pure core is exported separately:
import { computeOrder } from "@junglo/impose";
// Zero pdf-lib involved: just math. Ideal for live UI estimates.
const layout = computeOrder(20, { mode: "saddle", pagesPerSide: 2, flip: "short-edge" });
// layout[0].front → [{ slot: 0, page: 20, rotation: 0 }, { slot: 1, page: 1, rotation: 0 }]Options
| Option | Values | Notes |
|---|---|---|
| mode | saddle | signature | saddle: one folded stack; signature: bundles of sheets |
| sheet | A4 A3 Letter or {width, height, unit} | named sizes auto-orient (landscape for 2/8-up, portrait for 4/16-up); custom sizes used exactly as given |
| pagesPerSide | 2 4 8 16 | grid: 2×1, 2×2, 4×2, 4×4 |
| signatureSheets | number (default 4) | sheets per signature; last signature may be shorter |
| creep | mm (default 0) | per-sheet shift toward the spine on inner sheets (saddle 2-up) |
| bleed | mm (default 0) | source pages expected at trim+bleed size; crop marks offset outside the bleed |
| marks | { crop?, fold? } | drawn only where slack exists — never on or across page content |
| flip | short-edge | long-edge | must match your printer's duplex setting (see below) |
| scale | fit (default) | none | fit scales pages into slots preserving aspect ratio; mixed source sizes are fine |
Duplex flip — the classic imposition bug, made explicit
Back sides are laid out for a book-page turn (flip about the sheet's vertical axis). In printer-driver terms that is:
- 2-up / 8-up (landscape sheets): choose "flip on short edge".
- 4-up / 16-up (portrait sheets): choose "flip on long edge".
Pass that same value as flip. If your printer is set the other way, pass the
other value — the back sides are rotated 180° to compensate. Symptom of a
mismatch: back pages upside down.
How to fold
Hold the printed stack with the front of sheet 1 facing you (for a 2-up saddle booklet that's the side showing page 1 on its right half), sheets in print order.
- 2-up: fold the left half behind the right half. Done — page 1 is the cover.
- 4-up: fold left half behind, then the top half behind.
- 8-up: fold left behind, top behind, left behind.
- 16-up: fold left behind, top behind, left behind, top behind.
Then staple/sew the spine and trim the other three edges (cut layouts of 4-up and beyond need the trim to free the pages).
Bleed & marks
If your pages carry bleed, export them at trim + bleed size and pass
bleed in mm. Crop marks are drawn at the trim corners, offset to sit outside
the bleed, and suppressed wherever they would touch another page's area —
so on an exact-fit layout (A5 on A4) you simply get no marks, while on a
roomy custom sheet (e.g. 70×100 cm signature work) you get full crop and fold
marks in the slack space.
Limits
- Very large PDFs (hundreds of MB) can strain browser memory; the same code runs server-side (Bun/Node) unchanged if you need big files.
- Mixed page sizes are handled by
scale: "fit"; withscale: "none"oversized pages may overlap neighboring slots — know your sources. - pdf-lib is pinned (stable, ubiquitous, maintenance mode); the surface used is small (embed + draw).
License
MIT © junglostore
