@libpdf/core 0.3.2 → 0.3.4
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 +33 -8
- package/dist/index.mjs +131 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -153,26 +153,37 @@ declare class PdfBool implements PdfPrimitive {
|
|
|
153
153
|
//#endregion
|
|
154
154
|
//#region src/objects/pdf-name.d.ts
|
|
155
155
|
/**
|
|
156
|
-
* PDF name object (interned).
|
|
156
|
+
* PDF name object (interned via WeakRef).
|
|
157
157
|
*
|
|
158
158
|
* In PDF: `/Type`, `/Page`, `/Length`
|
|
159
159
|
*
|
|
160
|
-
* Names are interned using
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* Names are interned using a WeakRef cache: as long as any live object
|
|
161
|
+
* (e.g. a PdfDict key) holds a strong reference to a PdfName, calling
|
|
162
|
+
* `PdfName.of()` with the same string returns the *same instance*.
|
|
163
|
+
* Once all strong references are dropped, the GC may collect the
|
|
164
|
+
* PdfName and a FinalizationRegistry cleans up the cache entry.
|
|
165
|
+
*
|
|
166
|
+
* This avoids the correctness bug of LRU-based caching, where eviction
|
|
167
|
+
* of a still-referenced name would break Map key identity in PdfDict.
|
|
163
168
|
*
|
|
164
|
-
* Common PDF names (Type, Page, etc.) are
|
|
169
|
+
* Common PDF names (Type, Page, etc.) are held as static fields and
|
|
170
|
+
* therefore never collected.
|
|
165
171
|
*/
|
|
166
172
|
declare class PdfName implements PdfPrimitive {
|
|
167
173
|
readonly value: string;
|
|
168
174
|
get type(): "name";
|
|
175
|
+
/** WeakRef cache for interning. Entries are cleaned up by the FinalizationRegistry. */
|
|
169
176
|
private static cache;
|
|
177
|
+
/** Cleans up dead WeakRef entries from the cache when a PdfName is GC'd. */
|
|
178
|
+
private static registry;
|
|
170
179
|
/**
|
|
171
|
-
* Pre-cached common names that
|
|
172
|
-
* These are stored
|
|
180
|
+
* Pre-cached common names that are always available.
|
|
181
|
+
* These are stored as static readonly fields, so they always have
|
|
182
|
+
* strong references and their WeakRefs never die.
|
|
173
183
|
*/
|
|
174
184
|
private static readonly permanentCache;
|
|
175
185
|
static readonly Type: PdfName;
|
|
186
|
+
static readonly Subtype: PdfName;
|
|
176
187
|
static readonly Page: PdfName;
|
|
177
188
|
static readonly Pages: PdfName;
|
|
178
189
|
static readonly Catalog: PdfName;
|
|
@@ -182,9 +193,21 @@ declare class PdfName implements PdfPrimitive {
|
|
|
182
193
|
static readonly MediaBox: PdfName;
|
|
183
194
|
static readonly Resources: PdfName;
|
|
184
195
|
static readonly Contents: PdfName;
|
|
196
|
+
static readonly Annots: PdfName;
|
|
197
|
+
static readonly Root: PdfName;
|
|
198
|
+
static readonly Size: PdfName;
|
|
199
|
+
static readonly Info: PdfName;
|
|
200
|
+
static readonly Prev: PdfName;
|
|
201
|
+
static readonly ID: PdfName;
|
|
202
|
+
static readonly Encrypt: PdfName;
|
|
185
203
|
static readonly Length: PdfName;
|
|
186
204
|
static readonly Filter: PdfName;
|
|
187
205
|
static readonly FlateDecode: PdfName;
|
|
206
|
+
static readonly Font: PdfName;
|
|
207
|
+
static readonly BaseFont: PdfName;
|
|
208
|
+
static readonly Encoding: PdfName;
|
|
209
|
+
static readonly XObject: PdfName;
|
|
210
|
+
static readonly Names: PdfName;
|
|
188
211
|
/** Cached serialized form (e.g. "/Type"). Computed lazily on first toBytes(). */
|
|
189
212
|
private cachedBytes;
|
|
190
213
|
private constructor();
|
|
@@ -203,7 +226,9 @@ declare class PdfName implements PdfPrimitive {
|
|
|
203
226
|
*/
|
|
204
227
|
static clearCache(): void;
|
|
205
228
|
/**
|
|
206
|
-
* Get the current
|
|
229
|
+
* Get the current number of entries in the WeakRef cache.
|
|
230
|
+
* This includes entries whose targets may have been GC'd but whose
|
|
231
|
+
* FinalizationRegistry callbacks haven't run yet.
|
|
207
232
|
*/
|
|
208
233
|
static get cacheSize(): number;
|
|
209
234
|
toBytes(writer: ByteWriter): void;
|
package/dist/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { createCMSECDSASignature } from "pkijs";
|
|
|
11
11
|
import { base64 } from "@scure/base";
|
|
12
12
|
|
|
13
13
|
//#region package.json
|
|
14
|
-
var version = "0.3.
|
|
14
|
+
var version = "0.3.4";
|
|
15
15
|
|
|
16
16
|
//#endregion
|
|
17
17
|
//#region src/objects/pdf-array.ts
|
|
@@ -334,32 +334,41 @@ function escapeName$1(name) {
|
|
|
334
334
|
return result;
|
|
335
335
|
}
|
|
336
336
|
/**
|
|
337
|
-
*
|
|
338
|
-
* Can be overridden via PdfName.setCacheSize().
|
|
339
|
-
*/
|
|
340
|
-
const DEFAULT_NAME_CACHE_SIZE = 1e4;
|
|
341
|
-
/**
|
|
342
|
-
* PDF name object (interned).
|
|
337
|
+
* PDF name object (interned via WeakRef).
|
|
343
338
|
*
|
|
344
339
|
* In PDF: `/Type`, `/Page`, `/Length`
|
|
345
340
|
*
|
|
346
|
-
* Names are interned using
|
|
347
|
-
*
|
|
348
|
-
*
|
|
341
|
+
* Names are interned using a WeakRef cache: as long as any live object
|
|
342
|
+
* (e.g. a PdfDict key) holds a strong reference to a PdfName, calling
|
|
343
|
+
* `PdfName.of()` with the same string returns the *same instance*.
|
|
344
|
+
* Once all strong references are dropped, the GC may collect the
|
|
345
|
+
* PdfName and a FinalizationRegistry cleans up the cache entry.
|
|
349
346
|
*
|
|
350
|
-
*
|
|
347
|
+
* This avoids the correctness bug of LRU-based caching, where eviction
|
|
348
|
+
* of a still-referenced name would break Map key identity in PdfDict.
|
|
349
|
+
*
|
|
350
|
+
* Common PDF names (Type, Page, etc.) are held as static fields and
|
|
351
|
+
* therefore never collected.
|
|
351
352
|
*/
|
|
352
353
|
var PdfName = class PdfName {
|
|
353
354
|
get type() {
|
|
354
355
|
return "name";
|
|
355
356
|
}
|
|
356
|
-
|
|
357
|
+
/** WeakRef cache for interning. Entries are cleaned up by the FinalizationRegistry. */
|
|
358
|
+
static cache = /* @__PURE__ */ new Map();
|
|
359
|
+
/** Cleans up dead WeakRef entries from the cache when a PdfName is GC'd. */
|
|
360
|
+
static registry = new FinalizationRegistry((name) => {
|
|
361
|
+
const ref = PdfName.cache.get(name);
|
|
362
|
+
if (ref && ref.deref() === void 0) PdfName.cache.delete(name);
|
|
363
|
+
});
|
|
357
364
|
/**
|
|
358
|
-
* Pre-cached common names that
|
|
359
|
-
* These are stored
|
|
365
|
+
* Pre-cached common names that are always available.
|
|
366
|
+
* These are stored as static readonly fields, so they always have
|
|
367
|
+
* strong references and their WeakRefs never die.
|
|
360
368
|
*/
|
|
361
369
|
static permanentCache = /* @__PURE__ */ new Map();
|
|
362
370
|
static Type = PdfName.createPermanent("Type");
|
|
371
|
+
static Subtype = PdfName.createPermanent("Subtype");
|
|
363
372
|
static Page = PdfName.createPermanent("Page");
|
|
364
373
|
static Pages = PdfName.createPermanent("Pages");
|
|
365
374
|
static Catalog = PdfName.createPermanent("Catalog");
|
|
@@ -369,9 +378,21 @@ var PdfName = class PdfName {
|
|
|
369
378
|
static MediaBox = PdfName.createPermanent("MediaBox");
|
|
370
379
|
static Resources = PdfName.createPermanent("Resources");
|
|
371
380
|
static Contents = PdfName.createPermanent("Contents");
|
|
381
|
+
static Annots = PdfName.createPermanent("Annots");
|
|
382
|
+
static Root = PdfName.createPermanent("Root");
|
|
383
|
+
static Size = PdfName.createPermanent("Size");
|
|
384
|
+
static Info = PdfName.createPermanent("Info");
|
|
385
|
+
static Prev = PdfName.createPermanent("Prev");
|
|
386
|
+
static ID = PdfName.createPermanent("ID");
|
|
387
|
+
static Encrypt = PdfName.createPermanent("Encrypt");
|
|
372
388
|
static Length = PdfName.createPermanent("Length");
|
|
373
389
|
static Filter = PdfName.createPermanent("Filter");
|
|
374
390
|
static FlateDecode = PdfName.createPermanent("FlateDecode");
|
|
391
|
+
static Font = PdfName.createPermanent("Font");
|
|
392
|
+
static BaseFont = PdfName.createPermanent("BaseFont");
|
|
393
|
+
static Encoding = PdfName.createPermanent("Encoding");
|
|
394
|
+
static XObject = PdfName.createPermanent("XObject");
|
|
395
|
+
static Names = PdfName.createPermanent("Names");
|
|
375
396
|
/** Cached serialized form (e.g. "/Type"). Computed lazily on first toBytes(). */
|
|
376
397
|
cachedBytes = null;
|
|
377
398
|
constructor(value) {
|
|
@@ -384,12 +405,15 @@ var PdfName = class PdfName {
|
|
|
384
405
|
static of(name) {
|
|
385
406
|
const permanent = PdfName.permanentCache.get(name);
|
|
386
407
|
if (permanent) return permanent;
|
|
387
|
-
|
|
388
|
-
if (
|
|
389
|
-
|
|
390
|
-
|
|
408
|
+
const ref = PdfName.cache.get(name);
|
|
409
|
+
if (ref) {
|
|
410
|
+
const existing = ref.deref();
|
|
411
|
+
if (existing) return existing;
|
|
391
412
|
}
|
|
392
|
-
|
|
413
|
+
const instance$1 = new PdfName(name);
|
|
414
|
+
PdfName.cache.set(name, new WeakRef(instance$1));
|
|
415
|
+
PdfName.registry.register(instance$1, name);
|
|
416
|
+
return instance$1;
|
|
393
417
|
}
|
|
394
418
|
/**
|
|
395
419
|
* Clear the name cache.
|
|
@@ -403,7 +427,9 @@ var PdfName = class PdfName {
|
|
|
403
427
|
PdfName.cache.clear();
|
|
404
428
|
}
|
|
405
429
|
/**
|
|
406
|
-
* Get the current
|
|
430
|
+
* Get the current number of entries in the WeakRef cache.
|
|
431
|
+
* This includes entries whose targets may have been GC'd but whose
|
|
432
|
+
* FinalizationRegistry callbacks haven't run yet.
|
|
407
433
|
*/
|
|
408
434
|
static get cacheSize() {
|
|
409
435
|
return PdfName.cache.size;
|
|
@@ -21240,13 +21266,14 @@ var WidgetAnnotation = class {
|
|
|
21240
21266
|
* @param state Optional state name for stateful widgets
|
|
21241
21267
|
*/
|
|
21242
21268
|
setNormalAppearance(stream, state) {
|
|
21243
|
-
|
|
21269
|
+
const resolve = this.registry.resolve.bind(this.registry);
|
|
21270
|
+
let ap = this.dict.getDict("AP", resolve);
|
|
21244
21271
|
if (!ap) {
|
|
21245
21272
|
ap = new PdfDict();
|
|
21246
21273
|
this.dict.set("AP", ap);
|
|
21247
21274
|
}
|
|
21248
21275
|
if (state) {
|
|
21249
|
-
const nEntry = ap.get("N");
|
|
21276
|
+
const nEntry = ap.get("N", resolve);
|
|
21250
21277
|
let nDict;
|
|
21251
21278
|
if (nEntry instanceof PdfDict && !(nEntry instanceof PdfStream)) nDict = nEntry;
|
|
21252
21279
|
else {
|
|
@@ -21283,7 +21310,7 @@ var WidgetAnnotation = class {
|
|
|
21283
21310
|
* For checkboxes/radios, this is the value when checked.
|
|
21284
21311
|
*/
|
|
21285
21312
|
getOnValue() {
|
|
21286
|
-
const ap = this.dict.getDict("AP");
|
|
21313
|
+
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
|
|
21287
21314
|
if (!ap) return null;
|
|
21288
21315
|
const resolve = this.registry.resolve.bind(this.registry);
|
|
21289
21316
|
const n = ap.get("N", resolve);
|
|
@@ -21300,7 +21327,7 @@ var WidgetAnnotation = class {
|
|
|
21300
21327
|
* @returns True if all states have appearance streams
|
|
21301
21328
|
*/
|
|
21302
21329
|
hasAppearancesForStates(states) {
|
|
21303
|
-
const ap = this.dict.getDict("AP");
|
|
21330
|
+
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
|
|
21304
21331
|
if (!ap) return false;
|
|
21305
21332
|
const resolve = this.registry.resolve.bind(this.registry);
|
|
21306
21333
|
const n = ap.get("N", resolve);
|
|
@@ -21315,9 +21342,10 @@ var WidgetAnnotation = class {
|
|
|
21315
21342
|
* Check if this widget has any normal appearance stream.
|
|
21316
21343
|
*/
|
|
21317
21344
|
hasNormalAppearance() {
|
|
21318
|
-
const
|
|
21345
|
+
const resolve = this.registry.resolve.bind(this.registry);
|
|
21346
|
+
const ap = this.dict.getDict("AP", resolve);
|
|
21319
21347
|
if (!ap) return false;
|
|
21320
|
-
const n = ap.get("N");
|
|
21348
|
+
const n = ap.get("N", resolve);
|
|
21321
21349
|
return n !== null && n !== void 0;
|
|
21322
21350
|
}
|
|
21323
21351
|
/**
|
|
@@ -21325,7 +21353,7 @@ var WidgetAnnotation = class {
|
|
|
21325
21353
|
* For stateful widgets (checkbox/radio), pass the state name.
|
|
21326
21354
|
*/
|
|
21327
21355
|
getNormalAppearance(state) {
|
|
21328
|
-
const ap = this.dict.getDict("AP");
|
|
21356
|
+
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
|
|
21329
21357
|
if (!ap) return null;
|
|
21330
21358
|
const resolve = this.registry.resolve.bind(this.registry);
|
|
21331
21359
|
const n = ap.get("N", resolve);
|
|
@@ -21343,7 +21371,7 @@ var WidgetAnnotation = class {
|
|
|
21343
21371
|
* Get rollover appearance stream (shown on mouse hover).
|
|
21344
21372
|
*/
|
|
21345
21373
|
getRolloverAppearance(state) {
|
|
21346
|
-
const ap = this.dict.getDict("AP");
|
|
21374
|
+
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
|
|
21347
21375
|
if (!ap) return null;
|
|
21348
21376
|
const resolve = this.registry.resolve.bind(this.registry);
|
|
21349
21377
|
const r = ap.get("R", resolve);
|
|
@@ -21361,7 +21389,7 @@ var WidgetAnnotation = class {
|
|
|
21361
21389
|
* Get down appearance stream (shown when clicked).
|
|
21362
21390
|
*/
|
|
21363
21391
|
getDownAppearance(state) {
|
|
21364
|
-
const ap = this.dict.getDict("AP");
|
|
21392
|
+
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
|
|
21365
21393
|
if (!ap) return null;
|
|
21366
21394
|
const resolve = this.registry.resolve.bind(this.registry);
|
|
21367
21395
|
const d = ap.get("D", resolve);
|
|
@@ -21379,7 +21407,7 @@ var WidgetAnnotation = class {
|
|
|
21379
21407
|
* Get border style.
|
|
21380
21408
|
*/
|
|
21381
21409
|
getBorderStyle() {
|
|
21382
|
-
const bs = this.dict.getDict("BS");
|
|
21410
|
+
const bs = this.dict.getDict("BS", this.registry.resolve.bind(this.registry));
|
|
21383
21411
|
if (!bs) return null;
|
|
21384
21412
|
const result = {
|
|
21385
21413
|
width: bs.getNumber("W")?.value ?? 1,
|
|
@@ -21728,7 +21756,7 @@ var TerminalField = class extends FormField {
|
|
|
21728
21756
|
this._widgets = [new WidgetAnnotation(this.dict, this.ref, this.registry)];
|
|
21729
21757
|
return this._widgets;
|
|
21730
21758
|
}
|
|
21731
|
-
const kids = this.dict.getArray("Kids");
|
|
21759
|
+
const kids = this.dict.getArray("Kids", this.registry.resolve.bind(this.registry));
|
|
21732
21760
|
if (!kids) {
|
|
21733
21761
|
this._widgets = [];
|
|
21734
21762
|
return this._widgets;
|
|
@@ -21757,7 +21785,7 @@ var TerminalField = class extends FormField {
|
|
|
21757
21785
|
this._widgets = [new WidgetAnnotation(this.dict, this.ref, this.registry)];
|
|
21758
21786
|
return;
|
|
21759
21787
|
}
|
|
21760
|
-
const kids = this.dict.getArray("Kids");
|
|
21788
|
+
const kids = this.dict.getArray("Kids", this.registry.resolve.bind(this.registry));
|
|
21761
21789
|
if (!kids) {
|
|
21762
21790
|
this._widgets = [];
|
|
21763
21791
|
return;
|
|
@@ -21794,7 +21822,7 @@ var TerminalField = class extends FormField {
|
|
|
21794
21822
|
*/
|
|
21795
21823
|
addWidget(widgetDict) {
|
|
21796
21824
|
const widgetRef = this.registry.register(widgetDict);
|
|
21797
|
-
let kids = this.dict.getArray("Kids");
|
|
21825
|
+
let kids = this.dict.getArray("Kids", this.registry.resolve.bind(this.registry));
|
|
21798
21826
|
if (!kids) {
|
|
21799
21827
|
kids = new PdfArray([]);
|
|
21800
21828
|
this.dict.set("Kids", kids);
|
|
@@ -21990,7 +22018,7 @@ var DropdownField = class extends TerminalField {
|
|
|
21990
22018
|
* Get available options.
|
|
21991
22019
|
*/
|
|
21992
22020
|
getOptions() {
|
|
21993
|
-
return parseChoiceOptions(this.dict.getArray("Opt"));
|
|
22021
|
+
return parseChoiceOptions(this.dict.getArray("Opt", this.registry.resolve.bind(this.registry)));
|
|
21994
22022
|
}
|
|
21995
22023
|
/**
|
|
21996
22024
|
* Get current value.
|
|
@@ -22066,14 +22094,14 @@ var ListBoxField = class extends TerminalField {
|
|
|
22066
22094
|
* Get available options.
|
|
22067
22095
|
*/
|
|
22068
22096
|
getOptions() {
|
|
22069
|
-
return parseChoiceOptions(this.dict.getArray("Opt"));
|
|
22097
|
+
return parseChoiceOptions(this.dict.getArray("Opt", this.registry.resolve.bind(this.registry)));
|
|
22070
22098
|
}
|
|
22071
22099
|
/**
|
|
22072
22100
|
* Get selected values.
|
|
22073
22101
|
* For multi-select, checks /I (indices) first, then /V.
|
|
22074
22102
|
*/
|
|
22075
22103
|
getValue() {
|
|
22076
|
-
const indices = this.dict.getArray("I");
|
|
22104
|
+
const indices = this.dict.getArray("I", this.registry.resolve.bind(this.registry));
|
|
22077
22105
|
if (indices && indices.length > 0) {
|
|
22078
22106
|
const options = this.getOptions();
|
|
22079
22107
|
const result = [];
|
|
@@ -22122,7 +22150,7 @@ var ListBoxField = class extends TerminalField {
|
|
|
22122
22150
|
const indices = values.map((v) => options.findIndex((o) => o.value === v)).filter((i) => i >= 0).sort((a, b) => a - b);
|
|
22123
22151
|
if (indices.length > 0) this.dict.set("I", PdfArray.of(...indices.map((i) => PdfNumber.of(i))));
|
|
22124
22152
|
else this.dict.delete("I");
|
|
22125
|
-
}
|
|
22153
|
+
} else this.dict.delete("I");
|
|
22126
22154
|
this.needsAppearanceUpdate = true;
|
|
22127
22155
|
this.applyChange();
|
|
22128
22156
|
}
|
|
@@ -22758,7 +22786,11 @@ var FormFlattener = class {
|
|
|
22758
22786
|
* This isolates the original page's graphics state from our additions.
|
|
22759
22787
|
*/
|
|
22760
22788
|
wrapAndAppendContent(page, newContent) {
|
|
22761
|
-
|
|
22789
|
+
let existing = page.get("Contents");
|
|
22790
|
+
if (existing instanceof PdfRef) {
|
|
22791
|
+
const resolved = this.registry.resolve(existing);
|
|
22792
|
+
if (resolved instanceof PdfArray) existing = resolved;
|
|
22793
|
+
}
|
|
22762
22794
|
const prefixBytes = new Uint8Array([113, 10]);
|
|
22763
22795
|
const prefixStream = new PdfStream(new PdfDict(), prefixBytes);
|
|
22764
22796
|
const prefixRef = this.registry.register(prefixStream);
|
|
@@ -22994,7 +23026,7 @@ var AcroForm = class AcroForm {
|
|
|
22994
23026
|
*/
|
|
22995
23027
|
getFields() {
|
|
22996
23028
|
if (this.fieldsCache) return this.fieldsCache;
|
|
22997
|
-
const fieldsArray = this.dict.getArray("Fields");
|
|
23029
|
+
const fieldsArray = this.dict.getArray("Fields", this.registry.resolve.bind(this.registry));
|
|
22998
23030
|
if (!fieldsArray) return [];
|
|
22999
23031
|
const visited = /* @__PURE__ */ new Set();
|
|
23000
23032
|
const fields = this.collectFields(fieldsArray, visited, "");
|
|
@@ -23253,7 +23285,7 @@ var AcroForm = class AcroForm {
|
|
|
23253
23285
|
field.resolveWidgets();
|
|
23254
23286
|
fields.push(field);
|
|
23255
23287
|
} else {
|
|
23256
|
-
const childKids = dict.getArray("Kids");
|
|
23288
|
+
const childKids = dict.getArray("Kids", this.registry.resolve.bind(this.registry));
|
|
23257
23289
|
if (childKids) fields.push(...this.collectFields(childKids, visited, fullName));
|
|
23258
23290
|
}
|
|
23259
23291
|
}
|
|
@@ -23267,7 +23299,7 @@ var AcroForm = class AcroForm {
|
|
|
23267
23299
|
* - Its /Kids contain widgets (no /T) rather than child fields (have /T)
|
|
23268
23300
|
*/
|
|
23269
23301
|
isTerminalField(dict) {
|
|
23270
|
-
const kids = dict.getArray("Kids");
|
|
23302
|
+
const kids = dict.getArray("Kids", this.registry.resolve.bind(this.registry));
|
|
23271
23303
|
if (!kids || kids.length === 0) return true;
|
|
23272
23304
|
let firstKid = kids.at(0);
|
|
23273
23305
|
if (!firstKid) return true;
|
|
@@ -23326,7 +23358,7 @@ var AcroForm = class AcroForm {
|
|
|
23326
23358
|
* @param fieldRef Reference to the field dictionary
|
|
23327
23359
|
*/
|
|
23328
23360
|
addField(fieldRef) {
|
|
23329
|
-
let fieldsArray = this.dict.getArray("Fields");
|
|
23361
|
+
let fieldsArray = this.dict.getArray("Fields", this.registry.resolve.bind(this.registry));
|
|
23330
23362
|
if (!fieldsArray) {
|
|
23331
23363
|
fieldsArray = new PdfArray([]);
|
|
23332
23364
|
this.dict.set("Fields", fieldsArray);
|
|
@@ -23345,7 +23377,7 @@ var AcroForm = class AcroForm {
|
|
|
23345
23377
|
* @returns true if the field was found and removed, false otherwise
|
|
23346
23378
|
*/
|
|
23347
23379
|
removeField(fieldRef) {
|
|
23348
|
-
const fieldsArray = this.dict.getArray("Fields");
|
|
23380
|
+
const fieldsArray = this.dict.getArray("Fields", this.registry.resolve.bind(this.registry));
|
|
23349
23381
|
if (!fieldsArray) return false;
|
|
23350
23382
|
for (let i = 0; i < fieldsArray.length; i++) {
|
|
23351
23383
|
const item = fieldsArray.at(i);
|
|
@@ -27267,7 +27299,7 @@ var PDFPage = class PDFPage {
|
|
|
27267
27299
|
const ops = [pushGraphicsState()];
|
|
27268
27300
|
if (gsName) ops.push(setGraphicsState(`/${gsName}`));
|
|
27269
27301
|
if (options.rotate) {
|
|
27270
|
-
const textWidth = options.maxWidth ??
|
|
27302
|
+
const textWidth = options.maxWidth ?? max(lines.map((l) => l.width));
|
|
27271
27303
|
let ascent;
|
|
27272
27304
|
let descent;
|
|
27273
27305
|
if (typeof font === "string") {
|
|
@@ -32553,8 +32585,14 @@ var IndirectObjectParser = class {
|
|
|
32553
32585
|
*/
|
|
32554
32586
|
readStream(dict) {
|
|
32555
32587
|
this.skipStreamEOL();
|
|
32556
|
-
const length = this.resolveLength(dict);
|
|
32557
32588
|
const startPos = this.scanner.position;
|
|
32589
|
+
let length;
|
|
32590
|
+
try {
|
|
32591
|
+
length = this.resolveLength(dict);
|
|
32592
|
+
} catch {
|
|
32593
|
+
length = this.findEndStream(startPos);
|
|
32594
|
+
if (length < 0) throw new ObjectParseError("Stream missing /Length and no endstream found");
|
|
32595
|
+
}
|
|
32558
32596
|
const data = this.scanner.bytes.subarray(startPos, startPos + length);
|
|
32559
32597
|
this.scanner.moveTo(startPos + length);
|
|
32560
32598
|
this.skipOptionalEOL();
|
|
@@ -32604,6 +32642,43 @@ var IndirectObjectParser = class {
|
|
|
32604
32642
|
} else if (byte === LF) this.scanner.advance();
|
|
32605
32643
|
}
|
|
32606
32644
|
/**
|
|
32645
|
+
* Scan forward from startPos looking for the "endstream" keyword.
|
|
32646
|
+
* Returns the stream data length (excluding any EOL before endstream),
|
|
32647
|
+
* or -1 if not found.
|
|
32648
|
+
*/
|
|
32649
|
+
findEndStream(startPos) {
|
|
32650
|
+
const bytes = this.scanner.bytes;
|
|
32651
|
+
const len = bytes.length;
|
|
32652
|
+
const sig = [
|
|
32653
|
+
101,
|
|
32654
|
+
110,
|
|
32655
|
+
100,
|
|
32656
|
+
115,
|
|
32657
|
+
116,
|
|
32658
|
+
114,
|
|
32659
|
+
101,
|
|
32660
|
+
97,
|
|
32661
|
+
109
|
|
32662
|
+
];
|
|
32663
|
+
const sigLen = sig.length;
|
|
32664
|
+
for (let i = startPos; i <= len - sigLen; i++) {
|
|
32665
|
+
let match = true;
|
|
32666
|
+
for (let j = 0; j < sigLen; j++) if (bytes[i + j] !== sig[j]) {
|
|
32667
|
+
match = false;
|
|
32668
|
+
break;
|
|
32669
|
+
}
|
|
32670
|
+
if (match) {
|
|
32671
|
+
let end = i;
|
|
32672
|
+
if (end > startPos && bytes[end - 1] === LF) {
|
|
32673
|
+
end--;
|
|
32674
|
+
if (end > startPos && bytes[end - 1] === CR) end--;
|
|
32675
|
+
} else if (end > startPos && bytes[end - 1] === CR) end--;
|
|
32676
|
+
return end - startPos;
|
|
32677
|
+
}
|
|
32678
|
+
}
|
|
32679
|
+
return -1;
|
|
32680
|
+
}
|
|
32681
|
+
/**
|
|
32607
32682
|
* Resolve the /Length value from the stream dict.
|
|
32608
32683
|
* Handles both direct values and indirect references.
|
|
32609
32684
|
*/
|
|
@@ -33048,10 +33123,12 @@ var XRefParser = class {
|
|
|
33048
33123
|
* Returns the byte offset where xref starts.
|
|
33049
33124
|
*/
|
|
33050
33125
|
findStartXRef() {
|
|
33051
|
-
const
|
|
33052
|
-
|
|
33126
|
+
const bytes = this.scanner.bytes;
|
|
33127
|
+
let effectiveEnd = bytes.length;
|
|
33128
|
+
while (effectiveEnd > 0 && isWhitespace$1(bytes[effectiveEnd - 1])) effectiveEnd--;
|
|
33129
|
+
const searchStart = Math.max(0, effectiveEnd - 1024);
|
|
33053
33130
|
let startxrefPos = -1;
|
|
33054
|
-
for (let i =
|
|
33131
|
+
for (let i = effectiveEnd - 9; i >= searchStart; i--) if (this.matchesAt(i, "startxref")) {
|
|
33055
33132
|
startxrefPos = i;
|
|
33056
33133
|
break;
|
|
33057
33134
|
}
|
|
@@ -34278,7 +34355,7 @@ function writeComplete(registry, options) {
|
|
|
34278
34355
|
});
|
|
34279
34356
|
writeXRefStream(writer, {
|
|
34280
34357
|
entries,
|
|
34281
|
-
size:
|
|
34358
|
+
size: max(entries.map((e) => e.objectNumber), 0) + 1,
|
|
34282
34359
|
xrefOffset,
|
|
34283
34360
|
root: options.root,
|
|
34284
34361
|
info: options.info,
|
|
@@ -34288,7 +34365,7 @@ function writeComplete(registry, options) {
|
|
|
34288
34365
|
});
|
|
34289
34366
|
} else writeXRefTable(writer, {
|
|
34290
34367
|
entries,
|
|
34291
|
-
size:
|
|
34368
|
+
size: max(entries.map((e) => e.objectNumber), 0) + 1,
|
|
34292
34369
|
xrefOffset,
|
|
34293
34370
|
root: options.root,
|
|
34294
34371
|
info: options.info,
|
|
@@ -34631,7 +34708,7 @@ var NameTree = class {
|
|
|
34631
34708
|
console.warn(`NameTree: max depth (${MAX_DEPTH}) exceeded during lookup`);
|
|
34632
34709
|
return null;
|
|
34633
34710
|
}
|
|
34634
|
-
const kids = node.getArray("Kids");
|
|
34711
|
+
const kids = node.getArray("Kids", this.resolver);
|
|
34635
34712
|
if (!kids || kids.length === 0) return null;
|
|
34636
34713
|
let lo$1 = 0;
|
|
34637
34714
|
let hi$1 = kids.length - 1;
|
|
@@ -34666,7 +34743,7 @@ var NameTree = class {
|
|
|
34666
34743
|
}
|
|
34667
34744
|
if (!found) return null;
|
|
34668
34745
|
}
|
|
34669
|
-
const names = node.getArray("Names");
|
|
34746
|
+
const names = node.getArray("Names", this.resolver);
|
|
34670
34747
|
if (!names) return null;
|
|
34671
34748
|
const numPairs = Math.floor(names.length / 2);
|
|
34672
34749
|
let lo = 0;
|
|
@@ -34710,7 +34787,7 @@ var NameTree = class {
|
|
|
34710
34787
|
continue;
|
|
34711
34788
|
}
|
|
34712
34789
|
if (node.has("Kids")) {
|
|
34713
|
-
const kids = node.getArray("Kids");
|
|
34790
|
+
const kids = node.getArray("Kids", this.resolver);
|
|
34714
34791
|
if (kids) for (let i = 0; i < kids.length; i++) {
|
|
34715
34792
|
const kidRef = kids.at(i);
|
|
34716
34793
|
if (kidRef instanceof PdfRef) {
|
|
@@ -34728,7 +34805,7 @@ var NameTree = class {
|
|
|
34728
34805
|
});
|
|
34729
34806
|
}
|
|
34730
34807
|
} else if (node.has("Names")) {
|
|
34731
|
-
const names = node.getArray("Names");
|
|
34808
|
+
const names = node.getArray("Names", this.resolver);
|
|
34732
34809
|
if (names) for (let i = 0; i < names.length; i += 2) {
|
|
34733
34810
|
const key$1 = extractKey(names.at(i));
|
|
34734
34811
|
if (key$1 === null) continue;
|