要使用gg库,需要先安装go get -u github.com/fogleman/gg。对应的接口说明文档https://pkg.go.dev/github.com/fogleman/gg。
如:通过椭圆画花:
import "github.com/fogleman/gg"
func drawFlower() {
const S = 1024
dc := gg.NewContext(S, S)
dc.SetRGBA(0, 0, 0, 0.1)
for i := 0; i < 360; i += 15 {
dc.Push()
dc.RotateAbout(gg.Radians(float64(i)), S/2, S/2)
dc.DrawEllipse(S/2, S/2, S*7/16, S/8)
dc.Fill()
dc.Pop()
}
dc.SavePNG("D:\\temp\\out.png")
}
在使用库前,需要先创建一个context:
NewContext(width, height int) *Context
NewContextForImage(im image.Image) *Context
NewContextForRGBA(im *image.RGBA) *Context
一系列常见图形函数:
DrawPoint(x, y, r float64)
DrawLine(x1, y1, x2, y2 float64)
DrawRectangle(x, y, w, h float64)
DrawRoundedRectangle(x, y, w, h, r float64)
DrawCircle(x, y, r float64)
DrawArc(x, y, r, angle1, angle2 float64)
DrawEllipse(x, y, rx, ry float64)
DrawEllipticalArc(x, y, rx, ry, angle1, angle2 float64)
DrawRegularPolygon(n int, x, y, r, rotation float64)
DrawImage(im image.Image, x, y int)
DrawImageAnchored(im image.Image, x, y int, ax, ay float64)
SetPixel(x, y int)
MoveTo(x, y float64)
LineTo(x, y float64)
QuadraticTo(x1, y1, x2, y2 float64)
CubicTo(x1, y1, x2, y2, x3, y3 float64)
ClosePath()
ClearPath()
NewSubPath()
Clear() // Fill entire image with current color
Stroke()
Fill()
StrokePreserve()
FillPreserve()
DrawXXX函数只是创建了一系列的路径,只有调用Stoke函数后,才会使用当前设定(颜色、线宽等)完成实际的画图动作。
在图片上添加文字:
DrawString(s string, x, y float64)
DrawStringAnchored(s string, x, y, ax, ay float64)
DrawStringWrapped(s string, x, y, ax, ay, width, lineSpacing float64, align Align)
MeasureString(s string) (w, h float64)
MeasureMultilineString(s string, lineSpacing float64) (w, h float64)
WordWrap(s string, w float64) []string
SetFontFace(fontFace font.Face)
LoadFontFace(path string, points float64) error
设定颜色的函数:
SetRGB(r, g, b float64)
SetRGBA(r, g, b, a float64)
SetRGB255(r, g, b int)
SetRGBA255(r, g, b, a int)
SetColor(c color.Color)
SetHexColor(x string)
设定线与填充:
SetLineWidth(lineWidth float64)
SetLineCap(lineCap LineCap)
SetLineJoin(lineJoin LineJoin)
SetDash(dashes ...float64)
SetDashOffset(offset float64)
SetFillRule(fillRule FillRule)
设定渐变与样式
SetFillStyle(pattern Pattern)
SetStrokeStyle(pattern Pattern)
NewSolidPattern(color color.Color)
NewLinearGradient(x0, y0, x1, y1 float64)
NewRadialGradient(x0, y0, r0, x1, y1, r1 float64)
NewSurfacePattern(im image.Image, op RepeatOp)
各转换函数:
Identity()
Translate(x, y float64)
Scale(x, y float64)
Rotate(angle float64)
Shear(x, y float64)
ScaleAbout(sx, sy, x, y float64)
RotateAbout(angle, x, y float64)
ShearAbout(sx, sy, x, y float64)
TransformPoint(x, y float64) (tx, ty float64)
InvertY()
裁剪相关函数:
Clip() // 更新裁剪区:更新为,当前Path范围与裁剪区的交集
ClipPreserve()
ResetClip()
AsMask() *image.Alpha
SetMask(mask *image.Alpha)
InvertMask()
Radians(degrees float64) float64
Degrees(radians float64) float64
LoadImage(path string) (image.Image, error)
LoadPNG(path string) (image.Image, error)
SavePNG(path string, im image.Image) error
保存当前context的状态:
Push()
Pop()
在使用库之前需要先初始化一个Context对象。
通过draw函数画图时,只有调用Stroke(或Fill)函数后,才会真正画(使用当前设置);
如:画一条蓝色的线,边框为蓝色的矩形;以及一条红色的线,填充为红色的矩形。
若把Stroke-1处的Stoke注释掉,则:
func drawShapes() {
width := 300
height := 300
dc := gg.NewContext(width, height)
// blue line
pos := 50.0
dc.SetRGB255(0, 0, 255)
dc.SetLineWidth(3)
dc.DrawRectangle(10, 190, 100, 100)
//dc.Fill()
dc.DrawLine(0, pos, float64(width), pos)
dc.Stroke() // Stroke-1
// red line
pos += 100
dc.SetRGB255(255, 0, 0)
dc.SetLineWidth(2)
dc.DrawRectangle(150, 190, 100, 100)
dc.Fill() // Fill-2
dc.DrawLine(0, pos, float64(width), pos)
dc.Stroke()
dc.SavePNG("D:\\temp\\out.png")
}
输出的图片样式:

