Skip to main content

Python bindings for the imposer PDF booklet imposition library

Project description

imposer

A small, focused Rust library and CLI for arranging PDF pages into booklet layouts (n-up) with common binding options.

Features

  • Flexible n-up Imposition: Support for power-of-two pages-per-sheet (2-up, 4-up, 8-up, 16-up, 32-up, ...)
  • Multiple Binding Types: Saddle stitch and perfect binding with full mathematical accuracy
  • Automatic Padding: Intelligently pads to maintain proper sheet divisibility
  • Correct Page Ordering: Proper duplex booklet page ordering for accurate printing

Binding Types Explained

Saddle Stitch (Nested Binding)

Saddle stitch is the traditional booklet binding where pages are nested together. Each sheet wraps the previous one, creating a nested structure.

Structure:

Sheet 1 (outer):  Front: [Last, First]        Back: [Second, Last-1]
Sheet 2 (inner):  Front: [Last-2, Third]      Back: [Fourth, Last-3]
Sheet 3 (inner):  Front: [Last-4, Fifth]      Back: [Sixth, Last-5]
                  ... (continues inward)

Example: 8 pages, 2-up saddle stitch:

Sheet 1:  Front: [8, 1]    Back: [2, 7]
Sheet 2:  Front: [6, 3]    Back: [4, 5]
         ↓ Nest sheets (Sheet 2 inside Sheet 1)
Result: Pages fold correctly from outside to inside

Perfect Binding (Signatures Stacking)

Perfect binding groups pages into signatures, where each signature internally uses saddle-stitch ordering, but signatures are then stacked sequentially (not nested). This is how paperback books are bound.

Structure:

Signature 1: Pages 1-8    (internally: saddle-stitch ordered)
Signature 2: Pages 9-16   (internally: saddle-stitch ordered)
Signature 3: Pages 17-24  (internally: saddle-stitch ordered)
             ↓ Stack signatures (Sig 2 behind Sig 1, etc.)

Key Concept: Sheets Per Signature

The sheets_per_signature parameter controls how many physical sheets go into each signature:

  • 1 sheet per signature: Each signature contains a single nested sheet. The entire booklet is one large stacking of signatures. For 8 pages with 2-up and 1 sheet/sig, you get 2 signatures of 4 pages each.

  • 2+ sheets per signature: Multiple sheets are nested within each signature before stacking. For 8 pages with 2-up and 2 sheets/sig, you get 1 signature where both sheets are nested (identical to pure saddle stitch).

Important: Physical Sheets vs. Printing Sheets

The sheets_per_signature parameter refers to physical sheets after cutting. Different n-up values produce different numbers of physical sheets from one printing sheet:

  • 2-up: 1 printing sheet → 1 physical sheet
  • 4-up: 1 printing sheet → 2 physical sheets (cut horizontally)
  • 8-up: 1 printing sheet → 4 physical sheets (cut horizontally and vertically)

This means --perfect-binding --sheets-per-signature 2 --2up produces the same page grouping as --perfect-binding --sheets-per-signature 4 --4up, just with different grid layouts.

Example: 16 pages perfect binding comparison

Saddle Stitch (single signature):
  Sheet 1: [16, 1, 14, 3] / [2, 15, 4, 13]
  Sheet 2: [12, 5, 10, 7] / [6, 11, 8, 9]
  (all nested together)

Perfect Binding with 1 sheet/sig:
  Signature 1 (pages 1-8):
    Sheet 1: [8, 1, 6, 3] / [2, 7, 4, 5]
  Signature 2 (pages 9-16):
    Sheet 1: [16, 9, 14, 11] / [10, 15, 12, 13]
  (signatures stacked)

Perfect Binding with 2 sheets/sig:
  Signature 1 (pages 1-16):
    Sheet 1: [16, 1, 14, 3] / [2, 15, 4, 13]
    Sheet 2: [12, 5, 10, 7] / [6, 11, 8, 9]
  (identical to pure saddle stitch)

Algorithm Implementation

The imposition algorithms correctly:

  • Pad odd-page inputs to the next multiple of pages_per_sheet
  • Calculate optimal grid layout for page arrangement
  • Apply proper page reversal for duplex printing (varies by n-up value)
  • Handle arbitrary power-of-2 n-up values
  • Preserve blank pages in mathematically correct positions for proper folding
  • Verified with 109-page test across multiple n-up values (all pages present, no duplicates)

Documentation

Find the crate and detailed documentation online:

Notes and Capabilities

  • Assumes reasonably uniform page sizes across input PDF
  • Pads output with blank pages for proper sheet divisibility
  • Blank pages appear in mathematically correct positions (not consolidated)

