@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.
Files changed (345) hide show
  1. package/CHANGELOG.md +609 -0
  2. package/LICENSE +661 -0
  3. package/NOTICE +77 -0
  4. package/README.md +363 -2
  5. package/dist/build/index.js +21 -0
  6. package/dist/build/pdf-full-rw.js +10972 -0
  7. package/dist/build/pdf-full-rw.meta.json +105 -0
  8. package/dist/build/pdf-full-rw.min.js +53 -0
  9. package/dist/build/pdf-full.js +6078 -0
  10. package/dist/build/pdf-full.meta.json +90 -0
  11. package/dist/build/pdf-full.min.js +32 -0
  12. package/dist/build/pdf-large-rw.js +10367 -0
  13. package/dist/build/pdf-large-rw.meta.json +99 -0
  14. package/dist/build/pdf-large-rw.min.js +53 -0
  15. package/dist/build/pdf-large.js +5473 -0
  16. package/dist/build/pdf-large.meta.json +84 -0
  17. package/dist/build/pdf-large.min.js +32 -0
  18. package/dist/build/pdf-legacy-rw.js +12402 -0
  19. package/dist/build/pdf-legacy-rw.meta.json +110 -0
  20. package/dist/build/pdf-legacy-rw.min.js +53 -0
  21. package/dist/build/pdf-legacy.js +7508 -0
  22. package/dist/build/pdf-legacy.meta.json +95 -0
  23. package/dist/build/pdf-legacy.min.js +32 -0
  24. package/dist/build/pdf-rw.js +7578 -0
  25. package/dist/build/pdf-rw.meta.json +77 -0
  26. package/dist/build/pdf-rw.min.js +53 -0
  27. package/dist/build/pdf.js +2684 -0
  28. package/dist/build/pdf.meta.json +62 -0
  29. package/dist/build/pdf.min.js +32 -0
  30. package/dist/standalone/pdf-full-rw.js +16798 -0
  31. package/dist/standalone/pdf-full-rw.meta.json +78 -0
  32. package/dist/standalone/pdf-full-rw.min.js +56 -0
  33. package/dist/standalone/pdf-full.js +11904 -0
  34. package/dist/standalone/pdf-full.meta.json +63 -0
  35. package/dist/standalone/pdf-full.min.js +35 -0
  36. package/dist/standalone/pdf-large-rw.js +16193 -0
  37. package/dist/standalone/pdf-large-rw.meta.json +72 -0
  38. package/dist/standalone/pdf-large-rw.min.js +56 -0
  39. package/dist/standalone/pdf-large.js +11299 -0
  40. package/dist/standalone/pdf-large.meta.json +57 -0
  41. package/dist/standalone/pdf-large.min.js +35 -0
  42. package/dist/standalone/pdf-legacy-rw.js +18228 -0
  43. package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
  44. package/dist/standalone/pdf-legacy-rw.min.js +56 -0
  45. package/dist/standalone/pdf-legacy.js +13334 -0
  46. package/dist/standalone/pdf-legacy.meta.json +68 -0
  47. package/dist/standalone/pdf-legacy.min.js +35 -0
  48. package/dist/standalone/pdf-rw.js +13404 -0
  49. package/dist/standalone/pdf-rw.meta.json +50 -0
  50. package/dist/standalone/pdf-rw.min.js +56 -0
  51. package/dist/standalone/pdf.js +8510 -0
  52. package/dist/standalone/pdf.meta.json +35 -0
  53. package/dist/standalone/pdf.min.js +35 -0
  54. package/docs/README.md +53 -0
  55. package/docs/api/README.md +38 -0
  56. package/docs/api/_shared/README.md +91 -0
  57. package/docs/api/action/README.md +29 -0
  58. package/docs/api/action/action.md +81 -0
  59. package/docs/api/action/goTo.md +66 -0
  60. package/docs/api/action/launch.md +58 -0
  61. package/docs/api/action/named.md +55 -0
  62. package/docs/api/action/uri.md +54 -0
  63. package/docs/api/annot/README.md +53 -0
  64. package/docs/api/annot/annot.md +114 -0
  65. package/docs/api/annot/fileAttach.md +53 -0
  66. package/docs/api/annot/freeText.md +68 -0
  67. package/docs/api/annot/ink.md +69 -0
  68. package/docs/api/annot/link.md +74 -0
  69. package/docs/api/annot/markup.md +83 -0
  70. package/docs/api/annot/popup.md +52 -0
  71. package/docs/api/annot/projection.md +56 -0
  72. package/docs/api/annot/redact.md +67 -0
  73. package/docs/api/annot/square.md +87 -0
  74. package/docs/api/annot/stamp.md +54 -0
  75. package/docs/api/annot/text.md +69 -0
  76. package/docs/api/annot/widget.md +69 -0
  77. package/docs/api/associatedFiles/README.md +9 -0
  78. package/docs/api/associatedFiles/associatedFiles.md +78 -0
  79. package/docs/api/bundles/README.md +68 -0
  80. package/docs/api/bundles/dist-matrix.md +165 -0
  81. package/docs/api/bundles/pdf-full.md +148 -0
  82. package/docs/api/bundles/pdf-large.md +144 -0
  83. package/docs/api/bundles/pdf-legacy.md +169 -0
  84. package/docs/api/content/README.md +29 -0
  85. package/docs/api/content/color.md +99 -0
  86. package/docs/api/content/graphics.md +114 -0
  87. package/docs/api/content/images.md +124 -0
  88. package/docs/api/content/ops.md +100 -0
  89. package/docs/api/content/stream.md +107 -0
  90. package/docs/api/content/text.md +98 -0
  91. package/docs/api/crypto/README.md +29 -0
  92. package/docs/api/crypto/aesGcm.md +72 -0
  93. package/docs/api/crypto/permissions.md +79 -0
  94. package/docs/api/crypto/security.md +98 -0
  95. package/docs/api/crypto/standardV4.md +104 -0
  96. package/docs/api/crypto/standardV5.md +84 -0
  97. package/docs/api/crypto/standardV6.md +93 -0
  98. package/docs/api/destination/README.md +9 -0
  99. package/docs/api/destination/destination.md +79 -0
  100. package/docs/api/document/README.md +29 -0
  101. package/docs/api/document/builder.md +281 -0
  102. package/docs/api/document/catalog.md +98 -0
  103. package/docs/api/document/document.md +187 -0
  104. package/docs/api/document/encryptedWriter.md +149 -0
  105. package/docs/api/document/incrementalWriter.md +148 -0
  106. package/docs/api/document/page.md +99 -0
  107. package/docs/api/document/pages.md +82 -0
  108. package/docs/api/document/resources.md +102 -0
  109. package/docs/api/document/writer.md +157 -0
  110. package/docs/api/document/xrefStreamWriter.md +122 -0
  111. package/docs/api/embedded/README.md +13 -0
  112. package/docs/api/embedded/collection.md +80 -0
  113. package/docs/api/embedded/embeddedFile.md +86 -0
  114. package/docs/api/embedded/fileSpec.md +87 -0
  115. package/docs/api/errors.md +110 -0
  116. package/docs/api/extra/3d-richmedia.md +76 -0
  117. package/docs/api/extra/README.md +99 -0
  118. package/docs/api/extra/annot-extended.md +71 -0
  119. package/docs/api/extra/associated-files.md +70 -0
  120. package/docs/api/extra/ccitt-fax-decoder.md +74 -0
  121. package/docs/api/extra/color-spaces-extended.md +72 -0
  122. package/docs/api/extra/content-ops-extended.md +82 -0
  123. package/docs/api/extra/document-parts.md +69 -0
  124. package/docs/api/extra/embedded-files-portfolio.md +87 -0
  125. package/docs/api/extra/font-cid-typed.md +77 -0
  126. package/docs/api/extra/font-color-tagging.md +76 -0
  127. package/docs/api/extra/form-actions-extended.md +75 -0
  128. package/docs/api/extra/info-dict-deprecated.md +72 -0
  129. package/docs/api/extra/jbig2-read.md +80 -0
  130. package/docs/api/extra/legacy-deprecated-annots.md +89 -0
  131. package/docs/api/extra/legacy-deprecated-filters.md +78 -0
  132. package/docs/api/extra/legacy-rc4-read.md +74 -0
  133. package/docs/api/extra/legacy-xfa-read.md +65 -0
  134. package/docs/api/extra/linearization-write.md +71 -0
  135. package/docs/api/extra/misc.md +93 -0
  136. package/docs/api/extra/optional-content-extended.md +83 -0
  137. package/docs/api/extra/pdf-a-output-intent.md +65 -0
  138. package/docs/api/extra/pdf-sandbox.md +76 -0
  139. package/docs/api/extra/pdf-ua-tagged.md +63 -0
  140. package/docs/api/extra/pdf-x-prepress.md +65 -0
  141. package/docs/api/extra/redaction-iso32005.md +65 -0
  142. package/docs/api/extra/shading-typed.md +73 -0
  143. package/docs/api/extra/sig-aes-gcm.md +69 -0
  144. package/docs/api/extra/sig-pades.md +103 -0
  145. package/docs/api/extra/tagged-pdf-typed.md +78 -0
  146. package/docs/api/extra/transparency-typed.md +74 -0
  147. package/docs/api/extra/well-tagged-pdf.md +61 -0
  148. package/docs/api/extra/xmp-extended.md +65 -0
  149. package/docs/api/font/README.md +25 -0
  150. package/docs/api/font/embed.md +157 -0
  151. package/docs/api/font/encoding.md +95 -0
  152. package/docs/api/font/font.md +97 -0
  153. package/docs/api/font/type3.md +89 -0
  154. package/docs/api/form/README.md +35 -0
  155. package/docs/api/form/acroform.md +88 -0
  156. package/docs/api/form/appearance.md +87 -0
  157. package/docs/api/form/button.md +97 -0
  158. package/docs/api/form/choice.md +96 -0
  159. package/docs/api/form/fieldTree.md +93 -0
  160. package/docs/api/form/signature.md +90 -0
  161. package/docs/api/form/text.md +88 -0
  162. package/docs/api/linearization/README.md +11 -0
  163. package/docs/api/linearization/linearization.md +81 -0
  164. package/docs/api/main.md +116 -0
  165. package/docs/api/metadata/README.md +10 -0
  166. package/docs/api/metadata/info.md +70 -0
  167. package/docs/api/metadata/xmp.md +62 -0
  168. package/docs/api/ocg/README.md +23 -0
  169. package/docs/api/ocg/config.md +95 -0
  170. package/docs/api/ocg/ocg.md +77 -0
  171. package/docs/api/outline/README.md +11 -0
  172. package/docs/api/outline/outline.md +107 -0
  173. package/docs/api/pdf.md +152 -0
  174. package/docs/api/prepress/README.md +10 -0
  175. package/docs/api/prepress/outputIntent.md +79 -0
  176. package/docs/api/prepress/pageBoundary.md +75 -0
  177. package/docs/api/sig/README.md +32 -0
  178. package/docs/api/sig/byteRange.md +120 -0
  179. package/docs/api/sig/certChain.md +84 -0
  180. package/docs/api/sig/dss.md +111 -0
  181. package/docs/api/sig/oids.md +76 -0
  182. package/docs/api/sig/sha1.md +72 -0
  183. package/docs/api/sig/sign.md +317 -0
  184. package/docs/api/sig/signature.md +178 -0
  185. package/docs/api/sig/timestamp.md +84 -0
  186. package/docs/api/syntax/README.md +29 -0
  187. package/docs/api/syntax/crossRefStream.md +115 -0
  188. package/docs/api/syntax/filters/README.md +50 -0
  189. package/docs/api/syntax/filters/ascii85.md +76 -0
  190. package/docs/api/syntax/filters/asciiHex.md +73 -0
  191. package/docs/api/syntax/filters/dispatch.md +125 -0
  192. package/docs/api/syntax/filters/flate.md +134 -0
  193. package/docs/api/syntax/filters/runLength.md +78 -0
  194. package/docs/api/syntax/objStream.md +88 -0
  195. package/docs/api/syntax/parser-obj.md +97 -0
  196. package/docs/api/syntax/parser.md +151 -0
  197. package/docs/api/syntax/serializer.md +109 -0
  198. package/docs/api/syntax/tokenizer.md +104 -0
  199. package/docs/api/syntax/trailer.md +85 -0
  200. package/docs/api/syntax/xref.md +139 -0
  201. package/docs/api/tagged/README.md +25 -0
  202. package/docs/api/tagged/classMap.md +67 -0
  203. package/docs/api/tagged/markedContent.md +62 -0
  204. package/docs/api/tagged/parentTree.md +67 -0
  205. package/docs/api/tagged/roleMap.md +67 -0
  206. package/docs/api/tagged/structElement.md +76 -0
  207. package/docs/api/tagged/structTree.md +75 -0
  208. package/docs/guide/coverage.md +113 -0
  209. package/docs/guide/crypto.md +121 -0
  210. package/docs/guide/extending.md +76 -0
  211. package/docs/guide/getting-started.md +75 -0
  212. package/docs/guide/legacy-1.7.md +42 -0
  213. package/docs/guide/pades-integration.md +579 -0
  214. package/docs/guide/read-pdf.md +89 -0
  215. package/package.json +97 -4
  216. package/src/_shared/index.js +179 -0
  217. package/src/action/action.js +119 -0
  218. package/src/action/goTo.js +89 -0
  219. package/src/action/launch.js +61 -0
  220. package/src/action/named.js +54 -0
  221. package/src/action/uri.js +51 -0
  222. package/src/annot/annot.js +212 -0
  223. package/src/annot/fileAttach.js +55 -0
  224. package/src/annot/freeText.js +82 -0
  225. package/src/annot/ink.js +77 -0
  226. package/src/annot/link.js +77 -0
  227. package/src/annot/markup.js +91 -0
  228. package/src/annot/popup.js +53 -0
  229. package/src/annot/projection.js +52 -0
  230. package/src/annot/redact.js +87 -0
  231. package/src/annot/square.js +132 -0
  232. package/src/annot/stamp.js +48 -0
  233. package/src/annot/text.js +54 -0
  234. package/src/annot/widget.js +61 -0
  235. package/src/associatedFiles/associatedFiles.js +86 -0
  236. package/src/bundles/pdf-full.js +91 -0
  237. package/src/bundles/pdf-large.js +81 -0
  238. package/src/bundles/pdf-legacy.js +107 -0
  239. package/src/content/color.js +114 -0
  240. package/src/content/graphics.js +192 -0
  241. package/src/content/images.js +160 -0
  242. package/src/content/ops.js +137 -0
  243. package/src/content/stream.js +154 -0
  244. package/src/content/text.js +125 -0
  245. package/src/crypto/aesGcm.js +123 -0
  246. package/src/crypto/permissions.js +112 -0
  247. package/src/crypto/security.js +327 -0
  248. package/src/crypto/standardV4.js +443 -0
  249. package/src/crypto/standardV5.js +306 -0
  250. package/src/crypto/standardV6.js +334 -0
  251. package/src/destination/destination.js +183 -0
  252. package/src/document/builder.js +618 -0
  253. package/src/document/catalog.js +100 -0
  254. package/src/document/document.js +472 -0
  255. package/src/document/encryptedWriter.js +554 -0
  256. package/src/document/incrementalWriter.js +514 -0
  257. package/src/document/page.js +131 -0
  258. package/src/document/pages.js +103 -0
  259. package/src/document/resources.js +146 -0
  260. package/src/document/writer.js +211 -0
  261. package/src/document/xrefStreamWriter.js +353 -0
  262. package/src/embedded/collection.js +102 -0
  263. package/src/embedded/embeddedFile.js +99 -0
  264. package/src/embedded/fileSpec.js +137 -0
  265. package/src/errors.js +78 -0
  266. package/src/extra/3d-richmedia.js +171 -0
  267. package/src/extra/annot-extended.js +200 -0
  268. package/src/extra/associated-files.js +131 -0
  269. package/src/extra/ccitt-fax-decoder.js +776 -0
  270. package/src/extra/color-spaces-extended.js +196 -0
  271. package/src/extra/content-ops-extended.js +153 -0
  272. package/src/extra/document-parts.js +149 -0
  273. package/src/extra/embedded-files-portfolio.js +234 -0
  274. package/src/extra/font-cid-typed.js +185 -0
  275. package/src/extra/font-color-tagging.js +144 -0
  276. package/src/extra/form-actions-extended.js +196 -0
  277. package/src/extra/info-dict-deprecated.js +137 -0
  278. package/src/extra/jbig2-read.js +169 -0
  279. package/src/extra/legacy-deprecated-annots.js +198 -0
  280. package/src/extra/legacy-deprecated-filters.js +167 -0
  281. package/src/extra/legacy-rc4-read.js +235 -0
  282. package/src/extra/legacy-xfa-read.js +104 -0
  283. package/src/extra/linearization-write.js +97 -0
  284. package/src/extra/misc.js +217 -0
  285. package/src/extra/optional-content-extended.js +142 -0
  286. package/src/extra/pdf-a-output-intent.js +112 -0
  287. package/src/extra/pdf-sandbox.js +88 -0
  288. package/src/extra/pdf-ua-tagged.js +116 -0
  289. package/src/extra/pdf-x-prepress.js +114 -0
  290. package/src/extra/redaction-iso32005.js +136 -0
  291. package/src/extra/shading-typed.js +222 -0
  292. package/src/extra/sig-aes-gcm.js +135 -0
  293. package/src/extra/sig-pades.js +242 -0
  294. package/src/extra/tagged-pdf-typed.js +203 -0
  295. package/src/extra/transparency-typed.js +135 -0
  296. package/src/extra/well-tagged-pdf.js +138 -0
  297. package/src/extra/xmp-extended.js +190 -0
  298. package/src/font/embed.js +480 -0
  299. package/src/font/encoding.js +92 -0
  300. package/src/font/font.js +101 -0
  301. package/src/font/type3.js +75 -0
  302. package/src/form/acroform.js +94 -0
  303. package/src/form/appearance.js +90 -0
  304. package/src/form/button.js +105 -0
  305. package/src/form/choice.js +152 -0
  306. package/src/form/fieldTree.js +120 -0
  307. package/src/form/signature.js +100 -0
  308. package/src/form/text.js +101 -0
  309. package/src/linearization/linearization.js +107 -0
  310. package/src/main.js +411 -0
  311. package/src/metadata/info.js +87 -0
  312. package/src/metadata/xmp.js +62 -0
  313. package/src/ocg/config.js +156 -0
  314. package/src/ocg/ocg.js +124 -0
  315. package/src/outline/outline.js +157 -0
  316. package/src/pdf.js +133 -0
  317. package/src/prepress/outputIntent.js +118 -0
  318. package/src/prepress/pageBoundary.js +108 -0
  319. package/src/sig/byteRange.js +306 -0
  320. package/src/sig/certChain.js +247 -0
  321. package/src/sig/dss.js +317 -0
  322. package/src/sig/oids.js +157 -0
  323. package/src/sig/sha1.js +142 -0
  324. package/src/sig/sign.js +1899 -0
  325. package/src/sig/signature.js +1441 -0
  326. package/src/sig/timestamp.js +236 -0
  327. package/src/syntax/crossRefStream.js +133 -0
  328. package/src/syntax/filters/ascii85.js +122 -0
  329. package/src/syntax/filters/asciiHex.js +83 -0
  330. package/src/syntax/filters/dispatch.js +176 -0
  331. package/src/syntax/filters/flate.js +316 -0
  332. package/src/syntax/filters/runLength.js +96 -0
  333. package/src/syntax/objStream.js +99 -0
  334. package/src/syntax/parser-obj.js +52 -0
  335. package/src/syntax/parser.js +321 -0
  336. package/src/syntax/serializer.js +221 -0
  337. package/src/syntax/tokenizer.js +290 -0
  338. package/src/syntax/trailer.js +76 -0
  339. package/src/syntax/xref.js +341 -0
  340. package/src/tagged/classMap.js +81 -0
  341. package/src/tagged/markedContent.js +123 -0
  342. package/src/tagged/parentTree.js +126 -0
  343. package/src/tagged/roleMap.js +107 -0
  344. package/src/tagged/structElement.js +138 -0
  345. package/src/tagged/structTree.js +94 -0