裁剪图片为圆形:
func drawCircleImg() {
img, err := gg.LoadImage("D:\\temp\\tmp.jpg")
if err != nil {
panic(err)
}
dc := gg.NewContext(img.Bounds().Dx(), img.Bounds().Dy())
// 画圆形
radius := math.Min(float64(img.Bounds().Dx()), float64(img.Bounds().Dy())) / 2
dc.DrawCircle(float64(img.Bounds().Dx()/2), float64(img.Bounds().Dy()/2), radius)
// 对画布进行裁剪
dc.Clip()
dc.DrawImage(img, 0, 0)
dc.SavePNG("D:\\temp\\out.png")
}
旋转使用Rotate()(绕左上角) 或 RotateAbout(绕指定点):
func rotateImage() {
img, err := gg.LoadImage("D:\\temp\\tmp.jpg")
if err != nil {
panic(err)
}
width := 2 * img.Bounds().Dx()
height := 2 * img.Bounds().Dy()
dc := gg.NewContext(width, height)
dc.DrawRectangle(0, 0, float64(width), float64(width))
dc.SetRGB255(0, 255, 0)
dc.Fill()
dc.RotateAbout(gg.Radians(45), float64(width/2), float64(height/2))
dc.DrawImage(img, width/4, height/4)
dc.SavePNG("D:\\temp\\out.png")
}
输出样例图片:

gg中默认字体为basicfont.Face7x13,可修改为合适的字体与大小。
设定24号字体,且默认颜色为蓝色:
import (
"github.com/fogleman/gg"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font/gofont/goregular"
)
func initTextContext(w, h int) *gg.Context {
dc := gg.NewContext(w, h)
dc.DrawRectangle(0, 0, float64(w), float64(h))
dc.SetRGB255(245, 245, 245)
dc.Fill()
dc.SetRGB255(0, 0, 255)
font, err := truetype.Parse(goregular.TTF)
if err != nil {
log.Fatal(err)
}
face := truetype.NewFace(font, &truetype.Options{Size: 24})
dc.SetFontFace(face)
return dc
}
通过DrawString(s string, x, y float64)可方便地绘制文本:
通过MeasureString可计算要绘制文本的宽、高。
func drawText() {
width := 300
height := 300
dc := gg.NewContext(width, height)
dc.DrawRectangle(0, 0, float64(width), float64(width))
dc.SetRGB255(245, 245, 245)
dc.Fill()
dc.SetRGB255(0, 0, 255)
pos := dc.FontHeight()
text := "Hello World!"
dc.DrawString(text, 0, pos)
// set font
font, err := truetype.Parse(goregular.TTF)
if err != nil {
log.Fatal(err)
}
face := truetype.NewFace(font, &truetype.Options{Size: 24})
dc.SetFontFace(face)
pos += 50
dc.DrawString(text, 10, pos)
// center align
sW, sH := dc.MeasureString(text)
dc.DrawString(text, (float64(width)-sW)/2, (float64(height)-sH)/2)
// bottom
//dc.DrawString(text, 0, float64(height)-dc.FontHeight())
dc.DrawString(text, 0, float64(height))
dc.SavePNG("D:\\temp\\text.png")
}
样例显示:

通过计算,可设定文本的对齐方式,但太麻烦;可通过DrawStringAnchored(s string, x, y, ax, ay float64)设定文本的对齐方式(w、h为文本的宽、高):
func drawAlignText() {
width := 300
height := 300
dc := initTextContext(width, height)
text := "Hello World!"
dc.DrawStringAnchored(text, 0, dc.FontHeight(), 0, 0)
// center
dc.DrawStringAnchored(text, float64(width/2), float64(height/2), 0.5, 0.5)
// right
//dc.DrawStringAnchored(text, float64(width), float64(height)-dc.FontHeight(), 1, 1)
dc.DrawStringAnchored(text, float64(width), float64(height), 1, 0)
dc.SavePNG("D:\\temp\\text.png")
}
样例显示:

当文本内容过长时,需要通过DrawStringWrapped(s string, x, y, ax, ay, width, lineSpacing float64, align Align)折行显示:
lineSpacing*dc.FontHeight();func drawMultiLine() {
width := 300
height := 300
dc := initTextContext(width, height)
text := "Hello World! Hello World2! Hello World3!"
dc.DrawStringWrapped(text, float64(width/2), float64(height/2), 0.5, 0.5,
float64(width/2), 1.5, gg.AlignLeft)
dc.SavePNG("D:\\temp\\text.png")
}
样例显示:
