@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,196 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Opt-in: typed PDF color spaces per ISO 32000-2:2020 §8.6.
|
|
8
|
+
*
|
|
9
|
+
* Covers: CalGray (§8.6.5.2), CalRGB (§8.6.5.3), Lab (§8.6.5.4),
|
|
10
|
+
* ICCBased (§8.6.5.5, with Metadata), Indexed (§8.6.6.3),
|
|
11
|
+
* Separation (§8.6.6.4), DeviceN (§8.6.6.5) with /Attributes,
|
|
12
|
+
* NChannel (DeviceN subtype, /Process), Pattern (§8.7).
|
|
13
|
+
*
|
|
14
|
+
* Color spaces in PDF are typically arrays where the first element is
|
|
15
|
+
* the family name. We type the array form and the named device families.
|
|
16
|
+
*
|
|
17
|
+
* @module pdf/extra/color-spaces-extended
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Module factory.
|
|
22
|
+
*/
|
|
23
|
+
import { pdfErrors } from '../errors.js';
|
|
24
|
+
import { pdfParserObj } from '../syntax/parser-obj.js';
|
|
25
|
+
|
|
26
|
+
export const pdfColorSpacesExtended = {
|
|
27
|
+
name: 'pdfColorSpacesExtended',
|
|
28
|
+
dependencies: ['pdfErrors', 'pdfParserObj'],
|
|
29
|
+
deps: [pdfErrors, pdfParserObj],
|
|
30
|
+
factory(errors, parserObj) {
|
|
31
|
+
const { ParseError } = errors;
|
|
32
|
+
const { isType } = parserObj;
|
|
33
|
+
|
|
34
|
+
const COLOR_SPACE_FAMILIES = new Set([
|
|
35
|
+
'CalGray', 'CalRGB', 'Lab', 'ICCBased', 'Indexed',
|
|
36
|
+
'Separation', 'DeviceN', 'NChannel', 'Pattern',
|
|
37
|
+
'DeviceGray', 'DeviceRGB', 'DeviceCMYK'
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
function typeColorSpace(value) {
|
|
41
|
+
if (isType(value, 'name')) {
|
|
42
|
+
if (!COLOR_SPACE_FAMILIES.has(value.value)) {
|
|
43
|
+
return { family: 'NamedResource', name: value.value, raw: value };
|
|
44
|
+
}
|
|
45
|
+
return { family: value.value, raw: value };
|
|
46
|
+
}
|
|
47
|
+
if (!isType(value, 'array') || value.items.length < 1) {
|
|
48
|
+
throw new ParseError('pdf/extra/colorspace/bad-shape',
|
|
49
|
+
'color space must be name or non-empty array',
|
|
50
|
+
{ context: { type: value && value.type } });
|
|
51
|
+
}
|
|
52
|
+
const head = value.items[0];
|
|
53
|
+
if (!isType(head, 'name')) {
|
|
54
|
+
throw new ParseError('pdf/extra/colorspace/bad-family',
|
|
55
|
+
'color space array must start with a name');
|
|
56
|
+
}
|
|
57
|
+
const family = head.value;
|
|
58
|
+
if (!COLOR_SPACE_FAMILIES.has(family)) {
|
|
59
|
+
throw new ParseError('pdf/extra/colorspace/unknown',
|
|
60
|
+
'unknown color-space family',
|
|
61
|
+
{ context: { family } });
|
|
62
|
+
}
|
|
63
|
+
switch (family) {
|
|
64
|
+
case 'CalGray': return { family, ...readCalGray(value), raw: value };
|
|
65
|
+
case 'CalRGB': return { family, ...readCalRGB(value), raw: value };
|
|
66
|
+
case 'Lab': return { family, ...readLab(value), raw: value };
|
|
67
|
+
case 'ICCBased': return { family, ...readICCBased(value), raw: value };
|
|
68
|
+
case 'Indexed': return { family, ...readIndexed(value), raw: value };
|
|
69
|
+
case 'Separation': return { family, ...readSeparation(value), raw: value };
|
|
70
|
+
case 'DeviceN': return { family, ...readDeviceN(value), raw: value };
|
|
71
|
+
case 'NChannel': return { family, ...readDeviceN(value), nChannel: true, raw: value };
|
|
72
|
+
case 'Pattern': return { family, ...readPattern(value), raw: value };
|
|
73
|
+
default: return { family, raw: value };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function readCalDict(d) {
|
|
78
|
+
if (!isType(d, 'dict')) {
|
|
79
|
+
throw new ParseError('pdf/extra/colorspace/cal-no-dict',
|
|
80
|
+
'Cal* parameters dict missing');
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
whitePoint: numArr(d.entries.WhitePoint, 3),
|
|
84
|
+
blackPoint: numArr(d.entries.BlackPoint, 3),
|
|
85
|
+
gamma: d.entries.Gamma || null,
|
|
86
|
+
matrix: numArr(d.entries.Matrix, 9)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function readCalGray(arr) {
|
|
91
|
+
if (arr.items.length < 2) {
|
|
92
|
+
throw new ParseError('pdf/extra/colorspace/cal-truncated', 'CalGray needs dict');
|
|
93
|
+
}
|
|
94
|
+
return { params: readCalDict(arr.items[1]) };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function readCalRGB(arr) {
|
|
98
|
+
if (arr.items.length < 2) {
|
|
99
|
+
throw new ParseError('pdf/extra/colorspace/cal-truncated', 'CalRGB needs dict');
|
|
100
|
+
}
|
|
101
|
+
return { params: readCalDict(arr.items[1]) };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function readLab(arr) {
|
|
105
|
+
if (arr.items.length < 2 || !isType(arr.items[1], 'dict')) {
|
|
106
|
+
throw new ParseError('pdf/extra/colorspace/lab-truncated', 'Lab needs dict');
|
|
107
|
+
}
|
|
108
|
+
const d = arr.items[1].entries;
|
|
109
|
+
return {
|
|
110
|
+
whitePoint: numArr(d.WhitePoint, 3),
|
|
111
|
+
blackPoint: numArr(d.BlackPoint, 3),
|
|
112
|
+
range: numArr(d.Range, 4)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function readICCBased(arr) {
|
|
117
|
+
if (arr.items.length < 2 || !isType(arr.items[1], 'stream')) {
|
|
118
|
+
throw new ParseError('pdf/extra/colorspace/icc-no-stream',
|
|
119
|
+
'ICCBased needs a stream');
|
|
120
|
+
}
|
|
121
|
+
const s = arr.items[1];
|
|
122
|
+
const e = s.dict.entries;
|
|
123
|
+
return {
|
|
124
|
+
n: (e.N && (e.N.type === 'int' || e.N.type === 'real')) ? (e.N.value | 0) : null,
|
|
125
|
+
alt: e.Alternate || null,
|
|
126
|
+
range: numArr(e.Range, null),
|
|
127
|
+
metadata: e.Metadata || null,
|
|
128
|
+
profile: s
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function readIndexed(arr) {
|
|
133
|
+
if (arr.items.length < 4) {
|
|
134
|
+
throw new ParseError('pdf/extra/colorspace/indexed-truncated',
|
|
135
|
+
'Indexed needs [base hival lookup]');
|
|
136
|
+
}
|
|
137
|
+
const hival = arr.items[2];
|
|
138
|
+
if (!hival || (hival.type !== 'int' && hival.type !== 'real')) {
|
|
139
|
+
throw new ParseError('pdf/extra/colorspace/indexed-bad-hival',
|
|
140
|
+
'Indexed hival must be numeric');
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
base: arr.items[1],
|
|
144
|
+
hival: hival.value | 0,
|
|
145
|
+
lookup: arr.items[3]
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function readSeparation(arr) {
|
|
150
|
+
if (arr.items.length < 4) {
|
|
151
|
+
throw new ParseError('pdf/extra/colorspace/sep-truncated',
|
|
152
|
+
'Separation needs [name alternate tintTransform]');
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
colorant: isType(arr.items[1], 'name') ? arr.items[1].value : null,
|
|
156
|
+
alternate: arr.items[2],
|
|
157
|
+
tintTransform: arr.items[3]
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function readDeviceN(arr) {
|
|
162
|
+
if (arr.items.length < 4) {
|
|
163
|
+
throw new ParseError('pdf/extra/colorspace/devn-truncated',
|
|
164
|
+
'DeviceN needs [names alternate tintTransform attributes?]');
|
|
165
|
+
}
|
|
166
|
+
let names = null;
|
|
167
|
+
if (isType(arr.items[1], 'array')) {
|
|
168
|
+
names = arr.items[1].items.map(it => isType(it, 'name') ? it.value : null);
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
names,
|
|
172
|
+
alternate: arr.items[2],
|
|
173
|
+
tintTransform: arr.items[3],
|
|
174
|
+
attributes: arr.items[4] || null
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function readPattern(arr) {
|
|
179
|
+
return { base: arr.items[1] || null };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function numArr(v, expectedLen) {
|
|
183
|
+
if (!isType(v, 'array')) return null;
|
|
184
|
+
const out = [];
|
|
185
|
+
for (const it of v.items) {
|
|
186
|
+
if (!it || (it.type !== 'int' && it.type !== 'real')) return null;
|
|
187
|
+
out.push(it.value);
|
|
188
|
+
}
|
|
189
|
+
if (expectedLen != null && out.length !== expectedLen) return null;
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return { typeColorSpace, COLOR_SPACE_FAMILIES };
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Opt-in: extended graphics-state operators and full
|
|
8
|
+
* ExtGState typing.
|
|
9
|
+
*
|
|
10
|
+
* Per ISO 32000-2:2020 §8.4.5 (graphics-state operators) and §8.4.5
|
|
11
|
+
* Table 57 (ExtGState parameter dictionary).
|
|
12
|
+
*
|
|
13
|
+
* Rare gstate-extra ops covered: `d0`, `d1` (Type 3 font char-width
|
|
14
|
+
* shape operators, §9.6.4) ; `gs` is L0 already, but this module also
|
|
15
|
+
* exposes the catalog of every ExtGState key.
|
|
16
|
+
*
|
|
17
|
+
* @module pdf/extra/content-ops-extended
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Module factory.
|
|
22
|
+
*/
|
|
23
|
+
import { pdfErrors } from '../errors.js';
|
|
24
|
+
import { pdfParserObj } from '../syntax/parser-obj.js';
|
|
25
|
+
|
|
26
|
+
export const pdfContentOpsExtended = {
|
|
27
|
+
name: 'pdfContentOpsExtended',
|
|
28
|
+
dependencies: ['pdfErrors', 'pdfParserObj'],
|
|
29
|
+
deps: [pdfErrors, pdfParserObj],
|
|
30
|
+
factory(errors, parserObj) {
|
|
31
|
+
const { ParseError } = errors;
|
|
32
|
+
const { isType } = parserObj;
|
|
33
|
+
|
|
34
|
+
const EXT_GSTATE_KEYS = Object.freeze({
|
|
35
|
+
Type: { kind: 'name', doc: 'must be /ExtGState' },
|
|
36
|
+
LW: { kind: 'num', doc: 'line width' },
|
|
37
|
+
LC: { kind: 'int', doc: 'line cap style 0|1|2' },
|
|
38
|
+
LJ: { kind: 'int', doc: 'line join style 0|1|2' },
|
|
39
|
+
ML: { kind: 'num', doc: 'miter limit' },
|
|
40
|
+
D: { kind: 'array', doc: '[ dashArray dashPhase ]' },
|
|
41
|
+
RI: { kind: 'name', doc: 'rendering intent' },
|
|
42
|
+
OP: { kind: 'bool', doc: 'stroke overprint' },
|
|
43
|
+
op: { kind: 'bool', doc: 'non-stroke overprint' },
|
|
44
|
+
OPM: { kind: 'int', doc: 'overprint mode 0|1' },
|
|
45
|
+
Font: { kind: 'array', doc: '[ font size ]' },
|
|
46
|
+
BG: { kind: 'stream-or-func', doc: 'black-generation function' },
|
|
47
|
+
BG2: { kind: 'stream-or-name', doc: 'BG or /Default' },
|
|
48
|
+
UCR: { kind: 'stream-or-func', doc: 'undercolor-removal function' },
|
|
49
|
+
UCR2: { kind: 'stream-or-name', doc: 'UCR or /Default' },
|
|
50
|
+
TR: { kind: 'stream-or-func-or-array', doc: 'transfer function' },
|
|
51
|
+
TR2: { kind: 'stream-or-func-or-array-or-name', doc: 'transfer function or /Default' },
|
|
52
|
+
HT: { kind: 'dict-or-stream-or-name', doc: 'halftone' },
|
|
53
|
+
FL: { kind: 'num', doc: 'flatness tolerance' },
|
|
54
|
+
SM: { kind: 'num', doc: 'smoothness tolerance' },
|
|
55
|
+
SA: { kind: 'bool', doc: 'stroke adjustment' },
|
|
56
|
+
BM: { kind: 'name-or-array', doc: 'blend mode' },
|
|
57
|
+
SMask: { kind: 'dict-or-name', doc: 'soft mask' },
|
|
58
|
+
CA: { kind: 'num', doc: 'stroke alpha [0,1]' },
|
|
59
|
+
ca: { kind: 'num', doc: 'non-stroke alpha [0,1]' },
|
|
60
|
+
AIS: { kind: 'bool', doc: 'alpha is shape' },
|
|
61
|
+
TK: { kind: 'bool', doc: 'text knockout' },
|
|
62
|
+
UseBlackPtComp: { kind: 'name', doc: 'ON|OFF|Default' },
|
|
63
|
+
HTO: { kind: 'array', doc: 'halftone origin [tx ty]' }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const NUM = (v) => v && (v.type === 'int' || v.type === 'real');
|
|
67
|
+
|
|
68
|
+
function typeExtGState(dict) {
|
|
69
|
+
if (!isType(dict, 'dict')) {
|
|
70
|
+
throw new ParseError('pdf/extra/ext-gstate/not-dict',
|
|
71
|
+
'ExtGState must be a dictionary',
|
|
72
|
+
{ context: { type: dict && dict.type } });
|
|
73
|
+
}
|
|
74
|
+
const e = dict.entries;
|
|
75
|
+
if (e.Type && (e.Type.type !== 'name' || e.Type.value !== 'ExtGState')) {
|
|
76
|
+
throw new ParseError('pdf/extra/ext-gstate/bad-type',
|
|
77
|
+
'/Type entry must be /ExtGState',
|
|
78
|
+
{ context: { actual: e.Type.value } });
|
|
79
|
+
}
|
|
80
|
+
const out = {
|
|
81
|
+
type: e.Type ? e.Type.value : null,
|
|
82
|
+
lw: NUM(e.LW) ? e.LW.value : null,
|
|
83
|
+
lc: NUM(e.LC) ? (e.LC.value | 0) : null,
|
|
84
|
+
lj: NUM(e.LJ) ? (e.LJ.value | 0) : null,
|
|
85
|
+
ml: NUM(e.ML) ? e.ML.value : null,
|
|
86
|
+
d: isType(e.D, 'array') ? e.D : null,
|
|
87
|
+
ri: isType(e.RI, 'name') ? e.RI.value : null,
|
|
88
|
+
op: isType(e.OP, 'bool') ? e.OP.value : null,
|
|
89
|
+
opNs: isType(e.op, 'bool') ? e.op.value : null,
|
|
90
|
+
opm: NUM(e.OPM) ? (e.OPM.value | 0) : null,
|
|
91
|
+
font: isType(e.Font, 'array') ? e.Font : null,
|
|
92
|
+
bg: e.BG || null,
|
|
93
|
+
bg2: e.BG2 || null,
|
|
94
|
+
ucr: e.UCR || null,
|
|
95
|
+
ucr2: e.UCR2 || null,
|
|
96
|
+
tr: e.TR || null,
|
|
97
|
+
tr2: e.TR2 || null,
|
|
98
|
+
ht: e.HT || null,
|
|
99
|
+
fl: NUM(e.FL) ? e.FL.value : null,
|
|
100
|
+
sm: NUM(e.SM) ? e.SM.value : null,
|
|
101
|
+
sa: isType(e.SA, 'bool') ? e.SA.value : null,
|
|
102
|
+
bm: e.BM || null,
|
|
103
|
+
sMask: e.SMask || null,
|
|
104
|
+
ca: NUM(e.CA) ? e.CA.value : null,
|
|
105
|
+
caNs: NUM(e.ca) ? e.ca.value : null,
|
|
106
|
+
ais: isType(e.AIS, 'bool') ? e.AIS.value : null,
|
|
107
|
+
tk: isType(e.TK, 'bool') ? e.TK.value : null,
|
|
108
|
+
useBlackPtComp: isType(e.UseBlackPtComp, 'name') ? e.UseBlackPtComp.value : null,
|
|
109
|
+
hto: isType(e.HTO, 'array') ? e.HTO : null,
|
|
110
|
+
raw: dict,
|
|
111
|
+
_extras: {}
|
|
112
|
+
};
|
|
113
|
+
for (const k of Object.keys(e)) {
|
|
114
|
+
if (!(k in EXT_GSTATE_KEYS)) out._extras[k] = e[k];
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function decodeType3CharOp(op, operands) {
|
|
120
|
+
if (op !== 'd0' && op !== 'd1') {
|
|
121
|
+
throw new ParseError('pdf/extra/content-ops/unknown',
|
|
122
|
+
'expected d0 or d1 operator',
|
|
123
|
+
{ context: { op } });
|
|
124
|
+
}
|
|
125
|
+
if (op === 'd0') {
|
|
126
|
+
if (!operands || operands.length !== 2) {
|
|
127
|
+
throw new ParseError('pdf/extra/content-ops/bad-d0',
|
|
128
|
+
'd0 requires 2 operands wx wy',
|
|
129
|
+
{ context: { count: operands && operands.length } });
|
|
130
|
+
}
|
|
131
|
+
return { kind: 'd0', wx: +operands[0], wy: +operands[1] };
|
|
132
|
+
}
|
|
133
|
+
if (!operands || operands.length !== 6) {
|
|
134
|
+
throw new ParseError('pdf/extra/content-ops/bad-d1',
|
|
135
|
+
'd1 requires 6 operands wx wy llx lly urx ury',
|
|
136
|
+
{ context: { count: operands && operands.length } });
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
kind: 'd1',
|
|
140
|
+
wx: +operands[0],
|
|
141
|
+
wy: +operands[1],
|
|
142
|
+
bbox: [ +operands[2], +operands[3], +operands[4], +operands[5] ]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
typeExtGState,
|
|
148
|
+
decodeType3CharOp,
|
|
149
|
+
EXT_GSTATE_KEYS
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Opt-in: Document Parts (ISO/TS 32004) typing.
|
|
8
|
+
*
|
|
9
|
+
* TS 32004 introduces a hierarchical "Document Parts" tree rooted in the
|
|
10
|
+
* Catalog under `/DPartRoot`. Each node is a `/Type /DPart` dict with:
|
|
11
|
+
* /Parent — parent DPart (omitted on root)
|
|
12
|
+
* /DParts — array of child DPart refs or page refs
|
|
13
|
+
* /Start — first page index in this subtree (computed)
|
|
14
|
+
* /End — last page index in this subtree
|
|
15
|
+
* /DPM — Document Part Metadata dict
|
|
16
|
+
* /NodeNameTree — name-tree mapping local names → DPart refs
|
|
17
|
+
*
|
|
18
|
+
* @module pdf/extra/document-parts
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Module factory.
|
|
23
|
+
*/
|
|
24
|
+
import { pdfErrors } from '../errors.js';
|
|
25
|
+
import { pdfParser } from '../syntax/parser.js';
|
|
26
|
+
|
|
27
|
+
export const pdfDocumentParts = {
|
|
28
|
+
name: 'pdfDocumentParts',
|
|
29
|
+
dependencies: ['pdfErrors', 'pdfParser'],
|
|
30
|
+
deps: [pdfErrors, pdfParser],
|
|
31
|
+
factory(errors, parser) {
|
|
32
|
+
const { ParseError } = errors;
|
|
33
|
+
const { isType } = parser;
|
|
34
|
+
|
|
35
|
+
const DPART_KNOWN = new Set([
|
|
36
|
+
'Type', 'Parent', 'DParts', 'Start', 'End', 'DPM', 'NodeNameTree'
|
|
37
|
+
]);
|
|
38
|
+
const ROOT_KNOWN = new Set([
|
|
39
|
+
'Type', 'DPartRootNode', 'RecordLevel', 'NodeNameList'
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
function typeDPartRoot(dict) {
|
|
43
|
+
if (!isType(dict, 'dict')) {
|
|
44
|
+
throw new ParseError('pdf/extra/dparts/root/not-dict',
|
|
45
|
+
'/DPartRoot must be a dictionary',
|
|
46
|
+
{ context: { type: dict && dict.type } });
|
|
47
|
+
}
|
|
48
|
+
const e = dict.entries;
|
|
49
|
+
if (e.Type && (e.Type.type !== 'name' || e.Type.value !== 'DPartRoot')) {
|
|
50
|
+
throw new ParseError('pdf/extra/dparts/root/bad-type',
|
|
51
|
+
'/Type must be /DPartRoot when present',
|
|
52
|
+
{ context: { actual: e.Type.value } });
|
|
53
|
+
}
|
|
54
|
+
if (!e.DPartRootNode) {
|
|
55
|
+
throw new ParseError('pdf/extra/dparts/root/missing-node',
|
|
56
|
+
'/DPartRoot requires a /DPartRootNode entry');
|
|
57
|
+
}
|
|
58
|
+
const out = {
|
|
59
|
+
rootNode: e.DPartRootNode,
|
|
60
|
+
recordLevel: isType(e.RecordLevel, 'int') ? e.RecordLevel.value : null,
|
|
61
|
+
nodeNameList: toNameList(e.NodeNameList),
|
|
62
|
+
raw: dict,
|
|
63
|
+
_extras: {}
|
|
64
|
+
};
|
|
65
|
+
for (const k of Object.keys(e)) {
|
|
66
|
+
if (!ROOT_KNOWN.has(k)) out._extras[k] = e[k];
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function typeDPart(dict) {
|
|
72
|
+
if (!isType(dict, 'dict')) {
|
|
73
|
+
throw new ParseError('pdf/extra/dparts/node/not-dict',
|
|
74
|
+
'/DPart must be a dictionary',
|
|
75
|
+
{ context: { type: dict && dict.type } });
|
|
76
|
+
}
|
|
77
|
+
const e = dict.entries;
|
|
78
|
+
if (e.Type && (e.Type.type !== 'name' || e.Type.value !== 'DPart')) {
|
|
79
|
+
throw new ParseError('pdf/extra/dparts/node/bad-type',
|
|
80
|
+
'/Type must be /DPart when present',
|
|
81
|
+
{ context: { actual: e.Type.value } });
|
|
82
|
+
}
|
|
83
|
+
const out = {
|
|
84
|
+
parent: e.Parent || null,
|
|
85
|
+
dParts: toRefArray(e.DParts),
|
|
86
|
+
start: isType(e.Start, 'int') ? e.Start.value : null,
|
|
87
|
+
end: isType(e.End, 'int') ? e.End.value : null,
|
|
88
|
+
dpm: isType(e.DPM, 'dict') ? typeDPM(e.DPM) : null,
|
|
89
|
+
nodeNameTree: e.NodeNameTree || null,
|
|
90
|
+
raw: dict,
|
|
91
|
+
_extras: {}
|
|
92
|
+
};
|
|
93
|
+
if (e.DPM && !isType(e.DPM, 'dict')) {
|
|
94
|
+
throw new ParseError('pdf/extra/dparts/node/bad-dpm',
|
|
95
|
+
'/DPM must be a dictionary',
|
|
96
|
+
{ context: { type: e.DPM.type } });
|
|
97
|
+
}
|
|
98
|
+
for (const k of Object.keys(e)) {
|
|
99
|
+
if (!DPART_KNOWN.has(k)) out._extras[k] = e[k];
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function typeDPM(dict) {
|
|
105
|
+
if (!isType(dict, 'dict')) {
|
|
106
|
+
throw new ParseError('pdf/extra/dparts/dpm/not-dict',
|
|
107
|
+
'/DPM must be a dictionary',
|
|
108
|
+
{ context: { type: dict && dict.type } });
|
|
109
|
+
}
|
|
110
|
+
const e = dict.entries;
|
|
111
|
+
const out = { entries: {}, raw: dict };
|
|
112
|
+
for (const k of Object.keys(e)) out.entries[k] = e[k];
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function walkDParts(root, visit) {
|
|
117
|
+
if (!root) return;
|
|
118
|
+
if (typeof visit !== 'function') {
|
|
119
|
+
throw new ParseError('pdf/extra/dparts/walk/bad-visit',
|
|
120
|
+
'walkDParts requires a visit callback');
|
|
121
|
+
}
|
|
122
|
+
visit(root);
|
|
123
|
+
if (!root.dParts) return;
|
|
124
|
+
for (const child of root.dParts) {
|
|
125
|
+
if (isType(child, 'dict')) walkDParts(typeDPart(child), visit);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function toRefArray(v) {
|
|
130
|
+
if (!v) return null;
|
|
131
|
+
if (v.type !== 'array') return null;
|
|
132
|
+
return v.items.slice();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function toNameList(v) {
|
|
136
|
+
if (!v) return null;
|
|
137
|
+
if (v.type !== 'array') return null;
|
|
138
|
+
const out = [];
|
|
139
|
+
for (const it of v.items) {
|
|
140
|
+
if (isType(it, 'name')) out.push(it.value);
|
|
141
|
+
else out.push(it);
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return { typeDPartRoot, typeDPart, typeDPM, walkDParts };
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|