fix: add cjk fallback fonts for psd export
This commit is contained in:
parent
cc01b539bc
commit
59e26064e5
@ -136,6 +136,47 @@ function getFontMimeType(font: AgentPsdFont | undefined, fontFamily: string) {
|
|||||||
return "font/ttf";
|
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: {
|
async function createTextOverlayBuffer(params: {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
@ -192,6 +233,7 @@ async function createTextOverlayBuffer(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const escapedFamily = escapeXml(fontFamily || "sans-serif");
|
const escapedFamily = escapeXml(fontFamily || "sans-serif");
|
||||||
|
const fontFamilyStack = buildSvgFontFamilyStack(fontFamily, normalizedText);
|
||||||
const fontFaceCss = fontBuffer
|
const fontFaceCss = fontBuffer
|
||||||
? `@font-face { font-family: "${escapedFamily}"; src: url("data:${getFontMimeType(font, fontFamily)};base64,${fontBuffer.toString("base64")}"); }`
|
? `@font-face { font-family: "${escapedFamily}"; src: url("data:${getFontMimeType(font, fontFamily)};base64,${fontBuffer.toString("base64")}"); }`
|
||||||
: "";
|
: "";
|
||||||
@ -217,7 +259,7 @@ async function createTextOverlayBuffer(params: {
|
|||||||
<defs>
|
<defs>
|
||||||
<style>
|
<style>
|
||||||
${fontFaceCss}
|
${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>
|
</style>
|
||||||
<clipPath id="${clipId}">
|
<clipPath id="${clipId}">
|
||||||
<rect x="0" y="0" width="${width}" height="${height}" />
|
<rect x="0" y="0" width="${width}" height="${height}" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user