@embedpdf/plugin-stamp 3.0.0-next.12 → 3.0.0-next.14
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/{contract-BFCBVNRX.js → contract-B79Onij2.js} +13 -3
- package/dist/contract-B79Onij2.js.map +1 -0
- package/dist/{contract-WXRZPOWE.d.ts → contract-BS3m51Au.d.cts} +68 -6
- package/dist/{contract-C6CgKD69.cjs → contract-T-v5KaYd.cjs} +30 -2
- package/dist/contract-T-v5KaYd.cjs.map +1 -0
- package/dist/{contract-PLwYe8Zn.d.cts → contract-VuCLK5Sr.d.ts} +68 -6
- package/dist/contract.cjs +4 -1
- package/dist/contract.d.cts +2 -2
- package/dist/contract.d.ts +2 -2
- package/dist/contract.js +2 -2
- package/dist/index.cjs +194 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +192 -7
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
- package/dist/contract-BFCBVNRX.js.map +0 -1
- package/dist/contract-C6CgKD69.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_contract = require("./contract-
|
|
2
|
+
const require_contract = require("./contract-T-v5KaYd.cjs");
|
|
3
3
|
let _embedpdf_core = require("@embedpdf/core");
|
|
4
4
|
let _embedpdf_engine_core_runtime = require("@embedpdf/engine-core/runtime");
|
|
5
5
|
let _embedpdf_core_acrojs = require("@embedpdf/core-acrojs");
|
|
6
6
|
let _embedpdf_plugin_actions_contract_host = require("@embedpdf/plugin-actions/contract/host");
|
|
7
7
|
let _embedpdf_plugin_annotation_contract = require("@embedpdf/plugin-annotation/contract");
|
|
8
|
+
let _embedpdf_plugin_annotation_contract_host = require("@embedpdf/plugin-annotation/contract/host");
|
|
8
9
|
let _embedpdf_plugin_form_scripting = require("@embedpdf/plugin-form/scripting");
|
|
9
10
|
//#region src/blank-library.ts
|
|
10
11
|
/**
|
|
@@ -38,6 +39,51 @@ function blankLibraryPdf() {
|
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/capability.ts
|
|
40
41
|
const DEFAULT_PREVIEW_WIDTH = 256;
|
|
42
|
+
/** `#rrggbb` → the engine's sRGB triplet. */
|
|
43
|
+
const hexColor = (hex) => {
|
|
44
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
45
|
+
if (!m) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, `[stamp] mark color must be #rrggbb, got '${hex}'`);
|
|
46
|
+
const n = parseInt(m[1], 16);
|
|
47
|
+
return {
|
|
48
|
+
r: n >> 16 & 255,
|
|
49
|
+
g: n >> 8 & 255,
|
|
50
|
+
b: n & 255
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/** An exact ArrayBuffer over a view (the engine's binary idiom). */
|
|
54
|
+
const toArrayBuffer = (bytes) => {
|
|
55
|
+
const out = new ArrayBuffer(bytes.byteLength);
|
|
56
|
+
new Uint8Array(out).set(bytes);
|
|
57
|
+
return out;
|
|
58
|
+
};
|
|
59
|
+
/** The rect an ink mark occupies, padded by its stroke. */
|
|
60
|
+
const inkBounds = (strokes, strokeWidth) => {
|
|
61
|
+
let left = Infinity;
|
|
62
|
+
let bottom = Infinity;
|
|
63
|
+
let right = -Infinity;
|
|
64
|
+
let top = -Infinity;
|
|
65
|
+
for (const stroke of strokes) for (const { x, y } of stroke) {
|
|
66
|
+
if (x < left) left = x;
|
|
67
|
+
if (x > right) right = x;
|
|
68
|
+
if (y < bottom) bottom = y;
|
|
69
|
+
if (y > top) top = y;
|
|
70
|
+
}
|
|
71
|
+
if (!Number.isFinite(left)) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, "[stamp] an ink mark needs at least one point");
|
|
72
|
+
const pad = strokeWidth;
|
|
73
|
+
return {
|
|
74
|
+
left: left - pad,
|
|
75
|
+
bottom: bottom - pad,
|
|
76
|
+
right: right + pad,
|
|
77
|
+
top: top + pad
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
/** A generous box for typed text; the export crops to the glyphs. */
|
|
81
|
+
const textBounds = (text, fontSize) => ({
|
|
82
|
+
left: 0,
|
|
83
|
+
bottom: 0,
|
|
84
|
+
right: Math.max(1, text.length) * fontSize * .75 + fontSize,
|
|
85
|
+
top: fontSize * 1.6
|
|
86
|
+
});
|
|
41
87
|
/** Session-unique ids. Assets are session-scoped for now (no persistence),
|
|
42
88
|
* so a timestamp + counter is enough — durable ids come with the store port. */
|
|
43
89
|
let seq = 0;
|
|
@@ -129,6 +175,7 @@ function createStampCapability(ctx, config = {}) {
|
|
|
129
175
|
format: "png"
|
|
130
176
|
}));
|
|
131
177
|
const createLibrary = async (name, opts) => {
|
|
178
|
+
const kind = opts?.kind ?? "stamps";
|
|
132
179
|
const taken = new Set(Object.keys(ctx.getState().libraries));
|
|
133
180
|
const id = allocateId(opts?.id, "stamp-lib", taken);
|
|
134
181
|
const doc = await openAssetDocument(blankLibraryPdf());
|
|
@@ -136,7 +183,10 @@ function createStampCapability(ctx, config = {}) {
|
|
|
136
183
|
try {
|
|
137
184
|
requireCanonicalServices(doc);
|
|
138
185
|
await doc.metadata.update({ title: name });
|
|
139
|
-
await doc.pieceInfo.update(require_contract.STAMP_LIBRARY_PIECEINFO_APP, require_contract.stampLibraryPieceInfo(id, {
|
|
186
|
+
await doc.pieceInfo.update(require_contract.STAMP_LIBRARY_PIECEINFO_APP, require_contract.stampLibraryPieceInfo(id, {
|
|
187
|
+
kind,
|
|
188
|
+
categories: opts?.categories
|
|
189
|
+
}));
|
|
140
190
|
bytes = await doc.download();
|
|
141
191
|
} finally {
|
|
142
192
|
await doc.close();
|
|
@@ -147,6 +197,7 @@ function createStampCapability(ctx, config = {}) {
|
|
|
147
197
|
library: {
|
|
148
198
|
id,
|
|
149
199
|
name,
|
|
200
|
+
kind,
|
|
150
201
|
assetIds: [],
|
|
151
202
|
...opts?.categories ? { categories: opts.categories } : {}
|
|
152
203
|
}
|
|
@@ -180,6 +231,7 @@ function createStampCapability(ctx, config = {}) {
|
|
|
180
231
|
if (!docMeta.title) await doc.metadata.update({ title: libraryName });
|
|
181
232
|
const libraryCategories = opts?.categories ?? entryStringArray(catalogEntries, "Categories");
|
|
182
233
|
const libraryLocale = entryString(catalogEntries, "Locale");
|
|
234
|
+
const libraryKind = opts?.libraryKind ?? require_contract.libraryKindFromPdfName(entryName(catalogEntries, "Kind"));
|
|
183
235
|
const registry = (layout.namedPages ?? []).filter((entry) => entry.target.kind === "page");
|
|
184
236
|
const hidden = (layout.namedPages ?? []).filter((entry) => entry.target.kind !== "page");
|
|
185
237
|
if (hidden.length > 0) globalThis.console?.warn(`[stamp] library '${libraryName}' carries ${hidden.length} hidden-template or dangling registration(s); they are not stamps and were ignored`);
|
|
@@ -220,6 +272,7 @@ function createStampCapability(ctx, config = {}) {
|
|
|
220
272
|
});
|
|
221
273
|
}
|
|
222
274
|
await doc.pieceInfo.update(require_contract.STAMP_LIBRARY_PIECEINFO_APP, require_contract.stampLibraryPieceInfo(libraryId, {
|
|
275
|
+
kind: libraryKind,
|
|
223
276
|
categories: libraryCategories,
|
|
224
277
|
locale: libraryLocale
|
|
225
278
|
}));
|
|
@@ -261,6 +314,7 @@ function createStampCapability(ctx, config = {}) {
|
|
|
261
314
|
library: {
|
|
262
315
|
id: libraryId,
|
|
263
316
|
name: libraryName,
|
|
317
|
+
kind: libraryKind,
|
|
264
318
|
...libraryLocale ? { locale: libraryLocale } : {},
|
|
265
319
|
categories: libraryCategories,
|
|
266
320
|
assetIds: []
|
|
@@ -292,9 +346,76 @@ function createStampCapability(ctx, config = {}) {
|
|
|
292
346
|
});
|
|
293
347
|
return imported.library.id;
|
|
294
348
|
};
|
|
349
|
+
/**
|
|
350
|
+
* A drawn or typed mark rendered to a one-page PDF: the annotation is
|
|
351
|
+
* authored on a scratch page and exported the way "stamp from selection"
|
|
352
|
+
* exports — a fresh page the size of the mark, paths kept as paths, the
|
|
353
|
+
* font subset-embedded. Self-contained and Acrobat-readable.
|
|
354
|
+
*/
|
|
355
|
+
const renderMark = async (mark) => {
|
|
356
|
+
const doc = await openAssetDocument(blankLibraryPdf());
|
|
357
|
+
try {
|
|
358
|
+
const scratch = (await doc.pages.list()).pages[0];
|
|
359
|
+
if (!scratch) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.Unknown, "[stamp] no scratch page");
|
|
360
|
+
const page = doc.page(scratch.pageObjectNumber);
|
|
361
|
+
if (!page.annotations.exportAppearance) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.NotImplemented, "[stamp] authoring a mark needs an asset engine that can export annotation appearances");
|
|
362
|
+
const color = hexColor(mark.color ?? "#1d2b53");
|
|
363
|
+
const created = mark.kind === "ink" ? await page.annotations.create({
|
|
364
|
+
subtype: "ink",
|
|
365
|
+
inkList: mark.strokes.map((stroke) => stroke.map(({ x, y }) => ({
|
|
366
|
+
x,
|
|
367
|
+
y
|
|
368
|
+
}))),
|
|
369
|
+
rect: inkBounds(mark.strokes, mark.strokeWidth ?? 2),
|
|
370
|
+
color,
|
|
371
|
+
strokeWidth: mark.strokeWidth ?? 2
|
|
372
|
+
}) : await page.annotations.create({
|
|
373
|
+
subtype: "free-text",
|
|
374
|
+
intent: "free-text",
|
|
375
|
+
contents: mark.text,
|
|
376
|
+
fontFamily: mark.fontFamily,
|
|
377
|
+
fontSize: mark.fontSize ?? 36,
|
|
378
|
+
textAlign: "left",
|
|
379
|
+
rect: textBounds(mark.text, mark.fontSize ?? 36),
|
|
380
|
+
fontColor: color,
|
|
381
|
+
strokeWidth: 0
|
|
382
|
+
});
|
|
383
|
+
return new Uint8Array(await page.annotations.exportAppearance([created.created.ref]));
|
|
384
|
+
} finally {
|
|
385
|
+
await doc.close();
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
/** One page of a PDF as a single-page PDF (a `pdf` mark with `pageIndex`). */
|
|
389
|
+
const extractPage = async (bytes, pageIndex) => {
|
|
390
|
+
const doc = await openAssetDocument(bytes);
|
|
391
|
+
try {
|
|
392
|
+
const layout = await doc.pages.list();
|
|
393
|
+
const page = layout.pages[pageIndex];
|
|
394
|
+
if (!page) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, `[stamp] the PDF has no page ${pageIndex} (${layout.pageCount} pages)`);
|
|
395
|
+
return await doc.pages.extract([page.pageObjectNumber]);
|
|
396
|
+
} finally {
|
|
397
|
+
await doc.close();
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
/** The bytes an asset is made from: the caller's `source`, or its `mark` authored into one. */
|
|
401
|
+
const resolveAssetSource = async (input) => {
|
|
402
|
+
if (input.source === void 0 === (input.mark === void 0)) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, "[stamp] addAsset takes exactly one of `source` / `mark`");
|
|
403
|
+
if (input.source !== void 0) return (0, _embedpdf_engine_core_runtime.resolveBinarySource)(input.source);
|
|
404
|
+
const mark = input.mark;
|
|
405
|
+
switch (mark.kind) {
|
|
406
|
+
case "image": return (0, _embedpdf_engine_core_runtime.resolveBinarySource)(mark.source);
|
|
407
|
+
case "pdf": {
|
|
408
|
+
const resolved = await (0, _embedpdf_engine_core_runtime.resolveBinarySource)(mark.source);
|
|
409
|
+
if (mark.pageIndex === void 0) return resolved;
|
|
410
|
+
return { bytes: toArrayBuffer(await extractPage(new Uint8Array(resolved.bytes), mark.pageIndex)) };
|
|
411
|
+
}
|
|
412
|
+
case "ink":
|
|
413
|
+
case "text": return { bytes: toArrayBuffer(await renderMark(mark)) };
|
|
414
|
+
}
|
|
415
|
+
};
|
|
295
416
|
const addAsset = async (input) => {
|
|
296
417
|
if (input.libraryId && !ctx.getState().libraries[input.libraryId]) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.NotFound, `[stamp] unknown library '${input.libraryId}'`);
|
|
297
|
-
const resolved = await (
|
|
418
|
+
const resolved = await resolveAssetSource(input);
|
|
298
419
|
const meta = (0, _embedpdf_engine_core_runtime.sniffBinaryMetadata)(resolved.bytes);
|
|
299
420
|
if (!meta) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.InvalidArg, "[stamp] asset source must be PNG, JPEG, or single-page PDF bytes");
|
|
300
421
|
const isPdf = meta.mimeType === "application/pdf";
|
|
@@ -503,6 +624,43 @@ function createStampCapability(ctx, config = {}) {
|
|
|
503
624
|
});
|
|
504
625
|
});
|
|
505
626
|
};
|
|
627
|
+
const updateLibrary = async (id, patch) => {
|
|
628
|
+
if (!ctx.getState().libraries[id]) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.NotFound, `[stamp] unknown library '${id}'`);
|
|
629
|
+
return mutateLibrary(id, async () => {
|
|
630
|
+
const library = ctx.getState().libraries[id];
|
|
631
|
+
if (!library) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.NotFound, `[stamp] unknown library '${id}'`);
|
|
632
|
+
const canonicalBytes = libraryBinaries.get(id);
|
|
633
|
+
if (!canonicalBytes) throw new _embedpdf_engine_core_runtime.EngineError(_embedpdf_engine_core_runtime.EngineErrorCode.Unknown, `[stamp] canonical bytes are missing for library '${id}'`);
|
|
634
|
+
const next = {
|
|
635
|
+
...library,
|
|
636
|
+
...patch.name !== void 0 ? { name: patch.name } : {},
|
|
637
|
+
...patch.categories !== void 0 ? { categories: patch.categories } : {}
|
|
638
|
+
};
|
|
639
|
+
const doc = await openAssetDocument(canonicalBytes);
|
|
640
|
+
let rewritten;
|
|
641
|
+
try {
|
|
642
|
+
requireCanonicalServices(doc);
|
|
643
|
+
if (next.name !== library.name) await doc.metadata.update({ title: next.name });
|
|
644
|
+
await doc.pieceInfo.update(require_contract.STAMP_LIBRARY_PIECEINFO_APP, require_contract.stampLibraryPieceInfo(id, {
|
|
645
|
+
kind: next.kind,
|
|
646
|
+
categories: next.categories,
|
|
647
|
+
locale: next.locale
|
|
648
|
+
}));
|
|
649
|
+
rewritten = await doc.download();
|
|
650
|
+
} finally {
|
|
651
|
+
await doc.close();
|
|
652
|
+
}
|
|
653
|
+
libraryBinaries.set(id, rewritten);
|
|
654
|
+
ctx.dispatch({
|
|
655
|
+
type: "LIBRARY_UPDATED",
|
|
656
|
+
library: next
|
|
657
|
+
});
|
|
658
|
+
libraryChanged.emit({
|
|
659
|
+
libraryId: id,
|
|
660
|
+
reason: "updated"
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
};
|
|
506
664
|
/**
|
|
507
665
|
* Form-backed stamps are executable templates only until placement. Work
|
|
508
666
|
* on an isolated copy so neither the canonical library nor its reusable
|
|
@@ -582,6 +740,20 @@ function createStampCapability(ctx, config = {}) {
|
|
|
582
740
|
...stampPayload(asset, placement, placement !== bin),
|
|
583
741
|
targetWidth: opts?.targetWidth
|
|
584
742
|
});
|
|
743
|
+
armedByDocument.set(documentId, assetId);
|
|
744
|
+
};
|
|
745
|
+
/** Which asset this plugin armed per document. The annotation plugin owns
|
|
746
|
+
* the arm itself (a tool switch disarms it), so the answer is checked
|
|
747
|
+
* against it and forgotten once it no longer holds one. */
|
|
748
|
+
const armedByDocument = /* @__PURE__ */ new Map();
|
|
749
|
+
const armedAsset = (documentId) => {
|
|
750
|
+
const assetId = armedByDocument.get(documentId);
|
|
751
|
+
if (assetId === void 0) return null;
|
|
752
|
+
if (!ctx.tryForDocument(_embedpdf_plugin_annotation_contract_host.AnnotationToken, documentId)?.hasArmedStamp()) {
|
|
753
|
+
armedByDocument.delete(documentId);
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
return ctx.getState().assets[assetId] ?? null;
|
|
585
757
|
};
|
|
586
758
|
/**
|
|
587
759
|
* Ghost renders, one per size bucket per asset, rendered lazily on the
|
|
@@ -652,9 +824,10 @@ function createStampCapability(ctx, config = {}) {
|
|
|
652
824
|
if (ownedAssetEngine) Promise.resolve(ownedAssetEngine).then((engine) => engine.destroy()).catch(() => {});
|
|
653
825
|
});
|
|
654
826
|
return {
|
|
655
|
-
libraries: () => {
|
|
827
|
+
libraries: (query) => {
|
|
656
828
|
const s = ctx.getState();
|
|
657
|
-
|
|
829
|
+
const kinds = query?.kind === void 0 ? null : new Set(typeof query.kind === "string" ? [query.kind] : query.kind);
|
|
830
|
+
return s.libraryOrder.map((id) => s.libraries[id]).filter((l) => l != null && (kinds === null || kinds.has(l.kind)));
|
|
658
831
|
},
|
|
659
832
|
library: (id) => ctx.getState().libraries[id] ?? null,
|
|
660
833
|
assets: (libraryId) => {
|
|
@@ -671,6 +844,7 @@ function createStampCapability(ctx, config = {}) {
|
|
|
671
844
|
exportLibrary: (id) => libraryBinaries.get(id) ?? null,
|
|
672
845
|
onLibraryChanged: libraryChanged.on,
|
|
673
846
|
createLibrary,
|
|
847
|
+
updateLibrary,
|
|
674
848
|
importLibraryPdf,
|
|
675
849
|
addAsset,
|
|
676
850
|
addAssetFromAnnotations,
|
|
@@ -679,7 +853,11 @@ function createStampCapability(ctx, config = {}) {
|
|
|
679
853
|
removeLibrary,
|
|
680
854
|
armAsset,
|
|
681
855
|
placeAsset,
|
|
682
|
-
disarm: (documentId) =>
|
|
856
|
+
disarm: (documentId) => {
|
|
857
|
+
armedByDocument.delete(documentId);
|
|
858
|
+
ctx.forDocument(_embedpdf_plugin_annotation_contract.AnnotationToken, documentId).disarmStamp();
|
|
859
|
+
},
|
|
860
|
+
armedAsset
|
|
683
861
|
};
|
|
684
862
|
}
|
|
685
863
|
//#endregion
|
|
@@ -701,6 +879,13 @@ const stampReducer = (state, action) => {
|
|
|
701
879
|
},
|
|
702
880
|
libraryOrder: [...state.libraryOrder, action.library.id]
|
|
703
881
|
};
|
|
882
|
+
case "LIBRARY_UPDATED": return state.libraries[action.library.id] ? {
|
|
883
|
+
...state,
|
|
884
|
+
libraries: {
|
|
885
|
+
...state.libraries,
|
|
886
|
+
[action.library.id]: action.library
|
|
887
|
+
}
|
|
888
|
+
} : state;
|
|
704
889
|
case "LIBRARY_REMOVED": {
|
|
705
890
|
const library = state.libraries[action.libraryId];
|
|
706
891
|
if (!library) return state;
|
|
@@ -851,12 +1036,15 @@ function persistStampLibraries(stamp, store, opts = {}) {
|
|
|
851
1036
|
};
|
|
852
1037
|
}
|
|
853
1038
|
//#endregion
|
|
1039
|
+
exports.DEFAULT_LIBRARY_KIND = require_contract.DEFAULT_LIBRARY_KIND;
|
|
854
1040
|
exports.STAMP_LIBRARY_PIECEINFO_APP = require_contract.STAMP_LIBRARY_PIECEINFO_APP;
|
|
855
1041
|
exports.STAMP_PIECEINFO_APP = require_contract.STAMP_PIECEINFO_APP;
|
|
856
1042
|
exports.STAMP_PIECEINFO_VERSION = require_contract.STAMP_PIECEINFO_VERSION;
|
|
857
1043
|
exports.StampToken = require_contract.StampToken;
|
|
858
1044
|
exports.assetIdFor = require_contract.assetIdFor;
|
|
859
1045
|
exports.customStampName = require_contract.customStampName;
|
|
1046
|
+
exports.libraryKindFromPdfName = require_contract.libraryKindFromPdfName;
|
|
1047
|
+
exports.libraryKindToPdfName = require_contract.libraryKindToPdfName;
|
|
860
1048
|
exports.memoryStampStore = memoryStampStore;
|
|
861
1049
|
exports.parseStampKey = require_contract.parseStampKey;
|
|
862
1050
|
exports.persistStampLibraries = persistStampLibraries;
|