@awacloud/pdf 0.0.0-stage → 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/CHANGELOG.md +609 -0
- package/LICENSE +661 -0
- package/NOTICE +77 -0
- package/README.md +363 -2
- package/dist/build/index.js +21 -0
- package/dist/build/pdf-full-rw.js +10972 -0
- package/dist/build/pdf-full-rw.meta.json +105 -0
- package/dist/build/pdf-full-rw.min.js +53 -0
- package/dist/build/pdf-full.js +6078 -0
- package/dist/build/pdf-full.meta.json +90 -0
- package/dist/build/pdf-full.min.js +32 -0
- package/dist/build/pdf-large-rw.js +10367 -0
- package/dist/build/pdf-large-rw.meta.json +99 -0
- package/dist/build/pdf-large-rw.min.js +53 -0
- package/dist/build/pdf-large.js +5473 -0
- package/dist/build/pdf-large.meta.json +84 -0
- package/dist/build/pdf-large.min.js +32 -0
- package/dist/build/pdf-legacy-rw.js +12402 -0
- package/dist/build/pdf-legacy-rw.meta.json +110 -0
- package/dist/build/pdf-legacy-rw.min.js +53 -0
- package/dist/build/pdf-legacy.js +7508 -0
- package/dist/build/pdf-legacy.meta.json +95 -0
- package/dist/build/pdf-legacy.min.js +32 -0
- package/dist/build/pdf-rw.js +7578 -0
- package/dist/build/pdf-rw.meta.json +77 -0
- package/dist/build/pdf-rw.min.js +53 -0
- package/dist/build/pdf.js +2684 -0
- package/dist/build/pdf.meta.json +62 -0
- package/dist/build/pdf.min.js +32 -0
- package/dist/standalone/pdf-full-rw.js +16798 -0
- package/dist/standalone/pdf-full-rw.meta.json +78 -0
- package/dist/standalone/pdf-full-rw.min.js +56 -0
- package/dist/standalone/pdf-full.js +11904 -0
- package/dist/standalone/pdf-full.meta.json +63 -0
- package/dist/standalone/pdf-full.min.js +35 -0
- package/dist/standalone/pdf-large-rw.js +16193 -0
- package/dist/standalone/pdf-large-rw.meta.json +72 -0
- package/dist/standalone/pdf-large-rw.min.js +56 -0
- package/dist/standalone/pdf-large.js +11299 -0
- package/dist/standalone/pdf-large.meta.json +57 -0
- package/dist/standalone/pdf-large.min.js +35 -0
- package/dist/standalone/pdf-legacy-rw.js +18228 -0
- package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
- package/dist/standalone/pdf-legacy-rw.min.js +56 -0
- package/dist/standalone/pdf-legacy.js +13334 -0
- package/dist/standalone/pdf-legacy.meta.json +68 -0
- package/dist/standalone/pdf-legacy.min.js +35 -0
- package/dist/standalone/pdf-rw.js +13404 -0
- package/dist/standalone/pdf-rw.meta.json +50 -0
- package/dist/standalone/pdf-rw.min.js +56 -0
- package/dist/standalone/pdf.js +8510 -0
- package/dist/standalone/pdf.meta.json +35 -0
- package/dist/standalone/pdf.min.js +35 -0
- package/docs/README.md +53 -0
- package/docs/api/README.md +38 -0
- package/docs/api/_shared/README.md +91 -0
- package/docs/api/action/README.md +29 -0
- package/docs/api/action/action.md +81 -0
- package/docs/api/action/goTo.md +66 -0
- package/docs/api/action/launch.md +58 -0
- package/docs/api/action/named.md +55 -0
- package/docs/api/action/uri.md +54 -0
- package/docs/api/annot/README.md +53 -0
- package/docs/api/annot/annot.md +114 -0
- package/docs/api/annot/fileAttach.md +53 -0
- package/docs/api/annot/freeText.md +68 -0
- package/docs/api/annot/ink.md +69 -0
- package/docs/api/annot/link.md +74 -0
- package/docs/api/annot/markup.md +83 -0
- package/docs/api/annot/popup.md +52 -0
- package/docs/api/annot/projection.md +56 -0
- package/docs/api/annot/redact.md +67 -0
- package/docs/api/annot/square.md +87 -0
- package/docs/api/annot/stamp.md +54 -0
- package/docs/api/annot/text.md +69 -0
- package/docs/api/annot/widget.md +69 -0
- package/docs/api/associatedFiles/README.md +9 -0
- package/docs/api/associatedFiles/associatedFiles.md +78 -0
- package/docs/api/bundles/README.md +68 -0
- package/docs/api/bundles/dist-matrix.md +165 -0
- package/docs/api/bundles/pdf-full.md +148 -0
- package/docs/api/bundles/pdf-large.md +144 -0
- package/docs/api/bundles/pdf-legacy.md +169 -0
- package/docs/api/content/README.md +29 -0
- package/docs/api/content/color.md +99 -0
- package/docs/api/content/graphics.md +114 -0
- package/docs/api/content/images.md +124 -0
- package/docs/api/content/ops.md +100 -0
- package/docs/api/content/stream.md +107 -0
- package/docs/api/content/text.md +98 -0
- package/docs/api/crypto/README.md +29 -0
- package/docs/api/crypto/aesGcm.md +72 -0
- package/docs/api/crypto/permissions.md +79 -0
- package/docs/api/crypto/security.md +98 -0
- package/docs/api/crypto/standardV4.md +104 -0
- package/docs/api/crypto/standardV5.md +84 -0
- package/docs/api/crypto/standardV6.md +93 -0
- package/docs/api/destination/README.md +9 -0
- package/docs/api/destination/destination.md +79 -0
- package/docs/api/document/README.md +29 -0
- package/docs/api/document/builder.md +281 -0
- package/docs/api/document/catalog.md +98 -0
- package/docs/api/document/document.md +187 -0
- package/docs/api/document/encryptedWriter.md +149 -0
- package/docs/api/document/incrementalWriter.md +148 -0
- package/docs/api/document/page.md +99 -0
- package/docs/api/document/pages.md +82 -0
- package/docs/api/document/resources.md +102 -0
- package/docs/api/document/writer.md +157 -0
- package/docs/api/document/xrefStreamWriter.md +122 -0
- package/docs/api/embedded/README.md +13 -0
- package/docs/api/embedded/collection.md +80 -0
- package/docs/api/embedded/embeddedFile.md +86 -0
- package/docs/api/embedded/fileSpec.md +87 -0
- package/docs/api/errors.md +110 -0
- package/docs/api/extra/3d-richmedia.md +76 -0
- package/docs/api/extra/README.md +99 -0
- package/docs/api/extra/annot-extended.md +71 -0
- package/docs/api/extra/associated-files.md +70 -0
- package/docs/api/extra/ccitt-fax-decoder.md +74 -0
- package/docs/api/extra/color-spaces-extended.md +72 -0
- package/docs/api/extra/content-ops-extended.md +82 -0
- package/docs/api/extra/document-parts.md +69 -0
- package/docs/api/extra/embedded-files-portfolio.md +87 -0
- package/docs/api/extra/font-cid-typed.md +77 -0
- package/docs/api/extra/font-color-tagging.md +76 -0
- package/docs/api/extra/form-actions-extended.md +75 -0
- package/docs/api/extra/info-dict-deprecated.md +72 -0
- package/docs/api/extra/jbig2-read.md +80 -0
- package/docs/api/extra/legacy-deprecated-annots.md +89 -0
- package/docs/api/extra/legacy-deprecated-filters.md +78 -0
- package/docs/api/extra/legacy-rc4-read.md +74 -0
- package/docs/api/extra/legacy-xfa-read.md +65 -0
- package/docs/api/extra/linearization-write.md +71 -0
- package/docs/api/extra/misc.md +93 -0
- package/docs/api/extra/optional-content-extended.md +83 -0
- package/docs/api/extra/pdf-a-output-intent.md +65 -0
- package/docs/api/extra/pdf-sandbox.md +76 -0
- package/docs/api/extra/pdf-ua-tagged.md +63 -0
- package/docs/api/extra/pdf-x-prepress.md +65 -0
- package/docs/api/extra/redaction-iso32005.md +65 -0
- package/docs/api/extra/shading-typed.md +73 -0
- package/docs/api/extra/sig-aes-gcm.md +69 -0
- package/docs/api/extra/sig-pades.md +103 -0
- package/docs/api/extra/tagged-pdf-typed.md +78 -0
- package/docs/api/extra/transparency-typed.md +74 -0
- package/docs/api/extra/well-tagged-pdf.md +61 -0
- package/docs/api/extra/xmp-extended.md +65 -0
- package/docs/api/font/README.md +25 -0
- package/docs/api/font/embed.md +157 -0
- package/docs/api/font/encoding.md +95 -0
- package/docs/api/font/font.md +97 -0
- package/docs/api/font/type3.md +89 -0
- package/docs/api/form/README.md +35 -0
- package/docs/api/form/acroform.md +88 -0
- package/docs/api/form/appearance.md +87 -0
- package/docs/api/form/button.md +97 -0
- package/docs/api/form/choice.md +96 -0
- package/docs/api/form/fieldTree.md +93 -0
- package/docs/api/form/signature.md +90 -0
- package/docs/api/form/text.md +88 -0
- package/docs/api/linearization/README.md +11 -0
- package/docs/api/linearization/linearization.md +81 -0
- package/docs/api/main.md +116 -0
- package/docs/api/metadata/README.md +10 -0
- package/docs/api/metadata/info.md +70 -0
- package/docs/api/metadata/xmp.md +62 -0
- package/docs/api/ocg/README.md +23 -0
- package/docs/api/ocg/config.md +95 -0
- package/docs/api/ocg/ocg.md +77 -0
- package/docs/api/outline/README.md +11 -0
- package/docs/api/outline/outline.md +107 -0
- package/docs/api/pdf.md +152 -0
- package/docs/api/prepress/README.md +10 -0
- package/docs/api/prepress/outputIntent.md +79 -0
- package/docs/api/prepress/pageBoundary.md +75 -0
- package/docs/api/sig/README.md +32 -0
- package/docs/api/sig/byteRange.md +120 -0
- package/docs/api/sig/certChain.md +84 -0
- package/docs/api/sig/dss.md +111 -0
- package/docs/api/sig/oids.md +76 -0
- package/docs/api/sig/sha1.md +72 -0
- package/docs/api/sig/sign.md +317 -0
- package/docs/api/sig/signature.md +178 -0
- package/docs/api/sig/timestamp.md +84 -0
- package/docs/api/syntax/README.md +29 -0
- package/docs/api/syntax/crossRefStream.md +115 -0
- package/docs/api/syntax/filters/README.md +50 -0
- package/docs/api/syntax/filters/ascii85.md +76 -0
- package/docs/api/syntax/filters/asciiHex.md +73 -0
- package/docs/api/syntax/filters/dispatch.md +125 -0
- package/docs/api/syntax/filters/flate.md +134 -0
- package/docs/api/syntax/filters/runLength.md +78 -0
- package/docs/api/syntax/objStream.md +88 -0
- package/docs/api/syntax/parser-obj.md +97 -0
- package/docs/api/syntax/parser.md +151 -0
- package/docs/api/syntax/serializer.md +109 -0
- package/docs/api/syntax/tokenizer.md +104 -0
- package/docs/api/syntax/trailer.md +85 -0
- package/docs/api/syntax/xref.md +139 -0
- package/docs/api/tagged/README.md +25 -0
- package/docs/api/tagged/classMap.md +67 -0
- package/docs/api/tagged/markedContent.md +62 -0
- package/docs/api/tagged/parentTree.md +67 -0
- package/docs/api/tagged/roleMap.md +67 -0
- package/docs/api/tagged/structElement.md +76 -0
- package/docs/api/tagged/structTree.md +75 -0
- package/docs/guide/coverage.md +113 -0
- package/docs/guide/crypto.md +121 -0
- package/docs/guide/extending.md +76 -0
- package/docs/guide/getting-started.md +75 -0
- package/docs/guide/legacy-1.7.md +42 -0
- package/docs/guide/pades-integration.md +579 -0
- package/docs/guide/read-pdf.md +89 -0
- package/package.json +97 -4
- package/src/_shared/index.js +179 -0
- package/src/action/action.js +119 -0
- package/src/action/goTo.js +89 -0
- package/src/action/launch.js +61 -0
- package/src/action/named.js +54 -0
- package/src/action/uri.js +51 -0
- package/src/annot/annot.js +212 -0
- package/src/annot/fileAttach.js +55 -0
- package/src/annot/freeText.js +82 -0
- package/src/annot/ink.js +77 -0
- package/src/annot/link.js +77 -0
- package/src/annot/markup.js +91 -0
- package/src/annot/popup.js +53 -0
- package/src/annot/projection.js +52 -0
- package/src/annot/redact.js +87 -0
- package/src/annot/square.js +132 -0
- package/src/annot/stamp.js +48 -0
- package/src/annot/text.js +54 -0
- package/src/annot/widget.js +61 -0
- package/src/associatedFiles/associatedFiles.js +86 -0
- package/src/bundles/pdf-full.js +91 -0
- package/src/bundles/pdf-large.js +81 -0
- package/src/bundles/pdf-legacy.js +107 -0
- package/src/content/color.js +114 -0
- package/src/content/graphics.js +192 -0
- package/src/content/images.js +160 -0
- package/src/content/ops.js +137 -0
- package/src/content/stream.js +154 -0
- package/src/content/text.js +125 -0
- package/src/crypto/aesGcm.js +123 -0
- package/src/crypto/permissions.js +112 -0
- package/src/crypto/security.js +327 -0
- package/src/crypto/standardV4.js +443 -0
- package/src/crypto/standardV5.js +306 -0
- package/src/crypto/standardV6.js +334 -0
- package/src/destination/destination.js +183 -0
- package/src/document/builder.js +618 -0
- package/src/document/catalog.js +100 -0
- package/src/document/document.js +472 -0
- package/src/document/encryptedWriter.js +554 -0
- package/src/document/incrementalWriter.js +514 -0
- package/src/document/page.js +131 -0
- package/src/document/pages.js +103 -0
- package/src/document/resources.js +146 -0
- package/src/document/writer.js +211 -0
- package/src/document/xrefStreamWriter.js +353 -0
- package/src/embedded/collection.js +102 -0
- package/src/embedded/embeddedFile.js +99 -0
- package/src/embedded/fileSpec.js +137 -0
- package/src/errors.js +78 -0
- package/src/extra/3d-richmedia.js +171 -0
- package/src/extra/annot-extended.js +200 -0
- package/src/extra/associated-files.js +131 -0
- package/src/extra/ccitt-fax-decoder.js +776 -0
- package/src/extra/color-spaces-extended.js +196 -0
- package/src/extra/content-ops-extended.js +153 -0
- package/src/extra/document-parts.js +149 -0
- package/src/extra/embedded-files-portfolio.js +234 -0
- package/src/extra/font-cid-typed.js +185 -0
- package/src/extra/font-color-tagging.js +144 -0
- package/src/extra/form-actions-extended.js +196 -0
- package/src/extra/info-dict-deprecated.js +137 -0
- package/src/extra/jbig2-read.js +169 -0
- package/src/extra/legacy-deprecated-annots.js +198 -0
- package/src/extra/legacy-deprecated-filters.js +167 -0
- package/src/extra/legacy-rc4-read.js +235 -0
- package/src/extra/legacy-xfa-read.js +104 -0
- package/src/extra/linearization-write.js +97 -0
- package/src/extra/misc.js +217 -0
- package/src/extra/optional-content-extended.js +142 -0
- package/src/extra/pdf-a-output-intent.js +112 -0
- package/src/extra/pdf-sandbox.js +88 -0
- package/src/extra/pdf-ua-tagged.js +116 -0
- package/src/extra/pdf-x-prepress.js +114 -0
- package/src/extra/redaction-iso32005.js +136 -0
- package/src/extra/shading-typed.js +222 -0
- package/src/extra/sig-aes-gcm.js +135 -0
- package/src/extra/sig-pades.js +242 -0
- package/src/extra/tagged-pdf-typed.js +203 -0
- package/src/extra/transparency-typed.js +135 -0
- package/src/extra/well-tagged-pdf.js +138 -0
- package/src/extra/xmp-extended.js +190 -0
- package/src/font/embed.js +480 -0
- package/src/font/encoding.js +92 -0
- package/src/font/font.js +101 -0
- package/src/font/type3.js +75 -0
- package/src/form/acroform.js +94 -0
- package/src/form/appearance.js +90 -0
- package/src/form/button.js +105 -0
- package/src/form/choice.js +152 -0
- package/src/form/fieldTree.js +120 -0
- package/src/form/signature.js +100 -0
- package/src/form/text.js +101 -0
- package/src/linearization/linearization.js +107 -0
- package/src/main.js +411 -0
- package/src/metadata/info.js +87 -0
- package/src/metadata/xmp.js +62 -0
- package/src/ocg/config.js +156 -0
- package/src/ocg/ocg.js +124 -0
- package/src/outline/outline.js +157 -0
- package/src/pdf.js +133 -0
- package/src/prepress/outputIntent.js +118 -0
- package/src/prepress/pageBoundary.js +108 -0
- package/src/sig/byteRange.js +306 -0
- package/src/sig/certChain.js +247 -0
- package/src/sig/dss.js +317 -0
- package/src/sig/oids.js +157 -0
- package/src/sig/sha1.js +142 -0
- package/src/sig/sign.js +1899 -0
- package/src/sig/signature.js +1441 -0
- package/src/sig/timestamp.js +236 -0
- package/src/syntax/crossRefStream.js +133 -0
- package/src/syntax/filters/ascii85.js +122 -0
- package/src/syntax/filters/asciiHex.js +83 -0
- package/src/syntax/filters/dispatch.js +176 -0
- package/src/syntax/filters/flate.js +316 -0
- package/src/syntax/filters/runLength.js +96 -0
- package/src/syntax/objStream.js +99 -0
- package/src/syntax/parser-obj.js +52 -0
- package/src/syntax/parser.js +321 -0
- package/src/syntax/serializer.js +221 -0
- package/src/syntax/tokenizer.js +290 -0
- package/src/syntax/trailer.js +76 -0
- package/src/syntax/xref.js +341 -0
- package/src/tagged/classMap.js +81 -0
- package/src/tagged/markedContent.js +123 -0
- package/src/tagged/parentTree.js +126 -0
- package/src/tagged/roleMap.js +107 -0
- package/src/tagged/structElement.js +138 -0
- package/src/tagged/structTree.js +94 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
module: pdfEncryptedWriter
|
|
3
|
+
category: pdf/document
|
|
4
|
+
dependencies: [pdfErrors, pdfWriter, pdfStandardV5, pdfStandardV6, pdfStandardV4, pdfAesGcm]
|
|
5
|
+
returns: object
|
|
6
|
+
worker-safe: true
|
|
7
|
+
status: complete
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# pdfEncryptedWriter
|
|
11
|
+
|
|
12
|
+
> Emits an `/Encrypt`-protected PDF — wraps `pdfWriter` with the Standard Security Handlers.
|
|
13
|
+
|
|
14
|
+
**Module** `pdfEncryptedWriter` | **Source** `packages/front/office/pdf/src/document/encryptedWriter.js` | **Deps** `pdfErrors`, `pdfWriter`, `pdfStandardV5`, `pdfStandardV6`, `pdfStandardV4`, `pdfAesGcm` | **Worker-safe** yes
|
|
15
|
+
|
|
16
|
+
Encrypts a from-scratch indirect-object graph (same shape as `pdfWriter`'s
|
|
17
|
+
`indirects`) and emits the result with an `/Encrypt` dictionary. Supports:
|
|
18
|
+
|
|
19
|
+
- **V=4, R=4** (PDF 1.6) — method `'AESV2'` (AES-128-CBC, default) or `'V2'`
|
|
20
|
+
(RC4-128), delegated to `pdfStandardV4`.
|
|
21
|
+
- **V=5, R=5** (historical AES-256, Adobe Extension Level 3) — delegated to `pdfStandardV5`.
|
|
22
|
+
- **V=5, R=6** (ISO 32000-2:2020 hardening) — delegated to `pdfStandardV6`. Method
|
|
23
|
+
`'AESV3'` (AES-256-CBC, default) or `'AESV4'` (AES-256-GCM, ISO TS 32003 — requires `pdfAesGcm`).
|
|
24
|
+
|
|
25
|
+
An optional distinct cipher for `/Type /EmbeddedFile` streams (`/EFF`, ISO
|
|
26
|
+
32000-1 §7.6.5) is selected via `opts.encrypt.effMethod`, validated against
|
|
27
|
+
the same (version, method) rules as the main `method`. Every `string` and
|
|
28
|
+
`stream.raw` payload in the indirect graph is walked and encrypted in place
|
|
29
|
+
(fresh IV per object) before the `/Encrypt` indirect is appended and the
|
|
30
|
+
trailer patched.
|
|
31
|
+
|
|
32
|
+
## Resolve
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
const ew = runtime.resolve('pdfEncryptedWriter');
|
|
36
|
+
// Returns: { writeEncryptedDocument }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
| Method | Signature | Returns |
|
|
42
|
+
|--------|-----------|---------|
|
|
43
|
+
| `writeEncryptedDocument` | `(opts: EncWriteOpts) => EncWriteResult` | Encrypted PDF bytes plus the derived crypto material. |
|
|
44
|
+
|
|
45
|
+
### `EncWriteOpts`
|
|
46
|
+
|
|
47
|
+
Mirrors `pdfWriter`'s `WriteOpts` (`indirects`, `root`, `info?`, `id?`, `version?`) plus:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
{
|
|
51
|
+
encrypt: {
|
|
52
|
+
version: 4 | 5,
|
|
53
|
+
revision: 4 | 5 | 6,
|
|
54
|
+
method?: 'AESV2' | 'V2' | 'AESV3' | 'AESV4', // default per version
|
|
55
|
+
effMethod?: 'AESV2' | 'V2' | 'AESV3' | 'AESV4', // optional, /Type /EmbeddedFile only
|
|
56
|
+
keyBits?: number, // default 128 (V4) / 256 (V5)
|
|
57
|
+
ownerPassword?: string | Uint8Array,
|
|
58
|
+
userPassword?: string | Uint8Array,
|
|
59
|
+
permissions?: number, // /P bitmask (Table 24)
|
|
60
|
+
encryptMetadata?: boolean, // default true
|
|
61
|
+
randomBytes?: (n: number) => Uint8Array // default globalThis.crypto.getRandomValues
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`randomBytes` supplies every key, salt and IV the writer draws. When it is
|
|
67
|
+
omitted the writer uses `globalThis.crypto.getRandomValues`, read at call
|
|
68
|
+
time; when neither exists the call throws `pdf/crypto/enc-writer/no-random`
|
|
69
|
+
before producing any output. There is no non-cryptographic fallback.
|
|
70
|
+
|
|
71
|
+
### `EncWriteResult`
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
{
|
|
75
|
+
bytes: Uint8Array, encryptObjNum: number,
|
|
76
|
+
fek: Uint8Array, id: [Uint8Array, Uint8Array],
|
|
77
|
+
O, U, OE?, UE?, Perms?: Uint8Array,
|
|
78
|
+
version, revision, method, effMethod
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Examples
|
|
83
|
+
|
|
84
|
+
### V=5 R=6, AES-256-CBC, deterministic (test) randomness
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
const ew = runtime.resolve('pdfEncryptedWriter');
|
|
88
|
+
const out = ew.writeEncryptedDocument({
|
|
89
|
+
indirects, root: { num: 1, gen: 0 },
|
|
90
|
+
encrypt: {
|
|
91
|
+
version: 5, revision: 6,
|
|
92
|
+
ownerPassword: 'owner', userPassword: 'user',
|
|
93
|
+
permissions: -4,
|
|
94
|
+
randomBytes: makeDeterministicRand(1) // test-only PRNG
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
out.bytes; // encrypted PDF, ready to write to disk
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### V=4 R=4, legacy RC4-128
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
const out = ew.writeEncryptedDocument({
|
|
104
|
+
indirects, root: { num: 1, gen: 0 },
|
|
105
|
+
encrypt: { version: 4, revision: 4, method: 'V2', userPassword: 'user' }
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Distinct cipher for embedded-file streams (`/EFF`)
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
const out = ew.writeEncryptedDocument({
|
|
113
|
+
indirects, root: { num: 1, gen: 0 },
|
|
114
|
+
encrypt: {
|
|
115
|
+
version: 5, revision: 6, method: 'AESV3',
|
|
116
|
+
effMethod: 'AESV4', // embedded files get AES-GCM, everything else AES-CBC
|
|
117
|
+
userPassword: 'user'
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Recovering the FEK to decrypt
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
const v6 = runtime.resolve('pdfStandardV6');
|
|
126
|
+
const r = v6.tryPassword(typedEncryptDict, 'user', false);
|
|
127
|
+
r.fileEncryptionKey; // === out.fek, when the password matches
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Errors
|
|
131
|
+
|
|
132
|
+
| Code | Class | When |
|
|
133
|
+
|------|-------|------|
|
|
134
|
+
| `pdf/crypto/enc-writer/missing-writer` | `EncryptionError` | Constructed without a `pdfWriter.writeDocument` function (module wiring). |
|
|
135
|
+
| `pdf/crypto/enc-writer/unsupported-version` | `EncryptionError` | `(version, revision)` outside `{4,4}`, `{5,5}`, `{5,6}`. |
|
|
136
|
+
| `pdf/crypto/enc-writer/missing-v4` | `EncryptionError` | `version: 4` requested but `pdfStandardV4` not supplied. |
|
|
137
|
+
| `pdf/crypto/enc-writer/bad-input` | `RenderError` | `opts` missing or not an object. |
|
|
138
|
+
| `pdf/crypto/enc-writer/no-encrypt` | `RenderError` | `opts.encrypt` missing. |
|
|
139
|
+
| `pdf/crypto/enc-writer/bad-method` | `RenderError` | `method` incompatible with `version` (V=4 wants AESV2/V2, V=5 wants AESV3/AESV4). |
|
|
140
|
+
| `pdf/crypto/enc-writer/missing-gcm` | `EncryptionError` | `method` or `effMethod` is `'AESV4'` but `pdfAesGcm` not supplied. |
|
|
141
|
+
| `pdf/crypto/enc-writer/bad-eff-method` | `RenderError` | `effMethod` incompatible with `version`. |
|
|
142
|
+
| `pdf/crypto/enc-writer/no-random` | `EncryptionError` | No `randomBytes` and no `globalThis.crypto.getRandomValues`. |
|
|
143
|
+
| `pdf/crypto/enc-writer/no-trailer` / `no-trailer-close` | `RenderError` | Internal: the base `writeDocument` output didn't contain a patchable trailer (should not occur in practice). |
|
|
144
|
+
|
|
145
|
+
## See also
|
|
146
|
+
|
|
147
|
+
- [`pdfWriter`](./writer.md) — the base emitter this wraps.
|
|
148
|
+
- [`pdfStandardV4`](../crypto/standardV4.md) · [`pdfStandardV5`](../crypto/standardV5.md) · [`pdfStandardV6`](../crypto/standardV6.md) · [`pdfAesGcm`](../crypto/aesGcm.md)
|
|
149
|
+
- [`pdfSecurity`](../crypto/security.md) — the read-side dispatcher.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
module: pdfIncrementalWriter
|
|
3
|
+
category: pdf/document
|
|
4
|
+
dependencies: [pdfErrors, pdfSerializer, pdfTokenizer, pdfParser, pdfXref, pdfTrailer]
|
|
5
|
+
returns: object
|
|
6
|
+
worker-safe: true
|
|
7
|
+
status: complete
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# pdfIncrementalWriter
|
|
11
|
+
|
|
12
|
+
> Append-only incremental update — ISO 32000-2 §7.5.6.
|
|
13
|
+
|
|
14
|
+
**Module** `pdfIncrementalWriter` | **Source** `packages/front/office/pdf/src/document/incrementalWriter.js` | **Deps** `pdfErrors`, `pdfSerializer`, `pdfTokenizer`, `pdfParser`, `pdfXref`, `pdfTrailer` | **Worker-safe** yes
|
|
15
|
+
|
|
16
|
+
`appendIncremental(pdfBytes, opts)` produces a new PDF that carries the
|
|
17
|
+
original bytes **verbatim**, followed by an incremental-update section:
|
|
18
|
+
`originalBytes ‖ newObjects ‖ xref ‖ trailer (with /Prev) ‖ %%EOF`. It locates
|
|
19
|
+
the previous `startxref`/trailer to chain `/Prev` and carry over `/Root`,
|
|
20
|
+
`/Info`, `/Size`, `/ID` unless the caller overrides them, then emits a fresh
|
|
21
|
+
cross-reference section covering only the newly-added object numbers (one
|
|
22
|
+
subsection per contiguous run — object 0's free-list head is always
|
|
23
|
+
re-emitted), in the form the section-selection rule below picks. A reader that follows the `/Prev` chain (e.g. `pdfDocument`)
|
|
24
|
+
sees the new entries win over older ones automatically. This is the
|
|
25
|
+
non-destructive counterpart of a full re-emit: existing objects are never
|
|
26
|
+
patched in place, only appended to — the mechanism behind PAdES levels
|
|
27
|
+
T/LT/LTA (`pdfSign`) appending DSS/DocTimeStamp updates.
|
|
28
|
+
|
|
29
|
+
Scope: no ObjStm grouping; hybrid-reference bases are refused (below).
|
|
30
|
+
|
|
31
|
+
## Section forms and the selection rule
|
|
32
|
+
|
|
33
|
+
The update's cross-reference section takes the form of the base's **newest**
|
|
34
|
+
section, the one the final `startxref` designates:
|
|
35
|
+
|
|
36
|
+
| Newest base section | Update written | Trailer keys come from |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Classical `xref` table | Classical table + `trailer` dict, `/Prev` = the base's `startxref` offset. **Byte-identical** to the output of earlier versions, which wrote only this form. | The newest trailer dict alone. |
|
|
39
|
+
| `/Type /XRef` stream (§7.5.8) | One uncompressed `/Type /XRef` stream object (no `/Filter`), carrying `/W`, `/Index`, `/Size`, `/Prev`, `/Root` and, when known, `/Info` and `/ID`. No `trailer` keyword. The stream takes object number `max(size, prevSize, newMaxNum + 1)`, and the written `/Size` is one more. | The newest-first merge of every section's dict in the `/Prev` chain, as [`pdfDocument`](./document.md) types it. So a linearized file whose `/Root` sits in only one of its two xref streams still resolves `/Root`. |
|
|
40
|
+
| Hybrid-reference file: a classical trailer carrying `/XRefStm`, anywhere in the chain | **Refused**, `pdf/incremental/hybrid-base`. | — |
|
|
41
|
+
| Neither a table nor an xref stream | **Refused**, `pdf/incremental/unsupported-base`. | — |
|
|
42
|
+
|
|
43
|
+
Hybrid-reference bases are refused on purpose. A hybrid file carries two
|
|
44
|
+
cross-reference forms, so two conforming readers can resolve different
|
|
45
|
+
objects in it, and an update over it could read differently from viewer to
|
|
46
|
+
viewer. The refusal is reversible: support can be added once a real hybrid
|
|
47
|
+
file is available to choose and test a form against.
|
|
48
|
+
|
|
49
|
+
The emitted stream is read back by this library's own reader: an update over
|
|
50
|
+
a stream base re-reads with both the base objects and the appended ones
|
|
51
|
+
reachable (`tests/real-shapes.integration.test.js`).
|
|
52
|
+
|
|
53
|
+
## Resolve
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
const iw = runtime.resolve('pdfIncrementalWriter');
|
|
57
|
+
// Returns: { appendIncremental, appendIncrementalWithOffsets, readBaseTrailer }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
| Method | Signature | Returns |
|
|
63
|
+
|--------|-----------|---------|
|
|
64
|
+
| `appendIncremental` | `(pdfBytes: Uint8Array, opts: AppendOpts) => Uint8Array` | The original bytes plus one incremental-update section. |
|
|
65
|
+
| `appendIncrementalWithOffsets` | `(pdfBytes: Uint8Array, opts: AppendOpts) => { bytes, offsets, xrefOffset }` | Same as `appendIncremental`: same options, same validation and refusals, and `bytes` is byte-identical to its return value. `offsets` is a `Map<num, byteOffset>` giving where each update's `num gen obj` header starts in `bytes`. `xrefOffset` is where the update's cross-reference section (table or stream object) starts, which is the offset the new `startxref` records. |
|
|
66
|
+
| `readBaseTrailer` | `(pdfBytes: Uint8Array) => { form, xrefOffset, trailer }` | The trailer an update over `pdfBytes` starts from. Nothing is written. `form` is `'table'` or `'stream'` (the newest section's form). `trailer` is the typed newest-first merge of every section's dict, as `pdfDocument` types it, for classical bases too. It is `null` when no section supplies a usable `/Size` and `/Root`. The base is vetted as `appendIncremental` vets it, so a hybrid-reference base throws `pdf/incremental/hybrid-base` and a `startxref` that designates neither form throws `pdf/incremental/unsupported-base`. |
|
|
67
|
+
|
|
68
|
+
`appendIncrementalWithOffsets` and `readBaseTrailer` were added for
|
|
69
|
+
[`pdfSign`](../sig/sign.md). The signer reads the merged `/Size`
|
|
70
|
+
to number its signature object. It then patches the fixed-width `/ByteRange`
|
|
71
|
+
placeholder inside that object, found from its offset, without changing the
|
|
72
|
+
byte length. Every offset recorded in the cross-reference section therefore
|
|
73
|
+
stays valid.
|
|
74
|
+
|
|
75
|
+
### `AppendOpts`
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
{
|
|
79
|
+
updates: [ { num, gen?, value }, … ], // required — num >= 1
|
|
80
|
+
root?: { num, gen }, // defaults to the previous /Root
|
|
81
|
+
info?: { num, gen }, // defaults to the previous /Info
|
|
82
|
+
id?: [ Uint8Array, Uint8Array ], // defaults to the previous /ID
|
|
83
|
+
size?: number, // defaults to max(prevSize, newMaxNum + 1)
|
|
84
|
+
encrypt?: { num, gen } // the base's /Encrypt, repeated in the update; never defaulted
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`opts.root` is mandatory only when no section of the base supplies a usable
|
|
89
|
+
`/Root` (and `/Size`) — on a classical base, when the newest trailer does not.
|
|
90
|
+
|
|
91
|
+
`opts.encrypt` is the base's `/Encrypt` reference (the `{ num, gen }` that
|
|
92
|
+
`readBaseTrailer(...).trailer.encrypt` reports). It is written as
|
|
93
|
+
`/Encrypt n g R` right after `/ID`, in the trailer or in the cross-reference
|
|
94
|
+
stream dictionary. An update over an encrypted document needs it to
|
|
95
|
+
conform (ISO 32000-2 §7.5.6): every trailer of an encrypted file carries
|
|
96
|
+
`/Encrypt`. It is not taken from the base by default. Without it the output
|
|
97
|
+
is byte-identical to what it was before the option existed. A direct
|
|
98
|
+
`/Encrypt` dictionary (a typed `{ type: 'dict' }`) is written as it is in a
|
|
99
|
+
classical trailer. Over a cross-reference stream base it is refused with
|
|
100
|
+
`pdf/xref/bad-stream-section`.
|
|
101
|
+
|
|
102
|
+
## Examples
|
|
103
|
+
|
|
104
|
+
### Append a new indirect object to an existing PDF
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
const iw = runtime.resolve('pdfIncrementalWriter');
|
|
108
|
+
const updated = iw.appendIncremental(originalBytes, {
|
|
109
|
+
updates: [
|
|
110
|
+
{ num: 42, gen: 0, value: { type: 'dict', entries: {
|
|
111
|
+
Type: { type: 'name', value: 'Example' }
|
|
112
|
+
} } }
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
// `updated` re-parses via pdfDocument.readDocument, following /Prev.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Update the Catalog to point at a new object (e.g. DSS)
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
const nextNum = 43;
|
|
122
|
+
const updated = iw.appendIncremental(signedBytes, {
|
|
123
|
+
updates: [
|
|
124
|
+
{ num: nextNum, gen: 0, value: dssDict },
|
|
125
|
+
{ num: 1, gen: 0, value: updatedCatalogDict } // re-defines obj 1
|
|
126
|
+
],
|
|
127
|
+
root: { num: 1, gen: 0 }
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Errors
|
|
132
|
+
|
|
133
|
+
| Code | Class | When |
|
|
134
|
+
|------|-------|------|
|
|
135
|
+
| `pdf/incremental/bad-input` | `RenderError` | `pdfBytes` is not a `Uint8Array` (every member). |
|
|
136
|
+
| `pdf/incremental/no-updates` | `RenderError` | `opts.updates` is not an array. |
|
|
137
|
+
| `pdf/incremental/bad-update` | `RenderError` | An update entry lacks a finite `num >= 1`. |
|
|
138
|
+
| `pdf/incremental/no-startxref` | `ParseError` | `pdfBytes` has no `startxref` — not a valid PDF. |
|
|
139
|
+
| `pdf/incremental/no-root` | `RenderError` | `opts.root` missing and no `/Root` can be read from the base (see the table above). |
|
|
140
|
+
| `pdf/incremental/hybrid-base` | `RenderError` | A classical section in the base's `/Prev` chain carries `/XRefStm` (hybrid-reference file). Nothing is written. |
|
|
141
|
+
| `pdf/incremental/unsupported-base` | `ParseError` | `startxref` designates neither a classical `xref` table nor a `/Type /XRef` stream. Nothing is written. |
|
|
142
|
+
| `pdf/xref/bad-stream-section` | `RenderError` | Cross-reference stream base, and `opts.encrypt` is not an indirect reference (propagated from `pdfXref.buildXrefStream`). |
|
|
143
|
+
|
|
144
|
+
## See also
|
|
145
|
+
|
|
146
|
+
- [`pdfWriter`](./writer.md) — full re-emit (the `{ num, gen, value }` update shape mirrors `writeDocument`'s `indirects`).
|
|
147
|
+
- [`pdfSign`](../sig/sign.md) — appends every signature (all levels), the LT/LTA DSS and the LTA DocTimeStamp through this module.
|
|
148
|
+
- [`pdfDssBuilder`](../sig/dss.md) — produces the DSS updates typically appended here.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
module: pdfPage
|
|
3
|
+
category: pdf/document
|
|
4
|
+
dependencies: [pdfErrors, pdfParser]
|
|
5
|
+
returns: object
|
|
6
|
+
worker-safe: true
|
|
7
|
+
status: complete
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# pdfPage
|
|
11
|
+
|
|
12
|
+
> Typing of a `/Type /Page` dictionary, ISO 32000-2 §7.7.3.3 — boxes, contents, rotate, annots.
|
|
13
|
+
|
|
14
|
+
**Module** `pdfPage` | **Source** `packages/front/office/pdf/src/document/page.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
|
|
15
|
+
|
|
16
|
+
Normalises a Page dictionary:
|
|
17
|
+
|
|
18
|
+
- The boxes (`MediaBox`, `CropBox`, `BleedBox`, `TrimBox`, `ArtBox`) are
|
|
19
|
+
flattened to `[llx, lly, urx, ury]` numeric tuples.
|
|
20
|
+
- `/Contents` is always exposed as `Array<{num, gen}>` (empty, single, or
|
|
21
|
+
multiple).
|
|
22
|
+
- `/Rotate` is normalised to a multiple of 90 within `[0, 270]`; an invalid
|
|
23
|
+
value becomes 0.
|
|
24
|
+
- `/Resources` is inheritable (§7.7.3.4) — not resolved here, kept raw.
|
|
25
|
+
- Unknown entries go to `_extras`.
|
|
26
|
+
|
|
27
|
+
## Resolve
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
const page = runtime.resolve('pdfPage');
|
|
31
|
+
// Returns: { typePage }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
| Method | Signature | Returns |
|
|
37
|
+
|--------|-----------|---------|
|
|
38
|
+
| `typePage` | `(dict: PdfDict) => TypedPage` | Typed record. |
|
|
39
|
+
|
|
40
|
+
### `TypedPage` shape
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
{
|
|
44
|
+
parent: { num, gen } | null,
|
|
45
|
+
mediaBox: [number, number, number, number] | null,
|
|
46
|
+
cropBox?: [number, number, number, number],
|
|
47
|
+
bleedBox?, trimBox?, artBox?: same,
|
|
48
|
+
resources: PdfObject | null,
|
|
49
|
+
contents: Array<{ num, gen }>, // always an array, sometimes empty
|
|
50
|
+
rotate: number, // 0 | 90 | 180 | 270
|
|
51
|
+
annots: Array<PdfObject>, // references or inline annotations
|
|
52
|
+
userUnit?: number,
|
|
53
|
+
tabs?: string,
|
|
54
|
+
metadata?: PdfRef,
|
|
55
|
+
group?: PdfObject,
|
|
56
|
+
raw: PdfDict,
|
|
57
|
+
_extras: Object<string, PdfObject>
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Examples
|
|
62
|
+
|
|
63
|
+
### Dimensions of the first page
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
const doc = api.read(bytes);
|
|
67
|
+
const p0 = doc.pages[0];
|
|
68
|
+
const [llx, lly, urx, ury] = p0.mediaBox; // e.g. [0, 0, 612, 792]
|
|
69
|
+
console.log('rotate=', p0.rotate);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Iterating the content streams
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
for (const ref of p0.contents) {
|
|
76
|
+
const stream = doc._raw.resolve({ type: 'ref', ...ref });
|
|
77
|
+
// stream.raw: Uint8Array — decode /Filter with pdfFilterDispatch
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Counting annotations
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
doc.pages.reduce((n, p) => n + p.annots.length, 0);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Errors
|
|
88
|
+
|
|
89
|
+
| Code | Class | When |
|
|
90
|
+
|------|-------|------|
|
|
91
|
+
| `pdf/page/not-dict` | `ParseError` | Argument is not a dictionary. |
|
|
92
|
+
| `pdf/page/bad-type` | `ParseError` | `/Type` present but not `/Page`. |
|
|
93
|
+
|
|
94
|
+
## See also
|
|
95
|
+
|
|
96
|
+
- [`pdfPages`](./pages.md) — produces the reference list typed here.
|
|
97
|
+
- [`pdfResources`](./resources.md) — resolves the inheritable `/Resources`.
|
|
98
|
+
- [`pdfDocument`](./document.md)
|
|
99
|
+
- [`pdfErrors`](../errors.md)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
module: pdfPages
|
|
3
|
+
category: pdf/document
|
|
4
|
+
dependencies: [pdfErrors, pdfParser]
|
|
5
|
+
returns: object
|
|
6
|
+
worker-safe: true
|
|
7
|
+
status: complete
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# pdfPages
|
|
11
|
+
|
|
12
|
+
> Page-tree walker, ISO 32000-2 §7.7.3 — `/Pages` tree → ordered list of leaf references.
|
|
13
|
+
|
|
14
|
+
**Module** `pdfPages` | **Source** `packages/front/office/pdf/src/document/pages.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
|
|
15
|
+
|
|
16
|
+
Descends `/Kids` recursively from the root pointed at by the Catalog. Guard
|
|
17
|
+
rails: maximum depth (`maxDepth = 64`), maximum page count
|
|
18
|
+
(`maxPages = 200000`), cycle detection through a `Set<'num:gen'>`. Tolerant of
|
|
19
|
+
intermediate nodes without `/Type` (present in some older PDFs): the fallback
|
|
20
|
+
test is the presence of `/Kids`.
|
|
21
|
+
|
|
22
|
+
## Resolve
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
const pages = runtime.resolve('pdfPages');
|
|
26
|
+
// Returns: { walkPageTree, readPageCount }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## API
|
|
30
|
+
|
|
31
|
+
| Method | Signature | Returns |
|
|
32
|
+
|--------|-----------|---------|
|
|
33
|
+
| `walkPageTree` | `(rootRef, resolveRef, opts?: { maxDepth?, maxPages? }) => Array<{num, gen}>` | Leaf references in document order. |
|
|
34
|
+
| `readPageCount` | `(node: PdfDict) => number \| null` | Reads `/Count` off an intermediate node. |
|
|
35
|
+
|
|
36
|
+
`resolveRef` must accept `{ type: 'ref', num, gen }` and return the materialised
|
|
37
|
+
dictionary — typically `doc._raw.resolve`.
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Standard walk
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
const pages = runtime.resolve('pdfPages');
|
|
45
|
+
const refs = pages.walkPageTree(doc.catalog.pages, doc._raw.resolve);
|
|
46
|
+
refs.length; // page count
|
|
47
|
+
refs[0]; // { num: 3, gen: 0 }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### `/Count` sanity check
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
const root = doc._raw.resolve({ type: 'ref', ...doc.catalog.pages });
|
|
54
|
+
const declared = pages.readPageCount(root);
|
|
55
|
+
const actual = pages.walkPageTree(doc.catalog.pages, doc._raw.resolve).length;
|
|
56
|
+
if (declared !== null && declared !== actual) {
|
|
57
|
+
console.warn('page tree /Count mismatch', { declared, actual });
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Limiting the depth
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
pages.walkPageTree(rootRef, resolve, { maxDepth: 16 });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Errors
|
|
68
|
+
|
|
69
|
+
| Code | Class | When |
|
|
70
|
+
|------|-------|------|
|
|
71
|
+
| `pdf/pages/max-depth` | `ParseError` | Tree deeper than `maxDepth`. |
|
|
72
|
+
| `pdf/pages/cycle` | `ParseError` | Reference already visited during the walk. |
|
|
73
|
+
| `pdf/pages/not-dict` | `ParseError` | A resolved node is not a dictionary. |
|
|
74
|
+
| `pdf/pages/too-many` | `ParseError` | More than `maxPages` leaves found. |
|
|
75
|
+
| `pdf/pages/missing-kids` | `ParseError` | Intermediate node without `/Kids`. |
|
|
76
|
+
| `pdf/pages/non-ref-kid` | `ParseError` | `/Kids` holds something other than a reference. |
|
|
77
|
+
|
|
78
|
+
## See also
|
|
79
|
+
|
|
80
|
+
- [`pdfPage`](./page.md) — types each leaf.
|
|
81
|
+
- [`pdfCatalog`](./catalog.md) — supplies `catalog.pages`.
|
|
82
|
+
- [`pdfDocument`](./document.md)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
module: pdfResources
|
|
3
|
+
category: pdf/document
|
|
4
|
+
dependencies: [pdfErrors, pdfParser]
|
|
5
|
+
returns: object
|
|
6
|
+
worker-safe: true
|
|
7
|
+
status: complete
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# pdfResources
|
|
11
|
+
|
|
12
|
+
> Resolution of a Page's or Form XObject's `/Resources` dictionary — ISO 32000-2 §7.8.3.
|
|
13
|
+
|
|
14
|
+
**Module** `pdfResources` | **Source** `packages/front/office/pdf/src/document/resources.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
|
|
15
|
+
|
|
16
|
+
Six named sub-dictionaries map the **local names** used inside a content stream
|
|
17
|
+
to indirect objects: `/Font`, `/XObject`, `/ColorSpace`, `/ExtGState`,
|
|
18
|
+
`/Pattern`, `/Shading`. A legacy `/ProcSet` is read but never required
|
|
19
|
+
(deprecated in PDF 2.0). Resources are **inheritable**: a Page without its own
|
|
20
|
+
`/Resources` walks up the page tree's `/Parent` chain (§7.7.3.4).
|
|
21
|
+
`resolvePageResources` implements that walk with a cycle guard.
|
|
22
|
+
|
|
23
|
+
Any category value may itself be an indirect reference (§7.3.10). Real
|
|
24
|
+
documents do this: a measured ANSSI guide carries `/ExtGState` as
|
|
25
|
+
`N 0 R` on 56 of its 58 pages. Rejecting that used to throw away the
|
|
26
|
+
page's whole resource map, fonts included. The resolver you pass reaches
|
|
27
|
+
objects inside object streams,
|
|
28
|
+
because it is the document's own `_raw.resolve`.
|
|
29
|
+
|
|
30
|
+
## Resolve
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const r = runtime.resolve('pdfResources');
|
|
34
|
+
// Returns: { typeResources, resolvePageResources, lookupResource }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
| Method | Signature | Returns |
|
|
40
|
+
|--------|-----------|---------|
|
|
41
|
+
| `typeResources` | `(dict\|null, resolveRef?) => Resources` | Direct typing. With `resolveRef`, an indirect category (`/Font 12 0 R`) is resolved through it; a category that resolves to `null` is treated as absent. |
|
|
42
|
+
| `resolvePageResources` | `(pageDict, resolveRef) => Resources` | Inherited walk, at most 64 levels; passes `resolveRef` on to `typeResources`. |
|
|
43
|
+
| `lookupResource` | `(resources, category, name, resolveRef?) => object` | Named lookup. |
|
|
44
|
+
|
|
45
|
+
### `Resources` shape
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
{
|
|
49
|
+
Font: { [name]: PdfObject },
|
|
50
|
+
XObject: { [name]: PdfObject },
|
|
51
|
+
ColorSpace: { [name]: PdfObject },
|
|
52
|
+
ExtGState: { [name]: PdfObject },
|
|
53
|
+
Pattern: { [name]: PdfObject },
|
|
54
|
+
Shading: { [name]: PdfObject },
|
|
55
|
+
ProcSet: string[] | null,
|
|
56
|
+
raw: object | null
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`lookupResource` returns the resolved object directly (ref → object) when
|
|
61
|
+
`resolveRef` is supplied, otherwise the typed entry (possibly a `ref`).
|
|
62
|
+
|
|
63
|
+
## Examples
|
|
64
|
+
|
|
65
|
+
### Page → Resources
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
const r = runtime.resolve('pdfResources');
|
|
69
|
+
const res = r.resolvePageResources(pageDict, doc._raw.resolve);
|
|
70
|
+
res.Font; // { F1: <typed font dict>, F2: … }
|
|
71
|
+
res.ExtGState; // { GS1: … }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Look up a named font
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
const fontDict = r.lookupResource(res, 'Font', 'F1', doc._raw.resolve);
|
|
78
|
+
const typed = runtime.resolve('pdfFont').typeFont(fontDict);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Direct typing without the walk
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
const res = r.typeResources(pageDict.entries.Resources);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Errors
|
|
88
|
+
|
|
89
|
+
| Code | Class | When |
|
|
90
|
+
|------|-------|------|
|
|
91
|
+
| `pdf/resources/not-dict` | `ParseError` | `/Resources` is not a dictionary. |
|
|
92
|
+
| `pdf/resources/bad-subdict` | `ParseError` | A sub-dictionary (`/Font`, …) is not a dictionary — or it is an indirect reference and no `resolveRef` was supplied. |
|
|
93
|
+
| `pdf/resources/bad-shape` | `ParseError` | `/Resources` is neither a dictionary nor a reference. |
|
|
94
|
+
| `pdf/resources/cycle` | `ParseError` | Cycle detected in the `/Parent` chain. |
|
|
95
|
+
| `pdf/resources/unknown-category` | `ParseError` | Invalid category passed to `lookupResource`. |
|
|
96
|
+
| `pdf/resources/missing-name` | `ParseError` | Name not found in the category. |
|
|
97
|
+
|
|
98
|
+
## See also
|
|
99
|
+
|
|
100
|
+
- [`pdfPage`](./page.md) — supplies `pageDict`.
|
|
101
|
+
- [`pdfPages`](./pages.md) — page-tree walk.
|
|
102
|
+
- [`pdfFont`](../font/font.md), [`pdfImages`](../content/images.md) — typers for the resolved entries.
|