@adnsistemas/pdf-lib 2.4.5 → 2.6.0

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.
Files changed (104) hide show
  1. package/README.md +43 -0
  2. package/cjs/api/PDFDocument.d.ts +14 -0
  3. package/cjs/api/PDFDocument.d.ts.map +1 -1
  4. package/cjs/api/PDFDocument.js +51 -3
  5. package/cjs/api/PDFDocument.js.map +1 -1
  6. package/cjs/api/PDFDocumentOptions.d.ts +1 -0
  7. package/cjs/api/PDFDocumentOptions.d.ts.map +1 -1
  8. package/cjs/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
  9. package/cjs/api/snapshot/DefaultDocumentSnapshot.d.ts.map +1 -1
  10. package/cjs/api/snapshot/DefaultDocumentSnapshot.js +10 -0
  11. package/cjs/api/snapshot/DefaultDocumentSnapshot.js.map +1 -1
  12. package/cjs/api/snapshot/DocumentSnapshot.d.ts +4 -0
  13. package/cjs/api/snapshot/DocumentSnapshot.d.ts.map +1 -1
  14. package/cjs/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
  15. package/cjs/api/snapshot/IncrementalDocumentSnapshot.d.ts.map +1 -1
  16. package/cjs/api/snapshot/IncrementalDocumentSnapshot.js +17 -0
  17. package/cjs/api/snapshot/IncrementalDocumentSnapshot.js.map +1 -1
  18. package/cjs/core/PDFContext.d.ts +10 -1
  19. package/cjs/core/PDFContext.d.ts.map +1 -1
  20. package/cjs/core/PDFContext.js +52 -2
  21. package/cjs/core/PDFContext.js.map +1 -1
  22. package/cjs/core/document/PDFCrossRefSection.d.ts +6 -1
  23. package/cjs/core/document/PDFCrossRefSection.d.ts.map +1 -1
  24. package/cjs/core/document/PDFCrossRefSection.js +65 -2
  25. package/cjs/core/document/PDFCrossRefSection.js.map +1 -1
  26. package/cjs/core/parser/PDFParser.d.ts +2 -2
  27. package/cjs/core/parser/PDFParser.d.ts.map +1 -1
  28. package/cjs/core/parser/PDFParser.js +23 -5
  29. package/cjs/core/parser/PDFParser.js.map +1 -1
  30. package/cjs/core/parser/PDFXRefStreamParser.d.ts.map +1 -1
  31. package/cjs/core/parser/PDFXRefStreamParser.js +6 -0
  32. package/cjs/core/parser/PDFXRefStreamParser.js.map +1 -1
  33. package/cjs/core/writers/PDFWriter.d.ts.map +1 -1
  34. package/cjs/core/writers/PDFWriter.js +10 -0
  35. package/cjs/core/writers/PDFWriter.js.map +1 -1
  36. package/dist/pdf-lib.esm.js +232 -12
  37. package/dist/pdf-lib.esm.js.map +1 -1
  38. package/dist/pdf-lib.esm.min.js +3 -3
  39. package/dist/pdf-lib.esm.min.js.map +1 -1
  40. package/dist/pdf-lib.js +232 -12
  41. package/dist/pdf-lib.js.map +1 -1
  42. package/dist/pdf-lib.min.js +3 -3
  43. package/dist/pdf-lib.min.js.map +1 -1
  44. package/es/api/PDFDocument.d.ts +14 -0
  45. package/es/api/PDFDocument.d.ts.map +1 -1
  46. package/es/api/PDFDocument.js +51 -3
  47. package/es/api/PDFDocument.js.map +1 -1
  48. package/es/api/PDFDocumentOptions.d.ts +1 -0
  49. package/es/api/PDFDocumentOptions.d.ts.map +1 -1
  50. package/es/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
  51. package/es/api/snapshot/DefaultDocumentSnapshot.d.ts.map +1 -1
  52. package/es/api/snapshot/DefaultDocumentSnapshot.js +10 -0
  53. package/es/api/snapshot/DefaultDocumentSnapshot.js.map +1 -1
  54. package/es/api/snapshot/DocumentSnapshot.d.ts +4 -0
  55. package/es/api/snapshot/DocumentSnapshot.d.ts.map +1 -1
  56. package/es/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
  57. package/es/api/snapshot/IncrementalDocumentSnapshot.d.ts.map +1 -1
  58. package/es/api/snapshot/IncrementalDocumentSnapshot.js +17 -0
  59. package/es/api/snapshot/IncrementalDocumentSnapshot.js.map +1 -1
  60. package/es/core/PDFContext.d.ts +10 -1
  61. package/es/core/PDFContext.d.ts.map +1 -1
  62. package/es/core/PDFContext.js +52 -2
  63. package/es/core/PDFContext.js.map +1 -1
  64. package/es/core/document/PDFCrossRefSection.d.ts +6 -1
  65. package/es/core/document/PDFCrossRefSection.d.ts.map +1 -1
  66. package/es/core/document/PDFCrossRefSection.js +65 -2
  67. package/es/core/document/PDFCrossRefSection.js.map +1 -1
  68. package/es/core/parser/PDFParser.d.ts +2 -2
  69. package/es/core/parser/PDFParser.d.ts.map +1 -1
  70. package/es/core/parser/PDFParser.js +23 -5
  71. package/es/core/parser/PDFParser.js.map +1 -1
  72. package/es/core/parser/PDFXRefStreamParser.d.ts.map +1 -1
  73. package/es/core/parser/PDFXRefStreamParser.js +6 -0
  74. package/es/core/parser/PDFXRefStreamParser.js.map +1 -1
  75. package/es/core/writers/PDFWriter.d.ts.map +1 -1
  76. package/es/core/writers/PDFWriter.js +10 -0
  77. package/es/core/writers/PDFWriter.js.map +1 -1
  78. package/package.json +4 -4
  79. package/src/api/PDFDocument.ts +55 -0
  80. package/src/api/PDFDocumentOptions.ts +1 -0
  81. package/src/api/snapshot/DefaultDocumentSnapshot.ts +13 -0
  82. package/src/api/snapshot/DocumentSnapshot.ts +6 -0
  83. package/src/api/snapshot/IncrementalDocumentSnapshot.ts +20 -0
  84. package/src/core/PDFContext.ts +53 -2
  85. package/src/core/document/PDFCrossRefSection.ts +70 -2
  86. package/src/core/parser/PDFParser.ts +22 -3
  87. package/src/core/parser/PDFXRefStreamParser.ts +8 -0
  88. package/src/core/writers/PDFWriter.ts +11 -0
  89. package/ts3.4/cjs/api/PDFDocument.d.ts +14 -0
  90. package/ts3.4/cjs/api/PDFDocumentOptions.d.ts +1 -0
  91. package/ts3.4/cjs/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
  92. package/ts3.4/cjs/api/snapshot/DocumentSnapshot.d.ts +4 -0
  93. package/ts3.4/cjs/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
  94. package/ts3.4/cjs/core/PDFContext.d.ts +10 -1
  95. package/ts3.4/cjs/core/document/PDFCrossRefSection.d.ts +6 -1
  96. package/ts3.4/cjs/core/parser/PDFParser.d.ts +2 -2
  97. package/ts3.4/es/api/PDFDocument.d.ts +14 -0
  98. package/ts3.4/es/api/PDFDocumentOptions.d.ts +1 -0
  99. package/ts3.4/es/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
  100. package/ts3.4/es/api/snapshot/DocumentSnapshot.d.ts +4 -0
  101. package/ts3.4/es/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
  102. package/ts3.4/es/core/PDFContext.d.ts +10 -1
  103. package/ts3.4/es/core/document/PDFCrossRefSection.d.ts +6 -1
  104. package/ts3.4/es/core/parser/PDFParser.d.ts +2 -2
