@pixldocs/canvas-renderer 0.5.110 → 0.5.112
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 +82 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +82 -8
- package/dist/index.js.map +1 -1
- package/dist/svgTextToPath-4Y_THSBg.cjs.map +1 -1
- package/dist/svgTextToPath-CQ2Tp03U.js.map +1 -1
- package/package.json +1 -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
|
|
package/dist/index.js
CHANGED
|
@@ -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,
|
|
@@ -17653,7 +17726,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
17653
17726
|
const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
|
|
17654
17727
|
drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
|
|
17655
17728
|
const shouldStripBg = stripPageBackground ?? hasGradient;
|
|
17656
|
-
const textMode = options.textMode ?? (options.outlineText ===
|
|
17729
|
+
const textMode = options.textMode ?? (options.outlineText === true ? "pixel-perfect" : "selectable");
|
|
17657
17730
|
const shouldOutlineText = textMode === "pixel-perfect" || textMode === "auto";
|
|
17658
17731
|
const outlineSubMode = textMode === "auto" ? "complex-only" : "all";
|
|
17659
17732
|
let pageSvg = page.svg;
|
|
@@ -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,
|