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,144 @@
|
|
|
1
|
+
import { ByteArray } from '../types'
|
|
2
|
+
import { PdfFilter } from './types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates an LZW filter for encoding and decoding PDF stream data.
|
|
6
|
+
* LZW (Lempel-Ziv-Welch) is a lossless compression algorithm.
|
|
7
|
+
* This is a minimal implementation for PDF (12-bit, no early change, no predictor).
|
|
8
|
+
*
|
|
9
|
+
* @returns A PdfFilter object with encode and decode methods.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const filter = lzw()
|
|
14
|
+
* const compressed = filter.encode(rawData)
|
|
15
|
+
* const decompressed = filter.decode(compressed)
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function lzw(): PdfFilter {
|
|
19
|
+
return {
|
|
20
|
+
/**
|
|
21
|
+
* Compresses data using the LZW algorithm.
|
|
22
|
+
*
|
|
23
|
+
* @param data - The data to compress.
|
|
24
|
+
* @returns The LZW compressed data as a byte array.
|
|
25
|
+
*/
|
|
26
|
+
encode: (data: ByteArray) => {
|
|
27
|
+
// Minimal LZW encode for PDF (12-bit, no early change, no predictor)
|
|
28
|
+
const CLEAR = 256,
|
|
29
|
+
EOD = 257
|
|
30
|
+
let dict = new Map<string, number>()
|
|
31
|
+
for (let i = 0; i < 256; i++) dict.set(String.fromCharCode(i), i)
|
|
32
|
+
let codeSize = 9
|
|
33
|
+
let nextCode = 258
|
|
34
|
+
let out: number[] = [CLEAR]
|
|
35
|
+
let w = ''
|
|
36
|
+
for (let i = 0; i < data.length; i++) {
|
|
37
|
+
const c = String.fromCharCode(data[i])
|
|
38
|
+
const wc = w + c
|
|
39
|
+
if (dict.has(wc)) {
|
|
40
|
+
w = wc
|
|
41
|
+
} else {
|
|
42
|
+
out.push(dict.get(w)!)
|
|
43
|
+
if (nextCode < 4096) {
|
|
44
|
+
dict.set(wc, nextCode++)
|
|
45
|
+
if (nextCode === 1 << codeSize && codeSize < 12)
|
|
46
|
+
codeSize++
|
|
47
|
+
}
|
|
48
|
+
w = c
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (w) out.push(dict.get(w)!)
|
|
52
|
+
out.push(EOD)
|
|
53
|
+
// Bit packing
|
|
54
|
+
let bits = 0,
|
|
55
|
+
bitBuffer = 0
|
|
56
|
+
let result: number[] = []
|
|
57
|
+
codeSize = 9
|
|
58
|
+
nextCode = 258
|
|
59
|
+
for (let i = 0; i < out.length; i++) {
|
|
60
|
+
let code = out[i]
|
|
61
|
+
bitBuffer |= code << bits
|
|
62
|
+
bits += codeSize
|
|
63
|
+
while (bits >= 8) {
|
|
64
|
+
result.push(bitBuffer & 0xff)
|
|
65
|
+
bitBuffer >>= 8
|
|
66
|
+
bits -= 8
|
|
67
|
+
}
|
|
68
|
+
if (code === CLEAR) {
|
|
69
|
+
codeSize = 9
|
|
70
|
+
nextCode = 258
|
|
71
|
+
} else {
|
|
72
|
+
if (nextCode < 4096) {
|
|
73
|
+
nextCode++
|
|
74
|
+
if (nextCode === 1 << codeSize && codeSize < 12)
|
|
75
|
+
codeSize++
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (bits > 0) result.push(bitBuffer & 0xff)
|
|
80
|
+
return new Uint8Array(result)
|
|
81
|
+
},
|
|
82
|
+
/**
|
|
83
|
+
* Decompresses LZW compressed data.
|
|
84
|
+
*
|
|
85
|
+
* @param data - The LZW compressed data to decompress.
|
|
86
|
+
* @returns The decompressed data as a byte array.
|
|
87
|
+
*/
|
|
88
|
+
decode: (data: ByteArray) => {
|
|
89
|
+
// Simple LZW decode for PDF (12-bit, no early change)
|
|
90
|
+
// Adapted from public domain sources for educational use
|
|
91
|
+
let pos = 0
|
|
92
|
+
let bits = 0
|
|
93
|
+
let bitBuffer = 0
|
|
94
|
+
function readBits(n: number) {
|
|
95
|
+
while (bits < n) {
|
|
96
|
+
if (pos >= data.length) return null
|
|
97
|
+
bitBuffer |= data[pos++] << bits
|
|
98
|
+
bits += 8
|
|
99
|
+
}
|
|
100
|
+
const out = bitBuffer & ((1 << n) - 1)
|
|
101
|
+
bitBuffer >>= n
|
|
102
|
+
bits -= n
|
|
103
|
+
return out
|
|
104
|
+
}
|
|
105
|
+
const CLEAR = 256,
|
|
106
|
+
EOD = 257
|
|
107
|
+
let codeSize = 9
|
|
108
|
+
let dict: ByteArray[] = []
|
|
109
|
+
for (let i = 0; i < 256; i++) dict[i] = new Uint8Array([i])
|
|
110
|
+
dict[CLEAR] = undefined as any
|
|
111
|
+
dict[EOD] = undefined as any
|
|
112
|
+
let out: number[] = []
|
|
113
|
+
let prev: ByteArray | undefined
|
|
114
|
+
let code: number | null
|
|
115
|
+
while ((code = readBits(codeSize)) !== null) {
|
|
116
|
+
if (code === CLEAR) {
|
|
117
|
+
dict = []
|
|
118
|
+
for (let i = 0; i < 256; i++) dict[i] = new Uint8Array([i])
|
|
119
|
+
dict[CLEAR] = undefined as any
|
|
120
|
+
dict[EOD] = undefined as any
|
|
121
|
+
codeSize = 9
|
|
122
|
+
prev = undefined
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
if (code === EOD) break
|
|
126
|
+
let entry: ByteArray
|
|
127
|
+
if (dict[code]) {
|
|
128
|
+
entry = dict[code]
|
|
129
|
+
} else if (prev) {
|
|
130
|
+
entry = new Uint8Array([...prev, prev[0]])
|
|
131
|
+
} else {
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
134
|
+
out.push(...entry)
|
|
135
|
+
if (prev) {
|
|
136
|
+
dict.push(new Uint8Array([...prev, entry[0]]))
|
|
137
|
+
}
|
|
138
|
+
prev = entry
|
|
139
|
+
if (dict.length === 1 << codeSize && codeSize < 12) codeSize++
|
|
140
|
+
}
|
|
141
|
+
return new Uint8Array(out)
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ByteArray } from '../types.js'
|
|
2
|
+
import { PdfFilter } from './types.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a pass-through filter that performs no transformation.
|
|
6
|
+
* Returns data unchanged, useful for testing or as a placeholder filter.
|
|
7
|
+
*
|
|
8
|
+
* @returns A PdfFilter object with encode and decode methods that return data unchanged.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const filter = passthroughFilter()
|
|
13
|
+
* const result = filter.encode(data) // Returns data unchanged
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function passthroughFilter(): PdfFilter {
|
|
17
|
+
return {
|
|
18
|
+
/**
|
|
19
|
+
* Returns the data unchanged.
|
|
20
|
+
*
|
|
21
|
+
* @param data - The data to pass through.
|
|
22
|
+
* @returns The same data unchanged.
|
|
23
|
+
*/
|
|
24
|
+
decode: (data: ByteArray) => {
|
|
25
|
+
return data
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* Returns the data unchanged.
|
|
29
|
+
*
|
|
30
|
+
* @param data - The data to pass through.
|
|
31
|
+
* @returns The same data unchanged.
|
|
32
|
+
*/
|
|
33
|
+
encode: (data: ByteArray) => {
|
|
34
|
+
return data
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ByteArray } from '../types.js'
|
|
2
|
+
import { PdfFilter } from './types.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Run-Length filter for encoding and decoding PDF stream data.
|
|
6
|
+
* Run-Length encoding is a simple compression algorithm that replaces
|
|
7
|
+
* sequences of repeated bytes with a count and the byte value.
|
|
8
|
+
*
|
|
9
|
+
* @returns A PdfFilter object with encode and decode methods.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const filter = runLength()
|
|
14
|
+
* const compressed = filter.encode(rawData)
|
|
15
|
+
* const decompressed = filter.decode(compressed)
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function runLength(): PdfFilter {
|
|
19
|
+
return {
|
|
20
|
+
/**
|
|
21
|
+
* Compresses data using Run-Length encoding.
|
|
22
|
+
* Appends 128 as the end-of-data marker.
|
|
23
|
+
*
|
|
24
|
+
* @param data - The data to compress.
|
|
25
|
+
* @returns The Run-Length encoded data as a byte array.
|
|
26
|
+
*/
|
|
27
|
+
encode: (data: ByteArray) => {
|
|
28
|
+
const out: number[] = []
|
|
29
|
+
let i = 0
|
|
30
|
+
while (i < data.length) {
|
|
31
|
+
let runLength = 1
|
|
32
|
+
while (
|
|
33
|
+
runLength < 128 &&
|
|
34
|
+
i + runLength < data.length &&
|
|
35
|
+
data[i] === data[i + runLength]
|
|
36
|
+
) {
|
|
37
|
+
runLength++
|
|
38
|
+
}
|
|
39
|
+
if (runLength > 1) {
|
|
40
|
+
out.push(257 - runLength)
|
|
41
|
+
out.push(data[i])
|
|
42
|
+
i += runLength
|
|
43
|
+
} else {
|
|
44
|
+
let literalLength = 1
|
|
45
|
+
while (
|
|
46
|
+
literalLength < 128 &&
|
|
47
|
+
i + literalLength < data.length &&
|
|
48
|
+
(data[i + literalLength] !==
|
|
49
|
+
data[i + literalLength - 1] ||
|
|
50
|
+
literalLength === 1)
|
|
51
|
+
) {
|
|
52
|
+
literalLength++
|
|
53
|
+
}
|
|
54
|
+
out.push(literalLength - 1)
|
|
55
|
+
for (let j = 0; j < literalLength; ++j) {
|
|
56
|
+
out.push(data[i + j])
|
|
57
|
+
}
|
|
58
|
+
i += literalLength
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
out.push(128) // EOD
|
|
62
|
+
return new Uint8Array(out)
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* Decompresses Run-Length encoded data.
|
|
66
|
+
* Stops at the end-of-data marker (128).
|
|
67
|
+
*
|
|
68
|
+
* @param data - The Run-Length encoded data to decompress.
|
|
69
|
+
* @returns The decompressed data as a byte array.
|
|
70
|
+
*/
|
|
71
|
+
decode: (data: ByteArray) => {
|
|
72
|
+
const out: number[] = []
|
|
73
|
+
let i = 0
|
|
74
|
+
while (i < data.length) {
|
|
75
|
+
const len = data[i++]
|
|
76
|
+
if (len === 128) break // EOD
|
|
77
|
+
if (len < 128) {
|
|
78
|
+
for (let j = 0; j < len + 1; ++j) {
|
|
79
|
+
out.push(data[i++])
|
|
80
|
+
}
|
|
81
|
+
} else if (len > 128) {
|
|
82
|
+
const count = 257 - len
|
|
83
|
+
const value = data[i++]
|
|
84
|
+
for (let j = 0; j < count; ++j) {
|
|
85
|
+
out.push(value)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return new Uint8Array(out)
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ByteArray } from '../types'
|
|
2
|
+
|
|
3
|
+
export interface PdfFilter {
|
|
4
|
+
encode(data: ByteArray): ByteArray
|
|
5
|
+
decode(data: ByteArray): ByteArray
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const PDF_FILTER_TYPES = {
|
|
9
|
+
FlateDecode: 'FlateDecode',
|
|
10
|
+
Fl: 'Fl',
|
|
11
|
+
ASCIIHexDecode: 'ASCIIHexDecode',
|
|
12
|
+
ASCII85Decode: 'ASCII85Decode',
|
|
13
|
+
LZWDecode: 'LZWDecode',
|
|
14
|
+
RunLengthDecode: 'RunLengthDecode',
|
|
15
|
+
CCITTFaxDecode: 'CCITTFaxDecode',
|
|
16
|
+
DCTDecode: 'DCTDecode',
|
|
17
|
+
JPXDecode: 'JPXDecode',
|
|
18
|
+
Crypt: 'Crypt',
|
|
19
|
+
} as const
|
|
20
|
+
|
|
21
|
+
export type PdfStreamFilterType = keyof typeof PDF_FILTER_TYPES
|