@@ -9278,12 +9278,20 @@ SimpleRNG.withSeed = (seed) => new SimpleRNG(seed);
9278
9278
 
9279
9279
  const byAscendingObjectNumber = ([a], [b]) => a.objectNumber - b.objectNumber;
9280
9280
  class PDFContext {
9281
- constructor() {
9281
+ get preserveObjectsVersions() {
9282
+ return this._preserveObjectsVersions;
9283
+ }
9284
+ constructor(preserveObjectsVersions) {
9282
9285
  this.isDecrypted = true;
9286
+ this.xrefs = [];
9287
+ this._preserveObjectsVersions = preserveObjectsVersions
9288
+ ? preserveObjectsVersions
9289
+ : false;
9283
9290
  this.largestObjectNumber = 0;
9284
9291
  this.header = PDFHeader.forVersion(1, 7);
9285
9292
  this.trailerInfo = {};
9286
9293
  this.indirectObjects = new Map();
9294
+ this.objectsPreviousVersions = new Map();
9287
9295
  this.rng = SimpleRNG.withSeed(1);
9288
9296
  this.pdfFileDetails = {
9289
9297
  pdfSize: 0,
@@ -9292,6 +9300,18 @@ class PDFContext {
9292
9300
  };
9293
9301
  }
9294
9302
  assign(ref, object) {
9303
+ if (this.preserveObjectsVersions) {
9304
+ const prevOV = this.indirectObjects.get(ref);
9305
+ if (prevOV) {
9306
+ const prevList = this.objectsPreviousVersions.get(ref);
9307
+ if (!prevList) {
9308
+ this.objectsPreviousVersions.set(ref, [prevOV]);
9309
+ }
9310
+ else {
9311
+ prevList.unshift(prevOV);
9312
+ }
9313
+ }
9314
+ }
9295
9315
  this.indirectObjects.set(ref, object);
9296
9316
  if (ref.objectNumber > this.largestObjectNumber) {
9297
9317
  this.largestObjectNumber = ref.objectNumber;
@@ -9307,6 +9327,21 @@ class PDFContext {
9307
9327
  return ref;
9308
9328
  }
9309
9329
  delete(ref) {
9330
+ if (this.snapshot)
9331
+ this.snapshot.markDeletedRef(ref);
9332
+ if (this.preserveObjectsVersions) {
9333
+ const object = this.indirectObjects.get(ref);
9334
+ if (object) {
9335
+ // check is not already deleted
9336
+ const verlist = this.objectsPreviousVersions.get(ref);
9337
+ if (verlist) {
9338
+ verlist.unshift(object);
9339
+ }
9340
+ else {
9341
+ this.objectsPreviousVersions.set(ref, [object]);
9342
+ }
9343
+ }
9344
+ }
9310
9345
  return this.indirectObjects.delete(ref);
9311
9346
  }
9312
9347
  lookupMaybe(ref, ...types) {
@@ -9492,8 +9527,23 @@ class PDFContext {
9492
9527
  if (this.snapshot)
9493
9528
  this.snapshot.markObjForSave(obj);
9494
9529
  }
9530
+ getObjectVersions(ref) {
9531
+ if (!this.preserveObjectsVersions)
9532
+ return [];
9533
+ const list = this.objectsPreviousVersions.get(ref);
9534
+ if (list)
9535
+ return list;
9536
+ return [];
9537
+ }
9538
+ listXrefEntries(xrefIndex = -1) {
9539
+ if (xrefIndex < 0)
9540
+ xrefIndex = this.xrefs.length - 1;
9541
+ if (xrefIndex < 0 || xrefIndex >= this.xrefs.length)
9542
+ return [];
9543
+ return this.xrefs[xrefIndex].listRefs();
9544
+ }
9495
9545
  }
9496
- PDFContext.create = () => new PDFContext();
9546
+ PDFContext.create = (withObjectVersions = false) => new PDFContext(withObjectVersions);
9497
9547
 
9498
9548
  class PDFPageLeaf extends PDFDict {
9499
9549
  constructor(map, context, autoNormalizeCTM = true) {
@@ -9840,6 +9890,7 @@ class DefaultDocumentSnapshot {
9840
9890
  constructor() {
9841
9891
  this.pdfSize = 0;
9842
9892
  this.prevStartXRef = 0;
9893
+ this.deletedCount = 0;
9843
9894
  }
9844
9895
  shouldSave(_objectNumber) {
9845
9896
  return true;
@@ -9856,11 +9907,22 @@ class DefaultDocumentSnapshot {
9856
9907
  markObjsForSave(_objs) {
9857
9908
  throw new Error('This method should not be called.');
9858
9909
  }
9910
+ markDeletedObj(_obj) {
9911
+ throw new Error('This method should not be called.');
9912
+ }
9913
+ markDeletedRef(_ref) {
9914
+ throw new Error('This method should not be called.');
9915
+ }
9916
+ deletedRef(_index) {
9917
+ throw new Error('This method should not be called.');
9918
+ }
9859
9919
  }
9860
9920
  const defaultDocumentSnapshot = new DefaultDocumentSnapshot();
9861
9921
 
9862
9922
  class IncrementalDocumentSnapshot {
9863
9923
  constructor(lastObjectNumber, indirectObjects, pdfSize, prevStartXRef, context) {
9924
+ this.deletedCount = 0;
9925
+ this.deleted = [];
9864
9926
  this.lastObjectNumber = lastObjectNumber;
9865
9927
  this.changedObjects = indirectObjects;
9866
9928
  this.pdfSize = pdfSize;
@@ -9893,11 +9955,26 @@ class IncrementalDocumentSnapshot {
9893
9955
  .map((obj) => this.context.getRef(obj))
9894
9956
  .filter((ref) => ref !== undefined));
9895
9957
  }
9958
+ markDeletedRef(ref) {
9959
+ if (this.deleted.findIndex((dref) => dref.objectNumber === ref.objectNumber) <
9960
+ 0)
9961
+ this.deletedCount = this.deleted.push(ref);
9962
+ }
9963
+ markDeletedObj(obj) {
9964
+ const oref = this.context.getRef(obj);
9965
+ if (oref)
9966
+ this.markDeletedRef(oref);
9967
+ }
9968
+ deletedRef(index) {
9969
+ if (index < 0 || index >= this.deleted.length)
9970
+ return null;
9971
+ return this.deleted[index];
9972
+ }
9896
9973
  }
9897
9974
 
9898
9975
  /**
9899
9976
  * Entries should be added using the [[addEntry]] and [[addDeletedEntry]]
9900
- * methods **in order of ascending object number**.
9977
+ * methods.
9901
9978
  */
9902
9979
  class PDFCrossRefSection {
9903
9980
  constructor(firstEntry) {
@@ -9909,6 +9986,23 @@ class PDFCrossRefSection {
9909
9986
  this.append({ ref, offset, deleted: false });
9910
9987
  }
9911
9988
  addDeletedEntry(ref, nextFreeObjectNumber) {
9989
+ // fix the first entry if required
9990
+ if (!this.subsections.length) {
9991
+ this.subsections = [
9992
+ [
9993
+ {
9994
+ ref: PDFRef.of(0, 65535),
9995
+ offset: ref.objectNumber,
9996
+ deleted: true,
9997
+ },
9998
+ ],
9999
+ ];
10000
+ this.chunkIdx = 0;
10001
+ this.chunkLength = 1;
10002
+ }
10003
+ else if (!this.subsections[0][0].offset) {
10004
+ this.subsections[0][0].offset = ref.objectNumber;
10005
+ }
9912
10006
  this.append({ ref, offset: nextFreeObjectNumber, deleted: true });
9913
10007
  }
9914
10008
  toString() {
@@ -9991,7 +10085,37 @@ class PDFCrossRefSection {
9991
10085
  }
9992
10086
  const chunk = this.subsections[this.chunkIdx];
9993
10087
  const prevEntry = chunk[this.chunkLength - 1];
9994
- if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber > 1) {
10088
+ if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber !== 1) {
10089
+ // the current chunk is not the right chunk, find the right one, or create a new one
10090
+ for (let c = 0; c < this.subsections.length; c++) {
10091
+ const first = this.subsections[c][0];
10092
+ const last = this.subsections[c][this.subsections[c].length - 1];
10093
+ if (first.ref.objectNumber > currEntry.ref.objectNumber) {
10094
+ // goes before this subsection, or at the start of it
10095
+ if (first.ref.objectNumber - currEntry.ref.objectNumber === 1) {
10096
+ // first element of subsection
10097
+ this.subsections[c].unshift(currEntry);
10098
+ if (c === this.chunkIdx)
10099
+ this.chunkLength += 1;
10100
+ return;
10101
+ }
10102
+ else {
10103
+ // create subsection
10104
+ this.subsections.splice(c, 0, [currEntry]);
10105
+ this.chunkIdx++;
10106
+ return;
10107
+ }
10108
+ }
10109
+ else if (last.ref.objectNumber > currEntry.ref.objectNumber) {
10110
+ // goes in this subsection, find its place..
10111
+ const cep = this.subsections[c].findIndex((ee) => ee.ref.objectNumber > currEntry.ref.objectNumber);
10112
+ this.subsections[c].splice(cep, 0, currEntry);
10113
+ if (c === this.chunkIdx)
10114
+ this.chunkLength += 1;
10115
+ }
10116
+ // bigger, keep looking
10117
+ }
10118
+ // if got to here, then a new subsection is required
9995
10119
  this.subsections.push([currEntry]);
9996
10120
  this.chunkIdx += 1;
9997
10121
  this.chunkLength = 1;
@@ -10001,6 +10125,22 @@ class PDFCrossRefSection {
10001
10125
  this.chunkLength += 1;
10002
10126
  }
10003
10127
  }
10128
+ /**
10129
+ * Returns all the entries in the XREF section, except the first one (object == 0)
10130
+ * @returns {Entry[]} All the entries in the XREF section
10131
+ */
10132
+ listRefs() {
10133
+ const refList = [];
10134
+ for (let rangeIdx = 0, rangeLen = this.subsections.length; rangeIdx < rangeLen; rangeIdx++) {
10135
+ const range = this.subsections[rangeIdx];
10136
+ for (let entryIdx = 0, entryLen = range.length; entryIdx < entryLen; entryIdx++) {
10137
+ const entry = range[entryIdx];
10138
+ if (entry.ref.objectNumber)
10139
+ refList.push(entry);
10140
+ }
10141
+ }
10142
+ return refList;
10143
+ }
10004
10144
  }
10005
10145
  PDFCrossRefSection.create = () => new PDFCrossRefSection({
10006
10146
  ref: PDFRef.of(0, 65535),
@@ -10232,6 +10372,15 @@ class PDFWriter {
10232
10372
  if (this.shouldWaitForTick(1))
10233
10373
  yield waitForTick();
10234
10374
  }
10375
+ // deleted objects
10376
+ for (let idx = 0; idx < this.snapshot.deletedCount; idx++) {
10377
+ const dref = this.snapshot.deletedRef(idx);
10378
+ if (!dref)
10379
+ break;
10380
+ const nextdref = this.snapshot.deletedRef(idx + 1);
10381
+ // add 1 to generation number for deleted ref
10382
+ xref.addDeletedEntry(PDFRef.of(dref.objectNumber, dref.generationNumber + 1), nextdref ? nextdref.objectNumber : 0);
10383
+ }
10235
10384
  const xrefOffset = size;
10236
10385
  size += xref.sizeInBytes() + 1; // '\n'
10237
10386
  const trailerDict = PDFTrailerDict.of(this.createTrailerDict(this.snapshot.prevStartXRef));
@@ -15764,11 +15913,17 @@ class PDFXRefStreamParser {
15764
15913
  }
15765
15914
  this.alreadyParsed = true;
15766
15915
  this.context.trailerInfo = {
15916
+ Size: this.dict.lookup(PDFName.of('Size'), PDFNumber),
15767
15917
  Root: this.dict.get(PDFName.of('Root')),
15768
15918
  Encrypt: this.dict.get(PDFName.of('Encrypt')),
15769
15919
  Info: this.dict.get(PDFName.of('Info')),
15770
15920
  ID: this.dict.get(PDFName.of('ID')),
15771
15921
  };
15922
+ // if open for incremental update, make sure next object number doesn't overlap a deleted one
15923
+ if (this.context.trailerInfo.Size &&
15924
+ this.context.pdfFileDetails.originalBytes)
15925
+ this.context.largestObjectNumber =
15926
+ this.context.trailerInfo.Size.asNumber() - 1;
15772
15927
  const entries = this.parseEntries();
15773
15928
  // for (let idx = 0, len = entries.length; idx < len; idx++) {
15774
15929
  // const entry = entries[idx];
@@ -15813,8 +15968,8 @@ class PDFXRefStreamParser {
15813
15968
  PDFXRefStreamParser.forStream = (rawStream) => new PDFXRefStreamParser(rawStream);
15814
15969
 
15815
15970
  class PDFParser extends PDFObjectParser {
15816
- constructor(pdfBytes, objectsPerTick = Infinity, throwOnInvalidObject = false, warnOnInvalidObjects = false, capNumbers = false, cryptoFactory, forIncrementalUpdate = false) {
15817
- super(ByteStream.of(pdfBytes), PDFContext.create(), capNumbers, cryptoFactory);
15971
+ constructor(pdfBytes, objectsPerTick = Infinity, throwOnInvalidObject = false, warnOnInvalidObjects = false, capNumbers = false, cryptoFactory, forIncrementalUpdate = false, preserveObjectsVersions = false) {
15972
+ super(ByteStream.of(pdfBytes), PDFContext.create(preserveObjectsVersions), capNumbers, cryptoFactory);
15818
15973
  this.alreadyParsed = false;
15819
15974
  this.parsedObjects = 0;
15820
15975
  this.shouldWaitForTick = () => {
@@ -15921,7 +16076,17 @@ class PDFParser extends PDFObjectParser {
15921
16076
  }
15922
16077
  else if (object instanceof PDFRawStream &&
15923
16078
  object.dict.lookup(PDFName.of('Type')) === PDFName.of('XRef')) {
15924
- PDFXRefStreamParser.forStream(object).parseIntoContext();
16079
+ const entries = PDFXRefStreamParser.forStream(object).parseIntoContext();
16080
+ if (entries.length) {
16081
+ const xref = PDFCrossRefSection.createEmpty();
16082
+ for (const entry of entries) {
16083
+ if (entry.deleted)
16084
+ xref.addDeletedEntry(entry.ref, entry.offset);
16085
+ else
16086
+ xref.addEntry(entry.ref, entry.offset);
16087
+ }
16088
+ this.context.xrefs.push(xref);
16089
+ }
15925
16090
  }
15926
16091
  // always register the object and the ref, to properly handle object numeration
15927
16092
  this.context.assign(ref, object);
@@ -16021,11 +16186,16 @@ class PDFParser extends PDFObjectParser {
16021
16186
  const dict = this.parseDict();
16022
16187
  const { context } = this;
16023
16188
  context.trailerInfo = {
16189
+ Size: dict.lookupMaybe(PDFName.of('Size'), PDFNumber) ||
16190
+ context.trailerInfo.Size,
16024
16191
  Root: dict.get(PDFName.of('Root')) || context.trailerInfo.Root,
16025
16192
  Encrypt: dict.get(PDFName.of('Encrypt')) || context.trailerInfo.Encrypt,
16026
16193
  Info: dict.get(PDFName.of('Info')) || context.trailerInfo.Info,
16027
16194
  ID: dict.get(PDFName.of('ID')) || context.trailerInfo.ID,
16028
16195
  };
16196
+ // if open for incremental update, then deleted objects need to be preserved, and largestObjectNumber has to be Size-1
16197
+ if (context.trailerInfo.Size && context.pdfFileDetails.originalBytes)
16198
+ context.largestObjectNumber = context.trailerInfo.Size.asNumber() - 1;
16029
16199
  }
16030
16200
  maybeParseTrailer() {
16031
16201
  this.skipWhitespaceAndComments();
@@ -16044,7 +16214,9 @@ class PDFParser extends PDFObjectParser {
16044
16214
  parseDocumentSection() {
16045
16215
  return __awaiter(this, void 0, void 0, function* () {
16046
16216
  yield this.parseIndirectObjects();
16047
- this.maybeParseCrossRefSection();
16217
+ const xref = this.maybeParseCrossRefSection();
16218
+ if (xref)
16219
+ this.context.xrefs.push(xref);
16048
16220
  this.maybeParseTrailerDict();
16049
16221
  this.maybeParseTrailer();
16050
16222
  // TODO: Can this be done only when needed, to avoid harming performance?
@@ -16101,7 +16273,7 @@ class PDFParser extends PDFObjectParser {
16101
16273
  }
16102
16274
  }
16103
16275
  }
16104
- PDFParser.forBytesWithOptions = (pdfBytes, objectsPerTick, throwOnInvalidObject, warnOnInvalidObjects, capNumbers, cryptoFactory, forIncrementalUpdate) => new PDFParser(pdfBytes, objectsPerTick, throwOnInvalidObject, warnOnInvalidObjects, capNumbers, cryptoFactory, forIncrementalUpdate);
16276
+ PDFParser.forBytesWithOptions = (pdfBytes, objectsPerTick, throwOnInvalidObject, warnOnInvalidObjects, capNumbers, cryptoFactory, forIncrementalUpdate, preserveObjectsVersions) => new PDFParser(pdfBytes, objectsPerTick, throwOnInvalidObject, warnOnInvalidObjects, capNumbers, cryptoFactory, forIncrementalUpdate, preserveObjectsVersions);
16105
16277
 
16106
16278
  var cryptoJs = {exports: {}};
16107
16279
 
@@ -35630,7 +35802,7 @@ class PDFDocument {
35630
35802
  */
35631
35803
  static load(pdf, options = {}) {
35632
35804
  return __awaiter(this, void 0, void 0, function* () {
35633
- const { ignoreEncryption = false, parseSpeed = ParseSpeeds.Slow, throwOnInvalidObject = false, warnOnInvalidObjects = false, updateMetadata = true, capNumbers = false, password, forIncrementalUpdate = false, } = options;
35805
+ const { ignoreEncryption = false, parseSpeed = ParseSpeeds.Slow, throwOnInvalidObject = false, warnOnInvalidObjects = false, updateMetadata = true, capNumbers = false, password, forIncrementalUpdate = false, preserveObjectsVersions = false, } = options;
35634
35806
  assertIs(pdf, 'pdf', ['string', Uint8Array, ArrayBuffer]);
35635
35807
  assertIs(ignoreEncryption, 'ignoreEncryption', ['boolean']);
35636
35808
  assertIs(parseSpeed, 'parseSpeed', ['number']);
@@ -35638,14 +35810,15 @@ class PDFDocument {
35638
35810
  assertIs(warnOnInvalidObjects, 'warnOnInvalidObjects', ['boolean']);
35639
35811
  assertIs(password, 'password', ['string', 'undefined']);
35640
35812
  assertIs(forIncrementalUpdate, 'forIncrementalUpdate', ['boolean']);
35813
+ assertIs(preserveObjectsVersions, 'preserveObjectsVersions', ['boolean']);
35641
35814
  const bytes = toUint8Array(pdf);
35642
- const context = yield PDFParser.forBytesWithOptions(bytes, parseSpeed, throwOnInvalidObject, undefined, capNumbers, undefined, forIncrementalUpdate).parseDocument();
35815
+ const context = yield PDFParser.forBytesWithOptions(bytes, parseSpeed, throwOnInvalidObject, undefined, capNumbers, undefined, forIncrementalUpdate, preserveObjectsVersions).parseDocument();
35643
35816
  if (!!context.lookup(context.trailerInfo.Encrypt) &&
35644
35817
  password !== undefined) {
35645
35818
  // Decrypt
35646
35819
  const fileIds = context.lookup(context.trailerInfo.ID, PDFArray);
35647
35820
  const encryptDict = context.lookup(context.trailerInfo.Encrypt, PDFDict);
35648
- const decryptedContext = yield PDFParser.forBytesWithOptions(bytes, parseSpeed, throwOnInvalidObject, warnOnInvalidObjects, capNumbers, new CipherTransformFactory(encryptDict, fileIds.get(0).asBytes(), password), forIncrementalUpdate).parseDocument();
35821
+ const decryptedContext = yield PDFParser.forBytesWithOptions(bytes, parseSpeed, throwOnInvalidObject, warnOnInvalidObjects, capNumbers, new CipherTransformFactory(encryptDict, fileIds.get(0).asBytes(), password), forIncrementalUpdate, preserveObjectsVersions).parseDocument();
35649
35822
  const pdfDoc = new PDFDocument(decryptedContext, true, updateMetadata);
35650
35823
  if (forIncrementalUpdate)
35651
35824
  pdfDoc.takeSnapshot();
@@ -36108,8 +36281,10 @@ class PDFDocument {
36108
36281
  if (this.pageCount === 0)
36109
36282
  throw new RemovePageFromEmptyDocumentError();
36110
36283
  assertRange(index, 'index', 0, pageCount - 1);
36284
+ const page = this.getPage(index);
36111
36285
  this.catalog.removeLeafNode(index);
36112
36286
  this.pageCount = pageCount - 1;
36287
+ this.context.delete(page.ref);
36113
36288
  }
36114
36289
  /**
36115
36290
  * Add a page to the end of this document. This method accepts three
@@ -36937,6 +37112,51 @@ class PDFDocument {
36937
37112
  }
36938
37113
  return snapshot;
36939
37114
  }
37115
+ /**
37116
+ * Returns the update version of the object as 'actual', and all the previous versions, of the objects
37117
+ * that has changed in the indicated update (or the last one).
37118
+ * If document wasn't load to preserve objects versions, an empty array is returned.
37119
+ * @param {number} lastUpdateMinusX If not the last update, how many updates before the last.
37120
+ * @returns {PDFObjectVersions[]} Objects modified in the update, and previous versions
37121
+ */
37122
+ getChangedObjects(lastUpdateMinusX = 0) {
37123
+ if (!this.context.preserveObjectsVersions)
37124
+ return [];
37125
+ if (lastUpdateMinusX < 0)
37126
+ lastUpdateMinusX = 0;
37127
+ const upind = this.context.xrefs.length - lastUpdateMinusX - 1;
37128
+ const entries = this.context.listXrefEntries(upind);
37129
+ if (!entries.length)
37130
+ return [];
37131
+ const changed = new Map();
37132
+ for (const entry of entries) {
37133
+ const ref = entry.ref;
37134
+ changed.set(ref, {
37135
+ ref,
37136
+ actual: entry.deleted ? undefined : this.context.lookup(ref),
37137
+ previous: this.context.getObjectVersions(ref),
37138
+ });
37139
+ }
37140
+ // if not the las update, then check objects later modified and adjust PDFObjectVersions accordingly
37141
+ if (!lastUpdateMinusX)
37142
+ return Array.from(changed.entries()).map((value) => value[1]);
37143
+ while (lastUpdateMinusX) {
37144
+ lastUpdateMinusX -= 1;
37145
+ const upind = this.context.xrefs.length - lastUpdateMinusX - 1;
37146
+ const nentries = this.context.listXrefEntries(upind);
37147
+ for (const nentry of nentries) {
37148
+ const oce = changed.get(nentry.ref);
37149
+ if (oce && oce.actual) {
37150
+ oce.actual = oce.previous[0];
37151
+ oce.previous = oce.previous.slice(1);
37152
+ }
37153
+ }
37154
+ }
37155
+ // if PDF has errors, it may happen to end with objects that has no current, nor previous versions
37156
+ return Array.from(changed.entries())
37157
+ .map((value) => value[1])
37158
+ .filter((ov) => ov.actual || ov.previous.length);
37159
+ }
36940
37160
  prepareForSave(options) {
36941
37161
  return __awaiter(this, void 0, void 0, function* () {
36942
37162
  const { addDefaultPage = true, updateFieldAppearances = true } = options;