@laminapdf/sdk 0.2.0-alpha.2 → 0.2.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -8
- package/dist/api.d.ts +8 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +4 -2
- package/dist/api.js.map +1 -1
- package/dist/builder.d.ts +43 -22
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +122 -83
- package/dist/builder.js.map +1 -1
- package/dist/document.d.ts +89 -22
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +177 -67
- package/dist/document.js.map +1 -1
- package/dist/errors.d.ts +5 -5
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -16
- package/dist/errors.js.map +1 -1
- package/dist/extract-job.d.ts +100 -0
- package/dist/extract-job.d.ts.map +1 -0
- package/dist/extract-job.js +177 -0
- package/dist/extract-job.js.map +1 -0
- package/dist/extract.d.ts +57 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +5 -0
- package/dist/extract.js.map +1 -0
- package/dist/font.d.ts +13 -6
- package/dist/font.d.ts.map +1 -1
- package/dist/font.js +50 -20
- package/dist/font.js.map +1 -1
- package/dist/generated/builder-enums.d.ts +3 -3
- package/dist/generated/builder-enums.d.ts.map +1 -1
- package/dist/generated/builder-enums.js +10 -0
- package/dist/generated/builder-enums.js.map +1 -1
- package/dist/generated/codes.d.ts +18 -6
- package/dist/generated/codes.d.ts.map +1 -1
- package/dist/generated/codes.js +114 -5
- package/dist/generated/codes.js.map +1 -1
- package/dist/generated/explain.d.ts.map +1 -1
- package/dist/generated/explain.js +45 -11
- package/dist/generated/explain.js.map +1 -1
- package/dist/generated/extract.d.ts +282 -0
- package/dist/generated/extract.d.ts.map +1 -0
- package/dist/generated/extract.js +4 -0
- package/dist/generated/extract.js.map +1 -0
- package/dist/init.d.ts +13 -5
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +23 -11
- package/dist/init.js.map +1 -1
- package/dist/internal/handle.d.ts +58 -0
- package/dist/internal/handle.d.ts.map +1 -0
- package/dist/internal/handle.js +113 -0
- package/dist/internal/handle.js.map +1 -0
- package/dist/internal/instance.d.ts +56 -0
- package/dist/internal/instance.d.ts.map +1 -0
- package/dist/internal/instance.js +125 -0
- package/dist/internal/instance.js.map +1 -0
- package/dist/source/http.d.ts +1 -1
- package/dist/source/http.js +2 -2
- package/dist/source/http.js.map +1 -1
- package/dist/source/range.d.ts +6 -1
- package/dist/source/range.d.ts.map +1 -1
- package/dist/source/range.js +10 -6
- package/dist/source/range.js.map +1 -1
- package/dist/text.d.ts +3 -3
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +3 -3
- package/dist/text.js.map +1 -1
- package/dist/types.d.ts +19 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/dist/worker/client.d.ts +3 -2
- package/dist/worker/client.d.ts.map +1 -1
- package/dist/worker/client.js +6 -4
- package/dist/worker/client.js.map +1 -1
- package/dist/worker/entry.js +1 -1
- package/dist/worker/entry.js.map +1 -1
- package/dist/worker/server.d.ts.map +1 -1
- package/dist/worker/server.js +42 -9
- package/dist/worker/server.js.map +1 -1
- package/dist/worker/support.d.ts +13 -3
- package/dist/worker/support.d.ts.map +1 -1
- package/dist/worker/support.js +5 -0
- package/dist/worker/support.js.map +1 -1
- package/dist/worker/types.d.ts +8 -1
- package/dist/worker/types.d.ts.map +1 -1
- package/docs/AGENTS.md +14 -0
- package/docs/api/README.md +166 -0
- package/docs/api/classes/Builder.md +467 -0
- package/docs/api/classes/Document.md +854 -0
- package/docs/api/classes/ExtractJob.md +236 -0
- package/docs/api/classes/Font.md +74 -0
- package/docs/api/classes/Image.md +140 -0
- package/docs/api/classes/LaminaPdfError.md +189 -0
- package/docs/api/classes/Page.md +178 -0
- package/docs/api/classes/PageRef.md +253 -0
- package/docs/api/classes/PageText.md +129 -0
- package/docs/api/classes/PageTextRun.md +167 -0
- package/docs/api/classes/PendingPath.md +97 -0
- package/docs/api/classes/SaveJob.md +205 -0
- package/docs/api/classes/Surface.md +331 -0
- package/docs/api/classes/Transaction.md +111 -0
- package/docs/api/functions/callbackSource.md +33 -0
- package/docs/api/functions/extractWithModels.md +70 -0
- package/docs/api/functions/httpRangeSource.md +48 -0
- package/docs/api/functions/init.md +36 -0
- package/docs/api/functions/isExtractLoaded.md +21 -0
- package/docs/api/functions/isInitialized.md +19 -0
- package/docs/api/functions/isLaminaPdfError.md +41 -0
- package/docs/api/functions/isTextLoaded.md +19 -0
- package/docs/api/functions/loadExtract.md +28 -0
- package/docs/api/functions/loadText.md +28 -0
- package/docs/api/functions/onLeak.md +29 -0
- package/docs/api/functions/reset.md +22 -0
- package/docs/api/functions/wasmMemory.md +22 -0
- package/docs/api/interfaces/BuilderOptions.md +108 -0
- package/docs/api/interfaces/ByteRange.md +29 -0
- package/docs/api/interfaces/ChunkOptions.md +37 -0
- package/docs/api/interfaces/Diagnostic.md +67 -0
- package/docs/api/interfaces/ExtractOptions.md +92 -0
- package/docs/api/interfaces/ExtractResult.md +37 -0
- package/docs/api/interfaces/FontInfo.md +37 -0
- package/docs/api/interfaces/HostModels.md +57 -0
- package/docs/api/interfaces/HttpRangeOptions.md +78 -0
- package/docs/api/interfaces/InitOptions.md +40 -0
- package/docs/api/interfaces/LayoutRegion.md +38 -0
- package/docs/api/interfaces/Leak.md +21 -0
- package/docs/api/interfaces/Location.md +53 -0
- package/docs/api/interfaces/ModelInfo.md +45 -0
- package/docs/api/interfaces/ModelRequest.md +45 -0
- package/docs/api/interfaces/Models.md +45 -0
- package/docs/api/interfaces/OcrWord.md +37 -0
- package/docs/api/interfaces/OpLog.md +25 -0
- package/docs/api/interfaces/OpenOptions.md +37 -0
- package/docs/api/interfaces/PageTextOptions.md +21 -0
- package/docs/api/interfaces/PathBuilder.md +195 -0
- package/docs/api/interfaces/QuadPoint.md +25 -0
- package/docs/api/interfaces/RangeOptions.md +54 -0
- package/docs/api/interfaces/RangeSource.md +59 -0
- package/docs/api/interfaces/StrokeStyle.md +61 -0
- package/docs/api/interfaces/TagSpec.md +69 -0
- package/docs/api/interfaces/TextBoxOptions.md +93 -0
- package/docs/api/interfaces/TextGlyph.md +29 -0
- package/docs/api/interfaces/TextOptions.md +101 -0
- package/docs/api/interfaces/WasmMemory.md +37 -0
- package/docs/api/type-aliases/AfRelationship.md +15 -0
- package/docs/api/type-aliases/Align.md +15 -0
- package/docs/api/type-aliases/ArtifactKind.md +15 -0
- package/docs/api/type-aliases/AttachmentOptions.md +15 -0
- package/docs/api/type-aliases/BlendMode.md +15 -0
- package/docs/api/type-aliases/BoxRect.md +15 -0
- package/docs/api/type-aliases/BuildOptions.md +15 -0
- package/docs/api/type-aliases/Cell.md +71 -0
- package/docs/api/type-aliases/Chunk.md +79 -0
- package/docs/api/type-aliases/Color.md +16 -0
- package/docs/api/type-aliases/Coordinates.md +55 -0
- package/docs/api/type-aliases/Direction.md +15 -0
- package/docs/api/type-aliases/DocumentInfo.md +15 -0
- package/docs/api/type-aliases/DropReason.md +15 -0
- package/docs/api/type-aliases/Dropped.md +59 -0
- package/docs/api/type-aliases/Edited.md +15 -0
- package/docs/api/type-aliases/ErrorCode.md +15 -0
- package/docs/api/type-aliases/ErrorKind.md +15 -0
- package/docs/api/type-aliases/ExtractFormat.md +15 -0
- package/docs/api/type-aliases/ExtractJobOptions.md +31 -0
- package/docs/api/type-aliases/ExtractStep.md +61 -0
- package/docs/api/type-aliases/ExtractedBlock.md +94 -0
- package/docs/api/type-aliases/ExtractedPage.md +73 -0
- package/docs/api/type-aliases/ExtractedSource.md +48 -0
- package/docs/api/type-aliases/Extraction.md +22 -0
- package/docs/api/type-aliases/FillRule.md +15 -0
- package/docs/api/type-aliases/Fit.md +15 -0
- package/docs/api/type-aliases/Flags.md +15 -0
- package/docs/api/type-aliases/Generator.md +43 -0
- package/docs/api/type-aliases/GlyphQuad.md +15 -0
- package/docs/api/type-aliases/InfoPatch.md +15 -0
- package/docs/api/type-aliases/LaminaPdfWarning.md +16 -0
- package/docs/api/type-aliases/LimitName.md +15 -0
- package/docs/api/type-aliases/Limits.md +15 -0
- package/docs/api/type-aliases/LineBox.md +15 -0
- package/docs/api/type-aliases/LineCap.md +15 -0
- package/docs/api/type-aliases/LineJoin.md +15 -0
- package/docs/api/type-aliases/LinkTarget.md +15 -0
- package/docs/api/type-aliases/Metadata.md +15 -0
- package/docs/api/type-aliases/ModelResult.md +15 -0
- package/docs/api/type-aliases/Op.md +15 -0
- package/docs/api/type-aliases/OutlineEntry.md +15 -0
- package/docs/api/type-aliases/OutlineNode.md +15 -0
- package/docs/api/type-aliases/Overflow.md +15 -0
- package/docs/api/type-aliases/PageInfo.md +15 -0
- package/docs/api/type-aliases/PageLabel.md +15 -0
- package/docs/api/type-aliases/PageSizeName.md +15 -0
- package/docs/api/type-aliases/Point.md +15 -0
- package/docs/api/type-aliases/Profile.md +15 -0
- package/docs/api/type-aliases/Progress.md +15 -0
- package/docs/api/type-aliases/ReadingOrder.md +15 -0
- package/docs/api/type-aliases/Rect.md +15 -0
- package/docs/api/type-aliases/Region.md +31 -0
- package/docs/api/type-aliases/RegionLabel.md +15 -0
- package/docs/api/type-aliases/RenderMode.md +15 -0
- package/docs/api/type-aliases/Rotation.md +15 -0
- package/docs/api/type-aliases/SaveOptions.md +15 -0
- package/docs/api/type-aliases/SaveReport.md +15 -0
- package/docs/api/type-aliases/Span.md +74 -0
- package/docs/api/type-aliases/SplitOn.md +15 -0
- package/docs/api/type-aliases/Standard14.md +15 -0
- package/docs/api/type-aliases/StructRef.md +41 -0
- package/docs/api/type-aliases/StructSource.md +17 -0
- package/docs/api/type-aliases/StructureKid.md +15 -0
- package/docs/api/type-aliases/StructureNode.md +16 -0
- package/docs/api/type-aliases/TableDetector.md +15 -0
- package/docs/api/type-aliases/TableMode.md +15 -0
- package/docs/api/type-aliases/TableScope.md +15 -0
- package/docs/api/type-aliases/Tag.md +15 -0
- package/docs/api/type-aliases/TagName.md +15 -0
- package/docs/api/type-aliases/Target.md +15 -0
- package/docs/api/type-aliases/TargetView.md +18 -0
- package/docs/api/type-aliases/TextLayer.md +72 -0
- package/docs/api/type-aliases/TextLayerStatus.md +15 -0
- package/docs/api/type-aliases/TextLayout.md +15 -0
- package/docs/api/type-aliases/TextRange.md +33 -0
- package/docs/api/type-aliases/TextRunInfo.md +15 -0
- package/docs/api/type-aliases/Transform.md +15 -0
- package/docs/api/type-aliases/UndoOutcome.md +15 -0
- package/docs/api/type-aliases/ViewerPreferences.md +15 -0
- package/docs/api/type-aliases/WarningCode.md +15 -0
- package/docs/api/type-aliases/WasmSource.md +16 -0
- package/docs/api/variables/Matrix.md +99 -0
- package/docs/api/variables/PAGE_SIZES.md +15 -0
- package/docs/api/variables/TAG_NAMES.md +15 -0
- package/docs/errors/README.md +173 -0
- package/docs/errors/aes-padding-invalid.md +34 -0
- package/docs/errors/already-initialized.md +34 -0
- package/docs/errors/binary-output-to-terminal.md +35 -0
- package/docs/errors/builder-finished.md +35 -0
- package/docs/errors/cancelled.md +35 -0
- package/docs/errors/cmap-invalid.md +42 -0
- package/docs/errors/collection-index.md +33 -0
- package/docs/errors/color-components.md +33 -0
- package/docs/errors/content-bad-operands.md +36 -0
- package/docs/errors/content-path-unpainted.md +36 -0
- package/docs/errors/content-resource-missing.md +37 -0
- package/docs/errors/content-syntax.md +36 -0
- package/docs/errors/content-unbalanced-bt.md +36 -0
- package/docs/errors/content-unbalanced-marked.md +36 -0
- package/docs/errors/content-unbalanced-q.md +36 -0
- package/docs/errors/content-unknown-operator.md +37 -0
- package/docs/errors/covered-text.md +33 -0
- package/docs/errors/data-pending.md +34 -0
- package/docs/errors/decompress.md +34 -0
- package/docs/errors/device-color-without-output-intent.md +33 -0
- package/docs/errors/direct-page.md +34 -0
- package/docs/errors/disposed.md +34 -0
- package/docs/errors/document-changed.md +34 -0
- package/docs/errors/embedded-file-forbidden.md +35 -0
- package/docs/errors/embedded-file-without-mime-type.md +36 -0
- package/docs/errors/encoding-full.md +34 -0
- package/docs/errors/encrypted-base.md +33 -0
- package/docs/errors/extract-column-order-uncertain.md +38 -0
- package/docs/errors/extract-limit-blocks.md +35 -0
- package/docs/errors/extract-module-not-loaded.md +37 -0
- package/docs/errors/extract-needs-ocr.md +37 -0
- package/docs/errors/extract-reading-order-ambiguous.md +32 -0
- package/docs/errors/extract-struct-tree-ignored.md +32 -0
- package/docs/errors/extract-table-ambiguous.md +32 -0
- package/docs/errors/extract-table-limit.md +35 -0
- package/docs/errors/extract-untagged-content.md +32 -0
- package/docs/errors/fetch-failed.md +34 -0
- package/docs/errors/flate-truncated.md +34 -0
- package/docs/errors/flow-content-too-large.md +34 -0
- package/docs/errors/flow-keep-broken.md +34 -0
- package/docs/errors/flow-layout-unstable.md +38 -0
- package/docs/errors/font-invalid.md +36 -0
- package/docs/errors/font-mismatch.md +34 -0
- package/docs/errors/font-not-embeddable.md +34 -0
- package/docs/errors/font-not-embedded.md +35 -0
- package/docs/errors/font-not-shapable.md +33 -0
- package/docs/errors/glyph-out-of-range.md +34 -0
- package/docs/errors/glyph-without-unicode.md +37 -0
- package/docs/errors/heading-level-skipped.md +36 -0
- package/docs/errors/image-data-length.md +33 -0
- package/docs/errors/image-too-large.md +32 -0
- package/docs/errors/inline-image-unterminated.md +36 -0
- package/docs/errors/input-unreadable.md +37 -0
- package/docs/errors/instance-reset.md +34 -0
- package/docs/errors/invalid-argument.md +33 -0
- package/docs/errors/invalid-axis-value.md +32 -0
- package/docs/errors/invalid-box.md +34 -0
- package/docs/errors/invalid-color.md +32 -0
- package/docs/errors/invalid-command-line.md +44 -0
- package/docs/errors/invalid-date.md +34 -0
- package/docs/errors/invalid-entry.md +34 -0
- package/docs/errors/invalid-feature.md +32 -0
- package/docs/errors/invalid-font.md +32 -0
- package/docs/errors/invalid-geometry.md +32 -0
- package/docs/errors/invalid-icc-profile.md +32 -0
- package/docs/errors/invalid-image.md +33 -0
- package/docs/errors/invalid-op-log.md +33 -0
- package/docs/errors/invalid-page-label.md +34 -0
- package/docs/errors/invalid-page-labels.md +32 -0
- package/docs/errors/invalid-page-range.md +37 -0
- package/docs/errors/invalid-rotate.md +34 -0
- package/docs/errors/invalid-spans.md +39 -0
- package/docs/errors/invalid-structure-nesting.md +38 -0
- package/docs/errors/invalid-structure.md +34 -0
- package/docs/errors/invalid-text-range.md +33 -0
- package/docs/errors/job-finished.md +34 -0
- package/docs/errors/limit-exceeded.md +38 -0
- package/docs/errors/link-without-contents.md +33 -0
- package/docs/errors/link-without-structure.md +37 -0
- package/docs/errors/markdown-html-ignored.md +33 -0
- package/docs/errors/markdown-image-missing.md +34 -0
- package/docs/errors/missing-alt-text.md +33 -0
- package/docs/errors/missing-glyph.md +33 -0
- package/docs/errors/missing-header.md +37 -0
- package/docs/errors/missing-lang.md +32 -0
- package/docs/errors/missing-root.md +34 -0
- package/docs/errors/missing-title.md +32 -0
- package/docs/errors/model-failed.md +33 -0
- package/docs/errors/model-needs-host.md +40 -0
- package/docs/errors/model-result-unexpected.md +36 -0
- package/docs/errors/name-tree-node-skipped.md +34 -0
- package/docs/errors/nested-transaction.md +34 -0
- package/docs/errors/no-pending-save.md +32 -0
- package/docs/errors/no-transaction.md +33 -0
- package/docs/errors/not-initialized.md +35 -0
- package/docs/errors/not-pdf.md +33 -0
- package/docs/errors/not-rebased.md +35 -0
- package/docs/errors/object-number-out-of-range.md +38 -0
- package/docs/errors/objstm-index-mismatch.md +36 -0
- package/docs/errors/out-of-memory.md +38 -0
- package/docs/errors/outline-cycle.md +34 -0
- package/docs/errors/outline-item-skipped.md +34 -0
- package/docs/errors/output-unwritable.md +37 -0
- package/docs/errors/overwrite-refused.md +36 -0
- package/docs/errors/page-count-mismatch.md +34 -0
- package/docs/errors/page-index-out-of-range.md +34 -0
- package/docs/errors/page-tree-node-skipped.md +35 -0
- package/docs/errors/password-required.md +36 -0
- package/docs/errors/path-outside-roots.md +32 -0
- package/docs/errors/perms-mismatch.md +34 -0
- package/docs/errors/profile-version-conflict.md +35 -0
- package/docs/errors/redaction-not-applied.md +32 -0
- package/docs/errors/reference-cycle.md +35 -0
- package/docs/errors/render-backend-unavailable.md +32 -0
- package/docs/errors/render-failed.md +33 -0
- package/docs/errors/render-too-large.md +36 -0
- package/docs/errors/repaired-base.md +34 -0
- package/docs/errors/requires-rewrite.md +38 -0
- package/docs/errors/revision-index-out-of-range.md +34 -0
- package/docs/errors/saved-not-rebased.md +34 -0
- package/docs/errors/sink-not-empty.md +33 -0
- package/docs/errors/sink.md +31 -0
- package/docs/errors/source-budget-exceeded.md +34 -0
- package/docs/errors/source-changed.md +33 -0
- package/docs/errors/source.md +30 -0
- package/docs/errors/stale-generation.md +34 -0
- package/docs/errors/stream-length-recovered.md +37 -0
- package/docs/errors/strict.md +34 -0
- package/docs/errors/subset-failed.md +31 -0
- package/docs/errors/syntax.md +34 -0
- package/docs/errors/tag-element-not-open.md +41 -0
- package/docs/errors/tag-element-unclosed.md +34 -0
- package/docs/errors/text-in-earlier-revision.md +36 -0
- package/docs/errors/text-module-not-loaded.md +36 -0
- package/docs/errors/text-overflow.md +34 -0
- package/docs/errors/tounicode-conflict.md +32 -0
- package/docs/errors/type.md +34 -0
- package/docs/errors/unexpected-eof.md +34 -0
- package/docs/errors/unknown-axis.md +33 -0
- package/docs/errors/unknown-code.md +36 -0
- package/docs/errors/unknown-destination.md +33 -0
- package/docs/errors/unknown-font.md +33 -0
- package/docs/errors/unknown-option.md +33 -0
- package/docs/errors/unknown-page.md +34 -0
- package/docs/errors/unmapped-glyph.md +36 -0
- package/docs/errors/unnumbered-heading-misused.md +34 -0
- package/docs/errors/unset-object.md +30 -0
- package/docs/errors/unsupported-filter.md +34 -0
- package/docs/errors/unsupported-image.md +33 -0
- package/docs/errors/unsupported-layout-option.md +33 -0
- package/docs/errors/unsupported-security-handler.md +34 -0
- package/docs/errors/unsupported-version.md +32 -0
- package/docs/errors/untagged-content.md +35 -0
- package/docs/errors/warnings-truncated.md +35 -0
- package/docs/errors/wasm-trap.md +37 -0
- package/docs/errors/whole-font-rebuilt.md +30 -0
- package/docs/errors/worker-crashed.md +33 -0
- package/docs/errors/worker-failed.md +32 -0
- package/docs/errors/worker-version-mismatch.md +34 -0
- package/docs/errors/would-invalidate-signatures.md +38 -0
- package/docs/errors/wrong-document.md +33 -0
- package/docs/errors/wrong-password.md +34 -0
- package/docs/errors/xobject-cycle.md +36 -0
- package/docs/errors/xref-repaired.md +36 -0
- package/docs/errors/xrefstm-ignored.md +34 -0
- package/docs/llms.txt +94 -0
- package/docs/pages/concepts/dependencies.md +44 -0
- package/docs/pages/concepts/drawing-pages.md +76 -0
- package/docs/pages/concepts/errors-and-warnings.md +68 -0
- package/docs/pages/concepts/how-lamina-thinks.md +98 -0
- package/docs/pages/concepts/pages-and-coordinates.md +75 -0
- package/docs/pages/guides/accessible-pdfs.md +262 -0
- package/docs/pages/guides/archival-pdfs.md +433 -0
- package/docs/pages/guides/edit-a-pdf.md +143 -0
- package/docs/pages/guides/flowing-pages.md +379 -0
- package/docs/pages/guides/fonts-and-text.md +204 -0
- package/docs/pages/guides/images-and-vectors.md +221 -0
- package/docs/pages/guides/keep-the-page-responsive.md +85 -0
- package/docs/pages/guides/links-outlines-and-metadata.md +224 -0
- package/docs/pages/guides/open-large-files.md +69 -0
- package/docs/pages/guides/password-protected-files.md +70 -0
- package/docs/pages/guides/save-a-pdf.md +154 -0
- package/docs/pages/guides/test-generated-pdfs.md +324 -0
- package/docs/pages/guides/untrusted-files.md +82 -0
- package/docs/pages/index.md +33 -0
- package/docs/pages/install.md +79 -0
- package/docs/pages/quick-start/browser.md +71 -0
- package/docs/pages/quick-start/bun.md +64 -0
- package/docs/pages/quick-start/deno.md +62 -0
- package/docs/pages/quick-start/node.md +65 -0
- package/docs/pages/quick-start/rust.md +62 -0
- package/docs/pages/quick-start/workers.md +139 -0
- package/docs/pages/recipes/cloudflare-worker.md +115 -0
- package/docs/pages/recipes/element-flow.md +248 -0
- package/docs/pages/recipes/extract-markdown.md +152 -0
- package/docs/pages/recipes/generate-then-edit.md +142 -0
- package/docs/pages/recipes/hello.md +101 -0
- package/docs/pages/recipes/images-and-vectors.md +216 -0
- package/docs/pages/recipes/invoice.md +233 -0
- package/docs/pages/recipes/links-and-outlines.md +222 -0
- package/docs/pages/recipes/multilingual.md +196 -0
- package/docs/pages/recipes/open-untrusted.md +65 -0
- package/docs/pages/recipes/pdf-a-archive.md +212 -0
- package/docs/pages/recipes/pdf-a3-invoice-with-xml.md +229 -0
- package/docs/pages/recipes/pdf-ua-report.md +244 -0
- package/docs/pages/recipes/report.md +125 -0
- package/docs/pages/recipes/web-worker-client.md +64 -0
- package/docs/pages/recipes.md +48 -0
- package/docs/pages/reference/benchmarks.md +93 -0
- package/docs/pages/reference/changelog.md +134 -0
- package/docs/pages/reference/codes.md +14 -0
- package/docs/pages/reference/glossary.md +108 -0
- package/docs/pages/reference/rust.md +36 -0
- package/docs/pages/reference/stability.md +59 -0
- package/docs/pages/start/coding-agents.md +45 -0
- package/docs/pages/start/first-pdf.md +81 -0
- package/docs/pages/troubleshooting.md +74 -0
- package/docs/renames.json +86 -0
- package/docs/schemas/error.schema.json +322 -0
- package/docs/schemas/renames.schema.json +29 -0
- package/package.json +7 -3
- package/schemas/error.schema.json +37 -3
|
@@ -0,0 +1,48 @@
|
|
|
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.4"
|
|
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. To test your own PDFs the same way, see [Test the PDFs you generate](../pages/guides/test-generated-pdfs.md).
|
|
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
|
+
- [Element flow](../pages/recipes/element-flow.md): a report whose parts each start below the one before, over two pages.
|
|
25
|
+
- [Links and outlines](../pages/recipes/links-and-outlines.md): links, an outline and page labels.
|
|
26
|
+
|
|
27
|
+
## Edit a PDF
|
|
28
|
+
|
|
29
|
+
- [Generate, then edit](../pages/recipes/generate-then-edit.md): open a file's bytes, change its metadata and save incrementally.
|
|
30
|
+
|
|
31
|
+
## Read a PDF
|
|
32
|
+
|
|
33
|
+
- [Extract text for an LLM](../pages/recipes/extract-markdown.md): Markdown, JSON with boxes, and chunks for retrieval, in TypeScript and Rust.
|
|
34
|
+
|
|
35
|
+
## Meet a standard
|
|
36
|
+
|
|
37
|
+
- [A PDF/UA report](../pages/recipes/pdf-ua-report.md): an accessible report a screen reader can follow.
|
|
38
|
+
- [A PDF/A archive](../pages/recipes/pdf-a-archive.md): a letter for long-term archiving.
|
|
39
|
+
- [A PDF/A-3 invoice with XML](../pages/recipes/pdf-a3-invoice-with-xml.md): an invoice with its data attached.
|
|
40
|
+
|
|
41
|
+
## Run it in production (TypeScript)
|
|
42
|
+
|
|
43
|
+
- [A 100-page report](../pages/recipes/report.md): the case Lamina PDF times in every runtime.
|
|
44
|
+
- [Open someone else's file](../pages/recipes/open-untrusted.md): a password and tighter limits, with the outcome as a value.
|
|
45
|
+
- [Save in a Web Worker](../pages/recipes/web-worker-client.md): progress and cancelling, off the main thread.
|
|
46
|
+
- [A Cloudflare Worker](../pages/recipes/cloudflare-worker.md): a PDF per request.
|
|
47
|
+
|
|
48
|
+
Next: [Hello, world](../pages/recipes/hello.md), the smallest PDF Lamina PDF writes.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Benchmarks"
|
|
3
|
+
description: "How fast Lamina PDF makes PDFs in each runtime, how large its WebAssembly files are, and how well it extracts text on a public benchmark."
|
|
4
|
+
version: "0.2.0-alpha.4"
|
|
5
|
+
url: "https://docs.laminapdf.com/reference/benchmarks/"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Benchmarks
|
|
9
|
+
|
|
10
|
+
How fast Lamina PDF makes PDFs in each runtime, how large its WebAssembly files are, and how well it extracts text on a public benchmark.
|
|
11
|
+
|
|
12
|
+
These are Lamina PDF's measured numbers: how long it takes to make a PDF in each runtime, how much your app downloads, and how well it extracts text from a public benchmark of real pages. Each table states the version, the date and the machine it came from, so you can judge how the numbers apply to yours.
|
|
13
|
+
|
|
14
|
+
## How long a PDF takes to make
|
|
15
|
+
|
|
16
|
+
Each figure is the time to build a document and save it to bytes, after the WebAssembly module has loaded. Every runtime builds the same three documents and gets the same bytes:
|
|
17
|
+
|
|
18
|
+
- **First PDF:** the first one-page "Hello" PDF after `init()`, before the runtime has optimised anything.
|
|
19
|
+
- **Hello:** the same PDF afterwards, the median of 20 builds.
|
|
20
|
+
- **One-page invoice:** the [invoice recipe](../../pages/recipes/invoice.md), a tagged A4 page with an embedded font and a table of items, the median of 20 builds.
|
|
21
|
+
- **100-page report:** the [report recipe](../../pages/recipes/report.md), with two embedded fonts and a table on every page, the median of 3 builds.
|
|
22
|
+
|
|
23
|
+
| Runtime | Version | First PDF | Hello | One-page invoice | 100-page report | WebAssembly memory |
|
|
24
|
+
| --- | --- | ---: | ---: | ---: | ---: | ---: |
|
|
25
|
+
| Node 24 | 24.19.0 | 19.8 ms | 0.8 ms | 3.5 ms | 222 ms | 4.3 MB |
|
|
26
|
+
| Deno | 2.9.6 | 23.8 ms | 0.7 ms | 3.6 ms | 238 ms | 4.3 MB |
|
|
27
|
+
| Bun | 1.4.4 | 14.9 ms | 1.4 ms | 3.6 ms | 151 ms | 4.3 MB |
|
|
28
|
+
| Cloudflare Workers (workerd) | 4.152.0 | 25.0 ms | 2.0 ms | 5.0 ms | 226 ms | 4.3 MB |
|
|
29
|
+
| Chromium | 1.64.1 | 18.3 ms | 0.7 ms | 3.7 ms | 215 ms | 4.3 MB |
|
|
30
|
+
| Firefox | 1.64.1 | 2.0 ms | 1.0 ms | 5.0 ms | 313 ms | 4.3 MB |
|
|
31
|
+
| WebKit (Safari's engine) | 1.64.1 | 28.0 ms | 2.5 ms | 4.0 ms | 169 ms | 4.3 MB |
|
|
32
|
+
| Rust, native | 1.99.1 | – | – | 0.9 ms | 45.9 ms | – |
|
|
33
|
+
|
|
34
|
+
Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.2 when the run began.
|
|
35
|
+
|
|
36
|
+
The browsers run in Playwright at the version shown, and Cloudflare Workers run in workerd through wrangler. WebAssembly memory is the modules' memory after the reports, in megabytes of 1,000,000 bytes. It never shrinks, so it is their peak. The JavaScript heap isn't included. The native Rust row is the same invoice and report built by the `laminapdf` crate, the median build as measured by criterion, a Rust benchmarking library.
|
|
37
|
+
|
|
38
|
+
## How much your app downloads
|
|
39
|
+
|
|
40
|
+
`@laminapdf/sdk` loads one WebAssembly file, chosen by what you use. `base` reads, edits and saves documents and draws shapes and images; `text` adds fonts and text; `extract` adds text extraction without the fonts. Each file has a size budget, and a change that grows a file past its budget can't be merged until the budget is raised on purpose.
|
|
41
|
+
|
|
42
|
+
| File | Gzip | Brotli | Budget (gzip) |
|
|
43
|
+
| --- | ---: | ---: | ---: |
|
|
44
|
+
| `lamina_pdf_base.wasm` | 400.0 kB | 318.2 kB | 410.0 kB |
|
|
45
|
+
| `lamina_pdf_extract.wasm` | 668.1 kB | 519.0 kB | 690.0 kB |
|
|
46
|
+
| `lamina_pdf_pdfium.wasm` | 2,158.0 kB | 1,653.6 kB | 2,243.2 kB |
|
|
47
|
+
| `lamina_pdf_render_hayro.wasm` | 1,781.7 kB | 1,392.4 kB | 1,855.0 kB |
|
|
48
|
+
| `lamina_pdf_text.wasm` | 1,153.0 kB | 875.5 kB | 1,200.0 kB |
|
|
49
|
+
| `@laminapdf/sdk` (JavaScript) | 19.2 kB | – | 20.0 kB |
|
|
50
|
+
| `@laminapdf/sdk/worker` (JavaScript) | 4.7 kB | – | 5.0 kB |
|
|
51
|
+
| `@laminapdf/sdk/worker/entry` (JavaScript) | 19.2 kB | – | 20.0 kB |
|
|
52
|
+
|
|
53
|
+
Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.2 when the run began.
|
|
54
|
+
|
|
55
|
+
Sizes are in kilobytes of 1,000 bytes, as a server sends them compressed. The JavaScript rows are `@laminapdf/sdk`'s code, minified: its API with the code that loads the WebAssembly, then the Web Worker client and the file that runs in the Web Worker.
|
|
56
|
+
|
|
57
|
+
## How well it extracts text
|
|
58
|
+
|
|
59
|
+
[olmOCR-bench](https://huggingface.co/datasets/allenai/olmOCR-bench), by the Allen Institute for AI, checks extracted text with small tests. A test checks that one passage comes before another, that a table cell sits beside its neighbours, or that a page's running header is left out. These figures use the three subsets made of pages that store their text, not scans, and the benchmark's own tests score the Markdown that Lamina PDF writes.
|
|
60
|
+
|
|
61
|
+
| Subset | What it checks | Pages | Tests | Passed | Score |
|
|
62
|
+
| --- | --- | ---: | ---: | ---: | ---: |
|
|
63
|
+
| `multi_column` | reading order: 884 tests that one passage comes before another, on 231 multi-column pages | 231 | 884 | 461 | 52.1 % |
|
|
64
|
+
| `table_tests` | tables: 1,020 tests that a cell's neighbours (up, down, left, right, headings) are right, and 2 baseline tests, on 188 pages | 188 | 1,022 | 245 | 24.0 % |
|
|
65
|
+
| `headers_footers` | running headers, footers and page numbers left out: 753 tests, and 7 baseline tests, on 266 pages | 266 | 760 | 457 | 60.1 % |
|
|
66
|
+
| Baseline | the page gave text, without long repeats (one test per page) | – | 676 | 578 | 85.5 % |
|
|
67
|
+
|
|
68
|
+
Overall, as the benchmark averages its groups, 55.4 %; without the baseline group, 45.4 %. 672 pages were extracted and 13 failed. On one thread that is 428 pages a second, with a median of 2.0 ms a page.
|
|
69
|
+
|
|
70
|
+
Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.7 when the run began.
|
|
71
|
+
|
|
72
|
+
Every page in the benchmark is a file of its own, so the time per page includes opening the file. A page with no text, such as a scan, counts against the score, as it would for you. Lamina PDF reads one page at a time on one thread here, without a layout model or OCR.
|
|
73
|
+
|
|
74
|
+
### Also looking for tables without ruled lines
|
|
75
|
+
|
|
76
|
+
Most tables in the benchmark have no ruled lines. Extraction finds tables like these when you ask it to look for text lined up in columns too: `tables: "lattice-and-stream"` in TypeScript, `TableMode::LatticeAndStream` in Rust. It finds more tables, but it reads some multi-column pages as tables, which costs those pages their reading order.
|
|
77
|
+
|
|
78
|
+
| Subset | What it checks | Pages | Tests | Passed | Score |
|
|
79
|
+
| --- | --- | ---: | ---: | ---: | ---: |
|
|
80
|
+
| `multi_column` | reading order: 884 tests that one passage comes before another, on 231 multi-column pages | 231 | 884 | 131 | 14.8 % |
|
|
81
|
+
| `table_tests` | tables: 1,020 tests that a cell's neighbours (up, down, left, right, headings) are right, and 2 baseline tests, on 188 pages | 188 | 1,022 | 480 | 47.0 % |
|
|
82
|
+
| `headers_footers` | running headers, footers and page numbers left out: 753 tests, and 7 baseline tests, on 266 pages | 266 | 760 | 456 | 60.0 % |
|
|
83
|
+
| Baseline | the page gave text, without long repeats (one test per page) | – | 676 | 578 | 85.5 % |
|
|
84
|
+
|
|
85
|
+
Overall, as the benchmark averages its groups, 51.8 %; without the baseline group, 40.6 %. 672 pages were extracted and 13 failed. On one thread that is 375 pages a second, with a median of 2.0 ms a page.
|
|
86
|
+
|
|
87
|
+
Measured with Lamina PDF 0.2.0-alpha.3 (commit `40c4179`) on 8 November 2026, on Apple M1 Pro (8 cores, 16 GB of memory), macOS 27.0.1, with a load average of 8.4 when the run began.
|
|
88
|
+
|
|
89
|
+
## Where these numbers come from
|
|
90
|
+
|
|
91
|
+
One command runs every measurement on one machine and writes the file this page reads, so no figure here is typed by hand. The numbers are one machine's, taken before a release. Each version of these docs keeps the numbers measured for it. Each table gives the machine's load average as its run began: how many jobs were running or waiting for a processor. A load average well above the core count means other jobs shared the machine, so the timings are slower than its best.
|
|
92
|
+
|
|
93
|
+
Next: [make your first PDF](../../pages/start/first-pdf.md) and time it on your own machine.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Changelog"
|
|
3
|
+
description: "What changed in each Lamina PDF release, newest first."
|
|
4
|
+
version: "0.2.0-alpha.4"
|
|
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.4
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- Extraction now leaves out text painted over by a later shape, image or annotation, as a reader can't see it either. A black box drawn over two words of a line takes those words out and keeps the rest of the line, so `Pay [box] now.` reads `Pay now.`. Covered text is listed under `dropped` with the new reason `covered`, its box and how many characters it held, never its text; `drop: { keepSpans: true }` shows it to an auditor. Only opaque paint drawn after the text covers it. A translucent box, a highlighter, shading under the text, a box in an optional layer and a scanned page's image over its own text layer all leave the text in. For Rust callers, `Flags` gains `covered`, `DropReason` gains `Covered`, and `BlendMode` now lives in `laminapdf-model` (`laminapdf::BlendMode` is unchanged).
|
|
19
|
+
- Running headers, footers and watermarks can now say what they are. `surface.artifact("footer", s => …)` marks its content as a footer attached to the bottom of the page (`/Subtype /Footer /Attached [/Bottom]`), `"header"` as a header attached to the top, and `"watermark"` as a watermark. `"pagination"` still writes the plain form. In Rust it is `Artifact::footer()`, `Artifact::header()` and `Artifact::watermark()`, with `with_attached` for other edges.
|
|
20
|
+
|
|
21
|
+
A paragraph split by a page break can now stay one paragraph for screen readers. In Rust, `surface.open_element(TagKind::P)` places it, `surface.resume(id, |s| …)` draws its content on that page or a later one, and `builder.close_element(id)` writes it.
|
|
22
|
+
|
|
23
|
+
`surface.measure_text_box(…)` (Rust) returns the layout `text_box` would draw, without drawing it.
|
|
24
|
+
|
|
25
|
+
Arabic text with diacritics now builds under PDF/UA-1 and PDF/A-2u: a letter the font draws as a body and a dot no longer fails with `glyph-without-unicode`.
|
|
26
|
+
- Rust flows can now have footnotes, a contents page and bookmarks. A footnote is a raised number in the text, numbered through the flow, with its note at the foot of the same page; a line whose notes don't fit moves to the next page with them. A contents page lists the headings with dot leaders, the page each one starts on and a link to it. The flow is laid out a second time to fill in the page numbers, and the new error code `flow-layout-unstable` reports a fault if they ever fail to settle. Every heading gets a bookmark in the document's outline, nested by level, which `Flow::with_outline(false)` turns off. Tagged documents can also use the `TOC`, `TOCI` and `Reference` structure types, which `@laminapdf/sdk` now accepts as tag names.
|
|
27
|
+
- Rust callers can now pour a document into as many pages as it needs. `Builder::flow` takes blocks (headings, paragraphs of styled text and links, lists, figures, spacers, page breaks and groups kept together) and a page template. The template sets the margins, a header, a footer and an optional different first page. Paragraphs split only between lines, leaving at least two lines at the foot and the head of a page. Headings stay with what follows them, and figures move whole. Headers and footers can show `{page}`, `{pages}`, `{section}` and `{title}`, so "Page 3 of 12" is right on every page. The output is tagged: each paragraph stays one element across pages, and headers and footers are marked as page furniture. New codes: `flow-content-too-large` for a line or figure taller than a page, and the warning `flow-keep-broken` for blocks kept together that can't fit on one page. The TypeScript package doesn't have flows yet.
|
|
28
|
+
- Rust flows can now hold tables that run across pages. A table's header rows repeat at the top of every page it continues on, no body row is split between pages, and its footer rows, such as a total, stay on the page of the last body row. Each column takes a fixed width, a share of the free width, or its widest cell's width, and the widths are worked out once so the columns line up on every page. Cells hold paragraphs, can span columns and align their text; a table sets its cells' padding and can have a frame, rules and a shaded header. The output is tagged as one table across all its pages, and the repeated header rows are marked as page furniture, so screen readers and text extraction read the header once. Tagged documents can also use the `THead`, `TBody` and `TFoot` structure types, which `@laminapdf/sdk` now accepts as tag names.
|
|
29
|
+
- Rust callers can now turn Markdown into flowing, tagged pages: `Builder::markdown(text, &MarkdownBuildOptions)` reads CommonMark with tables, footnotes, strikethrough and task lists, takes the title, language, author and subject from front matter, and lays the document out with the flow layer. Links to `#a-heading` go to that heading, and a table runs across pages with its header repeated. Images come only from the caller, through `MarkdownBuildOptions::with_image`; nothing is fetched. Raw HTML and images that weren't passed are left out with the warnings `markdown-html-ignored` and `markdown-image-missing`, which give the position in the Markdown, never its text.
|
|
30
|
+
|
|
31
|
+
If you pass no fonts, the builder sets the document in Helvetica and Courier, which flows can now use. They set Latin text only, and a PDF/UA-1 build refuses them.
|
|
32
|
+
|
|
33
|
+
Flows also gain code spans and code blocks, struck-out text, block quotes (`BlockQuote`), thematic breaks and lists that start at any number. The `laminapdf` crate's new `markdown` feature is on by default.
|
|
34
|
+
- Text runs and text boxes now say where the next element can start. What `surface.text()` and `surface.textBox()` return has a `bottom`: the bottom of the last line that draws something, where the next text box's top can go. In Rust it is `TextRun::bottom()` and `TextLayout::bottom()`. It is left out when nothing is drawn, such as empty text, text of only white space, or a box too short for one line, so an empty section adds no gap. A clipped box gives its last drawn line; check `overflow !== undefined` before treating the text as placed.
|
|
35
|
+
- Read a document's outline and named destinations, and move through it with thumbnails. `Document.outline()` gives the outline's items with their titles, whether each starts expanded, and where each goes: a page and a view in page space (points from the displayed page's top-left, y down), whichever coordinates the file used. `Document.namedDestination(name)` finds one named destination. Both need the extract or text module, like `page.text()`.
|
|
36
|
+
|
|
37
|
+
In `@laminapdf/viewer`, `ViewerClient.outline()` and `namedDestination(name)` read them in the document Web Worker, and `Viewer.goToDestination(target)` shows an item's or a destination's target, with each kind of fit. `ThumbnailStrip` is a list of the pages as small pictures. It mounts only the thumbnails near its view, renders after the main view's pages and goes to a page on a click or a key.
|
|
38
|
+
- `doc.structureTree()` reads a tagged document's structure tree: its elements in reading order, down to the marked content each owns on a page. Each element gives its standard type (`H1`, `P`, `LI`, `Figure` …), alternate text, language and actual text; custom types resolve through the role map. A text run's `mcid` links it to its element, so a viewer can give assistive technology a document's headings, paragraphs, lists and tables.
|
|
39
|
+
|
|
40
|
+
`doc.isTagged` says whether the document claims to be tagged. Both need the extract or text module, as `page.text()` does. For Rust callers, `Document::structure_tree()` returns `StructureNode`s.
|
|
41
|
+
- Rust callers can now lay out a paragraph whose words change font, size or language: a bold word inside a sentence, a superscript, an Arabic name in an English line. `laminapdf_text::break_spans` takes the text and a list of `StyledSpan`s, each covering a stretch of it with its own fonts, size, baseline rise, language and OpenType features. Lines still break only where the text allows, so a style change inside a word never splits it. Spans of one style are shaped together, so kerning carries across them. Each line reports its ascent and descent from its tallest run, and `pdf_line_run` draws a superscript's rise. `break_lines` is unchanged. Spans that don't cover the text once, in order, that split a letter from its accent, or that name no font or a font past the list fail with the new error code `invalid-spans`.
|
|
42
|
+
- The Rust façade reads a document's outline (`Document::outline()`) and named destinations (`Document::named_destination(name)`), each target a page index and a view in page space. The extract and text modules give them to JavaScript as `WasmDocument.outline()` and `namedDestination(name)`.
|
|
43
|
+
- The viewer is sharp at every zoom level. It sized each page's canvas and sharp tiles from the page's CSS width times the pixel ratio, while the renderer sizes the page in 32-bit floats, so at most zoom levels the right-hand tile came out one pixel wider than the page. The renderer refused it, and the rest of the page stayed blurry. `@laminapdf/render` now exports `pagePixels`, the page's size in pixels at a scale as its planner computes it, and the viewer sizes canvases and tiles with it.
|
|
44
|
+
- The viewer keeps the page in view sharp at every zoom up to 800 %. Each page's canvas now holds at most 8 million pixels; a larger page keeps that canvas as a backdrop, and a detail canvas over the part in view takes the sharp tiles at the full pixel ratio. The detail canvas's size follows the viewport rather than the zoom, so the canvases fit the same memory as before. `createViewer` takes a `detailPool` option, and the render stats count `detailCanvases`.
|
|
45
|
+
- Find now lists its results. `viewer.find.results()` gives every match found so far in document order, each with its page and a snippet of the text around it, and `goTo(ordinal)` goes to one. The web reader shows them in a Results tab in the sidebar while find is open.
|
|
46
|
+
- Find text across a whole document. `viewer.find` searches from the current page forward and wraps round, so scrolling never waits. Results stream in by page, and the first match shows as soon as it's found. `next()` and `previous()` move between matches and scroll each into view, and the matches on the page are highlighted. Options cover case, whole words and diacritics. Match counts agree with pdf.js's find. `ViewerClient.find(query, options, pages)` is the call underneath.
|
|
47
|
+
- The document worker now counts every network request it makes from the moment it starts: `client.networkLog()` returns them all, with the requests its Content Security Policy blocked, and the `network` and `csp-violation` events report each as it happens. `watchNetwork` does the counting and is exported for the page too: it wraps `fetch`, `XMLHttpRequest`, `WebSocket` and `sendBeacon` and reads everything else the browser loads from Resource Timing.
|
|
48
|
+
- The viewer opens remote PDFs: `client.open({ url })` makes the document worker fetch the file itself with HTTP Range requests, so its bytes never pass through the page. Lamina PDF reads the file range by range, and a render fetches the bytes it needs, so page 1 of a large file appears after a small part of it has arrived. Requests send no cookies or referrer and skip the HTTP cache. A server that ignores `Range` sends the whole file, which the viewer accepts up to 256 MiB. The new `progress` event reports how much has been read.
|
|
49
|
+
- Every page's text is selectable and copyable, and a tagged document reads well in a screen reader. The viewer lays one transparent span over each text run of Lamina PDF's extraction, aligned to the rendered glyphs at every zoom and rotation, in any script. A selection runs from one page into the next, and the pages it touches stay mounted while you scroll away. Copy writes the extracted text in reading order. A tagged document's structure tree becomes a hidden tree of headings, paragraphs, lists, tables and figures that owns the spans.
|
|
50
|
+
|
|
51
|
+
`createViewer`'s `text` option turns the layer off or sets `outline`, `untaggedLabel` and `onSelection`. `Viewer.keepMounted(pages)` pins pages. `ViewerClient.pageText(index)` and `structure()` give a page's runs and glyph quads and the document's structure tree. The document Web Worker loads the extract module once the render backend is ready, so the first page never waits for it.
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- `ViewerClient.open` now returns the document's title from its metadata as `title`, when the file has one, so an app can name its window after the document.
|
|
56
|
+
- A mouse drag selects a page's text again. The layer slots above the text covered the whole page and took every press; every slot but `text` now lets the pointer through. A layer added with `addLayer` gets such a slot too, so an element in it that should be clicked, such as a link, sets `pointer-events: auto` on itself.
|
|
57
|
+
|
|
58
|
+
A selection's colour no longer hides the text it selects: the text layer (`.lamina-text-layer`) now has `mix-blend-mode: multiply`, so an opaque `::selection` tint shows under the ink.
|
|
59
|
+
- The page no longer flickers while zooming. Each pause in a pinch or ctrl+wheel zoom repainted the page for its new zoom with the blurry low-resolution pass, throwing away the sharp pixels it showed; the repaint now keeps those pixels, scaled, until the sharp tiles for the new zoom replace them.
|
|
60
|
+
- When you zoom out far enough that more than three pages show, every page now turns sharp. Before, the first three did and the rest stayed blurry for good, because the canvas pool's rounding to whole pixels counted as a cap and every page waited for one of three detail canvases.
|
|
61
|
+
|
|
62
|
+
## 0.2.0-alpha.3
|
|
63
|
+
|
|
64
|
+
### Minor Changes
|
|
65
|
+
|
|
66
|
+
- 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`.
|
|
67
|
+
- 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.
|
|
68
|
+
|
|
69
|
+
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()`.
|
|
70
|
+
- `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.
|
|
71
|
+
- 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/`.
|
|
72
|
+
- 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.
|
|
73
|
+
- Breaking (Rust, while alpha): every public type now has a name of its own, and each item one public path.
|
|
74
|
+
|
|
75
|
+
- An extracted run is `PageTextRun` (`laminapdf::extract::PageTextRun`, `laminapdf_text::PageTextRun`), the name `@laminapdf/sdk` already gives it. `TextRun` now means only drawn text.
|
|
76
|
+
- `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`.
|
|
77
|
+
- `laminapdf-text`'s OpenType tag is `OpenTypeTag`, and the façade exports it for `Font::instance(&[(OpenTypeTag::WEIGHT, 700.0)])`.
|
|
78
|
+
- `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.
|
|
79
|
+
- `laminapdf::Document::ops` and `into_ops` are hidden from the docs. They stay for Lamina PDF's own crates, and may change without notice.
|
|
80
|
+
|
|
81
|
+
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.
|
|
82
|
+
- 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`.
|
|
83
|
+
- 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.
|
|
84
|
+
- 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`.
|
|
85
|
+
- 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:
|
|
86
|
+
|
|
87
|
+
- `Matrix::translate` takes two `f64`s instead of two `Pt`s.
|
|
88
|
+
- `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)`.
|
|
89
|
+
- 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`.
|
|
90
|
+
- `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`.
|
|
91
|
+
- `Dash` is `#[non_exhaustive]`: build one with `Dash::new`. The content reader's `Matrix::from_object` is removed.
|
|
92
|
+
- The content reader's current colour, `laminapdf_content::Color`, is now `CurrentColor`, so `Color` means only the builder's colour.
|
|
93
|
+
|
|
94
|
+
The JavaScript API and every output are unchanged.
|
|
95
|
+
|
|
96
|
+
### Patch Changes
|
|
97
|
+
|
|
98
|
+
- `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.
|
|
99
|
+
- 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.
|
|
100
|
+
- 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.
|
|
101
|
+
|
|
102
|
+
## 0.2.0-alpha.2
|
|
103
|
+
|
|
104
|
+
### Minor Changes
|
|
105
|
+
|
|
106
|
+
- `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.
|
|
107
|
+
- 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.
|
|
108
|
+
|
|
109
|
+
### Patch Changes
|
|
110
|
+
|
|
111
|
+
- 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`.
|
|
112
|
+
|
|
113
|
+
## 0.2.0-alpha.1
|
|
114
|
+
|
|
115
|
+
### Minor Changes
|
|
116
|
+
|
|
117
|
+
- 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`).
|
|
118
|
+
- `@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.
|
|
119
|
+
- 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`.
|
|
120
|
+
- `@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.
|
|
121
|
+
- 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.
|
|
122
|
+
|
|
123
|
+
## 0.2.0-alpha.0
|
|
124
|
+
|
|
125
|
+
### Minor Changes
|
|
126
|
+
|
|
127
|
+
- 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.
|
|
128
|
+
- `@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.
|
|
129
|
+
|
|
130
|
+
## 0.1.0-alpha.0
|
|
131
|
+
|
|
132
|
+
### Minor Changes
|
|
133
|
+
|
|
134
|
+
- 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.4"
|
|
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).
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Glossary"
|
|
3
|
+
description: "The PDF and Lamina PDF terms the docs use, each in a sentence or two."
|
|
4
|
+
version: "0.2.0-alpha.4"
|
|
5
|
+
url: "https://docs.laminapdf.com/reference/glossary/"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Glossary
|
|
9
|
+
|
|
10
|
+
The PDF and Lamina PDF terms the docs use, each in a sentence or two.
|
|
11
|
+
|
|
12
|
+
The terms the docs use, in plain words. Each page links a term here the first time it uses one.
|
|
13
|
+
|
|
14
|
+
## How Lamina PDF works
|
|
15
|
+
|
|
16
|
+
### Overlay
|
|
17
|
+
|
|
18
|
+
Where Lamina PDF keeps your edits. The bytes you opened never change; the overlay sits on top of them, and saving writes it out. See [how Lamina PDF thinks about a PDF](../../pages/concepts/how-lamina-thinks.md).
|
|
19
|
+
|
|
20
|
+
### Incremental save
|
|
21
|
+
|
|
22
|
+
A save that keeps the original bytes as they are and appends a new revision with your edits after them. Signatures over the original stay valid.
|
|
23
|
+
|
|
24
|
+
### Full rewrite
|
|
25
|
+
|
|
26
|
+
A save that writes the whole file again. The result is smaller and tidier, but it's no longer the original bytes, so it breaks any signature.
|
|
27
|
+
|
|
28
|
+
### Façade
|
|
29
|
+
|
|
30
|
+
The `laminapdf` crate: one API in front of Lamina PDF's core crates, which most Rust code depends on alone.
|
|
31
|
+
|
|
32
|
+
### Glue
|
|
33
|
+
|
|
34
|
+
The JavaScript that sits next to each `.wasm` file. It loads the module and converts values between JavaScript and Rust.
|
|
35
|
+
|
|
36
|
+
### Export condition
|
|
37
|
+
|
|
38
|
+
A key in a package's `exports` map, such as `node`, `browser`, `deno` or `workerd`, that tells a runtime or bundler which file to load. `@laminapdf/sdk` has one per runtime.
|
|
39
|
+
|
|
40
|
+
## Inside a PDF file
|
|
41
|
+
|
|
42
|
+
### COS
|
|
43
|
+
|
|
44
|
+
PDF's object layer: the dictionaries, arrays, numbers, strings, names, streams and references a file is made of.
|
|
45
|
+
|
|
46
|
+
### Content stream
|
|
47
|
+
|
|
48
|
+
A stream of drawing instructions for a page: where to put text, which lines and shapes to draw, which images to place.
|
|
49
|
+
|
|
50
|
+
### XObject
|
|
51
|
+
|
|
52
|
+
A reusable piece of content that a content stream draws by name: an image, or a form, which is a group of drawing instructions.
|
|
53
|
+
|
|
54
|
+
### Cross-reference table
|
|
55
|
+
|
|
56
|
+
The index at the end of a file that gives the byte offset of every object, so a reader can jump straight to one. Newer files store it as a compressed stream instead.
|
|
57
|
+
|
|
58
|
+
### Xref
|
|
59
|
+
|
|
60
|
+
Short for [cross-reference table](#cross-reference-table).
|
|
61
|
+
|
|
62
|
+
### Object stream
|
|
63
|
+
|
|
64
|
+
A compressed stream that holds many small objects together, to make the file smaller. Files from PDF 1.5 on can use them.
|
|
65
|
+
|
|
66
|
+
### Page space
|
|
67
|
+
|
|
68
|
+
Lamina PDF's coordinates: points from the top-left corner of the page as it's displayed, with y going down. See [pages and coordinates](../../pages/concepts/pages-and-coordinates.md).
|
|
69
|
+
|
|
70
|
+
### Crop box
|
|
71
|
+
|
|
72
|
+
The part of a page a viewer shows; anything outside it is cut off. Page space starts at its top-left corner.
|
|
73
|
+
|
|
74
|
+
### User unit
|
|
75
|
+
|
|
76
|
+
A page entry that makes each user-space unit bigger than 1/72 of an inch, for very large pages. Lamina PDF applies it, so page-space numbers are always points of 1/72 inch.
|
|
77
|
+
|
|
78
|
+
### User space
|
|
79
|
+
|
|
80
|
+
PDF's own coordinates: points from the bottom-left corner of the page, with y going up, before any rotation. Lamina PDF's API uses page space instead; see [pages and coordinates](../../pages/concepts/pages-and-coordinates.md).
|
|
81
|
+
|
|
82
|
+
## Fonts and text
|
|
83
|
+
|
|
84
|
+
### Standard 14 fonts
|
|
85
|
+
|
|
86
|
+
The fourteen fonts every PDF reader supplies: Times, Helvetica and Courier, each in four styles, plus Symbol and ZapfDingbats. A PDF can use them without embedding them.
|
|
87
|
+
|
|
88
|
+
### Type 0
|
|
89
|
+
|
|
90
|
+
A font type whose character codes can be more than one byte long, so a font can reach any of its glyphs. Lamina PDF embeds every font except the standard 14 as Type 0.
|
|
91
|
+
|
|
92
|
+
### CMap
|
|
93
|
+
|
|
94
|
+
A table that maps a font's character codes to character IDs (CIDs), which pick its glyphs, or, in a ToUnicode CMap, to Unicode text.
|
|
95
|
+
|
|
96
|
+
### ToUnicode
|
|
97
|
+
|
|
98
|
+
A CMap a font carries that maps its codes to Unicode, so a reader can copy, search and extract the text.
|
|
99
|
+
|
|
100
|
+
## Signatures
|
|
101
|
+
|
|
102
|
+
### DocMDP
|
|
103
|
+
|
|
104
|
+
The permissions of a certifying signature: which changes the signed document still allows, such as none, filling in forms, or comments. DocMDP stands for document modification detection and prevention.
|
|
105
|
+
|
|
106
|
+
### UR3
|
|
107
|
+
|
|
108
|
+
A usage-rights signature, which unlocks features such as saving form data in Adobe Reader. An edit it doesn't allow invalidates it.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Rust API (rustdoc)"
|
|
3
|
+
description: "Where to read the API documentation of the Lamina PDF crates."
|
|
4
|
+
version: "0.2.0-alpha.4"
|
|
5
|
+
url: "https://docs.laminapdf.com/reference/rust/"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Rust API (rustdoc)
|
|
9
|
+
|
|
10
|
+
Where to read the API documentation of the Lamina PDF crates.
|
|
11
|
+
|
|
12
|
+
docs.rs builds the API documentation of every Lamina PDF crate on crates.io. Start with [`laminapdf` on docs.rs](https://docs.rs/laminapdf/0.2.0-alpha.4/laminapdf/), the crate to depend on. It wraps the core crates and holds `Document`, `Builder`, `Error`, `Warning`, jobs and `CancelToken`.
|
|
13
|
+
|
|
14
|
+
The other crates are documented the same way:
|
|
15
|
+
|
|
16
|
+
- [`laminapdf-syntax`](https://docs.rs/laminapdf-syntax/0.2.0-alpha.4/laminapdf_syntax/)
|
|
17
|
+
- [`laminapdf-cos`](https://docs.rs/laminapdf-cos/0.2.0-alpha.4/laminapdf_cos/)
|
|
18
|
+
- [`laminapdf-model`](https://docs.rs/laminapdf-model/0.2.0-alpha.4/laminapdf_model/)
|
|
19
|
+
- [`laminapdf-ops`](https://docs.rs/laminapdf-ops/0.2.0-alpha.4/laminapdf_ops/)
|
|
20
|
+
- [`laminapdf-save`](https://docs.rs/laminapdf-save/0.2.0-alpha.4/laminapdf_save/)
|
|
21
|
+
- [`laminapdf-content`](https://docs.rs/laminapdf-content/0.2.0-alpha.4/laminapdf_content/)
|
|
22
|
+
- [`laminapdf-text`](https://docs.rs/laminapdf-text/0.2.0-alpha.4/laminapdf_text/)
|
|
23
|
+
- [`laminapdf-build`](https://docs.rs/laminapdf-build/0.2.0-alpha.4/laminapdf_build/)
|
|
24
|
+
- [`laminapdf-render-pdfium`](https://docs.rs/laminapdf-render-pdfium/0.2.0-alpha.4/laminapdf_render_pdfium/)
|
|
25
|
+
|
|
26
|
+
docs.rs couldn't build `laminapdf-source` and `laminapdf-render` at 0.2.0-alpha.2, so their docs come with the next release; until then, build them yourself as below. [Install](../../pages/install.md#every-published-package) lists every crate, with its page on crates.io.
|
|
27
|
+
|
|
28
|
+
## Build the docs yourself
|
|
29
|
+
|
|
30
|
+
To read the docs of a change before it's released, build them from a checkout of Lamina PDF:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
cargo doc --workspace --no-deps --all-features --open
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The command opens the docs in your browser. Every public item of every crate is documented.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Stability policy"
|
|
3
|
+
description: "What a Lamina PDF version number promises, and what stays the same in every version."
|
|
4
|
+
version: "0.2.0-alpha.4"
|
|
5
|
+
url: "https://docs.laminapdf.com/reference/stability/"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Stability policy
|
|
9
|
+
|
|
10
|
+
What a Lamina PDF version number promises, and what stays the same in every version.
|
|
11
|
+
|
|
12
|
+
Lamina PDF is in alpha, so its API can still change from one release to the next. A few things never change, whatever the version: error and warning codes, the error object's fields, saved edit logs, and identical output from every runtime. This page says what each version number promises, so you know when an upgrade needs a code change.
|
|
13
|
+
|
|
14
|
+
## One version for every package
|
|
15
|
+
|
|
16
|
+
Every crate and every npm package shares one version, and they are released together, from `laminapdf` and its crates to `@laminapdf/sdk` and the viewer. So `@laminapdf/sdk` at a version always runs the Rust code of `laminapdf` at the same version. [Install](../../pages/install.md#every-published-package) lists every package.
|
|
17
|
+
|
|
18
|
+
## What a version number tells you
|
|
19
|
+
|
|
20
|
+
- **Alphas promise nothing to each other.** Anything can change between `0.2.0-alpha.1` and `0.2.0-alpha.2`. While you try an alpha, pin the exact version: `npm install --save-exact @laminapdf/sdk@0.2.0-alpha.4`, and `laminapdf = "=0.2.0-alpha.4"` in `Cargo.toml`.
|
|
21
|
+
- **The `alpha` tag names the newest alpha.** `npm install @laminapdf/sdk@alpha` gets it. A plain `npm install @laminapdf/sdk` gets a `0.0.0` placeholder that only reserves the name.
|
|
22
|
+
- **After the alphas, `0.x` versions follow SemVer as Cargo reads it.** A breaking change raises the minor version (`0.2` to `0.3`), and features and fixes raise the patch (`0.2.0` to `0.2.1`). So an upgrade within one `0.x` line never needs a code change.
|
|
23
|
+
|
|
24
|
+
## What counts as a breaking change
|
|
25
|
+
|
|
26
|
+
A change breaks your code when it does one of these:
|
|
27
|
+
|
|
28
|
+
- removes or renames a public Rust item or an export of `@laminapdf/sdk`
|
|
29
|
+
- changes one so that code using it stops compiling or behaves differently from its documentation
|
|
30
|
+
- raises the minimum Rust version, the minimum Node version or the Cloudflare Workers `compatibility_date`
|
|
31
|
+
- adds an error kind, since code that matches on the nine kinds has to handle the new one
|
|
32
|
+
- changes the bytes written for the same input and options
|
|
33
|
+
|
|
34
|
+
Everything else keeps your code working: new functions, types, options and fields; new error and warning codes; documentation; speed; and fixes that make output follow the PDF standard where it didn't. The changelog lists those fixes.
|
|
35
|
+
|
|
36
|
+
## What never changes
|
|
37
|
+
|
|
38
|
+
Four promises hold across every version, `0.x` and alphas included:
|
|
39
|
+
|
|
40
|
+
- **Error and warning codes are never renamed or reused** for another meaning. A retired code stays in the [code reference](../../errors/README.md) with the version that retired it, and keeps its page. New codes can appear in any release, so handle a code you don't know.
|
|
41
|
+
- **The error object only grows.** Each error names its schema, `laminapdf.error/1`. Within one schema, a field can be added, but never removed or given another type.
|
|
42
|
+
- **Saved edit logs keep loading.** A log names its format version (`{ v: 1, ops }`, as [Edit a PDF](../../pages/guides/edit-a-pdf.md#replay-edits-stored-as-json) shows). A new op or optional field keeps the version. A changed or removed one raises it, and every older version still loads.
|
|
43
|
+
- **The same input gives the same bytes everywhere.** With the same input, options and version, Rust and every JavaScript runtime write identical files, so you can [test your PDFs against reference PDFs](../../pages/guides/test-generated-pdfs.md).
|
|
44
|
+
|
|
45
|
+
## How the promises are checked
|
|
46
|
+
|
|
47
|
+
Lamina PDF compares every change with the newest published release: the Rust crates with [cargo-semver-checks](https://github.com/obi1kenobi/cargo-semver-checks), and `@laminapdf/sdk` with a report of its exported types. A change that breaks either one has to raise the minor version, and the changelog lists it first.
|
|
48
|
+
|
|
49
|
+
Each release also installs itself twice and runs the quick start: once from the packages before they're published, and once from npm and crates.io after. Both runs cover Node 22, 24 and 26, Deno, Bun, Chromium, Cloudflare Workers and a Rust program, and every run has to write the same `hello.pdf`, byte for byte.
|
|
50
|
+
|
|
51
|
+
## What isn't promised yet
|
|
52
|
+
|
|
53
|
+
- The low-level file-structure and model types that `laminapdf` re-exports are public, but they can change in any minor release.
|
|
54
|
+
- Package sizes and speed are measured on every change, not promised.
|
|
55
|
+
- The minimum Rust version is two releases behind the newest stable Rust (1.97 today). Raising it is a minor-version change, and the changelog says so.
|
|
56
|
+
|
|
57
|
+
## Before you upgrade
|
|
58
|
+
|
|
59
|
+
The [changelog](../../pages/reference/changelog.md) lists every release's changes, breaking ones first. Read the entries between your version and the new one, then move the exact version you pin.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Use Lamina PDF with coding agents"
|
|
3
|
+
description: "Point a coding agent at the docs inside the installed package, so its answers match the version you use."
|
|
4
|
+
version: "0.2.0-alpha.4"
|
|
5
|
+
url: "https://docs.laminapdf.com/start/coding-agents/"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Use Lamina PDF with coding agents
|
|
9
|
+
|
|
10
|
+
Point a coding agent at the docs inside the installed package, so its answers match the version you use.
|
|
11
|
+
|
|
12
|
+
A coding agent guesses a new library's names from what it saw in training, which may be an older version or none at all. Each package therefore carries its own copy of these docs as Markdown. The copy sits in `node_modules/@laminapdf/sdk/docs/` for TypeScript and in the `laminapdf` crate's `docs/` folder for Rust, and every file names the version it describes.
|
|
13
|
+
|
|
14
|
+
## Add the snippet to your agent's instructions
|
|
15
|
+
|
|
16
|
+
Copy this snippet into your project's `AGENTS.md`, `CLAUDE.md` or the file your agent reads. It sends the agent to the installed docs first, and it lists the rules where Lamina PDF differs from other PDF libraries:
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/AGENTS.md`:
|
|
19
|
+
|
|
20
|
+
```md
|
|
21
|
+
## Lamina PDF
|
|
22
|
+
|
|
23
|
+
This project uses Lamina PDF (`@laminapdf/sdk` in TypeScript, the `laminapdf` crate in Rust) to create, read, edit and save PDF files.
|
|
24
|
+
|
|
25
|
+
- **Read the installed docs first.** They match the installed version: `node_modules/@laminapdf/sdk/docs/llms.txt` lists every page, and `docs/api/` holds the API reference. In Rust they are in the `laminapdf` crate's `docs/` folder. Online: https://docs.laminapdf.com/llms.txt (the latest version).
|
|
26
|
+
- **Call `await init()` once before anything else.** After it every call is synchronous. Fonts and text need `await init({ text: true })`; reading text needs the extract or text module (`await init({ extract: true })` or `{ text: true }`). Rust needs no setup.
|
|
27
|
+
- **Positions are points from the top-left corner** of the page as it is displayed, with y going down. A text position is its baseline. Page numbers in the API start at 0 (`page(0)` is the first page).
|
|
28
|
+
- **Branch on an error's `code`, never its message.** Every error is a `LaminaPdfError` with a stable `code` (such as `wrong-password`) and a `hint`; `docs/errors/<code>.md` explains each one. Warnings, which say what Lamina PDF repaired in a damaged file, use the same codes.
|
|
29
|
+
- **Free what you open.** A `Document` or `Builder` holds WebAssembly memory: declare it with `using`, or call `free()` when you are done.
|
|
30
|
+
- **Check `docs/renames.json`** when a name in older code or an older answer doesn't exist: it says what each renamed item is called now.
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What the package docs hold
|
|
34
|
+
|
|
35
|
+
The folder starts at `llms.txt`, an index in the [llms.txt](https://llmstxt.org/) format whose links stay inside the folder:
|
|
36
|
+
|
|
37
|
+
- `pages/`: every page of this site as Markdown, with the examples written out in full.
|
|
38
|
+
- `errors/`: a page per error and warning code, the same text as the [code pages](../../errors/README.md).
|
|
39
|
+
- `api/`: the TypeScript API reference (npm package only; Rust's is on docs.rs).
|
|
40
|
+
- `renames.json`: what each renamed item is called now, so an agent holding an old name finds the new one.
|
|
41
|
+
- `AGENTS.md`: the snippet above.
|
|
42
|
+
|
|
43
|
+
## The same docs online
|
|
44
|
+
|
|
45
|
+
This site serves the same Markdown for the latest version. Each page has a twin at its address with `.md` in place of the final slash, such as [`/install.md`](https://docs.laminapdf.com/install.md), and [`/llms.txt`](https://docs.laminapdf.com/llms.txt) lists them all. [`/llms-full.txt`](https://docs.laminapdf.com/llms-full.txt) puts every page in one file for agents that read a whole site at once. Prefer the package copy while you work in a project, because it matches the code the agent calls.
|