@@ -0,0 +1,157 @@
1
+ ---
2
+ module: pdfFontEmbed
3
+ category: pdf/font
4
+ dependencies: [pdfErrors, embedSubsetForPdf, embedFontDescriptor, embedCidSystemInfo, embedToUnicodeBuilder]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfFontEmbed
11
+
12
+ > Adapter between `@awacloud/fonts/embed-pdf` and PDF dicts — ISO 32000-2 §9.6 / §9.7 / §9.10.
13
+
14
+ **Module** `pdfFontEmbed` | **Source** `packages/front/office/pdf/src/font/embed.js` | **Deps** `pdfErrors`, `embedSubsetForPdf`, `embedFontDescriptor`, `embedCidSystemInfo`, `embedToUnicodeBuilder` | **Worker-safe** yes
15
+
16
+ The only file in `@awacloud/pdf` that knows about `@awacloud/fonts/embed-pdf`. It takes an already-parsed font (the output of `fonts.read(bytes)`) plus a set of code points, and produces the PDF dicts needed to embed a **subset** of that font — either simple (`/TrueType` + `/WinAnsiEncoding`) or composite (`/Type0` + `/Identity-H` + `/CIDFontType2`). The subsetting itself is delegated to `subsetForPdf`; this module exists so the writer's call sites don't re-derive the wiring.
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const emb = runtime.resolve('pdfFontEmbed');
22
+ // Returns: { embedSimple, embedCid }
23
+ ```
24
+
25
+ ## API
26
+
27
+ | Method | Signature | Returns |
28
+ |--------|-----------|---------|
29
+ | `embedSimple` | `(parsedFont, codePoints, opts?) => SimpleEmbed` | `/TrueType` + `/WinAnsiEncoding`. Every code point must be CP1252-representable. |
30
+ | `embedCid` | `(parsedFont, codePoints, opts?) => CidEmbed` | `/Type0` + `/Identity-H` with a `/CIDFontType2` descendant. Any Unicode code point. |
31
+
32
+ `parsedFont` must be a real parsed `Font` — `unicodeMap`, `glyphIndexForCodePoint`, `advanceWidth` and a numeric `unitsPerEm` are all read. `codePoints` is any iterable of integers; it is de-duplicated and sorted, and the sorted array is echoed back as `codePoints`. `opts` is forwarded to `subsetForPdf` (`embedCid` adds `{ cid: true }`).
33
+
34
+ The factory validates at construction that its four injected `@awacloud/fonts/embed-pdf` helpers (`subsetForPdf`, `buildFontDescriptor`, `buildCidSystemInfo`, `embedBuildToUnicode`) are functions, throwing `ContractError` otherwise.
35
+
36
+ ## What the adapter consumes
37
+
38
+ `subsetForPdf(font, codePoints, opts?)` returns exactly eight keys — `subsetBytes`, `gidMap`, `glyphMap`, `encoding`, `widths`, `toUnicodeCmap`, `postScriptName`, `fontDescriptor`. The adapter reads all of them except `encoding` (always `null`: under `Identity-H` the encoding is the cmap). A unit-tier **contract-shape guard** (`src/font/embed.test.js`) resolves the REAL `embedSubsetForPdf` through a `ModuleRuntime` and asserts that key set, so the stub can never drift from the package again.
39
+
40
+ Two conversions happen here and nowhere else:
41
+
42
+ - **Widths.** `subset.widths` is indexed by NEW gid and expressed in **font units**. Everything this module emits (`/Widths`, `/W`, `widthOf`) is `round(w * 1000 / unitsPerEm)`.
43
+ - **`/ToUnicode` source.** A `/ToUnicode` CMap is keyed by *character code*. For `embedCid` the code IS the CID (= the subset's new gid), which is exactly how `subset.toUnicodeCmap` is keyed — it is used verbatim. For `embedSimple` the codes are WinAnsi **bytes**, so the gid-keyed CMap would be wrong; the adapter builds the byte-keyed map and passes it to `embedBuildToUnicode` with `{ codeBytes: 1 }`, so the CMap declares a one-byte codespace (`<00> <FF>`) and 2-hex-digit codes; `embedCid` keeps the 2-byte default. Never both for one route.
44
+
45
+ ## The consumer's contract — the descriptor carries no font program
46
+
47
+ `buildFontDescriptor` puts the raw subset bytes in `FontFile2` (TrueType) or `FontFile3` (CFF). The adapter **lifts them out**: the returned `descriptor` dict has no font-program key, and the bytes come back as `fontFile` with the key name in `fontFileKey`. The consumer must:
48
+
49
+ 1. allocate the font program as a **stream indirect** whose dict carries `/Length1 = fontFile.length` (the serializer adds `/Length`), and set `descriptor.entries[fontFileKey]` to that ref;
50
+ 2. allocate `toUnicodeStream` as a stream indirect too and set the font dict's `ToUnicode` to that ref — `pdfSerializer` refuses an inline stream (`pdf/serializer/inline-stream`).
51
+
52
+ The font dict itself may be written inline or as an indirect; the descriptor nests fine inside it.
53
+
54
+ Do this wiring in **new** dicts — spread the result's `entries` into a fresh
55
+ `obj.dict({ … })` and add the references there — rather than by assigning into
56
+ the result's own dicts. The embed result is then left untouched and can be
57
+ reused for another document (or another page tree) as is.
58
+ [`pdfBuilder`](../document/builder.md)'s `addFont({ name, embedded })` does
59
+ exactly this wiring for you: it copies the entries into new dicts, never
60
+ mutates the result, and allocates its indirects per document.
61
+
62
+ ### Shape `SimpleEmbed`
63
+
64
+ ```js
65
+ {
66
+ subtype: 'TrueType',
67
+ fontDict: typed dict (Type/Subtype/BaseFont/Encoding/FirstChar/LastChar/Widths/FontDescriptor/ToUnicode),
68
+ descriptor: typed dict — no FontFile2/FontFile3 key,
69
+ toUnicodeStream: typed stream (byte-keyed CMap),
70
+ fontFile: Uint8Array — the subset font program,
71
+ fontFileKey: 'FontFile2' | 'FontFile3',
72
+ encode(text): Uint8Array — one WinAnsi byte per code point,
73
+ widthOf(cp): number — 1000/em, 0 when the cp is not embedded,
74
+ codePoints: number[] — de-duplicated, ascending
75
+ }
76
+ ```
77
+
78
+ `BaseFont` is the subsetter's `postScriptName` (already `ABCDEF+Family`). `FirstChar`/`LastChar` are the min/max WinAnsi bytes of the embedded set, and `Widths` covers `[FirstChar..LastChar]` with `0` in the unused slots.
79
+
80
+ ### Shape `CidEmbed`
81
+
82
+ ```js
83
+ {
84
+ type0Dict: typed dict (Type/Subtype:Type0/BaseFont/Encoding:Identity-H/DescendantFonts/ToUnicode),
85
+ cidFontDict: typed dict (Subtype:CIDFontType2/CIDSystemInfo/FontDescriptor/DW/W/CIDToGIDMap:Identity),
86
+ descriptor: typed dict — no FontFile2/FontFile3 key,
87
+ toUnicodeStream: typed stream (CID-keyed CMap),
88
+ fontFile: Uint8Array,
89
+ fontFileKey: 'FontFile2' | 'FontFile3',
90
+ encode(text): Uint8Array — 2 big-endian bytes (the CID) per code point;
91
+ an unknown cp becomes CID 0 (.notdef) and bumps `encode.missing`,
92
+ widthOf(cp): number — 1000/em, 0 when the cp is not embedded,
93
+ codePoints: number[]
94
+ }
95
+ ```
96
+
97
+ The subset is renumbered, so **CID === new gid** and `/CIDToGIDMap` is `/Identity`. `/DW` is `1000`; `/W` is the compact `[c [w …] …]` form over the subset's gids.
98
+
99
+ ## Examples
100
+
101
+ ### Simple embed (`/TrueType` + `/WinAnsiEncoding`)
102
+
103
+ ```js
104
+ const emb = runtime.resolve('pdfFontEmbed');
105
+ const { obj } = runtime.resolve('pdfParserObj');
106
+
107
+ const e = emb.embedSimple(parsedFont, [...'Hello'].map(c => c.codePointAt(0)));
108
+
109
+ // Clone, don't mutate: new dicts carry the two stream references,
110
+ // `e` itself stays reusable for another document.
111
+ const descriptor = obj.dict({ ...e.descriptor.entries, [e.fontFileKey]: obj.ref(6, 0) });
112
+ const fontDict = obj.dict({ ...e.fontDict.entries, FontDescriptor: descriptor, ToUnicode: obj.ref(7, 0) });
113
+
114
+ const indirects = [
115
+ /* … catalog, pages, page, contents … */
116
+ { num: 5, gen: 0, value: fontDict },
117
+ { num: 6, gen: 0, value: obj.stream(obj.dict({ Length1: obj.int(e.fontFile.length) }), e.fontFile) },
118
+ { num: 7, gen: 0, value: obj.stream(obj.dict({}), e.toUnicodeStream.raw) }
119
+ ];
120
+
121
+ // Content stream: the show-string is what `encode` produced.
122
+ e.encode('Hello'); // Uint8Array [0x48, 0x65, 0x6C, 0x6C, 0x6F]
123
+ e.widthOf(0x48); // advance width of 'H' in 1000/em, never font units
124
+ ```
125
+
126
+ ### CID embed (composite `/Type0`)
127
+
128
+ ```js
129
+ const e = emb.embedCid(parsedFont, [...'Uni é fi'].map(c => c.codePointAt(0)));
130
+
131
+ const descriptor = obj.dict({ ...e.descriptor.entries, [e.fontFileKey]: obj.ref(6, 0) });
132
+ const cidFont = obj.dict({ ...e.cidFontDict.entries, FontDescriptor: descriptor });
133
+ const type0 = obj.dict({ ...e.type0Dict.entries,
134
+ DescendantFonts: obj.array([cidFont]),
135
+ ToUnicode: obj.ref(7, 0) });
136
+ // font program at 6 and e.toUnicodeStream at 7, as in the simple route
137
+
138
+ const codes = e.encode('Uni é fi'); // 2 bytes per code point, big-endian CIDs
139
+ e.encode.missing; // 0 — every cp was in the subset
140
+ ```
141
+
142
+ ## Errors
143
+
144
+ | Code | Class | When |
145
+ |------|--------|------|
146
+ | `pdf/embed/missing-fonts-embed` | `ContractError` | The injected `@awacloud/fonts/embed-pdf` helpers are absent or don't supply the 4 required functions (thrown at factory time). |
147
+ | `pdf/embed/bad-font` | `ContractError` | `parsedFont` is not a parsed `Font` (missing `unicodeMap` / `glyphIndexForCodePoint` / `advanceWidth` / numeric `unitsPerEm`). |
148
+ | `pdf/embed/bad-codepoints` | `ContractError` | `codePoints` is not iterable, is empty, or holds a non-integer / out-of-range value (`context.cp`). |
149
+ | `pdf/embed/not-winansi` | `ContractError` | `embedSimple` was given a code point outside CP1252 (`context.cp`) — use `embedCid`. Also thrown by `SimpleEmbed.encode` for a character outside the embedded set. |
150
+
151
+ ## See also
152
+
153
+ - [`pdfFont`](./font.md) — read-side typing.
154
+ - [`pdfFontEncoding`](./encoding.md) — `/Encoding` resolution.
155
+ - [`pdfWriter`](../document/writer.md) — consumes the payload.
156
+ - [`parser-obj`](../syntax/parser-obj.md) — `obj.*` constructors.
157
+ - `tests/font-embed-real.integration.test.js` — both routes written and read back against a REAL parsed font.
@@ -0,0 +1,95 @@
1
+ ---
2
+ module: pdfFontEncoding
3
+ category: pdf/font
4
+ dependencies: [pdfErrors]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfFontEncoding
11
+
12
+ > Resolution of a simple font's `/Encoding` entry — ISO 32000-2 §9.6.5.
13
+
14
+ **Module** `pdfFontEncoding` | **Source** `packages/front/office/pdf/src/font/encoding.js` | **Deps** `pdfErrors` | **Worker-safe** yes
15
+
16
+ Builds a 256-entry table of **glyph names** (or `null` for unmapped slots) from a PDF `/Encoding` entry. Three accepted shapes:
17
+
18
+ - **absent** → `StandardEncoding`.
19
+ - **name**: `/WinAnsiEncoding`, `/MacRomanEncoding`, `/MacExpertEncoding`, `/StandardEncoding`, `/SymbolEncoding`, `/ZapfDingbatsEncoding`.
20
+ - **dict**: `{ BaseEncoding?: name, Differences?: array }` — overlays slots on top of the base table.
21
+
22
+ The module is **pure**: it does not know the named tables themselves. The caller passes `lookupNamed` (typically `@awacloud/fonts/encodings#lookupEncoding`).
23
+
24
+ ## Resolve
25
+
26
+ ```js
27
+ const enc = runtime.resolve('pdfFontEncoding');
28
+ // Returns: { resolveEncoding }
29
+ ```
30
+
31
+ ## API
32
+
33
+ | Method | Signature | Returns |
34
+ |--------|-----------|---------|
35
+ | `resolveEncoding` | `(entry, lookupNamed) => Array<string\|null>` | 256-entry table of glyph names. |
36
+
37
+ ### `Differences` format (§9.6.5.4)
38
+
39
+ Array interleaving ints (starting slot) and names (consecutive glyphs):
40
+
41
+ ```
42
+ [ 1 /a /b /c 65 /A /B ]
43
+ └─ slot 1=a, 2=b, 3=c
44
+ └─ slot 65=A, 66=B
45
+ ```
46
+
47
+ ## Examples
48
+
49
+ ### Named encoding
50
+
51
+ ```js
52
+ const enc = runtime.resolve('pdfFontEncoding');
53
+ const table = enc.resolveEncoding(
54
+ { type: 'name', value: 'WinAnsiEncoding' },
55
+ lookupNamed
56
+ );
57
+ table[0x41]; // 'A'
58
+ table[0x80]; // 'Euro' (WinAnsi)
59
+ ```
60
+
61
+ ### Encoding with Differences
62
+
63
+ ```js
64
+ const entry = obj.dict({
65
+ BaseEncoding: obj.name('WinAnsiEncoding'),
66
+ Differences: obj.array([
67
+ obj.int(1), obj.name('exclamdown'), obj.name('cent')
68
+ ])
69
+ });
70
+ const table = enc.resolveEncoding(entry, lookupNamed);
71
+ table[1]; // 'exclamdown'
72
+ table[2]; // 'cent'
73
+ ```
74
+
75
+ ### Absent encoding → Standard
76
+
77
+ ```js
78
+ const table = enc.resolveEncoding(null, lookupNamed);
79
+ // → StandardEncoding
80
+ ```
81
+
82
+ ## Errors
83
+
84
+ | Code | Class | When |
85
+ |------|--------|------|
86
+ | `pdf/encoding/bad-base` | `ParseError` | `/BaseEncoding` is not a name. |
87
+ | `pdf/encoding/bad-shape` | `ParseError` | `/Encoding` is neither a name nor a dict. |
88
+ | `pdf/encoding/bad-differences` | `ParseError` | `/Differences` is not an array. |
89
+ | `pdf/encoding/bad-differences-entry` | `ParseError` | A `/Differences` entry is neither int nor name. |
90
+
91
+ ## See also
92
+
93
+ - [`pdfFont`](./font.md) — carries the `encoding` field.
94
+ - [`pdfType3`](./type3.md) — accepts the same format.
95
+ - [`pdfText`](../content/text.md) — `extractText` consumes the mapping.
@@ -0,0 +1,97 @@
1
+ ---
2
+ module: pdfFont
3
+ category: pdf/font
4
+ dependencies: [pdfErrors, pdfParser]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfFont
11
+
12
+ > Typing of a PDF Font dict — ISO 32000-2 §9.6 / §9.7.
13
+
14
+ **Module** `pdfFont` | **Source** `packages/front/office/pdf/src/font/font.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
15
+
16
+ This module **does not parse font files** — all PFB/PFA, TrueType/OpenType, CFF, CIDFont byte reading is delegated to `@awacloud/fonts`. Here we only type the Font **dictionary** (Type, Subtype, BaseFont, Encoding, FirstChar, LastChar, Widths, FontDescriptor, ToUnicode, DescendantFonts) and classify the font among `Type0`, `Type1`, `MMType1`, `Type3`, `TrueType`, `CIDFontType0`, `CIDFontType2`. A Standard 14 fallback is available if the caller supplies `opts.standard14` (`isStandard14` / `lookupStandard14` lookup).
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const f = runtime.resolve('pdfFont');
22
+ // Returns: { typeFont, resolveDescendant }
23
+ ```
24
+
25
+ ## API
26
+
27
+ | Method | Signature | Returns |
28
+ |--------|-----------|---------|
29
+ | `typeFont` | `(dict, opts?: { standard14 }) => Font` | Typing. |
30
+ | `resolveDescendant` | `(type0Font, resolveRef) => Font \| null` | Reads the descendant CIDFont of a Type0. |
31
+
32
+ ### Shape `Font`
33
+
34
+ ```js
35
+ {
36
+ subtype: 'Type0'|'Type1'|'MMType1'|'Type3'|'TrueType'|'CIDFontType0'|'CIDFontType2',
37
+ baseFont: string | null,
38
+ encoding: PdfObject | null, // name | dict
39
+ firstChar: int | null,
40
+ lastChar: int | null,
41
+ widths: number[] | null,
42
+ fontDescriptor: PdfObject | null,
43
+ toUnicode: PdfObject | null,
44
+ descendantFonts: PdfObject[] | null,
45
+ standard14: object | null, // set when the fallback triggers
46
+ raw: object
47
+ }
48
+ ```
49
+
50
+ The Standard 14 fallback triggers only when: `subtype ∈ {Type1, MMType1}`, **no** `/FontDescriptor`, and `baseFont` is recognized by `isStandard14`.
51
+
52
+ ## Examples
53
+
54
+ ### Simple typing
55
+
56
+ ```js
57
+ const f = runtime.resolve('pdfFont');
58
+ const font = f.typeFont(resources.Font.F1);
59
+ font.subtype; // 'Type1'
60
+ font.baseFont; // 'Helvetica'
61
+ ```
62
+
63
+ ### Composite Type0 + descendant
64
+
65
+ ```js
66
+ const type0 = f.typeFont(resources.Font.F1);
67
+ if (type0.subtype === 'Type0') {
68
+ const cid = f.resolveDescendant(type0, doc._raw.resolve);
69
+ cid.subtype; // 'CIDFontType2'
70
+ }
71
+ ```
72
+
73
+ ### Standard 14 fallback
74
+
75
+ ```js
76
+ const font = f.typeFont(dict, {
77
+ standard14: runtime.resolve('fontsStandard14')
78
+ });
79
+ font.standard14; // { widths, bbox, italicAngle, ... } | null
80
+ ```
81
+
82
+ ## Errors
83
+
84
+ | Code | Class | When |
85
+ |------|--------|------|
86
+ | `pdf/font/not-dict` | `ParseError` | Argument is not a typed dict. |
87
+ | `pdf/font/bad-type` | `ParseError` | `/Type` present but ≠ `/Font`. |
88
+ | `pdf/font/missing-subtype` | `ParseError` | `/Subtype` absent or not a name. |
89
+ | `pdf/font/unknown-subtype` | `ParseError` | `/Subtype` outside the 7 known values. |
90
+
91
+ ## See also
92
+
93
+ - [`pdfFontEncoding`](./encoding.md) — `/Encoding` resolution.
94
+ - [`pdfType3`](./type3.md) — Type 3 font (PDF-specific).
95
+ - [`pdfFontEmbed`](./embed.md) — write-side adapter.
96
+ - [`pdfText`](../content/text.md) — consumes `subtype` for `extractText`.
97
+ - [`pdfResources`](../document/resources.md) — supplies the dicts.
@@ -0,0 +1,89 @@
1
+ ---
2
+ module: pdfType3
3
+ category: pdf/font
4
+ dependencies: [pdfErrors, pdfParser]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfType3
11
+
12
+ > Typing of a Type 3 font (glyphs defined by content streams) — ISO 32000-2 §9.6.4.
13
+
14
+ **Module** `pdfType3` | **Source** `packages/front/office/pdf/src/font/type3.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
15
+
16
+ Unlike Type1/TrueType/CIDFont (which delegate to `@awacloud/fonts`), Type 3 fonts are **PDF-specific**: each glyph is defined by a content stream in `/CharProcs`. That is why this module lives here rather than in `@awacloud/fonts`. The exposed record carries `bbox`, `matrix` (defaults to `[0.001, 0, 0, 0.001, 0, 0]`), `charProcs`, `encoding`, `firstChar`/`lastChar`/`widths`, `fontDescriptor` (optional in PDF 2.0), and `resources` (local to the glyphs).
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const t3 = runtime.resolve('pdfType3');
22
+ // Returns: { typeType3 }
23
+ ```
24
+
25
+ ## API
26
+
27
+ | Method | Signature | Returns |
28
+ |--------|-----------|---------|
29
+ | `typeType3` | `(dict) => Type3Font` | Typing. |
30
+
31
+ ### Shape `Type3Font`
32
+
33
+ ```js
34
+ {
35
+ subtype: 'Type3',
36
+ bbox: [llx,lly,urx,ury] | null,
37
+ matrix: [0.001,0,0,0.001,0,0], // default
38
+ charProcs: { [glyphName]: PdfObject }, // stream | ref
39
+ encoding: PdfObject | null,
40
+ firstChar: int | null,
41
+ lastChar: int | null,
42
+ widths: number[] | null,
43
+ fontDescriptor: PdfObject | null,
44
+ resources: PdfObject | null,
45
+ raw: object
46
+ }
47
+ ```
48
+
49
+ ## Examples
50
+
51
+ ### Typing
52
+
53
+ ```js
54
+ const t3 = runtime.resolve('pdfType3');
55
+ const font = t3.typeType3(resources.Font.F1);
56
+ font.subtype; // 'Type3'
57
+ font.bbox; // [0, 0, 1000, 1000]
58
+ font.matrix; // [0.001, 0, 0, 0.001, 0, 0]
59
+ ```
60
+
61
+ ### Rendering a glyph stream
62
+
63
+ ```js
64
+ const procRef = font.charProcs.a; // ref to a content stream
65
+ const proc = doc._raw.resolve(procRef);
66
+ const ops = runtime.resolve('pdfContentStream').parseContentStream(proc.raw);
67
+ // The first op is usually d0 or d1 (set glyph metrics)
68
+ ```
69
+
70
+ ### Encoding via the dedicated module
71
+
72
+ ```js
73
+ const enc = runtime.resolve('pdfFontEncoding');
74
+ const table = enc.resolveEncoding(font.encoding, lookupNamed);
75
+ ```
76
+
77
+ ## Errors
78
+
79
+ | Code | Class | When |
80
+ |------|--------|------|
81
+ | `pdf/type3/not-dict` | `ParseError` | Argument is not a typed dict. |
82
+ | `pdf/type3/wrong-subtype` | `ParseError` | `/Subtype` absent, not a name, or ≠ `/Type3`. |
83
+
84
+ ## See also
85
+
86
+ - [`pdfFont`](./font.md) — generic typing (other subtypes).
87
+ - [`pdfFontEncoding`](./encoding.md) — `/Encoding` resolution.
88
+ - [`pdfContentStream`](../content/stream.md) — parses `CharProcs`.
89
+ - [`pdfContentOps`](../content/ops.md) — `d0` / `d1` Type3 ops.
@@ -0,0 +1,35 @@
1
+ # Form — ISO 32000-2 §12.7 / §12.5.5
2
+
3
+ Interactive forms (AcroForm) layer: root dict typing, field-tree walk, typing by `/FT`, and `/AP` appearance streams.
4
+
5
+ | Module | Returns | Deps | Description |
6
+ |--------|----------|------|-------------|
7
+ | [`pdfAcroForm`](./acroform.md) | `{ typeAcroForm }` | `pdfErrors`, `pdfParser` | `/AcroForm` dict, §12.7.3. |
8
+ | [`pdfFieldTree`](./fieldTree.md) | `{ walkFieldTree, getInherited }` | `pdfErrors`, `pdfParser` | Walk + inheritance, §12.7.4. |
9
+ | [`pdfButtonField`](./button.md) | `{ typeButtonField }` | `pdfErrors`, `pdfParser` | `/FT /Btn`, §12.7.5.2. |
10
+ | [`pdfTextField`](./text.md) | `{ typeTextField }` | `pdfErrors`, `pdfParser` | `/FT /Tx`, §12.7.5.3. |
11
+ | [`pdfChoiceField`](./choice.md) | `{ typeChoiceField }` | `pdfErrors`, `pdfParser` | `/FT /Ch`, §12.7.5.4. |
12
+ | [`pdfSignatureField`](./signature.md) | `{ typeSignatureField }` | `pdfErrors`, `pdfParser` | `/FT /Sig`, §12.7.5.5. |
13
+ | [`pdfAppearance`](./appearance.md) | `{ typeAppearanceStreams, listPopulatedSlots }` | `pdfErrors`, `pdfParser` | `/AP`, §12.5.5. |
14
+
15
+ ## Common pattern
16
+
17
+ ```js
18
+ const af = runtime.resolve('pdfAcroForm').typeAcroForm(doc._raw.resolve(catalog.acroForm));
19
+ const records = runtime.resolve('pdfFieldTree').walkFieldTree(af.fields, doc._raw.resolve);
20
+ for (const r of records.filter(r => r.terminal)) {
21
+ const ft = r.node.entries.FT && r.node.entries.FT.value;
22
+ switch (ft) {
23
+ case 'Btn': runtime.resolve('pdfButtonField').typeButtonField(r.node); break;
24
+ case 'Tx': runtime.resolve('pdfTextField').typeTextField(r.node); break;
25
+ case 'Ch': runtime.resolve('pdfChoiceField').typeChoiceField(r.node); break;
26
+ case 'Sig': runtime.resolve('pdfSignatureField').typeSignatureField(r.node); break;
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## See also
32
+
33
+ - [Document layer](../document/README.md) — `pdfCatalog` carries `/AcroForm`.
34
+ - [Content layer](../content/README.md) — `pdfContentStream` parses appearances.
35
+ - [Syntax layer](../syntax/README.md) — the underlying `pdfParser`.
@@ -0,0 +1,88 @@
1
+ ---
2
+ module: pdfAcroForm
3
+ category: pdf/form
4
+ dependencies: [pdfErrors, pdfParser]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfAcroForm
11
+
12
+ > Typing of the Catalog's `/AcroForm` dict — ISO 32000-2 §12.7.3.
13
+
14
+ **Module** `pdfAcroForm` | **Source** `packages/front/office/pdf/src/form/acroform.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
15
+
16
+ The Catalog's `/AcroForm` describes the interactive-forms layer: root `/Fields`, `/NeedAppearances`, `/SigFlags` (bit 1 = SignaturesExist, bit 2 = AppendOnly), `/CO` (calculation order), `/DR` (default Resources), `/DA` (default appearance), `/Q` (default quadding, 0=left/1=center/2=right). `/XFA` (legacy 1.7) is preserved verbatim in `_extras` for 2.0 fidelity. Any unknown entry is also captured in `_extras`.
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const af = runtime.resolve('pdfAcroForm');
22
+ // Returns: { typeAcroForm }
23
+ ```
24
+
25
+ ## API
26
+
27
+ | Method | Signature | Returns |
28
+ |--------|-----------|---------|
29
+ | `typeAcroForm` | `(dict) => AcroForm` | Typing. |
30
+
31
+ ### Shape `AcroForm`
32
+
33
+ ```js
34
+ {
35
+ fields: Array<{num:number, gen:number}>,
36
+ needAppearances: boolean, // default false
37
+ sigFlags: number, // default 0
38
+ co: Array<{num,gen}>, // calculation order
39
+ dr: object|null, // /DR dict
40
+ da: Uint8Array|null,// /DA bytes
41
+ q: number, // default 0
42
+ raw: object,
43
+ _extras: { [key]: PdfObject } // /XFA + others
44
+ }
45
+ ```
46
+
47
+ `/Fields` is required by §12.7.3 but a degenerate AcroForm dict without it is tolerated (result `[]`).
48
+
49
+ ## Examples
50
+
51
+ ### Typing from the Catalog
52
+
53
+ ```js
54
+ const af = runtime.resolve('pdfAcroForm');
55
+ if (doc.catalog.acroForm) {
56
+ const form = af.typeAcroForm(doc._raw.resolve(doc.catalog.acroForm));
57
+ form.fields.length;
58
+ (form.sigFlags & 1) !== 0; // SignaturesExist
59
+ (form.sigFlags & 2) !== 0; // AppendOnly
60
+ }
61
+ ```
62
+
63
+ ### Walking the roots
64
+
65
+ ```js
66
+ const ft = runtime.resolve('pdfFieldTree');
67
+ const records = ft.walkFieldTree(form.fields, doc._raw.resolve);
68
+ ```
69
+
70
+ ### XFA preservation
71
+
72
+ ```js
73
+ form._extras.XFA; // typed array/stream — passed through as-is to the writer
74
+ ```
75
+
76
+ ## Errors
77
+
78
+ | Code | Class | When |
79
+ |------|--------|------|
80
+ | `pdf/form/acroform/not-dict` | `ParseError` | Argument is not a typed dict. |
81
+ | `pdf/form/acroform/bad-fields` | `ParseError` | `/Fields` is not an array of refs. |
82
+ | `pdf/form/acroform/bad-co` | `ParseError` | `/CO` is not an array of refs. |
83
+
84
+ ## See also
85
+
86
+ - [`pdfFieldTree`](./fieldTree.md) — walks `fields`.
87
+ - [`pdfButtonField`](./button.md), [`pdfTextField`](./text.md), [`pdfChoiceField`](./choice.md), [`pdfSignatureField`](./signature.md) — typing by `/FT`.
88
+ - [`pdfCatalog`](../document/catalog.md) — carries `acroForm`.
@@ -0,0 +1,87 @@
1
+ ---
2
+ module: pdfAppearance
3
+ category: pdf/form
4
+ dependencies: [pdfErrors, pdfParser]
5
+ returns: object
6
+ worker-safe: true
7
+ status: complete
8
+ ---
9
+
10
+ # pdfAppearance
11
+
12
+ > Typing of the `/AP` appearance-streams dict — ISO 32000-2 §12.5.5.
13
+
14
+ **Module** `pdfAppearance` | **Source** `packages/front/office/pdf/src/form/appearance.js` | **Deps** `pdfErrors`, `pdfParser` | **Worker-safe** yes
15
+
16
+ A widget annotation carries an `/AP` with 3 slots: **N** (Normal, required), **R** (Rollover, optional), **D** (Down, optional). Each slot is either a direct stream (or ref), or a sub-dict mapping **state names** (e.g. `/Yes`, `/Off`) to streams — the form used by checkbox/radio, with the current state selected by `/AS`. The module normalizes both shapes to `{ default, states }`.
17
+
18
+ ## Resolve
19
+
20
+ ```js
21
+ const ap = runtime.resolve('pdfAppearance');
22
+ // Returns: { typeAppearanceStreams, listPopulatedSlots }
23
+ ```
24
+
25
+ ## API
26
+
27
+ | Method | Signature | Returns |
28
+ |--------|-----------|---------|
29
+ | `typeAppearanceStreams` | `(dict) => Appearance` | Typing. |
30
+ | `listPopulatedSlots` | `(ap) => Array<'N'\|'R'\|'D'>` | Non-null slots. |
31
+
32
+ ### Shape `Appearance`
33
+
34
+ ```js
35
+ {
36
+ N: { default: stream|ref|null, states: { [stateName]: stream|ref } },
37
+ R: { ... } | null,
38
+ D: { ... } | null,
39
+ raw: object,
40
+ _extras: { [key]: PdfObject }
41
+ }
42
+ ```
43
+
44
+ - If the slot was a bare stream/ref → `default` is set, `states = {}`.
45
+ - If the slot was a sub-dict → `default = null`, `states` populated.
46
+ - `/N` is always present (otherwise `pdf/form/ap/missing-n`).
47
+
48
+ ## Examples
49
+
50
+ ### Stateless (text field)
51
+
52
+ ```js
53
+ const ap = runtime.resolve('pdfAppearance');
54
+ const a = ap.typeAppearanceStreams(widget.entries.AP);
55
+ a.N.default; // typed stream
56
+ a.N.states; // {}
57
+ ```
58
+
59
+ ### Checkbox/radio (with states)
60
+
61
+ ```js
62
+ const a = ap.typeAppearanceStreams(widget.entries.AP);
63
+ const currentState = widget.entries.AS && widget.entries.AS.value; // 'Yes' | 'Off'
64
+ const visualStream = a.N.states[currentState] || a.N.default;
65
+ ```
66
+
67
+ ### Enumeration
68
+
69
+ ```js
70
+ ap.listPopulatedSlots(a); // ['N'] or ['N','R'] or ['N','R','D']
71
+ ```
72
+
73
+ ## Errors
74
+
75
+ | Code | Class | When |
76
+ |------|--------|------|
77
+ | `pdf/form/ap/not-dict` | `ParseError` | Argument is not a typed dict. |
78
+ | `pdf/form/ap/missing-n` | `ParseError` | `/N` absent (Normal slot required). |
79
+ | `pdf/form/ap/bad-state` | `ParseError` | A state entry is neither a stream nor a ref. |
80
+ | `pdf/form/ap/bad-slot` | `ParseError` | An `/N`/`/R`/`/D` slot is neither stream/ref nor a sub-dict. |
81
+
82
+ ## See also
83
+
84
+ - [`pdfButtonField`](./button.md) — checkbox/radio uses the `states`.
85
+ - [`pdfTextField`](./text.md), [`pdfChoiceField`](./choice.md), [`pdfSignatureField`](./signature.md).
86
+ - [`pdfContentStream`](../content/stream.md) — parses the appearance streams.
87
+ - [`pdfImages`](../content/images.md) — typing of the underlying Form XObjects.