@lpdfio/lpdf 0.32.0 → 0.33.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/browser.js CHANGED
@@ -234,6 +234,20 @@ var LpdfEngine = class {
234
234
  const len0 = WASM_VECTOR_LEN;
235
235
  wasm.lpdfengine_set_font_metrics(this.__wbg_ptr, ptr0, len0);
236
236
  }
237
+ /**
238
+ * Set the memory a render may allocate, in megabytes: 1024 when it isn't set. A render that needs more stops
239
+ * with an error that names the cap. What the engine holds before the render, such as its loaded fonts, doesn't
240
+ * count.
241
+ *
242
+ * Returns an error when `mb` is 0 or above 4096, the most 32-bit WebAssembly addresses.
243
+ * @param {number} mb
244
+ */
245
+ set_max_memory_mb(mb) {
246
+ const ret = wasm.lpdfengine_set_max_memory_mb(this.__wbg_ptr, mb);
247
+ if (ret[1]) {
248
+ throw takeFromExternrefTable0(ret[0]);
249
+ }
250
+ }
237
251
  /**
238
252
  * Set the current Unix timestamp (seconds) for license expiry checking.
239
253
  * Must be called before `render_pdf` when using a time-limited token.
@@ -243,6 +257,32 @@ var LpdfEngine = class {
243
257
  set_now(unix) {
244
258
  wasm.lpdfengine_set_now(this.__wbg_ptr, unix);
245
259
  }
260
+ /**
261
+ * Draw PNG stamps over the pages of an existing PDF, and return the file with them added as an incremental
262
+ * update: the input, byte for byte, then the images and the pages they change. The original bytes stay as they
263
+ * were, so an owner password and its permissions stay, and so does a digital signature's revision.
264
+ *
265
+ * `stamps` is a JSON list of stamps, each with an `image`, the name of a PNG loaded with `load_image`, a `page`
266
+ * scope, a box (`x`, `y`, `anchor`, `width`, `height`, placed as a layer element is) and how the image sits in it
267
+ * (`align`, `justify`, `scale`, `max-grow`). Without a valid license key, each stamped page gets the attribution
268
+ * line of a render in its top-right corner.
269
+ * @param {Uint8Array} pdf
270
+ * @param {string} stamps
271
+ * @returns {Uint8Array}
272
+ */
273
+ stamp(pdf, stamps) {
274
+ const ptr0 = passArray8ToWasm0(pdf, wasm.__wbindgen_malloc);
275
+ const len0 = WASM_VECTOR_LEN;
276
+ const ptr1 = passStringToWasm0(stamps, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
277
+ const len1 = WASM_VECTOR_LEN;
278
+ const ret = wasm.lpdfengine_stamp(this.__wbg_ptr, ptr0, len0, ptr1, len1);
279
+ if (ret[3]) {
280
+ throw takeFromExternrefTable0(ret[2]);
281
+ }
282
+ var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
283
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
284
+ return v3;
285
+ }
246
286
  };
247
287
  if (Symbol.dispose) LpdfEngine.prototype[Symbol.dispose] = LpdfEngine.prototype.free;
