Files
newapi-dashboard/server/utils/font.ts

67 lines
2.2 KiB
TypeScript

import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const FONTS_DIR = path.join(__dirname, '..', 'fonts')
const FONT_FILE = path.join(FONTS_DIR, 'NotoSansSC-Regular.otf')
const CDN_URLS = [
'https://cdn.jsdelivr.net/gh/googlefonts/noto-cjk@main/Sans/SubsetOTF/SC/NotoSansSC-Regular.otf',
'https://raw.githubusercontent.com/googlefonts/noto-cjk/main/Sans/SubsetOTF/SC/NotoSansSC-Regular.otf',
]
let fontReady: string | null = null
export async function ensureChineseFont(): Promise<string> {
if (fontReady) return fontReady
// Check if already downloaded
if (fs.existsSync(FONT_FILE) && fs.statSync(FONT_FILE).size > 100000) {
fontReady = FONT_FILE
return FONT_FILE
}
// Ensure directory exists
if (!fs.existsSync(FONTS_DIR)) fs.mkdirSync(FONTS_DIR, { recursive: true })
// Try each CDN URL
for (const url of CDN_URLS) {
try {
console.log(`Downloading Chinese font from ${url.split('/')[2]}...`)
const res = await fetch(url, { signal: AbortSignal.timeout(60000) })
if (!res.ok) continue
const buf = Buffer.from(await res.arrayBuffer())
if (buf.length < 100000) continue // too small, probably error page
fs.writeFileSync(FONT_FILE, buf)
console.log(`Chinese font downloaded (${(buf.length / 1024 / 1024).toFixed(1)} MB)`)
fontReady = FONT_FILE
return FONT_FILE
} catch (e: any) {
console.warn(`Font download failed from ${url.split('/')[2]}: ${e.message}`)
}
}
// Fallback: try local system fonts
const fallbacks = [
'C:\\Windows\\Fonts\\simhei.ttf',
'C:\\Windows\\Fonts\\msyh.ttf',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
'/System/Library/Fonts/PingFang.ttc',
]
for (const f of fallbacks) {
if (fs.existsSync(f)) {
console.log(`Using fallback system font: ${f}`)
fontReady = f
return f
}
}
throw new Error('No Chinese font available. Set PDF_FONT_PATH env variable to a TTF/OTF font path.')
}
export function getChineseFont(): string {
if (!fontReady) throw new Error('Font not initialized. Call ensureChineseFont() first.')
return fontReady
}