@pixldocs/canvas-renderer 0.5.109 → 0.5.111
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/dist/index.cjs +85 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +85 -11
- package/dist/index.js.map +1 -1
- package/dist/{svgTextToPath-CeL46_ks.cjs → svgTextToPath-4Y_THSBg.cjs} +36 -4
- package/dist/svgTextToPath-4Y_THSBg.cjs.map +1 -0
- package/dist/{svgTextToPath-B2UVS22F.js → svgTextToPath-CQ2Tp03U.js} +36 -4
- package/dist/svgTextToPath-CQ2Tp03U.js.map +1 -0
- package/package.json +1 -1
- package/dist/svgTextToPath-B2UVS22F.js.map +0 -1
- package/dist/svgTextToPath-CeL46_ks.cjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -144,6 +144,9 @@ export declare function extractFontFamiliesFromSvgs(svgs: string[]): Set<string>
|
|
|
144
144
|
/** Font used for Devanagari / Hindi script */
|
|
145
145
|
export declare const FONT_FALLBACK_DEVANAGARI = "Hind";
|
|
146
146
|
|
|
147
|
+
/** Font used only when the active font lacks math/operator glyphs. */
|
|
148
|
+
export declare const FONT_FALLBACK_MATH = "Noto Sans Math";
|
|
149
|
+
|
|
147
150
|
/** Font used for symbols (● ◆ ★ etc.) */
|
|
148
151
|
export declare const FONT_FALLBACK_SYMBOLS = "Noto Sans";
|
|
149
152
|
|
|
@@ -256,7 +259,7 @@ export declare function normalizeFontFamily(fontStack: string): string;
|
|
|
256
259
|
* Package version banner. Bump alongside package.json so we can confirm
|
|
257
260
|
* (via browser:log) that the deployed bundle matches the expected build.
|
|
258
261
|
*/
|
|
259
|
-
export declare const PACKAGE_VERSION = "0.5.
|
|
262
|
+
export declare const PACKAGE_VERSION = "0.5.110";
|
|
260
263
|
|
|
261
264
|
export declare interface PageSettings {
|
|
262
265
|
backgroundColor?: string;
|
|
@@ -302,7 +305,7 @@ export declare interface PdfFromFormOptions {
|
|
|
302
305
|
title?: string;
|
|
303
306
|
/** Base URL for TTF font files for PDF font embedding */
|
|
304
307
|
fontBaseUrl?: string;
|
|
305
|
-
/** PDF text rendering mode. Default:
|
|
308
|
+
/** PDF text rendering mode. Default: pixel-perfect path text for canvas parity. */
|
|
306
309
|
textMode?: 'auto' | 'selectable' | 'pixel-perfect';
|
|
307
310
|
}
|
|
308
311
|
|
package/dist/index.js
CHANGED
|
@@ -13998,7 +13998,7 @@ function PixldocsPreview(props) {
|
|
|
13998
13998
|
!canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
13999
13999
|
] });
|
|
14000
14000
|
}
|
|
14001
|
-
const PACKAGE_VERSION = "0.5.
|
|
14001
|
+
const PACKAGE_VERSION = "0.5.110";
|
|
14002
14002
|
const roundParityValue = (value) => {
|
|
14003
14003
|
if (typeof value !== "number") return value;
|
|
14004
14004
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -14285,7 +14285,7 @@ class PixldocsRenderer {
|
|
|
14285
14285
|
async renderPdf(templateConfig, options) {
|
|
14286
14286
|
const svgs = await this.renderAllPageSvgs(templateConfig);
|
|
14287
14287
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
14288
|
-
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl, textMode: (options == null ? void 0 : options.textMode) ??
|
|
14288
|
+
return assemblePdfFromSvgs2(svgs, { title: options == null ? void 0 : options.title, fontBaseUrl: options == null ? void 0 : options.fontBaseUrl, textMode: (options == null ? void 0 : options.textMode) ?? "pixel-perfect" });
|
|
14289
14289
|
}
|
|
14290
14290
|
/**
|
|
14291
14291
|
* Resolve from V2 sectionState and render a vector PDF.
|
|
@@ -14310,7 +14310,7 @@ class PixldocsRenderer {
|
|
|
14310
14310
|
}
|
|
14311
14311
|
const svgs = await this.renderAllPageSvgs(configToRender);
|
|
14312
14312
|
const { assemblePdfFromSvgs: assemblePdfFromSvgs2 } = await Promise.resolve().then(() => pdfExport);
|
|
14313
|
-
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl, textMode: options.textMode ??
|
|
14313
|
+
return assemblePdfFromSvgs2(svgs, { title: title ?? resolved.config.name, fontBaseUrl, textMode: options.textMode ?? "pixel-perfect" });
|
|
14314
14314
|
}
|
|
14315
14315
|
async renderById(templateId, formData, options) {
|
|
14316
14316
|
const resolved = await resolveTemplateData({
|
|
@@ -15052,6 +15052,7 @@ function resolveFontWeight(weight) {
|
|
|
15052
15052
|
}
|
|
15053
15053
|
const FONT_FALLBACK_SYMBOLS = "Noto Sans";
|
|
15054
15054
|
const FONT_FALLBACK_DEVANAGARI = "Hind";
|
|
15055
|
+
const FONT_FALLBACK_MATH = "Noto Sans Math";
|
|
15055
15056
|
const FONT_FILES = {
|
|
15056
15057
|
"Playfair Display": {
|
|
15057
15058
|
regular: "PlayfairDisplay-Regular.ttf",
|
|
@@ -15523,6 +15524,9 @@ const FONT_FILES = {
|
|
|
15523
15524
|
medium: "Hind-Medium.ttf",
|
|
15524
15525
|
semibold: "Hind-SemiBold.ttf"
|
|
15525
15526
|
},
|
|
15527
|
+
"Noto Sans Math": {
|
|
15528
|
+
regular: "NotoSansMath-Regular.ttf"
|
|
15529
|
+
},
|
|
15526
15530
|
"Cinzel": { regular: "Cinzel-Regular.ttf", bold: "Cinzel-Bold.ttf" },
|
|
15527
15531
|
"Cormorant Garamond": {
|
|
15528
15532
|
regular: "CormorantGaramond-Regular.ttf",
|
|
@@ -15625,6 +15629,54 @@ function isJsPdfEmbeddableTrueType(bytes) {
|
|
|
15625
15629
|
}
|
|
15626
15630
|
return false;
|
|
15627
15631
|
}
|
|
15632
|
+
function base64ToBytes(b64) {
|
|
15633
|
+
const binary = atob(b64);
|
|
15634
|
+
const bytes = new Uint8Array(binary.length);
|
|
15635
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
15636
|
+
return bytes;
|
|
15637
|
+
}
|
|
15638
|
+
function extractSupportedCodePointsFromTtf(bytes) {
|
|
15639
|
+
const out = /* @__PURE__ */ new Set();
|
|
15640
|
+
if (bytes.length < 12) return out;
|
|
15641
|
+
const u16 = (o) => bytes[o] << 8 | bytes[o + 1];
|
|
15642
|
+
const i16 = (o) => {
|
|
15643
|
+
const v = u16(o);
|
|
15644
|
+
return v & 32768 ? v - 65536 : v;
|
|
15645
|
+
};
|
|
15646
|
+
const u32 = (o) => (bytes[o] << 24 | bytes[o + 1] << 16 | bytes[o + 2] << 8 | bytes[o + 3]) >>> 0;
|
|
15647
|
+
let cmap = 0;
|
|
15648
|
+
for (let i = 0, n = u16(4); i < n; i++) {
|
|
15649
|
+
const off = 12 + i * 16;
|
|
15650
|
+
if (String.fromCharCode(bytes[off], bytes[off + 1], bytes[off + 2], bytes[off + 3]) === "cmap") {
|
|
15651
|
+
cmap = u32(off + 8);
|
|
15652
|
+
break;
|
|
15653
|
+
}
|
|
15654
|
+
}
|
|
15655
|
+
if (!cmap) return out;
|
|
15656
|
+
const candidates = [];
|
|
15657
|
+
for (let i = 0, n = u16(cmap + 2); i < n; i++) {
|
|
15658
|
+
const enc = cmap + 4 + i * 8;
|
|
15659
|
+
const platform = u16(enc), encoding = u16(enc + 2), off = cmap + u32(enc + 4), format = u16(off);
|
|
15660
|
+
const score = (format === 12 ? 40 : format === 4 ? 30 : 0) + (platform === 3 && encoding === 10 ? 2 : platform === 0 ? 1 : 0);
|
|
15661
|
+
if (score) candidates.push({ format, off, score });
|
|
15662
|
+
}
|
|
15663
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
15664
|
+
const best = candidates[0];
|
|
15665
|
+
if (!best) return out;
|
|
15666
|
+
if (best.format === 12) {
|
|
15667
|
+
for (let i = 0, n = u32(best.off + 12); i < n; i++) {
|
|
15668
|
+
const off = best.off + 16 + i * 12, start = u32(off), end = u32(off + 4);
|
|
15669
|
+
for (let cp = start; cp <= end && cp <= 1114111; cp++) out.add(cp);
|
|
15670
|
+
}
|
|
15671
|
+
} else if (best.format === 4) {
|
|
15672
|
+
const segCount = u16(best.off + 6) / 2, endCodes = best.off + 14, startCodes = endCodes + segCount * 2 + 2, deltas = startCodes + segCount * 2, ranges = deltas + segCount * 2;
|
|
15673
|
+
for (let i = 0; i < segCount; i++) for (let cp = u16(startCodes + i * 2), end = u16(endCodes + i * 2); cp <= end && cp !== 65535; cp++) {
|
|
15674
|
+
const ro = u16(ranges + i * 2);
|
|
15675
|
+
if (ro === 0 ? (cp + i16(deltas + i * 2) & 65535) !== 0 : u16(ranges + i * 2 + ro + (cp - u16(startCodes + i * 2)) * 2) !== 0) out.add(cp);
|
|
15676
|
+
}
|
|
15677
|
+
}
|
|
15678
|
+
return out;
|
|
15679
|
+
}
|
|
15628
15680
|
async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
15629
15681
|
const fontFiles = FONT_FILES[fontName];
|
|
15630
15682
|
if (!fontFiles) return false;
|
|
@@ -15641,6 +15693,7 @@ async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
|
15641
15693
|
try {
|
|
15642
15694
|
const b64 = await fetchTTFAsBase64(url);
|
|
15643
15695
|
if (!b64) return false;
|
|
15696
|
+
registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(b64)));
|
|
15644
15697
|
pdf.addFileToVFS(fileName, b64);
|
|
15645
15698
|
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
15646
15699
|
if (fontName !== jsPdfFontName) {
|
|
@@ -15661,6 +15714,7 @@ const googleFontNotFound = /* @__PURE__ */ new Set();
|
|
|
15661
15714
|
const fontshareNotFound = /* @__PURE__ */ new Set();
|
|
15662
15715
|
const remoteVariantKey = (family, weight, isItalic) => `${family}|${resolveFontWeight(weight)}|${isItalic ? "i" : "n"}`;
|
|
15663
15716
|
const registeredVariants = /* @__PURE__ */ new Set();
|
|
15717
|
+
const registeredVariantCoverage = /* @__PURE__ */ new Map();
|
|
15664
15718
|
const variantKey = (family, weight, italic) => `${family}|${resolveFontWeight(weight)}|${italic ? "i" : "n"}`;
|
|
15665
15719
|
const resolveBestRegisteredVariant = (family, weight, italic) => {
|
|
15666
15720
|
const want = resolveFontWeight(weight);
|
|
@@ -15671,6 +15725,12 @@ const resolveBestRegisteredVariant = (family, weight, italic) => {
|
|
|
15671
15725
|
for (const w of nearest) if (registeredVariants.has(variantKey(family, w, !italic))) return { weight: w, italic: !italic };
|
|
15672
15726
|
return null;
|
|
15673
15727
|
};
|
|
15728
|
+
const doesVariantSupportChar = (family, weight, italic, char) => {
|
|
15729
|
+
var _a;
|
|
15730
|
+
const cp = char.codePointAt(0);
|
|
15731
|
+
if (cp == null) return false;
|
|
15732
|
+
return ((_a = registeredVariantCoverage.get(variantKey(family, weight, italic))) == null ? void 0 : _a.has(cp)) === true;
|
|
15733
|
+
};
|
|
15674
15734
|
function bytesToBase64(bytes) {
|
|
15675
15735
|
let binary = "";
|
|
15676
15736
|
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
@@ -15787,6 +15847,7 @@ function registerJsPdfFont(pdf, fontName, resolvedWeight, isItalic, base64) {
|
|
|
15787
15847
|
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);
|
|
15788
15848
|
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
15789
15849
|
try {
|
|
15850
|
+
registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(base64)));
|
|
15790
15851
|
pdf.addFileToVFS(fileName, base64);
|
|
15791
15852
|
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
15792
15853
|
if (fontName !== jsPdfFontName) {
|
|
@@ -15883,6 +15944,7 @@ async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
|
15883
15944
|
if (page.elements) walkElements(page.elements);
|
|
15884
15945
|
}
|
|
15885
15946
|
fontKeys.add(`${FONT_FALLBACK_SYMBOLS}${SEP}400${SEP}normal`);
|
|
15947
|
+
fontKeys.add(`${FONT_FALLBACK_MATH}${SEP}400${SEP}normal`);
|
|
15886
15948
|
for (const w of [300, 400, 500, 600, 700]) {
|
|
15887
15949
|
fontKeys.add(`${FONT_FALLBACK_DEVANAGARI}${SEP}${w}${SEP}normal`);
|
|
15888
15950
|
}
|
|
@@ -15916,10 +15978,10 @@ function containsDevanagari(text) {
|
|
|
15916
15978
|
}
|
|
15917
15979
|
return false;
|
|
15918
15980
|
}
|
|
15919
|
-
function containsSymbol(text) {
|
|
15981
|
+
function containsSymbol(text, mainSupportsChar) {
|
|
15920
15982
|
if (!text) return false;
|
|
15921
15983
|
for (const char of text) {
|
|
15922
|
-
if (classifyChar(char)
|
|
15984
|
+
if (classifyChar(char, mainSupportsChar) !== "main") return true;
|
|
15923
15985
|
}
|
|
15924
15986
|
return false;
|
|
15925
15987
|
}
|
|
@@ -15933,19 +15995,25 @@ function isCommonLatinPunctuation(char) {
|
|
|
15933
15995
|
if (c === 8467 || c === 8482) return true;
|
|
15934
15996
|
return false;
|
|
15935
15997
|
}
|
|
15936
|
-
function
|
|
15998
|
+
function isMathOperator(char) {
|
|
15999
|
+
const c = char.codePointAt(0) ?? 0;
|
|
16000
|
+
return c >= 8592 && c <= 8959 || c >= 8960 && c <= 9215 || c >= 10176 && c <= 11007 || c >= 11008 && c <= 11097;
|
|
16001
|
+
}
|
|
16002
|
+
function classifyChar(char, mainSupportsChar) {
|
|
15937
16003
|
if (isBasicLatinOrLatin1(char)) return "main";
|
|
15938
16004
|
if (isCommonLatinPunctuation(char)) return "main";
|
|
16005
|
+
if (!isDevanagari(char) && (mainSupportsChar == null ? void 0 : mainSupportsChar(char))) return "main";
|
|
15939
16006
|
if (isDevanagari(char)) return "devanagari";
|
|
16007
|
+
if (isMathOperator(char)) return "math";
|
|
15940
16008
|
return "symbol";
|
|
15941
16009
|
}
|
|
15942
|
-
function splitIntoRuns(text) {
|
|
16010
|
+
function splitIntoRuns(text, mainSupportsChar) {
|
|
15943
16011
|
if (!text) return [];
|
|
15944
16012
|
const runs = [];
|
|
15945
16013
|
let currentType = null;
|
|
15946
16014
|
let currentText = "";
|
|
15947
16015
|
for (const char of text) {
|
|
15948
|
-
const type = classifyChar(char);
|
|
16016
|
+
const type = classifyChar(char, mainSupportsChar);
|
|
15949
16017
|
if (type !== currentType && currentText) {
|
|
15950
16018
|
runs.push({ text: currentText, runType: currentType });
|
|
15951
16019
|
currentText = "";
|
|
@@ -16053,15 +16121,17 @@ function rewriteSvgFontsForJsPDF(svgStr) {
|
|
|
16053
16121
|
}
|
|
16054
16122
|
const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
|
|
16055
16123
|
const hasDevanagari = containsDevanagari(directText);
|
|
16056
|
-
const
|
|
16124
|
+
const mainSupportsChar = (char) => doesVariantSupportChar(clean, resolved, actualItalic, char);
|
|
16125
|
+
const hasSymbol = containsSymbol(directText, mainSupportsChar);
|
|
16057
16126
|
if ((hasDevanagari || hasSymbol) && directText.length > 0) {
|
|
16058
16127
|
const devanagariWeight = resolveFontWeight(weight);
|
|
16059
16128
|
const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);
|
|
16060
16129
|
const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400) : jsPdfName;
|
|
16130
|
+
const mathJsPdfName = isFontAvailable(FONT_FALLBACK_MATH) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_MATH, 400) : symbolJsPdfName;
|
|
16061
16131
|
const childNodes = Array.from(el.childNodes);
|
|
16062
16132
|
for (const node of childNodes) {
|
|
16063
16133
|
if (node.nodeType !== 3 || !node.textContent) continue;
|
|
16064
|
-
const runs = splitIntoRuns(node.textContent);
|
|
16134
|
+
const runs = splitIntoRuns(node.textContent, mainSupportsChar);
|
|
16065
16135
|
if (runs.length <= 1 && ((_b = runs[0]) == null ? void 0 : _b.runType) === "main") continue;
|
|
16066
16136
|
const fragment = doc.createDocumentFragment();
|
|
16067
16137
|
for (const run of runs) {
|
|
@@ -16071,6 +16141,8 @@ function rewriteSvgFontsForJsPDF(svgStr) {
|
|
|
16071
16141
|
runFont = devanagariJsPdfName;
|
|
16072
16142
|
} else if (run.runType === "symbol") {
|
|
16073
16143
|
runFont = symbolJsPdfName;
|
|
16144
|
+
} else if (run.runType === "math") {
|
|
16145
|
+
runFont = mathJsPdfName;
|
|
16074
16146
|
} else {
|
|
16075
16147
|
runFont = jsPdfName;
|
|
16076
16148
|
}
|
|
@@ -16177,6 +16249,7 @@ async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
|
|
|
16177
16249
|
const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
16178
16250
|
__proto__: null,
|
|
16179
16251
|
FONT_FALLBACK_DEVANAGARI,
|
|
16252
|
+
FONT_FALLBACK_MATH,
|
|
16180
16253
|
FONT_FALLBACK_SYMBOLS,
|
|
16181
16254
|
FONT_FILES,
|
|
16182
16255
|
FONT_WEIGHT_LABELS,
|
|
@@ -17667,7 +17740,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
17667
17740
|
}
|
|
17668
17741
|
if (shouldOutlineText) {
|
|
17669
17742
|
try {
|
|
17670
|
-
const { convertAllTextToPath } = await import("./svgTextToPath-
|
|
17743
|
+
const { convertAllTextToPath } = await import("./svgTextToPath-CQ2Tp03U.js");
|
|
17671
17744
|
pageSvg = await convertAllTextToPath(pageSvg, fontBaseUrl, { mode: outlineSubMode });
|
|
17672
17745
|
try {
|
|
17673
17746
|
dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-text-to-path-raw");
|
|
@@ -17823,6 +17896,7 @@ function setAutoShrinkDebug(enabled) {
|
|
|
17823
17896
|
}
|
|
17824
17897
|
export {
|
|
17825
17898
|
FONT_FALLBACK_DEVANAGARI,
|
|
17899
|
+
FONT_FALLBACK_MATH,
|
|
17826
17900
|
FONT_FALLBACK_SYMBOLS,
|
|
17827
17901
|
FONT_FILES,
|
|
17828
17902
|
PACKAGE_VERSION,
|