pagyra-js 0.0.1
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/.eslintrc.json +30 -0
- package/CHANGELOG.md +13 -0
- package/README.md +275 -0
- package/UA_Styles_Chromium.md +93 -0
- package/_ext/woff2_conversion/brotli-decode.d.ts +139 -0
- package/_ext/woff2_conversion/brotli-encode.d.ts +129 -0
- package/_ext/woff2_conversion/brotli-port.d.ts +12 -0
- package/_ext/woff2_conversion/brotli-shared-dictionary.d.ts +25 -0
- package/_ext/woff2_conversion/brotli-types.d.ts +15 -0
- package/_ext/woff2_conversion/woff2-common.d.ts +37 -0
- package/_ext/woff2_conversion/woff2-decode.d.ts +32 -0
- package/_ext/woff2_conversion/woff2-encode.d.ts +31 -0
- package/_ext/woff2_conversion/woff2-output.d.ts +39 -0
- package/_ext/woff2_original_cpp/brotli/brotli.c +1559 -0
- package/_ext/woff2_original_cpp/brotli/brotli.md +116 -0
- package/_ext/woff2_original_cpp/brotli/decode.h +409 -0
- package/_ext/woff2_original_cpp/brotli/encode.h +505 -0
- package/_ext/woff2_original_cpp/brotli/port.h +302 -0
- package/_ext/woff2_original_cpp/brotli/shared_dictionary.h +100 -0
- package/_ext/woff2_original_cpp/brotli/types.h +83 -0
- package/_ext/woff2_original_cpp/cmake/FindBrotliDec.cmake +35 -0
- package/_ext/woff2_original_cpp/cmake/FindBrotliEnc.cmake +35 -0
- package/_ext/woff2_original_cpp/include/woff2/decode.h +36 -0
- package/_ext/woff2_original_cpp/include/woff2/encode.h +43 -0
- package/_ext/woff2_original_cpp/include/woff2/output.h +86 -0
- package/_ext/woff2_original_cpp/src/buffer.h +164 -0
- package/_ext/woff2_original_cpp/src/convert_woff2ttf_fuzzer.cc +13 -0
- package/_ext/woff2_original_cpp/src/convert_woff2ttf_fuzzer_new_entry.cc +12 -0
- package/_ext/woff2_original_cpp/src/file.h +30 -0
- package/_ext/woff2_original_cpp/src/font.cc +400 -0
- package/_ext/woff2_original_cpp/src/font.h +105 -0
- package/_ext/woff2_original_cpp/src/glyph.cc +383 -0
- package/_ext/woff2_original_cpp/src/glyph.h +71 -0
- package/_ext/woff2_original_cpp/src/normalize.cc +314 -0
- package/_ext/woff2_original_cpp/src/normalize.h +39 -0
- package/_ext/woff2_original_cpp/src/port.h +66 -0
- package/_ext/woff2_original_cpp/src/round.h +27 -0
- package/_ext/woff2_original_cpp/src/store_bytes.h +55 -0
- package/_ext/woff2_original_cpp/src/table_tags.cc +82 -0
- package/_ext/woff2_original_cpp/src/table_tags.h +30 -0
- package/_ext/woff2_original_cpp/src/transform.cc +430 -0
- package/_ext/woff2_original_cpp/src/transform.h +26 -0
- package/_ext/woff2_original_cpp/src/variable_length.cc +129 -0
- package/_ext/woff2_original_cpp/src/variable_length.h +30 -0
- package/_ext/woff2_original_cpp/src/woff2_common.cc +50 -0
- package/_ext/woff2_original_cpp/src/woff2_common.h +64 -0
- package/_ext/woff2_original_cpp/src/woff2_compress.cc +43 -0
- package/_ext/woff2_original_cpp/src/woff2_dec.cc +1398 -0
- package/_ext/woff2_original_cpp/src/woff2_decompress.cc +41 -0
- package/_ext/woff2_original_cpp/src/woff2_enc.cc +458 -0
- package/_ext/woff2_original_cpp/src/woff2_info.cc +142 -0
- package/_ext/woff2_original_cpp/src/woff2_out.cc +63 -0
- package/assets/fonts/ttf/arimo/Arimo-Bold.ttf +0 -0
- package/assets/fonts/ttf/arimo/Arimo-BoldItalic.ttf +0 -0
- package/assets/fonts/ttf/arimo/Arimo-Italic.ttf +0 -0
- package/assets/fonts/ttf/arimo/Arimo-Regular.ttf +0 -0
- package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Black.ttf +0 -0
- package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Bold.ttf +0 -0
- package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Regular.ttf +0 -0
- package/assets/fonts/ttf/dejavu/DejaVuSans.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Bold.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Light.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Medium.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Regular.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-SemiBold.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Bold.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Light.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Medium.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Regular.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-SemiBold.ttf +0 -0
- package/assets/fonts/ttf/notosans/NotoSans-Regular.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-Bold.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-BoldItalic.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-Italic.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-Regular.ttf +0 -0
- package/assets/fonts/ttf/stixtwomath/STIXTwoMath-Regular.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-Bold.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-BoldItalic.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-Italic.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-Regular.ttf +0 -0
- package/assets/fonts/woff/lato/lato-latin-400-italic.woff +0 -0
- package/assets/fonts/woff/lato/lato-latin-400-normal.woff +0 -0
- package/assets/fonts/woff/lato/lato-latin-700-italic.woff +0 -0
- package/assets/fonts/woff/lato/lato-latin-700-normal.woff +0 -0
- package/assets/fonts/woff2/caveat/Caveat-Bold.woff2 +0 -0
- package/assets/fonts/woff2/caveat/Caveat-Regular.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-400-italic.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-400-normal.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-700-italic.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-700-normal.woff2 +0 -0
- package/docs/AGENTS.md +288 -0
- package/docs/BACKGROUND-REPEAT-IMPLEMENTATION.md +127 -0
- package/docs/BACKGROUND-REPEAT-REFERENCE.md +127 -0
- package/docs/BACKGROUND-REPEAT-SPACE-ROUND.md +164 -0
- package/docs/css-properties-support.md +256 -0
- package/docs/src_modules_table.md +172 -0
- package/docs/text-overlap-fix.md +85 -0
- package/docs/text-overlap-investigation.md +27 -0
- package/eslint.config.js +36 -0
- package/glyph_measure.htm +1458 -0
- package/package.json +50 -0
- package/playground/browser-entry.ts +2 -0
- package/playground/exports/background-text-debug.pdf +0 -0
- package/playground/public/app.js +875 -0
- package/playground/public/assets/1.webp +0 -0
- package/playground/public/examples/accents-test.html +24 -0
- package/playground/public/examples/advanced-selectors-demo.html +118 -0
- package/playground/public/examples/background-advanced-showcase.html +82 -0
- package/playground/public/examples/background-clip-text.html +36 -0
- package/playground/public/examples/background-origin-showcase.html +137 -0
- package/playground/public/examples/background-position-showcase.html +83 -0
- package/playground/public/examples/background-repeat-showcase.html +83 -0
- package/playground/public/examples/background-repeat-space-round.html +348 -0
- package/playground/public/examples/background-size-showcase.html +82 -0
- package/playground/public/examples/background-text-debug.html +18 -0
- package/playground/public/examples/baseline-test.html +24 -0
- package/playground/public/examples/bold-showcase.html +150 -0
- package/playground/public/examples/bold-strike-example.html +12 -0
- package/playground/public/examples/border-collapse-test.html +23 -0
- package/playground/public/examples/centered-shadow-div.html +72 -0
- package/playground/public/examples/css-variables.html +50 -0
- package/playground/public/examples/debug-accents.html +11 -0
- package/playground/public/examples/debug-text-overlap.html +46 -0
- package/playground/public/examples/flex-gap-column.html +130 -0
- package/playground/public/examples/flex-gap-row.html +137 -0
- package/playground/public/examples/flex-padding-test.html +29 -0
- package/playground/public/examples/flexbox-text-test.html +193 -0
- package/playground/public/examples/fonts-demo.html +126 -0
- package/playground/public/examples/footer-example.html +4 -0
- package/playground/public/examples/gradient-text.html +54 -0
- package/playground/public/examples/grid-gap-demo.html +156 -0
- package/playground/public/examples/header-example.html +4 -0
- package/playground/public/examples/header-footer-example.html +27 -0
- package/playground/public/examples/image-showcase.html +33 -0
- package/playground/public/examples/justify-text.html +22 -0
- package/playground/public/examples/linear-gradient-example.html +38 -0
- package/playground/public/examples/lorem-span.html +14 -0
- package/playground/public/examples/margin-block-showcase.html +21 -0
- package/playground/public/examples/margin-inline-showcase.html +21 -0
- package/playground/public/examples/monthly-summary.html +95 -0
- package/playground/public/examples/multi-page-lorem.html +190 -0
- package/playground/public/examples/opacity-debug.html +39 -0
- package/playground/public/examples/opacity-example.html +70 -0
- package/playground/public/examples/png-image-example.html +13 -0
- package/playground/public/examples/red-rectangle.html +18 -0
- package/playground/public/examples/repro.html +24 -0
- package/playground/public/examples/rounded-borders-test.html +24 -0
- package/playground/public/examples/simple-list.html +89 -0
- package/playground/public/examples/simple-svg.html +37 -0
- package/playground/public/examples/simple-table.html +52 -0
- package/playground/public/examples/skew-div.html +138 -0
- package/playground/public/examples/skew-text.html +21 -0
- package/playground/public/examples/starter-report.css +51 -0
- package/playground/public/examples/starter-report.html +23 -0
- package/playground/public/examples/svg-aspect-ratio-showcase.html +116 -0
- package/playground/public/examples/svg-gradients-linear.html +28 -0
- package/playground/public/examples/svg-gradients-radial.html +29 -0
- package/playground/public/examples/svg-gradients-showcase.html +66 -0
- package/playground/public/examples/svg-image-path-test.html +43 -0
- package/playground/public/examples/svg-images-clipping.html +27 -0
- package/playground/public/examples/svg-path-gallery.html +118 -0
- package/playground/public/examples/svg-radial-transform-demo.html +78 -0
- package/playground/public/examples/svg-transform-stack.html +103 -0
- package/playground/public/examples/svg-transforms-demo.html +127 -0
- package/playground/public/examples/table-merge-test.html +34 -0
- package/playground/public/examples/text-decoration-showcase.html +138 -0
- package/playground/public/examples/text-indent-showcase.html +137 -0
- package/playground/public/examples/text-shadow-example.html +29 -0
- package/playground/public/examples/very-complex-css.html +293 -0
- package/playground/public/examples/webp-example.html +13 -0
- package/playground/public/examples/z-index-demo.html +93 -0
- package/playground/public/examples.json +240 -0
- package/playground/public/images/dice.png +0 -0
- package/playground/public/images/duck.jpg +0 -0
- package/playground/public/index.html +149 -0
- package/playground/public/mode.js +1 -0
- package/playground/public/styles.css +382 -0
- package/playground/public/tmp-h2-debug.html +33 -0
- package/playground/public/tmp-italic-debug.html +32 -0
- package/playground/public/vendor/codemirror/codemirror.min.css +1 -0
- package/playground/public/vendor/codemirror/codemirror.min.js +1 -0
- package/playground/public/vendor/codemirror/css.min.js +1 -0
- package/playground/public/vendor/codemirror/darcula.min.css +1 -0
- package/playground/public/vendor/codemirror/htmlmixed.min.js +1 -0
- package/playground/public/vendor/codemirror/javascript.min.js +1 -0
- package/playground/public/vendor/codemirror/xml.min.js +1 -0
- package/playground/public/vendor/pagyra-playground-browser.js +165966 -0
- package/playground/public/vendor/pagyra-playground-browser.js.map +7 -0
- package/playground/server.d.ts +1 -0
- package/playground/server.js +68 -0
- package/playground/server.ts +128 -0
- package/scripts/browser-build.ts +101 -0
- package/scripts/build-browser-bundle.ts +52 -0
- package/scripts/glyph-comparison/simulate.ts +744 -0
- package/scripts/playground-browser-server.ts +57 -0
- package/scripts/probe-roboto.ts +6 -0
- package/scripts/render-playground-example.ts +121 -0
- package/scripts/run-glyph-atlas-tuner-runner.mjs +113 -0
- package/scripts/run-glyph-atlas-tuner.ts +141 -0
- package/scripts/top-ts-files.ps1 +39 -0
- package/scripts/top-ts-files.sh +37 -0
- package/scripts/woff2_info.ps1 +132 -0
- package/src/browser-entry.ts +14 -0
- package/src/compression/adler32.ts +45 -0
- package/src/compression/brotli/brotli.ts +463 -0
- package/src/compression/brotli/index.ts +15 -0
- package/src/compression/brotli/transform.ts +184 -0
- package/src/compression/brotli/types.ts +58 -0
- package/src/compression/brotli/utils.ts +157 -0
- package/src/compression/brotli/vendor/bit_reader.js +124 -0
- package/src/compression/brotli/vendor/context.js +250 -0
- package/src/compression/brotli/vendor/decode.d.ts +2 -0
- package/src/compression/brotli/vendor/decode.js +938 -0
- package/src/compression/brotli/vendor/dictionary-data.js +9469 -0
- package/src/compression/brotli/vendor/dictionary.js +36 -0
- package/src/compression/brotli/vendor/huffman.js +123 -0
- package/src/compression/brotli/vendor/package.json +3 -0
- package/src/compression/brotli/vendor/prefix.js +60 -0
- package/src/compression/brotli/vendor/streams.js +31 -0
- package/src/compression/brotli/vendor/transform.js +247 -0
- package/src/compression/brotli/vendor-decode.d.ts +4 -0
- package/src/compression/brotli/woff2-glyf-transform.ts +623 -0
- package/src/compression/decompress.ts +16 -0
- package/src/compression/deflate.ts +295 -0
- package/src/compression/index.ts +4 -0
- package/src/compression/types.ts +26 -0
- package/src/compression/utils.ts +107 -0
- package/src/core.ts +18 -0
- package/src/css/apply-declarations.ts +86 -0
- package/src/css/background-types.ts +65 -0
- package/src/css/browser-defaults.ts +16 -0
- package/src/css/clip-path-types.ts +13 -0
- package/src/css/compute-style.ts +494 -0
- package/src/css/css-unit-resolver.ts +65 -0
- package/src/css/custom-properties.ts +215 -0
- package/src/css/enums.ts +127 -0
- package/src/css/font-face-parser.ts +233 -0
- package/src/css/font-weight.ts +65 -0
- package/src/css/inline-style-parser.ts +27 -0
- package/src/css/layout-property-resolver.ts +75 -0
- package/src/css/length.ts +141 -0
- package/src/css/line-height.ts +96 -0
- package/src/css/named-colors.ts +150 -0
- package/src/css/parsers/background-parser-extended.ts +111 -0
- package/src/css/parsers/background-parser.ts +456 -0
- package/src/css/parsers/border-block-parser.ts +26 -0
- package/src/css/parsers/border-inline-parser.ts +26 -0
- package/src/css/parsers/border-parser-extended.ts +256 -0
- package/src/css/parsers/border-parser.ts +175 -0
- package/src/css/parsers/box-shadow-parser.ts +106 -0
- package/src/css/parsers/clip-path-parser.ts +92 -0
- package/src/css/parsers/color-parser.ts +14 -0
- package/src/css/parsers/dimension-parser.ts +117 -0
- package/src/css/parsers/display-flex-parser.ts +59 -0
- package/src/css/parsers/flex-parser.ts +144 -0
- package/src/css/parsers/font-parser.ts +40 -0
- package/src/css/parsers/gradient-parser.ts +366 -0
- package/src/css/parsers/grid-parser-extended.ts +55 -0
- package/src/css/parsers/grid-parser.ts +218 -0
- package/src/css/parsers/length-parser.ts +95 -0
- package/src/css/parsers/list-style-parser.ts +39 -0
- package/src/css/parsers/margin-block-parser.ts +12 -0
- package/src/css/parsers/margin-inline-parser.ts +12 -0
- package/src/css/parsers/margin-parser.ts +30 -0
- package/src/css/parsers/opacity-parser.ts +32 -0
- package/src/css/parsers/overflow-wrap-parser.ts +38 -0
- package/src/css/parsers/padding-block-parser.ts +12 -0
- package/src/css/parsers/padding-inline-parser.ts +12 -0
- package/src/css/parsers/padding-parser.ts +30 -0
- package/src/css/parsers/position-parser.ts +75 -0
- package/src/css/parsers/register-parsers.ts +302 -0
- package/src/css/parsers/registry.ts +18 -0
- package/src/css/parsers/text-parser-extended.ts +144 -0
- package/src/css/parsers/text-parser.ts +25 -0
- package/src/css/parsers/text-shadow-parser.ts +94 -0
- package/src/css/properties/box-model.ts +82 -0
- package/src/css/properties/flexbox.ts +44 -0
- package/src/css/properties/gap.ts +14 -0
- package/src/css/properties/grid.ts +94 -0
- package/src/css/properties/layout.ts +59 -0
- package/src/css/properties/misc.ts +44 -0
- package/src/css/properties/typography.ts +71 -0
- package/src/css/properties/visual.ts +68 -0
- package/src/css/selectors/matcher.ts +219 -0
- package/src/css/selectors/parser.ts +163 -0
- package/src/css/selectors/simple-key.ts +31 -0
- package/src/css/selectors/specificity.ts +41 -0
- package/src/css/selectors/types.ts +31 -0
- package/src/css/shorthands/border-shorthand.ts +68 -0
- package/src/css/shorthands/box-shorthand.ts +33 -0
- package/src/css/style-inheritance.ts +50 -0
- package/src/css/style.ts +402 -0
- package/src/css/ua-defaults/base-defaults.ts +266 -0
- package/src/css/ua-defaults/browser-defaults.ts +134 -0
- package/src/css/ua-defaults/element-defaults.ts +374 -0
- package/src/css/ua-defaults/types.ts +43 -0
- package/src/css/unit-conversion.ts +24 -0
- package/src/css/utils.ts +108 -0
- package/src/css/viewport.ts +17 -0
- package/src/debug/audit.ts +20 -0
- package/src/debug/ids.ts +13 -0
- package/src/debug/log.js +28 -0
- package/src/debug/log.ts +52 -0
- package/src/debug/tree.ts +57 -0
- package/src/dom/node.ts +133 -0
- package/src/environment/browser-environment.ts +78 -0
- package/src/environment/environment.ts +35 -0
- package/src/environment/global.ts +13 -0
- package/src/environment/node-environment.browser.ts +28 -0
- package/src/environment/node-environment.ts +64 -0
- package/src/fonts/detector.ts +28 -0
- package/src/fonts/engines/ttf-engine.ts +28 -0
- package/src/fonts/engines/woff-engine.ts +38 -0
- package/src/fonts/engines/woff2-engine.ts +41 -0
- package/src/fonts/extractors/metrics-extractor.ts +362 -0
- package/src/fonts/font-registry-resolver.ts +132 -0
- package/src/fonts/index.ts +3 -0
- package/src/fonts/orchestrator.ts +92 -0
- package/src/fonts/parsers/base-parser.ts +23 -0
- package/src/fonts/types.ts +85 -0
- package/src/fonts/utils/ttf-reconstructor.ts +120 -0
- package/src/fonts/woff/decoder.ts +105 -0
- package/src/fonts/woff2/buffer.ts +106 -0
- package/src/fonts/woff2/decoder.ts +981 -0
- package/src/geometry/box.ts +48 -0
- package/src/geometry/matrix.ts +59 -0
- package/src/html/css/parse-css.ts +85 -0
- package/src/html/dom-converter.ts +433 -0
- package/src/html/image-converter.ts +200 -0
- package/src/html-to-pdf.ts +410 -0
- package/src/image/base-decoder.ts +149 -0
- package/src/image/image-service.ts +188 -0
- package/src/image/jpeg-decoder.ts +73 -0
- package/src/image/png-decoder.ts +550 -0
- package/src/image/types.ts +20 -0
- package/src/image/webp-decoder.ts +242 -0
- package/src/image/webp-huffman.ts +218 -0
- package/src/image/webp-riff-parser.ts +54 -0
- package/src/image/webp-vp8l-decoder.ts +199 -0
- package/src/index.ts +35 -0
- package/src/layout/context/float-context.ts +62 -0
- package/src/layout/context/layout-environment.ts +29 -0
- package/src/layout/debug.ts +18 -0
- package/src/layout/inline/bounding-box-calculator.ts +132 -0
- package/src/layout/inline/font-baseline-calculator.ts +76 -0
- package/src/layout/inline/inline-utils.ts +94 -0
- package/src/layout/inline/layout.ts +285 -0
- package/src/layout/inline/line_breaker.ts +109 -0
- package/src/layout/inline/measurement.ts +144 -0
- package/src/layout/inline/run-placer.ts +139 -0
- package/src/layout/inline/text-alignment.ts +70 -0
- package/src/layout/inline/tokenizer.ts +195 -0
- package/src/layout/inline/types.ts +76 -0
- package/src/layout/pipeline/context-factory.ts +16 -0
- package/src/layout/pipeline/default-engine.ts +24 -0
- package/src/layout/pipeline/engine.ts +59 -0
- package/src/layout/pipeline/layout-tree.ts +13 -0
- package/src/layout/pipeline/out-of-flow-manager.ts +73 -0
- package/src/layout/pipeline/strategy.ts +12 -0
- package/src/layout/pipeline/text-metrics-initializer.ts +13 -0
- package/src/layout/strategies/block.ts +236 -0
- package/src/layout/strategies/display-none.ts +14 -0
- package/src/layout/strategies/fallback.ts +15 -0
- package/src/layout/strategies/flex.ts +477 -0
- package/src/layout/strategies/fragmentation.ts +17 -0
- package/src/layout/strategies/grid.ts +247 -0
- package/src/layout/strategies/image.ts +342 -0
- package/src/layout/strategies/inline.ts +128 -0
- package/src/layout/strategies/table.ts +595 -0
- package/src/layout/table/cell_layout.ts +31 -0
- package/src/layout/table/diagnostics.ts +19 -0
- package/src/layout/text-run.ts +42 -0
- package/src/layout/utils/content-measurer.ts +117 -0
- package/src/layout/utils/display-utils.ts +24 -0
- package/src/layout/utils/floats.ts +98 -0
- package/src/layout/utils/gap-calculator.ts +167 -0
- package/src/layout/utils/inline-formatter.ts +31 -0
- package/src/layout/utils/inline-formatting.ts +9 -0
- package/src/layout/utils/margin.ts +140 -0
- package/src/layout/utils/node-math.ts +237 -0
- package/src/layout/utils/overflow.ts +14 -0
- package/src/layout/utils/sizing.ts +12 -0
- package/src/layout/utils/text-metrics.ts +361 -0
- package/src/logging/debug.ts +58 -0
- package/src/pdf/font/base14/widths-courier-bold.ts +159 -0
- package/src/pdf/font/base14/widths-courier.ts +159 -0
- package/src/pdf/font/base14/widths-helvetica-bold.ts +158 -0
- package/src/pdf/font/base14/widths-helvetica.ts +158 -0
- package/src/pdf/font/base14/widths-times-bold.ts +158 -0
- package/src/pdf/font/base14/widths-times-roman.ts +158 -0
- package/src/pdf/font/base14/widths-types.ts +25 -0
- package/src/pdf/font/base14-widths.ts +32 -0
- package/src/pdf/font/blur.ts +81 -0
- package/src/pdf/font/builtin-fonts.browser.ts +262 -0
- package/src/pdf/font/builtin-fonts.ts +126 -0
- package/src/pdf/font/composite-glyph-parser.ts +242 -0
- package/src/pdf/font/embedder.ts +395 -0
- package/src/pdf/font/font-config.ts +190 -0
- package/src/pdf/font/font-registry.ts +263 -0
- package/src/pdf/font/font-subset.ts +258 -0
- package/src/pdf/font/glyph-atlas-maxrects.ts +305 -0
- package/src/pdf/font/glyph-atlas-tuner.ts +98 -0
- package/src/pdf/font/glyph-atlas.ts +226 -0
- package/src/pdf/font/glyph-cache.ts +127 -0
- package/src/pdf/font/loca-reader.ts +109 -0
- package/src/pdf/font/managers/font-resource-manager.ts +73 -0
- package/src/pdf/font/managers/subset-resource-manager.ts +164 -0
- package/src/pdf/font/rasterizer.ts +270 -0
- package/src/pdf/font/resolvers/base-font-mapper.ts +77 -0
- package/src/pdf/font/resolvers/family-resolver.ts +33 -0
- package/src/pdf/font/resolvers/weight-style-applicator.ts +63 -0
- package/src/pdf/font/simple-glyph-parser.ts +289 -0
- package/src/pdf/font/to-unicode.ts +109 -0
- package/src/pdf/font/transformation-matrix.ts +136 -0
- package/src/pdf/font/ttf-cmap.ts +180 -0
- package/src/pdf/font/ttf-global-metrics.ts +58 -0
- package/src/pdf/font/ttf-glyf.ts +125 -0
- package/src/pdf/font/ttf-glyph-metrics.ts +43 -0
- package/src/pdf/font/ttf-lite.ts +269 -0
- package/src/pdf/font/ttf-table-parser.ts +132 -0
- package/src/pdf/font/ttf-table-provider.ts +61 -0
- package/src/pdf/font/widths.ts +79 -0
- package/src/pdf/font-subset/font-registry.ts +127 -0
- package/src/pdf/header-footer-layout.ts +153 -0
- package/src/pdf/header-footer-painter.ts +209 -0
- package/src/pdf/header-footer-renderer.ts +357 -0
- package/src/pdf/header-footer-tokens.ts +55 -0
- package/src/pdf/header-footer.ts +25 -0
- package/src/pdf/layout-tree-builder.ts +261 -0
- package/src/pdf/page-painter.ts +241 -0
- package/src/pdf/pagination.ts +155 -0
- package/src/pdf/primitives/pdf-builder.ts +378 -0
- package/src/pdf/primitives/pdf-bytes.ts +40 -0
- package/src/pdf/primitives/pdf-document.ts +108 -0
- package/src/pdf/primitives/pdf-reference-manager.ts +47 -0
- package/src/pdf/primitives/pdf-resource-registries.ts +255 -0
- package/src/pdf/primitives/pdf-serializers.ts +194 -0
- package/src/pdf/primitives/pdf-types.ts +73 -0
- package/src/pdf/render.ts +210 -0
- package/src/pdf/renderer/box-painter.ts +236 -0
- package/src/pdf/renderer/page-paint.ts +102 -0
- package/src/pdf/renderer/paint-box-shadows.ts +218 -0
- package/src/pdf/renderer/radius.ts +58 -0
- package/src/pdf/renderers/graphics-state-manager.ts +40 -0
- package/src/pdf/renderers/image-renderer.ts +127 -0
- package/src/pdf/renderers/radius-utils.ts +80 -0
- package/src/pdf/renderers/rectangle-renderer.ts +129 -0
- package/src/pdf/renderers/rounded-rect-path.ts +120 -0
- package/src/pdf/renderers/shape-renderer.ts +563 -0
- package/src/pdf/renderers/shape-utils.ts +194 -0
- package/src/pdf/renderers/text-decoration-renderer.ts +313 -0
- package/src/pdf/renderers/text-encoder.ts +41 -0
- package/src/pdf/renderers/text-font-resolver.ts +75 -0
- package/src/pdf/renderers/text-renderer-utils.ts +28 -0
- package/src/pdf/renderers/text-renderer.ts +391 -0
- package/src/pdf/renderers/text-shadow-renderer.ts +300 -0
- package/src/pdf/shading/gradient-service.ts +525 -0
- package/src/pdf/shading/index.ts +1 -0
- package/src/pdf/stacking/build-stacking-contexts.ts +93 -0
- package/src/pdf/stacking/resolve-paint-order.ts +157 -0
- package/src/pdf/stacking/types.ts +40 -0
- package/src/pdf/svg/aspect-ratio.ts +81 -0
- package/src/pdf/svg/coordinate-mapper.ts +81 -0
- package/src/pdf/svg/geometry-builder.ts +45 -0
- package/src/pdf/svg/render-svg.ts +296 -0
- package/src/pdf/svg/shape-renderer.ts +463 -0
- package/src/pdf/svg/style-computer.ts +246 -0
- package/src/pdf/transform-adapter.ts +26 -0
- package/src/pdf/types.ts +377 -0
- package/src/pdf/utils/background-layer-resolver.ts +439 -0
- package/src/pdf/utils/background-tiles.ts +192 -0
- package/src/pdf/utils/border-dashes.ts +109 -0
- package/src/pdf/utils/border-radius-utils.ts +86 -0
- package/src/pdf/utils/box-dimensions-utils.ts +47 -0
- package/src/pdf/utils/clip-path-resolver.ts +50 -0
- package/src/pdf/utils/clipping-path-builder.ts +190 -0
- package/src/pdf/utils/color-utils.ts +102 -0
- package/src/pdf/utils/coordinate-transformer.ts +30 -0
- package/src/pdf/utils/drop-shadow-raster.ts +233 -0
- package/src/pdf/utils/encoding.ts +98 -0
- package/src/pdf/utils/glyph-atlas-registrar.ts +13 -0
- package/src/pdf/utils/glyph-run-renderer.ts +129 -0
- package/src/pdf/utils/image-command-partitioner.ts +28 -0
- package/src/pdf/utils/image-matrix-builder.ts +31 -0
- package/src/pdf/utils/image-utils.ts +26 -0
- package/src/pdf/utils/list-utils.ts +194 -0
- package/src/pdf/utils/node-text-run-factory.ts +202 -0
- package/src/pdf/utils/page-resource-registrar.ts +46 -0
- package/src/pdf/utils/result-combiner.ts +102 -0
- package/src/pdf/utils/shadow-utils.ts +127 -0
- package/src/pdf/utils/text-alignment-resolver.ts +76 -0
- package/src/pdf/utils/text-decoration-utils.ts +64 -0
- package/src/pdf/utils/text-layout-adjuster.ts +185 -0
- package/src/pdf/utils/text-utils.ts +193 -0
- package/src/pdf/utils/transform-scope-manager.ts +69 -0
- package/src/render/offset.ts +170 -0
- package/src/shim/empty.ts +2 -0
- package/src/shim/fs-empty.ts +5 -0
- package/src/shim/url-empty.ts +7 -0
- package/src/shim/zlib-empty.ts +9 -0
- package/src/style/shorthands/index.ts +19 -0
- package/src/style/ua/defaults.ts +69 -0
- package/src/svg/index.ts +4 -0
- package/src/svg/parser-registry.ts +71 -0
- package/src/svg/parser.ts +486 -0
- package/src/svg/path-data.ts +515 -0
- package/src/svg/types.ts +194 -0
- package/src/text/line-breaker.ts +321 -0
- package/src/text/text-transform.ts +43 -0
- package/src/text/text.ts +33 -0
- package/src/transform/css-parser.ts +95 -0
- package/src/types/fonts.ts +62 -0
- package/src/types/public.ts +19 -0
- package/src/units/page-utils.ts +58 -0
- package/src/units/units.ts +50 -0
- package/src/utils/base64.ts +24 -0
- package/test-output.txt +79 -0
- package/tests/css/background-parser.spec.ts +14 -0
- package/tests/css/clip-path-parser.spec.ts +66 -0
- package/tests/environment/path-resolution.spec.ts +104 -0
- package/tests/helpers/ai-layout-diagnostics.ts +141 -0
- package/tests/helpers/render-utils.ts +52 -0
- package/tests/helpers/text-geometry.ts +56 -0
- package/tests/layout/custom-properties.test.ts +38 -0
- package/tests/layout/gap-calculator.spec.ts +196 -0
- package/tests/layout/inline-background-alignment.spec.ts +93 -0
- package/tests/layout/inline-fragments.spec.ts +26 -0
- package/tests/layout/run-placer-baseline.spec.ts +108 -0
- package/tests/pdf/alignments.spec.ts +26 -0
- package/tests/pdf/background-clip.spec.ts +57 -0
- package/tests/pdf/background-repeat-space-round.spec.ts +35 -0
- package/tests/pdf/background-repeat.spec.ts +137 -0
- package/tests/pdf/border-radius.spec.ts +151 -0
- package/tests/pdf/clip-path.spec.ts +92 -0
- package/tests/pdf/radial-gradient.spec.ts +50 -0
- package/tests/pdf/svg-stroke-dash.spec.ts +81 -0
- package/tests/pdf/text-transform-matrix.spec.ts +43 -0
- package/tsconfig.json +17 -0
- package/types/fonts.js +10 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import type { PdfMetadata } from "../types.js";
|
|
2
|
+
import type { PdfObjectRef, PdfObject, PdfPage } from "./pdf-types.js";
|
|
3
|
+
import { PdfReferenceManager } from "./pdf-reference-manager.js";
|
|
4
|
+
import {
|
|
5
|
+
FontRegistry,
|
|
6
|
+
ImageRegistry,
|
|
7
|
+
ExtGStateRegistry,
|
|
8
|
+
ShadingRegistry,
|
|
9
|
+
PatternRegistry,
|
|
10
|
+
ObjectRegistry,
|
|
11
|
+
StreamRegistry,
|
|
12
|
+
} from "./pdf-resource-registries.js";
|
|
13
|
+
import {
|
|
14
|
+
serializeValue,
|
|
15
|
+
serializeType1Font,
|
|
16
|
+
serializeExtGState,
|
|
17
|
+
serializeStream,
|
|
18
|
+
serializeInfo,
|
|
19
|
+
serializeTrailer,
|
|
20
|
+
formatXref,
|
|
21
|
+
formatNumber,
|
|
22
|
+
hasMetadata,
|
|
23
|
+
} from "./pdf-serializers.js";
|
|
24
|
+
import { concatBytes, encodeBinaryString } from "./pdf-bytes.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Orchestrates PDF document generation by coordinating resource registries,
|
|
28
|
+
* reference management, and serialization.
|
|
29
|
+
*
|
|
30
|
+
* This class follows the Single Responsibility Principle by focusing on
|
|
31
|
+
* assembling the PDF document from registered resources.
|
|
32
|
+
*/
|
|
33
|
+
export class PdfBuilder {
|
|
34
|
+
private readonly pages: PdfPage[] = [];
|
|
35
|
+
private readonly refManager = new PdfReferenceManager();
|
|
36
|
+
|
|
37
|
+
// Public registries for resource management
|
|
38
|
+
readonly fontRegistry = new FontRegistry();
|
|
39
|
+
readonly imageRegistry = new ImageRegistry();
|
|
40
|
+
readonly extGStateRegistry = new ExtGStateRegistry();
|
|
41
|
+
readonly shadingRegistry = new ShadingRegistry();
|
|
42
|
+
readonly patternRegistry = new PatternRegistry();
|
|
43
|
+
readonly objectRegistry = new ObjectRegistry();
|
|
44
|
+
readonly streamRegistry = new StreamRegistry();
|
|
45
|
+
|
|
46
|
+
constructor(private readonly metadata: PdfMetadata = {}) { }
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Adds a page to the document.
|
|
50
|
+
*/
|
|
51
|
+
addPage(page: PdfPage): void {
|
|
52
|
+
this.pages.push(page);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Finalizes the document and returns the complete PDF as bytes.
|
|
57
|
+
*/
|
|
58
|
+
finalize(): Uint8Array {
|
|
59
|
+
const objects: PdfObject[] = [];
|
|
60
|
+
const header = encodeBinaryString("%PDF-1.4\n");
|
|
61
|
+
|
|
62
|
+
// Helper to push objects with proper reference assignment
|
|
63
|
+
const pushObject = (
|
|
64
|
+
body: string | Uint8Array | unknown,
|
|
65
|
+
ref?: PdfObjectRef | null
|
|
66
|
+
): PdfObjectRef => {
|
|
67
|
+
const objectRef = this.refManager.ensureRefNumber(ref ?? { objectNumber: 0 });
|
|
68
|
+
let payload: Uint8Array;
|
|
69
|
+
|
|
70
|
+
if (typeof body === "string") {
|
|
71
|
+
payload = encodeBinaryString(body);
|
|
72
|
+
} else if (body instanceof Uint8Array) {
|
|
73
|
+
payload = body;
|
|
74
|
+
} else {
|
|
75
|
+
const serialized = serializeValue(body as Record<string, unknown> | readonly unknown[]);
|
|
76
|
+
payload = encodeBinaryString(serialized);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
objects.push({ ref: objectRef, body: payload });
|
|
80
|
+
return objectRef;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Reserve object numbers for streams/objects that may be referenced
|
|
84
|
+
this.reserveObjectNumbers();
|
|
85
|
+
|
|
86
|
+
// Build all PDF objects
|
|
87
|
+
this.buildFonts(pushObject);
|
|
88
|
+
this.buildExtGStates(pushObject);
|
|
89
|
+
this.buildShadings(pushObject);
|
|
90
|
+
this.buildPatterns(pushObject);
|
|
91
|
+
this.buildImages(pushObject);
|
|
92
|
+
this.buildStreams(pushObject);
|
|
93
|
+
this.buildCustomObjects(pushObject);
|
|
94
|
+
|
|
95
|
+
const pageRefs = this.buildPages(pushObject);
|
|
96
|
+
const pagesRef = this.buildPagesTree(pageRefs, pushObject);
|
|
97
|
+
const catalogRef = this.buildCatalog(pagesRef, pushObject);
|
|
98
|
+
const infoRef = this.buildMetadata(pushObject);
|
|
99
|
+
|
|
100
|
+
return this.assemblePdf(header, objects, catalogRef, infoRef);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Reserves object numbers for resources that may be referenced by others.
|
|
105
|
+
*/
|
|
106
|
+
private reserveObjectNumbers(): void {
|
|
107
|
+
for (const stream of this.streamRegistry.getAll()) {
|
|
108
|
+
this.refManager.ensureRefNumber(stream.ref);
|
|
109
|
+
}
|
|
110
|
+
for (const obj of this.objectRegistry.getAll()) {
|
|
111
|
+
this.refManager.ensureRefNumber(obj.ref);
|
|
112
|
+
}
|
|
113
|
+
for (const pattern of this.patternRegistry.getAll()) {
|
|
114
|
+
this.refManager.ensureRefNumber(pattern.ref);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Builds font objects.
|
|
120
|
+
*/
|
|
121
|
+
private buildFonts(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
122
|
+
for (const font of this.fontRegistry.getAll()) {
|
|
123
|
+
font.objectRef = pushObject(serializeType1Font(font.baseFont), font.objectRef);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Builds ExtGState objects.
|
|
129
|
+
*/
|
|
130
|
+
private buildExtGStates(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
131
|
+
for (const state of this.extGStateRegistry.getAll()) {
|
|
132
|
+
state.ref = pushObject(serializeExtGState(state.alpha), state.ref);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Builds shading objects.
|
|
138
|
+
*/
|
|
139
|
+
private buildShadings(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
140
|
+
for (const shading of this.shadingRegistry.getAll()) {
|
|
141
|
+
shading.ref = pushObject(shading.dict, shading.ref);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Builds pattern objects.
|
|
147
|
+
*/
|
|
148
|
+
private buildPatterns(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
149
|
+
for (const pattern of this.patternRegistry.getAll()) {
|
|
150
|
+
pattern.ref = pushObject(pattern.dict, pattern.ref);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Builds image XObject streams.
|
|
156
|
+
*/
|
|
157
|
+
private buildImages(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
158
|
+
for (const image of this.imageRegistry.getAll()) {
|
|
159
|
+
const entries = [
|
|
160
|
+
"/Type /XObject",
|
|
161
|
+
"/Subtype /Image",
|
|
162
|
+
`/Width ${image.width}`,
|
|
163
|
+
`/Height ${image.height}`,
|
|
164
|
+
`/ColorSpace /${image.colorSpace}`,
|
|
165
|
+
`/BitsPerComponent ${image.bitsPerComponent}`,
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
if (image.filter) {
|
|
169
|
+
entries.push(`/Filter /${image.filter}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (image.sMask) {
|
|
173
|
+
entries.push(`/SMask ${image.sMask.objectNumber} 0 R`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const stream = serializeStream(image.data, entries);
|
|
177
|
+
image.ref = pushObject(stream, image.ref);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Builds custom stream objects.
|
|
183
|
+
*/
|
|
184
|
+
private buildStreams(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
185
|
+
for (const stream of this.streamRegistry.getAll()) {
|
|
186
|
+
const entries = Object.entries(stream.headers).map(([k, v]) => `/${k} ${v}`);
|
|
187
|
+
const body = serializeStream(stream.data, entries);
|
|
188
|
+
stream.ref = pushObject(body, stream.ref);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Builds custom registered objects.
|
|
194
|
+
*/
|
|
195
|
+
private buildCustomObjects(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): void {
|
|
196
|
+
for (const obj of this.objectRegistry.getAll()) {
|
|
197
|
+
obj.ref = pushObject(obj.value, obj.ref);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Builds page objects and returns their references.
|
|
203
|
+
*/
|
|
204
|
+
private buildPages(pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef): PdfObjectRef[] {
|
|
205
|
+
const pageRefs: PdfObjectRef[] = [];
|
|
206
|
+
|
|
207
|
+
for (const page of this.pages) {
|
|
208
|
+
const contentRef = pushObject(serializeStream(page.contents));
|
|
209
|
+
|
|
210
|
+
const resourcesParts = this.buildPageResources(page);
|
|
211
|
+
const annotationRefs = this.buildPageAnnotations(page, pushObject);
|
|
212
|
+
|
|
213
|
+
const resources = resourcesParts.length > 0 ? `/Resources << ${resourcesParts.join(" ")} >>` : "";
|
|
214
|
+
const annots = annotationRefs.length > 0
|
|
215
|
+
? `/Annots [${annotationRefs.map((r) => `${r.objectNumber} 0 R`).join(" ")}]`
|
|
216
|
+
: "";
|
|
217
|
+
|
|
218
|
+
const pageBody = [
|
|
219
|
+
"<<",
|
|
220
|
+
"/Type /Page",
|
|
221
|
+
`/MediaBox [0 0 ${formatNumber(page.width)} ${formatNumber(page.height)}]`,
|
|
222
|
+
resources,
|
|
223
|
+
annots,
|
|
224
|
+
`/Contents ${contentRef.objectNumber} 0 R`,
|
|
225
|
+
">>",
|
|
226
|
+
]
|
|
227
|
+
.filter(Boolean)
|
|
228
|
+
.join("\n");
|
|
229
|
+
|
|
230
|
+
const pageRef = pushObject(pageBody);
|
|
231
|
+
pageRefs.push(pageRef);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return pageRefs;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Builds page resources dictionary parts.
|
|
239
|
+
*/
|
|
240
|
+
private buildPageResources(page: PdfPage): string[] {
|
|
241
|
+
const resourcesParts: string[] = [];
|
|
242
|
+
|
|
243
|
+
// Fonts
|
|
244
|
+
const fontEntries: string[] = [];
|
|
245
|
+
for (const [alias, ref] of page.resources.fonts) {
|
|
246
|
+
fontEntries.push(`/${alias} ${ref.objectNumber} 0 R`);
|
|
247
|
+
}
|
|
248
|
+
if (fontEntries.length > 0) {
|
|
249
|
+
resourcesParts.push(`/Font << ${fontEntries.join(" ")} >>`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// XObjects (images)
|
|
253
|
+
const xObjectEntries: string[] = [];
|
|
254
|
+
for (const [alias, ref] of page.resources.xObjects) {
|
|
255
|
+
xObjectEntries.push(`/${alias} ${ref.objectNumber} 0 R`);
|
|
256
|
+
}
|
|
257
|
+
if (xObjectEntries.length > 0) {
|
|
258
|
+
resourcesParts.push(`/XObject << ${xObjectEntries.join(" ")} >>`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ExtGStates
|
|
262
|
+
const gStateEntries: string[] = [];
|
|
263
|
+
for (const [alias, ref] of page.resources.extGStates) {
|
|
264
|
+
gStateEntries.push(`/${alias} ${ref.objectNumber} 0 R`);
|
|
265
|
+
}
|
|
266
|
+
if (gStateEntries.length > 0) {
|
|
267
|
+
resourcesParts.push(`/ExtGState << ${gStateEntries.join(" ")} >>`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Shadings
|
|
271
|
+
const shadingEntries: string[] = [];
|
|
272
|
+
for (const [alias, ref] of page.resources.shadings) {
|
|
273
|
+
shadingEntries.push(`/${alias} ${ref.objectNumber} 0 R`);
|
|
274
|
+
}
|
|
275
|
+
if (shadingEntries.length > 0) {
|
|
276
|
+
resourcesParts.push(`/Shading << ${shadingEntries.join(" ")} >>`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Patterns
|
|
280
|
+
const patternEntries: string[] = [];
|
|
281
|
+
if (page.resources.patterns) {
|
|
282
|
+
for (const [alias, ref] of page.resources.patterns) {
|
|
283
|
+
patternEntries.push(`/${alias} ${ref.objectNumber} 0 R`);
|
|
284
|
+
}
|
|
285
|
+
if (patternEntries.length > 0) {
|
|
286
|
+
resourcesParts.push(`/Pattern << ${patternEntries.join(" ")} >>`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return resourcesParts;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Builds page annotation objects.
|
|
295
|
+
*/
|
|
296
|
+
private buildPageAnnotations(
|
|
297
|
+
page: PdfPage,
|
|
298
|
+
pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef
|
|
299
|
+
): PdfObjectRef[] {
|
|
300
|
+
const annotationRefs: PdfObjectRef[] = [];
|
|
301
|
+
for (const annotation of page.annotations) {
|
|
302
|
+
const annotRef = pushObject(annotation);
|
|
303
|
+
annotationRefs.push(annotRef);
|
|
304
|
+
}
|
|
305
|
+
return annotationRefs;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Builds the Pages tree object.
|
|
310
|
+
*/
|
|
311
|
+
private buildPagesTree(
|
|
312
|
+
pageRefs: PdfObjectRef[],
|
|
313
|
+
pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef
|
|
314
|
+
): PdfObjectRef {
|
|
315
|
+
const kids = pageRefs.map((ref) => `${ref.objectNumber} 0 R`).join(" ");
|
|
316
|
+
return pushObject(
|
|
317
|
+
["<<", "/Type /Pages", `/Count ${pageRefs.length}`, `/Kids [${kids}]`, ">>"].join("\n")
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Builds the Catalog object.
|
|
323
|
+
*/
|
|
324
|
+
private buildCatalog(
|
|
325
|
+
pagesRef: PdfObjectRef,
|
|
326
|
+
pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef
|
|
327
|
+
): PdfObjectRef {
|
|
328
|
+
return pushObject(
|
|
329
|
+
["<<", "/Type /Catalog", `/Pages ${pagesRef.objectNumber} 0 R`, ">>"].join("\n")
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Builds the Info (metadata) object if metadata is present.
|
|
335
|
+
*/
|
|
336
|
+
private buildMetadata(
|
|
337
|
+
pushObject: (body: string | Uint8Array | unknown, ref?: PdfObjectRef | null) => PdfObjectRef
|
|
338
|
+
): PdfObjectRef | null {
|
|
339
|
+
if (hasMetadata(this.metadata)) {
|
|
340
|
+
return pushObject(serializeInfo(this.metadata));
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Assembles the final PDF byte array.
|
|
347
|
+
*/
|
|
348
|
+
private assemblePdf(
|
|
349
|
+
header: Uint8Array,
|
|
350
|
+
objects: PdfObject[],
|
|
351
|
+
catalogRef: PdfObjectRef,
|
|
352
|
+
infoRef: PdfObjectRef | null
|
|
353
|
+
): Uint8Array {
|
|
354
|
+
const xrefEntries: string[] = ["0000000000 65535 f \n"];
|
|
355
|
+
const chunks: Uint8Array[] = [header];
|
|
356
|
+
let offset = header.length;
|
|
357
|
+
|
|
358
|
+
// Write all objects
|
|
359
|
+
for (const object of objects) {
|
|
360
|
+
const objectHeader = encodeBinaryString(`${object.ref.objectNumber} 0 obj\n`);
|
|
361
|
+
const objectFooter = encodeBinaryString("\nendobj\n");
|
|
362
|
+
const objectBuffer = concatBytes([objectHeader, object.body, objectFooter]);
|
|
363
|
+
xrefEntries.push(formatXref(offset));
|
|
364
|
+
chunks.push(objectBuffer);
|
|
365
|
+
offset += objectBuffer.length;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Write cross-reference table and trailer
|
|
369
|
+
const xrefStart = offset;
|
|
370
|
+
const size = this.refManager.getObjectCount();
|
|
371
|
+
const trailerBody = encodeBinaryString(
|
|
372
|
+
`xref\n0 ${size}\n${xrefEntries.join("")}trailer\n${serializeTrailer(size, catalogRef, infoRef)}\nstartxref\n${xrefStart}\n%%EOF\n`
|
|
373
|
+
);
|
|
374
|
+
chunks.push(trailerBody);
|
|
375
|
+
|
|
376
|
+
return concatBytes(chunks);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for working with PDF byte data without relying on Node's Buffer.
|
|
3
|
+
* These utilities keep encoding predictable across Node and browser builds.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Encode a "binary" string (latin1) into a Uint8Array.
|
|
8
|
+
* Characters beyond 0xFF are truncated to preserve byte-for-byte output.
|
|
9
|
+
*/
|
|
10
|
+
export function encodeBinaryString(value: string): Uint8Array {
|
|
11
|
+
const out = new Uint8Array(value.length);
|
|
12
|
+
for (let i = 0; i < value.length; i++) {
|
|
13
|
+
out[i] = value.charCodeAt(i) & 0xff;
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Encode a UTF-8 string into bytes. Use this for plain text sections; avoids Buffer.
|
|
20
|
+
*/
|
|
21
|
+
const utf8Encoder = new TextEncoder();
|
|
22
|
+
export function encodeText(value: string): Uint8Array {
|
|
23
|
+
return utf8Encoder.encode(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Concatenate byte chunks into a single Uint8Array.
|
|
28
|
+
*/
|
|
29
|
+
export function concatBytes(chunks: Uint8Array[]): Uint8Array {
|
|
30
|
+
let total = 0;
|
|
31
|
+
for (const chunk of chunks) total += chunk.length;
|
|
32
|
+
|
|
33
|
+
const out = new Uint8Array(total);
|
|
34
|
+
let offset = 0;
|
|
35
|
+
for (const chunk of chunks) {
|
|
36
|
+
out.set(chunk, offset);
|
|
37
|
+
offset += chunk.length;
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { PdfMetadata } from "../types.js";
|
|
2
|
+
import type { PdfObjectRef, PdfPage, PdfResources } from "./pdf-types.js";
|
|
3
|
+
import { PdfBuilder } from "./pdf-builder.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Main PDF document class that provides a public API for PDF generation.
|
|
7
|
+
*
|
|
8
|
+
* This class now acts as a thin facade over the PdfBuilder architecture,
|
|
9
|
+
* delegating all responsibilities to focused, single-purpose components.
|
|
10
|
+
* The public API remains unchanged for backward compatibility.
|
|
11
|
+
*/
|
|
12
|
+
export class PdfDocument {
|
|
13
|
+
private readonly builder: PdfBuilder;
|
|
14
|
+
|
|
15
|
+
constructor(metadata: PdfMetadata = {}) {
|
|
16
|
+
this.builder = new PdfBuilder(metadata);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Registers a standard Type1 font and returns a reference to it.
|
|
21
|
+
*/
|
|
22
|
+
registerStandardFont(baseFont: string): PdfObjectRef {
|
|
23
|
+
return this.builder.fontRegistry.register(baseFont);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Adds a page to the document.
|
|
28
|
+
*/
|
|
29
|
+
addPage(page: Omit<PdfPage, "resources"> & { resources?: Partial<PdfResources> }): void {
|
|
30
|
+
const resources: PdfResources = {
|
|
31
|
+
fonts: page.resources?.fonts ?? new Map(),
|
|
32
|
+
xObjects: page.resources?.xObjects ?? new Map(),
|
|
33
|
+
extGStates: page.resources?.extGStates ?? new Map(),
|
|
34
|
+
shadings: page.resources?.shadings ?? new Map(),
|
|
35
|
+
patterns: page.resources?.patterns ?? new Map(),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.builder.addPage({
|
|
39
|
+
width: page.width,
|
|
40
|
+
height: page.height,
|
|
41
|
+
contents: page.contents,
|
|
42
|
+
resources,
|
|
43
|
+
annotations: page.annotations ?? [],
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Registers an image and returns a reference to it.
|
|
49
|
+
* Handles deduplication and PNG alpha channel separation automatically.
|
|
50
|
+
*/
|
|
51
|
+
registerImage(image: {
|
|
52
|
+
src: string;
|
|
53
|
+
width: number;
|
|
54
|
+
height: number;
|
|
55
|
+
format: "jpeg" | "png" | "gif" | "webp";
|
|
56
|
+
channels: number;
|
|
57
|
+
bitsPerComponent: number;
|
|
58
|
+
data: Uint8Array;
|
|
59
|
+
}): PdfObjectRef {
|
|
60
|
+
return this.builder.imageRegistry.register(image);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Registers an ExtGState with the given alpha value.
|
|
65
|
+
* Automatically deduplicates by alpha value.
|
|
66
|
+
*/
|
|
67
|
+
registerExtGState(alpha: number): PdfObjectRef {
|
|
68
|
+
return this.builder.extGStateRegistry.register(alpha);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Registers a shading resource.
|
|
73
|
+
*/
|
|
74
|
+
registerShading(name: string, dict: string): PdfObjectRef {
|
|
75
|
+
return this.builder.shadingRegistry.register(name, dict);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Registers a pattern resource.
|
|
80
|
+
*/
|
|
81
|
+
registerPattern(name: string, dict: string): PdfObjectRef {
|
|
82
|
+
return this.builder.patternRegistry.register(name, dict);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Registers a custom PDF object.
|
|
87
|
+
*/
|
|
88
|
+
register(value: string | Record<string, unknown> | readonly unknown[] | object): PdfObjectRef {
|
|
89
|
+
return this.builder.objectRegistry.register(value);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Registers a stream object with custom headers.
|
|
94
|
+
*/
|
|
95
|
+
registerStream(data: Uint8Array, extraHeaders: Record<string, string> = {}): PdfObjectRef {
|
|
96
|
+
return this.builder.streamRegistry.register(data, extraHeaders);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Finalizes the PDF document and returns the complete PDF as a byte array.
|
|
101
|
+
*/
|
|
102
|
+
finalize(): Uint8Array {
|
|
103
|
+
return this.builder.finalize();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Re-export PdfObjectRef for backward compatibility
|
|
108
|
+
export type { PdfObjectRef } from "./pdf-types.js";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { PdfObjectRef } from "./pdf-types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Manages PDF object reference assignment and numbering.
|
|
5
|
+
*
|
|
6
|
+
* This class follows the Single Responsibility Principle by handling
|
|
7
|
+
* only object reference creation and number assignment.
|
|
8
|
+
*/
|
|
9
|
+
export class PdfReferenceManager {
|
|
10
|
+
private currentObjectNumber = 1;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new PDF object reference with an unassigned object number.
|
|
14
|
+
* The actual number will be assigned later by ensureRefNumber().
|
|
15
|
+
*/
|
|
16
|
+
createRef(): PdfObjectRef {
|
|
17
|
+
return { objectNumber: -1 };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ensures the given reference has a valid object number.
|
|
22
|
+
* If the reference already has a number, it updates the internal counter.
|
|
23
|
+
* Otherwise, it assigns the next available number.
|
|
24
|
+
*/
|
|
25
|
+
ensureRefNumber(ref: PdfObjectRef): PdfObjectRef {
|
|
26
|
+
if (ref.objectNumber <= 0) {
|
|
27
|
+
ref.objectNumber = this.currentObjectNumber++;
|
|
28
|
+
} else if (ref.objectNumber >= this.currentObjectNumber) {
|
|
29
|
+
this.currentObjectNumber = ref.objectNumber + 1;
|
|
30
|
+
}
|
|
31
|
+
return ref;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns the next available object number without incrementing.
|
|
36
|
+
*/
|
|
37
|
+
getNextObjectNumber(): number {
|
|
38
|
+
return this.currentObjectNumber;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns the current total count of objects (for PDF size field).
|
|
43
|
+
*/
|
|
44
|
+
getObjectCount(): number {
|
|
45
|
+
return this.currentObjectNumber;
|
|
46
|
+
}
|
|
47
|
+
}
|