Files
tyapi-server/internal/shared/pdf/font_manager.go
2025-12-03 12:03:42 +08:00

218 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package pdf
import (
"os"
"runtime"
"github.com/jung-kurt/gofpdf/v2"
"go.uber.org/zap"
)
// FontManager 字体管理器
type FontManager struct {
logger *zap.Logger
chineseFontName string
chineseFontPath string
chineseFontLoaded bool
watermarkFontName string
watermarkFontPath string
watermarkFontLoaded bool
}
// NewFontManager 创建字体管理器
func NewFontManager(logger *zap.Logger) *FontManager {
return &FontManager{
logger: logger,
chineseFontName: "ChineseFont",
watermarkFontName: "WatermarkFont",
}
}
// LoadChineseFont 加载中文字体到PDF只使用黑体
func (fm *FontManager) LoadChineseFont(pdf *gofpdf.Fpdf) bool {
if fm.chineseFontLoaded {
return true
}
fontPaths := fm.getHeiFontPaths() // 只获取黑体路径
if len(fontPaths) == 0 {
fm.logger.Warn("未找到黑体字体路径PDF中的中文可能显示为空白")
return false
}
// 尝试添加黑体字体
for _, fontPath := range fontPaths {
if fm.tryAddFont(pdf, fontPath) {
fm.chineseFontPath = fontPath
fm.chineseFontLoaded = true
fm.logger.Info("成功添加黑体字体(常规和粗体)", zap.String("font_path", fontPath))
return true
}
}
fm.logger.Warn("未找到可用的黑体字体文件PDF中的中文可能显示为空白")
return false
}
// LoadWatermarkFont 加载水印字体到PDF使用宋体或其他非黑体字体
func (fm *FontManager) LoadWatermarkFont(pdf *gofpdf.Fpdf) bool {
if fm.watermarkFontLoaded {
return true
}
fontPaths := fm.getWatermarkFontPaths() // 获取水印字体路径(宋体等)
if len(fontPaths) == 0 {
// 如果找不到水印字体,使用主字体(黑体)
fm.logger.Warn("未找到水印字体,将使用主字体(黑体)")
return false
}
// 尝试添加水印字体
for _, fontPath := range fontPaths {
if fm.tryAddWatermarkFont(pdf, fontPath) {
fm.watermarkFontPath = fontPath
fm.watermarkFontLoaded = true
fm.logger.Info("成功添加水印字体", zap.String("font_path", fontPath))
return true
}
}
fm.logger.Warn("未找到可用的水印字体文件,将使用主字体(黑体)")
return false
}
// tryAddFont 尝试添加字体捕获panic
func (fm *FontManager) tryAddFont(pdf *gofpdf.Fpdf, fontPath string) bool {
defer func() {
if r := recover(); r != nil {
fm.logger.Error("添加字体时发生panic", zap.Any("panic", r), zap.String("font_path", fontPath))
}
}()
// gofpdf v2使用AddUTF8Font添加支持UTF-8的字体
pdf.AddUTF8Font(fm.chineseFontName, "", fontPath) // 常规样式
pdf.AddUTF8Font(fm.chineseFontName, "B", fontPath) // 粗体样式
return true
}
// tryAddWatermarkFont 尝试添加水印字体捕获panic
func (fm *FontManager) tryAddWatermarkFont(pdf *gofpdf.Fpdf, fontPath string) bool {
defer func() {
if r := recover(); r != nil {
fm.logger.Error("添加水印字体时发生panic", zap.Any("panic", r), zap.String("font_path", fontPath))
}
}()
// gofpdf v2使用AddUTF8Font添加支持UTF-8的字体
pdf.AddUTF8Font(fm.watermarkFontName, "", fontPath) // 常规样式
pdf.AddUTF8Font(fm.watermarkFontName, "B", fontPath) // 粗体样式
return true
}
// getHeiFontPaths 获取黑体字体路径(支持跨平台,只返回黑体)
func (fm *FontManager) getHeiFontPaths() []string {
var fontPaths []string
// Windows系统
if runtime.GOOS == "windows" {
fontPaths = []string{
`C:\Windows\Fonts\simhei.ttf`, // 黑体(优先)
}
} else if runtime.GOOS == "linux" {
// Linux系统黑体字体路径
fontPaths = []string{
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", // 文泉驿正黑(黑体)
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc", // 文泉驿微米黑(黑体)
}
} else if runtime.GOOS == "darwin" {
// macOS系统黑体字体路径
fontPaths = []string{
"/Library/Fonts/Microsoft/SimHei.ttf", // 黑体
"/System/Library/Fonts/STHeiti Light.ttc", // 黑体
}
}
// 过滤出实际存在的字体文件
var existingFonts []string
for _, fontPath := range fontPaths {
if _, err := os.Stat(fontPath); err == nil {
existingFonts = append(existingFonts, fontPath)
}
}
return existingFonts
}
// getWatermarkFontPaths 获取水印字体路径(支持跨平台,使用宋体或其他非黑体字体)
func (fm *FontManager) getWatermarkFontPaths() []string {
var fontPaths []string
// Windows系统
if runtime.GOOS == "windows" {
fontPaths = []string{
`C:\Windows\Fonts\simsun.ttf`, // 宋体(优先用于水印)
`C:\Windows\Fonts\simkai.ttf`, // 楷体(备选)
}
} else if runtime.GOOS == "linux" {
// Linux系统宋体字体路径
fontPaths = []string{
"/usr/share/fonts/truetype/arphic/uming.ttc", // 文鼎PL UMing宋体
}
} else if runtime.GOOS == "darwin" {
// macOS系统宋体字体路径
fontPaths = []string{
"/System/Library/Fonts/STSong.ttc", // 宋体
}
}
// 过滤出实际存在的字体文件
var existingFonts []string
for _, fontPath := range fontPaths {
if _, err := os.Stat(fontPath); err == nil {
existingFonts = append(existingFonts, fontPath)
}
}
return existingFonts
}
// SetFont 设置字体(使用黑体)
func (fm *FontManager) SetFont(pdf *gofpdf.Fpdf, style string, size float64) {
if fm.chineseFontLoaded {
pdf.SetFont(fm.chineseFontName, style, size)
} else {
// 如果没有黑体字体使用Arial作为后备
pdf.SetFont("Arial", style, size)
}
}
// SetWatermarkFont 设置水印字体(使用宋体或其他非黑体字体)
func (fm *FontManager) SetWatermarkFont(pdf *gofpdf.Fpdf, style string, size float64) {
if fm.watermarkFontLoaded {
pdf.SetFont(fm.watermarkFontName, style, size)
} else {
// 如果水印字体不可用,使用主字体(黑体)作为后备
fm.SetFont(pdf, style, size)
}
}
// IsChineseFontAvailable 检查中文字体是否可用
func (fm *FontManager) IsChineseFontAvailable() bool {
return fm.chineseFontLoaded
}
// GetChineseFontName 获取中文字体名称
func (fm *FontManager) GetChineseFontName() string {
return fm.chineseFontName
}
// GetWatermarkFontName 获取水印字体名称
func (fm *FontManager) GetWatermarkFontName() string {
return fm.watermarkFontName
}
// IsWatermarkFontAvailable 检查水印字体是否可用
func (fm *FontManager) IsWatermarkFontAvailable() bool {
return fm.watermarkFontLoaded
}