fix: add cjk fallback fonts for psd export
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-31 18:25:15 +08:00
parent cc01b539bc
commit 59e26064e5

View File

@ -136,6 +136,47 @@ function getFontMimeType(font: AgentPsdFont | undefined, fontFamily: string) {
return "font/ttf";
}
const GENERIC_FONT_FAMILIES = new Set(["sans-serif", "serif", "monospace", "cursive", "fantasy", "system-ui"]);
const CJK_FALLBACK_FONT_FAMILIES = [
"Noto Sans CJK SC",
"Noto Sans SC",
"Source Han Sans SC",
"Microsoft YaHei",
"PingFang SC",
"Hiragino Sans GB",
"WenQuanYi Zen Hei",
"SimHei",
"Arial Unicode MS",
"sans-serif",
] as const;
function textContainsCjkGlyphs(value: string) {
return /[\u3400-\u9fff\u3040-\u30ff\uac00-\ud7af]/.test(String(value || ""));
}
function buildSvgFontFamilyStack(fontFamily: string, text: string) {
const familyTokens = new Set<string>();
const primaryFamily = String(fontFamily || "").trim();
if (primaryFamily) {
familyTokens.add(primaryFamily);
}
if (textContainsCjkGlyphs(text)) {
for (const fallbackFamily of CJK_FALLBACK_FONT_FAMILIES) {
familyTokens.add(fallbackFamily);
}
} else {
familyTokens.add("sans-serif");
}
return Array.from(familyTokens)
.map((family) =>
GENERIC_FONT_FAMILIES.has(family) ? family : `"${escapeXml(family)}"`
)
.join(", ");
}
async function createTextOverlayBuffer(params: {
width: number;
height: number;
@ -192,6 +233,7 @@ async function createTextOverlayBuffer(params: {
}
const escapedFamily = escapeXml(fontFamily || "sans-serif");
const fontFamilyStack = buildSvgFontFamilyStack(fontFamily, normalizedText);
const fontFaceCss = fontBuffer
? `@font-face { font-family: "${escapedFamily}"; src: url("data:${getFontMimeType(font, fontFamily)};base64,${fontBuffer.toString("base64")}"); }`
: "";
@ -217,7 +259,7 @@ async function createTextOverlayBuffer(params: {
<defs>
<style>
${fontFaceCss}
.text { font-family: "${escapedFamily}", sans-serif; font-size: ${adjustedFontSize}px; font-weight: ${fontWeight}; fill: ${textColor}; letter-spacing: ${letterSpacing}px; }
.text { font-family: ${fontFamilyStack}; font-size: ${adjustedFontSize}px; font-weight: ${fontWeight}; fill: ${textColor}; letter-spacing: ${letterSpacing}px; }
</style>
<clipPath id="${clipId}">
<rect x="0" y="0" width="${width}" height="${height}" />