@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.
- package/README.md +43 -0
- package/cjs/api/PDFDocument.d.ts +14 -0
- package/cjs/api/PDFDocument.d.ts.map +1 -1
- package/cjs/api/PDFDocument.js +51 -3
- package/cjs/api/PDFDocument.js.map +1 -1
- package/cjs/api/PDFDocumentOptions.d.ts +1 -0
- package/cjs/api/PDFDocumentOptions.d.ts.map +1 -1
- package/cjs/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
- package/cjs/api/snapshot/DefaultDocumentSnapshot.d.ts.map +1 -1
- package/cjs/api/snapshot/DefaultDocumentSnapshot.js +10 -0
- package/cjs/api/snapshot/DefaultDocumentSnapshot.js.map +1 -1
- package/cjs/api/snapshot/DocumentSnapshot.d.ts +4 -0
- package/cjs/api/snapshot/DocumentSnapshot.d.ts.map +1 -1
- package/cjs/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
- package/cjs/api/snapshot/IncrementalDocumentSnapshot.d.ts.map +1 -1
- package/cjs/api/snapshot/IncrementalDocumentSnapshot.js +17 -0
- package/cjs/api/snapshot/IncrementalDocumentSnapshot.js.map +1 -1
- package/cjs/core/PDFContext.d.ts +10 -1
- package/cjs/core/PDFContext.d.ts.map +1 -1
- package/cjs/core/PDFContext.js +52 -2
- package/cjs/core/PDFContext.js.map +1 -1
- package/cjs/core/document/PDFCrossRefSection.d.ts +6 -1
- package/cjs/core/document/PDFCrossRefSection.d.ts.map +1 -1
- package/cjs/core/document/PDFCrossRefSection.js +65 -2
- package/cjs/core/document/PDFCrossRefSection.js.map +1 -1
- package/cjs/core/parser/PDFParser.d.ts +2 -2
- package/cjs/core/parser/PDFParser.d.ts.map +1 -1
- package/cjs/core/parser/PDFParser.js +23 -5
- package/cjs/core/parser/PDFParser.js.map +1 -1
- package/cjs/core/parser/PDFXRefStreamParser.d.ts.map +1 -1
- package/cjs/core/parser/PDFXRefStreamParser.js +6 -0
- package/cjs/core/parser/PDFXRefStreamParser.js.map +1 -1
- package/cjs/core/writers/PDFWriter.d.ts.map +1 -1
- package/cjs/core/writers/PDFWriter.js +10 -0
- package/cjs/core/writers/PDFWriter.js.map +1 -1
- package/dist/pdf-lib.esm.js +232 -12
- package/dist/pdf-lib.esm.js.map +1 -1
- package/dist/pdf-lib.esm.min.js +3 -3
- package/dist/pdf-lib.esm.min.js.map +1 -1
- package/dist/pdf-lib.js +232 -12
- package/dist/pdf-lib.js.map +1 -1
- package/dist/pdf-lib.min.js +3 -3
- package/dist/pdf-lib.min.js.map +1 -1
- package/es/api/PDFDocument.d.ts +14 -0
- package/es/api/PDFDocument.d.ts.map +1 -1
- package/es/api/PDFDocument.js +51 -3
- package/es/api/PDFDocument.js.map +1 -1
- package/es/api/PDFDocumentOptions.d.ts +1 -0
- package/es/api/PDFDocumentOptions.d.ts.map +1 -1
- package/es/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
- package/es/api/snapshot/DefaultDocumentSnapshot.d.ts.map +1 -1
- package/es/api/snapshot/DefaultDocumentSnapshot.js +10 -0
- package/es/api/snapshot/DefaultDocumentSnapshot.js.map +1 -1
- package/es/api/snapshot/DocumentSnapshot.d.ts +4 -0
- package/es/api/snapshot/DocumentSnapshot.d.ts.map +1 -1
- package/es/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
- package/es/api/snapshot/IncrementalDocumentSnapshot.d.ts.map +1 -1
- package/es/api/snapshot/IncrementalDocumentSnapshot.js +17 -0
- package/es/api/snapshot/IncrementalDocumentSnapshot.js.map +1 -1
- package/es/core/PDFContext.d.ts +10 -1
- package/es/core/PDFContext.d.ts.map +1 -1
- package/es/core/PDFContext.js +52 -2
- package/es/core/PDFContext.js.map +1 -1
- package/es/core/document/PDFCrossRefSection.d.ts +6 -1
- package/es/core/document/PDFCrossRefSection.d.ts.map +1 -1
- package/es/core/document/PDFCrossRefSection.js +65 -2
- package/es/core/document/PDFCrossRefSection.js.map +1 -1
- package/es/core/parser/PDFParser.d.ts +2 -2
- package/es/core/parser/PDFParser.d.ts.map +1 -1
- package/es/core/parser/PDFParser.js +23 -5
- package/es/core/parser/PDFParser.js.map +1 -1
- package/es/core/parser/PDFXRefStreamParser.d.ts.map +1 -1
- package/es/core/parser/PDFXRefStreamParser.js +6 -0
- package/es/core/parser/PDFXRefStreamParser.js.map +1 -1
- package/es/core/writers/PDFWriter.d.ts.map +1 -1
- package/es/core/writers/PDFWriter.js +10 -0
- package/es/core/writers/PDFWriter.js.map +1 -1
- package/package.json +4 -4
- package/src/api/PDFDocument.ts +55 -0
- package/src/api/PDFDocumentOptions.ts +1 -0
- package/src/api/snapshot/DefaultDocumentSnapshot.ts +13 -0
- package/src/api/snapshot/DocumentSnapshot.ts +6 -0
- package/src/api/snapshot/IncrementalDocumentSnapshot.ts +20 -0
- package/src/core/PDFContext.ts +53 -2
- package/src/core/document/PDFCrossRefSection.ts +70 -2
- package/src/core/parser/PDFParser.ts +22 -3
- package/src/core/parser/PDFXRefStreamParser.ts +8 -0
- package/src/core/writers/PDFWriter.ts +11 -0
- package/ts3.4/cjs/api/PDFDocument.d.ts +14 -0
- package/ts3.4/cjs/api/PDFDocumentOptions.d.ts +1 -0
- package/ts3.4/cjs/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
- package/ts3.4/cjs/api/snapshot/DocumentSnapshot.d.ts +4 -0
- package/ts3.4/cjs/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
- package/ts3.4/cjs/core/PDFContext.d.ts +10 -1
- package/ts3.4/cjs/core/document/PDFCrossRefSection.d.ts +6 -1
- package/ts3.4/cjs/core/parser/PDFParser.d.ts +2 -2
- package/ts3.4/es/api/PDFDocument.d.ts +14 -0
- package/ts3.4/es/api/PDFDocumentOptions.d.ts +1 -0
- package/ts3.4/es/api/snapshot/DefaultDocumentSnapshot.d.ts +4 -0
- package/ts3.4/es/api/snapshot/DocumentSnapshot.d.ts +4 -0
- package/ts3.4/es/api/snapshot/IncrementalDocumentSnapshot.d.ts +5 -0
- package/ts3.4/es/core/PDFContext.d.ts +10 -1
- package/ts3.4/es/core/document/PDFCrossRefSection.d.ts +6 -1
- package/ts3.4/es/core/parser/PDFParser.d.ts +2 -2
|
@@ -4,6 +4,7 @@ import type { DocumentSnapshot } from './DocumentSnapshot';
|
|
|
4
4
|
export class DefaultDocumentSnapshot implements DocumentSnapshot {
|
|
5
5
|
pdfSize = 0;
|
|
6
6
|
prevStartXRef = 0;
|
|
7
|
+
deletedCount = 0;
|
|
7
8
|
|
|
8
9
|
shouldSave(_objectNumber: number): boolean {
|
|
9
10
|
return true;
|
|
@@ -24,6 +25,18 @@ export class DefaultDocumentSnapshot implements DocumentSnapshot {
|
|
|
24
25
|
markObjsForSave(_objs: PDFObject[]): void {
|
|
25
26
|
throw new Error('This method should not be called.');
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
markDeletedObj(_obj: PDFObject): void {
|
|
30
|
+
throw new Error('This method should not be called.');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
markDeletedRef(_ref: PDFRef): void {
|
|
34
|
+
throw new Error('This method should not be called.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
deletedRef(_index: number): PDFRef | null {
|
|
38
|
+
throw new Error('This method should not be called.');
|
|
39
|
+
}
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
export const defaultDocumentSnapshot = new DefaultDocumentSnapshot();
|
|
@@ -3,6 +3,7 @@ import type { PDFObject, PDFRef } from '../../core';
|
|
|
3
3
|
export interface DocumentSnapshot {
|
|
4
4
|
pdfSize: number;
|
|
5
5
|
prevStartXRef: number;
|
|
6
|
+
deletedCount: number;
|
|
6
7
|
|
|
7
8
|
shouldSave: (objectNumber: number) => boolean;
|
|
8
9
|
|
|
@@ -11,4 +12,9 @@ export interface DocumentSnapshot {
|
|
|
11
12
|
|
|
12
13
|
markObjForSave: (obj: PDFObject) => void;
|
|
13
14
|
markObjsForSave: (objs: PDFObject[]) => void;
|
|
15
|
+
|
|
16
|
+
markDeletedRef: (ref: PDFRef) => void;
|
|
17
|
+
markDeletedObj: (obj: PDFObject) => void;
|
|
18
|
+
|
|
19
|
+
deletedRef: (index: number) => PDFRef | null;
|
|
14
20
|
}
|
|
@@ -4,7 +4,9 @@ import type { DocumentSnapshot } from './DocumentSnapshot';
|
|
|
4
4
|
export class IncrementalDocumentSnapshot implements DocumentSnapshot {
|
|
5
5
|
pdfSize: number;
|
|
6
6
|
prevStartXRef: number;
|
|
7
|
+
deletedCount: number = 0;
|
|
7
8
|
|
|
9
|
+
private deleted: PDFRef[] = [];
|
|
8
10
|
private lastObjectNumber: number;
|
|
9
11
|
private changedObjects: number[];
|
|
10
12
|
|
|
@@ -56,4 +58,22 @@ export class IncrementalDocumentSnapshot implements DocumentSnapshot {
|
|
|
56
58
|
.filter((ref) => ref !== undefined) as PDFRef[],
|
|
57
59
|
);
|
|
58
60
|
}
|
|
61
|
+
|
|
62
|
+
markDeletedRef(ref: PDFRef): void {
|
|
63
|
+
if (
|
|
64
|
+
this.deleted.findIndex((dref) => dref.objectNumber === ref.objectNumber) <
|
|
65
|
+
0
|
|
66
|
+
)
|
|
67
|
+
this.deletedCount = this.deleted.push(ref);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
markDeletedObj(obj: PDFObject): void {
|
|
71
|
+
const oref = this.context.getRef(obj);
|
|
72
|
+
if (oref) this.markDeletedRef(oref);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
deletedRef(index: number): PDFRef | null {
|
|
76
|
+
if (index < 0 || index >= this.deleted.length) return null;
|
|
77
|
+
return this.deleted[index];
|
|
78
|
+
}
|
|
59
79
|
}
|
package/src/core/PDFContext.ts
CHANGED
|
@@ -21,6 +21,8 @@ import PDFContentStream from './structures/PDFContentStream';
|
|
|
21
21
|
import PDFSecurity from './security/PDFSecurity';
|
|
22
22
|
import { typedArrayFor } from '../utils';
|
|
23
23
|
import { SimpleRNG } from '../utils/rng';
|
|
24
|
+
import PDFCrossRefSection from './document/PDFCrossRefSection';
|
|
25
|
+
import type { Entry } from './document/PDFCrossRefSection';
|
|
24
26
|
|
|
25
27
|
type LookupKey = PDFRef | PDFObject | undefined;
|
|
26
28
|
|
|
@@ -55,11 +57,13 @@ const byAscendingObjectNumber = (
|
|
|
55
57
|
|
|
56
58
|
class PDFContext {
|
|
57
59
|
isDecrypted = true;
|
|
58
|
-
static create = (
|
|
60
|
+
static create = (withObjectVersions: boolean = false) =>
|
|
61
|
+
new PDFContext(withObjectVersions);
|
|
59
62
|
|
|
60
63
|
largestObjectNumber: number;
|
|
61
64
|
header: PDFHeader;
|
|
62
65
|
trailerInfo: {
|
|
66
|
+
Size?: PDFNumber;
|
|
63
67
|
Root?: PDFObject;
|
|
64
68
|
Encrypt?: PDFObject;
|
|
65
69
|
Info?: PDFObject;
|
|
@@ -73,20 +77,30 @@ class PDFContext {
|
|
|
73
77
|
originalBytes?: Uint8Array;
|
|
74
78
|
};
|
|
75
79
|
snapshot?: DocumentSnapshot;
|
|
80
|
+
xrefs: PDFCrossRefSection[] = [];
|
|
81
|
+
private _preserveObjectsVersions: boolean;
|
|
82
|
+
public get preserveObjectsVersions(): boolean {
|
|
83
|
+
return this._preserveObjectsVersions;
|
|
84
|
+
}
|
|
76
85
|
|
|
77
86
|
security?: PDFSecurity;
|
|
78
87
|
|
|
79
88
|
private readonly indirectObjects: Map<PDFRef, PDFObject>;
|
|
89
|
+
private readonly objectsPreviousVersions: Map<PDFRef, PDFObject[]>;
|
|
80
90
|
|
|
81
91
|
private pushGraphicsStateContentStreamRef?: PDFRef;
|
|
82
92
|
private popGraphicsStateContentStreamRef?: PDFRef;
|
|
83
93
|
|
|
84
|
-
private constructor() {
|
|
94
|
+
private constructor(preserveObjectsVersions?: boolean) {
|
|
95
|
+
this._preserveObjectsVersions = preserveObjectsVersions
|
|
96
|
+
? preserveObjectsVersions
|
|
97
|
+
: false;
|
|
85
98
|
this.largestObjectNumber = 0;
|
|
86
99
|
this.header = PDFHeader.forVersion(1, 7);
|
|
87
100
|
this.trailerInfo = {};
|
|
88
101
|
|
|
89
102
|
this.indirectObjects = new Map();
|
|
103
|
+
this.objectsPreviousVersions = new Map();
|
|
90
104
|
this.rng = SimpleRNG.withSeed(1);
|
|
91
105
|
this.pdfFileDetails = {
|
|
92
106
|
pdfSize: 0,
|
|
@@ -96,6 +110,17 @@ class PDFContext {
|
|
|
96
110
|
}
|
|
97
111
|
|
|
98
112
|
assign(ref: PDFRef, object: PDFObject): void {
|
|
113
|
+
if (this.preserveObjectsVersions) {
|
|
114
|
+
const prevOV = this.indirectObjects.get(ref);
|
|
115
|
+
if (prevOV) {
|
|
116
|
+
const prevList = this.objectsPreviousVersions.get(ref);
|
|
117
|
+
if (!prevList) {
|
|
118
|
+
this.objectsPreviousVersions.set(ref, [prevOV]);
|
|
119
|
+
} else {
|
|
120
|
+
prevList.unshift(prevOV);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
99
124
|
this.indirectObjects.set(ref, object);
|
|
100
125
|
if (ref.objectNumber > this.largestObjectNumber) {
|
|
101
126
|
this.largestObjectNumber = ref.objectNumber;
|
|
@@ -114,6 +139,19 @@ class PDFContext {
|
|
|
114
139
|
}
|
|
115
140
|
|
|
116
141
|
delete(ref: PDFRef): boolean {
|
|
142
|
+
if (this.snapshot) this.snapshot.markDeletedRef(ref);
|
|
143
|
+
if (this.preserveObjectsVersions) {
|
|
144
|
+
const object = this.indirectObjects.get(ref);
|
|
145
|
+
if (object) {
|
|
146
|
+
// check is not already deleted
|
|
147
|
+
const verlist = this.objectsPreviousVersions.get(ref);
|
|
148
|
+
if (verlist) {
|
|
149
|
+
verlist.unshift(object);
|
|
150
|
+
} else {
|
|
151
|
+
this.objectsPreviousVersions.set(ref, [object]);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
117
155
|
return this.indirectObjects.delete(ref);
|
|
118
156
|
}
|
|
119
157
|
|
|
@@ -391,6 +429,19 @@ class PDFContext {
|
|
|
391
429
|
registerObjectChange(obj: PDFObject) {
|
|
392
430
|
if (this.snapshot) this.snapshot.markObjForSave(obj);
|
|
393
431
|
}
|
|
432
|
+
|
|
433
|
+
getObjectVersions(ref: PDFRef): PDFObject[] {
|
|
434
|
+
if (!this.preserveObjectsVersions) return [];
|
|
435
|
+
const list = this.objectsPreviousVersions.get(ref);
|
|
436
|
+
if (list) return list;
|
|
437
|
+
return [];
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
listXrefEntries(xrefIndex: number = -1): Entry[] {
|
|
441
|
+
if (xrefIndex < 0) xrefIndex = this.xrefs.length - 1;
|
|
442
|
+
if (xrefIndex < 0 || xrefIndex >= this.xrefs.length) return [];
|
|
443
|
+
return this.xrefs[xrefIndex].listRefs();
|
|
444
|
+
}
|
|
394
445
|
}
|
|
395
446
|
|
|
396
447
|
export default PDFContext;
|
|
@@ -10,7 +10,7 @@ export interface Entry {
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Entries should be added using the [[addEntry]] and [[addDeletedEntry]]
|
|
13
|
-
* methods
|
|
13
|
+
* methods.
|
|
14
14
|
*/
|
|
15
15
|
class PDFCrossRefSection {
|
|
16
16
|
static create = () =>
|
|
@@ -37,6 +37,22 @@ class PDFCrossRefSection {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
addDeletedEntry(ref: PDFRef, nextFreeObjectNumber: number): void {
|
|
40
|
+
// fix the first entry if required
|
|
41
|
+
if (!this.subsections.length) {
|
|
42
|
+
this.subsections = [
|
|
43
|
+
[
|
|
44
|
+
{
|
|
45
|
+
ref: PDFRef.of(0, 65535),
|
|
46
|
+
offset: ref.objectNumber,
|
|
47
|
+
deleted: true,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
];
|
|
51
|
+
this.chunkIdx = 0;
|
|
52
|
+
this.chunkLength = 1;
|
|
53
|
+
} else if (!this.subsections[0][0].offset) {
|
|
54
|
+
this.subsections[0][0].offset = ref.objectNumber;
|
|
55
|
+
}
|
|
40
56
|
this.append({ ref, offset: nextFreeObjectNumber, deleted: true });
|
|
41
57
|
}
|
|
42
58
|
|
|
@@ -159,7 +175,35 @@ class PDFCrossRefSection {
|
|
|
159
175
|
const chunk = this.subsections[this.chunkIdx];
|
|
160
176
|
const prevEntry = chunk[this.chunkLength - 1];
|
|
161
177
|
|
|
162
|
-
if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber
|
|
178
|
+
if (currEntry.ref.objectNumber - prevEntry.ref.objectNumber !== 1) {
|
|
179
|
+
// the current chunk is not the right chunk, find the right one, or create a new one
|
|
180
|
+
for (let c = 0; c < this.subsections.length; c++) {
|
|
181
|
+
const first = this.subsections[c][0];
|
|
182
|
+
const last = this.subsections[c][this.subsections[c].length - 1];
|
|
183
|
+
if (first.ref.objectNumber > currEntry.ref.objectNumber) {
|
|
184
|
+
// goes before this subsection, or at the start of it
|
|
185
|
+
if (first.ref.objectNumber - currEntry.ref.objectNumber === 1) {
|
|
186
|
+
// first element of subsection
|
|
187
|
+
this.subsections[c].unshift(currEntry);
|
|
188
|
+
if (c === this.chunkIdx) this.chunkLength += 1;
|
|
189
|
+
return;
|
|
190
|
+
} else {
|
|
191
|
+
// create subsection
|
|
192
|
+
this.subsections.splice(c, 0, [currEntry]);
|
|
193
|
+
this.chunkIdx++;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
} else if (last.ref.objectNumber > currEntry.ref.objectNumber) {
|
|
197
|
+
// goes in this subsection, find its place..
|
|
198
|
+
const cep = this.subsections[c].findIndex(
|
|
199
|
+
(ee) => ee.ref.objectNumber > currEntry.ref.objectNumber,
|
|
200
|
+
);
|
|
201
|
+
this.subsections[c].splice(cep, 0, currEntry);
|
|
202
|
+
if (c === this.chunkIdx) this.chunkLength += 1;
|
|
203
|
+
}
|
|
204
|
+
// bigger, keep looking
|
|
205
|
+
}
|
|
206
|
+
// if got to here, then a new subsection is required
|
|
163
207
|
this.subsections.push([currEntry]);
|
|
164
208
|
this.chunkIdx += 1;
|
|
165
209
|
this.chunkLength = 1;
|
|
@@ -168,6 +212,30 @@ class PDFCrossRefSection {
|
|
|
168
212
|
this.chunkLength += 1;
|
|
169
213
|
}
|
|
170
214
|
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Returns all the entries in the XREF section, except the first one (object == 0)
|
|
218
|
+
* @returns {Entry[]} All the entries in the XREF section
|
|
219
|
+
*/
|
|
220
|
+
listRefs(): Entry[] {
|
|
221
|
+
const refList: Entry[] = [];
|
|
222
|
+
for (
|
|
223
|
+
let rangeIdx = 0, rangeLen = this.subsections.length;
|
|
224
|
+
rangeIdx < rangeLen;
|
|
225
|
+
rangeIdx++
|
|
226
|
+
) {
|
|
227
|
+
const range = this.subsections[rangeIdx];
|
|
228
|
+
for (
|
|
229
|
+
let entryIdx = 0, entryLen = range.length;
|
|
230
|
+
entryIdx < entryLen;
|
|
231
|
+
entryIdx++
|
|
232
|
+
) {
|
|
233
|
+
const entry = range[entryIdx];
|
|
234
|
+
if (entry.ref.objectNumber) refList.push(entry);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return refList;
|
|
238
|
+
}
|
|
171
239
|
}
|
|
172
240
|
|
|
173
241
|
export default PDFCrossRefSection;
|
|
@@ -24,6 +24,7 @@ import { Keywords } from '../syntax/Keywords';
|
|
|
24
24
|
import { IsDigit } from '../syntax/Numeric';
|
|
25
25
|
import { waitForTick } from '../../utils';
|
|
26
26
|
import { CipherTransformFactory } from '../crypto';
|
|
27
|
+
import PDFNumber from '../objects/PDFNumber';
|
|
27
28
|
|
|
28
29
|
class PDFParser extends PDFObjectParser {
|
|
29
30
|
static forBytesWithOptions = (
|
|
@@ -34,6 +35,7 @@ class PDFParser extends PDFObjectParser {
|
|
|
34
35
|
capNumbers?: boolean,
|
|
35
36
|
cryptoFactory?: CipherTransformFactory,
|
|
36
37
|
forIncrementalUpdate?: boolean,
|
|
38
|
+
preserveObjectsVersions?: boolean,
|
|
37
39
|
) =>
|
|
38
40
|
new PDFParser(
|
|
39
41
|
pdfBytes,
|
|
@@ -43,6 +45,7 @@ class PDFParser extends PDFObjectParser {
|
|
|
43
45
|
capNumbers,
|
|
44
46
|
cryptoFactory,
|
|
45
47
|
forIncrementalUpdate,
|
|
48
|
+
preserveObjectsVersions,
|
|
46
49
|
);
|
|
47
50
|
|
|
48
51
|
private readonly objectsPerTick: number;
|
|
@@ -59,10 +62,11 @@ class PDFParser extends PDFObjectParser {
|
|
|
59
62
|
capNumbers = false,
|
|
60
63
|
cryptoFactory?: CipherTransformFactory,
|
|
61
64
|
forIncrementalUpdate = false,
|
|
65
|
+
preserveObjectsVersions = false,
|
|
62
66
|
) {
|
|
63
67
|
super(
|
|
64
68
|
ByteStream.of(pdfBytes),
|
|
65
|
-
PDFContext.create(),
|
|
69
|
+
PDFContext.create(preserveObjectsVersions),
|
|
66
70
|
capNumbers,
|
|
67
71
|
cryptoFactory,
|
|
68
72
|
);
|
|
@@ -195,7 +199,15 @@ class PDFParser extends PDFObjectParser {
|
|
|
195
199
|
object instanceof PDFRawStream &&
|
|
196
200
|
object.dict.lookup(PDFName.of('Type')) === PDFName.of('XRef')
|
|
197
201
|
) {
|
|
198
|
-
PDFXRefStreamParser.forStream(object).parseIntoContext();
|
|
202
|
+
const entries = PDFXRefStreamParser.forStream(object).parseIntoContext();
|
|
203
|
+
if (entries.length) {
|
|
204
|
+
const xref = PDFCrossRefSection.createEmpty();
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
if (entry.deleted) xref.addDeletedEntry(entry.ref, entry.offset);
|
|
207
|
+
else xref.addEntry(entry.ref, entry.offset);
|
|
208
|
+
}
|
|
209
|
+
this.context.xrefs.push(xref);
|
|
210
|
+
}
|
|
199
211
|
}
|
|
200
212
|
// always register the object and the ref, to properly handle object numeration
|
|
201
213
|
this.context.assign(ref, object);
|
|
@@ -307,11 +319,17 @@ class PDFParser extends PDFObjectParser {
|
|
|
307
319
|
|
|
308
320
|
const { context } = this;
|
|
309
321
|
context.trailerInfo = {
|
|
322
|
+
Size:
|
|
323
|
+
dict.lookupMaybe(PDFName.of('Size'), PDFNumber) ||
|
|
324
|
+
context.trailerInfo.Size,
|
|
310
325
|
Root: dict.get(PDFName.of('Root')) || context.trailerInfo.Root,
|
|
311
326
|
Encrypt: dict.get(PDFName.of('Encrypt')) || context.trailerInfo.Encrypt,
|
|
312
327
|
Info: dict.get(PDFName.of('Info')) || context.trailerInfo.Info,
|
|
313
328
|
ID: dict.get(PDFName.of('ID')) || context.trailerInfo.ID,
|
|
314
329
|
};
|
|
330
|
+
// if open for incremental update, then deleted objects need to be preserved, and largestObjectNumber has to be Size-1
|
|
331
|
+
if (context.trailerInfo.Size && context.pdfFileDetails.originalBytes)
|
|
332
|
+
context.largestObjectNumber = context.trailerInfo.Size.asNumber() - 1;
|
|
315
333
|
}
|
|
316
334
|
|
|
317
335
|
private maybeParseTrailer(): PDFTrailer | void {
|
|
@@ -333,7 +351,8 @@ class PDFParser extends PDFObjectParser {
|
|
|
333
351
|
|
|
334
352
|
private async parseDocumentSection(): Promise<void> {
|
|
335
353
|
await this.parseIndirectObjects();
|
|
336
|
-
this.maybeParseCrossRefSection();
|
|
354
|
+
const xref = this.maybeParseCrossRefSection();
|
|
355
|
+
if (xref) this.context.xrefs.push(xref);
|
|
337
356
|
this.maybeParseTrailerDict();
|
|
338
357
|
this.maybeParseTrailer();
|
|
339
358
|
|
|
@@ -66,11 +66,19 @@ class PDFXRefStreamParser {
|
|
|
66
66
|
this.alreadyParsed = true;
|
|
67
67
|
|
|
68
68
|
this.context.trailerInfo = {
|
|
69
|
+
Size: this.dict.lookup(PDFName.of('Size'), PDFNumber),
|
|
69
70
|
Root: this.dict.get(PDFName.of('Root')),
|
|
70
71
|
Encrypt: this.dict.get(PDFName.of('Encrypt')),
|
|
71
72
|
Info: this.dict.get(PDFName.of('Info')),
|
|
72
73
|
ID: this.dict.get(PDFName.of('ID')),
|
|
73
74
|
};
|
|
75
|
+
// if open for incremental update, make sure next object number doesn't overlap a deleted one
|
|
76
|
+
if (
|
|
77
|
+
this.context.trailerInfo.Size &&
|
|
78
|
+
this.context.pdfFileDetails.originalBytes
|
|
79
|
+
)
|
|
80
|
+
this.context.largestObjectNumber =
|
|
81
|
+
this.context.trailerInfo.Size.asNumber() - 1;
|
|
74
82
|
|
|
75
83
|
const entries = this.parseEntries();
|
|
76
84
|
|
|
@@ -166,6 +166,17 @@ class PDFWriter {
|
|
|
166
166
|
size += this.computeIndirectObjectSize(indirectObject);
|
|
167
167
|
if (this.shouldWaitForTick(1)) await waitForTick();
|
|
168
168
|
}
|
|
169
|
+
// deleted objects
|
|
170
|
+
for (let idx = 0; idx < this.snapshot.deletedCount; idx++) {
|
|
171
|
+
const dref = this.snapshot.deletedRef(idx);
|
|
172
|
+
if (!dref) break;
|
|
173
|
+
const nextdref = this.snapshot.deletedRef(idx + 1);
|
|
174
|
+
// add 1 to generation number for deleted ref
|
|
175
|
+
xref.addDeletedEntry(
|
|
176
|
+
PDFRef.of(dref.objectNumber, dref.generationNumber + 1),
|
|
177
|
+
nextdref ? nextdref.objectNumber : 0,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
169
180
|
|
|
170
181
|
const xrefOffset = size;
|
|
171
182
|
size += xref.sizeInBytes() + 1; // '\n'
|
|
@@ -6,6 +6,7 @@ import PDFForm from './form/PDFForm';
|
|
|
6
6
|
import { StandardFonts } from './StandardFonts';
|
|
7
7
|
import { PageBoundingBox, PDFCatalog, PDFContext } from '../core';
|
|
8
8
|
import { AttachmentOptions, SaveOptions, Base64SaveOptions, LoadOptions, CreateOptions, EmbedFontOptions, SetTitleOptions, IncrementalSaveOptions } from './PDFDocumentOptions';
|
|
9
|
+
import PDFObject from '../core/objects/PDFObject';
|
|
9
10
|
import PDFRef from '../core/objects/PDFRef';
|
|
10
11
|
import { Fontkit } from '../types/fontkit';
|
|
11
12
|
import { TransformationMatrix } from '../types/matrix';
|
|
@@ -22,6 +23,11 @@ export type PDFAttachment = {
|
|
|
22
23
|
creationDate: Date | undefined;
|
|
23
24
|
modificationDate: Date | undefined;
|
|
24
25
|
};
|
|
26
|
+
export type PDFObjectVersions = {
|
|
27
|
+
ref: PDFRef;
|
|
28
|
+
actual: PDFObject | undefined;
|
|
29
|
+
previous: PDFObject[];
|
|
30
|
+
};
|
|
25
31
|
/**
|
|
26
32
|
* Represents a PDF document.
|
|
27
33
|
*/
|
|
@@ -828,6 +834,14 @@ export default class PDFDocument {
|
|
|
828
834
|
saveAsBase64(options?: Base64SaveOptions): Promise<string>;
|
|
829
835
|
findPageForAnnotationRef(ref: PDFRef): PDFPage | undefined;
|
|
830
836
|
takeSnapshot(): DocumentSnapshot;
|
|
837
|
+
/**
|
|
838
|
+
* Returns the update version of the object as 'actual', and all the previous versions, of the objects
|
|
839
|
+
* that has changed in the indicated update (or the last one).
|
|
840
|
+
* If document wasn't load to preserve objects versions, an empty array is returned.
|
|
841
|
+
* @param {number} lastUpdateMinusX If not the last update, how many updates before the last.
|
|
842
|
+
* @returns {PDFObjectVersions[]} Objects modified in the update, and previous versions
|
|
843
|
+
*/
|
|
844
|
+
getChangedObjects(lastUpdateMinusX?: number): PDFObjectVersions[];
|
|
831
845
|
private prepareForSave;
|
|
832
846
|
private embedAll;
|
|
833
847
|
private updateInfoDict;
|
|
@@ -3,11 +3,15 @@ import { DocumentSnapshot } from './DocumentSnapshot';
|
|
|
3
3
|
export declare class DefaultDocumentSnapshot implements DocumentSnapshot {
|
|
4
4
|
pdfSize: number;
|
|
5
5
|
prevStartXRef: number;
|
|
6
|
+
deletedCount: number;
|
|
6
7
|
shouldSave(_objectNumber: number): boolean;
|
|
7
8
|
markRefForSave(_ref: PDFRef): void;
|
|
8
9
|
markRefsForSave(_refs: PDFRef[]): void;
|
|
9
10
|
markObjForSave(_obj: PDFObject): void;
|
|
10
11
|
markObjsForSave(_objs: PDFObject[]): void;
|
|
12
|
+
markDeletedObj(_obj: PDFObject): void;
|
|
13
|
+
markDeletedRef(_ref: PDFRef): void;
|
|
14
|
+
deletedRef(_index: number): PDFRef | null;
|
|
11
15
|
}
|
|
12
16
|
export declare const defaultDocumentSnapshot: DefaultDocumentSnapshot;
|
|
13
17
|
//# sourceMappingURL=DefaultDocumentSnapshot.d.ts.map
|
|
@@ -2,10 +2,14 @@ import { PDFObject, PDFRef } from '../../core';
|
|
|
2
2
|
export interface DocumentSnapshot {
|
|
3
3
|
pdfSize: number;
|
|
4
4
|
prevStartXRef: number;
|
|
5
|
+
deletedCount: number;
|
|
5
6
|
shouldSave: (objectNumber: number) => boolean;
|
|
6
7
|
markRefForSave: (ref: PDFRef) => void;
|
|
7
8
|
markRefsForSave: (refs: PDFRef[]) => void;
|
|
8
9
|
markObjForSave: (obj: PDFObject) => void;
|
|
9
10
|
markObjsForSave: (objs: PDFObject[]) => void;
|
|
11
|
+
markDeletedRef: (ref: PDFRef) => void;
|
|
12
|
+
markDeletedObj: (obj: PDFObject) => void;
|
|
13
|
+
deletedRef: (index: number) => PDFRef | null;
|
|
10
14
|
}
|
|
11
15
|
//# sourceMappingURL=DocumentSnapshot.d.ts.map
|
|
@@ -3,6 +3,8 @@ import { DocumentSnapshot } from './DocumentSnapshot';
|
|
|
3
3
|
export declare class IncrementalDocumentSnapshot implements DocumentSnapshot {
|
|
4
4
|
pdfSize: number;
|
|
5
5
|
prevStartXRef: number;
|
|
6
|
+
deletedCount: number;
|
|
7
|
+
private deleted;
|
|
6
8
|
private lastObjectNumber;
|
|
7
9
|
private changedObjects;
|
|
8
10
|
context: PDFContext;
|
|
@@ -12,5 +14,8 @@ export declare class IncrementalDocumentSnapshot implements DocumentSnapshot {
|
|
|
12
14
|
markRefsForSave(refs: PDFRef[]): void;
|
|
13
15
|
markObjForSave(obj: PDFObject): void;
|
|
14
16
|
markObjsForSave(objs: PDFObject[]): void;
|
|
17
|
+
markDeletedRef(ref: PDFRef): void;
|
|
18
|
+
markDeletedObj(obj: PDFObject): void;
|
|
19
|
+
deletedRef(index: number): PDFRef | null;
|
|
15
20
|
}
|
|
16
21
|
//# sourceMappingURL=IncrementalDocumentSnapshot.d.ts.map
|
|
@@ -16,6 +16,8 @@ import PDFOperator from './operators/PDFOperator';
|
|
|
16
16
|
import PDFContentStream from './structures/PDFContentStream';
|
|
17
17
|
import PDFSecurity from './security/PDFSecurity';
|
|
18
18
|
import { SimpleRNG } from '../utils/rng';
|
|
19
|
+
import PDFCrossRefSection from './document/PDFCrossRefSection';
|
|
20
|
+
import { Entry } from './document/PDFCrossRefSection';
|
|
19
21
|
type LookupKey = PDFRef | PDFObject | undefined;
|
|
20
22
|
interface LiteralObject {
|
|
21
23
|
[name: string]: Literal | PDFObject;
|
|
@@ -32,10 +34,11 @@ interface LiteralConfig {
|
|
|
32
34
|
}
|
|
33
35
|
declare class PDFContext {
|
|
34
36
|
isDecrypted: boolean;
|
|
35
|
-
static create: () => PDFContext;
|
|
37
|
+
static create: (withObjectVersions?: boolean) => PDFContext;
|
|
36
38
|
largestObjectNumber: number;
|
|
37
39
|
header: PDFHeader;
|
|
38
40
|
trailerInfo: {
|
|
41
|
+
Size?: PDFNumber;
|
|
39
42
|
Root?: PDFObject;
|
|
40
43
|
Encrypt?: PDFObject;
|
|
41
44
|
Info?: PDFObject;
|
|
@@ -49,8 +52,12 @@ declare class PDFContext {
|
|
|
49
52
|
originalBytes?: Uint8Array;
|
|
50
53
|
};
|
|
51
54
|
snapshot?: DocumentSnapshot;
|
|
55
|
+
xrefs: PDFCrossRefSection[];
|
|
56
|
+
private _preserveObjectsVersions;
|
|
57
|
+
readonly preserveObjectsVersions: boolean;
|
|
52
58
|
security?: PDFSecurity;
|
|
53
59
|
private readonly indirectObjects;
|
|
60
|
+
private readonly objectsPreviousVersions;
|
|
54
61
|
private pushGraphicsStateContentStreamRef?;
|
|
55
62
|
private popGraphicsStateContentStreamRef?;
|
|
56
63
|
private constructor();
|
|
@@ -112,6 +119,8 @@ declare class PDFContext {
|
|
|
112
119
|
getPopGraphicsStateContentStream(): PDFRef;
|
|
113
120
|
addRandomSuffix(prefix: string, suffixLength?: number): string;
|
|
114
121
|
registerObjectChange(obj: PDFObject): void;
|
|
122
|
+
getObjectVersions(ref: PDFRef): PDFObject[];
|
|
123
|
+
listXrefEntries(xrefIndex?: number): Entry[];
|
|
115
124
|
}
|
|
116
125
|
export default PDFContext;
|
|
117
126
|
//# sourceMappingURL=PDFContext.d.ts.map
|
|
@@ -6,7 +6,7 @@ export interface Entry {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Entries should be added using the [[addEntry]] and [[addDeletedEntry]]
|
|
9
|
-
* methods
|
|
9
|
+
* methods.
|
|
10
10
|
*/
|
|
11
11
|
declare class PDFCrossRefSection {
|
|
12
12
|
static create: () => PDFCrossRefSection;
|
|
@@ -23,6 +23,11 @@ declare class PDFCrossRefSection {
|
|
|
23
23
|
private copySubsectionsIntoBuffer;
|
|
24
24
|
private copyEntriesIntoBuffer;
|
|
25
25
|
private append;
|
|
26
|
+
/**
|
|
27
|
+
* Returns all the entries in the XREF section, except the first one (object == 0)
|
|
28
|
+
* @returns {Entry[]} All the entries in the XREF section
|
|
29
|
+
*/
|
|
30
|
+
listRefs(): Entry[];
|
|
26
31
|
}
|
|
27
32
|
export default PDFCrossRefSection;
|
|
28
33
|
//# sourceMappingURL=PDFCrossRefSection.d.ts.map
|
|
@@ -2,13 +2,13 @@ import PDFObjectParser from './PDFObjectParser';
|
|
|
2
2
|
import PDFContext from '../PDFContext';
|
|
3
3
|
import { CipherTransformFactory } from '../crypto';
|
|
4
4
|
declare class PDFParser extends PDFObjectParser {
|
|
5
|
-
static forBytesWithOptions: (pdfBytes: Uint8Array, objectsPerTick?: number, throwOnInvalidObject?: boolean, warnOnInvalidObjects?: boolean, capNumbers?: boolean, cryptoFactory?: CipherTransformFactory, forIncrementalUpdate?: boolean) => PDFParser;
|
|
5
|
+
static forBytesWithOptions: (pdfBytes: Uint8Array, objectsPerTick?: number, throwOnInvalidObject?: boolean, warnOnInvalidObjects?: boolean, capNumbers?: boolean, cryptoFactory?: CipherTransformFactory, forIncrementalUpdate?: boolean, preserveObjectsVersions?: boolean) => PDFParser;
|
|
6
6
|
private readonly objectsPerTick;
|
|
7
7
|
private readonly throwOnInvalidObject;
|
|
8
8
|
private readonly warnOnInvalidObjects;
|
|
9
9
|
private alreadyParsed;
|
|
10
10
|
private parsedObjects;
|
|
11
|
-
constructor(pdfBytes: Uint8Array, objectsPerTick?: number, throwOnInvalidObject?: boolean, warnOnInvalidObjects?: boolean, capNumbers?: boolean, cryptoFactory?: CipherTransformFactory, forIncrementalUpdate?: boolean);
|
|
11
|
+
constructor(pdfBytes: Uint8Array, objectsPerTick?: number, throwOnInvalidObject?: boolean, warnOnInvalidObjects?: boolean, capNumbers?: boolean, cryptoFactory?: CipherTransformFactory, forIncrementalUpdate?: boolean, preserveObjectsVersions?: boolean);
|
|
12
12
|
parseDocument(): Promise<PDFContext>;
|
|
13
13
|
private maybeRecoverRoot;
|
|
14
14
|
private parseHeader;
|
|
@@ -6,6 +6,7 @@ import PDFForm from './form/PDFForm';
|
|
|
6
6
|
import { StandardFonts } from './StandardFonts';
|
|
7
7
|
import { PageBoundingBox, PDFCatalog, PDFContext } from '../core';
|
|
8
8
|
import { AttachmentOptions, SaveOptions, Base64SaveOptions, LoadOptions, CreateOptions, EmbedFontOptions, SetTitleOptions, IncrementalSaveOptions } from './PDFDocumentOptions';
|
|
9
|
+
import PDFObject from '../core/objects/PDFObject';
|
|
9
10
|
import PDFRef from '../core/objects/PDFRef';
|
|
10
11
|
import { Fontkit } from '../types/fontkit';
|
|
11
12
|
import { TransformationMatrix } from '../types/matrix';
|
|
@@ -22,6 +23,11 @@ export type PDFAttachment = {
|
|
|
22
23
|
creationDate: Date | undefined;
|
|
23
24
|
modificationDate: Date | undefined;
|
|
24
25
|
};
|
|
26
|
+
export type PDFObjectVersions = {
|
|
27
|
+
ref: PDFRef;
|
|
28
|
+
actual: PDFObject | undefined;
|
|
29
|
+
previous: PDFObject[];
|
|
30
|
+
};
|
|
25
31
|
/**
|
|
26
32
|
* Represents a PDF document.
|
|
27
33
|
*/
|
|
@@ -828,6 +834,14 @@ export default class PDFDocument {
|
|
|
828
834
|
saveAsBase64(options?: Base64SaveOptions): Promise<string>;
|
|
829
835
|
findPageForAnnotationRef(ref: PDFRef): PDFPage | undefined;
|
|
830
836
|
takeSnapshot(): DocumentSnapshot;
|
|
837
|
+
/**
|
|
838
|
+
* Returns the update version of the object as 'actual', and all the previous versions, of the objects
|
|
839
|
+
* that has changed in the indicated update (or the last one).
|
|
840
|
+
* If document wasn't load to preserve objects versions, an empty array is returned.
|
|
841
|
+
* @param {number} lastUpdateMinusX If not the last update, how many updates before the last.
|
|
842
|
+
* @returns {PDFObjectVersions[]} Objects modified in the update, and previous versions
|
|
843
|
+
*/
|
|
844
|
+
getChangedObjects(lastUpdateMinusX?: number): PDFObjectVersions[];
|
|
831
845
|
private prepareForSave;
|
|
832
846
|
private embedAll;
|
|
833
847
|
private updateInfoDict;
|
|
@@ -3,11 +3,15 @@ import { DocumentSnapshot } from './DocumentSnapshot';
|
|
|
3
3
|
export declare class DefaultDocumentSnapshot implements DocumentSnapshot {
|
|
4
4
|
pdfSize: number;
|
|
5
5
|
prevStartXRef: number;
|
|
6
|
+
deletedCount: number;
|
|
6
7
|
shouldSave(_objectNumber: number): boolean;
|
|
7
8
|
markRefForSave(_ref: PDFRef): void;
|
|
8
9
|
markRefsForSave(_refs: PDFRef[]): void;
|
|
9
10
|
markObjForSave(_obj: PDFObject): void;
|
|
10
11
|
markObjsForSave(_objs: PDFObject[]): void;
|
|
12
|
+
markDeletedObj(_obj: PDFObject): void;
|
|
13
|
+
markDeletedRef(_ref: PDFRef): void;
|
|
14
|
+
deletedRef(_index: number): PDFRef | null;
|
|
11
15
|
}
|
|
12
16
|
export declare const defaultDocumentSnapshot: DefaultDocumentSnapshot;
|
|
13
17
|
//# sourceMappingURL=DefaultDocumentSnapshot.d.ts.map
|
|
@@ -2,10 +2,14 @@ import { PDFObject, PDFRef } from '../../core';
|
|
|
2
2
|
export interface DocumentSnapshot {
|
|
3
3
|
pdfSize: number;
|
|
4
4
|
prevStartXRef: number;
|
|
5
|
+
deletedCount: number;
|
|
5
6
|
shouldSave: (objectNumber: number) => boolean;
|
|
6
7
|
markRefForSave: (ref: PDFRef) => void;
|
|
7
8
|
markRefsForSave: (refs: PDFRef[]) => void;
|
|
8
9
|
markObjForSave: (obj: PDFObject) => void;
|
|
9
10
|
markObjsForSave: (objs: PDFObject[]) => void;
|
|
11
|
+
markDeletedRef: (ref: PDFRef) => void;
|
|
12
|
+
markDeletedObj: (obj: PDFObject) => void;
|
|
13
|
+
deletedRef: (index: number) => PDFRef | null;
|
|
10
14
|
}
|
|
11
15
|
//# sourceMappingURL=DocumentSnapshot.d.ts.map
|