Command-line options reference

Required options

  • -i, --input <PATH>: Input PDF file path. Must be a valid PDF.
  • -o, --output <PATH>: Output PDF file path. The generated booklet will be written here.

Layout and binding options

  • -n, --pages-per-sheet <N> (default: 2): Number of pages to arrange per sheet side. Must be a power of 2 for saddle stitch (2, 4, 8, 16, 32, 64, ...). No restriction for perfect binding.

  • -p, --page-size <SIZE> (default: a4): Output page size. Valid options: a4, a3, a5, letter, legal, tabloid.

  • --perfect-binding: Use perfect binding instead of saddle stitch. Perfect binding stacks signatures sequentially (like a paperback book) rather than nesting them. Cannot be used with saddle-stitch-specific settings.

Perfect binding signature control

Note: These options only apply when --perfect-binding is used.

  • --sheets-per-signature <N> (default: 1): Number of physical sheets to nest within each signature. A value of 1 creates simple stacking; higher values create sewn signatures with nested sheets inside.

  • --num-signatures <N> (optional): If specified, pages are evenly distributed across this many signatures. This takes precedence over --sheets-per-signature. Useful when you want a specific number of signature sections regardless of content.

Important note on --sheets-per-signature and --num-signatures: These are mutually exclusive concepts:

  • Use --sheets-per-signature when you want to control the physical structure of each signature (how many sheets are nested per signature).
  • Use --num-signatures when you want to control the number of signature sections the document is divided into. If both are specified, --num-signatures takes precedence.

Scaling and appearance options

  • --no-scale-to-fit: Do not scale source pages to fit the output page size. By default, pages are scaled to fill the available space while respecting margins.

  • --no-preserve-aspect-ratio: Allow pages to be stretched or compressed to fill the output page. By default, aspect ratio is preserved, which may result in letterboxing or pillarboxing.

  • --draw-guides: Draw fold and cut guide lines on the output. Useful for debugging and visualizing the page layout before printing.

  • --number-pages: Replace page content with page numbers. Useful for visualizing the page order without needing to view the actual PDF content.

Default behavior

If you run imposer -i input.pdf -o output.pdf with no other options:

  • Uses saddle stitch binding
  • Creates a 2-up layout (2 pages per sheet)
  • Output size is A4
  • Pages are scaled to fit the output size while preserving aspect ratio
  • No guides or page numbers are drawn

Building

cargo build --release

Development

This project uses cargo-make to replicate CI checks locally.

Install cargo-make

cargo install cargo-make

Run all CI checks

cargo make

This runs all checks that CI performs:

  • Code formatting (cargo fmt --check)
  • Clippy linting (cargo clippy)
  • Rust tests (cargo nextest run)
  • Python bindings build and tests
  • Python bindings synchronization check

Available tasks

  • cargo make - Run all CI checks (default)
  • cargo make quick - Quick checks (format + clippy only)
  • cargo make rust-only - Rust checks only (skip Python)
  • cargo make all-continue - Run all checks, continue on errors (useful for debugging)
  • cargo make fmt - Auto-format code
  • cargo make clippy-fix - Auto-fix clippy issues
  • cargo make test - Run Rust tests only
  • cargo make python-test - Run Python tests only
  • cargo make --list-all-steps - List all available tasks

Note: The default task stops on first error (matching CI behavior). If you want to run all checks even when some fail, use cargo make all-continue.

Pre-commit workflow

Before committing, ensure all checks pass:

cargo make

If cargo make passes locally, CI should also pass.

Try it

cargo run --bin imposer -- -i input.pdf -o booklet.pdf

Installation

Using the binary (when Cargo bin is in your PATH)

If you prefer to run imposer directly from your shell without cargo run, install the binary into your Cargo bin directory (usually ~/.cargo/bin) and make sure that directory is on your PATH.

  • Install locally from the repository (installs into ~/.cargo/bin):
cargo install --path .
  • Or install the published crate from crates.io:
cargo install imposer
  • Ensure ~/.cargo/bin is on your PATH (add to your shell profile if necessary):
export PATH="$HOME/.cargo/bin:$PATH"
# Add the line above to ~/.bashrc, ~/.zshrc, or your shell profile to make it persistent

Using imposer from the command line

Once imposer is installed and in your PATH, you can run it directly:

imposer -i input.pdf -o output.pdf

Common usage examples

Saddle stitch 2-up (default):

imposer -i input.pdf -o booklet.pdf

Saddle stitch 4-up (4 pages per sheet):

imposer -i input.pdf -o booklet.pdf -n 4

Perfect binding with 2 sheets per signature, 2-up layout:

