67 lines
2.2 KiB
TypeScript
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
|
|
}
|