@libpdf/core 0.0.1-beta.13 → 0.0.1-beta.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/index.d.mts +28 -6
- package/dist/index.mjs +100 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5895,6 +5895,16 @@ interface RemoveAnnotationsOptions {
|
|
|
5895
5895
|
interface FlattenAnnotationsOptions {
|
|
5896
5896
|
/** Annotation types to exclude from flattening */
|
|
5897
5897
|
exclude?: AnnotationSubtype[];
|
|
5898
|
+
/**
|
|
5899
|
+
* Remove Link annotations instead of keeping them.
|
|
5900
|
+
*
|
|
5901
|
+
* Link annotations contain URI or other actions that Adobe considers
|
|
5902
|
+
* "hidden behavior" which can cause signature validation warnings.
|
|
5903
|
+
* Enable this option when preparing documents for signing.
|
|
5904
|
+
*
|
|
5905
|
+
* @default false
|
|
5906
|
+
*/
|
|
5907
|
+
removeLinks?: boolean;
|
|
5898
5908
|
}
|
|
5899
5909
|
//#endregion
|
|
5900
5910
|
//#region src/attachments/types.d.ts
|
|
@@ -7684,6 +7694,24 @@ declare class PDF {
|
|
|
7684
7694
|
static merge(sources: Uint8Array[], options?: MergeOptions): Promise<PDF>;
|
|
7685
7695
|
/** PDF version string (e.g., "1.7", "2.0") */
|
|
7686
7696
|
get version(): string;
|
|
7697
|
+
/**
|
|
7698
|
+
* Upgrade the PDF version.
|
|
7699
|
+
*
|
|
7700
|
+
* Sets the /Version entry in the catalog dictionary. This is the standard
|
|
7701
|
+
* way to upgrade PDF version in incremental updates since the header
|
|
7702
|
+
* cannot be modified.
|
|
7703
|
+
*
|
|
7704
|
+
* The version will only be upgraded if the new version is higher than
|
|
7705
|
+
* the current version.
|
|
7706
|
+
*
|
|
7707
|
+
* @param version - Target version (e.g., "1.7", "2.0")
|
|
7708
|
+
*
|
|
7709
|
+
* @example
|
|
7710
|
+
* ```typescript
|
|
7711
|
+
* pdf.upgradeVersion("1.7");
|
|
7712
|
+
* ```
|
|
7713
|
+
*/
|
|
7714
|
+
upgradeVersion(version: string): void;
|
|
7687
7715
|
/** Whether the document is encrypted */
|
|
7688
7716
|
get isEncrypted(): boolean;
|
|
7689
7717
|
/** Whether authentication succeeded (for encrypted docs) */
|
|
@@ -8619,12 +8647,6 @@ declare class PDF {
|
|
|
8619
8647
|
* Used by signing to chain incremental updates.
|
|
8620
8648
|
*/
|
|
8621
8649
|
private saveInternal;
|
|
8622
|
-
/**
|
|
8623
|
-
* Ensure all reachable objects are loaded into the registry.
|
|
8624
|
-
*
|
|
8625
|
-
* Walks from the catalog to load all referenced objects.
|
|
8626
|
-
*/
|
|
8627
|
-
private ensureObjectsLoaded;
|
|
8628
8650
|
}
|
|
8629
8651
|
//#endregion
|
|
8630
8652
|
//#region src/signatures/signers/crypto-key.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { createCMSECDSASignature } from "pkijs";
|
|
|
9
9
|
import { base64 } from "@scure/base";
|
|
10
10
|
|
|
11
11
|
//#region package.json
|
|
12
|
-
var version = "0.0.1-beta.
|
|
12
|
+
var version = "0.0.1-beta.14";
|
|
13
13
|
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/objects/pdf-array.ts
|
|
@@ -26270,6 +26270,11 @@ var AnnotationFlattener = class {
|
|
|
26270
26270
|
if (isPopupAnnotation(annotDict)) continue;
|
|
26271
26271
|
const subtype = annotDict.getName("Subtype")?.value;
|
|
26272
26272
|
if (!subtype) continue;
|
|
26273
|
+
if (subtype === "Link") {
|
|
26274
|
+
if (options.removeLinks) {
|
|
26275
|
+
if (annotRef) refsToRemove.add(`${annotRef.objectNumber} ${annotRef.generation}`);
|
|
26276
|
+
}
|
|
26277
|
+
}
|
|
26273
26278
|
if (NON_FLATTENABLE_TYPES.includes(subtype)) continue;
|
|
26274
26279
|
if (options.exclude?.includes(subtype)) continue;
|
|
26275
26280
|
const annotation = createAnnotation(annotDict, annotRef, this.registry);
|
|
@@ -26295,7 +26300,8 @@ var AnnotationFlattener = class {
|
|
|
26295
26300
|
}
|
|
26296
26301
|
this.normalizeAppearanceStream(appearance);
|
|
26297
26302
|
const xObjectName = `FlatAnnot${xObjectIndex++}`;
|
|
26298
|
-
|
|
26303
|
+
let appearanceRef = this.registry.getRef(appearance);
|
|
26304
|
+
if (!appearanceRef) appearanceRef = this.registry.register(appearance);
|
|
26299
26305
|
xObjects.set(xObjectName, appearanceRef);
|
|
26300
26306
|
const rect = this.getAnnotationRect(annotDict);
|
|
26301
26307
|
const matrix = this.calculateTransformMatrix(rect, appearance);
|
|
@@ -26320,7 +26326,6 @@ var AnnotationFlattener = class {
|
|
|
26320
26326
|
* Generate appearance for annotation types we support.
|
|
26321
26327
|
*/
|
|
26322
26328
|
generateAppearance(annotation) {
|
|
26323
|
-
annotation.type;
|
|
26324
26329
|
const rect = annotation.rect;
|
|
26325
26330
|
if (annotation instanceof PDFHighlightAnnotation) {
|
|
26326
26331
|
const highlight = annotation;
|
|
@@ -26512,22 +26517,42 @@ var AnnotationFlattener = class {
|
|
|
26512
26517
|
}
|
|
26513
26518
|
/**
|
|
26514
26519
|
* Remove specific annotations from page.
|
|
26520
|
+
*
|
|
26521
|
+
* IMPORTANT: If Annots is an indirect reference, we modify the array in-place
|
|
26522
|
+
* to preserve the indirection. This is critical for signing: if we convert
|
|
26523
|
+
* an indirect Annots to a direct array, then later signing will convert it
|
|
26524
|
+
* back to indirect, modifying the page object and potentially breaking
|
|
26525
|
+
* signature validation.
|
|
26515
26526
|
*/
|
|
26516
26527
|
removeAnnotations(page, toRemove) {
|
|
26517
26528
|
if (toRemove.size === 0) return;
|
|
26518
|
-
|
|
26519
|
-
if (
|
|
26520
|
-
|
|
26521
|
-
|
|
26529
|
+
const annotsEntry = page.get("Annots");
|
|
26530
|
+
if (!annotsEntry) return;
|
|
26531
|
+
const wasIndirect = annotsEntry instanceof PdfRef;
|
|
26532
|
+
let annots;
|
|
26533
|
+
if (annotsEntry instanceof PdfRef) {
|
|
26534
|
+
const resolved = this.registry.resolve(annotsEntry);
|
|
26535
|
+
annots = resolved instanceof PdfArray ? resolved : void 0;
|
|
26536
|
+
} else if (annotsEntry instanceof PdfArray) annots = annotsEntry;
|
|
26537
|
+
if (!annots) return;
|
|
26538
|
+
const indicesToRemove = [];
|
|
26522
26539
|
for (let i = 0; i < annots.length; i++) {
|
|
26523
26540
|
const item = annots.at(i);
|
|
26524
26541
|
if (item instanceof PdfRef) {
|
|
26525
26542
|
const key$1 = `${item.objectNumber} ${item.generation}`;
|
|
26526
|
-
if (
|
|
26543
|
+
if (toRemove.has(key$1)) indicesToRemove.push(i);
|
|
26527
26544
|
}
|
|
26528
26545
|
}
|
|
26529
|
-
if (
|
|
26530
|
-
|
|
26546
|
+
if (indicesToRemove.length === 0) return;
|
|
26547
|
+
if (wasIndirect) for (let i = indicesToRemove.length - 1; i >= 0; i--) annots.remove(indicesToRemove[i]);
|
|
26548
|
+
else {
|
|
26549
|
+
const remaining = [];
|
|
26550
|
+
for (let i = 0; i < annots.length; i++) if (!indicesToRemove.includes(i)) {
|
|
26551
|
+
const item = annots.at(i);
|
|
26552
|
+
if (item instanceof PdfRef) remaining.push(item);
|
|
26553
|
+
}
|
|
26554
|
+
page.set("Annots", PdfArray.of(...remaining));
|
|
26555
|
+
}
|
|
26531
26556
|
}
|
|
26532
26557
|
};
|
|
26533
26558
|
|
|
@@ -30298,7 +30323,11 @@ var XRefParser = class {
|
|
|
30298
30323
|
const entries = /* @__PURE__ */ new Map();
|
|
30299
30324
|
this.expectKeyword("xref");
|
|
30300
30325
|
this.skipWhitespaceFromCurrent();
|
|
30301
|
-
while (
|
|
30326
|
+
while (true) {
|
|
30327
|
+
this.skipWhitespaceFromCurrent();
|
|
30328
|
+
if (this.peekKeyword("trailer")) break;
|
|
30329
|
+
this.parseSubsection(entries);
|
|
30330
|
+
}
|
|
30302
30331
|
this.expectKeyword("trailer");
|
|
30303
30332
|
this.skipWhitespaceFromCurrent();
|
|
30304
30333
|
const result = new ObjectParser(new TokenReader(this.scanner)).parseObject();
|
|
@@ -31352,6 +31381,30 @@ function encryptStreamDict(stream, ctx) {
|
|
|
31352
31381
|
return encrypted;
|
|
31353
31382
|
}
|
|
31354
31383
|
/**
|
|
31384
|
+
* Collect all refs reachable from the document root and trailer entries.
|
|
31385
|
+
*
|
|
31386
|
+
* Walks the object graph starting from Root, Info, and Encrypt (if present),
|
|
31387
|
+
* returning the set of all object keys (as "objNum gen" strings) that are reachable.
|
|
31388
|
+
* This is used for garbage collection during full saves.
|
|
31389
|
+
*/
|
|
31390
|
+
function collectReachableRefs(registry, root, info, encrypt) {
|
|
31391
|
+
const visited = /* @__PURE__ */ new Set();
|
|
31392
|
+
const walk = (obj) => {
|
|
31393
|
+
if (obj === null) return;
|
|
31394
|
+
if (obj instanceof PdfRef) {
|
|
31395
|
+
const key$1 = `${obj.objectNumber} ${obj.generation}`;
|
|
31396
|
+
if (visited.has(key$1)) return;
|
|
31397
|
+
visited.add(key$1);
|
|
31398
|
+
walk(registry.resolve(obj));
|
|
31399
|
+
} else if (obj instanceof PdfDict) for (const [, value] of obj) walk(value);
|
|
31400
|
+
else if (obj instanceof PdfArray) for (const item of obj) walk(item);
|
|
31401
|
+
};
|
|
31402
|
+
walk(root);
|
|
31403
|
+
if (info) walk(info);
|
|
31404
|
+
if (encrypt) walk(encrypt);
|
|
31405
|
+
return visited;
|
|
31406
|
+
}
|
|
31407
|
+
/**
|
|
31355
31408
|
* Write a complete PDF from scratch.
|
|
31356
31409
|
*
|
|
31357
31410
|
* Structure:
|
|
@@ -31386,9 +31439,10 @@ function writeComplete(registry, options) {
|
|
|
31386
31439
|
10
|
|
31387
31440
|
]));
|
|
31388
31441
|
const offsets = /* @__PURE__ */ new Map();
|
|
31389
|
-
const
|
|
31390
|
-
for (const [ref, obj] of registry.entries())
|
|
31391
|
-
|
|
31442
|
+
const reachableKeys = collectReachableRefs(registry, options.root, options.info, options.encrypt);
|
|
31443
|
+
for (const [ref, obj] of registry.entries()) {
|
|
31444
|
+
const key$1 = `${ref.objectNumber} ${ref.generation}`;
|
|
31445
|
+
if (!reachableKeys.has(key$1)) continue;
|
|
31392
31446
|
let prepared = prepareObjectForWrite(obj, compress);
|
|
31393
31447
|
if (options.securityHandler && options.encrypt && ref !== options.encrypt) prepared = encryptObject(prepared, {
|
|
31394
31448
|
handler: options.securityHandler,
|
|
@@ -37639,6 +37693,33 @@ var PDF = class PDF {
|
|
|
37639
37693
|
get version() {
|
|
37640
37694
|
return this.ctx.info.version;
|
|
37641
37695
|
}
|
|
37696
|
+
/**
|
|
37697
|
+
* Upgrade the PDF version.
|
|
37698
|
+
*
|
|
37699
|
+
* Sets the /Version entry in the catalog dictionary. This is the standard
|
|
37700
|
+
* way to upgrade PDF version in incremental updates since the header
|
|
37701
|
+
* cannot be modified.
|
|
37702
|
+
*
|
|
37703
|
+
* The version will only be upgraded if the new version is higher than
|
|
37704
|
+
* the current version.
|
|
37705
|
+
*
|
|
37706
|
+
* @param version - Target version (e.g., "1.7", "2.0")
|
|
37707
|
+
*
|
|
37708
|
+
* @example
|
|
37709
|
+
* ```typescript
|
|
37710
|
+
* pdf.upgradeVersion("1.7");
|
|
37711
|
+
* ```
|
|
37712
|
+
*/
|
|
37713
|
+
upgradeVersion(version$1) {
|
|
37714
|
+
const parseVersion$1 = (v) => {
|
|
37715
|
+
const [major, minor] = v.split(".").map(Number);
|
|
37716
|
+
return major * 10 + (minor || 0);
|
|
37717
|
+
};
|
|
37718
|
+
const currentVersion = parseVersion$1(this.ctx.info.version);
|
|
37719
|
+
if (parseVersion$1(version$1) <= currentVersion) return;
|
|
37720
|
+
this.ctx.catalog.getDict().set("Version", PdfName.of(version$1));
|
|
37721
|
+
this.ctx.info.version = version$1;
|
|
37722
|
+
}
|
|
37642
37723
|
/** Whether the document is encrypted */
|
|
37643
37724
|
get isEncrypted() {
|
|
37644
37725
|
return this.ctx.info.isEncrypted;
|
|
@@ -39019,7 +39100,11 @@ var PDF = class PDF {
|
|
|
39019
39100
|
formFields = form.getFields().length;
|
|
39020
39101
|
form.flatten(options?.form);
|
|
39021
39102
|
}
|
|
39022
|
-
const
|
|
39103
|
+
const annotationOptions = {
|
|
39104
|
+
removeLinks: true,
|
|
39105
|
+
...options?.annotations
|
|
39106
|
+
};
|
|
39107
|
+
const annotations = this.flattenAnnotations(annotationOptions);
|
|
39023
39108
|
return {
|
|
39024
39109
|
layers: layerResult.layerCount,
|
|
39025
39110
|
formFields,
|
|
@@ -39179,7 +39264,6 @@ var PDF = class PDF {
|
|
|
39179
39264
|
this._pendingSecurity = { action: "none" };
|
|
39180
39265
|
return result$1;
|
|
39181
39266
|
}
|
|
39182
|
-
this.ensureObjectsLoaded();
|
|
39183
39267
|
const result = writeComplete(this.ctx.registry, {
|
|
39184
39268
|
version: this.ctx.info.version,
|
|
39185
39269
|
root,
|
|
@@ -39192,28 +39276,6 @@ var PDF = class PDF {
|
|
|
39192
39276
|
this._pendingSecurity = { action: "none" };
|
|
39193
39277
|
return result;
|
|
39194
39278
|
}
|
|
39195
|
-
/**
|
|
39196
|
-
* Ensure all reachable objects are loaded into the registry.
|
|
39197
|
-
*
|
|
39198
|
-
* Walks from the catalog to load all referenced objects.
|
|
39199
|
-
*/
|
|
39200
|
-
ensureObjectsLoaded() {
|
|
39201
|
-
const visited = /* @__PURE__ */ new Set();
|
|
39202
|
-
const walk = (obj) => {
|
|
39203
|
-
if (obj === null) return;
|
|
39204
|
-
if (obj instanceof PdfRef) {
|
|
39205
|
-
const key$1 = `${obj.objectNumber} ${obj.generation}`;
|
|
39206
|
-
if (visited.has(key$1)) return;
|
|
39207
|
-
visited.add(key$1);
|
|
39208
|
-
walk(this.getObject(obj));
|
|
39209
|
-
} else if (obj instanceof PdfDict) for (const [, value] of obj) walk(value);
|
|
39210
|
-
else if (obj instanceof PdfArray) for (const item of obj) walk(item);
|
|
39211
|
-
};
|
|
39212
|
-
const root = this.ctx.info.trailer.getRef("Root");
|
|
39213
|
-
if (root) walk(root);
|
|
39214
|
-
const infoRef = this.ctx.info.trailer.getRef("Info");
|
|
39215
|
-
if (infoRef) walk(infoRef);
|
|
39216
|
-
}
|
|
39217
39279
|
};
|
|
39218
39280
|
|
|
39219
39281
|
//#endregion
|