imposer -i input.pdf -o book.pdf --perfect-binding --sheets-per-signature 2

Perfect binding 4-up (larger pages per sheet):

imposer -i input.pdf -o book.pdf --perfect-binding -n 4

All options and defaults are available via the help command:

imposer --help

Python bindings

imposer also provides Python bindings via PyO3, allowing you to use the library directly in Python code. This is useful for:

  • Integrating PDF imposition into Python applications
  • Batch processing PDFs programmatically
  • Embedding booklet generation in web services
  • Automating workflows in tools like Scribus

Installation

Install the Python package from PyPI:

pip install imposer

Or install locally from the repository:

pip install .

Basic usage

import imposer

# Create a default 2-up A4 saddle-stitch booklet
config = imposer.BookletConfig()
imposer.generate_booklet_from_file("input.pdf", "output.pdf", config)

Configuration options

import imposer

# Configure a custom booklet
binding = imposer.BindingType.perfect_bound(
    sheets_per_signature=8,  # 8 sheets per signature
    num_signatures=3         # 3 total signatures
)

config = (
    imposer.BookletConfig()
    .with_page_size(imposer.PageSize.a4())
    .with_pages_per_sheet(4)
    .with_binding_type(binding)
    .with_draw_guides(True)       # Draw cut/fold lines
    .with_number_pages(True)      # Add page numbers
    .with_scale_to_fit(True)      # Scale pages to fit
    .with_preserve_aspect_ratio(True)
)

imposer.generate_booklet_from_file("input.pdf", "output.pdf", config)

In-memory processing

Process PDFs without intermediate files:

import imposer

# Read input PDF
with open("input.pdf", "rb") as f:
    input_bytes = f.read()

# Generate booklet configuration
config = imposer.BookletConfig()

# Process in memory
output_bytes = imposer.generate_booklet(input_bytes, config)

# Write output
with open("output.pdf", "wb") as f:
    f.write(output_bytes)

Available page sizes

imposer.PageSize.a4()      # A4 (210 × 297 mm)
imposer.PageSize.a3()      # A3 (297 × 420 mm)
imposer.PageSize.a5()      # A5 (148 × 210 mm)
imposer.PageSize.letter()  # Letter (8.5 × 11 in)
imposer.PageSize.legal()   # Legal (8.5 × 14 in)
imposer.PageSize.tabloid() # Tabloid (11 × 17 in)

Binding types

# Saddle-stitch (default): pages nested, stapled in the middle
binding = imposer.BindingType.saddle_stitch()

# Perfect binding: signatures stacked, glued at spine
binding = imposer.BindingType.perfect_bound(
    sheets_per_signature=4,    # Pages per signature (default: 1)
    num_signatures=None        # Override with specific signature count
)

Examples

See examples/python_example.py for detailed examples including:

  • Basic booklet creation
  • Different page sizes
  • Various n-up layouts
  • Perfect binding with signatures
  • Guides and page numbers
  • In-memory processing
  • Scribus integration

Run the example:

python examples/python_example.py input.pdf

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

