Golang处理Word文档模板实现标签填充|表格插入|图标绘制和插入|删除段落|删除标签

本教程主要实现【Golang处理Word文档模板实现标签填充|表格插入|图标绘制和插入|删除段落|删除标签】。
本文源码:https://gitee.com/songfayuan/go-zero-demo
教程源码分支:master 分支(_examples/word-template/fill-word-template.go)

Golang处理Word文档模板教程

本教程将指导您使用Golang处理Word文档模板,包括自定义标签填充、动态插入表格、绘制图表和插入图表。我们将使用unioffice库和gg库来完成这些任务。

前提条件

在开始之前,请确保您已安装以下库:

  1. unioffice
  2. gg

您可以使用以下命令安装这些库:

go get -u github.com/Esword618/unioffice
go get -u github.com/fogleman/gg

代码结构

我们的代码分为以下几部分:

  1. 打开Word文档
  2. 填充模板中的变量
  3. 在指定标签处插入表格
  4. 创建折线图并保存为图片
  5. 在指定标签处插入图表
  6. 保存更新后的文档

示例代码

以下是完整的示例代码:

package mainimport ("fmt""log""math""strings""github.com/Esword618/unioffice/color""github.com/Esword618/unioffice/common""github.com/Esword618/unioffice/document""github.com/Esword618/unioffice/measurement""github.com/Esword618/unioffice/schema/soo/wml""github.com/fogleman/gg"
)//教程:https://blog.csdn.net/u011019141/article/details/140788882func main() {// 定义文档路径和图表文件路径docPath := "_examples/word-template/template.docx"lineChartFile := "/Users/songfayuan/Downloads/line_chart.PNG"barChartFile := "/Users/songfayuan/Downloads/bar_chart.png"pieChartFile := "/Users/songfayuan/Downloads/pie_chart.png"updatedDocPath := "/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", i+1, j+1))}}//分隔不同表格//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", i+1, j+1))}}// 移除标签段落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)*(barWidth+20)                       // 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, 50+float64(i)*(barWidth+20), 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)*(barWidth+barSpacing)               // 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, 50+float64(i)*(barWidth+barSpacing)+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, startAngle+angle)dc.LineTo(width/2, height/2)dc.Fill()// 计算标签位置midAngle := startAngle + angle/2labelX := width/2 + (radius+20)*math.Cos(midAngle)labelY := height/2 + (radius+20)*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文件
}

解释

  1. 打开文档

    doc, err := openDocument(docPath)
    

    使用unioffice库打开指定路径的Word文档。

  2. 填充模板中的变量

    fillTemplate(doc, map[string]string{"{{TASK_NAME}}": "任务名称示例","{{DETAILS}}":   "详细信息示例",
    })
    

    遍历文档中的每个段落和运行(文本片段),如果文本包含占位符,将其替换为实际值。

  3. 在指定标签处插入表格

    if err := insertTableAt(doc, "{{biaoge}}"); err != nil {log.Fatalf("插入表格时出错: %v", err)
    }
    

    查找包含指定标签的段落,在该段落之后插入表格并删除标签段落。

  4. 创建折线图并保存为图片

    if err := createLineChart(chartFile); err != nil {log.Fatalf("创建图表时出错: %v", err)
    }
    

    使用gg库绘制折线图并保存为PNG文件。

  5. 在指定标签处插入图表

    if err := insertImageAt(doc, chartFile, "{{tubiao}}"); err != nil {log.Fatalf("插入图表时出错: %v", err)
    }
    

    查找包含指定标签的段落,在该段落之后插入图表并删除标签段落。

  6. 保存更新后的文档

    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 ("bytes""fmt""log""math""strings""github.com/Esword618/unioffice/color""github.com/Esword618/unioffice/common""github.com/Esword618/unioffice/document""github.com/Esword618/unioffice/measurement""github.com/Esword618/unioffice/schema/soo/wml""github.com/fogleman/gg"
)//教程:https://blog.csdn.net/u011019141/article/details/140788882func main() {// 定义文档路径和图表文件路径docPath := "_examples/word-template/template.docx"updatedDocPath := "/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", i+1, j+1))}}//分隔不同表格//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", i+1, j+1))}}// 移除标签段落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)*(barWidth+20)                       // 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, 50+float64(i)*(barWidth+20), 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)*(barWidth+barSpacing)               // 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, 50+float64(i)*(barWidth+barSpacing)+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, startAngle+angle)dc.LineTo(width/2, height/2)dc.Fill()// 计算标签位置midAngle := startAngle + angle/2labelX := width/2 + (radius+20)*math.Cos(midAngle)labelY := height/2 + (radius+20)*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 …

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/390786.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win 10 局域网共享

