pdf-lite 1.7.4-alpha.6 → 1.7.4-alpha.7

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.
@@ -8,6 +8,7 @@ import { IncrementalParser } from './parser/incremental-parser.js';
8
8
  export declare class PdfDecoder extends IncrementalParser<PdfToken, PdfObject> {
9
9
  private ignoreWhitespace;
10
10
  private maxBufferSizeBytes;
11
+ private _bufferByteSize;
11
12
  /**
12
13
  * Creates a new PDF decoder.
13
14
  *
@@ -19,6 +20,7 @@ export declare class PdfDecoder extends IncrementalParser<PdfToken, PdfObject> {
19
20
  ignoreWhitespace?: boolean;
20
21
  maxBufferSizeBytes?: number;
21
22
  });
23
+ feed(...input: (PdfToken | PdfToken[])[]): void;
22
24
  private nextName;
23
25
  private nextIndirectObject;
24
26
  private nextValue;
@@ -34,6 +36,7 @@ export declare class PdfDecoder extends IncrementalParser<PdfToken, PdfObject> {
34
36
  private nextObject;
35
37
  private static isPrimitive;
36
38
  protected bufferSize(): number;
39
+ protected compact(): void;
37
40
  protected canCompact(): boolean;
38
41
  protected parse(): PdfObject;
39
42
  }
@@ -46,6 +46,7 @@ const DEFAULT_MAX_BUFFER_SIZE_BYTES = 10 * 1024 * 1024; // 10 MB
46
46
  export class PdfDecoder extends IncrementalParser {
47
47
  ignoreWhitespace = false;
48
48
  maxBufferSizeBytes = DEFAULT_MAX_BUFFER_SIZE_BYTES;
49
+ _bufferByteSize = 0;
49
50
  /**
50
51
  * Creates a new PDF decoder.
51
52
  *
@@ -59,6 +60,20 @@ export class PdfDecoder extends IncrementalParser {
59
60
  this.maxBufferSizeBytes =
60
61
  options?.maxBufferSizeBytes ?? DEFAULT_MAX_BUFFER_SIZE_BYTES;
61
62
  }
63
+ feed(...input) {
64
+ for (const item of input) {
65
+ if (Array.isArray(item)) {
66
+ for (const subItem of item) {
67
+ this._bufferByteSize += subItem.byteLength;
68
+ this.buffer.push(subItem);
69
+ }
70
+ }
71
+ else {
72
+ this._bufferByteSize += item.byteLength;
73
+ this.buffer.push(item);
74
+ }
75
+ }
76
+ }
62
77
  nextName() {
63
78
  const preTokens = this.nextExtraTokens();
64
79
  const token = this.expect(PdfNameToken);
@@ -356,10 +371,20 @@ export class PdfDecoder extends IncrementalParser {
356
371
  token instanceof PdfStringToken);
357
372
  }
358
373
  bufferSize() {
359
- return this.buffer.reduce((acc, obj) => acc + obj.byteLength, 0);
374
+ return this._bufferByteSize;
375
+ }
376
+ compact() {
377
+ if (this.bufferIndex > 0) {
378
+ for (let i = 0; i < this.bufferIndex; i++) {
379
+ this._bufferByteSize -= this.buffer[i].byteLength;
380
+ }
381
+ this.buffer = this.buffer.slice(this.bufferIndex);
382
+ this.bufferIndex = 0;
383
+ }
360
384
  }
361
385
  canCompact() {
362
- return (this.bufferIndex > 50 && this.bufferSize() > this.maxBufferSizeBytes);
386
+ return (this.bufferIndex > 50 &&
387
+ this._bufferByteSize > this.maxBufferSizeBytes);
363
388
  }
364
389
  parse() {
365
390
  return this.nextObject(true);
@@ -61,7 +61,7 @@ export class PdfTokenSerializer extends Parser {
61
61
  if (token instanceof PdfByteOffsetToken) {
62
62
  token.update(currentOffset);
63
63
  }
64
- currentOffset += token.toBytes().length;
64
+ currentOffset += token.byteLength;
65
65
  }
66
66
  }
67
67
  /**
@@ -3,6 +3,7 @@ import { Ref } from '../ref.js';
3
3
  import { PdfToken } from './token.js';
4
4
  export class PdfNumberToken extends PdfToken {
5
5
  #value;
6
+ #cachedBytes;
6
7
  padTo;
7
8
  decimalPlaces;
8
9
  isByteToken = false;
@@ -27,19 +28,28 @@ export class PdfNumberToken extends PdfToken {
27
28
  this.isByteToken = options.isByteToken ?? false;
28
29
  }
29
30
  toBytes() {
30
- return PdfNumberToken.toBytes(this.#value, this.padTo, this.decimalPlaces);
31
+ if (this.#cachedBytes && !this.isByteToken) {
32
+ return this.#cachedBytes;
33
+ }
34
+ const bytes = PdfNumberToken.toBytes(this.#value, this.padTo, this.decimalPlaces);
35
+ if (!this.isByteToken) {
36
+ this.#cachedBytes = bytes;
37
+ }
38
+ return bytes;
31
39
  }
32
40
  get ref() {
33
41
  return this.#value;
34
42
  }
35
43
  set ref(newRef) {
36
44
  this.#value = newRef;
45
+ this.#cachedBytes = undefined;
37
46
  }
38
47
  get value() {
39
48
  return this.#value.resolve();
40
49
  }
41
50
  set value(newValue) {
42
51
  this.#value.update(newValue);
52
+ this.#cachedBytes = undefined;
43
53
  }
44
54
  static getValue(bytes) {
45
55
  if (bytes instanceof Ref) {
@@ -964,12 +964,17 @@ export class PdfDocument extends PdfObject {
964
964
  linkRevisions() {
965
965
  const xrefLookups = this.revisions.map((rev) => rev.xref);
966
966
  const indirectObjects = this.objects.filter((x) => x instanceof PdfIndirectObject);
967
+ // Build offset map once for O(1) lookups across all xrefs
968
+ const offsetMap = new Map();
969
+ for (const obj of indirectObjects) {
970
+ offsetMap.set(obj.offset.resolve(), obj);
971
+ }
967
972
  for (const revision of this.revisions) {
968
973
  revision.xref.linkPrev(xrefLookups);
969
974
  // Walk the entire prev chain to link all xref entries
970
975
  let xref = revision.xref;
971
976
  while (xref) {
972
- xref.linkIndirectObjects(indirectObjects);
977
+ xref.linkIndirectObjects(indirectObjects, offsetMap);
973
978
  xref = xref.prev;
974
979
  }
975
980
  }
@@ -1112,7 +1117,9 @@ export class PdfDocument extends PdfObject {
1112
1117
  * @returns A cloned PdfDocument instance
1113
1118
  */
1114
1119
  cloneImpl() {
1115
- this.update();
1120
+ if (this.isModified()) {
1121
+ this.update();
1122
+ }
1116
1123
  const clonedRevisions = this.revisions.map((rev) => rev.clone());
1117
1124
  const cloned = new PdfDocument({
1118
1125
  revisions: clonedRevisions,
@@ -96,7 +96,7 @@ export declare class PdfXrefLookup {
96
96
  *
97
97
  * @param objects - Array of indirect objects to link
98
98
  */
99
- linkIndirectObjects(objects: PdfIndirectObject[]): void;
99
+ linkIndirectObjects(objects: PdfIndirectObject[], offsetMap?: Map<number, PdfIndirectObject>): void;
100
100
  /**
101
101
  * Links this xref to a previous xref lookup based on the Prev trailer entry.
102
102
  *
@@ -240,7 +240,10 @@ export class PdfXrefLookup {
240
240
  *
241
241
  * @param objects - Array of indirect objects to link
242
242
  */
243
- linkIndirectObjects(objects) {
243
+ linkIndirectObjects(objects, offsetMap) {
244
+ // Use provided map or build one for O(1) lookup
245
+ const byOffset = offsetMap ??
246
+ new Map(objects.map((obj) => [obj.offset.resolve(), obj]));
244
247
  for (const entry of this.entriesValues) {
245
248
  if (entry instanceof PdfXRefStreamCompressedEntry) {
246
249
  continue;
@@ -248,7 +251,7 @@ export class PdfXrefLookup {
248
251
  if (!entry.inUse) {
249
252
  continue;
250
253
  }
251
- const [matchedObject] = objects.filter((obj) => obj.offset.equals(entry.byteOffset.value));
254
+ const matchedObject = byOffset.get(entry.byteOffset.value);
252
255
  if (!matchedObject ||
253
256
  matchedObject.objectNumber !== entry.objectNumber.value) {
254
257
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-lite",
3
- "version": "1.7.4-alpha.6",
3
+ "version": "1.7.4-alpha.7",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "exports": {