diff --git a/lib/agents/psd-font-runtime.ts b/lib/agents/psd-font-runtime.ts index 9e29c8401..8f8824f50 100644 --- a/lib/agents/psd-font-runtime.ts +++ b/lib/agents/psd-font-runtime.ts @@ -10,7 +10,13 @@ import type { AgentPsdFont } from "@/lib/agents/psd-font-config"; const execFileAsync = promisify(execFile); const ensuredFontCache = new Map< string, - Promise<{ fontFamily: string; installedPath?: string }> + Promise<{ + fontFamily: string; + fontFullName?: string; + fontPostscriptName?: string; + fontStyle?: string; + installedPath?: string; + }> >(); function sanitizeFileSegment(value: string, fallback: string) { @@ -50,7 +56,7 @@ function getRuntimeFontDirectory() { return path.join(process.cwd(), ".next", "cache", "psd-fonts"); } -function parseFontconfigFamily(stdout: string) { +function parseFontconfigToken(stdout: string) { const firstLine = String(stdout || "") .split("\n") .map((line) => line.trim()) @@ -66,6 +72,22 @@ function parseFontconfigFamily(stdout: string) { .find(Boolean) || ""; } +function parseFontScanMetadata(stdout: string) { + const [fullName = "", family = "", style = "", postscriptName = ""] = String(stdout || "") + .split("\n") + .map((line) => line.trim()) + .find(Boolean) + ?.split("|") + .map((item) => item.trim()) || []; + + return { + fontFullName: fullName || undefined, + fontFamily: family || fullName || "", + fontStyle: style || undefined, + fontPostscriptName: postscriptName || undefined, + }; +} + async function ensureWritableFontFile(targetPath: string, fontBuffer: Buffer) { const existingFile = await fs.stat(targetPath).catch(() => null); if (existingFile && existingFile.size === fontBuffer.byteLength) { @@ -82,12 +104,34 @@ async function detectInstalledFontFamily(targetPath: string, fallbackFamily: str ["--format=%{family}\n", targetPath], { timeout: 15_000 } ); - return parseFontconfigFamily(stdout) || fallbackFamily; + return parseFontconfigToken(stdout) || fallbackFamily; } catch { return fallbackFamily; } } +async function detectInstalledFontMetadata(targetPath: string, fallbackFamily: string) { + try { + const { stdout } = await execFileAsync( + "fc-scan", + ["--format=%{fullname[0]}|%{family[0]}|%{style[0]}|%{postscriptname}\n", targetPath], + { timeout: 15_000 } + ); + const metadata = parseFontScanMetadata(stdout); + return { + ...metadata, + fontFamily: metadata.fontFamily || fallbackFamily, + }; + } catch { + return { + fontFamily: await detectInstalledFontFamily(targetPath, fallbackFamily), + fontFullName: undefined, + fontStyle: undefined, + fontPostscriptName: undefined, + }; + } +} + async function refreshFontCache(fontDirectory: string) { try { await execFileAsync("fc-cache", ["-f", fontDirectory], { timeout: 20_000 }); @@ -122,9 +166,10 @@ export async function ensurePsdFontAvailableForRender(params: { await ensureWritableFontFile(targetPath, fontBuffer); await refreshFontCache(fontDirectory); + const metadata = await detectInstalledFontMetadata(targetPath, fallbackFamily); return { - fontFamily: await detectInstalledFontFamily(targetPath, fallbackFamily), + ...metadata, installedPath: targetPath, }; })() diff --git a/lib/agents/psd-template-renderer.ts b/lib/agents/psd-template-renderer.ts index 831c8d28e..f0ad8c3bb 100644 --- a/lib/agents/psd-template-renderer.ts +++ b/lib/agents/psd-template-renderer.ts @@ -187,7 +187,9 @@ async function createTextOverlayBuffer(params: { fontBuffer?: Buffer; font: AgentPsdFont | undefined; fontFamily: string; + renderFontFamilies?: string[]; renderFontFamily?: string; + useExactFontFace?: boolean; fontSize: number; fontWeight: number; lineHeight: number; @@ -205,7 +207,9 @@ async function createTextOverlayBuffer(params: { fontBuffer, font, fontFamily, + renderFontFamilies, renderFontFamily, + useExactFontFace, fontSize, fontWeight, lineHeight, @@ -239,7 +243,7 @@ async function createTextOverlayBuffer(params: { const primaryFamilies = Array.from( new Set( - [renderFontFamily, fontFamily] + [...(renderFontFamilies || []), renderFontFamily, fontFamily] .map((family) => String(family || "").trim()) .filter(Boolean) ) @@ -275,7 +279,7 @@ async function createTextOverlayBuffer(params: { @@ -432,7 +436,15 @@ export async function renderAgentPsdTemplate(params: { fontBuffer, font, fontFamily: layer.fontFamily || font?.family || "sans-serif", + renderFontFamilies: runtimeFont + ? [ + runtimeFont.fontPostscriptName, + runtimeFont.fontFullName, + runtimeFont.fontFamily, + ].filter((value): value is string => Boolean(String(value || "").trim())) + : undefined, renderFontFamily: runtimeFont?.fontFamily, + useExactFontFace: Boolean(runtimeFont?.fontPostscriptName || runtimeFont?.fontFullName), fontSize: layer.fontSize, fontWeight: layer.fontWeight, lineHeight: layer.lineHeight,