文章目录

  • 概述
  • 基本使用
  • 基本概念
  • 基本底层操作
  • 具体操作:
    • 示例1:画圆
    • 示例2:画带边框的矩形
    • 示例3:贴图片文件
    • 示例4:贴文字
    • 示例5:半透明+缩放贴图
  • 备注

概述

最近的项目中需要用代码来手工绘图,例如设置背景图片、贴矩形、贴文字至指定位置等等,但是标准库中的image包又有些偏向底层了,于是想找一个go语言中可用性较高的2D渲染绘图封装库,寻找了一番,个人感觉最合适的便是fogleman/gg了:官方文档。

理解了gg包的一些基本概念之后,它还是很便于绘制2D图像的,预置了不少类似但不限于画圆、画方、画线、填充、描边、旋转、缩放、文字处理、剪切、蒙版、翻转的接口,那么,开始吧。

基本使用

如下代码:

package mainimport "github.com/fogleman/gg"func main() { dc := gg.NewContext(512, 512)dc.SetRGB255(255,222,173)dc.Clear()dc.SavePNG("out.png")
}

执行后,你便得到了一张黄图(纯黄色的图

解析

第一行,使用gg.NewContext创建了一个大小为512x512的画布dc。

第二行,通过dc.SetRGB255将当前画笔颜色设置为RGB 255,222,173,即黄色。

第三行,Clear方法将会使用当前画笔颜色填充满整个画布。

第四行,将画布保存成PNG格式图片。

基本概念

要想理解gg包的用法,首先要掌握一组基本概念,但此类内容网上又找不到任何参考资料,因此下述内容皆为我(RicheyJang)的个人理解,欢迎交流指正!

gg包的概念继承并改造于官方的freetype包,仅对于使用gg包来说,需要了解以下概念:

画布(Context):直译过来以及对于golang标准概念而言,它应该被成为上下文,但是为了便于理解,我称之为画布,是一张定义中、描绘中的图片。

路径(path):路径是一组子路径。

子路径(subpath):子路径是一个起点,加一组首尾相连的线性、二次或三次贝塞尔曲线(不一定闭合)。

当前路径(current path):当前正在定义(不一定已经真正画到画布上)的路径。

当前点(current point):画布上的一个点(像素点),标志了当前画笔所在的位置。也就是当前子路径的尾点。

基本底层操作

首先是直接针对路径的操作:

dc := gg.NewContext(w, h) // 创建宽为w、长为h的新画布。dc.Fill()
// Fill 将会使用当前画笔颜色填充满当前路径所闭合出的区域(当前路径中的各个子路径会被gg隐式闭合)。
dc.FillPreserve()
// FillPreserve 将会使用当前画笔颜色填充满当前路径所闭合出的区域(当前路径中的各个子路径会被gg隐式闭合)。
// 它与Fill方法的区别是,Fill将会一并删除当前路径,而FillPreserve不会。
dc.Stroke()
// Stroke 将会把当前路径使用当前画笔颜色描绘到画布上。
dc.StrokePreserve()
// StrokePreserve 它与Stroke方法的区别类比上述Fill与FillPreserve。

上述几个方法为非常常用的绘图方法,下面便是一些更偏底层的用于绘制路径本身的方法了。

dc.NewSubPath()
// NewSubPath 会在当前路径中新建一条子路径,会使得"当前点"不存在。
dc.ClearPath()
// ClearPath 将会清除当前路径。
dc.ClosePath()
// ClosePath 会添加一条起点为当前点、终点为当前子路径起点线性线段。用于显式地闭合当前子路径。
dc.MoveTo(x, y)
// MoveTo 会新建一条起点为(x,y)的子路径,并将当前点设为(x,y)。
dc.LineTo(x, y)
// LineTo 会向当前子路径添加一条起点为当前点、终点为(x,y)的线性线段,并将当前点设为(x,y)。若当前点不存在,它等同于MoveTo(x,y)。

不过,不会真有人直接只用上述路径操作来画图吧,那也太麻烦了(;´д`)ゞ。

gg包封装了一组以Draw打头的方法,用于便携地画出圆形、矩形、图像、文字等等路径或者贴图,不过此类内容,干说不如实操,请参阅后述具体操作章节。

接下来是一组针对画笔的操作:

dc.SetLineWidth(lineWidth)
// SetLineWidth 设置画笔宽度为lineWidth,会在Stroke时体现出来。
dc.SetFontFace(fontFace)
// SetFontFace 设置画笔字体为fontFace,fontFace为font.Face类型。
// 也可以使用LoadFontFace(path string, points float64)方法从本地路径加载字体文件。
dc.SetColor(c)
// SetColor 设置当前画笔颜色为c,c为color.Color类型。

关于设置画笔颜色,还有一系列封装方法,例如:(省略了dc.)

SetHexColor(x string)      // 使用Hex表达式,例如"#fafafa"
SetRGB(r, g, b float64)    // 使用RGB值,0<=r,g,b<=1
SetRGB255(r, g, b int)     // 更常用地,使用整数RGB值,0<=r,g,b<=255
SetRGBA(r, g, b, a float64)// 使用RGB值,a为不透明度,0<=r,g,b,a<=1

具体操作:

看了半天,怪累的,下面让我们进入实操环境叭!

示例1:画圆

package mainimport "github.com/fogleman/gg"func main() {dc := gg.NewContext(512, 512)dc.DrawCircle(250,250,200) // 添加一条以(250,250)为圆心、200为半径的圆形子路径dc.SetRGB255(255,222,173) // 设置画笔颜色为黄色dc.Fill() // 使用当前颜色(黄色)填充满当前路径(圆)所闭合出的区域dc.SavePNG("out.png")
}

另外,gg包中的坐标计算:(0,0)点位于画布的最左上角,横向为x轴,纵向为y轴。

效果:

示例2:画带边框的矩形

package mainimport "github.com/fogleman/gg"func main() {dc := gg.NewContext(512, 512)dc.DrawRectangle(50, 50, 300, 233) // 添加一条以(50,50)为左上点、宽300、长233的矩形子路径dc.SetLineWidth(5) // 设置画笔宽度为5像素dc.SetRGBA255(245,34,45, 255 / 2) // 设置画笔颜色为红色,且半透明dc.StrokePreserve() // 使用当前颜色(红)描出当前路径(矩形),但不删除当前路径dc.SetHexColor("#b7eb8f") // 设置画笔颜色为绿色dc.Fill() // 使用当前颜色(绿)填充满当前路径(矩形)所闭合出的区域dc.SavePNG("out.png")
}

效果:

示例3:贴图片文件

我们可以直接使用DrawImage(im image.Image, x, y int)方法来将一张已有图片贴到画布上,与上述内容不同的是,该方法不会描绘出一条新的子路径,而是将图片直接贴到画布上,这一点请注意。

package mainimport ("fmt""github.com/fogleman/gg"
)func main() {img,err := gg.LoadImage("./paimeng.jpeg") // gg包预置的将本地图片载入成image.Image结构的函数if err != nil {fmt.Println(err)return}dc := gg.NewContext(800, 800)dc.SetHexColor("#b7eb8f") // 设置画笔颜色为绿色dc.Clear() // 使用当前颜色(绿)填满画布,即设置背景色dc.DrawImage(img, 50,100) // 以(50,100)为左上角,贴入img图片dc.SavePNG("out.png")
}

效果:

默认的DrawImage(im image.Image, x, y int)方法,其定位方式为:图像的左上角位于画布上的(x,y)点。但有的时候,我们想让图像居中位置或右下角位于(x,y),此类情况无需我们自己进行计算,gg包已经考虑好了,使用DrawImageAnchored方法即可:

func (dc *Context) DrawImageAnchored(im image.Image, x, y int, ax, ay float64)

DrawImageAnchored方法会令图像的左上角位于 ( x − w ∗ a x , y − h ∗ a y ) (x - w * ax, y - h * ay) (x−w∗ax,y−h∗ay),其中,w、h分别为所贴入图像的宽和长。也就是说,当指定ax=ay=0.5时,图像的居中位置会位于(x,y),当ax=ay=1时,图像的右下角会位于(x,y),而对于DrawImage方法而言,其ax=ay=0。

示例4:贴文字

同贴图一样,贴文字也是会直接将文字贴入画布,而非绘制路径。

package mainimport ("github.com/fogleman/gg"
)func main() {S := float64(600)str :=
`一段挺长长长长长长长长长长长的文字
甚至还有换行`dc := gg.NewContext(int(S), int(S))dc.SetHexColor("#b7eb8f") // 设置画笔颜色为绿色dc.Clear() // 使用当前颜色(绿)填满画布,即设置背景色if err := dc.LoadFontFace("./zh-cn.ttf", 30); err != nil { // 从本地加载字体文件panic(err)}dc.SetRGB(0,0,0) // 设置画笔颜色为黑色sWidth, sHeight := dc.MeasureString(str)        // 测算字符串将在画布中占用的宽与长dc.DrawString(str, (S-sWidth)/2, (S+sHeight)/2) // 直接将文字贴入画布中// 文本框格式化文字,参见下方详解dc.DrawStringWrapped(str, S/2, S/2 + 100, 0.5, 0.5, S - 10, 1.3, gg.AlignCenter)dc.SavePNG("out.png")
}

效果:

代码中出现的DrawStringWrapped方法,通过类似文本框的方式,会自动地对要贴入的文字进行换行、偏移等操作。定义如下:

func (dc *Context) DrawStringWrapped(s string, x, y, ax, ay, width, lineSpacing float64, align Align)

其中,s为待贴入字符串;(x,y)为定位点,ax,ay参考上述DrawImageAnchored;lineSpacing为行距,例如,lineSpacing=1.3即为1.3倍行距,当其为0时,多行文字将重叠;align为对齐方式,包含AlignLeft、AlignCenter、AlignRight。

另外,代码中出现的MeatureString方法,它并不会对画布产生任何影响,只会测算字符串被放入画布后所会占用的宽度、高度;对于多行字符串,可以使用MeasureMultilineString方法:

func (dc *Context) MeasureMultilineString(s string, lineSpacing float64) (width, height float64)

示例5:半透明+缩放贴图

来个稍微复杂一点的。现在我需要读入一张未知尺寸的图片,作为一张即将生成的1024x1024大小图像的背景图,且需要将其设为半透明。也就是说,需要做的工作有:读入图片、缩放、设置不透明度、贴图。

上代码!

package mainimport ("fmt""image""image/color""github.com/fogleman/gg"
)// AdjustOpacity 将输入图像m的透明度变为原来的倍数。若原来为完成全不透明,则percentage = 0.5将变为半透明
func AdjustOpacity(m image.Image, percentage float64) image.Image {bounds := m.Bounds()dx := bounds.Dx()dy := bounds.Dy()newRgba := image.NewRGBA64(bounds)for i := 0; i < dx; i++ {for j := 0; j < dy; j++ {colorRgb := m.At(i, j)r, g, b, a := colorRgb.RGBA()opacity := uint16(float64(a) * percentage)v := newRgba.ColorModel().Convert(color.NRGBA64{R: uint16(r), G: uint16(g), B: uint16(b), A: opacity})_r, _g, _b, _a := v.RGBA()newRgba.SetRGBA64(i, j, color.RGBA64{R: uint16(_r), G: uint16(_g), B: uint16(_b), A: uint16(_a)})}}return newRgba
}func main() {bg, err := gg.LoadImage("./paimeng.jpeg")if err != nil {fmt.Println(err)return}bg = AdjustOpacity(bg, 0.5) // 设置不透明度S := 1024dc := gg.NewContext(S, S)sx := float64(S) / float64(bg.Bounds().Size().X) // 计算缩放倍率(宽)sy := float64(S) / float64(bg.Bounds().Size().Y) // 计算缩放倍率(长)// 设置背景dc.Scale(sx, sy) // 使画笔按倍率缩放dc.DrawImage(bg, 0, 0) // 贴图(会受上述缩放倍率影响)dc.SavePNG("out.png")
}

效果:

备注

如果后续此文有人看的话,我再更新一下gg包中的文字处理、剪切、蒙版、翻转、贝塞尔曲线等内容叭。

【Golang画图】2D渲染绘图库gg的概念与用法详解(一)相关推荐

  1. python【Matlibplot绘图库】-主要概念

    文章目录 1.概述 2.各函数含义 3.numpy处理数据 1.概述 Matplotlib的GitHub链接: https://github.com/matplotlib/matplotlibMatp ...

  2. plt.boxplot()函数绘制箱图、常用方法及含义详解

    1. 箱图含义 箱图是一中用于统计数据分布的统计图,也可以粗略地看出数据是否具有对称性,分布的分散程度等信息.箱图中的信息含义如下: 最下方的横线表示最小值 最上方的横线表示最大值 黑色空心圆圈表示异 ...

  3. Golang官方限流器的用法详解

    限流器是提升服务稳定性的非常重要的组件,可以用来限制请求速率,保护服务,以免服务过载.限流器的实现方法有很多种,常见的限流算法有固定窗口.滑动窗口.漏桶.令牌桶,我在前面的文章 「常用限流算法的应用场 ...

  4. golang包time用法详解

    在我们编程过程中,经常会用到与时间相关的各种务需求,下面来介绍 golang 中有关时间的一些基本用法,我们从 time 的几种 type 来开始介绍. 时间可分为时间点与时间段,golang 也不例 ...

  5. golang格式化输出-fmt包用法详解

    注意:我在这里给出golang查询关于包的使用的地址:https://godoc.org    声明: 此片文章并非原创,大多数内容都是来自:https://godoc.org/fmt,通过谷歌翻译进 ...

  6. golang:1.并发编程之互斥锁、读写锁详解

    本文转载自junjie,而后稍作修改. 一.互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段.它由标准库代码包sync中的Mutex结构体类型代表.sync.Mutex类型(确切地说,是 ...

  7. 海龟画图 python太阳花_python 简单的绘图工具turtle使用详解

    目录 1. 画布(canvas) 1.1 设置画布大小 2. 画笔 2.1 画笔的状态 2.2 画笔的属性 2.3 绘图命令 3. 命令详解 4. 绘图举例 4.1 太阳花 4.2 绘制小蟒蛇 4.3 ...

  8. python里自带的绘画库是_Python绘图Turtle库详解

    Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x.纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行 ...

  9. Golang 五种原子性操作的用法详解

    本文我们详细聊一下Go语言的原子操作的用法,啥是原子操作呢?顾名思义,原子操作就是具备原子性的操作... 是不是感觉说了跟没说一样,原子性的解释如下: 一个或者多个操作在 CPU 执行的过程中不被中断 ...

最新文章

  1. C02-程序设计基础提高班(C++)第7周上机任务-指针
  2. java的知识点30——设计模式
  3. php获取网站根目录
  4. Linux的Nginx报错emerg unknown directive stub_status in
  5. Alteral Max 10 FPGA 优点
  6. 现实生活中常用的动态路由—OSPF路由重分发
  7. zabbix-3.0.4安装部署
  8. Setup the FD.io Repository - Centos 7
  9. 【原译】汇编编程之:Hello World!详解- 好文!!!
  10. python f string_Python|f-string让我喜欢Python的原因之一
  11. CENTOS 7.0 安装discuz ,搭 mysql +php+apache 环境
  12. 机器学习第六回——无监督学习
  13. Macbookpro安装JDK8及环境配置
  14. 手把手教你实现——Python文字(汉字)转语音教程,举一反三~
  15. 省级-上市公司数字经济数据(2013-2020年)
  16. c语言 虚拟示波器软件下载,虚拟示波器
  17. BGI-College生信入门系列——3、数据库
  18. 解决IOS浏览器或者微信浏览器播放audio音效第二次播放不全
  19. 不是Nvidia(英伟达)显卡可以安装CUDA跑深度学习算法吗?
  20. 企业微信组织架构同步优化的思路

热门文章

  1. 用selenium登录百度网盘
  2. Spark学习笔记[1]-scala环境安装与基本语法
  3. 分享两个苹果cms10采集新闻和明星接口接口
  4. 【PM】从产品经理的角度探索游戏产品
  5. 搭建个人网站(2):Github和Vercel建站以及配置DNS
  6. 网页版白噪声A Soft Murmur
  7. 2019年10月8日股市走势预测——06
  8. 1.3 认识程序开发
  9. 老油条表示真干不过,部门新来的00后测试员已把我卷崩溃,想离职了...
  10. php支付宝提现demo,php 支付宝 支付Demo模板