@laminapdf/sdk 0.2.0-alpha.3 → 0.2.0-alpha.5
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 +21 -1
- package/dist/api.d.ts +5 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +1 -0
- package/dist/api.js.map +1 -1
- package/dist/builder.d.ts +8 -3
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +8 -3
- package/dist/builder.js.map +1 -1
- package/dist/document.d.ts +78 -1
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +112 -0
- package/dist/document.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 +1 -1
- package/dist/extract.d.ts.map +1 -1
- package/dist/extract.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 +2 -2
- package/dist/generated/codes.d.ts.map +1 -1
- package/dist/generated/codes.js +55 -1
- package/dist/generated/codes.js.map +1 -1
- package/dist/generated/explain.d.ts.map +1 -1
- package/dist/generated/explain.js +19 -2
- package/dist/generated/explain.js.map +1 -1
- package/dist/generated/extract.d.ts +50 -3
- package/dist/generated/extract.d.ts.map +1 -1
- package/dist/reflow.d.ts +88 -0
- package/dist/reflow.d.ts.map +1 -0
- package/dist/reflow.js +4 -0
- package/dist/reflow.js.map +1 -0
- package/dist/source/http.d.ts +1 -1
- package/dist/source/http.js +1 -1
- package/dist/types.d.ts +35 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/support.d.ts +10 -1
- package/dist/worker/support.d.ts.map +1 -1
- package/dist/worker/support.js +7 -0
- package/dist/worker/support.js.map +1 -1
- package/docs/AGENTS.md +1 -1
- package/docs/api/README.md +29 -1
- package/docs/api/classes/Builder.md +1 -1
- package/docs/api/classes/Document.md +186 -1
- package/docs/api/classes/ExtractJob.md +236 -0
- package/docs/api/classes/Font.md +1 -1
- package/docs/api/classes/Image.md +1 -1
- package/docs/api/classes/LaminaPdfError.md +1 -1
- package/docs/api/classes/Page.md +1 -1
- package/docs/api/classes/PageRef.md +1 -1
- package/docs/api/classes/PageText.md +1 -1
- package/docs/api/classes/PageTextRun.md +1 -1
- package/docs/api/classes/PendingPath.md +1 -1
- package/docs/api/classes/SaveJob.md +1 -1
- package/docs/api/classes/Surface.md +10 -5
- package/docs/api/classes/Transaction.md +1 -1
- package/docs/api/functions/callbackSource.md +1 -1
- package/docs/api/functions/extractWithModels.md +70 -0
- package/docs/api/functions/httpRangeSource.md +2 -2
- package/docs/api/functions/init.md +1 -1
- package/docs/api/functions/isExtractLoaded.md +1 -1
- package/docs/api/functions/isInitialized.md +1 -1
- package/docs/api/functions/isLaminaPdfError.md +1 -1
- package/docs/api/functions/isTextLoaded.md +1 -1
- package/docs/api/functions/loadExtract.md +1 -1
- package/docs/api/functions/loadText.md +1 -1
- package/docs/api/functions/onLeak.md +1 -1
- package/docs/api/functions/reset.md +1 -1
- package/docs/api/functions/wasmMemory.md +1 -1
- package/docs/api/interfaces/BuilderOptions.md +1 -1
- package/docs/api/interfaces/ByteRange.md +1 -1
- package/docs/api/interfaces/ChunkOptions.md +1 -1
- package/docs/api/interfaces/Diagnostic.md +1 -1
- package/docs/api/interfaces/ExtractOptions.md +1 -1
- package/docs/api/interfaces/ExtractResult.md +1 -1
- package/docs/api/interfaces/FontInfo.md +1 -1
- package/docs/api/interfaces/HostModels.md +57 -0
- package/docs/api/interfaces/HttpRangeOptions.md +1 -1
- package/docs/api/interfaces/InitOptions.md +1 -1
- package/docs/api/interfaces/LayoutRegion.md +38 -0
- package/docs/api/interfaces/Leak.md +1 -1
- package/docs/api/interfaces/Location.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/OpenOptions.md +1 -1
- package/docs/api/interfaces/PageTextOptions.md +1 -1
- package/docs/api/interfaces/PathBuilder.md +1 -1
- package/docs/api/interfaces/QuadPoint.md +1 -1
- package/docs/api/interfaces/RangeOptions.md +1 -1
- package/docs/api/interfaces/RangeSource.md +1 -1
- package/docs/api/interfaces/Reflow.md +61 -0
- package/docs/api/interfaces/ReflowChecks.md +69 -0
- package/docs/api/interfaces/StrokeStyle.md +1 -1
- package/docs/api/interfaces/TagSpec.md +3 -3
- package/docs/api/interfaces/TextBoxOptions.md +1 -1
- package/docs/api/interfaces/TextGlyph.md +1 -1
- package/docs/api/interfaces/TextOptions.md +1 -1
- package/docs/api/interfaces/WasmMemory.md +1 -1
- package/docs/api/type-aliases/AfRelationship.md +1 -1
- package/docs/api/type-aliases/Align.md +1 -1
- package/docs/api/type-aliases/ArtifactKind.md +2 -2
- package/docs/api/type-aliases/AttachmentOptions.md +1 -1
- package/docs/api/type-aliases/BlendMode.md +1 -1
- package/docs/api/type-aliases/BoxRect.md +1 -1
- package/docs/api/type-aliases/BuildOptions.md +1 -1
- package/docs/api/type-aliases/Cell.md +1 -1
- package/docs/api/type-aliases/Chunk.md +1 -1
- package/docs/api/type-aliases/Color.md +1 -1
- package/docs/api/type-aliases/Coordinates.md +1 -1
- package/docs/api/type-aliases/Direction.md +1 -1
- package/docs/api/type-aliases/DocumentInfo.md +1 -1
- package/docs/api/type-aliases/DocumentProperties.md +18 -0
- package/docs/api/type-aliases/DropReason.md +2 -2
- package/docs/api/type-aliases/Dropped.md +1 -1
- package/docs/api/type-aliases/Edited.md +1 -1
- package/docs/api/type-aliases/ErrorCode.md +2 -2
- package/docs/api/type-aliases/ErrorKind.md +1 -1
- package/docs/api/type-aliases/ExtractFormat.md +1 -1
- 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 +13 -1
- package/docs/api/type-aliases/ExtractedPage.md +9 -1
- package/docs/api/type-aliases/ExtractedSource.md +1 -1
- package/docs/api/type-aliases/Extraction.md +1 -1
- package/docs/api/type-aliases/FillRule.md +1 -1
- package/docs/api/type-aliases/Fit.md +1 -1
- package/docs/api/type-aliases/Flags.md +1 -1
- package/docs/api/type-aliases/Generator.md +5 -3
- package/docs/api/type-aliases/GlyphQuad.md +1 -1
- package/docs/api/type-aliases/InfoPatch.md +1 -1
- package/docs/api/type-aliases/LaminaPdfWarning.md +1 -1
- package/docs/api/type-aliases/LimitName.md +1 -1
- package/docs/api/type-aliases/Limits.md +1 -1
- package/docs/api/type-aliases/LineBox.md +1 -1
- package/docs/api/type-aliases/LineCap.md +1 -1
- package/docs/api/type-aliases/LineJoin.md +1 -1
- package/docs/api/type-aliases/LinkTarget.md +1 -1
- package/docs/api/type-aliases/Metadata.md +1 -1
- package/docs/api/type-aliases/ModelResult.md +15 -0
- package/docs/api/type-aliases/Op.md +1 -1
- package/docs/api/type-aliases/OutlineEntry.md +1 -1
- package/docs/api/type-aliases/OutlineNode.md +15 -0
- package/docs/api/type-aliases/Overflow.md +1 -1
- package/docs/api/type-aliases/PageImageReason.md +15 -0
- package/docs/api/type-aliases/PageInfo.md +1 -1
- package/docs/api/type-aliases/PageLabel.md +1 -1
- package/docs/api/type-aliases/PageLink.md +20 -0
- package/docs/api/type-aliases/PageSizeName.md +1 -1
- package/docs/api/type-aliases/Point.md +1 -1
- package/docs/api/type-aliases/Profile.md +1 -1
- package/docs/api/type-aliases/Progress.md +1 -1
- package/docs/api/type-aliases/ReadingOrder.md +1 -1
- package/docs/api/type-aliases/Rect.md +1 -1
- package/docs/api/type-aliases/ReflowBlock.md +44 -0
- package/docs/api/type-aliases/ReflowKind.md +15 -0
- package/docs/api/type-aliases/ReflowRefusal.md +16 -0
- package/docs/api/type-aliases/ReflowSource.md +15 -0
- package/docs/api/type-aliases/Region.md +1 -1
- package/docs/api/type-aliases/RegionLabel.md +15 -0
- package/docs/api/type-aliases/RenderMode.md +1 -1
- package/docs/api/type-aliases/Rotation.md +1 -1
- package/docs/api/type-aliases/SaveOptions.md +1 -1
- package/docs/api/type-aliases/SaveReport.md +1 -1
- package/docs/api/type-aliases/Span.md +12 -1
- package/docs/api/type-aliases/SplitOn.md +1 -1
- package/docs/api/type-aliases/Standard14.md +1 -1
- package/docs/api/type-aliases/StructRef.md +1 -1
- package/docs/api/type-aliases/StructSource.md +1 -1
- 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 +1 -1
- package/docs/api/type-aliases/TableMode.md +1 -1
- package/docs/api/type-aliases/TableScope.md +1 -1
- package/docs/api/type-aliases/Tag.md +1 -1
- package/docs/api/type-aliases/TagName.md +1 -1
- 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 +1 -1
- package/docs/api/type-aliases/TextRange.md +1 -1
- package/docs/api/type-aliases/TextRunInfo.md +1 -1
- package/docs/api/type-aliases/Transform.md +1 -1
- package/docs/api/type-aliases/UndoOutcome.md +1 -1
- package/docs/api/type-aliases/ViewerPreferences.md +1 -1
- package/docs/api/type-aliases/WarningCode.md +2 -2
- package/docs/api/type-aliases/WasmSource.md +1 -1
- package/docs/api/variables/Matrix.md +1 -1
- package/docs/api/variables/PAGE_SIZES.md +1 -1
- package/docs/api/variables/TAG_NAMES.md +2 -2
- package/docs/errors/README.md +18 -1
- package/docs/errors/aes-padding-invalid.md +1 -1
- package/docs/errors/already-initialized.md +1 -1
- package/docs/errors/binary-output-to-terminal.md +1 -1
- package/docs/errors/builder-finished.md +1 -1
- package/docs/errors/cancelled.md +1 -1
- package/docs/errors/cmap-invalid.md +1 -1
- package/docs/errors/collection-index.md +1 -1
- package/docs/errors/color-components.md +1 -1
- package/docs/errors/content-bad-operands.md +1 -1
- package/docs/errors/content-path-unpainted.md +1 -1
- package/docs/errors/content-resource-missing.md +1 -1
- package/docs/errors/content-syntax.md +1 -1
- package/docs/errors/content-unbalanced-bt.md +1 -1
- package/docs/errors/content-unbalanced-marked.md +1 -1
- package/docs/errors/content-unbalanced-q.md +1 -1
- package/docs/errors/content-unknown-operator.md +1 -1
- package/docs/errors/covered-text.md +33 -0
- package/docs/errors/data-pending.md +1 -1
- package/docs/errors/decompress.md +1 -1
- package/docs/errors/device-color-without-output-intent.md +1 -1
- package/docs/errors/direct-page.md +1 -1
- package/docs/errors/disposed.md +1 -1
- package/docs/errors/document-changed.md +1 -1
- package/docs/errors/embedded-file-forbidden.md +1 -1
- package/docs/errors/embedded-file-without-mime-type.md +1 -1
- package/docs/errors/encoding-full.md +1 -1
- package/docs/errors/encrypted-base.md +1 -1
- package/docs/errors/extract-column-order-uncertain.md +38 -0
- package/docs/errors/extract-limit-blocks.md +1 -1
- package/docs/errors/extract-module-not-loaded.md +1 -1
- package/docs/errors/extract-needs-ocr.md +37 -0
- package/docs/errors/extract-reading-order-ambiguous.md +1 -1
- package/docs/errors/extract-struct-tree-ignored.md +1 -1
- package/docs/errors/extract-table-ambiguous.md +1 -1
- package/docs/errors/extract-table-limit.md +1 -1
- package/docs/errors/extract-untagged-content.md +1 -1
- package/docs/errors/fetch-failed.md +3 -3
- package/docs/errors/flate-truncated.md +1 -1
- 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 +1 -1
- package/docs/errors/font-mismatch.md +1 -1
- package/docs/errors/font-not-embeddable.md +1 -1
- package/docs/errors/font-not-embedded.md +1 -1
- package/docs/errors/font-not-shapable.md +1 -1
- package/docs/errors/glyph-out-of-range.md +1 -1
- package/docs/errors/glyph-without-unicode.md +7 -5
- package/docs/errors/heading-level-skipped.md +1 -1
- package/docs/errors/image-data-length.md +1 -1
- package/docs/errors/image-too-large.md +1 -1
- package/docs/errors/inline-image-unterminated.md +1 -1
- package/docs/errors/input-unreadable.md +1 -1
- package/docs/errors/instance-reset.md +1 -1
- package/docs/errors/invalid-argument.md +1 -1
- package/docs/errors/invalid-axis-value.md +1 -1
- package/docs/errors/invalid-box.md +1 -1
- package/docs/errors/invalid-color.md +1 -1
- package/docs/errors/invalid-command-line.md +1 -1
- package/docs/errors/invalid-date.md +1 -1
- package/docs/errors/invalid-entry.md +1 -1
- package/docs/errors/invalid-feature.md +1 -1
- package/docs/errors/invalid-font.md +1 -1
- package/docs/errors/invalid-geometry.md +1 -1
- package/docs/errors/invalid-icc-profile.md +1 -1
- package/docs/errors/invalid-image.md +1 -1
- package/docs/errors/invalid-op-log.md +1 -1
- package/docs/errors/invalid-page-label.md +1 -1
- package/docs/errors/invalid-page-labels.md +1 -1
- package/docs/errors/invalid-page-range.md +1 -1
- package/docs/errors/invalid-rotate.md +1 -1
- package/docs/errors/invalid-spans.md +39 -0
- package/docs/errors/invalid-structure-nesting.md +1 -1
- package/docs/errors/invalid-structure.md +1 -1
- package/docs/errors/invalid-text-range.md +1 -1
- package/docs/errors/job-finished.md +1 -1
- package/docs/errors/limit-exceeded.md +1 -1
- package/docs/errors/link-without-contents.md +1 -1
- package/docs/errors/link-without-structure.md +1 -1
- 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 +1 -1
- package/docs/errors/missing-glyph.md +1 -1
- package/docs/errors/missing-header.md +1 -1
- package/docs/errors/missing-lang.md +1 -1
- package/docs/errors/missing-root.md +1 -1
- package/docs/errors/missing-title.md +1 -1
- 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 +1 -1
- package/docs/errors/nested-transaction.md +1 -1
- package/docs/errors/no-pending-save.md +1 -1
- package/docs/errors/no-transaction.md +1 -1
- package/docs/errors/not-initialized.md +1 -1
- package/docs/errors/not-pdf.md +1 -1
- package/docs/errors/not-rebased.md +1 -1
- package/docs/errors/object-number-out-of-range.md +1 -1
- package/docs/errors/objstm-index-mismatch.md +1 -1
- package/docs/errors/out-of-memory.md +1 -1
- package/docs/errors/outline-cycle.md +1 -1
- package/docs/errors/outline-item-skipped.md +1 -1
- package/docs/errors/output-unwritable.md +1 -1
- package/docs/errors/overwrite-refused.md +1 -1
- package/docs/errors/page-count-mismatch.md +1 -1
- package/docs/errors/page-index-out-of-range.md +1 -1
- package/docs/errors/page-tree-node-skipped.md +1 -1
- package/docs/errors/password-required.md +1 -1
- package/docs/errors/path-outside-roots.md +1 -1
- package/docs/errors/perms-mismatch.md +1 -1
- package/docs/errors/profile-version-conflict.md +1 -1
- package/docs/errors/redaction-not-applied.md +32 -0
- package/docs/errors/reference-cycle.md +1 -1
- package/docs/errors/render-backend-unavailable.md +1 -1
- package/docs/errors/render-failed.md +1 -1
- package/docs/errors/render-too-large.md +1 -1
- package/docs/errors/repaired-base.md +1 -1
- package/docs/errors/requires-rewrite.md +1 -1
- package/docs/errors/revision-index-out-of-range.md +34 -0
- package/docs/errors/saved-not-rebased.md +1 -1
- package/docs/errors/sink-not-empty.md +1 -1
- package/docs/errors/sink.md +1 -1
- package/docs/errors/source-budget-exceeded.md +1 -1
- package/docs/errors/source-changed.md +1 -1
- package/docs/errors/source.md +1 -1
- package/docs/errors/stale-generation.md +1 -1
- package/docs/errors/stream-length-recovered.md +1 -1
- package/docs/errors/strict.md +1 -1
- package/docs/errors/subset-failed.md +1 -1
- package/docs/errors/syntax.md +1 -1
- 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 +1 -1
- package/docs/errors/text-overflow.md +1 -1
- package/docs/errors/tounicode-conflict.md +1 -1
- package/docs/errors/type.md +1 -1
- package/docs/errors/unexpected-eof.md +1 -1
- package/docs/errors/unknown-axis.md +1 -1
- package/docs/errors/unknown-code.md +1 -1
- package/docs/errors/unknown-destination.md +1 -1
- package/docs/errors/unknown-font.md +1 -1
- package/docs/errors/unknown-option.md +1 -1
- package/docs/errors/unknown-page.md +1 -1
- package/docs/errors/unmapped-glyph.md +1 -1
- package/docs/errors/unnumbered-heading-misused.md +1 -1
- package/docs/errors/unset-object.md +1 -1
- package/docs/errors/unsupported-filter.md +1 -1
- package/docs/errors/unsupported-image.md +1 -1
- package/docs/errors/unsupported-layout-option.md +1 -1
- package/docs/errors/unsupported-security-handler.md +1 -1
- package/docs/errors/unsupported-version.md +1 -1
- package/docs/errors/untagged-content.md +1 -1
- package/docs/errors/warnings-truncated.md +1 -1
- package/docs/errors/wasm-trap.md +1 -1
- package/docs/errors/whole-font-rebuilt.md +1 -1
- package/docs/errors/worker-crashed.md +1 -1
- package/docs/errors/worker-failed.md +1 -1
- package/docs/errors/worker-version-mismatch.md +1 -1
- package/docs/errors/would-invalidate-signatures.md +1 -1
- package/docs/errors/wrong-document.md +1 -1
- package/docs/errors/wrong-password.md +1 -1
- package/docs/errors/xobject-cycle.md +1 -1
- package/docs/errors/xref-repaired.md +1 -1
- package/docs/errors/xrefstm-ignored.md +1 -1
- package/docs/llms.txt +7 -1
- package/docs/pages/concepts/dependencies.md +2 -2
- package/docs/pages/concepts/drawing-pages.md +76 -0
- package/docs/pages/concepts/errors-and-warnings.md +6 -2
- package/docs/pages/concepts/how-lamina-thinks.md +13 -1
- package/docs/pages/concepts/pages-and-coordinates.md +9 -1
- package/docs/pages/guides/accessible-pdfs.md +3 -1
- package/docs/pages/guides/archival-pdfs.md +5 -1
- package/docs/pages/guides/edit-a-pdf.md +8 -2
- package/docs/pages/guides/flowing-pages.md +379 -0
- package/docs/pages/guides/fonts-and-text.md +3 -1
- package/docs/pages/guides/images-and-vectors.md +3 -1
- package/docs/pages/guides/keep-the-page-responsive.md +8 -4
- package/docs/pages/guides/links-outlines-and-metadata.md +3 -1
- package/docs/pages/guides/open-large-files.md +69 -0
- package/docs/pages/guides/password-protected-files.md +1 -1
- package/docs/pages/guides/save-a-pdf.md +12 -2
- package/docs/pages/guides/test-generated-pdfs.md +324 -0
- package/docs/pages/guides/untrusted-files.md +3 -1
- package/docs/pages/index.md +2 -2
- package/docs/pages/install.md +9 -5
- package/docs/pages/quick-start/browser.md +5 -1
- package/docs/pages/quick-start/bun.md +5 -1
- package/docs/pages/quick-start/deno.md +5 -1
- package/docs/pages/quick-start/node.md +5 -1
- package/docs/pages/quick-start/rust.md +6 -2
- package/docs/pages/quick-start/workers.md +2 -2
- package/docs/pages/recipes/cloudflare-worker.md +1 -1
- package/docs/pages/recipes/element-flow.md +248 -0
- package/docs/pages/recipes/extract-markdown.md +44 -6
- package/docs/pages/recipes/generate-then-edit.md +13 -6
- package/docs/pages/recipes/hello.md +13 -6
- package/docs/pages/recipes/images-and-vectors.md +13 -6
- package/docs/pages/recipes/invoice.md +13 -6
- package/docs/pages/recipes/links-and-outlines.md +13 -6
- package/docs/pages/recipes/multilingual.md +13 -6
- package/docs/pages/recipes/open-untrusted.md +1 -1
- package/docs/pages/recipes/pdf-a-archive.md +13 -6
- package/docs/pages/recipes/pdf-a3-invoice-with-xml.md +13 -6
- package/docs/pages/recipes/pdf-ua-report.md +13 -6
- package/docs/pages/recipes/report.md +2 -2
- package/docs/pages/recipes/web-worker-client.md +1 -1
- package/docs/pages/recipes.md +3 -2
- package/docs/pages/reference/benchmarks.md +93 -0
- package/docs/pages/reference/changelog.md +77 -1
- package/docs/pages/reference/codes.md +1 -1
- package/docs/pages/reference/glossary.md +1 -1
- package/docs/pages/reference/rust.md +11 -11
- package/docs/pages/reference/stability.md +3 -3
- package/docs/pages/start/coding-agents.md +1 -1
- package/docs/pages/start/first-pdf.md +6 -2
- package/docs/pages/troubleshooting.md +1 -1
- package/docs/schemas/error.schema.json +18 -1
- package/package.json +5 -3
- package/schemas/error.schema.json +18 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "An invoice"
|
|
3
3
|
description: "A tagged one-page invoice with an embedded font, a table of line items with right-aligned amounts and a total, in TypeScript and Rust."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/invoice/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,9 @@ You'll make a one-page invoice: a heading, an address, a table of line items wit
|
|
|
13
13
|
|
|
14
14
|
The function takes a font file, draws the invoice and returns the PDF's bytes. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**TypeScript**
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/invoice.ts`:
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// An invoice that screen readers can follow, with an embedded font and a table of line items.
|
|
@@ -101,8 +103,11 @@ function rowBaseline(row: number): number {
|
|
|
101
103
|
function cell([width, inset]: readonly [number, number], baseline: number): Rect {
|
|
102
104
|
return [RIGHT_EDGE - inset - width, baseline - CELL_RISE, width, CELL_HEIGHT];
|
|
103
105
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Rust**
|
|
109
|
+
|
|
110
|
+
`crates/laminapdf/examples/invoice.rs`:
|
|
106
111
|
|
|
107
112
|
```rust
|
|
108
113
|
//! An invoice that screen readers can follow, with an embedded font and a table of line items.
|
|
@@ -205,9 +210,11 @@ fn right_aligned(s: &mut Surface, font: &FontHandle, text: &str, area: RectPt) -
|
|
|
205
210
|
let right = TextBoxOptions::new().with_align(Alignment::End);
|
|
206
211
|
s.text_box(text, font, BODY, area, &right).map(|_| ())
|
|
207
212
|
}
|
|
208
|
-
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Result:** [invoice.pdf](https://docs.laminapdf.com/examples/pdf/invoice.pdf)
|
|
209
216
|
|
|
210
|
-
The result is one A4 page with its body set in Noto Sans
|
|
217
|
+
The result is one A4 page with its body set in Noto Sans. The Result tab shows it, with a link to the PDF.
|
|
211
218
|
|
|
212
219
|
## How it works
|
|
213
220
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Links and outlines"
|
|
3
3
|
description: "Four A5 pages joined by web, page and named links, with a nested outline, page labels that read i, ii, 1, 2 and the outline shown on open."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/links-and-outlines/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,9 @@ You'll make four A5 pages joined by links to a website and between pages, an out
|
|
|
13
13
|
|
|
14
14
|
The function draws the four pages, links them and returns the PDF's bytes. It draws text, so in TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**TypeScript**
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/links-and-outlines.ts`:
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// Links and outlines: four A5 pages joined by links, bookmarks and page labels. The title page
|
|
@@ -93,8 +95,11 @@ function navigation(b: Builder): void {
|
|
|
93
95
|
{ start: 2, style: "decimal" },
|
|
94
96
|
]).viewerPreferences({ pageMode: "outlines" });
|
|
95
97
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Rust**
|
|
101
|
+
|
|
102
|
+
`crates/laminapdf/examples/links_and_outlines.rs`:
|
|
98
103
|
|
|
99
104
|
````rust
|
|
100
105
|
//! Links and outlines: four A5 pages joined by links, bookmarks and page labels.
|
|
@@ -192,9 +197,11 @@ fn navigation(b: &mut Builder) -> Result<(), Box<dyn Error>> {
|
|
|
192
197
|
.viewer_preferences(ViewerPreferences::default().with_page_mode(PageMode::Outlines));
|
|
193
198
|
Ok(())
|
|
194
199
|
}
|
|
195
|
-
|
|
200
|
+
````
|
|
201
|
+
|
|
202
|
+
**Result:** [links_and_outlines.pdf](https://docs.laminapdf.com/examples/pdf/links_and_outlines.pdf)
|
|
196
203
|
|
|
197
|
-
The result is four A5 pages with an outline and page labels
|
|
204
|
+
The result is four A5 pages with an outline and page labels. The Result tab shows it, with a link to the PDF.
|
|
198
205
|
|
|
199
206
|
## How it works
|
|
200
207
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Multilingual text"
|
|
3
3
|
description: "Latin, Arabic, Devanagari, Hebrew and Chinese on one page, each in its own embedded font, as a shaped line and a wrapped paragraph."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/multilingual/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,9 @@ You'll put five scripts on one page: Latin, Arabic, Devanagari, Hebrew and Chine
|
|
|
13
13
|
|
|
14
14
|
The function takes one font file per script, draws each script's line and paragraph, and returns the PDF's bytes. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**TypeScript**
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/multilingual.ts`:
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// Five scripts on one page, each as a single line and as a wrapped paragraph. The scripts are
|
|
@@ -69,8 +71,11 @@ export function multilingual(fonts: readonly Uint8Array[], options: BuilderOptio
|
|
|
69
71
|
using doc = b.finish();
|
|
70
72
|
return doc.save();
|
|
71
73
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Rust**
|
|
77
|
+
|
|
78
|
+
`crates/laminapdf/examples/multilingual.rs`:
|
|
74
79
|
|
|
75
80
|
````rust
|
|
76
81
|
//! Five scripts on one page, each as a single line and as a wrapped paragraph.
|
|
@@ -167,9 +172,11 @@ pub(crate) fn build(options: BuildOptions, fonts: Vec<Vec<u8>>) -> Result<Vec<u8
|
|
|
167
172
|
let mut doc = b.finish()?;
|
|
168
173
|
Ok(doc.save(&SaveOptions::new())?.bytes)
|
|
169
174
|
}
|
|
170
|
-
|
|
175
|
+
````
|
|
176
|
+
|
|
177
|
+
**Result:** [multilingual.pdf](https://docs.laminapdf.com/examples/pdf/multilingual.pdf)
|
|
171
178
|
|
|
172
|
-
The result is one A4 page, with each script set in its own Noto font
|
|
179
|
+
The result is one A4 page, with each script set in its own Noto font. The Result tab shows it, with a link to the PDF.
|
|
173
180
|
|
|
174
181
|
## How it works
|
|
175
182
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Open someone else's file"
|
|
3
3
|
description: "Open an uploaded PDF with an optional password and tighter limits, and get its page count and warnings, or the error, back as a value."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/open-untrusted/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "A PDF/A archive"
|
|
3
3
|
description: "An order confirmation for long-term archiving, written as PDF/A-2b and as PDF/A-2u that is also PDF/UA-1, with an embedded font and a photo."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/pdf-a-archive/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,9 @@ You'll write a letter confirming an order as a PDF/A file, which looks the same
|
|
|
13
13
|
|
|
14
14
|
The function takes the level, `2b` or `2u`, and builds the same letter under that level's profiles. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**TypeScript**
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/pdf-a-archive.ts`:
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// An archival letter, written as PDF/A-2b and as PDF/A-2u that is also PDF/UA-1.
|
|
@@ -78,8 +80,11 @@ function draw(s: Surface, font: Font, photo: Image): void {
|
|
|
78
80
|
s.text("Acme Widgets Ltd, 1 Example Street, London", { font, size: BODY, at: [MARGIN, FOOTER_BASELINE] }),
|
|
79
81
|
);
|
|
80
82
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Rust**
|
|
86
|
+
|
|
87
|
+
`crates/laminapdf/examples/pdf_a_archive.rs`:
|
|
83
88
|
|
|
84
89
|
```rust
|
|
85
90
|
//! An archival letter, written as PDF/A-2b and as PDF/A-2u that is also PDF/UA-1.
|
|
@@ -182,9 +187,11 @@ fn draw(s: &mut Surface, font: &FontHandle, photo: &Image) -> Result<(), BuildEr
|
|
|
182
187
|
let footer = "Acme Widgets Ltd, 1 Example Street, London";
|
|
183
188
|
s.tag(TagKind::P, |s| s.text(footer, font, BODY, FOOTER_AT).map(drop))
|
|
184
189
|
}
|
|
185
|
-
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Result:** [pdf_a_archive-2b.pdf](https://docs.laminapdf.com/examples/pdf/pdf_a_archive-2b.pdf), [pdf_a_archive-2u.pdf](https://docs.laminapdf.com/examples/pdf/pdf_a_archive-2u.pdf)
|
|
186
193
|
|
|
187
|
-
The result is one A4 letter under a translucent blue band, with a photo beside its text:
|
|
194
|
+
The result is one A4 letter under a translucent blue band, with a photo beside its text: the Result tab shows both versions, PDF/A-2b and PDF/A-2u, with links to the PDFs.
|
|
188
195
|
|
|
189
196
|
## How it works
|
|
190
197
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "A PDF/A-3 invoice with XML"
|
|
3
3
|
description: "A PDF/A-3b invoice that carries the same invoice as an attached XML file, for people to read and for software to process."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/pdf-a3-invoice-with-xml/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,9 @@ You'll write a one-page invoice as PDF/A-3b, with the same invoice attached as X
|
|
|
13
13
|
|
|
14
14
|
The function draws the invoice, writes the same items as XML and attaches that file before it finishes. In TypeScript it needs the text module, `init({ text: true })`. Both languages write the same bytes:
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**TypeScript**
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/pdf-a3-invoice-with-xml.ts`:
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// A PDF/A-3b invoice that carries the same invoice as XML, attached for software to read.
|
|
@@ -98,8 +100,11 @@ function draw(s: Surface, font: Font): void {
|
|
|
98
100
|
link: { target: { type: "uri", uri: "https://example.com/invoices/42" }, contents: "Invoice 42 online" },
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Rust**
|
|
106
|
+
|
|
107
|
+
`crates/laminapdf/examples/pdf_a3_invoice_with_xml.rs`:
|
|
103
108
|
|
|
104
109
|
```rust
|
|
105
110
|
//! A PDF/A-3b invoice that carries the same invoice as XML, attached for software to read.
|
|
@@ -200,9 +205,11 @@ fn draw(s: &mut Surface, font: &FontHandle) -> Result<(), BuildError> {
|
|
|
200
205
|
note.link(online, Some("Invoice 42 online".into()));
|
|
201
206
|
Ok(())
|
|
202
207
|
}
|
|
203
|
-
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Result:** [pdf_a3_invoice_with_xml.pdf](https://docs.laminapdf.com/examples/pdf/pdf_a3_invoice_with_xml.pdf)
|
|
204
211
|
|
|
205
|
-
The result is one A4 page with three line items and a total of € 99.40, carrying `invoice-42.xml
|
|
212
|
+
The result is one A4 page with three line items and a total of € 99.40, carrying `invoice-42.xml`. The Result tab shows it, with a link to the PDF. Viewers that show attachments list it there.
|
|
206
213
|
|
|
207
214
|
## How it works
|
|
208
215
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "A PDF/UA report"
|
|
3
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.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/pdf-ua-report/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,7 +13,9 @@ You'll build a one-page sales report that a screen reader can follow: headings,
|
|
|
13
13
|
|
|
14
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
15
|
|
|
16
|
-
|
|
16
|
+
**TypeScript**
|
|
17
|
+
|
|
18
|
+
`packages/sdk/examples/pdf-ua-report.ts`:
|
|
17
19
|
|
|
18
20
|
```ts
|
|
19
21
|
// An accessible report that screen readers can follow, checked against PDF/UA-1 when it is built.
|
|
@@ -110,8 +112,11 @@ function chart(s: Surface): void {
|
|
|
110
112
|
});
|
|
111
113
|
});
|
|
112
114
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Rust**
|
|
118
|
+
|
|
119
|
+
`crates/laminapdf/examples/pdf_ua_report.rs`:
|
|
115
120
|
|
|
116
121
|
```rust
|
|
117
122
|
//! An accessible report that screen readers can follow, checked against PDF/UA-1 when it is built.
|
|
@@ -214,9 +219,11 @@ fn chart(s: &mut Surface) -> Result<(), BuildError> {
|
|
|
214
219
|
Ok(())
|
|
215
220
|
})
|
|
216
221
|
}
|
|
217
|
-
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Result:** [pdf_ua_report.pdf](https://docs.laminapdf.com/examples/pdf/pdf_ua_report.pdf)
|
|
218
225
|
|
|
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
|
|
226
|
+
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. The Result tab shows it, with a link to the PDF.
|
|
220
227
|
|
|
221
228
|
## How it works
|
|
222
229
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "A 100-page report"
|
|
3
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.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/report/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -104,7 +104,7 @@ function cell([left, width]: readonly [number, number], baseline: number): Rect
|
|
|
104
104
|
}
|
|
105
105
|
```
|
|
106
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.
|
|
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. [Benchmarks](../../pages/reference/benchmarks.md) has the timings.
|
|
108
108
|
|
|
109
109
|
## How it works
|
|
110
110
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Save in a Web Worker"
|
|
3
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.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/web-worker-client/"
|
|
6
6
|
---
|
|
7
7
|
|
package/docs/pages/recipes.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Recipes"
|
|
3
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
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/recipes/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -11,7 +11,7 @@ Complete Lamina PDF programs, from one page of text to an archived invoice, each
|
|
|
11
11
|
|
|
12
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
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.
|
|
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
15
|
|
|
16
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
17
|
|
|
@@ -21,6 +21,7 @@ To run a Rust recipe from a checkout of Lamina PDF, use `cargo run -p laminapdf
|
|
|
21
21
|
- [An invoice](../pages/recipes/invoice.md): an embedded font, a table of line items, and tags for screen readers.
|
|
22
22
|
- [Multilingual text](../pages/recipes/multilingual.md): five scripts, each in its own embedded font.
|
|
23
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.
|
|
24
25
|
- [Links and outlines](../pages/recipes/links-and-outlines.md): links, an outline and page labels.
|
|
25
26
|
|
|
26
27
|
## Edit a PDF
|
|
@@ -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.5"
|
|
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.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Changelog"
|
|
3
3
|
description: "What changed in each Lamina PDF release, newest first."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/reference/changelog/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -11,6 +11,82 @@ What changed in each Lamina PDF release, newest first.
|
|
|
11
11
|
|
|
12
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
13
|
|
|
14
|
+
## 0.2.0-alpha.5
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- Reader mode for every PDF. When a file has no tags, or its tags fail reader mode's checks, `doc.reflow()` reads the page layout instead of refusing: `source` is `"approximate"` and `reason` says why the tags weren't used. A scanned page, or one whose column order extraction doubts, comes back as a `page-image` block with `why` (`"scanned"` or `"uncertain"`) and the page's text for searching. Tables and pictures are crops, and their captions are kept with them. Only a file with nothing to show has `available: false`, with the reason `"nothing"`.
|
|
19
|
+
- `doc.properties()` reads what a properties view shows about a document in one call. It returns the Info entries, with the creation and modification dates as ISO 8601, and the XMP packet as text. It also gives the PDF version, page count, file size, whether the file is linearized and tagged, and the fonts the pages use (name, type, embedded, subset, encoding). Encryption comes with the author's permissions, and signatures are counted, never verified. `contains` says whether the file holds JavaScript, attachments or a form. It needs the extract or text module. For Rust callers, `Document::properties()` returns the same as `DocumentProperties`, and `laminapdf-model` gains `Pages::fonts()` and `Document::xmp_packet()`.
|
|
20
|
+
|
|
21
|
+
The viewer's client gains `properties()`, `printPage(index, { dpi, annotations })` and `fileBytes()`. `printPage` draws a page in the document worker for printing, with annotations as their print flags say, and returns it as a PNG. `fileBytes` returns a linked file's bytes as opened.
|
|
22
|
+
- Reader mode for tagged PDFs. `doc.reflow()` returns the document's blocks in its structure tree's order: headings, paragraphs, list items, quotes, captions and notes as text, and each figure, formula and table as a crop of its page with its alternate text, never as reflowed text. It checks the tree first: a file whose tree it can't trust comes back with `available: false` and the reason. It needs the extract module. The viewer's worker serves it as `client.reflow()`.
|
|
23
|
+
- Links in PDFs now work in the viewer. `doc.pageLinks(index)` lists a page's links in page space, each with what following it does: a place in the document, a web address, another file, a named action, or an action such as JavaScript, which Lamina PDF never runs. The viewer draws an anchor over each link. Links inside the document go there, web links ask the app to confirm first, and anything else does nothing. `viewer.history` records each jump, so Back returns to where the reader was, and the web reader keeps those jumps in the browser's history.
|
|
24
|
+
- Pages can be drawn in Sepia, Dark or High contrast instead of their own colours. Images and annotations keep theirs, and so does text under a highlight.
|
|
25
|
+
|
|
26
|
+
- **Render request:** `RenderRequest.appearance` is `"original"` (the default), `"sepia"`, `"dark"` or `{ kind: "high-contrast", ink, paper }`, for both backends.
|
|
27
|
+
- **Colour maps:** `recolourRgb` and `recolourTile` in `@laminapdf/render` give the same bytes as the Rust crate's.
|
|
28
|
+
- **Viewer:** `setAppearance()` redraws the pages in view in the new colours, keeping the scroll position. The thumbnails follow.
|
|
29
|
+
- Each page is now a region that screen readers name and can land on. `createViewer({ pages: { name, roleDescription, focusOnJump } })` sets each page's name, "Page 4 of 120" unless the app gives its own, such as "Page iv, 4 of 120". With `focusOnJump`, a jump moves focus to the page it lands on: a link, the outline, a thumbnail or go to page. A find match leaves focus in the find field.
|
|
30
|
+
- Copying from the viewer now follows the page's reading order. A selection across two columns copies the left column, then the right. A paragraph's lines join into one line, hyphenated words join again, and a blank line separates paragraphs. HTML with a paragraph per block goes to the clipboard alongside the plain text.
|
|
31
|
+
|
|
32
|
+
`viewer.copySelection("exact")` keeps the layout's line breaks instead. An Alt/Option-drag, or a plain drag while `viewer.columnSelect` is on, selects the text inside a rectangle, such as one column. Selections also come as the viewer's `selectionchange` event, whose `settled` flag says when the pointer is up and a toolbar may show.
|
|
33
|
+
- A local file larger than 200 MiB now opens from a copy in the browser's origin-private file system (OPFS). The document worker makes the copy once, reuses it on later opens and reads it as needed, so it no longer holds the whole file in memory. The worker reports copying through the client's `progress` event, and a cancel stops it. `ViewerOpenOptions.copyAbove` sets the threshold.
|
|
34
|
+
|
|
35
|
+
The file opens from memory, as before, when the browser lacks OPFS, the copy won't fit or fails partway, or another tab is reading the file. When the copies would pass their budget, those opened longest ago are deleted first. `ViewerOpenOptions.keepCopy: false` removes the copy when its document closes. `CACHE_FOLDER` names the OPFS folder of copies, so an app can empty it.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- In Firefox, selecting a page's text with the mouse works again after the user has focused a text field on the page, such as the reader's page box. A drag that leaves the viewer can now highlight your app's own text in Firefox too, as it already could in Chromium and WebKit; set `user-select: none` on text you want to keep out. Copy still writes only the page text.
|
|
40
|
+
- A cancelled `open()` no longer leaves the page and the document Web Worker on different documents. The cancel can arrive after the Web Worker already opened the new file. `open()` then resolves with that document instead of rejecting, so renders keep working.
|
|
41
|
+
|
|
42
|
+
## 0.2.0-alpha.4
|
|
43
|
+
|
|
44
|
+
### Minor Changes
|
|
45
|
+
|
|
46
|
+
- 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).
|
|
47
|
+
- 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.
|
|
48
|
+
|
|
49
|
+
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.
|
|
50
|
+
|
|
51
|
+
`surface.measure_text_box(…)` (Rust) returns the layout `text_box` would draw, without drawing it.
|
|
52
|
+
|
|
53
|
+
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`.
|
|
54
|
+
- 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.
|
|
55
|
+
- 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.
|
|
56
|
+
- 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.
|
|
57
|
+
- 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.
|
|
58
|
+
|
|
59
|
+
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.
|
|
60
|
+
|
|
61
|
+
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.
|
|
62
|
+
- 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.
|
|
63
|
+
- 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()`.
|
|
64
|
+
|
|
65
|
+
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.
|
|
66
|
+
- `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.
|
|
67
|
+
|
|
68
|
+
`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.
|
|
69
|
+
- 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`.
|
|
70
|
+
- 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)`.
|
|
71
|
+
- 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.
|
|
72
|
+
- 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`.
|
|
73
|
+
- 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.
|
|
74
|
+
- 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.
|
|
75
|
+
- 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.
|
|
76
|
+
- 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.
|
|
77
|
+
- 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.
|
|
78
|
+
|
|
79
|
+
`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.
|
|
80
|
+
|
|
81
|
+
### Patch Changes
|
|
82
|
+
|
|
83
|
+
- `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.
|
|
84
|
+
- 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.
|
|
85
|
+
|
|
86
|
+
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.
|
|
87
|
+
- 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.
|
|
88
|
+
- 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.
|
|
89
|
+
|
|
14
90
|
## 0.2.0-alpha.3
|
|
15
91
|
|
|
16
92
|
### Minor Changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Rust API (rustdoc)"
|
|
3
3
|
description: "Where to read the API documentation of the Lamina PDF crates."
|
|
4
|
-
version: "0.2.0-alpha.
|
|
4
|
+
version: "0.2.0-alpha.5"
|
|
5
5
|
url: "https://docs.laminapdf.com/reference/rust/"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -9,19 +9,19 @@ url: "https://docs.laminapdf.com/reference/rust/"
|
|
|
9
9
|
|
|
10
10
|
Where to read the API documentation of the Lamina PDF crates.
|
|
11
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.
|
|
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.5/laminapdf/), the crate to depend on. It wraps the core crates and holds `Document`, `Builder`, `Error`, `Warning`, jobs and `CancelToken`.
|
|
13
13
|
|
|
14
14
|
The other crates are documented the same way:
|
|
15
15
|
|
|
16
|
-
- [`laminapdf-syntax`](https://docs.rs/laminapdf-syntax/0.2.0-alpha.
|
|
17
|
-
- [`laminapdf-cos`](https://docs.rs/laminapdf-cos/0.2.0-alpha.
|
|
18
|
-
- [`laminapdf-model`](https://docs.rs/laminapdf-model/0.2.0-alpha.
|
|
19
|
-
- [`laminapdf-ops`](https://docs.rs/laminapdf-ops/0.2.0-alpha.
|
|
20
|
-
- [`laminapdf-save`](https://docs.rs/laminapdf-save/0.2.0-alpha.
|
|
21
|
-
- [`laminapdf-content`](https://docs.rs/laminapdf-content/0.2.0-alpha.
|
|
22
|
-
- [`laminapdf-text`](https://docs.rs/laminapdf-text/0.2.0-alpha.
|
|
23
|
-
- [`laminapdf-build`](https://docs.rs/laminapdf-build/0.2.0-alpha.
|
|
24
|
-
- [`laminapdf-render-pdfium`](https://docs.rs/laminapdf-render-pdfium/0.2.0-alpha.
|
|
16
|
+
- [`laminapdf-syntax`](https://docs.rs/laminapdf-syntax/0.2.0-alpha.5/laminapdf_syntax/)
|
|
17
|
+
- [`laminapdf-cos`](https://docs.rs/laminapdf-cos/0.2.0-alpha.5/laminapdf_cos/)
|
|
18
|
+
- [`laminapdf-model`](https://docs.rs/laminapdf-model/0.2.0-alpha.5/laminapdf_model/)
|
|
19
|
+
- [`laminapdf-ops`](https://docs.rs/laminapdf-ops/0.2.0-alpha.5/laminapdf_ops/)
|
|
20
|
+
- [`laminapdf-save`](https://docs.rs/laminapdf-save/0.2.0-alpha.5/laminapdf_save/)
|
|
21
|
+
- [`laminapdf-content`](https://docs.rs/laminapdf-content/0.2.0-alpha.5/laminapdf_content/)
|
|
22
|
+
- [`laminapdf-text`](https://docs.rs/laminapdf-text/0.2.0-alpha.5/laminapdf_text/)
|
|
23
|
+
- [`laminapdf-build`](https://docs.rs/laminapdf-build/0.2.0-alpha.5/laminapdf_build/)
|
|
24
|
+
- [`laminapdf-render-pdfium`](https://docs.rs/laminapdf-render-pdfium/0.2.0-alpha.5/laminapdf_render_pdfium/)
|
|
25
25
|
|
|
26
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
27
|
|