1&#xff0c;打开共享 控制面板\网络和 Internet\网络和共享中心\高级共享设置 &#xff08;在控制面板界面建议使用大图片或小图标容易找到目标&#xff09; 或者直接复制红色部分&#xff0c;然后打开此电脑&#xff0c;粘贴到地址栏直接回车即可直接到达几面 打开如下2个…

达梦数据库一体机在宜昌市财政局上线了!

财政作为国家治理的基础和重要支柱&#xff0c;其数字化转型已成为构建现代财政制度的必由之路&#xff0c;引领着财政管理体系向更高效、更智能的方向迈进。 达梦数据全面助力财政信息化转型与智能化发展&#xff0c;采用 DAMEGN PAI I 系列数据库一体机&#xff0c;为宜昌市财…

Unity Camera

课程目标 1. 了解摄像机&#xff08;camera&#xff09;不同视角的设计与实现&#xff1b;2. 感受在不同摄像机视角下观察虚拟场景。 喜欢玩游戏或者看3D动漫的朋友可以回忆在虚拟场景中摄像头的运动变化带来的视觉感受&#xff0c;例如&#xff1a;摄像头给场景中的主角来个…

马来西亚原生静态IP注册的账号稳定吗?

马来西亚作为东南亚重要的经济体之一&#xff0c;其网络基础设施和互联网服务水平在近年来有了显著提升。静态IP作为一种固定的互联网协议地址&#xff0c;对于某些特定的网络应用和需求非常重要。本文将围绕马来西亚原生静态IP注册的账号稳定性进行探讨&#xff0c;分析其在不…

【Python系列】Python 字典合并

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

pytorch基础模块:Tensorboard、Dataset、Transforms、Dataloader

Tensorboard、Dataset、Transforms、Dataloader 该文档主要参考【土堆】的视频教程&#xff1a;pytorch入门教程–土堆 一、Tensorboard 安装tensorboard&#xff1a;pip install tensorboard 使用步骤&#xff1a; 引入相关库&#xff1a;from torch.utils.tensorboard i…

LinkedList接口源码解读

LinkedList 接口源码解读&#xff08;一&#xff09; 前言 因为追求质量&#xff0c;所以写的较慢。大概在接下来的三天内会把LinkedList源码解析出完。大概还有两篇文章。废话不多说&#xff0c;正片开始&#xff01; 大家都知道&#xff0c;LinkedList是在Java底层中是由 …

手机上音乐如何转换成MP3格式?分享5款音频格式转换APP

手机上音乐如何转换成MP3格式&#xff1f;相信很多外出办公或者不经常使用电脑的工作人士&#xff0c;学生党&#xff0c;媒体从业者都有这样的疑惑和需求。不同设备和应用可能支持不同的音频格式&#xff0c;导致某些情况下需要将音乐文件转换为MP3格式以确保兼容性。下面&…

操作系统|day4.Linux、Linux内核、Linux负载、Linux文件存储

文章目录 LinuxLinux内核定义功能态 Linux负载定义 Linux文件存储链接分类区别使用场景 拷贝 Linux Linux内核 定义 内核是操作系统的核心&#xff0c;具有很多最基本功能&#xff0c;它负责管理系统的进程、内存、设备驱动程序、文件和网络系统&#xff0c;决定着系统的性能…

.NET周刊【7月第4期 2024-07-28】

