From 63d05dda948e8f7eefd8c4a08dc19fd67e0dd977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?TATSUNO=20=E2=80=9CTaz=E2=80=9D=20Yasuhiro?= Date: Mon, 26 Jan 2026 06:47:27 +0900 Subject: [PATCH] feat(page): add userUnit option for custom page units (PDF 1.6) --- CHANGELOG.md | 2 +- docs/paper_sizes.md | 14 +++++++++++++- lib/page.js | 2 ++ tests/unit/page.spec.js | 15 +++++++++++++++ tests/unit/trailer.spec.js | 1 + 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d72b68c8..6baa6053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - Fix garbled text copying in Chrome/Edge for PDFs with >256 unique characters (#1659) - Fix Link accessibility issues - Fix Table Accessibility Issue: Operator CS/cs not allowed in this current state - +- Add userUnit option for custom page units (PDF 1.6) ### [v0.17.2] - 2025-08-30 diff --git a/docs/paper_sizes.md b/docs/paper_sizes.md index 93df2201..dce23a31 100644 --- a/docs/paper_sizes.md +++ b/docs/paper_sizes.md @@ -83,6 +83,18 @@ In order to use the predefined sizes, the name of the size (as named in the list // Passing size to the constructor const doc = new PDFDocument({size: 'A7'}); - + // Passing size to the addPage function doc.addPage({size: 'A7'}); + +### User Unit (PDF 1.6+) + +The `userUnit` option allows you to scale the physical size of a page without changing the coordinate system. This is useful for creating large format documents like posters or banners that exceed the standard PDF coordinate limit (200 inches or 14400 points). + +The default value is `1.0`, where 1 unit equals 1/72 inch (1 point). Setting `userUnit: 2.0` means 1 unit equals 2/72 inch, effectively doubling the physical size of the page. + + // Create a page with 2x physical size + doc.addPage({ size: 'A4', userUnit: 2.0 }); + + // Create a large poster (4x scale) + doc.addPage({ size: [612, 792], userUnit: 4.0 }); diff --git a/lib/page.js b/lib/page.js index 3d748140..9a8b0be3 100644 --- a/lib/page.js +++ b/lib/page.js @@ -74,6 +74,7 @@ class PDFPage { this._options = options; this.size = options.size || 'letter'; this.layout = options.layout || 'portrait'; + this.userUnit = options.userUnit || 1.0; // calculate page dimensions const dimensions = Array.isArray(this.size) @@ -107,6 +108,7 @@ class PDFPage { MediaBox: [0, 0, this.width, this.height], Contents: this.content, Resources: this.resources, + UserUnit: this.userUnit, }); this.markings = []; diff --git a/tests/unit/page.spec.js b/tests/unit/page.spec.js index ceb7ca70..8164517f 100644 --- a/tests/unit/page.spec.js +++ b/tests/unit/page.spec.js @@ -1,6 +1,21 @@ import PDFDocument from '../../lib/document'; describe('page', function () { + describe('userUnit', function () { + test('defaults to 1.0', function () { + const doc = new PDFDocument(); + expect(doc.page.userUnit).toBe(1.0); + expect(doc.page.dictionary.data.UserUnit).toBe(1.0); + }); + + test('can be set via page options', function () { + const doc = new PDFDocument({ autoFirstPage: false }); + doc.addPage({ userUnit: 2.5 }); + expect(doc.page.userUnit).toBe(2.5); + expect(doc.page.dictionary.data.UserUnit).toBe(2.5); + }); + }); + test('cascade page options', function () { const doc = new PDFDocument({ autoFirstPage: false, diff --git a/tests/unit/trailer.spec.js b/tests/unit/trailer.spec.js index c3ca0fc4..95c7566b 100644 --- a/tests/unit/trailer.spec.js +++ b/tests/unit/trailer.spec.js @@ -70,6 +70,7 @@ describe('Document trailer', () => { /MediaBox [0 0 612 792] /Contents 5 0 R /Resources 6 0 R +/UserUnit 1 /Annots [9 0 R] >>`, ]);