@pixldocs/canvas-renderer 0.4.4 → 0.4.6
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 +92 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +92 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -437,6 +437,9 @@ export declare function resolveTemplateData(options: ResolveOptions): Promise<Re
|
|
|
437
437
|
* CRITICAL: Also sets font-weight to "normal" because the weight is already baked into
|
|
438
438
|
* the jsPDF font name (e.g. JosefinSans-SemiBold). Without this, svg2pdf combines
|
|
439
439
|
* font-weight + font-style into "600normal" which won't match fonts registered with style "normal".
|
|
440
|
+
*
|
|
441
|
+
* For Devanagari text: splits <tspan> elements containing mixed scripts into separate
|
|
442
|
+
* <tspan> children — Latin runs use the original font, Devanagari runs use FONT_FALLBACK_DEVANAGARI.
|
|
440
443
|
*/
|
|
441
444
|
export declare function rewriteSvgFontsForJsPDF(svgStr: string): string;
|
|
442
445
|
|
package/dist/index.js
CHANGED
|
@@ -11881,8 +11881,47 @@ async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
|
11881
11881
|
console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);
|
|
11882
11882
|
return embedded;
|
|
11883
11883
|
}
|
|
11884
|
+
function isDevanagari(char) {
|
|
11885
|
+
const c = char.codePointAt(0) ?? 0;
|
|
11886
|
+
return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
|
|
11887
|
+
}
|
|
11888
|
+
function containsDevanagari(text) {
|
|
11889
|
+
if (!text) return false;
|
|
11890
|
+
for (const char of text) {
|
|
11891
|
+
if (isDevanagari(char)) return true;
|
|
11892
|
+
}
|
|
11893
|
+
return false;
|
|
11894
|
+
}
|
|
11895
|
+
function isBasicLatinOrLatin1(char) {
|
|
11896
|
+
const c = char.codePointAt(0) ?? 0;
|
|
11897
|
+
return c <= 591;
|
|
11898
|
+
}
|
|
11899
|
+
function classifyChar(char) {
|
|
11900
|
+
if (isBasicLatinOrLatin1(char)) return "main";
|
|
11901
|
+
if (isDevanagari(char)) return "devanagari";
|
|
11902
|
+
return "symbol";
|
|
11903
|
+
}
|
|
11904
|
+
function splitIntoRuns(text) {
|
|
11905
|
+
if (!text) return [];
|
|
11906
|
+
const runs = [];
|
|
11907
|
+
let currentType = null;
|
|
11908
|
+
let currentText = "";
|
|
11909
|
+
for (const char of text) {
|
|
11910
|
+
const type = classifyChar(char);
|
|
11911
|
+
if (type !== currentType && currentText) {
|
|
11912
|
+
runs.push({ text: currentText, runType: currentType });
|
|
11913
|
+
currentText = "";
|
|
11914
|
+
}
|
|
11915
|
+
currentType = type;
|
|
11916
|
+
currentText += char;
|
|
11917
|
+
}
|
|
11918
|
+
if (currentText && currentType) {
|
|
11919
|
+
runs.push({ text: currentText, runType: currentType });
|
|
11920
|
+
}
|
|
11921
|
+
return runs;
|
|
11922
|
+
}
|
|
11884
11923
|
function rewriteSvgFontsForJsPDF(svgStr) {
|
|
11885
|
-
var _a;
|
|
11924
|
+
var _a, _b;
|
|
11886
11925
|
const parser = new DOMParser();
|
|
11887
11926
|
const doc = parser.parseFromString(svgStr, "image/svg+xml");
|
|
11888
11927
|
const textEls = doc.querySelectorAll("text, tspan, textPath");
|
|
@@ -11903,6 +11942,17 @@ function rewriteSvgFontsForJsPDF(svgStr) {
|
|
|
11903
11942
|
}
|
|
11904
11943
|
return null;
|
|
11905
11944
|
};
|
|
11945
|
+
const resolveWeightNum = (weightRaw) => {
|
|
11946
|
+
const parsedWeight = Number.parseInt(weightRaw, 10);
|
|
11947
|
+
return Number.isFinite(parsedWeight) ? parsedWeight : /bold/i.test(weightRaw) ? 700 : /medium/i.test(weightRaw) ? 500 : /semi/i.test(weightRaw) ? 600 : /light/i.test(weightRaw) ? 300 : 400;
|
|
11948
|
+
};
|
|
11949
|
+
const buildStyleString = (existingStyle, fontName) => {
|
|
11950
|
+
const stylePairs = existingStyle.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^font-family\s*:/i.test(part) && !/^font-weight\s*:/i.test(part) && !/^font-style\s*:/i.test(part));
|
|
11951
|
+
stylePairs.push(`font-family: ${fontName}`);
|
|
11952
|
+
stylePairs.push(`font-weight: normal`);
|
|
11953
|
+
stylePairs.push(`font-style: normal`);
|
|
11954
|
+
return stylePairs.join("; ");
|
|
11955
|
+
};
|
|
11906
11956
|
for (const el of textEls) {
|
|
11907
11957
|
const inlineStyle = el.getAttribute("style") || "";
|
|
11908
11958
|
const rawFf = resolveInheritedValue(el, "font-family");
|
|
@@ -11911,19 +11961,50 @@ function rewriteSvgFontsForJsPDF(svgStr) {
|
|
|
11911
11961
|
if (!isFontAvailable(clean)) continue;
|
|
11912
11962
|
const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
|
|
11913
11963
|
const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
|
|
11914
|
-
const
|
|
11915
|
-
const weight = Number.isFinite(parsedWeight) ? parsedWeight : /bold/i.test(weightRaw) ? 700 : /medium/i.test(weightRaw) ? 500 : /semi/i.test(weightRaw) ? 600 : /light/i.test(weightRaw) ? 300 : 400;
|
|
11964
|
+
const weight = resolveWeightNum(weightRaw);
|
|
11916
11965
|
const resolved = resolveFontWeight(weight);
|
|
11917
11966
|
const isItalic = /italic|oblique/i.test(styleRaw);
|
|
11918
11967
|
const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
|
|
11919
|
-
el.
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11968
|
+
const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
|
|
11969
|
+
const hasDevanagari = containsDevanagari(directText);
|
|
11970
|
+
if (hasDevanagari && directText.length > 0) {
|
|
11971
|
+
const devanagariWeight = resolveFontWeight(weight);
|
|
11972
|
+
const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);
|
|
11973
|
+
const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400) : jsPdfName;
|
|
11974
|
+
const childNodes = Array.from(el.childNodes);
|
|
11975
|
+
for (const node of childNodes) {
|
|
11976
|
+
if (node.nodeType !== 3 || !node.textContent) continue;
|
|
11977
|
+
const runs = splitIntoRuns(node.textContent);
|
|
11978
|
+
if (runs.length <= 1 && ((_b = runs[0]) == null ? void 0 : _b.runType) !== "devanagari") continue;
|
|
11979
|
+
const fragment = doc.createDocumentFragment();
|
|
11980
|
+
for (const run of runs) {
|
|
11981
|
+
const tspan = doc.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
|
11982
|
+
let runFont;
|
|
11983
|
+
if (run.runType === "devanagari") {
|
|
11984
|
+
runFont = devanagariJsPdfName;
|
|
11985
|
+
} else if (run.runType === "symbol") {
|
|
11986
|
+
runFont = symbolJsPdfName;
|
|
11987
|
+
} else {
|
|
11988
|
+
runFont = jsPdfName;
|
|
11989
|
+
}
|
|
11990
|
+
tspan.setAttribute("font-family", runFont);
|
|
11991
|
+
tspan.setAttribute("font-weight", "normal");
|
|
11992
|
+
tspan.setAttribute("font-style", "normal");
|
|
11993
|
+
tspan.textContent = run.text;
|
|
11994
|
+
fragment.appendChild(tspan);
|
|
11995
|
+
}
|
|
11996
|
+
el.replaceChild(fragment, node);
|
|
11997
|
+
}
|
|
11998
|
+
el.setAttribute("font-family", jsPdfName);
|
|
11999
|
+
el.setAttribute("font-weight", "normal");
|
|
12000
|
+
el.setAttribute("font-style", "normal");
|
|
12001
|
+
el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
|
|
12002
|
+
} else {
|
|
12003
|
+
el.setAttribute("font-family", jsPdfName);
|
|
12004
|
+
el.setAttribute("font-weight", "normal");
|
|
12005
|
+
el.setAttribute("font-style", "normal");
|
|
12006
|
+
el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
|
|
12007
|
+
}
|
|
11927
12008
|
}
|
|
11928
12009
|
return new XMLSerializer().serializeToString(doc.documentElement);
|
|
11929
12010
|
}
|