go根据传入的表头和表内容及文字描述生成base64图片

go根据传入的表头和表内容及文字描述生成base64图片

package table2base64

import (
"bytes"
"encoding/base64"
"image"
"image/color"
"image/draw"
"image/png"
"io"
"math/rand"
"os"
"strconv"
"time"

"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
"icode.baidu.com/baidu/gdp/env"
)

const (
DefaultClosWidth      int = 103 //默认列宽
DefaultRowsHeight     int = 36  //默认行高
DefaultTextRowsHeight int = 20  //默认文字描述行高
)

var (
DefaultTTFFile     = ""
DefaultTTFFileBOLD = ""
)

// 初始化函数
func init() {
DefaultTTFFile = env.ConfDir() + "/SIMYOU.TTF"
DefaultTTFFileBOLD = env.ConfDir() + "/FZBOLD.TTF"
}

type DrawString interface {
string() string
}

// TabString 自定义字符串类型
type TabString string

// string 方法返回字符串 s 的值
func (s TabString) string() string {
return string(s)
}

// TabNumber 自定义数值类型
type TabNumber float64

// string 方法返回 TabNumber 类型的字符串表示形式
func (n TabNumber) string() string {
return strconv.FormatFloat(float64(n), 'f', -1, 64)
}

type TableContent [][]DrawString
type TableImg struct {
TTFFile        string          //字体文件路径
TTFFILEBold    string          //字体文件路径(粗体)
Header         []string        //表格头
Content        [][]interface{} //外部初始化表格内容
TextDesc       []string        //文字描述
ClosWidth      int             //列宽
RowsHeight     int             //行高
TextRowsHeight int             //文字描述行高

selfContent TableContent //内部使用表格内容
imgWidth    int          //图片宽
tableHeight int          //表格高
imgHeight   int          //图片高
cols        int          //列数
rows        int          //行数
base64Str   string       //base64数据
img         *image.RGBA  //图像资源对象
}

// NewTableImg 返回一个TableImg对象
func NewTableImg(tab *TableImg) *TableImg {
var c TableContent
for _, con := range tab.Content {
var cSlice []DrawString
for _, cc := range con {
value := convertToDrawValue(cc)
cSlice = append(cSlice, value)
}
c = append(c, cSlice)
}
if tab.TTFFile == "" {
tab.TTFFile = DefaultTTFFile
}
if tab.TTFFILEBold == "" {
tab.TTFFILEBold = DefaultTTFFileBOLD
}
return &TableImg{
TTFFile:        tab.TTFFile,
TTFFILEBold:    tab.TTFFILEBold,
Header:         tab.Header,
Content:        tab.Content,
ClosWidth:      tab.ClosWidth,
RowsHeight:     tab.RowsHeight,
TextDesc:       tab.TextDesc,
TextRowsHeight: tab.TextRowsHeight,

selfContent: c,
imgWidth:    tab.ClosWidth * len(tab.Header),
tableHeight: tab.RowsHeight * (len(tab.Content) + 1),
imgHeight:   tab.RowsHeight*(len(tab.Content)+1) + tab.TextRowsHeight*(len(tab.TextDesc)+1),
cols:        len(tab.Header),
rows:        len(tab.Content) + 1,
base64Str:   "",
img:         nil,
}
}

// convertToDrawValue 将一个输入转换为DrawString类型的值
func convertToDrawValue(cc interface{}) DrawString {
var value DrawString
switch v := cc.(type) {
case int:
value = TabNumber(v)
case int8:
value = TabNumber(v)
case int16:
value = TabNumber(v)
case int32:
value = TabNumber(v)
case int64:
value = TabNumber(v)
case float32:
value = TabNumber(v)
case float64:
value = TabNumber(v)
case string:
value = TabString(v)
default:
value = TabString("")
}
return value
}

