@pixldocs/canvas-renderer 0.5.96 → 0.5.98
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 +173 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +173 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -256,7 +256,7 @@ export declare function normalizeFontFamily(fontStack: string): string;
|
|
|
256
256
|
* Package version banner. Bump alongside package.json so we can confirm
|
|
257
257
|
* (via browser:log) that the deployed bundle matches the expected build.
|
|
258
258
|
*/
|
|
259
|
-
export declare const PACKAGE_VERSION = "0.5.
|
|
259
|
+
export declare const PACKAGE_VERSION = "0.5.98";
|
|
260
260
|
|
|
261
261
|
export declare interface PageSettings {
|
|
262
262
|
backgroundColor?: string;
|
package/dist/index.js
CHANGED
|
@@ -13084,7 +13084,7 @@ function PixldocsPreview(props) {
|
|
|
13084
13084
|
!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..." }) })
|
|
13085
13085
|
] });
|
|
13086
13086
|
}
|
|
13087
|
-
const PACKAGE_VERSION = "0.5.
|
|
13087
|
+
const PACKAGE_VERSION = "0.5.98";
|
|
13088
13088
|
const roundParityValue = (value) => {
|
|
13089
13089
|
if (typeof value !== "number") return value;
|
|
13090
13090
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -14045,6 +14045,7 @@ class PixldocsRenderer {
|
|
|
14045
14045
|
this.logFabricTextParitySnapshot("after-stable-text-metrics", fabricInstance);
|
|
14046
14046
|
}
|
|
14047
14047
|
}
|
|
14048
|
+
const __vite_import_meta_env__ = {};
|
|
14048
14049
|
const FONT_WEIGHT_LABELS = {
|
|
14049
14050
|
300: "Light",
|
|
14050
14051
|
400: "Regular",
|
|
@@ -14581,6 +14582,10 @@ function getEmbeddedJsPDFFontName(fontName, weight, isItalic = false) {
|
|
|
14581
14582
|
function isFontAvailable(fontName) {
|
|
14582
14583
|
return fontName in FONT_FILES;
|
|
14583
14584
|
}
|
|
14585
|
+
const registeredFamilies = /* @__PURE__ */ new Set();
|
|
14586
|
+
function isFamilyEmbedded(family) {
|
|
14587
|
+
return registeredFamilies.has(family);
|
|
14588
|
+
}
|
|
14584
14589
|
const ttfCache = /* @__PURE__ */ new Map();
|
|
14585
14590
|
async function fetchTTFAsBase64(url) {
|
|
14586
14591
|
const cached = ttfCache.get(url);
|
|
@@ -14653,12 +14658,165 @@ async function embedFont(pdf, fontName, weight, fontBaseUrl, isItalic = false) {
|
|
|
14653
14658
|
} catch {
|
|
14654
14659
|
}
|
|
14655
14660
|
}
|
|
14661
|
+
registeredFamilies.add(fontName);
|
|
14656
14662
|
return true;
|
|
14657
14663
|
} catch (e) {
|
|
14658
14664
|
console.warn(`[pdf-fonts] Failed to embed ${fontName} w${weight}:`, e);
|
|
14659
14665
|
return false;
|
|
14660
14666
|
}
|
|
14661
14667
|
}
|
|
14668
|
+
const googleFontNotFound = /* @__PURE__ */ new Set();
|
|
14669
|
+
const fontshareNotFound = /* @__PURE__ */ new Set();
|
|
14670
|
+
function bytesToBase64(bytes) {
|
|
14671
|
+
let binary = "";
|
|
14672
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
14673
|
+
return btoa(binary);
|
|
14674
|
+
}
|
|
14675
|
+
function getFontProxyUrl() {
|
|
14676
|
+
var _a;
|
|
14677
|
+
const viteUrl = (__vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_SUPABASE_URL) || "";
|
|
14678
|
+
const runtimeUrl = typeof globalThis !== "undefined" ? ((_a = globalThis.__CONFIG__) == null ? void 0 : _a.supabaseUrl) || globalThis.__PIXLDOCS_SUPABASE_URL || "" : "";
|
|
14679
|
+
const baseUrl = (viteUrl || runtimeUrl || "").replace(/\/$/, "");
|
|
14680
|
+
return baseUrl ? `${baseUrl}/functions/v1/font-proxy` : null;
|
|
14681
|
+
}
|
|
14682
|
+
async function fetchTtfViaProxy(family, weight, isItalic, source) {
|
|
14683
|
+
const proxyUrl = getFontProxyUrl();
|
|
14684
|
+
if (!proxyUrl) return null;
|
|
14685
|
+
try {
|
|
14686
|
+
const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;
|
|
14687
|
+
const res = await fetch(url);
|
|
14688
|
+
if (!res.ok) return null;
|
|
14689
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
14690
|
+
return isJsPdfEmbeddableTrueType(bytes) ? bytes : null;
|
|
14691
|
+
} catch {
|
|
14692
|
+
return null;
|
|
14693
|
+
}
|
|
14694
|
+
}
|
|
14695
|
+
async function fetchGoogleFontTTF(fontFamily, weight, isItalic = false) {
|
|
14696
|
+
const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
14697
|
+
if (ttfCache.has(cacheKey)) return ttfCache.get(cacheKey);
|
|
14698
|
+
if (googleFontNotFound.has(fontFamily)) return null;
|
|
14699
|
+
const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "google");
|
|
14700
|
+
if (proxyBytes) {
|
|
14701
|
+
const b64 = bytesToBase64(proxyBytes);
|
|
14702
|
+
ttfCache.set(cacheKey, b64);
|
|
14703
|
+
return b64;
|
|
14704
|
+
}
|
|
14705
|
+
try {
|
|
14706
|
+
const ital = isItalic ? "1" : "0";
|
|
14707
|
+
const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(
|
|
14708
|
+
fontFamily
|
|
14709
|
+
)}:ital,wght@${ital},${weight}&display=swap`;
|
|
14710
|
+
const cssRes = await fetch(cssUrl, {
|
|
14711
|
+
headers: {
|
|
14712
|
+
"User-Agent": "Mozilla/5.0 (Linux; U; Android 2.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko)"
|
|
14713
|
+
}
|
|
14714
|
+
});
|
|
14715
|
+
if (!cssRes.ok) {
|
|
14716
|
+
if (cssRes.status === 400 || cssRes.status === 404) googleFontNotFound.add(fontFamily);
|
|
14717
|
+
return null;
|
|
14718
|
+
}
|
|
14719
|
+
const css = await cssRes.text();
|
|
14720
|
+
const urlMatch = css.match(/url\(([^)]+)\)\s+format\(['"]?truetype['"]?\)/i) || css.match(/url\(([^)]+)\)/);
|
|
14721
|
+
if (!urlMatch) return null;
|
|
14722
|
+
const ttfUrl = urlMatch[1].replace(/['"]/g, "");
|
|
14723
|
+
const ttfRes = await fetch(ttfUrl);
|
|
14724
|
+
if (!ttfRes.ok) return null;
|
|
14725
|
+
const buf = await ttfRes.arrayBuffer();
|
|
14726
|
+
const bytes = new Uint8Array(buf);
|
|
14727
|
+
if (!isJsPdfEmbeddableTrueType(bytes)) {
|
|
14728
|
+
console.warn(`[pdf-fonts] Google Fonts returned a non-TTF for ${fontFamily} (${weight}); skipping`);
|
|
14729
|
+
return null;
|
|
14730
|
+
}
|
|
14731
|
+
const b64 = bytesToBase64(bytes);
|
|
14732
|
+
ttfCache.set(cacheKey, b64);
|
|
14733
|
+
return b64;
|
|
14734
|
+
} catch (err) {
|
|
14735
|
+
console.warn(`[pdf-fonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);
|
|
14736
|
+
return null;
|
|
14737
|
+
}
|
|
14738
|
+
}
|
|
14739
|
+
async function fetchFontshareTTF(fontFamily, weight, isItalic = false) {
|
|
14740
|
+
const cacheKey = `fs:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
|
|
14741
|
+
if (ttfCache.has(cacheKey)) return ttfCache.get(cacheKey);
|
|
14742
|
+
if (fontshareNotFound.has(fontFamily)) return null;
|
|
14743
|
+
const slug = fontFamily.trim().toLowerCase().replace(/\s+/g, "-");
|
|
14744
|
+
const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "fontshare");
|
|
14745
|
+
if (proxyBytes) {
|
|
14746
|
+
const b64 = bytesToBase64(proxyBytes);
|
|
14747
|
+
ttfCache.set(cacheKey, b64);
|
|
14748
|
+
return b64;
|
|
14749
|
+
}
|
|
14750
|
+
try {
|
|
14751
|
+
const styleSuffix = isItalic ? "i" : "";
|
|
14752
|
+
const cssUrl = `https://api.fontshare.com/v2/css?f[]=${slug}@${weight}${styleSuffix}&display=swap`;
|
|
14753
|
+
const cssRes = await fetch(cssUrl);
|
|
14754
|
+
if (!cssRes.ok) {
|
|
14755
|
+
if (cssRes.status === 400 || cssRes.status === 404) fontshareNotFound.add(fontFamily);
|
|
14756
|
+
return null;
|
|
14757
|
+
}
|
|
14758
|
+
const css = await cssRes.text();
|
|
14759
|
+
const ttMatch = css.match(/url\(([^)]+)\)\s+format\(['"]?truetype['"]?\)/i);
|
|
14760
|
+
if (!ttMatch) {
|
|
14761
|
+
fontshareNotFound.add(fontFamily);
|
|
14762
|
+
return null;
|
|
14763
|
+
}
|
|
14764
|
+
let ttfUrl = ttMatch[1].replace(/['"]/g, "").trim();
|
|
14765
|
+
if (ttfUrl.startsWith("//")) ttfUrl = `https:${ttfUrl}`;
|
|
14766
|
+
const ttfRes = await fetch(ttfUrl);
|
|
14767
|
+
if (!ttfRes.ok) return null;
|
|
14768
|
+
const buf = await ttfRes.arrayBuffer();
|
|
14769
|
+
const bytes = new Uint8Array(buf);
|
|
14770
|
+
if (!isJsPdfEmbeddableTrueType(bytes)) return null;
|
|
14771
|
+
const b64 = bytesToBase64(bytes);
|
|
14772
|
+
ttfCache.set(cacheKey, b64);
|
|
14773
|
+
return b64;
|
|
14774
|
+
} catch (err) {
|
|
14775
|
+
console.warn(`[pdf-fonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);
|
|
14776
|
+
return null;
|
|
14777
|
+
}
|
|
14778
|
+
}
|
|
14779
|
+
function registerJsPdfFont(pdf, fontName, resolvedWeight, isItalic, base64) {
|
|
14780
|
+
const label = FONT_WEIGHT_LABELS[resolvedWeight];
|
|
14781
|
+
const italicSuffix = isItalic ? "Italic" : "";
|
|
14782
|
+
const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);
|
|
14783
|
+
const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
|
|
14784
|
+
try {
|
|
14785
|
+
pdf.addFileToVFS(fileName, base64);
|
|
14786
|
+
pdf.addFont(fileName, jsPdfFontName, "normal");
|
|
14787
|
+
if (fontName !== jsPdfFontName) {
|
|
14788
|
+
try {
|
|
14789
|
+
pdf.addFont(fileName, fontName, "normal");
|
|
14790
|
+
} catch {
|
|
14791
|
+
}
|
|
14792
|
+
}
|
|
14793
|
+
registeredFamilies.add(fontName);
|
|
14794
|
+
return true;
|
|
14795
|
+
} catch (err) {
|
|
14796
|
+
console.warn(`[pdf-fonts] registerJsPdfFont failed for ${fontName}:`, err);
|
|
14797
|
+
return false;
|
|
14798
|
+
}
|
|
14799
|
+
}
|
|
14800
|
+
async function embedFontWithGoogleFallback(pdf, fontName, weight = 400, fontBaseUrl, isItalic = false) {
|
|
14801
|
+
if (FONT_FILES[fontName]) {
|
|
14802
|
+
const ok = await embedFont(pdf, fontName, weight, fontBaseUrl, isItalic);
|
|
14803
|
+
if (ok) return true;
|
|
14804
|
+
}
|
|
14805
|
+
const resolved = resolveFontWeight(weight);
|
|
14806
|
+
const fsB64 = await fetchFontshareTTF(fontName, resolved, isItalic);
|
|
14807
|
+
if (fsB64) return registerJsPdfFont(pdf, fontName, resolved, isItalic, fsB64);
|
|
14808
|
+
if (isItalic) {
|
|
14809
|
+
const fsUpright = await fetchFontshareTTF(fontName, resolved, false);
|
|
14810
|
+
if (fsUpright) return registerJsPdfFont(pdf, fontName, resolved, isItalic, fsUpright);
|
|
14811
|
+
}
|
|
14812
|
+
const b64 = await fetchGoogleFontTTF(fontName, resolved, isItalic);
|
|
14813
|
+
if (b64) return registerJsPdfFont(pdf, fontName, resolved, isItalic, b64);
|
|
14814
|
+
if (isItalic) {
|
|
14815
|
+
const uprightB64 = await fetchGoogleFontTTF(fontName, resolved, false);
|
|
14816
|
+
if (uprightB64) return registerJsPdfFont(pdf, fontName, resolved, isItalic, uprightB64);
|
|
14817
|
+
}
|
|
14818
|
+
return false;
|
|
14819
|
+
}
|
|
14662
14820
|
async function embedFontsForConfig(pdf, config, fontBaseUrl) {
|
|
14663
14821
|
const fontKeys = /* @__PURE__ */ new Set();
|
|
14664
14822
|
const SEP = "";
|
|
@@ -14817,7 +14975,7 @@ function rewriteSvgFontsForJsPDF(svgStr) {
|
|
|
14817
14975
|
const rawFf = resolveInheritedValue(el, "font-family");
|
|
14818
14976
|
if (!rawFf) continue;
|
|
14819
14977
|
const clean = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
|
|
14820
|
-
if (!isFontAvailable(clean)) continue;
|
|
14978
|
+
if (!isFontAvailable(clean) && !isFamilyEmbedded(clean)) continue;
|
|
14821
14979
|
const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
|
|
14822
14980
|
const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
|
|
14823
14981
|
const weight = resolveWeightNum(weightRaw);
|
|
@@ -14900,14 +15058,19 @@ async function embedFontsInPdf(pdf, fontFamilies, fontBaseUrl) {
|
|
|
14900
15058
|
fontFamilies.add(FONT_FALLBACK_SYMBOLS);
|
|
14901
15059
|
fontFamilies.add(FONT_FALLBACK_DEVANAGARI);
|
|
14902
15060
|
for (const family of fontFamilies) {
|
|
14903
|
-
if (
|
|
14904
|
-
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
15061
|
+
if (isFontAvailable(family)) {
|
|
15062
|
+
for (const w of weights) {
|
|
15063
|
+
tasks.push(
|
|
15064
|
+
embedFont(pdf, family, w, fontBaseUrl).then((ok) => {
|
|
15065
|
+
if (ok) embedded.add(`${family}${w}`);
|
|
15066
|
+
})
|
|
15067
|
+
);
|
|
15068
|
+
}
|
|
15069
|
+
} else {
|
|
14908
15070
|
tasks.push(
|
|
14909
|
-
|
|
14910
|
-
if (ok) embedded.add(`${family}
|
|
15071
|
+
embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, false).then((ok) => {
|
|
15072
|
+
if (ok) embedded.add(`${family}400`);
|
|
15073
|
+
else console.warn(`[pdf-fonts] No TTF (local/Google/Fontshare) for "${family}" — will use Helvetica fallback`);
|
|
14911
15074
|
})
|
|
14912
15075
|
);
|
|
14913
15076
|
}
|
|
@@ -14923,6 +15086,7 @@ const pdfFonts = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
|
|
|
14923
15086
|
FONT_FILES,
|
|
14924
15087
|
FONT_WEIGHT_LABELS,
|
|
14925
15088
|
embedFont,
|
|
15089
|
+
embedFontWithGoogleFallback,
|
|
14926
15090
|
embedFontsForConfig,
|
|
14927
15091
|
embedFontsInPdf,
|
|
14928
15092
|
extractFontFamiliesFromSvgs,
|