国内文章 .NET 高性能缓冲队列实现 BufferQueue https://mp.weixin.qq.com/s/fUhJpyPqwcmb3whuV3CDyg BufferQueue 是一个用 .NET 编写的高性能的缓冲队列实现&#xff0c;支持多线程并发操作。 项目地址&#xff1a;https://github.com/eventhorizon-cli/BufferQueue 项目…

【虚拟仿真】Unity3D中实现2DUI显示在3D物体旁边

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 这篇文章来实现2DUI显示在3D物体旁边,当我们需要在3D模型旁边显示2DUI的时候,比如人物的对…

grep工具的使用

grep [options]…… pattern [file]…… 工作方式&#xff1a; grep 在一个或者多个文件中搜索字符串模板&#xff0c;如果模板中包括空格&#xff0c;需要使用引号引起来&#xff0c;模 板后的所有字符串会被看作是文件名。 工作结果&#xff1a;如果模板搜索成功&#xf…

Springboot+Vue在线水果(销售)商城管理系统-附源码与配套论文

1.1 研究背景 互联网概念的产生到如今的蓬勃发展&#xff0c;用了短短的几十年时间就风靡全球&#xff0c;使得全球各个行业都进行了互联网的改造升级&#xff0c;标志着互联网浪潮的来临。在这个新的时代&#xff0c;各行各业都充分考虑互联网是否能与本行业进行结合&#xf…

Java:进程和线程

文章目录 进程线程的概念和区别总结如何创建线程1.继承Thread重写run2.实现Runnable重写run3.继承Thread重写run,通过匿名内部类来实现4. 实现Runnable重写run,通过匿名内部类来实现5.基于lambda表达式来创建 虚拟线程 并发编程: 通过写特殊的代码&#xff0c;把多个CPU核心都利…

Shell编程 --基础语法(1)

文章目录 Shell编程基础语法变量定义变量使用变量命令的使用只读变量删除变量 传递参数字符串获取字符串长度字符串截取 数组定义方式关联数组获取数组的长度 总结 Shell编程 Shell是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命令或者自动地解…

【人工智能基础三】卷积神经网络基础(CNN)

文章目录 1. 卷积神经网络结构2. 卷积神经网络计算2.1. 卷积层计算2.2. 池化层计算2.3. 全连接层计算 3. 典型卷积神经网络3.1. AlexNet3.2. VGGnet 卷积神经网络(Convolutional Neural Network&#xff0c;CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(Feedforward Ne…

计算机毕业设计Python+Tensorflow股票推荐系统 股票预测系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

1、用pycharm打开项目&#xff0c;一定要打开包含manage.py文件所在文件夹 2、配置解释器&#xff1a;建议使用Anaconda(Python 3.8(base))&#xff0c;低于3.8版本的&#xff0c;页面会不兼容 3、安装依赖库&#xff1a;打开pycharm的终端&#xff0c;输入&#xff1a; pip in…

Docker-学习笔记(借助宝塔面板)

ubuntu环境 一、安装 可以参考官网进行或其他博客进行安装 1.进入宝塔面板 进图Docker菜单&#xff0c;查看是否提示安装。 2.查看是否安装 查看版本 docker -v 证明已经安装 二、常用命令 1.查看版本 docker -v 2.启动、停止、重启docker systemctl start docker…

自制安卓车机软件(含APP)

本软件使用APPinventor2编程软件&#xff0c;耗时5天和3天调试&#xff0c;具有高德导航&#xff0c;视频播放&#xff0c;网易云音乐&#xff0c;酷狗&#xff0c;抖音&#xff0c;&#xff08;需下载车机版软件&#xff09;和自定义添加软件&#xff0c;网页有哔哩哔哩&#…

无人机工程师技术高级证书详解

随着无人机技术的飞速发展&#xff0c;其在航拍、农业、测绘、救援、物流等多个领域的应用日益广泛&#xff0c;对无人机工程师的专业技能与综合素质提出了更高要求。无人机工程师技术高级证书&#xff0c;作为对无人机领域高级工程师专业技能的权威认证&#xff0c;不仅是对个…