@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 CHANGED
@@ -11900,8 +11900,47 @@ async function embedFontsForConfig(pdf, config, fontBaseUrl) {
11900
11900
  console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);
11901
11901
  return embedded;
11902
11902
  }
11903
+ function isDevanagari(char) {
11904
+ const c = char.codePointAt(0) ?? 0;
11905
+ return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
11906
+ }
11907
+ function containsDevanagari(text) {
11908
+ if (!text) return false;
11909
+ for (const char of text) {
11910
+ if (isDevanagari(char)) return true;
11911
+ }
11912
+ return false;
11913
+ }
11914
+ function isBasicLatinOrLatin1(char) {
11915
+ const c = char.codePointAt(0) ?? 0;
11916
+ return c <= 591;
11917
+ }
11918
+ function classifyChar(char) {
11919
+ if (isBasicLatinOrLatin1(char)) return "main";
11920
+ if (isDevanagari(char)) return "devanagari";
11921
+ return "symbol";
11922
+ }
11923
+ function splitIntoRuns(text) {
11924
+ if (!text) return [];
11925
+ const runs = [];
11926
+ let currentType = null;
11927
+ let currentText = "";
11928
+ for (const char of text) {
11929
+ const type = classifyChar(char);
11930
+ if (type !== currentType && currentText) {
11931
+ runs.push({ text: currentText, runType: currentType });
11932
+ currentText = "";
11933
+ }
11934
+ currentType = type;
11935
+ currentText += char;
11936
+ }
11937
+ if (currentText && currentType) {
11938
+ runs.push({ text: currentText, runType: currentType });
11939
+ }
11940
+ return runs;
11941
+ }
11903
11942
  function rewriteSvgFontsForJsPDF(svgStr) {
11904
- var _a;
11943
+ var _a, _b;
11905
11944
  const parser = new DOMParser();
11906
11945
  const doc = parser.parseFromString(svgStr, "image/svg+xml");
11907
11946
  const textEls = doc.querySelectorAll("text, tspan, textPath");
@@ -11922,6 +11961,17 @@ function rewriteSvgFontsForJsPDF(svgStr) {
11922
11961
  }
11923
11962
  return null;
11924
11963
  };
11964
+ const resolveWeightNum = (weightRaw) => {
11965
+ const parsedWeight = Number.parseInt(weightRaw, 10);
11966
+ 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;
11967
+ };
11968
+ const buildStyleString = (existingStyle, fontName) => {
11969
+ 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));
11970
+ stylePairs.push(`font-family: ${fontName}`);
11971
+ stylePairs.push(`font-weight: normal`);
11972
+ stylePairs.push(`font-style: normal`);
11973
+ return stylePairs.join("; ");
11974
+ };
11925
11975
  for (const el of textEls) {
11926
11976
  const inlineStyle = el.getAttribute("style") || "";
11927
11977
  const rawFf = resolveInheritedValue(el, "font-family");
@@ -11930,19 +11980,50 @@ function rewriteSvgFontsForJsPDF(svgStr) {
11930
11980
  if (!isFontAvailable(clean)) continue;
11931
11981
  const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
11932
11982
  const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
11933
- const parsedWeight = Number.parseInt(weightRaw, 10);
11934
- 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;
11983
+ const weight = resolveWeightNum(weightRaw);
11935
11984
  const resolved = resolveFontWeight(weight);
11936
11985
  const isItalic = /italic|oblique/i.test(styleRaw);
11937
11986
  const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
11938
- el.setAttribute("font-family", jsPdfName);
11939
- el.setAttribute("font-weight", "normal");
11940
- el.setAttribute("font-style", "normal");
11941
- const stylePairs = inlineStyle.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));
11942
- stylePairs.push(`font-family: ${jsPdfName}`);
11943
- stylePairs.push(`font-weight: normal`);
11944
- stylePairs.push(`font-style: normal`);
11945
- el.setAttribute("style", stylePairs.join("; "));
11987
+ const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
11988
+ const hasDevanagari = containsDevanagari(directText);
11989
+ if (hasDevanagari && directText.length > 0) {
11990
+ const devanagariWeight = resolveFontWeight(weight);
11991
+ const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);
11992
+ const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400) : jsPdfName;
11993
+ const childNodes = Array.from(el.childNodes);
11994
+ for (const node of childNodes) {
11995
+ if (node.nodeType !== 3 || !node.textContent) continue;
11996
+ const runs = splitIntoRuns(node.textContent);
11997
+ if (runs.length <= 1 && ((_b = runs[0]) == null ? void 0 : _b.runType) !== "devanagari") continue;
11998
+ const fragment = doc.createDocumentFragment();
11999
+ for (const run of runs) {
12000
+ const tspan = doc.createElementNS("http://www.w3.org/2000/svg", "tspan");
12001
+ let runFont;
12002
+ if (run.runType === "devanagari") {
12003
+ runFont = devanagariJsPdfName;
12004
+ } else if (run.runType === "symbol") {
12005
+ runFont = symbolJsPdfName;
12006
+ } else {
12007
+ runFont = jsPdfName;
12008
+ }
12009
+ tspan.setAttribute("font-family", runFont);
12010
+ tspan.setAttribute("font-weight", "normal");
12011
+ tspan.setAttribute("font-style", "normal");
12012
+ tspan.textContent = run.text;
12013
+ fragment.appendChild(tspan);
12014
+ }
12015
+ el.replaceChild(fragment, node);
12016
+ }
12017
+ el.setAttribute("font-family", jsPdfName);
12018
+ el.setAttribute("font-weight", "normal");
12019
+ el.setAttribute("font-style", "normal");
12020
+ el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
12021
+ } else {
12022
+ el.setAttribute("font-family", jsPdfName);
12023
+ el.setAttribute("font-weight", "normal");
12024
+ el.setAttribute("font-style", "normal");
12025
+ el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
12026
+ }
11946
12027
  }
11947
12028
  return new XMLSerializer().serializeToString(doc.documentElement);
11948
12029
  }