golang实现pdf中自动换行的表格

需要用到的库:jung-kurt/gofpdf

由于CellFormat方法不支持\n换行,会被变成乱码,MultiCell方法会自动将坐标定位到下一行。所以需要自己实现坐标的计算变换。通过Rect方法画出单元格,MultiCell方法在格内自动换行写字,在计算坐标重复写单元格,最终组成一行。

参考ExampleFpdf_Rect()

  1. 实现自动换行的表格
go 复制代码
import "github.com/jung-kurt/gofpdf"


type pdfLine struct {
	pdf      *gofpdf.Fpdf
	h        float64	// 需要的行高
	x        float64	// 记录开始时坐标
	y        float64	// 记录开始时坐标
	style    string		// 风格  F仅填充 D仅边框 或者DF两个都要
	alignStr string		// 对其方式 LCR为水平的左、中、右,TMBA为垂直的上、中、下、基准线
	fontH    float64	// 字体高度
	cells    []pdfCell	// 
}

type pdfCell struct {
	w      float64	// 宽度
	h      float64	// 行高
	txtStr string	// 文本
	lines  int		// 判断文本会占几行
}

func (s *pdfLine) addLine(style string, alignStr string, cells ...pdfCell) {
	s.style = style
	s.alignStr = alignStr
	_, _, _, mbottom := s.pdf.GetMargins() // 获取当前页面边距
	_, pageh := s.pdf.GetPageSize()        // 获取当前页面尺寸
	x, y := s.pdf.GetXY()                  // 获取当前位置
	// 页面剩余行高不够时 开启新一页
	if s.pdf.GetY()+s.h > pageh-mbottom {
		s.pdf.AddPage()
		y = s.pdf.GetY()
	}
	s.x = x
	s.y = y
	_, s.fontH = s.pdf.GetFontSize()
	// 记录需要的最高行高
	for _, cell := range cells {
		lines := s.pdf.SplitText(cell.txtStr, cell.w)
		h := float64(len(lines)) * cell.h
		if s.h < h {
			s.h = h
		}
		cell.lines = len(lines)
		s.cells = append(s.cells, cell)
	}
	s.write()
}

// 写入
func (s *pdfLine) write() {
	x := s.x
	y := s.y
	// 手动记录并移动坐标
	for _, c := range s.cells {
		usedH := float64(c.lines) * s.fontH
		margin := (s.h - usedH) / 2.0
		s.pdf.Rect(x, s.y, c.w, s.h, s.style)
		s.pdf.SetXY(x, y+margin) // 保持单元格内的文字有边距
		s.pdf.MultiCell(c.w, s.fontH, c.txtStr, "", s.alignStr, false)
		x += c.w
		s.pdf.SetXY(x, y)
	}
	// 坐标重置为下一行的当前位置
	s.pdf.SetXY(s.x, s.y+s.h)
	// 重置变量
	s.cells = nil
	s.h = 0
}

// 使用  生成一个每行4列的表格
func main() {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.AddPage()
	pdf.AddUTF8Font("NotoSansSC-Regular", "", "src/font/NotoSansSC-Regular.ttf")
	pdf.SetFont("NotoSansSC-Regular", "", 12)
	myPdf := pdfLine{pdf: pdf}

	width, _ := pdf.GetPageSize()		// 页面宽度
	left, _, right, _ := pdf.GetMargins()	// 左右边距
	usable := width - left - right	// 可用的页面宽度
	_,h := pdf.GetFontSize()	// 字体高度
	tableH := h + 2	// 行高  多出2mm的边距
	tableWidth := usable / 4	// 每个单元个的宽度
	pdf.SetFillColor(233, 233, 233)
	// 表头
	myPdf.addLine("FD", "CM", []pdfCell{
			{w: tableWidth, h: tableH, txtStr: "表头1"},
			{w: tableWidth, h: tableH, txtStr: "表头2"},
			{w: tableWidth, h: tableH, txtStr: "表头3"},
			{w: tableWidth, h: tableH, txtStr: "表头4"},
		}...)
	// 内容
	myPdf.addLine("", "CM", []pdfCell{
			{w: tableWidth, h: tableH, txtStr: "内容1"},
			{w: tableWidth, h: tableH, txtStr: "假设这里是很长很长的内容,你可以自己替换一下"},
			{w: tableWidth, h: tableH, txtStr: "内容3"},
			{w: tableWidth, h: tableH, txtStr: "内容4"},
		}...)
}
  1. 创建页面、指定字体
go 复制代码
	// 添加页面
	pdf.AddPage()
	// 加载字体
	pdf.AddUTF8Font("NotoSansSC-Regular", "", "src/font/NotoSansSC-Regular.ttf")
	// 设置字体
	pdf.SetFont("NotoSansSC-Regular", "", 12)

加载字体时,会将前面New方法指定的目录和AddUTF8Font方法指定的目录文件拼在一起。

  1. 其他常用写入方法
go 复制代码
	// 简单单元格,接收参数为 1.单元格长度  2.行高  3.文本
	pdf.Cell(cellWeight, h, "my text")
	// 自动换行的单元格,调用这个方法之左边会回到下一行的开头
	pdf.MultiCell(0, h, "假设这是一个很长的单元格")
	// 设置填充颜色
	pdf.SetFillColor(233, 233, 233)
	// 指定格式的单元格  参数 1.单元格长度 2.行高 3.文本 4.边框形式(1全边框、或者LTRB分别代表左上右下) 5.单元格
	// 写入之后的坐标(1为下一行开头,2当前坐标的下一行) 6.对其方式(LCR为水平的左、中、右,TMBA为垂直的上、中、
	// 下、基准线) 7.是否填充当前格子 8.连接 9.连接url
	pdf.CellFormat(tableWidth, tableH, "总成本", "1", 0, "M", true, 0, "")
	// 插入图片 参数分别为  1图片位置 2x坐标 3y坐标 4图片宽度 5图片高度
	pdf.ImageOptions("src/font/logo.png", width-right-25, 5, 25, 0, false, opt, 0, "")
相关推荐
萧鼎29 分钟前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸30 分钟前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农30 分钟前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^31 分钟前
数据库连接池的创建
java·开发语言·数据库
秋の花39 分钟前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端42 分钟前
第六章 7.0 LinkList
java·开发语言·网络
可峰科技1 小时前
斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)
开发语言·qt
全栈开发圈1 小时前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
面试鸭1 小时前
离谱!买个人信息买到网安公司头上???
java·开发语言·职场和发展
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