[go]gg库绘图与添加文字


gg库是一个功能强大的图片处理库,提供了画圆、画方、画线、填充、描边、旋转、缩放、文字处理、剪切、蒙版、翻转的接口。

gg库

要使用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

在使用库前,需要先创建一个context:

NewContext(width, height int) *Context
NewContextForImage(im image.Image) *Context
NewContextForRGBA(im *image.RGBA) *Context

Draw函数

一系列常见图形函数:

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函数后,才会使用当前设定(颜色、线宽等)完成实际的画图动作。

Text函数

在图片上添加文字:

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

Color函数

设定颜色的函数:

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注释掉,则:

  • 蓝色的线将不会画出:因Fill-2会填充所有闭合路径后,清除路径信息;
  • 蓝色的矩形框会变为填充红色的矩形;
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(绕指定点):

  • 旋转是顺时针方向;
  • 参数是弧度,需要通过Radians把角度转换为弧度;
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)可方便地绘制文本:

  • 默认为左对齐;
  • 坐标点(x,y)为文本框的左下角位置:所以在左上角上绘制时坐标为(0, dc.FontHeight())

通过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为文本的宽、高):

  • 具体显示位置为:(x-wax, y+hay);
  • 左对齐为:(0, dc.FontHeight(), 0, 0)
  • 居中对齐为:(float64(width/2), float64(height/2), 0.5, 0.5)
  • 右对齐为:(float64(width), float64(height), 1, 0)
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)折行显示:

  • width为显示文本框的宽度;
  • lineSpacing为行高:多少个字体高度,实际行高为lineSpacing*dc.FontHeight()
  • align为文本在文本框中对齐方式
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")
}

样例显示:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值