@laminapdf/sdk 0.0.0-stage → 0.2.0-alpha.3

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 (478) hide show
  1. package/README.md +243 -2
  2. package/dist/api.d.ts +26 -0
  3. package/dist/api.d.ts.map +1 -0
  4. package/dist/api.js +12 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/builder.d.ts +335 -0
  7. package/dist/builder.d.ts.map +1 -0
  8. package/dist/builder.js +574 -0
  9. package/dist/builder.js.map +1 -0
  10. package/dist/defined.d.ts +5 -0
  11. package/dist/defined.d.ts.map +1 -0
  12. package/dist/defined.js +7 -0
  13. package/dist/defined.js.map +1 -0
  14. package/dist/document.d.ts +267 -0
  15. package/dist/document.d.ts.map +1 -0
  16. package/dist/document.js +472 -0
  17. package/dist/document.js.map +1 -0
  18. package/dist/entry/node.d.ts +30 -0
  19. package/dist/entry/node.d.ts.map +1 -0
  20. package/dist/entry/node.js +37 -0
  21. package/dist/entry/node.js.map +1 -0
  22. package/dist/entry/workerd.d.ts +30 -0
  23. package/dist/entry/workerd.d.ts.map +1 -0
  24. package/dist/entry/workerd.js +37 -0
  25. package/dist/entry/workerd.js.map +1 -0
  26. package/dist/errors.d.ts +102 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +131 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/explain.d.ts +20 -0
  31. package/dist/explain.d.ts.map +1 -0
  32. package/dist/explain.js +14 -0
  33. package/dist/explain.js.map +1 -0
  34. package/dist/extract.d.ts +57 -0
  35. package/dist/extract.d.ts.map +1 -0
  36. package/dist/extract.js +5 -0
  37. package/dist/extract.js.map +1 -0
  38. package/dist/font.d.ts +73 -0
  39. package/dist/font.d.ts.map +1 -0
  40. package/dist/font.js +133 -0
  41. package/dist/font.js.map +1 -0
  42. package/dist/generated/builder-enums.d.ts +29 -0
  43. package/dist/generated/builder-enums.d.ts.map +1 -0
  44. package/dist/generated/builder-enums.js +80 -0
  45. package/dist/generated/builder-enums.js.map +1 -0
  46. package/dist/generated/codes.d.ts +109 -0
  47. package/dist/generated/codes.d.ts.map +1 -0
  48. package/dist/generated/codes.js +508 -0
  49. package/dist/generated/codes.js.map +1 -0
  50. package/dist/generated/explain.d.ts +6 -0
  51. package/dist/generated/explain.d.ts.map +1 -0
  52. package/dist/generated/explain.js +155 -0
  53. package/dist/generated/explain.js.map +1 -0
  54. package/dist/generated/extract.d.ts +235 -0
  55. package/dist/generated/extract.d.ts.map +1 -0
  56. package/dist/generated/extract.js +4 -0
  57. package/dist/generated/extract.js.map +1 -0
  58. package/dist/index.d.ts +30 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +37 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/init.d.ts +88 -0
  63. package/dist/init.d.ts.map +1 -0
  64. package/dist/init.js +139 -0
  65. package/dist/init.js.map +1 -0
  66. package/dist/internal/handle.d.ts +58 -0
  67. package/dist/internal/handle.d.ts.map +1 -0
  68. package/dist/internal/handle.js +113 -0
  69. package/dist/internal/handle.js.map +1 -0
  70. package/dist/internal/instance.d.ts +56 -0
  71. package/dist/internal/instance.d.ts.map +1 -0
  72. package/dist/internal/instance.js +125 -0
  73. package/dist/internal/instance.js.map +1 -0
  74. package/dist/loader/fetch.d.ts +3 -0
  75. package/dist/loader/fetch.d.ts.map +1 -0
  76. package/dist/loader/fetch.js +2 -0
  77. package/dist/loader/fetch.js.map +1 -0
  78. package/dist/loader/node.d.ts +3 -0
  79. package/dist/loader/node.d.ts.map +1 -0
  80. package/dist/loader/node.js +9 -0
  81. package/dist/loader/node.js.map +1 -0
  82. package/dist/loader/workerd.d.ts +3 -0
  83. package/dist/loader/workerd.d.ts.map +1 -0
  84. package/dist/loader/workerd.js +15 -0
  85. package/dist/loader/workerd.js.map +1 -0
  86. package/dist/matrix.d.ts +16 -0
  87. package/dist/matrix.d.ts.map +1 -0
  88. package/dist/matrix.js +36 -0
  89. package/dist/matrix.js.map +1 -0
  90. package/dist/path.d.ts +34 -0
  91. package/dist/path.d.ts.map +1 -0
  92. package/dist/path.js +49 -0
  93. package/dist/path.js.map +1 -0
  94. package/dist/source/http.d.ts +36 -0
  95. package/dist/source/http.d.ts.map +1 -0
  96. package/dist/source/http.js +211 -0
  97. package/dist/source/http.js.map +1 -0
  98. package/dist/source/range.d.ts +75 -0
  99. package/dist/source/range.d.ts.map +1 -0
  100. package/dist/source/range.js +100 -0
  101. package/dist/source/range.js.map +1 -0
  102. package/dist/text.d.ts +90 -0
  103. package/dist/text.d.ts.map +1 -0
  104. package/dist/text.js +127 -0
  105. package/dist/text.js.map +1 -0
  106. package/dist/transaction.d.ts +36 -0
  107. package/dist/transaction.d.ts.map +1 -0
  108. package/dist/transaction.js +47 -0
  109. package/dist/transaction.js.map +1 -0
  110. package/dist/types.d.ts +79 -0
  111. package/dist/types.d.ts.map +1 -0
  112. package/dist/types.js +2 -0
  113. package/dist/types.js.map +1 -0
  114. package/dist/version.d.ts +3 -0
  115. package/dist/version.d.ts.map +1 -0
  116. package/dist/version.js +6 -0
  117. package/dist/version.js.map +1 -0
  118. package/dist/worker/client.d.ts +88 -0
  119. package/dist/worker/client.d.ts.map +1 -0
  120. package/dist/worker/client.js +407 -0
  121. package/dist/worker/client.js.map +1 -0
  122. package/dist/worker/emitter.d.ts +12 -0
  123. package/dist/worker/emitter.d.ts.map +1 -0
  124. package/dist/worker/emitter.js +34 -0
  125. package/dist/worker/emitter.js.map +1 -0
  126. package/dist/worker/entry.d.ts +2 -0
  127. package/dist/worker/entry.d.ts.map +1 -0
  128. package/dist/worker/entry.js +4 -0
  129. package/dist/worker/entry.js.map +1 -0
  130. package/dist/worker/index.d.ts +7 -0
  131. package/dist/worker/index.d.ts.map +1 -0
  132. package/dist/worker/index.js +4 -0
  133. package/dist/worker/index.js.map +1 -0
  134. package/dist/worker/protocol.d.ts +82 -0
  135. package/dist/worker/protocol.d.ts.map +1 -0
  136. package/dist/worker/protocol.js +11 -0
  137. package/dist/worker/protocol.js.map +1 -0
  138. package/dist/worker/server.d.ts +51 -0
  139. package/dist/worker/server.d.ts.map +1 -0
  140. package/dist/worker/server.js +493 -0
  141. package/dist/worker/server.js.map +1 -0
  142. package/dist/worker/support.d.ts +43 -0
  143. package/dist/worker/support.d.ts.map +1 -0
  144. package/dist/worker/support.js +26 -0
  145. package/dist/worker/support.js.map +1 -0
  146. package/dist/worker/transfer.d.ts +3 -0
  147. package/dist/worker/transfer.d.ts.map +1 -0
  148. package/dist/worker/transfer.js +13 -0
  149. package/dist/worker/transfer.js.map +1 -0
  150. package/dist/worker/types.d.ts +50 -0
  151. package/dist/worker/types.d.ts.map +1 -0
  152. package/dist/worker/types.js +2 -0
  153. package/dist/worker/types.js.map +1 -0
  154. package/docs/AGENTS.md +14 -0
  155. package/docs/api/README.md +147 -0
  156. package/docs/api/classes/Builder.md +467 -0
  157. package/docs/api/classes/Document.md +742 -0
  158. package/docs/api/classes/Font.md +74 -0
  159. package/docs/api/classes/Image.md +140 -0
  160. package/docs/api/classes/LaminaPdfError.md +189 -0
  161. package/docs/api/classes/Page.md +178 -0
  162. package/docs/api/classes/PageRef.md +253 -0
  163. package/docs/api/classes/PageText.md +129 -0
  164. package/docs/api/classes/PageTextRun.md +167 -0
  165. package/docs/api/classes/PendingPath.md +97 -0
  166. package/docs/api/classes/SaveJob.md +205 -0
  167. package/docs/api/classes/Surface.md +326 -0
  168. package/docs/api/classes/Transaction.md +111 -0
  169. package/docs/api/functions/callbackSource.md +33 -0
  170. package/docs/api/functions/httpRangeSource.md +48 -0
  171. package/docs/api/functions/init.md +36 -0
  172. package/docs/api/functions/isExtractLoaded.md +21 -0
  173. package/docs/api/functions/isInitialized.md +19 -0
  174. package/docs/api/functions/isLaminaPdfError.md +41 -0
  175. package/docs/api/functions/isTextLoaded.md +19 -0
  176. package/docs/api/functions/loadExtract.md +28 -0
  177. package/docs/api/functions/loadText.md +28 -0
  178. package/docs/api/functions/onLeak.md +29 -0
  179. package/docs/api/functions/reset.md +22 -0
  180. package/docs/api/functions/wasmMemory.md +22 -0
  181. package/docs/api/interfaces/BuilderOptions.md +108 -0
  182. package/docs/api/interfaces/ByteRange.md +29 -0
  183. package/docs/api/interfaces/ChunkOptions.md +37 -0
  184. package/docs/api/interfaces/Diagnostic.md +67 -0
  185. package/docs/api/interfaces/ExtractOptions.md +92 -0
  186. package/docs/api/interfaces/ExtractResult.md +37 -0
  187. package/docs/api/interfaces/FontInfo.md +37 -0
  188. package/docs/api/interfaces/HttpRangeOptions.md +78 -0
  189. package/docs/api/interfaces/InitOptions.md +40 -0
  190. package/docs/api/interfaces/Leak.md +21 -0
  191. package/docs/api/interfaces/Location.md +53 -0
  192. package/docs/api/interfaces/OpLog.md +25 -0
  193. package/docs/api/interfaces/OpenOptions.md +37 -0
  194. package/docs/api/interfaces/PageTextOptions.md +21 -0
  195. package/docs/api/interfaces/PathBuilder.md +195 -0
  196. package/docs/api/interfaces/QuadPoint.md +25 -0
  197. package/docs/api/interfaces/RangeOptions.md +54 -0
  198. package/docs/api/interfaces/RangeSource.md +59 -0
  199. package/docs/api/interfaces/StrokeStyle.md +61 -0
  200. package/docs/api/interfaces/TagSpec.md +69 -0
  201. package/docs/api/interfaces/TextBoxOptions.md +93 -0
  202. package/docs/api/interfaces/TextGlyph.md +29 -0
  203. package/docs/api/interfaces/TextOptions.md +101 -0
  204. package/docs/api/interfaces/WasmMemory.md +37 -0
  205. package/docs/api/type-aliases/AfRelationship.md +15 -0
  206. package/docs/api/type-aliases/Align.md +15 -0
  207. package/docs/api/type-aliases/ArtifactKind.md +15 -0
  208. package/docs/api/type-aliases/AttachmentOptions.md +15 -0
  209. package/docs/api/type-aliases/BlendMode.md +15 -0
  210. package/docs/api/type-aliases/BoxRect.md +15 -0
  211. package/docs/api/type-aliases/BuildOptions.md +15 -0
  212. package/docs/api/type-aliases/Cell.md +71 -0
  213. package/docs/api/type-aliases/Chunk.md +79 -0
  214. package/docs/api/type-aliases/Color.md +16 -0
  215. package/docs/api/type-aliases/Coordinates.md +55 -0
  216. package/docs/api/type-aliases/Direction.md +15 -0
  217. package/docs/api/type-aliases/DocumentInfo.md +15 -0
  218. package/docs/api/type-aliases/DropReason.md +15 -0
  219. package/docs/api/type-aliases/Dropped.md +59 -0
  220. package/docs/api/type-aliases/Edited.md +15 -0
  221. package/docs/api/type-aliases/ErrorCode.md +15 -0
  222. package/docs/api/type-aliases/ErrorKind.md +15 -0
  223. package/docs/api/type-aliases/ExtractFormat.md +15 -0
  224. package/docs/api/type-aliases/ExtractedBlock.md +82 -0
  225. package/docs/api/type-aliases/ExtractedPage.md +65 -0
  226. package/docs/api/type-aliases/ExtractedSource.md +48 -0
  227. package/docs/api/type-aliases/Extraction.md +22 -0
  228. package/docs/api/type-aliases/FillRule.md +15 -0
  229. package/docs/api/type-aliases/Fit.md +15 -0
  230. package/docs/api/type-aliases/Flags.md +15 -0
  231. package/docs/api/type-aliases/Generator.md +41 -0
  232. package/docs/api/type-aliases/GlyphQuad.md +15 -0
  233. package/docs/api/type-aliases/InfoPatch.md +15 -0
  234. package/docs/api/type-aliases/LaminaPdfWarning.md +16 -0
  235. package/docs/api/type-aliases/LimitName.md +15 -0
  236. package/docs/api/type-aliases/Limits.md +15 -0
  237. package/docs/api/type-aliases/LineBox.md +15 -0
  238. package/docs/api/type-aliases/LineCap.md +15 -0
  239. package/docs/api/type-aliases/LineJoin.md +15 -0
  240. package/docs/api/type-aliases/LinkTarget.md +15 -0
  241. package/docs/api/type-aliases/Metadata.md +15 -0
  242. package/docs/api/type-aliases/Op.md +15 -0
  243. package/docs/api/type-aliases/OutlineEntry.md +15 -0
  244. package/docs/api/type-aliases/Overflow.md +15 -0
  245. package/docs/api/type-aliases/PageInfo.md +15 -0
  246. package/docs/api/type-aliases/PageLabel.md +15 -0
  247. package/docs/api/type-aliases/PageSizeName.md +15 -0
  248. package/docs/api/type-aliases/Point.md +15 -0
  249. package/docs/api/type-aliases/Profile.md +15 -0
  250. package/docs/api/type-aliases/Progress.md +15 -0
  251. package/docs/api/type-aliases/ReadingOrder.md +15 -0
  252. package/docs/api/type-aliases/Rect.md +15 -0
  253. package/docs/api/type-aliases/Region.md +31 -0
  254. package/docs/api/type-aliases/RenderMode.md +15 -0
  255. package/docs/api/type-aliases/Rotation.md +15 -0
  256. package/docs/api/type-aliases/SaveOptions.md +15 -0
  257. package/docs/api/type-aliases/SaveReport.md +15 -0
  258. package/docs/api/type-aliases/Span.md +63 -0
  259. package/docs/api/type-aliases/SplitOn.md +15 -0
  260. package/docs/api/type-aliases/Standard14.md +15 -0
  261. package/docs/api/type-aliases/StructRef.md +41 -0
  262. package/docs/api/type-aliases/StructSource.md +17 -0
  263. package/docs/api/type-aliases/TableDetector.md +15 -0
  264. package/docs/api/type-aliases/TableMode.md +15 -0
  265. package/docs/api/type-aliases/TableScope.md +15 -0
  266. package/docs/api/type-aliases/Tag.md +15 -0
  267. package/docs/api/type-aliases/TagName.md +15 -0
  268. package/docs/api/type-aliases/TextLayout.md +15 -0
  269. package/docs/api/type-aliases/TextRange.md +33 -0
  270. package/docs/api/type-aliases/TextRunInfo.md +15 -0
  271. package/docs/api/type-aliases/Transform.md +15 -0
  272. package/docs/api/type-aliases/UndoOutcome.md +15 -0
  273. package/docs/api/type-aliases/ViewerPreferences.md +15 -0
  274. package/docs/api/type-aliases/WarningCode.md +15 -0
  275. package/docs/api/type-aliases/WasmSource.md +16 -0
  276. package/docs/api/variables/Matrix.md +99 -0
  277. package/docs/api/variables/PAGE_SIZES.md +15 -0
  278. package/docs/api/variables/TAG_NAMES.md +15 -0
  279. package/docs/errors/README.md +156 -0
  280. package/docs/errors/aes-padding-invalid.md +34 -0
  281. package/docs/errors/already-initialized.md +34 -0
  282. package/docs/errors/binary-output-to-terminal.md +35 -0
  283. package/docs/errors/builder-finished.md +35 -0
  284. package/docs/errors/cancelled.md +35 -0
  285. package/docs/errors/cmap-invalid.md +42 -0
  286. package/docs/errors/collection-index.md +33 -0
  287. package/docs/errors/color-components.md +33 -0
  288. package/docs/errors/content-bad-operands.md +36 -0
  289. package/docs/errors/content-path-unpainted.md +36 -0
  290. package/docs/errors/content-resource-missing.md +37 -0
  291. package/docs/errors/content-syntax.md +36 -0
  292. package/docs/errors/content-unbalanced-bt.md +36 -0
  293. package/docs/errors/content-unbalanced-marked.md +36 -0
  294. package/docs/errors/content-unbalanced-q.md +36 -0
  295. package/docs/errors/content-unknown-operator.md +37 -0
  296. package/docs/errors/data-pending.md +34 -0
  297. package/docs/errors/decompress.md +34 -0
  298. package/docs/errors/device-color-without-output-intent.md +33 -0
  299. package/docs/errors/direct-page.md +34 -0
  300. package/docs/errors/disposed.md +34 -0
  301. package/docs/errors/document-changed.md +34 -0
  302. package/docs/errors/embedded-file-forbidden.md +35 -0
  303. package/docs/errors/embedded-file-without-mime-type.md +36 -0
  304. package/docs/errors/encoding-full.md +34 -0
  305. package/docs/errors/encrypted-base.md +33 -0
  306. package/docs/errors/extract-limit-blocks.md +35 -0
  307. package/docs/errors/extract-module-not-loaded.md +37 -0
  308. package/docs/errors/extract-reading-order-ambiguous.md +32 -0
  309. package/docs/errors/extract-struct-tree-ignored.md +32 -0
  310. package/docs/errors/extract-table-ambiguous.md +32 -0
  311. package/docs/errors/extract-table-limit.md +35 -0
  312. package/docs/errors/extract-untagged-content.md +32 -0
  313. package/docs/errors/fetch-failed.md +34 -0
  314. package/docs/errors/flate-truncated.md +34 -0
  315. package/docs/errors/font-invalid.md +36 -0
  316. package/docs/errors/font-mismatch.md +34 -0
  317. package/docs/errors/font-not-embeddable.md +34 -0
  318. package/docs/errors/font-not-embedded.md +35 -0
  319. package/docs/errors/font-not-shapable.md +33 -0
  320. package/docs/errors/glyph-out-of-range.md +34 -0
  321. package/docs/errors/glyph-without-unicode.md +35 -0
  322. package/docs/errors/heading-level-skipped.md +36 -0
  323. package/docs/errors/image-data-length.md +33 -0
  324. package/docs/errors/image-too-large.md +32 -0
  325. package/docs/errors/inline-image-unterminated.md +36 -0
  326. package/docs/errors/input-unreadable.md +37 -0
  327. package/docs/errors/instance-reset.md +34 -0
  328. package/docs/errors/invalid-argument.md +33 -0
  329. package/docs/errors/invalid-axis-value.md +32 -0
  330. package/docs/errors/invalid-box.md +34 -0
  331. package/docs/errors/invalid-color.md +32 -0
  332. package/docs/errors/invalid-command-line.md +44 -0
  333. package/docs/errors/invalid-date.md +34 -0
  334. package/docs/errors/invalid-entry.md +34 -0
  335. package/docs/errors/invalid-feature.md +32 -0
  336. package/docs/errors/invalid-font.md +32 -0
  337. package/docs/errors/invalid-geometry.md +32 -0
  338. package/docs/errors/invalid-icc-profile.md +32 -0
  339. package/docs/errors/invalid-image.md +33 -0
  340. package/docs/errors/invalid-op-log.md +33 -0
  341. package/docs/errors/invalid-page-label.md +34 -0
  342. package/docs/errors/invalid-page-labels.md +32 -0
  343. package/docs/errors/invalid-page-range.md +37 -0
  344. package/docs/errors/invalid-rotate.md +34 -0
  345. package/docs/errors/invalid-structure-nesting.md +38 -0
  346. package/docs/errors/invalid-structure.md +34 -0
  347. package/docs/errors/invalid-text-range.md +33 -0
  348. package/docs/errors/job-finished.md +34 -0
  349. package/docs/errors/limit-exceeded.md +38 -0
  350. package/docs/errors/link-without-contents.md +33 -0
  351. package/docs/errors/link-without-structure.md +37 -0
  352. package/docs/errors/missing-alt-text.md +33 -0
  353. package/docs/errors/missing-glyph.md +33 -0
  354. package/docs/errors/missing-header.md +37 -0
  355. package/docs/errors/missing-lang.md +32 -0
  356. package/docs/errors/missing-root.md +34 -0
  357. package/docs/errors/missing-title.md +32 -0
  358. package/docs/errors/name-tree-node-skipped.md +34 -0
  359. package/docs/errors/nested-transaction.md +34 -0
  360. package/docs/errors/no-pending-save.md +32 -0
  361. package/docs/errors/no-transaction.md +33 -0
  362. package/docs/errors/not-initialized.md +35 -0
  363. package/docs/errors/not-pdf.md +33 -0
  364. package/docs/errors/not-rebased.md +35 -0
  365. package/docs/errors/object-number-out-of-range.md +38 -0
  366. package/docs/errors/objstm-index-mismatch.md +36 -0
  367. package/docs/errors/out-of-memory.md +38 -0
  368. package/docs/errors/outline-cycle.md +34 -0
  369. package/docs/errors/outline-item-skipped.md +34 -0
  370. package/docs/errors/output-unwritable.md +37 -0
  371. package/docs/errors/overwrite-refused.md +36 -0
  372. package/docs/errors/page-count-mismatch.md +34 -0
  373. package/docs/errors/page-index-out-of-range.md +34 -0
  374. package/docs/errors/page-tree-node-skipped.md +35 -0
  375. package/docs/errors/password-required.md +36 -0
  376. package/docs/errors/path-outside-roots.md +32 -0
  377. package/docs/errors/perms-mismatch.md +34 -0
  378. package/docs/errors/profile-version-conflict.md +35 -0
  379. package/docs/errors/reference-cycle.md +35 -0
  380. package/docs/errors/render-backend-unavailable.md +32 -0
  381. package/docs/errors/render-failed.md +33 -0
  382. package/docs/errors/render-too-large.md +36 -0
  383. package/docs/errors/repaired-base.md +34 -0
  384. package/docs/errors/requires-rewrite.md +38 -0
  385. package/docs/errors/saved-not-rebased.md +34 -0
  386. package/docs/errors/sink-not-empty.md +33 -0
  387. package/docs/errors/sink.md +31 -0
  388. package/docs/errors/source-budget-exceeded.md +34 -0
  389. package/docs/errors/source-changed.md +33 -0
  390. package/docs/errors/source.md +30 -0
  391. package/docs/errors/stale-generation.md +34 -0
  392. package/docs/errors/stream-length-recovered.md +37 -0
  393. package/docs/errors/strict.md +34 -0
  394. package/docs/errors/subset-failed.md +31 -0
  395. package/docs/errors/syntax.md +34 -0
  396. package/docs/errors/text-module-not-loaded.md +36 -0
  397. package/docs/errors/text-overflow.md +34 -0
  398. package/docs/errors/tounicode-conflict.md +32 -0
  399. package/docs/errors/type.md +34 -0
  400. package/docs/errors/unexpected-eof.md +34 -0
  401. package/docs/errors/unknown-axis.md +33 -0
  402. package/docs/errors/unknown-code.md +36 -0
  403. package/docs/errors/unknown-destination.md +33 -0
  404. package/docs/errors/unknown-font.md +33 -0
  405. package/docs/errors/unknown-option.md +33 -0
  406. package/docs/errors/unknown-page.md +34 -0
  407. package/docs/errors/unmapped-glyph.md +36 -0
  408. package/docs/errors/unnumbered-heading-misused.md +34 -0
  409. package/docs/errors/unset-object.md +30 -0
  410. package/docs/errors/unsupported-filter.md +34 -0
  411. package/docs/errors/unsupported-image.md +33 -0
  412. package/docs/errors/unsupported-layout-option.md +33 -0
  413. package/docs/errors/unsupported-security-handler.md +34 -0
  414. package/docs/errors/unsupported-version.md +32 -0
  415. package/docs/errors/untagged-content.md +35 -0
  416. package/docs/errors/warnings-truncated.md +35 -0
  417. package/docs/errors/wasm-trap.md +37 -0
  418. package/docs/errors/whole-font-rebuilt.md +30 -0
  419. package/docs/errors/worker-crashed.md +33 -0
  420. package/docs/errors/worker-failed.md +32 -0
  421. package/docs/errors/worker-version-mismatch.md +34 -0
  422. package/docs/errors/would-invalidate-signatures.md +38 -0
  423. package/docs/errors/wrong-document.md +33 -0
  424. package/docs/errors/wrong-password.md +34 -0
  425. package/docs/errors/xobject-cycle.md +36 -0
  426. package/docs/errors/xref-repaired.md +36 -0
  427. package/docs/errors/xrefstm-ignored.md +34 -0
  428. package/docs/llms.txt +88 -0
  429. package/docs/pages/concepts/dependencies.md +44 -0
  430. package/docs/pages/concepts/errors-and-warnings.md +64 -0
  431. package/docs/pages/concepts/how-lamina-thinks.md +86 -0
  432. package/docs/pages/concepts/pages-and-coordinates.md +67 -0
  433. package/docs/pages/guides/accessible-pdfs.md +260 -0
  434. package/docs/pages/guides/archival-pdfs.md +429 -0
  435. package/docs/pages/guides/edit-a-pdf.md +137 -0
  436. package/docs/pages/guides/fonts-and-text.md +202 -0
  437. package/docs/pages/guides/images-and-vectors.md +219 -0
  438. package/docs/pages/guides/keep-the-page-responsive.md +81 -0
  439. package/docs/pages/guides/links-outlines-and-metadata.md +222 -0
  440. package/docs/pages/guides/password-protected-files.md +70 -0
  441. package/docs/pages/guides/save-a-pdf.md +144 -0
  442. package/docs/pages/guides/untrusted-files.md +80 -0
  443. package/docs/pages/index.md +33 -0
  444. package/docs/pages/install.md +75 -0
  445. package/docs/pages/quick-start/browser.md +67 -0
  446. package/docs/pages/quick-start/bun.md +60 -0
  447. package/docs/pages/quick-start/deno.md +58 -0
  448. package/docs/pages/quick-start/node.md +61 -0
  449. package/docs/pages/quick-start/rust.md +58 -0
  450. package/docs/pages/quick-start/workers.md +139 -0
  451. package/docs/pages/recipes/cloudflare-worker.md +115 -0
  452. package/docs/pages/recipes/extract-markdown.md +114 -0
  453. package/docs/pages/recipes/generate-then-edit.md +135 -0
  454. package/docs/pages/recipes/hello.md +94 -0
  455. package/docs/pages/recipes/images-and-vectors.md +209 -0
  456. package/docs/pages/recipes/invoice.md +226 -0
  457. package/docs/pages/recipes/links-and-outlines.md +215 -0
  458. package/docs/pages/recipes/multilingual.md +189 -0
  459. package/docs/pages/recipes/open-untrusted.md +65 -0
  460. package/docs/pages/recipes/pdf-a-archive.md +205 -0
  461. package/docs/pages/recipes/pdf-a3-invoice-with-xml.md +222 -0
  462. package/docs/pages/recipes/pdf-ua-report.md +237 -0
  463. package/docs/pages/recipes/report.md +125 -0
  464. package/docs/pages/recipes/web-worker-client.md +64 -0
  465. package/docs/pages/recipes.md +47 -0
  466. package/docs/pages/reference/changelog.md +86 -0
  467. package/docs/pages/reference/codes.md +14 -0
  468. package/docs/pages/reference/glossary.md +108 -0
  469. package/docs/pages/reference/rust.md +36 -0
  470. package/docs/pages/reference/stability.md +59 -0
  471. package/docs/pages/start/coding-agents.md +45 -0
  472. package/docs/pages/start/first-pdf.md +77 -0
  473. package/docs/pages/troubleshooting.md +74 -0
  474. package/docs/renames.json +86 -0
  475. package/docs/schemas/error.schema.json +305 -0
  476. package/docs/schemas/renames.schema.json +29 -0
  477. package/package.json +93 -3
  478. package/schemas/error.schema.json +305 -0
