pdf-lite 1.0.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/.commitlintrc.cjs +25 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/workflows/docs.yaml +93 -0
- package/.github/workflows/prepare-release.yaml +79 -0
- package/.github/workflows/release.yaml +80 -0
- package/.github/workflows/test.yaml +35 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc +4 -0
- package/CONTRIBUTING.md +109 -0
- package/EXAMPLES.md +1515 -0
- package/LICENSE +21 -0
- package/README.md +285 -0
- package/examples/001-create-pdf.ts +112 -0
- package/examples/002-create-encrypted-pdf.ts +121 -0
- package/examples/003-sign-pdf.ts +347 -0
- package/examples/004-incremental-update.ts +206 -0
- package/examples/005-modify-acroform.ts +374 -0
- package/examples/006-tokeniser-example.ts +131 -0
- package/examples/007-decoder-example.ts +197 -0
- package/package.json +72 -0
- package/packages/pdf-lite/README.md +3 -0
- package/packages/pdf-lite/package.json +68 -0
- package/packages/pdf-lite/scripts/create-encryption-tests.sh +41 -0
- package/packages/pdf-lite/scripts/gen-signing-keys.sh +290 -0
- package/packages/pdf-lite/scripts/generate-all-signing-keys.sh +70 -0
- package/packages/pdf-lite/src/core/decoder.ts +454 -0
- package/packages/pdf-lite/src/core/generators.ts +128 -0
- package/packages/pdf-lite/src/core/incremental-parser.ts +221 -0
- package/packages/pdf-lite/src/core/index.ts +2 -0
- package/packages/pdf-lite/src/core/objects/pdf-array.ts +54 -0
- package/packages/pdf-lite/src/core/objects/pdf-boolean.ts +19 -0
- package/packages/pdf-lite/src/core/objects/pdf-comment.ts +50 -0
- package/packages/pdf-lite/src/core/objects/pdf-date.ts +74 -0
- package/packages/pdf-lite/src/core/objects/pdf-dictionary.ts +171 -0
- package/packages/pdf-lite/src/core/objects/pdf-hexadecimal.ts +54 -0
- package/packages/pdf-lite/src/core/objects/pdf-indirect-object.ts +137 -0
- package/packages/pdf-lite/src/core/objects/pdf-name.ts +19 -0
- package/packages/pdf-lite/src/core/objects/pdf-null.ts +15 -0
- package/packages/pdf-lite/src/core/objects/pdf-number.ts +98 -0
- package/packages/pdf-lite/src/core/objects/pdf-object-reference.ts +30 -0
- package/packages/pdf-lite/src/core/objects/pdf-object.ts +107 -0
- package/packages/pdf-lite/src/core/objects/pdf-start-xref.ts +39 -0
- package/packages/pdf-lite/src/core/objects/pdf-stream.ts +687 -0
- package/packages/pdf-lite/src/core/objects/pdf-string.ts +38 -0
- package/packages/pdf-lite/src/core/objects/pdf-trailer.ts +57 -0
- package/packages/pdf-lite/src/core/objects/pdf-xref-table.ts +264 -0
- package/packages/pdf-lite/src/core/parser.ts +22 -0
- package/packages/pdf-lite/src/core/ref.ts +102 -0
- package/packages/pdf-lite/src/core/serializer.ts +68 -0
- package/packages/pdf-lite/src/core/streams/object-stream.ts +20 -0
- package/packages/pdf-lite/src/core/tokeniser.ts +687 -0
- package/packages/pdf-lite/src/core/tokens/boolean-token.ts +20 -0
- package/packages/pdf-lite/src/core/tokens/byte-offset-token.ts +20 -0
- package/packages/pdf-lite/src/core/tokens/comment-token.ts +32 -0
- package/packages/pdf-lite/src/core/tokens/end-array-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/end-dictionary-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/end-object-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/end-stream-token.ts +11 -0
- package/packages/pdf-lite/src/core/tokens/hexadecimal-token.ts +22 -0
- package/packages/pdf-lite/src/core/tokens/name-token.ts +19 -0
- package/packages/pdf-lite/src/core/tokens/null-token.ts +9 -0
- package/packages/pdf-lite/src/core/tokens/number-token.ts +164 -0
- package/packages/pdf-lite/src/core/tokens/object-reference-token.ts +24 -0
- package/packages/pdf-lite/src/core/tokens/start-array-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/start-dictionary-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/start-object-token.ts +28 -0
- package/packages/pdf-lite/src/core/tokens/start-stream-token.ts +52 -0
- package/packages/pdf-lite/src/core/tokens/start-xref-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/stream-chunk-token.ts +8 -0
- package/packages/pdf-lite/src/core/tokens/string-token.ts +17 -0
- package/packages/pdf-lite/src/core/tokens/token.ts +43 -0
- package/packages/pdf-lite/src/core/tokens/trailer-token.ts +12 -0
- package/packages/pdf-lite/src/core/tokens/whitespace-token.ts +43 -0
- package/packages/pdf-lite/src/core/tokens/xref-table-entry-token.ts +65 -0
- package/packages/pdf-lite/src/core/tokens/xref-table-section-start-token.ts +31 -0
- package/packages/pdf-lite/src/core/tokens/xref-table-start-token.ts +13 -0
- package/packages/pdf-lite/src/crypto/ciphers/aes128.ts +63 -0
- package/packages/pdf-lite/src/crypto/ciphers/aes256.ts +50 -0
- package/packages/pdf-lite/src/crypto/ciphers/rc4.ts +82 -0
- package/packages/pdf-lite/src/crypto/constants.ts +10 -0
- package/packages/pdf-lite/src/crypto/key-derivation/key-derivation-aes256.ts +213 -0
- package/packages/pdf-lite/src/crypto/key-derivation/key-derivation.ts +122 -0
- package/packages/pdf-lite/src/crypto/key-gen/key-gen-aes256.ts +79 -0
- package/packages/pdf-lite/src/crypto/key-gen/key-gen-rc4-128.ts +190 -0
- package/packages/pdf-lite/src/crypto/key-gen/key-gen-rc4-40.ts +129 -0
- package/packages/pdf-lite/src/crypto/types.ts +6 -0
- package/packages/pdf-lite/src/crypto/utils.ts +81 -0
- package/packages/pdf-lite/src/filters/ascii85.ts +128 -0
- package/packages/pdf-lite/src/filters/asciihex.ts +55 -0
- package/packages/pdf-lite/src/filters/flate.ts +39 -0
- package/packages/pdf-lite/src/filters/lzw.ts +144 -0
- package/packages/pdf-lite/src/filters/pass-through.ts +37 -0
- package/packages/pdf-lite/src/filters/runlength.ts +92 -0
- package/packages/pdf-lite/src/filters/types.ts +21 -0
- package/packages/pdf-lite/src/index.ts +4 -0
- package/packages/pdf-lite/src/pdf/errors.ts +5 -0
- package/packages/pdf-lite/src/pdf/index.ts +4 -0
- package/packages/pdf-lite/src/pdf/pdf-document.ts +924 -0
- package/packages/pdf-lite/src/pdf/pdf-reader.ts +57 -0
- package/packages/pdf-lite/src/pdf/pdf-revision.ts +234 -0
- package/packages/pdf-lite/src/pdf/pdf-xref-lookup.ts +527 -0
- package/packages/pdf-lite/src/security/crypt-filters/aesv2.ts +58 -0
- package/packages/pdf-lite/src/security/crypt-filters/aesv3.ts +56 -0
- package/packages/pdf-lite/src/security/crypt-filters/base.ts +140 -0
- package/packages/pdf-lite/src/security/crypt-filters/identity.ts +40 -0
- package/packages/pdf-lite/src/security/crypt-filters/v2.ts +59 -0
- package/packages/pdf-lite/src/security/handlers/base.ts +625 -0
- package/packages/pdf-lite/src/security/handlers/pubSec.ts +413 -0
- package/packages/pdf-lite/src/security/handlers/utils.ts +304 -0
- package/packages/pdf-lite/src/security/handlers/v1.ts +225 -0
- package/packages/pdf-lite/src/security/handlers/v2.ts +128 -0
- package/packages/pdf-lite/src/security/handlers/v4.ts +379 -0
- package/packages/pdf-lite/src/security/handlers/v5.ts +298 -0
- package/packages/pdf-lite/src/security/types.ts +158 -0
- package/packages/pdf-lite/src/signing/document-security-store.ts +224 -0
- package/packages/pdf-lite/src/signing/index.ts +3 -0
- package/packages/pdf-lite/src/signing/signatures/adbe-pkcs7-detached.ts +154 -0
- package/packages/pdf-lite/src/signing/signatures/adbe-pkcs7-sha1.ts +161 -0
- package/packages/pdf-lite/src/signing/signatures/adbe-x509-rsa-sha1.ts +106 -0
- package/packages/pdf-lite/src/signing/signatures/base.ts +229 -0
- package/packages/pdf-lite/src/signing/signatures/etsi-cades-detached.ts +229 -0
- package/packages/pdf-lite/src/signing/signatures/etsi-rfc3161.ts +92 -0
- package/packages/pdf-lite/src/signing/signatures/index.ts +6 -0
- package/packages/pdf-lite/src/signing/signer.ts +120 -0
- package/packages/pdf-lite/src/signing/types.ts +86 -0
- package/packages/pdf-lite/src/signing/utils.ts +71 -0
- package/packages/pdf-lite/src/types.ts +44 -0
- package/packages/pdf-lite/src/utils/IterableReadableStream.ts +30 -0
- package/packages/pdf-lite/src/utils/algos.ts +446 -0
- package/packages/pdf-lite/src/utils/assert.ts +42 -0
- package/packages/pdf-lite/src/utils/bytesToHex.ts +18 -0
- package/packages/pdf-lite/src/utils/bytesToHexBytes.ts +27 -0
- package/packages/pdf-lite/src/utils/bytesToString.ts +17 -0
- package/packages/pdf-lite/src/utils/concatUint8Arrays.ts +26 -0
- package/packages/pdf-lite/src/utils/escapeString.ts +49 -0
- package/packages/pdf-lite/src/utils/hexBytesToBytes.ts +22 -0
- package/packages/pdf-lite/src/utils/hexBytesToString.ts +21 -0
- package/packages/pdf-lite/src/utils/hexToBytes.ts +18 -0
- package/packages/pdf-lite/src/utils/padBytes.ts +25 -0
- package/packages/pdf-lite/src/utils/predictors.ts +332 -0
- package/packages/pdf-lite/src/utils/replaceInBuffer.ts +56 -0
- package/packages/pdf-lite/src/utils/stringToBytes.ts +22 -0
- package/packages/pdf-lite/src/utils/stringToHexBytes.ts +23 -0
- package/packages/pdf-lite/src/utils/unescapeString.ts +123 -0
- package/packages/pdf-lite/test/acceptance/__snapshots__/versions.node.test.ts.snap +60766 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.3/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-aes-128.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-aes-256.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-rc4-128.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-rc4-40.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.5/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.6/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.7/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-aes-128.pdf +43 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-aes-256.pdf +43 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-rc4-128.pdf +43 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-rc4-40.pdf +44 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic.pdf +79 -0
- package/packages/pdf-lite/test/acceptance/versions.node.test.ts +41 -0
- package/packages/pdf-lite/test/unit/__snapshots__/decoder.node.test.ts.snap +86947 -0
- package/packages/pdf-lite/test/unit/__snapshots__/tokeniser.node.test.ts.snap +131829 -0
- package/packages/pdf-lite/test/unit/ciphers.test.ts +61 -0
- package/packages/pdf-lite/test/unit/decoder.node.test.ts +21 -0
- package/packages/pdf-lite/test/unit/decoder.test.ts +567 -0
- package/packages/pdf-lite/test/unit/filters.test.ts +67 -0
- package/packages/pdf-lite/test/unit/fixtures/basic.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-aes-128.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-aes-256.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-rc4-128.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-rc4-40.pdf +43 -0
- package/packages/pdf-lite/test/unit/fixtures/protectedAdobeLivecycle.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/rsa-2048/index.ts +187 -0
- package/packages/pdf-lite/test/unit/fixtures/template.pdf +0 -0
- package/packages/pdf-lite/test/unit/incremental-update.test.ts +0 -0
- package/packages/pdf-lite/test/unit/objects.test.ts +0 -0
- package/packages/pdf-lite/test/unit/pdf-document-signing.test.ts +0 -0
- package/packages/pdf-lite/test/unit/pdf-revision.test.ts +195 -0
- package/packages/pdf-lite/test/unit/pdf.browser.test.ts +0 -0
- package/packages/pdf-lite/test/unit/predictors.test.ts +226 -0
- package/packages/pdf-lite/test/unit/ref.test.ts +158 -0
- package/packages/pdf-lite/test/unit/security-handlers.test.ts +645 -0
- package/packages/pdf-lite/test/unit/serializer.test.ts +81 -0
- package/packages/pdf-lite/test/unit/signature-objects.test.ts +814 -0
- package/packages/pdf-lite/test/unit/string-escaping.test.ts +84 -0
- package/packages/pdf-lite/test/unit/tokeniser.node.test.ts +38 -0
- package/packages/pdf-lite/test/unit/tokeniser.test.ts +1213 -0
- package/packages/pdf-lite/test/unit/utils.test.ts +248 -0
- package/packages/pdf-lite/test/unit/xref-lookup.test.ts +72 -0
- package/packages/pdf-lite/tsconfig.json +4 -0
- package/packages/pdf-lite/tsconfig.prod.json +8 -0
- package/packages/pdf-lite/typedoc.json +14 -0
- package/packages/pdf-lite/vitest.config.ts +43 -0
- package/pnpm-workspace.yaml +2 -0
- package/renovate.json +34 -0
- package/scripts/build-examples.ts +30 -0
- package/scripts/bump-version.sh +56 -0
- package/scripts/gen-html-docs.sh +21 -0
- package/scripts/gen-md-docs.sh +15 -0
- package/scripts/prepare-release.sh +33 -0
- package/tsconfig.json +22 -0
- package/tsconfig.prod.json +12 -0
- package/typedoc.json +34 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PdfObject } from '../core/objects/pdf-object'
|
|
2
|
+
import { PdfObjectStream } from '../core/streams/object-stream'
|
|
3
|
+
import { ByteArray } from '../types'
|
|
4
|
+
import { PdfDocument } from './pdf-document'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A reader for parsing PDF data into PdfDocument instances.
|
|
8
|
+
* Processes streams of PDF objects and constructs documents from them.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Read PDF from file bytes
|
|
13
|
+
* const document = await PdfReader.fromBytes(fileBytes)
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export class PdfReader {
|
|
17
|
+
/** The stream of PDF objects to read from */
|
|
18
|
+
protected objectStream: AsyncIterable<PdfObject> | Iterable<PdfObject>
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new PdfReader instance.
|
|
22
|
+
*
|
|
23
|
+
* @param objectStream - An async or sync iterable of PDF objects
|
|
24
|
+
*/
|
|
25
|
+
constructor(objectStream: AsyncIterable<PdfObject> | Iterable<PdfObject>) {
|
|
26
|
+
this.objectStream = objectStream
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reads all objects from the stream and constructs a PdfDocument.
|
|
31
|
+
*
|
|
32
|
+
* @returns A promise that resolves to the parsed PdfDocument
|
|
33
|
+
*/
|
|
34
|
+
async read(): Promise<PdfDocument> {
|
|
35
|
+
const objects: PdfObject[] = []
|
|
36
|
+
|
|
37
|
+
for await (const obj of this.objectStream) {
|
|
38
|
+
objects.push(obj)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return PdfDocument.fromObjects(objects)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a PdfDocument directly from a byte stream.
|
|
46
|
+
* Convenience method that creates a reader internally.
|
|
47
|
+
*
|
|
48
|
+
* @param input - Async or sync iterable of byte arrays
|
|
49
|
+
* @returns A promise that resolves to the parsed PdfDocument
|
|
50
|
+
*/
|
|
51
|
+
static async fromBytes(
|
|
52
|
+
input: AsyncIterable<ByteArray> | Iterable<ByteArray>,
|
|
53
|
+
): Promise<PdfDocument> {
|
|
54
|
+
const reader = new PdfReader(new PdfObjectStream(input))
|
|
55
|
+
return reader.read()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { PdfDictionary } from '../core/objects/pdf-dictionary'
|
|
2
|
+
import { PdfIndirectObject } from '../core/objects/pdf-indirect-object'
|
|
3
|
+
import { PdfObject } from '../core/objects/pdf-object'
|
|
4
|
+
import { PdfTrailerEntries } from '../core/objects/pdf-trailer'
|
|
5
|
+
import { PdfToken } from '../core/tokens/token'
|
|
6
|
+
import { PdfWhitespaceToken } from '../core/tokens/whitespace-token'
|
|
7
|
+
import { PdfXrefLookup } from './pdf-xref-lookup'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Represents a single revision of a PDF document.
|
|
11
|
+
* PDF documents can have multiple revisions for incremental updates,
|
|
12
|
+
* where each revision contains its own set of objects and cross-reference table.
|
|
13
|
+
*/
|
|
14
|
+
export class PdfRevision extends PdfObject {
|
|
15
|
+
/** Objects contained in this revision */
|
|
16
|
+
objects: PdfObject[] = []
|
|
17
|
+
/** Cross-reference lookup table for this revision */
|
|
18
|
+
xref: PdfXrefLookup
|
|
19
|
+
/** Whether this revision is locked (cannot be modified) */
|
|
20
|
+
locked: boolean = false
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new PDF revision.
|
|
24
|
+
*
|
|
25
|
+
* @param options - Configuration options for the revision
|
|
26
|
+
* @param options.objects - Initial objects for this revision
|
|
27
|
+
* @param options.prev - Previous revision or xref lookup to link to
|
|
28
|
+
* @param options.locked - Whether the revision should be locked initially
|
|
29
|
+
*/
|
|
30
|
+
constructor(options?: {
|
|
31
|
+
objects?: PdfObject[]
|
|
32
|
+
prev?: PdfXrefLookup | PdfRevision
|
|
33
|
+
locked?: boolean
|
|
34
|
+
}) {
|
|
35
|
+
super()
|
|
36
|
+
this.modified = false
|
|
37
|
+
this.objects = options?.objects ?? []
|
|
38
|
+
|
|
39
|
+
this.xref = PdfXrefLookup.fromObjects(this.objects)
|
|
40
|
+
|
|
41
|
+
if (options?.prev) this.setPrev(options.prev)
|
|
42
|
+
if (!this.contains(this.xref.object))
|
|
43
|
+
this.addObject(...this.xref.toTrailerSection())
|
|
44
|
+
this.locked = options?.locked ?? false
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Links this revision to a previous revision's cross-reference table.
|
|
49
|
+
*
|
|
50
|
+
* @param xref - The previous revision's xref lookup or revision
|
|
51
|
+
*/
|
|
52
|
+
setPrev(xref: PdfXrefLookup | PdfRevision) {
|
|
53
|
+
xref = xref instanceof PdfRevision ? xref.xref : xref
|
|
54
|
+
this.xref.setPrev(xref)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Checks if an object reference exists in this revision.
|
|
59
|
+
*
|
|
60
|
+
* @param object - The object to check for
|
|
61
|
+
* @returns True if the exact object instance exists in this revision
|
|
62
|
+
*/
|
|
63
|
+
contains(object: PdfObject): boolean {
|
|
64
|
+
return this.objects.includes(object)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks if an equivalent object exists in this revision (by value equality).
|
|
69
|
+
*
|
|
70
|
+
* @param object - The object to check for
|
|
71
|
+
* @returns True if an equal object exists in this revision
|
|
72
|
+
*/
|
|
73
|
+
exists(object: PdfObject): boolean {
|
|
74
|
+
for (const obj of this.objects) {
|
|
75
|
+
if (obj.equals(object)) {
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Adds objects to the beginning of the revision's object list.
|
|
84
|
+
*
|
|
85
|
+
* @param objects - Objects to add at the beginning
|
|
86
|
+
*/
|
|
87
|
+
unshift(...objects: PdfObject[]): void {
|
|
88
|
+
for (const obj of objects.reverse()) {
|
|
89
|
+
this.objects.unshift(obj)
|
|
90
|
+
if (obj instanceof PdfIndirectObject) this.xref.addObject(obj)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Adds objects to the revision.
|
|
96
|
+
*
|
|
97
|
+
* @param objects - Objects to add to the revision
|
|
98
|
+
*/
|
|
99
|
+
addObject(...objects: PdfObject[]): void {
|
|
100
|
+
for (const obj of objects) {
|
|
101
|
+
this.addObjectAt(obj)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Adds an object at a specific position in the revision.
|
|
107
|
+
*
|
|
108
|
+
* @param object - The object to add
|
|
109
|
+
* @param index - Position to insert at (number) or object to insert before
|
|
110
|
+
* @throws Error if the revision is locked or index is out of bounds
|
|
111
|
+
*/
|
|
112
|
+
addObjectAt(object: PdfObject, index?: number | PdfObject): void {
|
|
113
|
+
if (this.locked) {
|
|
114
|
+
throw new Error('Cannot add object to locked PDF revision')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (index === undefined) {
|
|
118
|
+
index =
|
|
119
|
+
object instanceof PdfIndirectObject
|
|
120
|
+
? this.xref.object
|
|
121
|
+
: this.objects.length
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (typeof index !== 'number') {
|
|
125
|
+
index = this.objects.indexOf(index)
|
|
126
|
+
|
|
127
|
+
if (index === -1) {
|
|
128
|
+
index = this.objects.length
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (index < 0 || index > this.objects.length) {
|
|
133
|
+
throw new Error('Index out of bounds')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
this.objects.splice(index, 0, object)
|
|
137
|
+
this.sortObjects()
|
|
138
|
+
|
|
139
|
+
if (object instanceof PdfIndirectObject) {
|
|
140
|
+
this.xref.addObject(object)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.update()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Removes objects from the revision.
|
|
148
|
+
*
|
|
149
|
+
* @param objects - Objects to remove from the revision
|
|
150
|
+
* @throws Error if the revision is locked
|
|
151
|
+
*/
|
|
152
|
+
deleteObject(...objects: PdfObject[]): void {
|
|
153
|
+
if (this.locked) {
|
|
154
|
+
throw new Error('Cannot delete object from locked PDF revision')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (const object of objects) {
|
|
158
|
+
const index = this.objects.indexOf(object)
|
|
159
|
+
if (index === -1) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.modified = true
|
|
164
|
+
this.objects.splice(index, 1)
|
|
165
|
+
|
|
166
|
+
if (object instanceof PdfIndirectObject) {
|
|
167
|
+
this.xref.removeObject(object)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
isModified(): boolean {
|
|
173
|
+
return (
|
|
174
|
+
super.isModified() ||
|
|
175
|
+
this.xref.trailerDict.isModified() ||
|
|
176
|
+
this.objects.some((obj) => obj.isModified())
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Updates the revision by sorting objects and updating the xref table.
|
|
182
|
+
*/
|
|
183
|
+
update(): void {
|
|
184
|
+
if (this.locked) {
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
this.sortObjects()
|
|
188
|
+
this.xref.update()
|
|
189
|
+
this.modified = false
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Sorts objects by their insertion order.
|
|
194
|
+
* Indirect objects are placed before other objects.
|
|
195
|
+
*/
|
|
196
|
+
sortObjects(): void {
|
|
197
|
+
this.objects.sort((a, b) => {
|
|
198
|
+
if (
|
|
199
|
+
a instanceof PdfIndirectObject &&
|
|
200
|
+
b instanceof PdfIndirectObject
|
|
201
|
+
) {
|
|
202
|
+
return a.order() - b.order()
|
|
203
|
+
} else {
|
|
204
|
+
return 0
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Gets the trailer dictionary for this revision.
|
|
211
|
+
*
|
|
212
|
+
* @returns The trailer dictionary containing document metadata references
|
|
213
|
+
*/
|
|
214
|
+
get trailerDict(): PdfDictionary<PdfTrailerEntries> {
|
|
215
|
+
return this.xref.trailerDict
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Creates a deep copy of this revision.
|
|
220
|
+
*
|
|
221
|
+
* @returns A cloned PdfRevision instance
|
|
222
|
+
*/
|
|
223
|
+
clone(): this {
|
|
224
|
+
const clonedObjects = this.objects.map((obj) => obj.clone())
|
|
225
|
+
return new PdfRevision({ objects: clonedObjects }) as this
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
protected tokenize(): PdfToken[] {
|
|
229
|
+
return this.objects.flatMap((obj) => [
|
|
230
|
+
...obj.toTokens(),
|
|
231
|
+
PdfWhitespaceToken.NEWLINE,
|
|
232
|
+
])
|
|
233
|
+
}
|
|
234
|
+
}
|