imposer-0.3.0.tar.gz (74.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

imposer-0.3.0-cp314-cp314-macosx_11_0_arm64.whl (657.1 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

imposer-0.3.0-cp314-cp314-macosx_10_12_x86_64.whl (689.6 kB view details)

Uploaded CPython 3.14macOS 10.12+ x86-64

imposer-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl (780.4 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

imposer-0.3.0-cp312-cp312-manylinux_2_28_aarch64.whl (726.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ ARM64

imposer-0.3.0-cp311-cp311-manylinux_2_28_x86_64.whl (782.3 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

imposer-0.3.0-cp311-cp311-manylinux_2_28_aarch64.whl (729.0 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ ARM64

imposer-0.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (782.0 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

imposer-0.3.0-cp310-cp310-manylinux_2_28_aarch64.whl (729.0 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ ARM64

imposer-0.3.0-cp39-cp39-win_amd64.whl (569.7 kB view details)

Uploaded CPython 3.9Windows x86-64

imposer-0.3.0-cp39-cp39-manylinux_2_28_x86_64.whl (783.5 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.28+ x86-64

imposer-0.3.0-cp39-cp39-manylinux_2_28_aarch64.whl (731.2 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.28+ ARM64

File details

Details for the file imposer-0.3.0.tar.gz.

File metadata

  • Download URL: imposer-0.3.0.tar.gz
  • Upload date:
  • Size: 74.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for imposer-0.3.0.tar.gz
Algorithm Hash digest
SHA256 95190492773d19ee3fb7417731f552dc0ae49de7c7fde72b8a94eaee0e50bfec
MD5 af03b36326f9ea1760499a692d2a28a4
BLAKE2b-256 9099913b28d4ea3a783552fe259f13979bbfe65d6b802f10ca55cbe648716fa0

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0.tar.gz:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8111d5106e80e0f01ed99348d4738f7a641f488ce778478d7df78e74e4705efe
MD5 910a7e9d9c20a47606c6dfddfabf2fc6
BLAKE2b-256 46575054acde4f5e45c6dc224d224592140072ce09b745a9f12dfbd3a43810aa

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp314-cp314-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp314-cp314-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 7fd8f40d03c26dc9eb5156cbd0315fc64041edd00f141f0bd69c3c35ebe77ace
MD5 87b05404133828528d770826256ee206
BLAKE2b-256 cc7c59340a0c90e6a7dff38618bad5574a7914d5ae62d6df404f9d033494a814

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp314-cp314-macosx_10_12_x86_64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 17741b0348afc0daefcc4bef27208d75783e40d424e205b4708394a38b2b39f1
MD5 41f1d6ce734e6dcc1df1a809caee6784
BLAKE2b-256 8dd36fc6305953cf6a53935355f78c752ce92182c700dca759f49e5c7988b7ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp312-cp312-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp312-cp312-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 32610ab6423b77de5cc1773f38c9a83444293f0ffee3792e60dcfd425a57ff1d
MD5 b01b2fce6b6e3611d73d0222f9fc4b5b
BLAKE2b-256 bbca7239b60d932c0c383ce99b124e16e48cc29a31ef9c2b1522a80fe32d28b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp312-cp312-manylinux_2_28_aarch64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e9e38dd7a8b80b465f788de233e29d2732c27267b23d408f0fcde5bbe35fa43c
MD5 ea769887fd24774c23c6f3352ddead7b
BLAKE2b-256 b095f33e6f7196df9a2a91f64ddd8062158248af1e8c7a3eb2a9461d4e20ee07

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp311-cp311-manylinux_2_28_x86_64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp311-cp311-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp311-cp311-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 ffc7b01153f787e56d820d2df99c34d359e5135ea70032bc87bc4e8980ba6e03
MD5 b9ae4a506d91a7b0209546cc2c1ecc30
BLAKE2b-256 2bb5b8845797f6ef9d4b23144f61ae86e1765c9179db0f3f690b87b8f91f515f

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp311-cp311-manylinux_2_28_aarch64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 806134d3dece0faec0e0c4eb49ce06b82e678ed057eb1ec0127d59fa32c292d5
MD5 a3c9b72d433e454809f3da7f84624904
BLAKE2b-256 ffc7efaa3a32990ecd7e1f83bfd8abc1a43d7d3099aa6e47bd4ffe646715f6a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp310-cp310-manylinux_2_28_x86_64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp310-cp310-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp310-cp310-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 cdbb3f9b03ddba43b9c0ac480d04ea5f54d0db124af15c2ffd5f9a42b20f57ff
MD5 9d2ca9d708bc1133f02b9fe93680994e
BLAKE2b-256 359b9b41a528c3067bda4b4b54b0f5a570a6b48338338564443d48589214d622

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp310-cp310-manylinux_2_28_aarch64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: imposer-0.3.0-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 569.7 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for imposer-0.3.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 f9f9ef1cdb2f9772c34bede0cbf67c8dbed621a955c0e8d6f79cf13c239a8f8e
MD5 c847a194eced29856903c6c160df8fc6
BLAKE2b-256 bacf71939741cb1d089d9a78720543ecc13424b90025ce4eb93c6004c469df44

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp39-cp39-win_amd64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp39-cp39-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b68420f670319abc235250cacf6f93f8a42c7e21be64e84d752b859bf35dca97
MD5 898e5efd749cdf0af3c603e48afb5c29
BLAKE2b-256 837f29a2a22c910e7e85265d945b053ae2a6dbb21b8808f80a725d4fc9d06ba2

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp39-cp39-manylinux_2_28_x86_64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file imposer-0.3.0-cp39-cp39-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for imposer-0.3.0-cp39-cp39-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 cf9eef5cc7a9e566df6ecec840be118ec095adbc252cd7ef4793b0f75287ce9a
MD5 b0c8fa2e8324f72e5bc9458715411e88
BLAKE2b-256 63e5154e5daa955e183a4d4e5679f774a3bd264f09cb5b11649b5dff84041473

See more details on using hashes here.

Provenance

The following attestation bundles were made for imposer-0.3.0-cp39-cp39-manylinux_2_28_aarch64.whl:

Publisher: create-release.yaml on joaommartins/imposer-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page