This commit is contained in:
@@ -104,7 +104,7 @@ func (pb *PageBuilder) AddFirstPage(pdf *gofpdf.Fpdf, product *entities.Product,
|
||||
_, lineHt = pdf.GetFontSize()
|
||||
// 居中对齐的MultiCell(通过计算宽度实现)
|
||||
descWidth := pageWidth * 0.7
|
||||
descLines := pdf.SplitText(desc, descWidth)
|
||||
descLines := pb.safeSplitText(pdf, desc, descWidth, chineseFontAvailable)
|
||||
currentX := (pageWidth - descWidth) / 2
|
||||
for _, line := range descLines {
|
||||
pdf.SetX(currentX)
|
||||
@@ -120,7 +120,7 @@ func (pb *PageBuilder) AddFirstPage(pdf *gofpdf.Fpdf, product *entities.Product,
|
||||
pb.fontManager.SetFont(pdf, "", 12)
|
||||
_, lineHt = pdf.GetFontSize()
|
||||
contentWidth := pageWidth * 0.7
|
||||
contentLines := pdf.SplitText(content, contentWidth)
|
||||
contentLines := pb.safeSplitText(pdf, content, contentWidth, chineseFontAvailable)
|
||||
currentX := (pageWidth - contentWidth) / 2
|
||||
for _, line := range contentLines {
|
||||
pdf.SetX(currentX)
|
||||
@@ -731,3 +731,100 @@ func (pb *PageBuilder) getContentPreview(content string, maxLen int) string {
|
||||
}
|
||||
return content[:maxLen] + "..."
|
||||
}
|
||||
|
||||
// safeSplitText 安全地分割文本,避免在没有中文字体时调用SplitText导致panic
|
||||
func (pb *PageBuilder) safeSplitText(pdf *gofpdf.Fpdf, text string, width float64, chineseFontAvailable bool) []string {
|
||||
// 检查文本是否包含中文字符
|
||||
hasChinese := false
|
||||
for _, r := range text {
|
||||
if (r >= 0x4E00 && r <= 0x9FFF) || // 中文字符范围
|
||||
(r >= 0x3400 && r <= 0x4DBF) || // 扩展A
|
||||
(r >= 0x20000 && r <= 0x2A6DF) || // 扩展B
|
||||
(r >= 0x3000 && r <= 0x303F) || // CJK符号和标点
|
||||
(r >= 0xFF00 && r <= 0xFFEF) { // 全角字符
|
||||
hasChinese = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 如果文本包含中文但中文字体不可用,直接使用手动分割方法
|
||||
// 如果中文字体可用且文本不包含中文,可以尝试使用SplitText
|
||||
// 即使中文字体可用,如果文本包含中文,也要小心处理(字体可能未正确加载)
|
||||
if chineseFontAvailable && !hasChinese {
|
||||
// 对于纯英文/ASCII文本,可以安全使用SplitText
|
||||
var lines []string
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
pb.logger.Warn("SplitText发生panic,使用备用方法", zap.Any("error", r))
|
||||
}
|
||||
}()
|
||||
lines = pdf.SplitText(text, width)
|
||||
}()
|
||||
if len(lines) > 0 {
|
||||
return lines
|
||||
}
|
||||
}
|
||||
|
||||
// 使用手动分割方法(适用于中文文本或SplitText失败的情况)
|
||||
// 估算字符宽度:中文字符约6mm,英文字符约3mm(基于14号字体)
|
||||
fontSize, _ := pdf.GetFontSize()
|
||||
chineseCharWidth := fontSize * 0.43 // 中文字符宽度(mm)
|
||||
englishCharWidth := fontSize * 0.22 // 英文字符宽度(mm)
|
||||
|
||||
var lines []string
|
||||
var currentLine strings.Builder
|
||||
currentWidth := 0.0
|
||||
|
||||
runes := []rune(text)
|
||||
for _, r := range runes {
|
||||
// 计算字符宽度
|
||||
var charWidth float64
|
||||
if (r >= 0x4E00 && r <= 0x9FFF) || // 中文字符范围
|
||||
(r >= 0x3400 && r <= 0x4DBF) || // 扩展A
|
||||
(r >= 0x20000 && r <= 0x2A6DF) || // 扩展B
|
||||
(r >= 0x3000 && r <= 0x303F) || // CJK符号和标点
|
||||
(r >= 0xFF00 && r <= 0xFFEF) { // 全角字符
|
||||
charWidth = chineseCharWidth
|
||||
} else {
|
||||
charWidth = englishCharWidth
|
||||
}
|
||||
|
||||
// 检查是否需要换行
|
||||
if currentWidth+charWidth > width && currentLine.Len() > 0 {
|
||||
// 保存当前行
|
||||
lines = append(lines, currentLine.String())
|
||||
currentLine.Reset()
|
||||
currentWidth = 0.0
|
||||
}
|
||||
|
||||
// 处理换行符
|
||||
if r == '\n' {
|
||||
if currentLine.Len() > 0 {
|
||||
lines = append(lines, currentLine.String())
|
||||
currentLine.Reset()
|
||||
currentWidth = 0.0
|
||||
} else {
|
||||
// 空行
|
||||
lines = append(lines, "")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 添加字符到当前行
|
||||
currentLine.WriteRune(r)
|
||||
currentWidth += charWidth
|
||||
}
|
||||
|
||||
// 添加最后一行
|
||||
if currentLine.Len() > 0 {
|
||||
lines = append(lines, currentLine.String())
|
||||
}
|
||||
|
||||
// 如果没有分割出任何行,至少返回一行
|
||||
if len(lines) == 0 {
|
||||
lines = []string{text}
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user