网站开发一个多少钱啊,做网站需要招什么职位,alexa排名是什么意思,网站建设的具体流程图本教程主要实现【Golang处理Word文档模板实现标签填充|表格插入|图标绘制和插入|删除段落|删除标签】。 本文源码#xff1a;https://gitee.com/songfayuan/go-zero-demo 教程源码分支#xff1a;master 分支#xff08;_examples/word-template/fill-word-template.go…本教程主要实现【Golang处理Word文档模板实现标签填充|表格插入|图标绘制和插入|删除段落|删除标签】。 本文源码https://gitee.com/songfayuan/go-zero-demo 教程源码分支master 分支_examples/word-template/fill-word-template.go
Golang处理Word文档模板教程
本教程将指导您使用Golang处理Word文档模板包括自定义标签填充、动态插入表格、绘制图表和插入图表。我们将使用unioffice库和gg库来完成这些任务。
前提条件
在开始之前请确保您已安装以下库
uniofficegg
您可以使用以下命令安装这些库
go get -u github.com/Esword618/unioffice
go get -u github.com/fogleman/gg代码结构
我们的代码分为以下几部分
打开Word文档填充模板中的变量在指定标签处插入表格创建折线图并保存为图片在指定标签处插入图表保存更新后的文档
示例代码
以下是完整的示例代码
package mainimport (fmtlogmathstringsgithub.com/Esword618/unioffice/colorgithub.com/Esword618/unioffice/commongithub.com/Esword618/unioffice/documentgithub.com/Esword618/unioffice/measurementgithub.com/Esword618/unioffice/schema/soo/wmlgithub.com/fogleman/gg
)//教程https://blog.csdn.net/u011019141/article/details/140788882func main() {// 定义文档路径和图表文件路径docPath : _examples/word-template/template.docxlineChartFile : /Users/songfayuan/Downloads/line_chart.PNGbarChartFile : /Users/songfayuan/Downloads/bar_chart.pngpieChartFile : /Users/songfayuan/Downloads/pie_chart.pngupdatedDocPath : /Users/songfayuan/Downloads/updated_demo.docx// 打开文档doc, err : openDocument(docPath)if err ! nil {log.Fatalf(无法打开文档: %v, err)}// 填充模板中的变量fillTemplate(doc, map[string]string{{{TASK_NAME}}: 任务名称示例,{{DETAILS}}: 详细信息示例,})// 在指定标签处插入表格if err : insertTableAt(doc, {{biaoge}}); err ! nil {log.Fatalf(插入表格时出错: %v, err)}// 创建折线图并保存为图片if err : createLineChart(lineChartFile); err ! nil {log.Fatalf(创建图表时出错: %v, err)}// 在指定标签处插入图表if err : insertImageAt(doc, lineChartFile, {{tubiao}}); err ! nil {log.Fatalf(插入图表时出错: %v, err)}// 创建柱状图并保存为图片if err : createBarChart(barChartFile); err ! nil {log.Fatalf(创建柱状图时出错: %v, err)}// 在指定标签处插入柱状图if err : insertImageAt(doc, barChartFile, {{zhuzhuangtu}}); err ! nil {log.Fatalf(插入柱状图时出错: %v, err)}// 创建饼图并保存为图片if err : createPieChart(pieChartFile); err ! nil {log.Fatalf(创建饼图时出错: %v, err)}// 在指定标签处插入饼图if err : insertImageAt(doc, pieChartFile, {{bingtu}}); err ! nil {log.Fatalf(插入饼图时出错: %v, err)}// 删除{{a}}到{{b}}之间的段落if err : removeParagraphsBetweenTags(doc, {{a}}, {{b}}); err ! nil {log.Fatalf(删除段落时出错: %v, err)}// 删除指定标签if err : removeParagraphWithTag(doc, {{shanchu}}); err ! nil {log.Fatalf(删除指定标签时出错: %v, err)}// 保存更新后的Word文档if err : doc.SaveToFile(updatedDocPath); err ! nil {log.Fatalf(无法保存文档: %v, err)}fmt.Println(文档更新成功)
}// 打开文档
func openDocument(path string) (*document.Document, error) {return document.Open(path) // 使用unioffice库打开指定路径的文档
}// 填充模板中的变量
func fillTemplate(doc *document.Document, replacements map[string]string) {for _, para : range doc.Paragraphs() { // 遍历文档中的每个段落for _, run : range para.Runs() { // 遍历段落中的每个运行文本片段text : run.Text()for placeholder, replacement : range replacements { // 遍历需要替换的占位符if strings.Contains(text, placeholder) { // 如果文本包含占位符text strings.ReplaceAll(text, placeholder, replacement) // 替换占位符run.Clear() // 清除原有内容run.AddText(text) // 添加替换后的文本}}}}
}// 在指定标签处插入表格
func insertTableAt(doc *document.Document, tag string) error {paras : doc.Paragraphs() // 获取文档中的所有段落for _, para : range paras {if paraContainsTag(para, tag) { // 如果段落包含指定标签// 创建并配置表格table : doc.InsertTableAfter(para) // 在标签段落之后插入表格table.Properties().SetWidthPercent(100) // 设置表格宽度为100%borders : table.Properties().Borders()borders.SetAll(wml.ST_BorderSingle, color.Black, measurement.Dxa) // 设置所有边框为单线黑色for i : 0; i 3; i { // 创建表格行和单元格row : table.AddRow()for j : 0; j 3; j {cell : row.AddCell()cellPara : cell.AddParagraph()cellRun : cellPara.AddRun()cellRun.AddText(fmt.Sprintf(单元格 %d-%d, i1, j1))}}//分隔不同表格//doc.InsertParagraphAfter(para).AddRun().AddText(--------------)doc.InsertParagraphAfter(para).AddRun()// 创建并配置表格table doc.InsertTableAfter(para) // 在标签段落之后插入表格table.Properties().SetWidthPercent(100) // 设置表格宽度为100%borders table.Properties().Borders()borders.SetAll(wml.ST_BorderSingle, color.Black, measurement.Dxa) // 设置所有边框为单线黑色for i : 0; i 3; i { // 创建表格行和单元格row : table.AddRow()for j : 0; j 3; j {cell : row.AddCell()cellPara : cell.AddParagraph()cellRun : cellPara.AddRun()cellRun.AddText(fmt.Sprintf(单元格 %d-%d, i1, j1))}}// 移除标签段落replaceParagraphWithTable(para, tag) // 替换标签段落为表格// 删除段落doc.RemoveParagraph(para) // 从文档中删除标签段落return nil}}return fmt.Errorf(未找到标签 %s, tag) // 如果未找到标签段落返回错误
}// 在指定标签处插入图表
func insertImageAt(doc *document.Document, imagePath string, tag string) error {paras : doc.Paragraphs() // 获取文档中的所有段落for _, para : range paras {if paraContainsTag(para, tag) { // 如果段落包含指定标签img, err : common.ImageFromFile(imagePath) // 从文件中加载图片if err ! nil {return fmt.Errorf(无法从文件中加载图片: %v, err)}// 创建图片引用iref, err : doc.AddImage(img) // 将图片添加到文档中if err ! nil {return fmt.Errorf(无法将图片添加到文档: %v, err)}// 创建新的段落和运行以插入图表newPara : doc.InsertParagraphAfter(para) // 在标签段落之后插入新段落run : newPara.AddRun()// 插入图片到文档imgInl, err : run.AddDrawingInline(iref) // 在运行中添加图片if err ! nil {return fmt.Errorf(插入图片时出错: %v, err)}imgInl.SetSize(6*measurement.Inch, 4*measurement.Inch) // 设置图片尺寸为6x4英寸// 移除标签段落replaceParagraphWithTable(para, tag) // 替换标签段落为图表// 删除段落doc.RemoveParagraph(para) // 从文档中删除标签段落return nil}}return fmt.Errorf(未找到标签 %s, tag) // 如果未找到标签段落返回错误
}// 判断段落是否包含指定标签
func paraContainsTag(para *document.Paragraph, tag string) bool {for _, run : range para.Runs() { // 遍历段落中的每个运行if strings.Contains(run.Text(), tag) { // 如果运行文本包含标签return true}}return false
}// 移除标签段落
func replaceParagraphWithTable(para *document.Paragraph, tag string) {// 找到标签的 Runfor _, run : range para.Runs() {log.Printf(替换标签tag %v, tag)if strings.Contains(run.Text(), tag) {para.InsertRunAfter(para.AddRun())run.Clear() // 清除原有内容para.RemoveRun(run) // 移除运行break}}
}// 删除两个标签之间的段落
func removeParagraphsBetweenTags(doc *document.Document, startTag, endTag string) error {paras : doc.Paragraphs()startIndex, endIndex : -1, -1// 找到包含startTag和endTag的段落索引for i, para : range paras {if paraContainsTag(para, startTag) {startIndex i}if paraContainsTag(para, endTag) {endIndex ibreak}}if startIndex -1 {return fmt.Errorf(未找到标签 %s, startTag)}if endIndex -1 {return fmt.Errorf(未找到标签 %s, endTag)}if startIndex endIndex {return fmt.Errorf(标签 %s 和 %s 之间的顺序不正确, startTag, endTag)}// 删除startTag和endTag之间的段落for i : startIndex; i endIndex; i {doc.RemoveParagraph(paras[i])}return nil
}// 删除指定标签段落
func removeParagraphWithTag(doc *document.Document, tag string) error {paras : doc.Paragraphs()for _, para : range paras {if paraContainsTag(para, tag) {doc.RemoveParagraph(para)return nil}}return fmt.Errorf(未找到标签 %s, tag)
}// 创建折线图并保存为图片
func createLineChart(filename string) error {const (width 900 // 画布宽度height 600 // 画布高度)// 数据data : []struct {label stringvalue float64}{{身份证, 15},{电话号码, 20},{地址信息, 25},{银行卡号, 30},{财务数据, 35},{基础信息, 40},{户籍信息, 45},}// 创建画布dc : gg.NewContext(width, height)dc.SetRGB(1, 1, 1) // 背景色为白色dc.Clear()barWidth : float64(width-200) / float64(len(data)) // 调整每个数据点之间的间隔maxValue : 50.0 // 纵坐标最大值// 加载自定义字体if err : dc.LoadFontFace(_examples/word-template/msyh.ttf, 12); err ! nil {return fmt.Errorf(无法加载字体: %v, err)}// 绘制折线图dc.SetRGB(0, 0, 0) // 线条颜色为黑色for i, d : range data {x : 50 float64(i)*(barWidth20) // x轴起始位置y : height - 50 - (d.value / maxValue * (height - 100)) // y轴起始位置减去数据点的高度if i 0 {dc.MoveTo(x, y)} else {dc.LineTo(x, y)}}dc.Stroke()// 绘制坐标轴dc.SetRGB(0, 0, 0) // 黑色dc.DrawLine(50, height-50, width-50, height-50) // X轴dc.DrawLine(50, height-50, 50, 50) // Y轴dc.Stroke()// 添加横坐标标签for i, d : range data {dc.DrawStringAnchored(d.label, 50float64(i)*(barWidth20), height-30, 0.5, 1)}// 添加纵坐标标签for i : 0; i int(maxValue); i 5 {y : height - 50 - (float64(i) / maxValue * (height - 100))dc.DrawStringAnchored(fmt.Sprintf(%d, int(i)), 30, y, 1, 0.5)}// 保存图像为PNG文件return dc.SavePNG(filename)
}// 创建柱状图并保存为图片
func createBarChart(filename string) error {const (width 900 // 画布宽度height 700 // 画布高度)// 数据data : []struct {label stringvalue float64}{{身份证, 15},{电话号码, 20},{地址信息, 25},{银行卡号, 30},{财务数据, 35},{基础信息, 40},{户籍信息, 45},}// 创建画布dc : gg.NewContext(width, height)dc.SetRGB(1, 1, 1) // 背景色为白色dc.Clear()barWidth : float64(width-200) / float64(len(data)) // 调整柱子的宽度barSpacing : 10.0 // 增加柱子之间的间隔maxValue : 50.0 // 纵坐标最大值// 定义颜色colors : []struct{ R, G, B float64 }{{0.8, 0.2, 0.2}, // 红色{0.2, 0.8, 0.2}, // 绿色{0.2, 0.2, 0.8}, // 蓝色{0.8, 0.8, 0.2}, // 黄色{0.8, 0.2, 0.8}, // 紫色{0.2, 0.8, 0.8}, // 青色{0.8, 0.8, 0.8}, // 灰色}// 加载自定义字体if err : dc.LoadFontFace(_examples/word-template/msyh.ttf, 12); err ! nil {return fmt.Errorf(无法加载字体: %v, err)}// 绘制柱状图for i, d : range data {x : 50 float64(i)*(barWidthbarSpacing) // x轴起始位置y : height - 50 - (d.value / maxValue * (height - 100)) // y轴起始位置减去柱子的高度color : colors[i%len(colors)] // 循环使用颜色dc.SetRGB(color.R, color.G, color.B)dc.DrawRectangle(x, y, barWidth, (d.value / maxValue * (height - 100)))dc.Fill()}// 绘制坐标轴dc.SetRGB(0, 0, 0) // 黑色dc.DrawLine(50, height-50, width-50, height-50) // X轴dc.DrawLine(50, height-50, 50, 50) // Y轴dc.Stroke()// 添加横坐标标签for i, d : range data {dc.DrawStringAnchored(d.label, 50float64(i)*(barWidthbarSpacing)barWidth/2, height-30, 0.5, 1)}// 添加纵坐标标签for i : 0; i int(maxValue); i 5 {y : height - 50 - (float64(i) / maxValue * (height - 100))dc.DrawStringAnchored(fmt.Sprintf(%d, int(i)), 30, y, 1, 0.5)}// 保存图像为PNG文件return dc.SavePNG(filename)
}// 创建饼图并保存为图片
func createPieChart(filename string) error {const (width 640height 600radius 200 // 半径)dc : gg.NewContext(width, height)dc.SetRGB(1, 1, 1) // 背景色为白色dc.Clear()data : []struct {label stringvalue float64}{{身份证, 15}, {电话号码, 20}, {地址信息, 25}, {银行卡号, 30}, {财务数据, 35}, {基础信息, 40}, {户籍信息, 45},}colors : []struct{ R, G, B float64 }{{0.9, 0.3, 0.3}, // 红色{0.3, 0.9, 0.3}, // 绿色{0.3, 0.3, 0.9}, // 蓝色{0.9, 0.9, 0.3}, // 黄色{0.9, 0.3, 0.9}, // 紫色{0.3, 0.9, 0.9}, // 青色{0.9, 0.6, 0.3}, // 橙色}// 设置字体选择支持中文的字体if err : dc.LoadFontFace(_examples/word-template/msyh.ttf, 12); err ! nil {return fmt.Errorf(无法加载字体: %v, err)}var total float64for _, d : range data {total d.value}startAngle : -math.Pi / 2 // 从顶部开始绘制for i, d : range data {percentage : d.value / totalangle : percentage * 2 * math.Pi// 设置扇形颜色color : colors[i%len(colors)]dc.SetRGB(color.R, color.G, color.B)dc.DrawArc(width/2, height/2, radius, startAngle, startAngleangle)dc.LineTo(width/2, height/2)dc.Fill()// 计算标签位置midAngle : startAngle angle/2labelX : width/2 (radius20)*math.Cos(midAngle)labelY : height/2 (radius20)*math.Sin(midAngle)// 绘制标签和数据labelText : fmt.Sprintf(%s: %.0f, d.label, d.value)dc.SetRGB(0, 0, 0) // 文字颜色黑色dc.DrawStringAnchored(labelText, labelX, labelY, 0.5, 0.5)startAngle angle}return dc.SavePNG(filename) // 保存图像为PNG文件
}
解释 打开文档 doc, err : openDocument(docPath)使用unioffice库打开指定路径的Word文档。 填充模板中的变量 fillTemplate(doc, map[string]string{{{TASK_NAME}}: 任务名称示例,{{DETAILS}}: 详细信息示例,
})遍历文档中的每个段落和运行文本片段如果文本包含占位符将其替换为实际值。 在指定标签处插入表格 if err : insertTableAt(doc, {{biaoge}}); err ! nil {log.Fatalf(插入表格时出错: %v, err)
}查找包含指定标签的段落在该段落之后插入表格并删除标签段落。 创建折线图并保存为图片 if err : createLineChart(chartFile); err ! nil {log.Fatalf(创建图表时出错: %v, err)
}使用gg库绘制折线图并保存为PNG文件。 在指定标签处插入图表 if err : insertImageAt(doc, chartFile, {{tubiao}}); err ! nil {log.Fatalf(插入图表时出错: %v, err)
}查找包含指定标签的段落在该段落之后插入图表并删除标签段落。 保存更新后的文档 if err : doc.SaveToFile(updatedDocPath); err ! nil {log.Fatalf(无法保存文档: %v, err)
}将更新后的文档保存到指定路径。
运行代码
确保您已正确安装所需的库并将代码中的文件路径替换为您自己的路径。运行代码后您将得到一个填充了模板变量、插入了表格和图表的更新Word文档。
Word模板
标签填充
张三{{TASK_NAME}}
李四{{DETAILS}}插入表格
表格
{{biaoge}}插入图表
图表
{{tubiao}}
{{zhuzhuangtu}}
{{bingtu}}删除标签之间段落
{{a}}
段落1
段落2
段落3
段落4
{{b}}
段落5
删除指定标签
删除指定标签
{{shanchu}}
其他段落
9282892890拷贝到Word文档中保存为template.docx长这样
代码处理后的Word内容 优化版源码
优化版本图片不保存到磁盘保存到了缓存。
package mainimport (bytesfmtlogmathstringsgithub.com/Esword618/unioffice/colorgithub.com/Esword618/unioffice/commongithub.com/Esword618/unioffice/documentgithub.com/Esword618/unioffice/measurementgithub.com/Esword618/unioffice/schema/soo/wmlgithub.com/fogleman/gg
)//教程https://blog.csdn.net/u011019141/article/details/140788882func main() {// 定义文档路径和图表文件路径docPath : _examples/word-template/template.docxupdatedDocPath : /Users/songfayuan/Downloads/updated_demo.docx// 打开文档doc, err : openDocument(docPath)if err ! nil {log.Fatalf(无法打开文档: %v, err)}// 填充模板中的变量fillTemplate(doc, map[string]string{{{TASK_NAME}}: 任务名称示例,{{DETAILS}}: 详细信息示例,})// 在指定标签处插入表格if err : insertTableAt(doc, {{biaoge}}); err ! nil {log.Fatalf(插入表格时出错: %v, err)}// 创建折线图并存储到缓存中lineChartBuffer, err : createLineChart()if err ! nil {log.Fatalf(创建图表时出错: %v, err)}// 在指定标签处插入图表if err : insertImageAt(doc, lineChartBuffer, {{tubiao}}); err ! nil {log.Fatalf(插入图表时出错: %v, err)}// 创建柱状图并存储到缓存中barChartBuffer, err : createBarChart()if err ! nil {log.Fatalf(创建柱状图时出错: %v, err)}// 在指定标签处插入柱状图if err : insertImageAt(doc, barChartBuffer, {{zhuzhuangtu}}); err ! nil {log.Fatalf(插入柱状图时出错: %v, err)}// 创建饼图并存储到缓存中pieChartBuffer, err : createPieChart()if err ! nil {log.Fatalf(创建饼图时出错: %v, err)}// 在指定标签处插入饼图if err : insertImageAt(doc, pieChartBuffer, {{bingtu}}); err ! nil {log.Fatalf(插入饼图时出错: %v, err)}// 删除{{a}}到{{b}}之间的段落if err : removeParagraphsBetweenTags(doc, {{a}}, {{b}}); err ! nil {log.Fatalf(删除段落时出错: %v, err)}// 删除指定标签if err : removeParagraphWithTag(doc, {{shanchu}}); err ! nil {log.Fatalf(删除指定标签时出错: %v, err)}// 保存更新后的Word文档if err : doc.SaveToFile(updatedDocPath); err ! nil {log.Fatalf(无法保存文档: %v, err)}fmt.Println(文档更新成功)
}// 打开文档
func openDocument(path string) (*document.Document, error) {return document.Open(path) // 使用unioffice库打开指定路径的文档
}// 填充模板中的变量
func fillTemplate(doc *document.Document, replacements map[string]string) {for _, para : range doc.Paragraphs() { // 遍历文档中的每个段落for _, run : range para.Runs() { // 遍历段落中的每个运行文本片段text : run.Text()for placeholder, replacement : range replacements { // 遍历需要替换的占位符if strings.Contains(text, placeholder) { // 如果文本包含占位符text strings.ReplaceAll(text, placeholder, replacement) // 替换占位符run.Clear() // 清除原有内容run.AddText(text) // 添加替换后的文本}}}}
}// 在指定标签处插入表格
func insertTableAt(doc *document.Document, tag string) error {paras : doc.Paragraphs() // 获取文档中的所有段落for _, para : range paras {if paraContainsTag(para, tag) { // 如果段落包含指定标签// 创建并配置表格table : doc.InsertTableAfter(para) // 在标签段落之后插入表格table.Properties().SetWidthPercent(100) // 设置表格宽度为100%borders : table.Properties().Borders()borders.SetAll(wml.ST_BorderSingle, color.Black, measurement.Dxa) // 设置所有边框为单线黑色for i : 0; i 3; i { // 创建表格行和单元格row : table.AddRow()for j : 0; j 3; j {cell : row.AddCell()cellPara : cell.AddParagraph()cellRun : cellPara.AddRun()cellRun.AddText(fmt.Sprintf(单元格 %d-%d, i1, j1))}}//分隔不同表格//doc.InsertParagraphAfter(para).AddRun().AddText(--------------)doc.InsertParagraphAfter(para).AddRun()// 创建并配置表格table doc.InsertTableAfter(para) // 在标签段落之后插入表格table.Properties().SetWidthPercent(100) // 设置表格宽度为100%borders table.Properties().Borders()borders.SetAll(wml.ST_BorderSingle, color.Black, measurement.Dxa) // 设置所有边框为单线黑色for i : 0; i 3; i { // 创建表格行和单元格row : table.AddRow()for j : 0; j 3; j {cell : row.AddCell()cellPara : cell.AddParagraph()cellRun : cellPara.AddRun()cellRun.AddText(fmt.Sprintf(单元格 %d-%d, i1, j1))}}// 移除标签段落replaceParagraphWithTable(para, tag) // 替换标签段落为表格// 删除段落doc.RemoveParagraph(para) // 从文档中删除标签段落return nil}}return fmt.Errorf(未找到标签 %s, tag) // 如果未找到标签段落返回错误
}// 在指定标签处插入图表
func insertImageAt(doc *document.Document, imageBuffer *bytes.Buffer, tag string) error {paras : doc.Paragraphs() // 获取文档中的所有段落for _, para : range paras {if paraContainsTag(para, tag) { // 如果段落包含指定标签img, err : common.ImageFromBytes(imageBuffer.Bytes()) // 从内存缓冲区中加载图片if err ! nil {return fmt.Errorf(无法从内存缓冲区中加载图片: %v, err)}// 创建图片引用iref, err : doc.AddImage(img) // 将图片添加到文档中if err ! nil {return fmt.Errorf(无法将图片添加到文档: %v, err)}// 创建新的段落和运行以插入图表newPara : doc.InsertParagraphAfter(para) // 在标签段落之后插入新段落run : newPara.AddRun()// 插入图片到文档imgInl, err : run.AddDrawingInline(iref) // 在运行中添加图片if err ! nil {return fmt.Errorf(插入图片时出错: %v, err)}imgInl.SetSize(6*measurement.Inch, 4*measurement.Inch) // 设置图片尺寸为6x4英寸// 移除标签段落replaceParagraphWithTable(para, tag) // 替换标签段落为图表// 删除段落doc.RemoveParagraph(para) // 从文档中删除标签段落return nil}}return fmt.Errorf(未找到标签 %s, tag) // 如果未找到标签段落返回错误
}// 判断段落是否包含指定标签
func paraContainsTag(para *document.Paragraph, tag string) bool {for _, run : range para.Runs() { // 遍历段落中的每个运行if strings.Contains(run.Text(), tag) { // 如果运行文本包含标签return true}}return false
}// 移除标签段落
func replaceParagraphWithTable(para *document.Paragraph, tag string) {// 找到标签的 Runfor _, run : range para.Runs() {log.Printf(替换标签tag %v, tag)if strings.Contains(run.Text(), tag) {para.InsertRunAfter(para.AddRun())run.Clear() // 清除原有内容para.RemoveRun(run) // 移除运行break}}
}// 删除两个标签之间的段落
func removeParagraphsBetweenTags(doc *document.Document, startTag, endTag string) error {paras : doc.Paragraphs()startIndex, endIndex : -1, -1// 找到包含startTag和endTag的段落索引for i, para : range paras {if paraContainsTag(para, startTag) {startIndex i}if paraContainsTag(para, endTag) {endIndex ibreak}}if startIndex -1 {return fmt.Errorf(未找到标签 %s, startTag)}if endIndex -1 {return fmt.Errorf(未找到标签 %s, endTag)}if startIndex endIndex {return fmt.Errorf(标签 %s 和 %s 之间的顺序不正确, startTag, endTag)}// 删除startTag和endTag之间的段落for i : startIndex; i endIndex; i {doc.RemoveParagraph(paras[i])}return nil
}// 删除指定标签段落
func removeParagraphWithTag(doc *document.Document, tag string) error {paras : doc.Paragraphs()for _, para : range paras {if paraContainsTag(para, tag) {doc.RemoveParagraph(para)return nil}}return fmt.Errorf(未找到标签 %s, tag)
}// 创建折线图并将其存储到缓存中
func createLineChart() (*bytes.Buffer, error) {const (width 900 // 画布宽度height 600 // 画布高度)// 数据data : []struct {label stringvalue float64}{{身份证, 15},{电话号码, 20},{地址信息, 25},{银行卡号, 30},{财务数据, 35},{基础信息, 40},{户籍信息, 45},}// 创建画布dc : gg.NewContext(width, height)dc.SetRGB(1, 1, 1) // 背景色为白色dc.Clear()barWidth : float64(width-200) / float64(len(data)) // 调整每个数据点之间的间隔maxValue : 50.0 // 纵坐标最大值// 加载自定义字体if err : dc.LoadFontFace(_examples/word-template/msyh.ttf, 12); err ! nil {return nil, nil}// 绘制折线图dc.SetRGB(0, 0, 0) // 线条颜色为黑色for i, d : range data {x : 50 float64(i)*(barWidth20) // x轴起始位置y : height - 50 - (d.value / maxValue * (height - 100)) // y轴起始位置减去数据点的高度if i 0 {dc.MoveTo(x, y)} else {dc.LineTo(x, y)}}dc.Stroke()// 绘制坐标轴dc.SetRGB(0, 0, 0) // 黑色dc.DrawLine(50, height-50, width-50, height-50) // X轴dc.DrawLine(50, height-50, 50, 50) // Y轴dc.Stroke()// 添加横坐标标签for i, d : range data {dc.DrawStringAnchored(d.label, 50float64(i)*(barWidth20), height-30, 0.5, 1)}// 添加纵坐标标签for i : 0; i int(maxValue); i 5 {y : height - 50 - (float64(i) / maxValue * (height - 100))dc.DrawStringAnchored(fmt.Sprintf(%d, int(i)), 30, y, 1, 0.5)}// 将图表保存到缓冲区var buf bytes.Bufferif err : dc.EncodePNG(buf); err ! nil {return nil, err}return buf, nil
}// 创建柱状图并将其存储到缓存中
func createBarChart() (*bytes.Buffer, error) {const (width 900 // 画布宽度height 700 // 画布高度)// 数据data : []struct {label stringvalue float64}{{身份证, 15},{电话号码, 20},{地址信息, 25},{银行卡号, 30},{财务数据, 35},{基础信息, 40},{户籍信息, 45},}// 创建画布dc : gg.NewContext(width, height)dc.SetRGB(1, 1, 1) // 背景色为白色dc.Clear()barWidth : float64(width-200) / float64(len(data)) // 调整柱子的宽度barSpacing : 10.0 // 增加柱子之间的间隔maxValue : 50.0 // 纵坐标最大值// 定义颜色colors : []struct{ R, G, B float64 }{{0.8, 0.2, 0.2}, // 红色{0.2, 0.8, 0.2}, // 绿色{0.2, 0.2, 0.8}, // 蓝色{0.8, 0.8, 0.2}, // 黄色{0.8, 0.2, 0.8}, // 紫色{0.2, 0.8, 0.8}, // 青色{0.8, 0.8, 0.8}, // 灰色}// 加载自定义字体if err : dc.LoadFontFace(_examples/word-template/msyh.ttf, 12); err ! nil {return nil, nil}// 绘制柱状图for i, d : range data {x : 50 float64(i)*(barWidthbarSpacing) // x轴起始位置y : height - 50 - (d.value / maxValue * (height - 100)) // y轴起始位置减去柱子的高度color : colors[i%len(colors)] // 循环使用颜色dc.SetRGB(color.R, color.G, color.B)dc.DrawRectangle(x, y, barWidth, (d.value / maxValue * (height - 100)))dc.Fill()}// 绘制坐标轴dc.SetRGB(0, 0, 0) // 黑色dc.DrawLine(50, height-50, width-50, height-50) // X轴dc.DrawLine(50, height-50, 50, 50) // Y轴dc.Stroke()// 添加横坐标标签for i, d : range data {dc.DrawStringAnchored(d.label, 50float64(i)*(barWidthbarSpacing)barWidth/2, height-30, 0.5, 1)}// 添加纵坐标标签for i : 0; i int(maxValue); i 5 {y : height - 50 - (float64(i) / maxValue * (height - 100))dc.DrawStringAnchored(fmt.Sprintf(%d, int(i)), 30, y, 1, 0.5)}// 将图表保存到缓冲区var buf bytes.Bufferif err : dc.EncodePNG(buf); err ! nil {return nil, err}return buf, nil
}// 创建饼图并将其存储到缓存中
func createPieChart() (*bytes.Buffer, error) {const (width 640height 600radius 200 // 半径)dc : gg.NewContext(width, height)dc.SetRGB(1, 1, 1) // 背景色为白色dc.Clear()data : []struct {label stringvalue float64}{{身份证, 15}, {电话号码, 20}, {地址信息, 25}, {银行卡号, 30}, {财务数据, 35}, {基础信息, 40}, {户籍信息, 45},}colors : []struct{ R, G, B float64 }{{0.9, 0.3, 0.3}, // 红色{0.3, 0.9, 0.3}, // 绿色{0.3, 0.3, 0.9}, // 蓝色{0.9, 0.9, 0.3}, // 黄色{0.9, 0.3, 0.9}, // 紫色{0.3, 0.9, 0.9}, // 青色{0.9, 0.6, 0.3}, // 橙色}// 设置字体选择支持中文的字体if err : dc.LoadFontFace(_examples/word-template/msyh.ttf, 12); err ! nil {return nil, nil}var total float64for _, d : range data {total d.value}startAngle : -math.Pi / 2 // 从顶部开始绘制for i, d : range data {percentage : d.value / totalangle : percentage * 2 * math.Pi// 设置扇形颜色color : colors[i%len(colors)]dc.SetRGB(color.R, color.G, color.B)dc.DrawArc(width/2, height/2, radius, startAngle, startAngleangle)dc.LineTo(width/2, height/2)dc.Fill()// 计算标签位置midAngle : startAngle angle/2labelX : width/2 (radius20)*math.Cos(midAngle)labelY : height/2 (radius20)*math.Sin(midAngle)// 绘制标签和数据labelText : fmt.Sprintf(%s: %.0f, d.label, d.value)dc.SetRGB(0, 0, 0) // 文字颜色黑色dc.DrawStringAnchored(labelText, labelX, labelY, 0.5, 0.5)startAngle angle}// 将图表保存到缓冲区var buf bytes.Bufferif err : dc.EncodePNG(buf); err ! nil {return nil, err}return buf, nil
}The end …