takumi-pdf 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/export.cjs CHANGED
@@ -5,6 +5,7 @@ Object.defineProperties(exports, {
5
5
  let _takumi_rs_helpers_html = require("@takumi-rs/helpers/html");
6
6
  let _takumi_rs_helpers_jsx = require("@takumi-rs/helpers/jsx");
7
7
  let _takumi_rs_helpers_renderer = require("@takumi-rs/helpers/renderer");
8
+ let _takumi_rs_helpers = require("@takumi-rs/helpers");
8
9
  //#region pkg/takumi_pdf_wasm.js
9
10
  /**
10
11
  * A PDF renderer holding registered fonts and a decoded-resource cache.
@@ -497,6 +498,8 @@ async function __wbg_init(module_or_path) {
497
498
  }
498
499
  //#endregion
499
500
  //#region src/export.ts
501
+ /** Every character a page counter can produce, so subsetting keeps the fonts a band needs. */
502
+ const COUNTER_DIGITS = "0123456789";
500
503
  function isNode(value) {
501
504
  return typeof value === "object" && value !== null && "type" in value && !("$$typeof" in value);
502
505
  }
@@ -515,12 +518,20 @@ var PdfRenderer = class {
515
518
  /** Renders a node tree, JSX, or an HTML string to PDF bytes. See {@link RenderOptions}. */
516
519
  async render(node, options = {}) {
517
520
  const { fonts, images, header, footer, stylesheets, fontFamilies, ...rest } = options;
518
- const [main, headerResult, footerResult, resources] = await Promise.all([
521
+ const [main, headerResult, footerResult] = await Promise.all([
519
522
  resolveNode(node),
520
523
  header === void 0 ? void 0 : resolveNode(header),
521
- footer === void 0 ? void 0 : resolveNode(footer),
522
- this.fonts.resolveResources(fonts, images, fontFamilies)
524
+ footer === void 0 ? void 0 : resolveNode(footer)
523
525
  ]);
526
+ const bands = [headerResult?.node, footerResult?.node].filter((band) => band !== void 0);
527
+ const resources = await this.fonts.resolveResources(fonts && (0, _takumi_rs_helpers.subsetFonts)({
528
+ fonts,
529
+ source: bands.length > 0 ? [
530
+ main.node,
531
+ ...bands,
532
+ COUNTER_DIGITS
533
+ ] : main.node
534
+ }), images, fontFamilies);
524
535
  const sheets = [
525
536
  ...stylesheets ?? [],
526
537
  ...main.stylesheets,
@@ -539,14 +550,21 @@ var PdfRenderer = class {
539
550
  /**
540
551
  * Lays out a node tree without rendering and returns its size in CSS px.
541
552
  *
542
- * With page options the tree lays out at the full page width with unbounded
543
- * height, exactly how {@link render} measures a header or footer band
544
- * (`pageNumber` / `totalPages` hooks are filled with three-digit counters),
545
- * so the height tells you how much margin a band needs.
553
+ * With page options the tree lays out against the full page width with
554
+ * unbounded height, exactly how {@link render} measures a header or footer
555
+ * band (`pageNumber` / `totalPages` hooks are filled with three-digit
556
+ * counters), so the height tells you how much margin a band needs.
557
+ *
558
+ * The returned size is the tree's own, not the space it was laid out
559
+ * against: a box with `width: 100px` measures 100 wide on any page.
546
560
  */
547
561
  async measure(node, options = {}) {
548
562
  const { fonts, images, stylesheets, fontFamilies, ...rest } = options;
549
- const [main, resources] = await Promise.all([resolveNode(node), this.fonts.resolveResources(fonts, images, fontFamilies)]);
563
+ const main = await resolveNode(node);
564
+ const resources = await this.fonts.resolveResources(fonts && (0, _takumi_rs_helpers.subsetFonts)({
565
+ fonts,
566
+ source: [main.node, COUNTER_DIGITS]
567
+ }), images, fontFamilies);
550
568
  const sheets = [...stylesheets ?? [], ...main.stylesheets];
551
569
  return this.inner.measure(main.node, {
552
570
  ...rest,
package/dist/export.d.cts CHANGED
@@ -211,14 +211,15 @@ type ArchivalAttachment = Attachment & {
211
211
  };
212
212
  /**
213
213
  * Standards conformance. Invalid combinations are type errors: the `a` levels
214
- * imply a structure tree so `tagged: false` is rejected, PDF/A-4 is PDF 2.0
215
- * while PDF/UA-1 is PDF 1.7-only so they cannot combine, and only the
216
- * PDF/A-3 levels, PDF/A-4f (or plain PDF) accept attachments.
214
+ * imply a structure tree so `tagged: false` is rejected, PDF/UA-1 is PDF
215
+ * 1.7-only and PDF/UA-2 is PDF 2.0-only so each pairs with its own PDF/A
216
+ * levels, and only the PDF/A-3 levels, PDF/A-4f (or plain PDF) accept
217
+ * attachments.
217
218
  */
218
219
  type ConformanceOptions = {
219
220
  pdfa?: never;
220
- /** Structure tree: off, on (default), or validated against PDF/UA-1. */
221
- tagged?: boolean | "ua1";
221
+ /** Structure tree: off, on (default), or validated against PDF/UA. */
222
+ tagged?: boolean | "ua1" | "ua2";
222
223
  /** Files attached to the document. */
223
224
  attachments?: Attachment[];
224
225
  } | {
@@ -240,11 +241,11 @@ type ConformanceOptions = {
240
241
  attachments?: ArchivalAttachment[];
241
242
  } | {
242
243
  pdfa: "4";
243
- tagged?: boolean;
244
+ tagged?: boolean | "ua2";
244
245
  attachments?: never;
245
246
  } | {
246
247
  pdfa: "4f";
247
- tagged?: boolean;
248
+ tagged?: boolean | "ua2";
248
249
  attachments?: ArchivalAttachment[];
249
250
  };
250
251
  type RenderOptions = (PagedOptions | ViewportOptions) & ConformanceOptions & {
@@ -275,10 +276,13 @@ declare class PdfRenderer {
275
276
  /**
276
277
  * Lays out a node tree without rendering and returns its size in CSS px.
277
278
  *
278
- * With page options the tree lays out at the full page width with unbounded
279
- * height, exactly how {@link render} measures a header or footer band
280
- * (`pageNumber` / `totalPages` hooks are filled with three-digit counters),
281
- * so the height tells you how much margin a band needs.
279
+ * With page options the tree lays out against the full page width with
280
+ * unbounded height, exactly how {@link render} measures a header or footer
281
+ * band (`pageNumber` / `totalPages` hooks are filled with three-digit
282
+ * counters), so the height tells you how much margin a band needs.
283
+ *
284
+ * The returned size is the tree's own, not the space it was laid out
285
+ * against: a box with `width: 100px` measures 100 wide on any page.
282
286
  */
283
287
  measure(node: NodeInput, options?: MeasureOptions): Promise<MeasuredSize>;
284
288
  /** Registers a font ahead of time, deduped against earlier registrations. */
package/dist/export.d.mts CHANGED
@@ -211,14 +211,15 @@ type ArchivalAttachment = Attachment & {
211
211
  };
212
212
  /**
213
213
  * Standards conformance. Invalid combinations are type errors: the `a` levels
214
- * imply a structure tree so `tagged: false` is rejected, PDF/A-4 is PDF 2.0
215
- * while PDF/UA-1 is PDF 1.7-only so they cannot combine, and only the
216
- * PDF/A-3 levels, PDF/A-4f (or plain PDF) accept attachments.
214
+ * imply a structure tree so `tagged: false` is rejected, PDF/UA-1 is PDF
215
+ * 1.7-only and PDF/UA-2 is PDF 2.0-only so each pairs with its own PDF/A
216
+ * levels, and only the PDF/A-3 levels, PDF/A-4f (or plain PDF) accept
217
+ * attachments.
217
218
  */
218
219
  type ConformanceOptions = {
219
220
  pdfa?: never;
220
- /** Structure tree: off, on (default), or validated against PDF/UA-1. */
221
- tagged?: boolean | "ua1";
221
+ /** Structure tree: off, on (default), or validated against PDF/UA. */
222
+ tagged?: boolean | "ua1" | "ua2";
222
223
  /** Files attached to the document. */
223
224
  attachments?: Attachment[];
224
225
  } | {
@@ -240,11 +241,11 @@ type ConformanceOptions = {
240
241
  attachments?: ArchivalAttachment[];
241
242
  } | {
242
243
  pdfa: "4";
243
- tagged?: boolean;
244
+ tagged?: boolean | "ua2";
244
245
  attachments?: never;
245
246
  } | {
246
247
  pdfa: "4f";
247
- tagged?: boolean;
248
+ tagged?: boolean | "ua2";
248
249
  attachments?: ArchivalAttachment[];
249
250
  };
250
251
  type RenderOptions = (PagedOptions | ViewportOptions) & ConformanceOptions & {
@@ -275,10 +276,13 @@ declare class PdfRenderer {
275
276
  /**
276
277
  * Lays out a node tree without rendering and returns its size in CSS px.
277
278
  *
278
- * With page options the tree lays out at the full page width with unbounded
279
- * height, exactly how {@link render} measures a header or footer band
280
- * (`pageNumber` / `totalPages` hooks are filled with three-digit counters),
281
- * so the height tells you how much margin a band needs.
279
+ * With page options the tree lays out against the full page width with
280
+ * unbounded height, exactly how {@link render} measures a header or footer
281
+ * band (`pageNumber` / `totalPages` hooks are filled with three-digit
282
+ * counters), so the height tells you how much margin a band needs.
283
+ *
284
+ * The returned size is the tree's own, not the space it was laid out
285
+ * against: a box with `width: 100px` measures 100 wide on any page.
282
286
  */
283
287
  measure(node: NodeInput, options?: MeasureOptions): Promise<MeasuredSize>;
284
288
  /** Registers a font ahead of time, deduped against earlier registrations. */
package/dist/export.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { fromHtml } from "@takumi-rs/helpers/html";
2
2
  import { fromJsx } from "@takumi-rs/helpers/jsx";
3
3
  import { FontRegistry } from "@takumi-rs/helpers/renderer";
4
+ import { subsetFonts } from "@takumi-rs/helpers";
4
5
  //#region pkg/takumi_pdf_wasm.js
5
6
  /**
6
7
  * A PDF renderer holding registered fonts and a decoded-resource cache.
@@ -493,6 +494,8 @@ async function __wbg_init(module_or_path) {
493
494
  }
494
495
  //#endregion
495
496
  //#region src/export.ts
497
+ /** Every character a page counter can produce, so subsetting keeps the fonts a band needs. */
498
+ const COUNTER_DIGITS = "0123456789";
496
499
  function isNode(value) {
497
500
  return typeof value === "object" && value !== null && "type" in value && !("$$typeof" in value);
498
501
  }
@@ -511,12 +514,20 @@ var PdfRenderer = class {
511
514
  /** Renders a node tree, JSX, or an HTML string to PDF bytes. See {@link RenderOptions}. */
512
515
  async render(node, options = {}) {
513
516
  const { fonts, images, header, footer, stylesheets, fontFamilies, ...rest } = options;
514
- const [main, headerResult, footerResult, resources] = await Promise.all([
517
+ const [main, headerResult, footerResult] = await Promise.all([
515
518
  resolveNode(node),
516
519
  header === void 0 ? void 0 : resolveNode(header),
517
- footer === void 0 ? void 0 : resolveNode(footer),
518
- this.fonts.resolveResources(fonts, images, fontFamilies)
520
+ footer === void 0 ? void 0 : resolveNode(footer)
519
521
  ]);
522
+ const bands = [headerResult?.node, footerResult?.node].filter((band) => band !== void 0);
523
+ const resources = await this.fonts.resolveResources(fonts && subsetFonts({
524
+ fonts,
525
+ source: bands.length > 0 ? [
526
+ main.node,
527
+ ...bands,
528
+ COUNTER_DIGITS
529
+ ] : main.node
530
+ }), images, fontFamilies);
520
531
  const sheets = [
521
532
  ...stylesheets ?? [],
522
533
  ...main.stylesheets,
@@ -535,14 +546,21 @@ var PdfRenderer = class {
535
546
  /**
536
547
  * Lays out a node tree without rendering and returns its size in CSS px.
537
548
  *
538
- * With page options the tree lays out at the full page width with unbounded
539
- * height, exactly how {@link render} measures a header or footer band
540
- * (`pageNumber` / `totalPages` hooks are filled with three-digit counters),
541
- * so the height tells you how much margin a band needs.
549
+ * With page options the tree lays out against the full page width with
550
+ * unbounded height, exactly how {@link render} measures a header or footer
551
+ * band (`pageNumber` / `totalPages` hooks are filled with three-digit
552
+ * counters), so the height tells you how much margin a band needs.
553
+ *
554
+ * The returned size is the tree's own, not the space it was laid out
555
+ * against: a box with `width: 100px` measures 100 wide on any page.
542
556
  */
543
557
  async measure(node, options = {}) {
544
558
  const { fonts, images, stylesheets, fontFamilies, ...rest } = options;
545
- const [main, resources] = await Promise.all([resolveNode(node), this.fonts.resolveResources(fonts, images, fontFamilies)]);
559
+ const main = await resolveNode(node);
560
+ const resources = await this.fonts.resolveResources(fonts && subsetFonts({
561
+ fonts,
562
+ source: [main.node, COUNTER_DIGITS]
563
+ }), images, fontFamilies);
546
564
  const sheets = [...stylesheets ?? [], ...main.stylesheets];
547
565
  return this.inner.measure(main.node, {
548
566
  ...rest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "takumi-pdf",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "HTML/JSX to paged, selectable-text PDF, powered by takumi. WebAssembly, no Chromium.",
5
5
  "keywords": [
6
6
  "css",
@@ -83,7 +83,7 @@
83
83
  "publish-lint": "attw --pack . && publint --strict ."
84
84
  },
85
85
  "dependencies": {
86
- "@takumi-rs/helpers": "2.5.11"
86
+ "@takumi-rs/helpers": "2.6.0"
87
87
  },
88
88
  "devDependencies": {
89
89
  "@types/bun": "^1.3.14",
Binary file