modern-pdf-lib 0.40.0 → 0.40.2
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/README.md +3 -3
- package/dist/browser.cjs +4 -4
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/browser.mjs +4 -4
- package/dist/create.cjs +2 -2
- package/dist/create.mjs +2 -2
- package/dist/forms.cjs +1 -1
- package/dist/forms.mjs +1 -1
- package/dist/{index-CHhHRD6q.d.cts → index-DElljfgJ.d.cts} +2 -2
- package/dist/index-DElljfgJ.d.cts.map +1 -0
- package/dist/{index-CzmWmPxV.d.mts → index-KifTKVe6.d.mts} +2 -2
- package/dist/index-KifTKVe6.d.mts.map +1 -0
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{layout-DvciSXsr.cjs → layout-BaI3QhIe.cjs} +2 -2
- package/dist/{layout-BZ9InKTl.mjs → layout-DAV-X93C.mjs} +2 -2
- package/dist/parse.cjs +1 -1
- package/dist/parse.mjs +1 -1
- package/dist/pdfDocument-BX5o5hI7.d.cts.map +1 -1
- package/dist/pdfDocument-C7TItmPQ.d.mts.map +1 -1
- package/dist/{pdfDocument-Q0wrwKEZ.mjs → pdfDocument-CeA1ysxB.mjs} +111 -12
- package/dist/{pdfDocument-D5qz7duP.cjs → pdfDocument-CnVPQ_Cm.cjs} +111 -12
- package/dist/{pdfForm-CfLnlsj-.mjs → pdfForm-CMeKBmyB.mjs} +4 -4
- package/dist/{pdfForm-BVS_do95.cjs → pdfForm-Dym3PFT3.cjs} +4 -4
- package/dist/{src-wZnfMPwi.mjs → src-CGWTHRll.mjs} +171 -78
- package/dist/{src-aDYhSnal.cjs → src-DFojMRwY.cjs} +171 -78
- package/package.json +3 -3
- package/dist/index-CHhHRD6q.d.cts.map +0 -1
- package/dist/index-CzmWmPxV.d.mts.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_pdfDocument = require("./pdfDocument-
|
|
1
|
+
const require_pdfDocument = require("./pdfDocument-CnVPQ_Cm.cjs");
|
|
2
2
|
const require_pdfObjects = require("./pdfObjects-BcPlSI0a.cjs");
|
|
3
3
|
const require_streamDecode = require("./streamDecode-kQ-REV7v.cjs");
|
|
4
|
-
const require_pdfForm = require("./pdfForm-
|
|
4
|
+
const require_pdfForm = require("./pdfForm-Dym3PFT3.cjs");
|
|
5
5
|
const require_compressionAnalysis = require("./compressionAnalysis-DwxVCe4E.cjs");
|
|
6
6
|
const require_bridge = require("./bridge-ByvzPu5h.cjs");
|
|
7
7
|
const require_loader = require("./loader-DR7H0XOf.cjs");
|
|
@@ -277,7 +277,7 @@ function compressStream(stream, level) {
|
|
|
277
277
|
* @returns The incremental save result.
|
|
278
278
|
*/
|
|
279
279
|
async function saveDocumentIncremental(originalBytes, doc, options) {
|
|
280
|
-
const { buildDocumentStructure } = await Promise.resolve().then(() => require("./pdfDocument-
|
|
280
|
+
const { buildDocumentStructure } = await Promise.resolve().then(() => require("./pdfDocument-CnVPQ_Cm.cjs")).then((n) => n.pdfCatalog_exports);
|
|
281
281
|
const registry = doc.getRegistry();
|
|
282
282
|
const structure = buildDocumentStructure(doc.getInternalPages().map((p) => p.finalize()), {
|
|
283
283
|
producer: doc.getProducer(),
|
|
@@ -28156,16 +28156,40 @@ const EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
28156
28156
|
"pl",
|
|
28157
28157
|
"php"
|
|
28158
28158
|
]);
|
|
28159
|
-
/**
|
|
28160
|
-
|
|
28161
|
-
|
|
28162
|
-
|
|
28159
|
+
/**
|
|
28160
|
+
* Resolve a {@link PdfObject} that may be an indirect reference to its
|
|
28161
|
+
* underlying value using the registry. Non-refs are returned as-is; an
|
|
28162
|
+
* unresolvable ref yields `undefined`. (Mirrors `resolve()` in
|
|
28163
|
+
* `./sanitize.ts`.)
|
|
28164
|
+
*
|
|
28165
|
+
* This is security-critical: a hostile PDF can write a dangerous value
|
|
28166
|
+
* indirectly — e.g. `/S 99 0 R` where object 99 is the name `/JavaScript` — and
|
|
28167
|
+
* a conforming viewer treats that exactly like `/S /JavaScript`. Classifying
|
|
28168
|
+
* `/S`, `/Type`, `/Subtype`, `/UF`, `/F`, and `/URI` without resolving the ref
|
|
28169
|
+
* first would let that one indirection evade detection entirely.
|
|
28170
|
+
*/
|
|
28171
|
+
function resolveRef(obj, registry) {
|
|
28172
|
+
if (obj instanceof require_pdfObjects.PdfRef) return registry.resolve(obj);
|
|
28173
|
+
return obj;
|
|
28174
|
+
}
|
|
28175
|
+
/**
|
|
28176
|
+
* Read a `PdfName` value (without the leading `/`) from a dict entry, resolving
|
|
28177
|
+
* an indirect reference through the registry first.
|
|
28178
|
+
*/
|
|
28179
|
+
function nameValue$1(obj, registry) {
|
|
28180
|
+
const resolved = resolveRef(obj, registry);
|
|
28181
|
+
if (resolved !== void 0 && resolved.kind === "name") {
|
|
28182
|
+
const v = resolved.value;
|
|
28163
28183
|
return v.startsWith("/") ? v.slice(1) : v;
|
|
28164
28184
|
}
|
|
28165
28185
|
}
|
|
28166
|
-
/**
|
|
28167
|
-
|
|
28168
|
-
|
|
28186
|
+
/**
|
|
28187
|
+
* Read a `PdfString` value from a dict entry, resolving an indirect reference
|
|
28188
|
+
* through the registry first.
|
|
28189
|
+
*/
|
|
28190
|
+
function stringValue(obj, registry) {
|
|
28191
|
+
const resolved = resolveRef(obj, registry);
|
|
28192
|
+
if (resolved !== void 0 && resolved.kind === "string") return resolved.value;
|
|
28169
28193
|
}
|
|
28170
28194
|
/** Format a `PdfRef` as the canonical `"N G R"` string, if available. */
|
|
28171
28195
|
function refString(ref) {
|
|
@@ -28220,7 +28244,7 @@ function scanObjectGraph(registry, findings) {
|
|
|
28220
28244
|
if (obj.kind === "dict") dict = obj;
|
|
28221
28245
|
else if (obj.kind === "stream") dict = obj.dict;
|
|
28222
28246
|
if (dict === void 0) continue;
|
|
28223
|
-
inspectDict(dict, refStr, findings);
|
|
28247
|
+
inspectDict(dict, refStr, findings, registry);
|
|
28224
28248
|
}
|
|
28225
28249
|
}
|
|
28226
28250
|
/**
|
|
@@ -28229,8 +28253,10 @@ function scanObjectGraph(registry, findings) {
|
|
|
28229
28253
|
* @param dict The dictionary (or stream dictionary).
|
|
28230
28254
|
* @param refStr The owning object's `"N G R"` string, if known.
|
|
28231
28255
|
* @param findings Accumulator.
|
|
28256
|
+
* @param registry Object registry, used to resolve indirectly-referenced
|
|
28257
|
+
* name/string values (e.g. an `/S` that is a `PdfRef`).
|
|
28232
28258
|
*/
|
|
28233
|
-
function inspectDict(dict, refStr, findings) {
|
|
28259
|
+
function inspectDict(dict, refStr, findings, registry) {
|
|
28234
28260
|
if (dict.has("/OpenAction")) findings.push({
|
|
28235
28261
|
category: "OpenAction",
|
|
28236
28262
|
severity: "medium",
|
|
@@ -28249,15 +28275,15 @@ function inspectDict(dict, refStr, findings) {
|
|
|
28249
28275
|
detail: "A /JavaScript name tree (catalog /Names → /JavaScript) is present; these scripts execute automatically on open (ISO 32000 §12.6.4.16, §7.7.4).",
|
|
28250
28276
|
objectRef: refStr
|
|
28251
28277
|
});
|
|
28252
|
-
const subtype = nameValue$1(dict.get("/S"));
|
|
28253
|
-
if (subtype !== void 0) inspectActionSubtype(subtype, dict, refStr, findings);
|
|
28278
|
+
const subtype = nameValue$1(dict.get("/S"), registry);
|
|
28279
|
+
if (subtype !== void 0) inspectActionSubtype(subtype, dict, refStr, findings, registry);
|
|
28254
28280
|
if (dict.has("/XFA")) findings.push({
|
|
28255
28281
|
category: "XFA",
|
|
28256
28282
|
severity: "low",
|
|
28257
28283
|
detail: "Document contains an XFA form (/AcroForm → /XFA, ISO 32000 §12.7.8); XFA carries its own scripting and data-binding model.",
|
|
28258
28284
|
objectRef: refStr
|
|
28259
28285
|
});
|
|
28260
|
-
const annotSubtype = nameValue$1(dict.get("/Subtype"));
|
|
28286
|
+
const annotSubtype = nameValue$1(dict.get("/Subtype"), registry);
|
|
28261
28287
|
if (annotSubtype === "RichMedia") findings.push({
|
|
28262
28288
|
category: "RichMedia",
|
|
28263
28289
|
severity: "low",
|
|
@@ -28294,8 +28320,8 @@ function inspectDict(dict, refStr, findings) {
|
|
|
28294
28320
|
detail: "Object references sound content via a /Sound entry (ISO 32000 §13.3).",
|
|
28295
28321
|
objectRef: refStr
|
|
28296
28322
|
});
|
|
28297
|
-
if (nameValue$1(dict.get("/Type")) === "Filespec" || dict.has("/EF")) {
|
|
28298
|
-
const fileName = stringValue(dict.get("/UF")) ?? stringValue(dict.get("/F"));
|
|
28323
|
+
if (nameValue$1(dict.get("/Type"), registry) === "Filespec" || dict.has("/EF")) {
|
|
28324
|
+
const fileName = stringValue(dict.get("/UF"), registry) ?? stringValue(dict.get("/F"), registry);
|
|
28299
28325
|
if (fileName !== void 0) {
|
|
28300
28326
|
const ext = extensionOf(fileName);
|
|
28301
28327
|
if (ext !== "" && EXECUTABLE_EXTENSIONS.has(ext)) findings.push({
|
|
@@ -28311,7 +28337,7 @@ function inspectDict(dict, refStr, findings) {
|
|
|
28311
28337
|
* Flag a dangerous action `/S` subtype. Subtypes are ISO 32000 §12.6.4 /
|
|
28312
28338
|
* §12.7.5 action types.
|
|
28313
28339
|
*/
|
|
28314
|
-
function inspectActionSubtype(subtype, dict, refStr, findings) {
|
|
28340
|
+
function inspectActionSubtype(subtype, dict, refStr, findings, registry) {
|
|
28315
28341
|
switch (subtype) {
|
|
28316
28342
|
case "JavaScript":
|
|
28317
28343
|
findings.push({
|
|
@@ -28333,7 +28359,7 @@ function inspectActionSubtype(subtype, dict, refStr, findings) {
|
|
|
28333
28359
|
findings.push({
|
|
28334
28360
|
category: "URI",
|
|
28335
28361
|
severity: "medium",
|
|
28336
|
-
detail: `URI action (/S /URI, ISO 32000 §12.6.4.7) opens a remote URL ${describeUri(dict)}.`,
|
|
28362
|
+
detail: `URI action (/S /URI, ISO 32000 §12.6.4.7) opens a remote URL ${describeUri(dict, registry)}.`,
|
|
28337
28363
|
objectRef: refStr
|
|
28338
28364
|
});
|
|
28339
28365
|
break;
|
|
@@ -28381,8 +28407,8 @@ function inspectActionSubtype(subtype, dict, refStr, findings) {
|
|
|
28381
28407
|
}
|
|
28382
28408
|
}
|
|
28383
28409
|
/** Append the target URL of a /URI action to the detail string, if present. */
|
|
28384
|
-
function describeUri(dict) {
|
|
28385
|
-
const uri = stringValue(dict.get("/URI"));
|
|
28410
|
+
function describeUri(dict, registry) {
|
|
28411
|
+
const uri = stringValue(dict.get("/URI"), registry);
|
|
28386
28412
|
return uri !== void 0 ? `→ "${uri}"` : "";
|
|
28387
28413
|
}
|
|
28388
28414
|
/**
|
|
@@ -28882,6 +28908,10 @@ async function verifyRedactions(pdf, regions) {
|
|
|
28882
28908
|
if (regions === void 0 || regions.length === 0) throw new TypeError("verifyRedactions requires an explicit, non-empty `regions` array. Automatic redaction-region detection is not performed: black-filled rectangles are indistinguishable from legitimate graphics, and a loaded page's original /Redact annotations are not exposed through a stable public API. Pass the regions you redacted (PDF points, bottom-left origin, y-up).");
|
|
28883
28909
|
const doc = await require_pdfDocument.loadPdf(pdf);
|
|
28884
28910
|
const pageCount = doc.getPageCount();
|
|
28911
|
+
for (const region of regions) {
|
|
28912
|
+
const { page } = region;
|
|
28913
|
+
if (!Number.isInteger(page) || page < 0 || page >= pageCount) throw new RangeError(`verifyRedactions: region page index ${page} is out of range. The document has ${pageCount} page(s) (valid indices 0..${pageCount - 1}). Every region must name a real, inspectable page — an out-of-range page cannot be verified and must not be silently reported clean.`);
|
|
28914
|
+
}
|
|
28885
28915
|
const itemsByPage = /* @__PURE__ */ new Map();
|
|
28886
28916
|
const getItems = (pageIndex) => {
|
|
28887
28917
|
const cached = itemsByPage.get(pageIndex);
|
|
@@ -29087,21 +29117,41 @@ function decodePermissionBits(p) {
|
|
|
29087
29117
|
};
|
|
29088
29118
|
}
|
|
29089
29119
|
/**
|
|
29090
|
-
* Test whether the empty user password (`""`) authenticates against the
|
|
29091
|
-
* standard security handler.
|
|
29092
|
-
*
|
|
29093
|
-
*
|
|
29120
|
+
* Test whether the empty **user** password (`""`) authenticates against the
|
|
29121
|
+
* standard security handler.
|
|
29122
|
+
*
|
|
29123
|
+
* This must verify specifically against the `/U` (user) value using the
|
|
29124
|
+
* standard /U validation algorithm — **not** simply check whether the empty
|
|
29125
|
+
* password opens the document. The general file-key derivation
|
|
29126
|
+
* (`PdfEncryptionHandler.fromEncryptDict` / `computeFileEncryptionKey`)
|
|
29127
|
+
* accepts a password that matches **either** the user **or** the owner
|
|
29128
|
+
* password, so a document whose *owner* password is empty (while the user
|
|
29129
|
+
* password is non-empty) would otherwise be mis-reported as having an empty
|
|
29130
|
+
* user password. To avoid asserting a possibly-false `true`, we run the
|
|
29131
|
+
* user-password-specific check ({@link verifyUserPassword}) against `/U`.
|
|
29094
29132
|
*
|
|
29095
|
-
* Returns `undefined` when the test cannot be performed (e.g. the
|
|
29096
|
-
*
|
|
29133
|
+
* Returns `undefined` when the test cannot be performed (e.g. the `/O` / `/U`
|
|
29134
|
+
* values are missing, or the maths throws for an unsupported /V/R).
|
|
29097
29135
|
*/
|
|
29098
29136
|
async function testEmptyUserPassword(dict, fileId) {
|
|
29137
|
+
const ownerKey = getStringBytes(dict, "/O");
|
|
29138
|
+
const userKey = getStringBytes(dict, "/U");
|
|
29139
|
+
if (ownerKey === void 0 || userKey === void 0) return void 0;
|
|
29140
|
+
const dictValues = {
|
|
29141
|
+
version: getNumber(dict, "/V") ?? 0,
|
|
29142
|
+
revision: getNumber(dict, "/R") ?? 0,
|
|
29143
|
+
keyLength: getNumber(dict, "/Length") ?? 40,
|
|
29144
|
+
ownerKey,
|
|
29145
|
+
userKey,
|
|
29146
|
+
permissions: getNumber(dict, "/P") ?? 0,
|
|
29147
|
+
ownerEncryptionKey: getStringBytes(dict, "/OE"),
|
|
29148
|
+
userEncryptionKey: getStringBytes(dict, "/UE"),
|
|
29149
|
+
perms: getStringBytes(dict, "/Perms"),
|
|
29150
|
+
encryptMetadata: getBool(dict, "/EncryptMetadata") ?? true
|
|
29151
|
+
};
|
|
29099
29152
|
try {
|
|
29100
|
-
await require_pdfDocument.
|
|
29101
|
-
|
|
29102
|
-
} catch (err) {
|
|
29103
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
29104
|
-
if (/password/i.test(message)) return false;
|
|
29153
|
+
return await require_pdfDocument.verifyUserPassword("", dictValues, fileId);
|
|
29154
|
+
} catch {
|
|
29105
29155
|
return;
|
|
29106
29156
|
}
|
|
29107
29157
|
}
|
|
@@ -29115,6 +29165,32 @@ function getNumber(dict, key) {
|
|
|
29115
29165
|
const obj = dict.get(key);
|
|
29116
29166
|
if (obj !== void 0 && obj.kind === "number") return obj.value;
|
|
29117
29167
|
}
|
|
29168
|
+
/** Read a boolean value from a dict. */
|
|
29169
|
+
function getBool(dict, key) {
|
|
29170
|
+
const obj = dict.get(key);
|
|
29171
|
+
if (obj !== void 0 && obj.kind === "bool") return obj.value;
|
|
29172
|
+
}
|
|
29173
|
+
/**
|
|
29174
|
+
* Read raw bytes from a `/String` entry.
|
|
29175
|
+
*
|
|
29176
|
+
* Hex strings whose value is still raw hex digits (e.g. produced by
|
|
29177
|
+
* `PdfString.hexFromBytes`) are decoded from hex pairs; otherwise the
|
|
29178
|
+
* character codes are treated as raw Latin-1 bytes. Mirrors the decoding
|
|
29179
|
+
* used by `crypto/encryptionHandler.fromEncryptDict` so the /U validation
|
|
29180
|
+
* sees the same /O, /U, /OE, /UE, /Perms bytes.
|
|
29181
|
+
*/
|
|
29182
|
+
function getStringBytes(dict, key) {
|
|
29183
|
+
const obj = dict.get(key);
|
|
29184
|
+
if (obj === void 0 || obj.kind !== "string") return void 0;
|
|
29185
|
+
const str = obj;
|
|
29186
|
+
if (str.hex && /^[\da-fA-F\s]*$/.test(str.value)) {
|
|
29187
|
+
const clean = str.value.replace(/\s/g, "");
|
|
29188
|
+
return Uint8Array.fromHex(clean.length % 2 === 0 ? clean : clean + "0");
|
|
29189
|
+
}
|
|
29190
|
+
const bytes = new Uint8Array(str.value.length);
|
|
29191
|
+
for (let i = 0; i < str.value.length; i++) bytes[i] = str.value.charCodeAt(i) & 255;
|
|
29192
|
+
return bytes;
|
|
29193
|
+
}
|
|
29118
29194
|
//#endregion
|
|
29119
29195
|
//#region src/text/bidi.ts
|
|
29120
29196
|
/** UAX #9 §3.3.2: the maximum explicit embedding depth. */
|
|
@@ -29866,24 +29942,16 @@ function resolveImplicit(seq, types, levels) {
|
|
|
29866
29942
|
*/
|
|
29867
29943
|
function resetWhitespaceLevels(originalTypes, levels, baseLevel) {
|
|
29868
29944
|
const n = levels.length;
|
|
29869
|
-
|
|
29870
|
-
|
|
29945
|
+
const resettable = (t) => t === "WS" || t === "FSI" || t === "LRI" || t === "RLI" || t === "PDI" || isRemovedByX9(t);
|
|
29946
|
+
let runStart = 0;
|
|
29947
|
+
for (let i = 0; i < n; i++) {
|
|
29871
29948
|
const t = originalTypes[i];
|
|
29872
29949
|
if (t === "B" || t === "S") {
|
|
29873
|
-
levels[
|
|
29874
|
-
|
|
29875
|
-
|
|
29876
|
-
} else if (t === "WS" || t === "FSI" || t === "LRI" || t === "RLI" || t === "PDI" || isRemovedByX9(t)) {} else {
|
|
29877
|
-
if (resetFrom === n) {}
|
|
29878
|
-
resetFrom = i + 1 > resetFrom ? resetFrom : i + 1;
|
|
29879
|
-
resetFrom = i + 1;
|
|
29880
|
-
}
|
|
29881
|
-
}
|
|
29882
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
29883
|
-
const t = originalTypes[i];
|
|
29884
|
-
if (t === "WS" || t === "FSI" || t === "LRI" || t === "RLI" || t === "PDI" || isRemovedByX9(t)) levels[i] = baseLevel;
|
|
29885
|
-
else break;
|
|
29950
|
+
for (let j = runStart; j <= i; j++) levels[j] = baseLevel;
|
|
29951
|
+
runStart = i + 1;
|
|
29952
|
+
} else if (resettable(t)) {} else runStart = i + 1;
|
|
29886
29953
|
}
|
|
29954
|
+
for (let i = runStart; i < n; i++) levels[i] = baseLevel;
|
|
29887
29955
|
}
|
|
29888
29956
|
/** L2: reorder code-unit indices into visual order from the resolved levels. */
|
|
29889
29957
|
function reorderLevels(levels) {
|
|
@@ -31913,11 +31981,15 @@ function boxBlurD(stdDev) {
|
|
|
31913
31981
|
return Math.floor(stdDev * 3 * Math.sqrt(2 * Math.PI) / 4 + .5);
|
|
31914
31982
|
}
|
|
31915
31983
|
/**
|
|
31916
|
-
* One horizontal box blur of the given
|
|
31917
|
-
*
|
|
31918
|
-
*
|
|
31919
|
-
*
|
|
31920
|
-
*
|
|
31984
|
+
* One horizontal box blur of the given length, premultiplied float data, with
|
|
31985
|
+
* an asymmetric left/right radius to support the even-`d` rule. The window
|
|
31986
|
+
* covers offsets `[-leftRadius, +rightRadius]` inclusive.
|
|
31987
|
+
*
|
|
31988
|
+
* Samples that fall outside the filter region are treated as **transparent
|
|
31989
|
+
* black** `[0,0,0,0]` (SVG 1.1 §15.17 `edgeMode="none"`, the spec default).
|
|
31990
|
+
* In premultiplied space those samples contribute zero to every channel, so
|
|
31991
|
+
* the running sum simply skips them (the window length stays the full box
|
|
31992
|
+
* size, which is what fades edge pixels per spec).
|
|
31921
31993
|
*/
|
|
31922
31994
|
function boxBlurH(data, width, height, leftRadius, rightRadius) {
|
|
31923
31995
|
const out = new Float32Array(data.length);
|
|
@@ -31927,38 +31999,40 @@ function boxBlurH(data, width, height, leftRadius, rightRadius) {
|
|
|
31927
31999
|
for (let c = 0; c < 4; c++) {
|
|
31928
32000
|
let sum = 0;
|
|
31929
32001
|
for (let k = -leftRadius; k <= rightRadius; k++) {
|
|
31930
|
-
|
|
31931
|
-
sum += data[(row +
|
|
32002
|
+
if (k < 0 || k >= width) continue;
|
|
32003
|
+
sum += data[(row + k) * 4 + c];
|
|
31932
32004
|
}
|
|
31933
32005
|
for (let x = 0; x < width; x++) {
|
|
31934
32006
|
out[(row + x) * 4 + c] = sum / windowLen;
|
|
31935
32007
|
const dropX = x - leftRadius;
|
|
31936
32008
|
const addX = x + rightRadius + 1;
|
|
31937
|
-
|
|
31938
|
-
|
|
31939
|
-
sum += data[(row + ac) * 4 + c] - data[(row + dc) * 4 + c];
|
|
32009
|
+
if (addX >= 0 && addX < width) sum += data[(row + addX) * 4 + c];
|
|
32010
|
+
if (dropX >= 0 && dropX < width) sum -= data[(row + dropX) * 4 + c];
|
|
31940
32011
|
}
|
|
31941
32012
|
}
|
|
31942
32013
|
}
|
|
31943
32014
|
return out;
|
|
31944
32015
|
}
|
|
31945
|
-
/**
|
|
32016
|
+
/**
|
|
32017
|
+
* One vertical box blur — the transpose of {@link boxBlurH}. Out-of-bounds
|
|
32018
|
+
* samples are transparent black (SVG 1.1 §15.17 `edgeMode="none"`) and so
|
|
32019
|
+
* contribute zero to the running sum.
|
|
32020
|
+
*/
|
|
31946
32021
|
function boxBlurV(data, width, height, topRadius, bottomRadius) {
|
|
31947
32022
|
const out = new Float32Array(data.length);
|
|
31948
32023
|
const windowLen = topRadius + bottomRadius + 1;
|
|
31949
32024
|
for (let x = 0; x < width; x++) for (let c = 0; c < 4; c++) {
|
|
31950
32025
|
let sum = 0;
|
|
31951
32026
|
for (let k = -topRadius; k <= bottomRadius; k++) {
|
|
31952
|
-
|
|
31953
|
-
sum += data[(
|
|
32027
|
+
if (k < 0 || k >= height) continue;
|
|
32028
|
+
sum += data[(k * width + x) * 4 + c];
|
|
31954
32029
|
}
|
|
31955
32030
|
for (let y = 0; y < height; y++) {
|
|
31956
32031
|
out[(y * width + x) * 4 + c] = sum / windowLen;
|
|
31957
32032
|
const dropY = y - topRadius;
|
|
31958
32033
|
const addY = y + bottomRadius + 1;
|
|
31959
|
-
|
|
31960
|
-
|
|
31961
|
-
sum += data[(ac * width + x) * 4 + c] - data[(dc * width + x) * 4 + c];
|
|
32034
|
+
if (addY >= 0 && addY < height) sum += data[(addY * width + x) * 4 + c];
|
|
32035
|
+
if (dropY >= 0 && dropY < height) sum -= data[(dropY * width + x) * 4 + c];
|
|
31962
32036
|
}
|
|
31963
32037
|
}
|
|
31964
32038
|
return out;
|
|
@@ -33449,6 +33523,7 @@ function collectPages(children) {
|
|
|
33449
33523
|
*/
|
|
33450
33524
|
async function renderToPdf(root) {
|
|
33451
33525
|
let documentEl;
|
|
33526
|
+
const synthesized = [];
|
|
33452
33527
|
const stack = resolveNode(root);
|
|
33453
33528
|
while (stack.length > 0) {
|
|
33454
33529
|
const node = stack.shift();
|
|
@@ -33461,13 +33536,13 @@ async function renderToPdf(root) {
|
|
|
33461
33536
|
documentEl = node;
|
|
33462
33537
|
break;
|
|
33463
33538
|
}
|
|
33464
|
-
|
|
33465
|
-
type: "document",
|
|
33466
|
-
props: {},
|
|
33467
|
-
children: [node]
|
|
33468
|
-
};
|
|
33469
|
-
break;
|
|
33539
|
+
synthesized.push(node);
|
|
33470
33540
|
}
|
|
33541
|
+
if (documentEl === void 0 && synthesized.length > 0) documentEl = {
|
|
33542
|
+
type: "document",
|
|
33543
|
+
props: {},
|
|
33544
|
+
children: synthesized
|
|
33545
|
+
};
|
|
33471
33546
|
const doc = require_pdfDocument.createPdf();
|
|
33472
33547
|
const ctx = new RenderContext(doc);
|
|
33473
33548
|
await ctx.init();
|
|
@@ -37243,7 +37318,7 @@ function conformanceString(conformance) {
|
|
|
37243
37318
|
function convertPdfAConformanceXmp(xmp, toPart, toConformance) {
|
|
37244
37319
|
const partVal = partString(toPart);
|
|
37245
37320
|
let result = xmp;
|
|
37246
|
-
const partAttr = /pdfaid:part\s*=\s*"[^"]
|
|
37321
|
+
const partAttr = /pdfaid:part\s*=\s*(["'])[^"']*\1/;
|
|
37247
37322
|
const partElem = /<pdfaid:part>[^<]*<\/pdfaid:part>/;
|
|
37248
37323
|
if (partAttr.test(result)) result = result.replace(partAttr, `pdfaid:part="${partVal}"`);
|
|
37249
37324
|
else if (partElem.test(result)) result = result.replace(partElem, `<pdfaid:part>${partVal}</pdfaid:part>`);
|
|
@@ -37253,7 +37328,7 @@ function convertPdfAConformanceXmp(xmp, toPart, toConformance) {
|
|
|
37253
37328
|
}
|
|
37254
37329
|
if (toConformance !== void 0) {
|
|
37255
37330
|
const confVal = conformanceString(toConformance);
|
|
37256
|
-
const confAttr = /pdfaid:conformance\s*=\s*"[^"]
|
|
37331
|
+
const confAttr = /pdfaid:conformance\s*=\s*(["'])[^"']*\1/;
|
|
37257
37332
|
const confElem = /<pdfaid:conformance>[^<]*<\/pdfaid:conformance>/;
|
|
37258
37333
|
if (confAttr.test(result)) result = result.replace(confAttr, `pdfaid:conformance="${confVal}"`);
|
|
37259
37334
|
else if (confElem.test(result)) result = result.replace(confElem, `<pdfaid:conformance>${confVal}</pdfaid:conformance>`);
|
|
@@ -37291,7 +37366,7 @@ function injectIdentification(xmp, partVal, toConformance) {
|
|
|
37291
37366
|
function addConformanceBesidePart(xmp, confVal) {
|
|
37292
37367
|
const partElem = /(<pdfaid:part>[^<]*<\/pdfaid:part>)/;
|
|
37293
37368
|
if (partElem.test(xmp)) return xmp.replace(partElem, `$1<pdfaid:conformance>${confVal}</pdfaid:conformance>`);
|
|
37294
|
-
const partAttr = /(pdfaid:part\s*=\s*"[^"]
|
|
37369
|
+
const partAttr = /(pdfaid:part\s*=\s*(["'])[^"']*\2)/;
|
|
37295
37370
|
if (partAttr.test(xmp)) return xmp.replace(partAttr, `$1 pdfaid:conformance="${confVal}"`);
|
|
37296
37371
|
return xmp;
|
|
37297
37372
|
}
|
|
@@ -37544,10 +37619,28 @@ function isNonEmptyText(value) {
|
|
|
37544
37619
|
function amountsEqual(a, b) {
|
|
37545
37620
|
return Math.abs(a - b) <= MONETARY_TOLERANCE;
|
|
37546
37621
|
}
|
|
37547
|
-
/**
|
|
37622
|
+
/**
|
|
37623
|
+
* Round a monetary amount to two decimals using half-away-from-zero, the
|
|
37624
|
+
* commercial rounding convention EN 16931 applies to BT-* amounts (and the
|
|
37625
|
+
* convention the Factur-X generator emits). `Math.round` is half-up toward
|
|
37626
|
+
* +∞, which is wrong for negative amounts (e.g. a credit line), so the sign
|
|
37627
|
+
* is factored out explicitly.
|
|
37628
|
+
*/
|
|
37629
|
+
function roundToCents(value) {
|
|
37630
|
+
return Math.sign(value) * Math.round(Math.abs(value) * 100) / 100;
|
|
37631
|
+
}
|
|
37632
|
+
/**
|
|
37633
|
+
* Sum the line net amounts (Σ BT-131) of an invoice.
|
|
37634
|
+
*
|
|
37635
|
+
* Per EN 16931 each line net amount (BT-131) is rounded to two decimals
|
|
37636
|
+
* before the document-level sum (BT-106 / BT-109) is formed. Summing the raw
|
|
37637
|
+
* `quantity × unitPrice` products instead would diverge from the spec total
|
|
37638
|
+
* for fractional unit prices and could falsely flag (or falsely pass) a
|
|
37639
|
+
* borderline BR-CO-10 / BR-CO-13 comparison.
|
|
37640
|
+
*/
|
|
37548
37641
|
function sumLineNet(invoice) {
|
|
37549
37642
|
let total = 0;
|
|
37550
|
-
for (const line of invoice.lines) total += line.quantity * line.unitPrice;
|
|
37643
|
+
for (const line of invoice.lines) total += roundToCents(line.quantity * line.unitPrice);
|
|
37551
37644
|
return total;
|
|
37552
37645
|
}
|
|
37553
37646
|
/**
|
|
@@ -37825,15 +37918,15 @@ async function initWasm(options) {
|
|
|
37825
37918
|
if (wasmInitialized) return;
|
|
37826
37919
|
const inits = [];
|
|
37827
37920
|
if (options.deflate || options.deflateWasm) inits.push((async () => {
|
|
37828
|
-
const { initDeflateWasm } = await Promise.resolve().then(() => require("./pdfDocument-
|
|
37921
|
+
const { initDeflateWasm } = await Promise.resolve().then(() => require("./pdfDocument-CnVPQ_Cm.cjs")).then((n) => n.libdeflateWasm_exports);
|
|
37829
37922
|
await initDeflateWasm(options.deflateWasm);
|
|
37830
37923
|
})());
|
|
37831
37924
|
if (options.png || options.pngWasm) inits.push((async () => {
|
|
37832
|
-
const { initPngWasm } = await Promise.resolve().then(() => require("./pdfDocument-
|
|
37925
|
+
const { initPngWasm } = await Promise.resolve().then(() => require("./pdfDocument-CnVPQ_Cm.cjs")).then((n) => n.pngEmbed_exports);
|
|
37833
37926
|
await initPngWasm(options.pngWasm);
|
|
37834
37927
|
})());
|
|
37835
37928
|
if (options.fonts || options.fontWasm) inits.push((async () => {
|
|
37836
|
-
const { initSubsetWasm } = await Promise.resolve().then(() => require("./pdfDocument-
|
|
37929
|
+
const { initSubsetWasm } = await Promise.resolve().then(() => require("./pdfDocument-CnVPQ_Cm.cjs")).then((n) => n.fontSubset_exports);
|
|
37837
37930
|
await initSubsetWasm(options.fontWasm);
|
|
37838
37931
|
})());
|
|
37839
37932
|
if (options.jpeg || options.jpegWasm) inits.push((async () => {
|
|
@@ -40293,4 +40386,4 @@ Object.defineProperty(exports, "xyzToRgb", {
|
|
|
40293
40386
|
}
|
|
40294
40387
|
});
|
|
40295
40388
|
|
|
40296
|
-
//# sourceMappingURL=src-
|
|
40389
|
+
//# sourceMappingURL=src-DFojMRwY.cjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modern-pdf-lib",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.2",
|
|
4
4
|
"description": "A modern, WASM-accelerated PDF engine to create, parse, extract, fill, merge, and sign PDFs in every JavaScript runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -97,11 +97,11 @@
|
|
|
97
97
|
"fflate": "0.8.3"
|
|
98
98
|
},
|
|
99
99
|
"devDependencies": {
|
|
100
|
-
"@playwright/test": "1.62.0-alpha-2026-06-
|
|
100
|
+
"@playwright/test": "1.62.0-alpha-2026-06-27",
|
|
101
101
|
"@vitest/coverage-v8": "5.0.0-beta.5",
|
|
102
102
|
"esbuild": "0.28.1",
|
|
103
103
|
"fast-png": "8.0.0",
|
|
104
|
-
"miniflare": "4.
|
|
104
|
+
"miniflare": "4.20260625.0",
|
|
105
105
|
"oxlint": "^1.71.0",
|
|
106
106
|
"oxlint-tsgolint": "^0.23.0",
|
|
107
107
|
"pdf-lib": "^1.17.1",
|