@@ -0,0 +1,237 @@
1
+ ---
2
+ title: "A PDF/UA report"
3
+ description: "A one-page sales report a screen reader can follow, with headings, a table, a described chart and a link, checked against PDF/UA-1 as it's built."
4
+ version: "0.2.0-alpha.3"
5
+ url: "https://docs.laminapdf.com/recipes/pdf-ua-report/"
6
+ ---
7
+
8
+ # A PDF/UA report
9
+
10
+ A one-page sales report a screen reader can follow, with headings, a table, a described chart and a link, checked against PDF/UA-1 as it's built.
11
+
12
+ You'll build a one-page sales report that a screen reader can follow: headings, a table, a chart described in words and a link. You need this when a document has to meet accessibility law or a client's accessibility policy.
13
+
14
+ The function turns on the PDF/UA-1 profile, then draws each part of the report inside a tag that says what it is: a heading, a table cell, a figure. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
15
+
16
+ <TabItem label="TypeScript">`packages/sdk/examples/pdf-ua-report.ts`:
17
+
18
+ ```ts
19
+ // An accessible report that screen readers can follow, checked against PDF/UA-1 when it is built.
20
+ import { Builder, Font, type Surface, type Tag, type TagName } from "@laminapdf/sdk";
21
+
22
+ const MARGIN = 56;
23
+ const ROW = 18;
24
+ const COLUMN = 144;
25
+ const HEADER_BASELINE = 40;
26
+ const TITLE_BASELINE = 90;
27
+ const TABLE_TOP = 150;
28
+ const LINK_BASELINE = 400;
29
+ const CHART_LEFT = 320;
30
+ const CHART_BASE = 360;
31
+ const BAR_WIDTH = 36;
32
+ const BAR_PITCH = 50;
33
+ const BODY = 11;
34
+ /** The font sizes of the title and the headings; other text is `BODY`. */
35
+ const SIZES: Partial<Record<TagName, number>> = { H1: 22, H2: 15 };
36
+ const BLUE = [0.12, 0.47, 0.78] as const;
37
+ const QUARTERS = [
38
+ ["Q1", 120],
39
+ ["Q2", 135],
40
+ ["Q3", 160],
41
+ ["Q4", 150],
42
+ ] as const;
43
+ const CHART_ALT = "Bar chart of sales by quarter: 120, 135, 160 and 150 thousand euros.";
44
+
45
+ /**
46
+ * The report's bytes. Needs `init({ text: true })`.
47
+ *
48
+ * @param notoSans - the bytes of the Noto Sans font file.
49
+ */
50
+ export function pdfUaReport(notoSans: Uint8Array): Uint8Array<ArrayBuffer> {
51
+ using b = new Builder({ profiles: ["PDF/UA-1"] });
52
+ b.metadata({ title: "Annual sales report 2026" });
53
+ b.lang("en-GB");
54
+ const font = Font.fromBytes(notoSans);
55
+ b.font(font);
56
+ const page = b.page("A4");
57
+ draw(page.surface(), font);
58
+ page.finish();
59
+ using doc = b.finish();
60
+ return doc.save();
61
+ }
62
+
63
+ /** One line of text with its baseline at `y`, as the structure element `tag`, sized by it. */
64
+ function line(s: Surface, font: Font, tag: Tag, text: string, x: number, y: number): void {
65
+ const size = (typeof tag === "string" ? SIZES[tag] : undefined) ?? BODY;
66
+ s.tag(tag, (s) => s.text(text, { font, size, at: [x, y] }));
67
+ }
68
+
69
+ function draw(s: Surface, font: Font): void {
70
+ // The running header is decoration: an artifact, which screen readers skip.
71
+ s.artifact("pagination", (s) => s.text("Acme Widgets", { font, size: BODY, at: [MARGIN, HEADER_BASELINE] }));
72
+ line(s, font, "H1", "Annual sales report 2026", MARGIN, TITLE_BASELINE);
73
+ line(s, font, "P", "Sales grew in three quarters of four.", MARGIN, TITLE_BASELINE + 2 * ROW);
74
+ table(s, font);
75
+ chart(s);
76
+ const link = {
77
+ target: { type: "uri", uri: "https://example.com/accounts" },
78
+ contents: "The full 2026 accounts",
79
+ } as const;
80
+ s.tag("P", (s) =>
81
+ s.text("The full accounts", { font, size: BODY, at: [MARGIN, LINK_BASELINE], fill: [...BLUE], link }),
82
+ );
83
+ }
84
+
85
+ /** A heading and a table of the quarters, whose first row holds the columns' header cells. */
86
+ function table(s: Surface, font: Font): void {
87
+ line(s, font, "H2", "Sales by quarter", MARGIN, TABLE_TOP);
88
+ const header: Tag = { type: "TH", scope: "column" };
89
+ s.tag("Table", (s) => {
90
+ s.tag("TR", (s) => {
91
+ line(s, font, header, "Quarter", MARGIN, TABLE_TOP + ROW);
92
+ line(s, font, header, "Sales (k€)", MARGIN + COLUMN, TABLE_TOP + ROW);
93
+ });
94
+ QUARTERS.forEach(([quarter, sales], i) => {
95
+ const y = TABLE_TOP + ROW * (i + 2);
96
+ s.tag("TR", (s) => {
97
+ line(s, font, "TD", quarter, MARGIN, y);
98
+ line(s, font, "TD", sales.toFixed(0), MARGIN + COLUMN, y);
99
+ });
100
+ });
101
+ });
102
+ }
103
+
104
+ /** The quarters as bars standing on the chart's base: one figure with alternate text. */
105
+ function chart(s: Surface): void {
106
+ s.tag({ type: "Figure", alt: CHART_ALT }, (s) => {
107
+ s.fillColor([...BLUE]);
108
+ QUARTERS.forEach(([, sales], i) => {
109
+ s.path((p) => p.rect([CHART_LEFT + BAR_PITCH * i, CHART_BASE - sales, BAR_WIDTH, sales])).fill();
110
+ });
111
+ });
112
+ }
113
+ ```</TabItem>
114
+ <TabItem label="Rust">`crates/laminapdf/examples/pdf_ua_report.rs`:
115
+
116
+ ```rust
117
+ //! An accessible report that screen readers can follow, checked against PDF/UA-1 when it is built.
118
+
119
+ use laminapdf::{
120
+ ArtifactKind, BuildError, BuildOptions, Builder, Color, FillRule, FontHandle, LinkTarget, Metadata, PageSize,
121
+ PointPt, Profile, Pt, RectPt, SaveOptions, Surface, TableScope, Tag, TagKind,
122
+ };
123
+
124
+ const MARGIN: f64 = 56.0;
125
+ const ROW: f64 = 18.0;
126
+ const COLUMN: f64 = 144.0;
127
+ const HEADER_AT: PointPt = PointPt::from_points(MARGIN, 40.0);
128
+ const TITLE_BASELINE: f64 = 90.0;
129
+ const TABLE_TOP: f64 = 150.0;
130
+ const LINK_AT: PointPt = PointPt::from_points(MARGIN, 400.0);
131
+ const CHART_LEFT: f64 = 320.0;
132
+ const CHART_BASE: f64 = 360.0;
133
+ const BAR_WIDTH: Pt = Pt::new(36.0);
134
+ const BAR_PITCH: f64 = 50.0;
135
+ const BODY: Pt = Pt::new(11.0);
136
+ /// The font sizes of the title and the headings; other text is `BODY`.
137
+ const SIZES: [(TagKind, Pt); 2] = [(TagKind::H1, Pt::new(22.0)), (TagKind::H2, Pt::new(15.0))];
138
+ const BLUE: Color = Color::Rgb(0.12, 0.47, 0.78);
139
+ const QUARTERS: [(&str, f64); 4] = [("Q1", 120.0), ("Q2", 135.0), ("Q3", 160.0), ("Q4", 150.0)];
140
+ const CHART_ALT: &str = "Bar chart of sales by quarter: 120, 135, 160 and 150 thousand euros.";
141
+
142
+ fn main() -> Result<(), Box<dyn std::error::Error>> {
143
+ let mut args = std::env::args().skip(1);
144
+ let font = std::fs::read(args.next().ok_or("arguments: <font.ttf> [out-dir]")?)?;
145
+ let out = std::path::PathBuf::from(args.next().unwrap_or_else(|| "target/examples-out".into()));
146
+ std::fs::create_dir_all(&out)?;
147
+ Ok(std::fs::write(out.join("pdf_ua_report.pdf"), build(font)?)?)
148
+ }
149
+
150
+ pub(crate) fn build(font: Vec<u8>) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
151
+ let mut b = Builder::new(BuildOptions::new().with_profile(Profile::PdfUa1));
152
+ b.metadata(Metadata::default().with_title("Annual sales report 2026"));
153
+ b.lang("en-GB");
154
+ let font = b.font_bytes(font)?;
155
+ let mut page = b.page(PageSize::A4);
156
+ draw(page.surface(), &font)?;
157
+ page.finish()?;
158
+ Ok(b.finish()?.save(&SaveOptions::new())?.bytes)
159
+ }
160
+
161
+ /// One line of text with its baseline at `y`, as the structure element `tag`, sized by it.
162
+ fn line(s: &mut Surface, font: &FontHandle, tag: impl Into<Tag>, text: &str, x: f64, y: f64) -> Result<(), BuildError> {
163
+ let tag = tag.into();
164
+ let size = SIZES.iter().find(|e| e.0 == tag.kind()).map_or(BODY, |e| e.1);
165
+ s.tag(tag, |s| s.text(text, font, size, PointPt::from_points(x, y)).map(drop))
166
+ }
167
+
168
+ fn draw(s: &mut Surface, font: &FontHandle) -> Result<(), BuildError> {
169
+ // The running header is decoration: an artifact, which screen readers skip.
170
+ let header = |s: &mut Surface| s.text("Acme Widgets", font, BODY, HEADER_AT).map(drop);
171
+ s.artifact(ArtifactKind::Pagination, header)?;
172
+ line(s, font, TagKind::H1, "Annual sales report 2026", MARGIN, TITLE_BASELINE)?;
173
+ let summary = "Sales grew in three quarters of four.";
174
+ line(s, font, TagKind::P, summary, MARGIN, TITLE_BASELINE + 2.0 * ROW)?;
175
+ table(s, font)?;
176
+ chart(s)?;
177
+ let link = LinkTarget::Uri("https://example.com/accounts".into());
178
+ s.tag(TagKind::P, |s| {
179
+ let text = s.text("The full accounts", font, BODY, LINK_AT)?;
180
+ text.fill(BLUE).link(link, Some("The full 2026 accounts".into()));
181
+ Ok(())
182
+ })
183
+ }
184
+
185
+ /// A heading and a table of the quarters, whose first row holds the columns' header cells.
186
+ fn table(s: &mut Surface, font: &FontHandle) -> Result<(), BuildError> {
187
+ line(s, font, TagKind::H2, "Sales by quarter", MARGIN, TABLE_TOP)?;
188
+ let header = Tag::new(TagKind::TH).with_scope(TableScope::Column);
189
+ s.tag(TagKind::Table, |s| {
190
+ s.tag(TagKind::TR, |s| {
191
+ line(s, font, header.clone(), "Quarter", MARGIN, TABLE_TOP + ROW)?;
192
+ line(s, font, header.clone(), "Sales (k€)", MARGIN + COLUMN, TABLE_TOP + ROW)
193
+ })?;
194
+ for (row, (quarter, sales)) in (2_u8..).zip(QUARTERS) {
195
+ let y = TABLE_TOP + ROW * f64::from(row);
196
+ s.tag(TagKind::TR, |s| {
197
+ line(s, font, TagKind::TD, quarter, MARGIN, y)?;
198
+ line(s, font, TagKind::TD, &format!("{sales:.0}"), MARGIN + COLUMN, y)
199
+ })?;
200
+ }
201
+ Ok(())
202
+ })
203
+ }
204
+
205
+ /// The quarters as bars standing on the chart's base: one figure with alternate text.
206
+ fn chart(s: &mut Surface) -> Result<(), BuildError> {
207
+ s.tag(Tag::new(TagKind::Figure).with_alt(CHART_ALT), |s| {
208
+ s.fill_color(BLUE);
209
+ for (i, (_, sales)) in (0_u8..).zip(QUARTERS) {
210
+ let x = CHART_LEFT + BAR_PITCH * f64::from(i);
211
+ let bar = RectPt::from_xywh(Pt::new(x), Pt::new(CHART_BASE - sales), BAR_WIDTH, Pt::new(sales));
212
+ s.path(|p| _ = p.rect(bar)).fill(FillRule::NonZero);
213
+ }
214
+ Ok(())
215
+ })
216
+ }
217
+ ```</TabItem>
218
+
219
+ The result is one A4 page that reads, in order, as a title, a summary, a table of four quarters, a bar chart and a link: [open the reference PDF](https://docs.laminapdf.com/examples/pdf/pdf_ua_report.pdf).
220
+
221
+ ## How it works
222
+
223
+ - `profiles: ["PDF/UA-1"]` (`Profile::PdfUa1` in Rust) tags the document and makes `finish()` check the rules a program can check. It fails with a coded error for the first rule the report breaks; [Accessible PDFs](../../pages/guides/accessible-pdfs.md#what-pdfua-asks-for) lists them.
224
+ - `metadata` gives the report its title and `lang` its language, which PDF/UA-1 asks for. The font is an embedded Noto Sans, because PDF/UA-1 refuses the [standard 14 fonts](../../pages/reference/glossary.md#standard-14-fonts).
225
+ - `tag` puts what its callback draws inside a structure element, such as `H1`, `P` or `TD`, in reading order. The `line` helper tags one line of text and sizes it by its tag: 22 points for `H1`, 15 for `H2`, 11 for the rest.
226
+ - The table's first row holds `TH` header cells with a column scope, so a screen reader can name each cell's column.
227
+ - The four bars are one `Figure` with alternate text, the sentence a screen reader reads in place of the drawing. The running header is an artifact, which screen readers skip.
228
+ - The link's `contents`, "The full 2026 accounts", is its description. The builder makes the link a `Link` element inside its paragraph.
229
+
230
+ ## What to change
231
+
232
+ - **The numbers:** change `QUARTERS`, then change `CHART_ALT` to match. The builder checks that the chart has alternate text, not that the text is right; see [What a program can't check](../../pages/guides/accessible-pdfs.md#what-a-program-cant-check).
233
+ - **A list:** nest an `"L"`, an `"LI"` for each item, and inside each a `"Lbl"` for the bullet and an `"LBody"` for the text. An `L` holds `LI` items or a nested `L`, and an `LI` holds a `Lbl` and an `LBody`: anything else inside them fails `finish()` with `invalid-structure-nesting`.
234
+ - **A passage in another language:** tag it with its own, as in `{ type: "P", lang: "fr-FR" }` (`Tag::new(TagKind::P).with_lang("fr-FR")` in Rust).
235
+ - **Accessible and archival at once:** add a PDF/A profile beside it, as in `profiles: ["PDF/A-2u", "PDF/UA-1"]`. The [PDF/A archive](../../pages/recipes/pdf-a-archive.md) does this.
236
+
237
+ Next: [a PDF/A archive](../../pages/recipes/pdf-a-archive.md), a letter written for long-term keeping.
@@ -0,0 +1,125 @@
1
+ ---
2
+ title: "A 100-page report"
3
+ description: "A 100-page A4 report with two embedded fonts and a table on every page, the document Lamina PDF times in each JavaScript runtime."
4
+ version: "0.2.0-alpha.3"
5
+ url: "https://docs.laminapdf.com/recipes/report/"
6
+ ---
7
+
8
+ # A 100-page report
9
+
10
+ A 100-page A4 report with two embedded fonts and a table on every page, the document Lamina PDF times in each JavaScript runtime.
11
+
12
+ You'll make a 100-page report with two embedded fonts: on every page, a heading, a paragraph, a line of Chinese and a table of 20 products. Start from it for any long document you generate from data, such as monthly statements or a catalogue.
13
+
14
+ The function draws one region's page at a time in a loop, then returns the PDF's bytes:
15
+
16
+ `packages/sdk/examples/report.ts`:
17
+
18
+ ```ts
19
+ // A 100-page report with two embedded fonts. Each page has a heading, a paragraph broken into a
20
+ // box, a line of Chinese, a table of products with rules between the rows, and a page number.
21
+ import { Builder, type BuilderOptions, Font, PAGE_SIZES, type Rect, type Surface } from "@laminapdf/sdk";
22
+
23
+ /** The number of pages. */
24
+ const REPORT_PAGES = 100;
25
+ const PRODUCTS = 20;
26
+ const PRICE = 12.5;
27
+ const [PAGE_WIDTH] = PAGE_SIZES.A4;
28
+ const MARGIN = 56;
29
+ const RIGHT_EDGE = PAGE_WIDTH - MARGIN;
30
+ const HEADING_AT = [MARGIN, 72] as const;
31
+ const PARAGRAPH_BOX = [MARGIN, 88, RIGHT_EDGE - MARGIN, 60] as const;
32
+ const CHINESE_AT = [MARGIN, 166] as const;
33
+ const FOOTER_AT = [MARGIN, 800] as const;
34
+ const FIRST_ROW = 200;
35
+ const ROW_HEIGHT = 24;
36
+ /** The units' and the revenue's columns (left edge, width), both right-aligned. */
37
+ const UNITS_COLUMN = [300, 60] as const;
38
+ const REVENUE_COLUMN = [400, RIGHT_EDGE - 400] as const;
39
+ /** A cell's box starts this far above its row's baseline and is this tall; the rule is this far below. */
40
+ const CELL_RISE = 11;
41
+ const CELL_HEIGHT = 14;
42
+ const RULE_DROP = 7;
43
+ /** Font sizes: the heading, the paragraph and the Chinese line, the table, the page number. */
44
+ const SIZES = { heading: 20, body: 11, table: 10, footer: 9 } as const;
45
+ const PARAGRAPH =
46
+ "Quarterly figures for every region follow. Each table lists the units shipped, the revenue " +
47
+ "and the change against the previous quarter; totals are at the end of the report.";
48
+
49
+ /**
50
+ * The document's bytes. Needs `init({ text: true })`.
51
+ *
52
+ * @param latinFont - a font for the text, such as Noto Sans.
53
+ * @param chineseFont - a font with Chinese glyphs, such as Noto Sans SC.
54
+ * @param options - can fix the file ID, the producer and the creation date.
55
+ */
56
+ export function report(
57
+ latinFont: Uint8Array,
58
+ chineseFont: Uint8Array,
59
+ options: BuilderOptions = {},
60
+ ): Uint8Array<ArrayBuffer> {
61
+ using b = new Builder(options);
62
+ const font = Font.fromBytes(latinFont);
63
+ const chinese = Font.fromBytes(chineseFont);
64
+ b.font(font);
65
+ b.font(chinese);
66
+ for (let region = 1; region <= REPORT_PAGES; region++) {
67
+ const page = b.page("A4");
68
+ const s = page.surface();
69
+ s.text(`Region ${region}: quarterly report`, { font, size: SIZES.heading, at: HEADING_AT });
70
+ s.textBox(PARAGRAPH, { font, size: SIZES.body, box: PARAGRAPH_BOX });
71
+ s.text("你好世界,这是中文字体子集测试。", { font: chinese, size: SIZES.body, at: CHINESE_AT });
72
+ products(s, font, region);
73
+ s.text(`Page ${region} of ${REPORT_PAGES}`, { font, size: SIZES.footer, at: FOOTER_AT });
74
+ page.finish();
75
+ }
76
+ b.metadata({ title: "Quarterly report", author: "lamina examples" }).lang("en-GB");
77
+ using doc = b.finish();
78
+ return doc.save();
79
+ }
80
+
81
+ /** Made-up sales figures: the units of `product` that `region` shipped, from 0 to 499. */
82
+ function unitsShipped(region: number, product: number): number {
83
+ return (region * 37 + product * 11) % 500;
84
+ }
85
+
86
+ /** A region's table: one row per product, with its units and revenue right-aligned. */
87
+ function products(s: Surface, font: Font, region: number): void {
88
+ for (let product = 0; product < PRODUCTS; product++) {
89
+ const y = FIRST_ROW + ROW_HEIGHT * product;
90
+ const units = unitsShipped(region, product);
91
+ const size = SIZES.table;
92
+ s.text(`Product ${product + 1}`, { font, size, at: [MARGIN, y] });
93
+ s.textBox(String(units), { font, size, box: cell(UNITS_COLUMN, y), align: "end" });
94
+ s.textBox(`€ ${(units * PRICE).toFixed(2)}`, { font, size, box: cell(REVENUE_COLUMN, y), align: "end" });
95
+ s.strokeColor([0.8])
96
+ .path((p) => p.moveTo(MARGIN, y + RULE_DROP).lineTo(RIGHT_EDGE, y + RULE_DROP))
97
+ .stroke({ width: 0.5 });
98
+ }
99
+ }
100
+
101
+ /** The box of a cell in `column` (left edge, width) on the row at `baseline`. */
102
+ function cell([left, width]: readonly [number, number], baseline: number): Rect {
103
+ return [left, baseline - CELL_RISE, width, CELL_HEIGHT];
104
+ }
105
+ ```
106
+
107
+ The result is 100 A4 pages, one per region. It has no reference PDF to open. Instead, Lamina PDF's tests build and time the report in every JavaScript runtime and check its SHA-256 there, as does the Rust benchmark that builds the same bytes.
108
+
109
+ ## How it works
110
+
111
+ - It needs the text module, `init({ text: true })`, because it draws with embedded fonts.
112
+ - `Font.fromBytes` reads each font file, and `b.font` registers both before the first page. Each font is embedded once for the whole report, with only the glyphs its 100 pages draw.
113
+ - `s.text` draws one line, with `at[1]` as its baseline, and `s.textBox` breaks the paragraph into lines that fit `PARAGRAPH_BOX`.
114
+ - In the table, the units and the revenue are text boxes as wide as their columns, with `align: "end"` to right-align them. `cell` works out each box from its column and the row's baseline.
115
+ - `strokeColor([0.8])` sets a light gray, and each rule is a path from the left margin to the right edge, stroked 0.5 points wide.
116
+ - `metadata` and `lang("en-GB")` set the title, author and language once for the document, and `using` frees the builder and the document when the function returns.
117
+
118
+ ## What to change
119
+
120
+ - **Your data:** replace `unitsShipped` with your own figures, and set `REPORT_PAGES` and `PRODUCTS` to your counts.
121
+ - **A longer table:** 20 rows end at 656 points, above the page number at 800. For more rows, lower `ROW_HEIGHT` or carry the rest over to the next page.
122
+ - **Another script:** load a font that covers it and draw its text in that font, as the Chinese line does. See [Text and fonts](../../pages/guides/fonts-and-text.md).
123
+ - **The file's details:** pass `producer` and `creationDate` in `options`, such as `creationDate: "D:20261104120000Z"`. The builder never reads the clock, so a report without a date has none.
124
+
125
+ Next: [open someone else's file](../../pages/recipes/open-untrusted.md), with a password and tighter limits.
@@ -0,0 +1,64 @@
1
+ ---
2
+ title: "Save in a Web Worker"
3
+ description: "Open and save a PDF in a Web Worker, so a large file never freezes the page, with progress as it saves and a signal that stops the work."
4
+ version: "0.2.0-alpha.3"
5
+ url: "https://docs.laminapdf.com/recipes/web-worker-client/"
6
+ ---
7
+
8
+ # Save in a Web Worker
9
+
10
+ Open and save a PDF in a Web Worker, so a large file never freezes the page, with progress as it saves and a signal that stops the work.
11
+
12
+ You'll save a PDF in a Web Worker, reporting progress as it goes and stopping when the user presses Cancel. You need this in a browser app once files get large, because a save on the main thread freezes the page until it ends.
13
+
14
+ `saveInWorker` starts a Web Worker, opens the bytes there and saves them as a [full rewrite](../../pages/reference/glossary.md#full-rewrite), handing your `onProgress` and `signal` to each call:
15
+
16
+ `packages/sdk/examples/worker-client.ts`:
17
+
18
+ ```ts
19
+ // Saving a PDF in a Web Worker, so a large file never blocks the page: `@laminapdf/sdk/worker`
20
+ // runs the same API there, and each method returns a Promise. The save reports its progress step
21
+ // by step, and aborting the signal (a Cancel button, say) stops the work.
22
+ import { type CallOptions, connect } from "@laminapdf/sdk/worker";
23
+
24
+ /** What the save reports to and listens to. */
25
+ export type SaveInWorkerOptions = Pick<CallOptions, "onProgress" | "signal">;
26
+
27
+ /**
28
+ * Opens `bytes` in a Web Worker and saves them there as a full rewrite.
29
+ *
30
+ * @param bytes - any PDF; it is copied to the worker (`transfer: true` would move it).
31
+ * @param options - `onProgress` is called after each step of the save. Aborting `signal` stops
32
+ * the work wherever it is (starting the Web Worker, opening, or at the save's next step), and
33
+ * the promise rejects with a `cancelled` error.
34
+ * @returns the saved file.
35
+ */
36
+ export async function saveInWorker(bytes: Uint8Array, options: SaveInWorkerOptions = {}): Promise<Uint8Array> {
37
+ const client = await connect(options);
38
+ try {
39
+ await using doc = await client.open(bytes, options);
40
+ return await doc.save({ mode: "fullRewrite" }, options);
41
+ } finally {
42
+ client.terminate();
43
+ }
44
+ }
45
+ ```
46
+
47
+ The promise resolves to the saved file, or rejects with `cancelled` once the signal aborts. Lamina PDF's tests run it in Chromium, Firefox and WebKit.
48
+
49
+ ## How it works
50
+
51
+ - `connect` starts the Web Worker file that ships with `@laminapdf/sdk` and checks that it comes from the same build as your page.
52
+ - `client.open` copies the bytes into the Web Worker and returns a remote document, whose methods return promises. `await using` closes it there when the block ends.
53
+ - The Web Worker saves in steps of 20,000 units of work, about one per object in a full rewrite. Between steps it calls `onProgress` with `done`, `total` and `phase`, at most every 50 ms, so a small file saves in one step and reports none.
54
+ - Aborting the signal rejects the call at once with `cancelled`, and `error.cause` holds the signal's reason. A save stops at its next step.
55
+ - `client.terminate()` in `finally` stops the Web Worker however the save ended, which also stops an open that was still running.
56
+
57
+ ## What to change
58
+
59
+ - **A progress bar:** in `onProgress`, set a `<progress>` element's `value` to `done` and, when the save knows it, its `max` to `total`.
60
+ - **Large files:** pass `transfer: true` to `client.open` to move the buffer instead of copying it, which leaves your copy empty. See [Keep the page responsive](../../pages/guides/keep-the-page-responsive.md#move-bytes-instead-of-copying-them).
61
+ - **Several files:** call `connect` once, reuse the client for each file, and terminate it when the page no longer needs it.
62
+ - **Edits before the save:** apply them with `await doc.apply(ops)`, then save in the default `auto` mode. It appends them as an [incremental save](../../pages/reference/glossary.md#incremental-save) when the file allows one. See [Save a PDF](../../pages/guides/save-a-pdf.md#choose-a-save-mode).
63
+
64
+ Next: [a Cloudflare Worker](../../pages/recipes/cloudflare-worker.md) that generates a PDF per request.
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: "Recipes"
3
+ description: "Complete Lamina PDF programs, from one page of text to an archived invoice, each with its code and the PDF it writes."
4
+ version: "0.2.0-alpha.3"
5
+ url: "https://docs.laminapdf.com/recipes/"
6
+ ---
7
+
8
+ # Recipes
9
+
10
+ Complete Lamina PDF programs, from one page of text to an archived invoice, each with its code and the PDF it writes.
11
+
12
+ Each recipe is a complete program to copy: what it makes, the code, how it works and what to change. Pick the one closest to the document you need, and change it from there.
13
+
14
+ Most recipes exist twice, in Rust and in TypeScript, and both write exactly the same bytes. Lamina PDF's tests check that on every change, in Rust and in every JavaScript runtime: Node, Chromium, Firefox, WebKit, Deno, Bun and workerd. Each recipe shows the tested code, and its reference PDF is the file that code writes.
15
+
16
+ To run a Rust recipe from a checkout of Lamina PDF, use `cargo run -p laminapdf --example <name>`. Its header comment lists the arguments it takes, such as the font or image files it reads.
17
+
18
+ ## Create a PDF
19
+
20
+ - [Hello, world](../pages/recipes/hello.md): one page of text in a standard 14 font.
21
+ - [An invoice](../pages/recipes/invoice.md): an embedded font, a table of line items, and tags for screen readers.
22
+ - [Multilingual text](../pages/recipes/multilingual.md): five scripts, each in its own embedded font.
23
+ - [Images and vectors](../pages/recipes/images-and-vectors.md): paths, colour, transparency, a clip and two images.
24
+ - [Links and outlines](../pages/recipes/links-and-outlines.md): links, an outline and page labels.
25
+
26
+ ## Edit a PDF
27
+
28
+ - [Generate, then edit](../pages/recipes/generate-then-edit.md): open a file's bytes, change its metadata and save incrementally.
29
+
30
+ ## Read a PDF
31
+
32
+ - [Extract text for an LLM](../pages/recipes/extract-markdown.md): Markdown, JSON with boxes, and chunks for retrieval, in TypeScript and Rust.
33
+
34
+ ## Meet a standard
35
+
36
+ - [A PDF/UA report](../pages/recipes/pdf-ua-report.md): an accessible report a screen reader can follow.
37
+ - [A PDF/A archive](../pages/recipes/pdf-a-archive.md): a letter for long-term archiving.
38
+ - [A PDF/A-3 invoice with XML](../pages/recipes/pdf-a3-invoice-with-xml.md): an invoice with its data attached.
39
+
40
+ ## Run it in production (TypeScript)
41
+
42
+ - [A 100-page report](../pages/recipes/report.md): the case Lamina PDF times in every runtime.
43
+ - [Open someone else's file](../pages/recipes/open-untrusted.md): a password and tighter limits, with the outcome as a value.
44
+ - [Save in a Web Worker](../pages/recipes/web-worker-client.md): progress and cancelling, off the main thread.
45
+ - [A Cloudflare Worker](../pages/recipes/cloudflare-worker.md): a PDF per request.
46
+
47
+ Next: [Hello, world](../pages/recipes/hello.md), the smallest PDF Lamina PDF writes.
@@ -0,0 +1,86 @@
1
+ ---
2
+ title: "Changelog"
3
+ description: "What changed in each Lamina PDF release, newest first."
4
+ version: "0.2.0-alpha.3"
5
+ url: "https://docs.laminapdf.com/reference/changelog/"
6
+ ---
7
+
8
+ # Changelog
9
+
10
+ What changed in each Lamina PDF release, newest first.
11
+
12
+ Every Lamina PDF package shares one version, so each entry covers all of them, from the Rust crates to `@laminapdf/sdk` and the viewer. Breaking changes come first, under **Minor Changes**, as the [stability policy](../../pages/reference/stability.md) explains. Versions from `0.2.0-alpha.2` on are on npm and crates.io; earlier ones were never published.
13
+
14
+ ## 0.2.0-alpha.3
15
+
16
+ ### Minor Changes
17
+
18
+ - The package now carries its docs as Markdown in `docs/`, matched to its version: every page of the docs site, the API reference, a page per error code, `renames.json` (what renamed items are called now) and `AGENTS.md`, a snippet for your project's agent instructions. The `laminapdf` crate ships the same folder without the API reference. The docs site serves a Markdown copy of every page, `llms.txt` and `llms-full.txt`.
19
+ - Every handle on WebAssembly memory frees with `free()` or `using`: `Document`, `PageRef`, `SaveJob`, `Builder`, `Page` and `Image`. A second `free()` does nothing, and any other call afterwards throws `disposed` instead of a glue error. A page or save job is freed with its document, and freeing a document now frees its memory at once, even while pages of it are still held. Pages of a freed builder throw `disposed` too (`builder-finished` once it finishes), and a freed `Image` throws `disposed` instead of decoding again.
20
+
21
+ Each module's memory may grow to 2 GiB. Past that, the module traps and the call throws `out-of-memory`; any other trap throws `wasm-trap`. The next call runs in a fresh instance, and handles of the old one throw `instance-reset`. The new `reset()` gives grown memory back by starting every module afresh, and the new `onLeak(hook)` reports handles the garbage collector reclaims without a `free()`.
22
+ - `doc.extract({ format })` gives a document's text for an LLM or a search index: Markdown or plain text in reading order, the `laminapdf.extract/1` JSON with a box for every block (the same bytes as Rust's `extract_json`), or chunks sized for retrieval. Tables drawn with lines come out as tables, and hidden text is left out. It needs the extract or text module.
23
+ - Two new warning codes, `extract-table-ambiguous` and `extract-table-limit`, join the generated `WarningCode` union. In Rust, `laminapdf-extract` is now published, and the `laminapdf` crate exposes it. `Document::extract`, `extract_job` and `extract_json` return blocks in reading order, with tables and their cells. An `Extraction` renders as Markdown, plain text, retrieval chunks or `laminapdf.extract/1` JSON, whose JSON Schema is in `laminapdf-extract`'s `schemas/`.
24
+ - Breaking (Rust, while alpha): `laminapdf::Error` no longer exposes the errors of the crates below it. The `Cos`, `Ops`, `Save`, `Text` and `Build` variants are one opaque `Error::Core`, and `CosError`, `OpsError`, `SaveError` and `SinkError` are no longer re-exported (`BuildError` and `TextError` stay: the builder's and `Font`'s own methods return them). Match on `error_code()` instead; a `data-pending` error's ranges come from the new `Error::pending_ranges()`, which replaces `laminapdf_source::pending_ranges`. The JavaScript API and every error's code, message and JSON are unchanged.
25
+ - Breaking (Rust, while alpha): every public type now has a name of its own, and each item one public path.
26
+
27
+ - An extracted run is `PageTextRun` (`laminapdf::extract::PageTextRun`, `laminapdf_text::PageTextRun`), the name `@laminapdf/sdk` already gives it. `TextRun` now means only drawn text.
28
+ - `laminapdf-build`'s font handle is `FontHandle`, the name the façade already gave it, so the builder's signatures read `&FontHandle` beside `laminapdf::Font`.
29
+ - `laminapdf-text`'s OpenType tag is `OpenTypeTag`, and the façade exports it for `Font::instance(&[(OpenTypeTag::WEIGHT, 700.0)])`.
30
+ - `laminapdf-text`'s `extract` and `agl` modules are private. Their items are at the crate root (`laminapdf_text::TextExtractor`, `PageText` and the rest), and `agl::to_unicode` is now `glyph_name_to_unicode`, beside `zapf_dingbats_to_unicode`. `CMap` and `MAX_USECMAP_DEPTH` are now private to the crate.
31
+ - `laminapdf::Document::ops` and `into_ops` are hidden from the docs. They stay for Lamina PDF's own crates, and may change without notice.
32
+
33
+ In JavaScript, the extracted run's class is itself named `PageTextRun` now, so `run.constructor.name` reads `PageTextRun`. The rest of the JavaScript API and every output are unchanged.
34
+ - New: the `laminapdf` command-line tool (`crates/laminapdf-cli`, not published to crates.io yet), with `info`, `check`, `pages rotate`, `extract` and `explain`, versioned JSON reports with JSON Schemas, and exit codes 0–5 (ADR 0031). Its own error codes (`invalid-command-line`, `invalid-page-range`, `binary-output-to-terminal`, `unknown-code`, `overwrite-refused`, `input-unreadable`, `output-unwritable`) join every code table, so the TypeScript `ErrorCode` union lists them too. The Rust façade gains `Document::version`, `is_encrypted`, `is_tagged` and `read_every_object`, and `laminapdf::did_you_mean`.
35
+ - Two new warning codes, `extract-limit-blocks` and `extract-reading-order-ambiguous`, join the generated `WarningCode` union. In Rust, `Budget`, `Step` and `Phase` now come from `laminapdf-syntax` (the façade re-exports them at the same paths), `laminapdf_model::Document::is_tagged` and `RectPt::union` are new, and `laminapdf_text::is_right_to_left` is public. A new crate, `laminapdf-extract`, extracts blocks in reading order (ADR 0030); it is published with L3b.
36
+ - New: `laminapdf mcp`, an MCP server on standard input and output that serves the CLI's commands as tools, in builds with the `laminapdf-cli` crate's `mcp` feature (ADR 0031 §9). It touches only files under its `--root` folders, is read-only unless started with `--allow-write`, and keeps document text out of everything but report fields. A path outside the roots is the new error code `path-outside-roots`, so the TypeScript `ErrorCode` union lists it too. The Rust façade exposes the error schema as `laminapdf::ERROR_SCHEMA`.
37
+ - Breaking (Rust, while alpha): `Matrix`, `FillRule` and `Dash` are now defined once, in `laminapdf-model`. `laminapdf`, `laminapdf-build` and `laminapdf-content` re-export them under their old paths. Their API changes as follows:
38
+
39
+ - `Matrix::translate` takes two `f64`s instead of two `Pt`s.
40
+ - `Dash` lengths are `f64`s in the drawing's own units, so the builder takes points: `Dash::new(vec![18.0, 6.0], 0.0)`.
41
+ - The content reader's `Matrix::new` takes an array, `multiply` is `then` (the receiver applies first, with `after` for the other order), and `transform_point` is `apply`.
42
+ - `PageFrame::to_user_space_matrix` and `TilePlan::page_to_tile` return a `Matrix` instead of a `[f64; 6]`. Read its fields, or call `to_array()` for the six numbers. `laminapdf-render` re-exports `Matrix`.
43
+ - `Dash` is `#[non_exhaustive]`: build one with `Dash::new`. The content reader's `Matrix::from_object` is removed.
44
+ - The content reader's current colour, `laminapdf_content::Color`, is now `CurrentColor`, so `Color` means only the builder's colour.
45
+
46
+ The JavaScript API and every output are unchanged.
47
+
48
+ ### Patch Changes
49
+
50
+ - `didYouMean` now suggests the same names as errors from the WASM module. Names equally close to a mistyped one come in name order, and a typo with characters outside ASCII counts one edit per character.
51
+ - Text extraction now avoids a quadratic scan for right-to-left runs whose glyphs have zero advance, preventing long stalls on PDFs with missing font widths. The extracted text stays the same.
52
+ - The `@laminapdf/sdk/worker` worker now frees the document of an `open()` or `openUrl()` you abort just as it finishes. Before, the call rejected with `cancelled`, but the document stayed in the worker's memory until the worker stopped. An `open()` aborted while it ran always leaked its document, since the worker reads the cancel only after the synchronous open has answered.
53
+
54
+ ## 0.2.0-alpha.2
55
+
56
+ ### Minor Changes
57
+
58
+ - `Document::save` no longer takes a `CancelToken`. To stop a save from another thread, call `save_with(&options, &cancel)` instead. In TypeScript, `save()`, `saveWithReport()` and `SaveJob.step()` now return `Uint8Array<ArrayBuffer>`, which `Response` and `Blob` accept without a cast. Smaller additions: `RectPt::from_points(x, y, width, height)`, `SetInfo::patch(patch)` for an edit that records no `/ModDate`, and `new()` on `BuildOptions`, `OpenOptions`, `PngOptions`, `RetryOptions` and `TextBoxOptions`. You can now ignore the run that `Surface::text` returns: the text is drawn either way.
59
+ - The WASM module's `beginTag` and `beginArtifact` now take a structure type, table scope and artifact kind by name instead of by index, which breaks code that calls the module directly; `@laminapdf/sdk` already calls them that way. `@laminapdf/sdk` also exports the `LineCap`, `LineJoin` and `TableScope` types that `StrokeStyle` and `TagSpec` use, and `laminapdf-build`'s `FillRule`, `LineCap`, `LineJoin`, `BlendMode`, `ArtifactKind` and `TableScope` gain an `ALL` list of their variants.
60
+
61
+ ### Patch Changes
62
+
63
+ - Text copied from a standard 14 font no longer loses half of its last character when that text runs past 256 UTF-16 units and ends with a character outside the BMP, such as an emoji. Symbol and ZapfDingbats now write a `/CapHeight`, as every other font does, and `laminapdf-syntax` adds `Object::number` and `Object::rounded`.
64
+
65
+ ## 0.2.0-alpha.1
66
+
67
+ ### Minor Changes
68
+
69
+ - The library is called Lamina PDF, and its public names follow. `@laminapdf/sdk`'s error class is `LaminaPdfError`, checked with `isLaminaPdfError`, and its warnings are `LaminaPdfWarning`. The error object's JSON Schema is `laminapdf.error/1`. `@laminapdf/wasm`'s modules are `lamina_pdf_base`, `lamina_pdf_text`, `lamina_pdf_extract` and `lamina_pdf_render_hayro` (`.js`, `.d.ts` and `.wasm`).
70
+ - `@laminapdf/viewer` exports only its documented API: `ViewerClient`, `createViewer` and `Viewer`, the types of their options, events and state, the protocol types `client.call` takes, and `MIN_ZOOM`/`MAX_ZOOM`. Its internal helpers (layout, canvas pool, bitmap cache, tiles, zoom maths), its byte-source functions and its protocol constants are no longer exported. Its worker no longer keeps a log of every render, which grew without bound, and no longer serves test-only methods. `@laminapdf/sdk/worker/server`'s `serve()` takes a `saveBudget` (work units per save step), and `workerStats()` reports the handles and calls a worker holds. `@laminapdf/sdk/worker` exports the `Emitter` its client uses.
71
+ - A render `data-pending` thrown inside `@laminapdf/sdk`'s worker now reaches the page with its byte ranges: `LaminaPdfError.ranges` lists them. Before, they arrived empty. `RenderError` has a new `toDiagnostic()`, which returns the plain error object every Lamina PDF surface uses, and the worker posts that object for any error that has the method. `RenderError`'s `toJSON()`, `reviveRenderError` and `SerializedRenderError` are gone, and `ByteRange` and `RenderErrorKind` name its types. The viewer's worker now throws `RenderError`s for `cancelled` and `disposed` instead of plain objects, so they reach the page with a `docsUrl`.
72
+ - `@laminapdf/render` has one `WasmSource` type for where an engine's `.wasm` comes from (a URL, a `Response` or a promise of one, the bytes or a compiled module). `CloneableWasmSource` is the subset a Web Worker can be sent. `initPdfium` and `initHayro` both take it: `@laminapdf/render-pdfium`'s own `PdfiumWasm` type is gone, and `initHayro` no longer takes a `Request`, a promise of anything but a `Response`, or a view of a `SharedArrayBuffer`. `RenderBackend` declares `memory()`, which both backends already had; a backend written outside this repository has to add it. The adapters share the page-index check, the read handling and the pending-range merging, so hayro now reports adjacent missing reads as one range, as PDFium did.
73
+ - The `rotatePage` op now reads a `/Rotate` stored as an integral real, such as `90.0`, as the rotation the page displays; before, it read 0. `PageBuilder.rotate` now refuses angles other than 0, 90, 180 and 270, as its type says. In the Rust crates, `Rotation` from `laminapdf-syntax` replaces `laminapdf-render`'s `ViewRotation` and the degrees in `RenderPage::rotate`, and `laminapdf_cos::Page` drops `media_box`, `crop_box` and `rotate`: read them, and their strict-mode errors, from `laminapdf-model`'s page view.
74
+
75
+ ## 0.2.0-alpha.0
76
+
77
+ ### Minor Changes
78
+
79
+ - Accessible and archival PDFs. A `profiles` option on the builder (`PDF/UA-1`, `PDF/A-2b`, `PDF/A-2u`, `PDF/A-3b`; `BuildOptions::with_profile` in Rust) checks each machine-checkable rule the document breaks when it finishes, with a coded error per rule: `missing-title`, `missing-lang`, `untagged-content`, `missing-alt-text`, `heading-level-skipped`, `unnumbered-heading-misused`, `invalid-structure-nesting`, `link-without-structure`, `link-without-contents`, `font-not-embedded`, `glyph-without-unicode`, `device-color-without-output-intent`, `embedded-file-forbidden`, `embedded-file-without-mime-type` and `profile-version-conflict`. The builder writes the XMP identification, `/DisplayDocTitle` for PDF/UA-1 and, for PDF/A, an sRGB output intent with a 480-byte embedded ICC profile. `attach(name, bytes, mime, { relationship })` adds associated files for PDF/A-3b, such as an e-invoice's XML. Every example that claims a profile is validated by veraPDF each night.
80
+ - `@laminapdf/sdk/worker` can be extended: `@laminapdf/sdk/worker/server`'s `serve({ methods })` adds methods to the same worker, called with `client.request(method, params, { priority, key })`. The worker runs higher priorities first and coalesces calls with the same key. `emit()` sends events to `client.on("event")`, and `connect({ onDiscard })` sees late answers (by default it closes their ImageBitmaps). The worker protocol is now version 2.
81
+
82
+ ## 0.1.0-alpha.0
83
+
84
+ ### Minor Changes
85
+
86
+ - First alpha, `0.1.0-alpha.0`, versioned and tagged but not published (ADR 0017). The `lamina` façade and its core crates at the same version: open, read, edit and save PDFs (incremental and full rewrites, the save planner, undo/redo), generate them (pages, vectors, colour, images, standard 14 and embedded fonts with shaping, bidi and line breaking, links, outlines, metadata, tagged PDF), and extract page text; `@laminapdf/sdk` over the base, text and extract WebAssembly modules in browsers, Node, Deno, Bun and Cloudflare Workers.
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: "Error and warning codes"
3
+ description: "Every code Lamina PDF raises, generated from fixtures/codes.json when the site is built."
4
+ version: "0.2.0-alpha.3"
5
+ url: "https://docs.laminapdf.com/reference/codes/"
6
+ ---
7
+
8
+ # Error and warning codes
9
+
10
+ Every code Lamina PDF raises, generated from fixtures/codes.json when the site is built.
11
+
12
+ Every error and warning Lamina PDF raises, in Rust, in WebAssembly and in `@laminapdf/sdk`, has one of these codes. The tables below are read from `fixtures/codes.json` when this site is built: the same file `cargo xtask gen codes` generates the Rust enums and the TypeScript unions from. Each code links to its page on this site, which explains when it happens, why, how to fix it and what its `data` holds. See [Errors and warnings](../../pages/concepts/errors-and-warnings.md) for how to handle them.
13
+
14
+ See the [error and warning codes](../../errors/README.md).