248
288
  function check_license(token, now_unix) {
@@ -265,6 +305,11 @@ function __wbg_get_imports() {
265
305
  __wbg___wbindgen_throw_6b64449b9b9ed33c: function(arg0, arg1) {
266
306
  throw new Error(getStringFromWasm0(arg0, arg1));
267
307
  },
308
+ __wbg_getRandomValues_cc7f052a444bb2ce: function() {
309
+ return handleError(function(arg0, arg1) {
310
+ globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
311
+ }, arguments);
312
+ },
268
313
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
269
314
  const ret = getStringFromWasm0(arg0, arg1);
270
315
  return ret;
@@ -287,6 +332,11 @@ function __wbg_get_imports() {
287
332
  var LpdfEngineFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
288
333
  }, unregister: () => {
289
334
  } } : new FinalizationRegistry((ptr) => wasm.__wbg_lpdfengine_free(ptr >>> 0, 1));
335
+ function addToExternrefTable0(obj) {
336
+ const idx = wasm.__externref_table_alloc();
337
+ wasm.__wbindgen_externrefs.set(idx, obj);
338
+ return idx;
339
+ }
290
340
  function getArrayU8FromWasm0(ptr, len) {
291
341
  ptr = ptr >>> 0;
292
342
  return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
@@ -302,6 +352,14 @@ function getUint8ArrayMemory0() {
302
352
  }
303
353
  return cachedUint8ArrayMemory0;
304
354
  }
355
+ function handleError(f, args) {
356
+ try {
357
+ return f.apply(this, args);
358
+ } catch (e) {
359
+ const idx = addToExternrefTable0(e);
360
+ wasm.__wbindgen_exn_store(idx);
361
+ }
362
+ }
305
363
  function isLikeNone(x) {
306
364
  return x === void 0 || x === null;
307
365
  }
@@ -435,6 +493,15 @@ async function __wbg_init(module_or_path) {
435
493
  }
436
494
 
437
495
  // src/_shared.ts
496
+ var DEFAULT_MAX_MEMORY_MB = 1024;
497
+ var MAX_MEMORY_MB = 4096;
498
+ function maxMemoryMb(value) {
499
+ if (value === void 0) return DEFAULT_MAX_MEMORY_MB;
500
+ if (!Number.isInteger(value) || value < 1 || value > MAX_MEMORY_MB) {
501
+ throw new RangeError(`maxMemoryMb must be a whole number of megabytes from 1 to ${MAX_MEMORY_MB}, not ${value}`);
502
+ }
503
+ return value;
504
+ }
438
505
  var ENTROPY_BYTES = 32;
439
506
  function encryptionArguments(options, randomBytes) {
440
507
  const hasPassword = options.userPassword !== void 0 || options.ownerPassword !== void 0;
@@ -446,6 +513,123 @@ function encryptionArguments(options, randomBytes) {
446
513
  ];
447
514
  }
448
515
 
516
+ // src/render-error.ts
517
+ var LpdfRenderError = class extends Error {
518
+ constructor(message, cause) {
519
+ super(message);
520
+ this.name = "LpdfRenderError";
521
+ if (cause !== void 0) this.cause = cause;
522
+ }
523
+ };
524
+
525
+ // src/render-queue.ts
526
+ var DEFAULT_TIMEOUT = 5;
527
+ var MAX_DELAY_MS = 2 ** 31 - 1;
528
+ function renderTimeout(timeout) {
529
+ if (timeout === void 0) return DEFAULT_TIMEOUT;
530
+ if (!Number.isFinite(timeout) || timeout < 0) {
531
+ throw new RangeError(`timeout must be a number of seconds, 0 for no limit, not ${timeout}`);
532
+ }
533
+ return timeout;
534
+ }
535
+ function seconds(count) {
536
+ return count === 1 ? "1 second" : `${count} seconds`;
537
+ }
538
+ var RenderQueue = class {
539
+ constructor(_start) {
540
+ this._start = _start;
541
+ this._waiting = [];
542
+ }
543
+ /**
544
+ * Renders `job` once the renders before it have ended. Its timeout counts from when it starts.
545
+ *
546
+ * @param timeout - The seconds it may run, 0 for no limit.
547
+ * @returns The PDF; rejects with an `LpdfRenderError` when the engine refuses the document or the render runs
548
+ * past its timeout.
549
+ */
550
+ render(job, timeout) {
551
+ return new Promise((resolve, reject) => {
552
+ this._waiting.push({ job, timeout, resolve, reject });
553
+ this._next();
554
+ });
555
+ }
556
+ _next() {
557
+ if (this._running) return;
558
+ const pending = this._waiting.shift();
559
+ if (!pending) {
560
+ this._worker?.hold?.(false);
561
+ return;
562
+ }
563
+ this._running = pending;
564
+ try {
565
+ const worker = this._worker ??= this._startWorker();
566
+ worker.hold?.(true);
567
+ if (pending.timeout > 0) {
568
+ pending.timer = setTimeout(() => this._timedOut(pending), Math.min(pending.timeout * 1e3, MAX_DELAY_MS));
569
+ }
570
+ worker.post(pending.job);
571
+ } catch (e) {
572
+ this._dropWorker();
573
+ this._settle({ error: `The render worker failed: ${e instanceof Error ? e.message : String(e)}`, broken: true });
574
+ }
575
+ }
576
+ _startWorker() {
577
+ const worker = this._start({
578
+ replied: (reply) => {
579
+ if (worker !== this._worker) return;
580
+ if ("error" in reply && reply.broken) this._dropWorker();
581
+ this._settle(reply);
582
+ },
583
+ failed: (message) => {
584
+ if (worker !== this._worker) return;
585
+ this._dropWorker();
586
+ this._settle({ error: message, broken: true });
587
+ }
588
+ });
589
+ return worker;
590
+ }
591
+ _dropWorker() {
592
+ this._worker?.terminate();
593
+ this._worker = void 0;
594
+ }
595
+ _settle(reply) {
596
+ const pending = this._running;
597
+ if (!pending) return;
598
+ this._running = void 0;
599
+ clearTimeout(pending.timer);
600
+ if ("pdf" in reply) {
601
+ pending.resolve(reply.pdf);
602
+ } else {
603
+ pending.reject(new LpdfRenderError(reply.error, reply.cause));
604
+ }
605
+ this._next();
606
+ }
607
+ _timedOut(pending) {
608
+ if (pending !== this._running) return;
609
+ this._dropWorker();
610
+ this._settle({ error: `The render timed out after ${seconds(pending.timeout)}.`, broken: true });
611
+ }
612
+ };
613
+
614
+ // src/stamp.ts
615
+ function stampRequest(stamps) {
616
+ const images = /* @__PURE__ */ new Map();
617
+ const names = /* @__PURE__ */ new Map();
618
+ const list = stamps.map(({ image, maxGrow, ...rest }, i) => {
619
+ if (!(image instanceof Uint8Array)) {
620
+ throw new TypeError(`stamp ${i + 1}: image must be the PNG's bytes, a Uint8Array`);
621
+ }
622
+ let name = names.get(image);
623
+ if (name === void 0) {
624
+ name = `stamp-${names.size}`;
625
+ names.set(image, name);
626
+ images.set(name, image);
627
+ }
628
+ return { ...rest, image: name, ...maxGrow === void 0 ? {} : { "max-grow": maxGrow } };
629
+ });
630
+ return { stamps: JSON.stringify(list), images };
631
+ }
632
+
449
633
  // src/constants.ts
450
634
  var FieldType = {
451
635
  Text: "text",
@@ -458,7 +642,8 @@ var Pin = {
458
642
  Top: "top",
459
643
  Bottom: "bottom",
460
644
  Left: "left",
461
- Right: "right"
645
+ Right: "right",
646
+ Inset: "inset"
462
647
  };
463
648
  var Orientation = {
464
649
  Portrait: "portrait",
@@ -472,6 +657,10 @@ var FootnoteCounter = {
472
657
  Section: "section",
473
658
  Document: "document"
474
659
  };
660
+ var ColumnFill = {
661
+ Auto: "auto",
662
+ Balance: "balance"
663
+ };
475
664
  var Cipher = {
476
665
  Aes256: "aes-256",
477
666
  Rc4128: "rc4-128"
@@ -525,8 +714,48 @@ function nowUnix() {
525
714
  function secureRandomBytes(count) {
526
715
  return crypto.getRandomValues(new Uint8Array(count));
527
716
  }
528
- async function initLpdf(wasmSource, licenseKey = "") {
529
- await __wbg_init(wasmSource);
717
+ async function compileEngine(source) {
718
+ if (source instanceof WebAssembly.Module) return source;
719
+ const from = source ?? new URL("lpdf_bg.wasm", import.meta.url);
720
+ if (typeof from === "string" || from instanceof URL || from instanceof Request) {
721
+ return compileResponse(await fetch(from));
722
+ }
723
+ if (from instanceof Response) return compileResponse(from);
724
+ return WebAssembly.compile(from);
725
+ }
726
+ async function compileResponse(response) {
727
+ if (!response.ok) {
728
+ throw new Error(`The engine could not be loaded from ${response.url}: ${response.status} ${response.statusText}`);
729
+ }
730
+ if (response.headers.get("Content-Type")?.startsWith("application/wasm")) {
731
+ return WebAssembly.compileStreaming(response);
732
+ }
733
+ return WebAssembly.compile(await response.arrayBuffer());
734
+ }
735
+ var renderWorkerUrl;
736
+ function startBrowserWorker(module, events) {
737
+ renderWorkerUrl ??= URL.createObjectURL(new Blob(['"use strict";\n(() => {\n // wasm/lpdf-web.js\n var import_meta = {};\n var LpdfEngine = class {\n __destroy_into_raw() {\n const ptr = this.__wbg_ptr;\n this.__wbg_ptr = 0;\n LpdfEngineFinalization.unregister(this);\n return ptr;\n }\n free() {\n const ptr = this.__destroy_into_raw();\n wasm.__wbg_lpdfengine_free(ptr, 0);\n }\n /**\n * Register the bytes of a file a document carries, for the `<file>` of its `<attachments>` whose `ref`, or with\n * no ref whose name, is `name`. The PDF carries them as they are.\n * @param {string} name\n * @param {Uint8Array} bytes\n */\n load_file(name, bytes) {\n const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.lpdfengine_load_file(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n }\n /**\n * Register raw font bytes (TTF/OTF) for a custom font name.\n * Call this once per font before calling `render_pdf`.\n * Glyph advance-width metrics are extracted automatically from the font\n * bytes so the layout engine can measure text accurately \u2014 no separate\n * `set_font_metrics` call is required.\n * @param {string} name\n * @param {Uint8Array} bytes\n */\n load_font(name, bytes) {\n const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.lpdfengine_load_font(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n }\n /**\n * Register raw image bytes (JPEG or PNG) for an image name.\n * Call this for every image referenced by `<img name="\u2026">` nodes.\n * @param {string} name\n * @param {Uint8Array} bytes\n */\n load_image(name, bytes) {\n const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.lpdfengine_load_image(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n }\n /**\n * Register the text of a file of Markdown rules, the root of which is a `<markdown-styles>`, for the\n * `src` that names it. The engine reads no files: call this once for every `<markdown-styles src="\u2026">`\n * of the document before `render_pdf`, as `load_font` is called for a font.\n * @param {string} src\n * @param {string} xml\n */\n load_markdown_styles(src, xml) {\n const ptr0 = passStringToWasm0(src, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.lpdfengine_load_markdown_styles(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n }\n /**\n * Register the bytes of an ICC colour profile, for the `<profile>` of a document\'s `<assets>` whose `ref`, or with\n * no ref whose name, is `name`: the press profile a PDF/X document names in `<output profile>`.\n * @param {string} name\n * @param {Uint8Array} bytes\n */\n load_profile(name, bytes) {\n const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);\n const len1 = WASM_VECTOR_LEN;\n wasm.lpdfengine_load_profile(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n }\n /**\n * @param {string} license_key\n */\n constructor(license_key) {\n const ptr0 = passStringToWasm0(license_key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ret = wasm.lpdfengine_new(ptr0, len0);\n this.__wbg_ptr = ret >>> 0;\n LpdfEngineFinalization.register(this, this.__wbg_ptr, this);\n return this;\n }\n /**\n * @param {string} xml\n * @returns {string}\n */\n render(xml) {\n let deferred2_0;\n let deferred2_1;\n try {\n const ptr0 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ret = wasm.lpdfengine_render(this.__wbg_ptr, ptr0, len0);\n deferred2_0 = ret[0];\n deferred2_1 = ret[1];\n return getStringFromWasm0(ret[0], ret[1]);\n } finally {\n wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);\n }\n }\n /**\n * Render `xml` to binary PDF bytes.\n *\n * Any custom fonts referenced in `<font src="\u2026">` declarations must have\n * their bytes registered via `load_font` before calling this method.\n *\n * `json_data` is an optional JSON string used to resolve `data-*`\n * attributes in the template. Pass `None` (or `null` / `undefined` from\n * JavaScript) to render the template with its inline fallback content.\n *\n * The rest is for a document that asks for encryption in its `<output>`, which sets the cipher and\n * the permissions: the passwords, which the template never holds, and `entropy`, at least 32 random\n * bytes from the host\'s secure generator for AES-256. A document that asks for encryption needs an\n * owner password, or `skip_encryption` to render it unencrypted, as a preview does; passwords for a\n * document that doesn\'t ask for it are an error, and so are passwords with `skip_encryption`.\n * @param {string} xml\n * @param {string | null | undefined} json_data\n * @param {string | null | undefined} user_password\n * @param {string | null | undefined} owner_password\n * @param {boolean} skip_encryption\n * @param {Uint8Array} entropy\n * @returns {Uint8Array}\n */\n render_pdf(xml, json_data, user_password, owner_password, skip_encryption, entropy) {\n const ptr0 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n var ptr1 = isLikeNone(json_data) ? 0 : passStringToWasm0(json_data, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n var len1 = WASM_VECTOR_LEN;\n var ptr2 = isLikeNone(user_password) ? 0 : passStringToWasm0(user_password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n var len2 = WASM_VECTOR_LEN;\n var ptr3 = isLikeNone(owner_password) ? 0 : passStringToWasm0(owner_password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n var len3 = WASM_VECTOR_LEN;\n const ptr4 = passArray8ToWasm0(entropy, wasm.__wbindgen_malloc);\n const len4 = WASM_VECTOR_LEN;\n const ret = wasm.lpdfengine_render_pdf(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, skip_encryption, ptr4, len4);\n if (ret[3]) {\n throw takeFromExternrefTable0(ret[2]);\n }\n var v6 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n return v6;\n }\n /**\n * @param {string} json\n * @returns {string}\n */\n render_tree(json) {\n let deferred2_0;\n let deferred2_1;\n try {\n const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n const ret = wasm.lpdfengine_render_tree(this.__wbg_ptr, ptr0, len0);\n deferred2_0 = ret[0];\n deferred2_1 = ret[1];\n return getStringFromWasm0(ret[0], ret[1]);\n } finally {\n wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);\n }\n }\n /**\n * Render a JSON kit-tree document to PDF bytes.\n *\n * This is the JSON counterpart of `render_pdf`. The Node adapter uses it\n * when an `LpdfDocument` Kit tree is passed to `renderPdf()`, avoiding an\n * intermediate XML serialisation step. PHP, Python, and .NET adapters also\n * use this entry point.\n *\n * The passwords, `skip_encryption` and `entropy` are those of `render_pdf`, for a document whose\n * `output` asks for encryption.\n * @param {string} json\n * @param {string | null | undefined} user_password\n * @param {string | null | undefined} owner_password\n * @param {boolean} skip_encryption\n * @param {Uint8Array} entropy\n * @returns {Uint8Array}\n */\n render_tree_pdf(json, user_password, owner_password, skip_encryption, entropy) {\n const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n var ptr1 = isLikeNone(user_password) ? 0 : passStringToWasm0(user_password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n var len1 = WASM_VECTOR_LEN;\n var ptr2 = isLikeNone(owner_password) ? 0 : passStringToWasm0(owner_password, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n var len2 = WASM_VECTOR_LEN;\n const ptr3 = passArray8ToWasm0(entropy, wasm.__wbindgen_malloc);\n const len3 = WASM_VECTOR_LEN;\n const ret = wasm.lpdfengine_render_tree_pdf(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, skip_encryption, ptr3, len3);\n if (ret[3]) {\n throw takeFromExternrefTable0(ret[2]);\n }\n var v5 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n return v5;\n }\n /**\n * Set an optional ISO 8601 creation timestamp (e.g. `"2024-06-01T12:00:00"`, `"2024-06-01T12:00:00.000Z"` or\n * `"2024-06-01T12:00:00+01:00"`). When provided, written as `/CreationDate` in the PDF info dictionary, with\n * the precision and the time zone it was given in; a value that is not a date makes the render an error.\n * Omitting this keeps builds reproducible (no embedded timestamp).\n * @param {string} iso\n */\n set_created_on(iso) {\n const ptr0 = passStringToWasm0(iso, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n wasm.lpdfengine_set_created_on(this.__wbg_ptr, ptr0, len0);\n }\n /**\n * Inject glyph advance-width tables for custom fonts.\n *\n * Call this *before* `render_pdf` / `render` when the document uses custom\n * fonts (declared via `<font src="\u2026"`). The adapter extracts these widths\n * from the font binary and passes them as a JSON object:\n *\n * ```json\n * { "fontName": { "default": 500, "ascii": [260, 285, \u2026] } }\n * ```\n *\n * `ascii` is a 95-element array for code points 32\u2013126. `default` is used\n * for code points outside that range. All values are in 1/1000 em units.\n * @param {string} json\n */\n set_font_metrics(json) {\n const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len0 = WASM_VECTOR_LEN;\n wasm.lpdfengine_set_font_metrics(this.__wbg_ptr, ptr0, len0);\n }\n /**\n * Set the memory a render may allocate, in megabytes: 1024 when it isn\'t set. A render that needs more stops\n * with an error that names the cap. What the engine holds before the render, such as its loaded fonts, doesn\'t\n * count.\n *\n * Returns an error when `mb` is 0 or above 4096, the most 32-bit WebAssembly addresses.\n * @param {number} mb\n */\n set_max_memory_mb(mb) {\n const ret = wasm.lpdfengine_set_max_memory_mb(this.__wbg_ptr, mb);\n if (ret[1]) {\n throw takeFromExternrefTable0(ret[0]);\n }\n }\n /**\n * Set the current Unix timestamp (seconds) for license expiry checking.\n * Must be called before `render_pdf` when using a time-limited token.\n * If not set (default `0`), expiry is not checked.\n * @param {bigint} unix\n */\n set_now(unix) {\n wasm.lpdfengine_set_now(this.__wbg_ptr, unix);\n }\n /**\n * Draw PNG stamps over the pages of an existing PDF, and return the file with them added as an incremental\n * update: the input, byte for byte, then the images and the pages they change. The original bytes stay as they\n * were, so an owner password and its permissions stay, and so does a digital signature\'s revision.\n *\n * `stamps` is a JSON list of stamps, each with an `image`, the name of a PNG loaded with `load_image`, a `page`\n * scope, a box (`x`, `y`, `anchor`, `width`, `height`, placed as a layer element is) and how the image sits in it\n * (`align`, `justify`, `scale`, `max-grow`). Without a valid license key, each stamped page gets the attribution\n * line of a render in its top-right corner.\n * @param {Uint8Array} pdf\n * @param {string} stamps\n * @returns {Uint8Array}\n */\n stamp(pdf, stamps) {\n const ptr0 = passArray8ToWasm0(pdf, wasm.__wbindgen_malloc);\n const len0 = WASM_VECTOR_LEN;\n const ptr1 = passStringToWasm0(stamps, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n const len1 = WASM_VECTOR_LEN;\n const ret = wasm.lpdfengine_stamp(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n if (ret[3]) {\n throw takeFromExternrefTable0(ret[2]);\n }\n var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n return v3;\n }\n };\n if (Symbol.dispose) LpdfEngine.prototype[Symbol.dispose] = LpdfEngine.prototype.free;\n function __wbg_get_imports() {\n const import0 = {\n __proto__: null,\n __wbg___wbindgen_throw_6b64449b9b9ed33c: function(arg0, arg1) {\n throw new Error(getStringFromWasm0(arg0, arg1));\n },\n __wbg_getRandomValues_cc7f052a444bb2ce: function() {\n return handleError(function(arg0, arg1) {\n globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));\n }, arguments);\n },\n __wbindgen_cast_0000000000000001: function(arg0, arg1) {\n const ret = getStringFromWasm0(arg0, arg1);\n return ret;\n },\n __wbindgen_init_externref_table: function() {\n const table = wasm.__wbindgen_externrefs;\n const offset = table.grow(4);\n table.set(0, void 0);\n table.set(offset + 0, void 0);\n table.set(offset + 1, null);\n table.set(offset + 2, true);\n table.set(offset + 3, false);\n }\n };\n return {\n __proto__: null,\n "./lpdf_bg.js": import0\n };\n }\n var LpdfEngineFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {\n }, unregister: () => {\n } } : new FinalizationRegistry((ptr) => wasm.__wbg_lpdfengine_free(ptr >>> 0, 1));\n function addToExternrefTable0(obj) {\n const idx = wasm.__externref_table_alloc();\n wasm.__wbindgen_externrefs.set(idx, obj);\n return idx;\n }\n function getArrayU8FromWasm0(ptr, len) {\n ptr = ptr >>> 0;\n return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);\n }\n function getStringFromWasm0(ptr, len) {\n ptr = ptr >>> 0;\n return decodeText(ptr, len);\n }\n var cachedUint8ArrayMemory0 = null;\n function getUint8ArrayMemory0() {\n if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {\n cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);\n }\n return cachedUint8ArrayMemory0;\n }\n function handleError(f, args) {\n try {\n return f.apply(this, args);\n } catch (e) {\n const idx = addToExternrefTable0(e);\n wasm.__wbindgen_exn_store(idx);\n }\n }\n function isLikeNone(x) {\n return x === void 0 || x === null;\n }\n function passArray8ToWasm0(arg, malloc) {\n const ptr = malloc(arg.length * 1, 1) >>> 0;\n getUint8ArrayMemory0().set(arg, ptr / 1);\n WASM_VECTOR_LEN = arg.length;\n return ptr;\n }\n function passStringToWasm0(arg, malloc, realloc) {\n if (realloc === void 0) {\n const buf = cachedTextEncoder.encode(arg);\n const ptr2 = malloc(buf.length, 1) >>> 0;\n getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf);\n WASM_VECTOR_LEN = buf.length;\n return ptr2;\n }\n let len = arg.length;\n let ptr = malloc(len, 1) >>> 0;\n const mem = getUint8ArrayMemory0();\n let offset = 0;\n for (; offset < len; offset++) {\n const code = arg.charCodeAt(offset);\n if (code > 127) break;\n mem[ptr + offset] = code;\n }\n if (offset !== len) {\n if (offset !== 0) {\n arg = arg.slice(offset);\n }\n ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;\n const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);\n const ret = cachedTextEncoder.encodeInto(arg, view);\n offset += ret.written;\n ptr = realloc(ptr, len, offset, 1) >>> 0;\n }\n WASM_VECTOR_LEN = offset;\n return ptr;\n }\n function takeFromExternrefTable0(idx) {\n const value = wasm.__wbindgen_externrefs.get(idx);\n wasm.__externref_table_dealloc(idx);\n return value;\n }\n var cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });\n cachedTextDecoder.decode();\n var MAX_SAFARI_DECODE_BYTES = 2146435072;\n var numBytesDecoded = 0;\n function decodeText(ptr, len) {\n numBytesDecoded += len;\n if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {\n cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });\n cachedTextDecoder.decode();\n numBytesDecoded = len;\n }\n return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));\n }\n var cachedTextEncoder = new TextEncoder();\n if (!("encodeInto" in cachedTextEncoder)) {\n cachedTextEncoder.encodeInto = function(arg, view) {\n const buf = cachedTextEncoder.encode(arg);\n view.set(buf);\n return {\n read: arg.length,\n written: buf.length\n };\n };\n }\n var WASM_VECTOR_LEN = 0;\n var wasmModule;\n var wasm;\n function __wbg_finalize_init(instance, module) {\n wasm = instance.exports;\n wasmModule = module;\n cachedUint8ArrayMemory0 = null;\n wasm.__wbindgen_start();\n return wasm;\n }\n async function __wbg_load(module, imports) {\n if (typeof Response === "function" && module instanceof Response) {\n if (typeof WebAssembly.instantiateStreaming === "function") {\n try {\n return await WebAssembly.instantiateStreaming(module, imports);\n } catch (e) {\n const validResponse = module.ok && expectedResponseType(module.type);\n if (validResponse && module.headers.get("Content-Type") !== "application/wasm") {\n console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\\n", e);\n } else {\n throw e;\n }\n }\n }\n const bytes = await module.arrayBuffer();\n return await WebAssembly.instantiate(bytes, imports);\n } else {\n const instance = await WebAssembly.instantiate(module, imports);\n if (instance instanceof WebAssembly.Instance) {\n return { instance, module };\n } else {\n return instance;\n }\n }\n function expectedResponseType(type) {\n switch (type) {\n case "basic":\n case "cors":\n case "default":\n return true;\n }\n return false;\n }\n }\n async function __wbg_init(module_or_path) {\n if (wasm !== void 0) return wasm;\n if (module_or_path !== void 0) {\n if (Object.getPrototypeOf(module_or_path) === Object.prototype) {\n ({ module_or_path } = module_or_path);\n } else {\n console.warn("using deprecated parameters for the initialization function; pass a single object instead");\n }\n }\n if (module_or_path === void 0) {\n module_or_path = new URL("lpdf_bg.wasm", import_meta.url);\n }\n const imports = __wbg_get_imports();\n if (typeof module_or_path === "string" || typeof Request === "function" && module_or_path instanceof Request || typeof URL === "function" && module_or_path instanceof URL) {\n module_or_path = fetch(module_or_path);\n }\n const { instance, module } = await __wbg_load(await module_or_path, imports);\n return __wbg_finalize_init(instance, module);\n }\n\n // src/render-error.ts\n var ENGINE_CRASHED = "The engine crashed during the render. This is a bug in Lpdf, or the render ran out of memory before its cap stopped it: please report it with the document at https://github.com/lpdfio/lpdf/issues.";\n\n // src/render-job.ts\n function runRenderJob(createEngine, job) {\n let engine;\n let reply;\n try {\n engine = createEngine(job.licenseKey);\n engine.set_now(job.now);\n engine.set_max_memory_mb(job.maxMemoryMb);\n if (job.createdOn) engine.set_created_on(job.createdOn);\n for (const [name, bytes] of job.fonts) engine.load_font(name, bytes);\n for (const [name, bytes] of job.images) engine.load_image(name, bytes);\n for (const [name, bytes] of job.files) engine.load_file(name, bytes);\n for (const [name, bytes] of job.profiles) engine.load_profile(name, bytes);\n for (const [src, text] of job.markdownStyles) engine.load_markdown_styles(src, text);\n const { document } = job;\n const pdf = "xml" in document ? engine.render_pdf(document.xml, document.data, ...job.encryption) : "tree" in document ? engine.render_tree_pdf(document.tree, ...job.encryption) : engine.stamp(document.pdf, document.stamps);\n reply = { pdf };\n } catch (e) {\n const crashed = e instanceof WebAssembly.RuntimeError || e instanceof RangeError;\n reply = crashed ? { error: ENGINE_CRASHED, broken: true, cause: `${e.name}: ${e.message}` } : { error: e instanceof Error ? e.message : String(e), broken: false };\n }\n if ("pdf" in reply || !reply.broken) {\n try {\n engine?.free();\n } catch {\n if ("error" in reply) reply = { ...reply, broken: true };\n }\n }\n return reply;\n }\n function transferList(reply) {\n if (!("pdf" in reply)) return [];\n const { buffer, byteLength } = reply.pdf;\n return buffer instanceof ArrayBuffer && buffer.byteLength === byteLength ? [buffer] : [];\n }\n\n // src/browser-worker.ts\n var ready;\n self.onmessage = async (event) => {\n const message = event.data;\n if ("module" in message) {\n const loading = __wbg_init({ module_or_path: message.module });\n loading.catch(() => void 0);\n ready = loading;\n return;\n }\n let reply;\n try {\n if (!ready) throw new Error("the worker was sent no engine");\n await ready;\n } catch (e) {\n reply = { error: `The engine did not load: ${e instanceof Error ? e.message : String(e)}`, broken: true };\n self.postMessage(reply);\n return;\n }\n try {\n reply = runRenderJob((licenseKey) => new LpdfEngine(licenseKey), message);\n } catch (e) {\n reply = { error: e instanceof Error ? e.message : String(e), broken: true };\n }\n self.postMessage(reply, { transfer: transferList(reply) });\n };\n})();\n'], { type: "text/javascript" }));
738
+ const worker = new Worker(renderWorkerUrl, { name: "lpdf-render" });
739
+ worker.onmessage = (event) => events.replied(event.data);
740
+ worker.onerror = (event) => {
741
+ event.preventDefault();
742
+ events.failed(
743
+ `The render worker failed${event.message ? `: ${event.message}` : ""}. A page with a Content-Security-Policy must allow blob: in worker-src for it.`
744
+ );
745
+ };
746
+ worker.onmessageerror = () => events.failed("A reply of the render worker could not be read.");
747
+ worker.postMessage({ module });
748
+ return {
749
+ post: (job) => worker.postMessage(job),
750
+ terminate: () => worker.terminate()
751
+ };
752
+ }
753
+ async function initLpdf(wasmSource, licenseKey = "", options = {}) {
754
+ const timeout = renderTimeout(options.timeout);
755
+ const memory = maxMemoryMb(options.maxMemoryMb);
756
+ const module = await compileEngine(wasmSource);
757
+ await __wbg_init({ module_or_path: module });
758
+ const queue = new RenderQueue((events) => startBrowserWorker(module, events));
530
759
  const fontMap = /* @__PURE__ */ new Map();
531
760
  const imageMap = /* @__PURE__ */ new Map();
532
761
  const fileMap = /* @__PURE__ */ new Map();
@@ -552,48 +781,48 @@ async function initLpdf(wasmSource, licenseKey = "") {
552
781
  return JSON.parse(check_license(key ?? licenseKey, nowUnix()));
553
782
  },
554
783
  async render(input, callOptions = {}) {
555
- const engine = new LpdfEngine(licenseKey);
556
- engine.set_now(nowUnix());
557
- for (const [name, bytes] of fontMap) {
558
- engine.load_font(name, bytes);
559
- }
560
- for (const [name, bytes] of imageMap) {
561
- engine.load_image(name, bytes);
562
- }
563
- for (const [name, bytes] of fileMap) {
564
- engine.load_file(name, bytes);
565
- }
566
- for (const [name, bytes] of profileMap) {
567
- engine.load_profile(name, bytes);
568
- }
569
- for (const [src, text] of markdownStyles) {
570
- engine.load_markdown_styles(src, text);
571
- }
572
- if (callOptions.createdOn) {
573
- engine.set_created_on(callOptions.createdOn);
574
- }
575
- const encryption = encryptionArguments(callOptions, secureRandomBytes);
576
- let pdf;
577
- try {
578
- if (typeof input === "string") {
579
- const dataJson = callOptions.data != null ? JSON.stringify(callOptions.data) : null;
580
- pdf = engine.render_pdf(input, dataJson, ...encryption);
581
- } else {
582
- pdf = engine.render_tree_pdf(JSON.stringify(input), ...encryption);
583
- }
584
- } finally {
585
- engine.free();
586
- }
587
- return pdf;
784
+ const job = {
785
+ licenseKey,
786
+ now: nowUnix(),
787
+ maxMemoryMb: memory,
788
+ createdOn: callOptions.createdOn,
789
+ fonts: new Map(fontMap),
790
+ images: new Map(imageMap),
791
+ files: new Map(fileMap),
792
+ profiles: new Map(profileMap),
793
+ markdownStyles: new Map(markdownStyles),
794
+ document: typeof input === "string" ? { xml: input, data: callOptions.data != null ? JSON.stringify(callOptions.data) : null } : { tree: JSON.stringify(input) },
795
+ encryption: encryptionArguments(callOptions, secureRandomBytes)
796
+ };
797
+ return queue.render(job, timeout);
798
+ },
799
+ async stamp(pdf, stamps) {
800
+ const { stamps: json, images } = stampRequest(stamps);
801
+ const job = {
802
+ licenseKey,
803
+ now: nowUnix(),
804
+ maxMemoryMb: memory,
805
+ createdOn: void 0,
806
+ fonts: /* @__PURE__ */ new Map(),
807
+ images,
808
+ files: /* @__PURE__ */ new Map(),
809
+ profiles: /* @__PURE__ */ new Map(),
810
+ markdownStyles: /* @__PURE__ */ new Map(),
811
+ document: { pdf, stamps: json },
812
+ encryption: [null, null, false, new Uint8Array()]
813
+ };
814
+ return queue.render(job, timeout);
588
815
  }
589
816
  };
590
817
  }
591
818
  export {
592
819
  BuiltinFont,
593
820
  Cipher,
821
+ ColumnFill,
594
822
  FieldType,
595
823
  FileRelationship,
596
824
  FootnoteCounter,
825
+ LpdfRenderError,
597
826
  NoAttr,
598
827
  Orientation,
599
828
  PageScope,
@@ -13,6 +13,7 @@ export declare const Pin: {
13
13
  readonly Bottom: "bottom";
14
14
  readonly Left: "left";
15
15
  readonly Right: "right";
16
+ readonly Inset: "inset";
16
17
  };
17
18
  export type Pin = (typeof Pin)[keyof typeof Pin];
18
19
  /** The values of the `orientation` attribute of a document or a section. */
@@ -33,6 +34,12 @@ export declare const FootnoteCounter: {
33
34
  readonly Document: "document";
34
35
  };
35
36
  export type FootnoteCounter = (typeof FootnoteCounter)[keyof typeof FootnoteCounter];
37
+ /** The values of the `column-fill` attribute of a section: how the columns of its last page fill. */
38
+ export declare const ColumnFill: {
39
+ readonly Auto: "auto";
40
+ readonly Balance: "balance";
41
+ };
42
+ export type ColumnFill = (typeof ColumnFill)[keyof typeof ColumnFill];
36
43
  /** The values of the `encrypt` attribute of the output: the cipher the PDF is encrypted with. */
37
44
  export declare const Cipher: {
38
45
  readonly Aes256: "aes-256";
package/dist/constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // Generated from lpdf.xsd by scripts/gen-sdk-api.mjs.
3
3
  // Do not edit: change the schema and run `make gen-sdk-api`.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.PageScope = exports.BuiltinFont = exports.FileRelationship = exports.Permission = exports.Cipher = exports.FootnoteCounter = exports.SectionType = exports.Orientation = exports.Pin = exports.FieldType = void 0;
5
+ exports.PageScope = exports.BuiltinFont = exports.FileRelationship = exports.Permission = exports.Cipher = exports.ColumnFill = exports.FootnoteCounter = exports.SectionType = exports.Orientation = exports.Pin = exports.FieldType = void 0;
6
6
  /** The values of the `type` attribute of a field. */
7
7
  exports.FieldType = {
8
8
  Text: 'text',
@@ -17,6 +17,7 @@ exports.Pin = {
17
17
  Bottom: 'bottom',
18
18
  Left: 'left',
19
19
  Right: 'right',
20
+ Inset: 'inset',
20
21
  };
21
22
  /** The values of the `orientation` attribute of a document or a section. */
22
23
  exports.Orientation = {
@@ -33,6 +34,11 @@ exports.FootnoteCounter = {
33
34
  Section: 'section',
34
35
  Document: 'document',
35
36
  };
37
+ /** The values of the `column-fill` attribute of a section: how the columns of its last page fill. */
38
+ exports.ColumnFill = {
39
+ Auto: 'auto',
40
+ Balance: 'balance',
41
+ };
36
42
  /** The values of the `encrypt` attribute of the output: the cipher the PDF is encrypted with. */
37
43
  exports.Cipher = {
38
44
  Aes256: 'aes-256',
package/dist/engine.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { type RenderOptions } from './_shared';
1
+ import { type EngineOptions, type RenderOptions } from './_shared';
2
2
  import type { PdfDocument } from './kit';
3
+ import { type StampAttr } from './stamp';
4
+ export { LpdfRenderError } from './render-error';
3
5
  /** How a license key stands with this build of the engine. */
4
6
  export type LicenseStatus = 'licensed' | 'no_key' | 'expired' | 'version_mismatch' | 'wrong_product' | 'unknown_key' | 'bad_signature' | 'malformed';
5
7
  /**
@@ -22,10 +24,6 @@ export interface LicenseCheck {
22
24
  /** Which key this is on its license — 1, 2, 3 in issue order. */
23
25
  key?: number;
24
26
  }
25
- /** Thrown when the lpdf engine returns a layout or parse error. */
26
- export declare class LpdfRenderError extends Error {
27
- constructor(message: string);
28
- }
29
27
  export declare class PdfEngine {
30
28
  private _licenseKey;
31
29
  private readonly _fonts;
@@ -33,8 +31,17 @@ export declare class PdfEngine {
33
31
  private readonly _files;
34
32
  private readonly _profiles;
35
33
  private readonly _markdownStyles;
34
+ private readonly _timeout;
35
+ private readonly _maxMemoryMb;
36
36
  private _disposed;
37
- constructor();
37
+ /**
38
+ * @param options - Engine-level options: `timeout`, the seconds a render may run before it rejects with an
39
+ * `LpdfRenderError` that names the limit, 5 when left out and no limit at 0; `maxMemoryMb`, the megabytes a render
40
+ * may allocate before it rejects with an `LpdfRenderError` that names the cap, 1024 when left out.
41
+ * @throws {RangeError} when `timeout` is negative or not a finite number, or `maxMemoryMb` is not a whole number
42
+ * from 1 to 4096.
43
+ */
44
+ constructor(options?: EngineOptions);
38
45
  /**
39
46
  * Set the license key. Returns `this` for chaining.
40
47
  */
@@ -84,27 +91,53 @@ export declare class PdfEngine {
84
91
  dispose(): void;
85
92
  [Symbol.dispose](): void;
86
93
  /**
87
- * Hand the engine the files of Markdown rules that a document names: the ones loaded here, and the ones read from
88
- * their `src`. A file that can't be read is left for the engine to report, naming the `src`.
94
+ * The files of Markdown rules that a document names: the ones loaded here, and the ones read from their `src`. A
95
+ * file that can't be read is left for the engine to report, naming the `src`.
89
96
  */
90
- private _loadMarkdownStyles;
97
+ private _markdownStylesFor;
91
98
  /**
92
- * Hand the engine the files the document carries: the ones loaded here, and the ones read from the `src` of a file
93
- * that wasn't. A `src` that can't be read is an error that names the file and the path.
99
+ * The files the document carries: the ones loaded here, and the ones read from the `src` of a file that wasn't. A
100
+ * `src` that can't be read is an error that names the file and the path.
94
101
  */
95
- private _loadFiles;
102
+ private _filesFor;
96
103
  /**
97
- * Hand the engine the color profiles the document declares: the ones loaded here, and the ones read from the `src`
98
- * of a profile that wasn't. A `src` that can't be read is an error that names the profile and the path.
104
+ * The color profiles the document declares: the ones loaded here, and the ones read from the `src` of a profile
105
+ * that wasn't. A `src` that can't be read is an error that names the profile and the path.
99
106
  */
100
- private _loadProfiles;
107
+ private _profilesFor;
101
108
  private _throwIfDisposed;
102
109
  /**
103
110
  * Render an lpdf XML string to PDF bytes (Node.js).
111
+ *
112
+ * The render runs on a worker thread, after the renders before it. It rejects with an `LpdfRenderError` when the
113
+ * engine refuses the document, when it runs past the engine's `timeout` or needs more than its `maxMemoryMb`, or
114
+ * when the engine crashes, after which the next render runs on a fresh engine.
104
115
  */
105
116
  render(input: string, callOptions?: RenderOptions): Promise<Uint8Array>;
106
117
  /**
107
- * Render a `PdfDocument` tree (built with `Pdf.document`) to PDF bytes (Node.js).
118
+ * Render a `PdfDocument` tree (built with `Pdf.document`) to PDF bytes (Node.js), on a worker thread as an XML
119
+ * string is.
108
120
  */
109
121
  render(input: PdfDocument, callOptions?: RenderOptions): Promise<Uint8Array>;
122
+ /**
123
+ * Draw PNG images over the pages of an existing PDF, and return the PDF with them (Node.js). Nothing is laid out:
124
+ * each image is drawn in its stamp's box, over the pages its `page` names.
125
+ *
126
+ * The output is the input, byte for byte, with an incremental update after it, so an owner password and its
127
+ * permissions stay, and so does a digital signature, for the revision it signed. A PDF/A file stays PDF/A. Without a
128
+ * license key each stamped page gets the attribution line in its top-right corner. A stamp covers what is under it
129
+ * and does not remove it: the text under an image can still be selected and found, so a stamp is not a redaction.
130
+ *
131
+ * The stamp runs on a worker thread, as a render does, with its `timeout` and `maxMemoryMb`. It rejects with an
132
+ * `LpdfRenderError` when the input is not a PDF, needs a password to open, or doesn't have a page a stamp names, and
133
+ * when an image is not a PNG or a stamp's options are wrong.
134
+ *
135
+ * @throws {TypeError} when a stamp's `image` is not the PNG's bytes.
136
+ */
137
+ stamp(pdf: Uint8Array, stamps: StampAttr[]): Promise<Uint8Array>;
138
+ /**
139
+ * A render of `input` with every file it needs, read here from the `src` of each font, image, file, profile and
140
+ * file of rules the document names and that wasn't loaded: the worker reads nothing itself.
141
+ */
142
+ private _job;
110
143
  }