// GenerateImageGetBase64 生成表格图片并返回base64
func (tab *TableImg) GenerateImageGetBase64() (string, error) {
cols := len(tab.Header)
rows := len(tab.Content) + 1
// 创建一个新的 RGBA 图片
tab.img = image.NewRGBA(image.Rect(0, 0, tab.imgWidth, tab.imgHeight))

// 以白色作为背景绘制整个图片
draw.Draw(tab.img, tab.img.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src)

//填充表头背景色
fillArea := image.Rect(0, 0, tab.imgWidth, tab.RowsHeight)
draw.Draw(tab.img, fillArea, &image.Uniform{color.RGBA{162, 206, 232, 255}}, image.Point{0, 0}, draw.Src)

randSource := rand.NewSource(time.Now().UnixNano())
r := rand.New(randSource)
for i := 1; i < rows; i += 3 {
fillArea := image.Rect(0, tab.RowsHeight*(i+2), tab.imgWidth, tab.RowsHeight*(i+3))
draw.Draw(tab.img, fillArea, &image.Uniform{color.RGBA{uint8(r.Intn(100) + 150),
uint8(r.Intn(100) + 150), uint8(r.Intn(100) + 150), 255}}, image.Point{0, 0}, draw.Src)
}
//绘制表格线
for i := 0; i <= cols; i++ {
x := i * (tab.imgWidth / cols)
if x >= tab.imgWidth {
x = tab.imgWidth - 1
}
tab.drawLine(x, 0, x, tab.tableHeight, color.RGBA{123, 123, 123, 255})
}
for i := 0; i <= rows; i++ {
y := i * (tab.tableHeight / rows)
if y >= tab.tableHeight {
y = tab.tableHeight - 1
}
tab.drawLine(0, y, tab.imgWidth, y, color.RGBA{123, 123, 123, 255})
}

f, err := os.OpenFile(tab.TTFFile, os.O_RDONLY, 0644) // 0644表示文件权限
if err != nil {
return "", err
}
defer f.Close()
byteFile, _ := io.ReadAll(f)

fBold, err := os.OpenFile(tab.TTFFILEBold, os.O_RDONLY, 0644) // 0644表示文件权限
if err != nil {
return "", err
}
defer fBold.Close()
byteFileBold, _ := io.ReadAll(fBold)
// 在图片上绘制内容
// 绘制 header 中的内容
for i, h := range tab.Header {
if err := tab.drawText(h, (tab.imgWidth/cols)*i+10, 20, byteFile); err != nil {
return "", err
}

}
// 绘制 content 中的内容
for i, c := range tab.selfContent {
bFile := byteFile
if i >= len(tab.selfContent)-3 {
bFile = byteFileBold
}
y := (tab.tableHeight/rows)*(i+1) + 20
for j, item := range c {
x := (tab.imgWidth/cols)*j + 10
if err := tab.drawText(item.string(), x, y, bFile); err != nil {
return "", err
}
}
}
// 绘制 文字描述 中的内容
for i, c := range tab.TextDesc {
y := (tab.tableHeight/rows)*(len(tab.selfContent)+1) + 20
y += i * tab.TextRowsHeight
if err := tab.drawText(c, 10, y, byteFile); err != nil {
return "", err
}
}

// 创建一个内存缓冲区
var buf bytes.Buffer
// 将图片编码为 PNG 格式并写入缓冲区
err = png.Encode(&buf, tab.img)
if err != nil {
return "", err
}
// 将 PNG 图片转换为 base64 编码的字符串
tab.base64Str = base64.StdEncoding.EncodeToString(buf.Bytes())

return tab.base64Str, nil
}

// drawText 方法绘制文本到图像上
func (tab *TableImg) drawText(text string, x, y int, fileByte []byte) error {
col := color.RGBA{A: 255}
point := image.Point{X: x, Y: y}
ff, _ := truetype.Parse(fileByte)
drawer := &font.Drawer{
Dst: tab.img,
Src: image.NewUniform(col),
Face: truetype.NewFace(ff, &truetype.Options{
Size: 14,
}),
Dot: fixed.P(point.X, point.Y),
}
drawer.DrawString(text)
return nil
}

// drawLine 函数绘制一条直线。
// x0,y0,x1和y1表示起点和终点的坐标值,c为直线颜色。
func (tab *TableImg) drawLine(x0, y0, x1, y1 int, c color.Color) {
dx := abs(x1 - x0)
dy := abs(y1 - y0)
sx, sy := 1, 1
if x0 > x1 {
sx = -1
}
if y0 > y1 {
sy = -1
}
err := dx - dy

for {
tab.img.Set(x0, y0, c)
if x0 == x1 && y0 == y1 {
break
}
e2 := 2 * err
if e2 > -dy {
err -= dy
x0 += sx
}
if e2 < dx {
err += dx
y0 += sy
}
}
}

// abs 函数返回输入整数的绝对值。
func abs(x int) int {
if x < 0 {
return -x
}
return x
}

用法

base64, _ := table2base64.NewTableImg(&table2base64.TableImg{
Header:         header,
Content:        data,
ClosWidth:      115,
TextDesc:       text,
TextRowsHeight: table2base64.DefaultTextRowsHeight,
RowsHeight:     table2base64.DefaultRowsHeight,
TTFFile:        table2base64.DefaultTTFFile,
}).GenerateImageGetBase64()


最后编辑于:2024/01/04作者: 牛逼PHP

发表评论