前言
这篇文章是学习记录,所诉内容应该是相对片面的,欢迎指正。
参考文章如下:
https://www.cnblogs.com/msnsj/p/4242572.html
https://studygolang.com/pkgdoc
image接口
在go语言中文网中对image接口有如下描述:
image实现了基本的2D图片库。
基本接口叫作Image。图片的色彩定义在image/color包。
Image接口可以通过调用如NewRGBA和NewPaletted函数等获得;也可以通过调用Decode函数解码包含GIF、JPEG或PNG格式图像数据的输入流获得。解码任何具体图像类型之前都必须注册对应类型的解码函数。注册过程一般是作为包初始化的副作用,放在包的init函数里。
image接口的源代码:
type Image interface {
// ColorModel方法返回图像的色彩模型
ColorModel() color.Model
// Bounds方法返回图像的范围,范围不一定包括点(0, 0)
Bounds() Rectangle
// At方法返回(x, y)位置的色彩
// At(Bounds().Min.X, Bounds().Min.Y)返回网格左上角像素的色彩
// At(Bounds().Max.X-1, Bounds().Max.Y-1) 返回网格右下角像素的色彩
At(x, y int) color.Color
}
任何一个struct只要实现了image中的三个方法,便实现了image接口
RGBA
RGBA是一个结构体,可以用来保存图片信息
type RGBA struct {
// Pix保管图像的像素色彩信息,顺序为R, G, B, A
// 像素(x, y)起始位置是Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]
Pix []uint8
// Stride是Pix中每行像素占用的字节数
Stride int
// Rect是图像的范围
Rect Rectangle
}
RGBA类型代表一幅内存中的图像,其At方法返回color.RGBA类型的值。
因为不是很懂RGBA是什么,所以我对这个名词进行了搜索,结果如下:
RGBA是代表Red(红色)Green(绿色)Blue(蓝色)和Alpha的色彩空间。虽然它有的时候被描述为一个颜色空间,但是它其实仅仅是RGB模型的附加了额外的信息。采用的颜色是RGB,可以属于任何一种RGB颜色空间,但是Catmull和Smith在1971至1972年间提出了这个不可或缺的alpha数值,使得alpha渲染和alpha合成变得可能。提出者以alpha来命名是源于经典的线性插值方程αA + (1-α)B所用的就是这个希腊字母。
也就是说RGBA代表的是四个颜色的值,而在go语言中,我们可以通过color.RGBA对图片的颜色进行调控,构建我们想要的结果。
与RGBA相关的函数
func NewRGBA(r Rectangle) *RGBA
NewRGBA函数创建并返回一个具有指定范围的RGBA。
func (*RGBA) At
func (p *RGBA) At(x, y int) color.Color
func (*RGBA) Bounds
func (p *RGBA) Bounds() Rectangle
func (*RGBA) ColorModel
func (p *RGBA) ColorModel() color.Model
func (*RGBA) Opaque
func (p *RGBA) Opaque() bool
Opaque方法可以扫描整个图像并报告图像是否是完全不透明的。
func (*RGBA) PixOffset
func (p *RGBA) PixOffset(x, y int) int
PixOffset方法返回像素(x, y)的数据起始位置在Pix字段的偏移量/索引。
func (*RGBA) Set
func (p *RGBA) Set(x, y int, c color.Color)
func (*RGBA) SetRGBA
func (p *RGBA) SetRGBA(x, y int, c color.RGBA)
func (*RGBA) SubImage
func (p *RGBA) SubImage(r Rectangle) Image
SubImage方法返回代表原图像一部分(r的范围)的新图像。返回值和原图像的像素数据是共用的。
创建图片(示例)
示例一
过程:
首先使用os包下的create函数创建一个jpeg格式的图片,然后使用NewAlpha调用image接口,创建一个以(0,0)为起点,(500,200)为终点的图片对象,再依次遍历每一个像素点,使用Set函数对像素点的颜色进行设置。设置完成后,将image中的信息导入到文件中。
package main
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"log"
"os"
)
const (
dx = 500
dy = 200
)
func main() {
//新建文件,作为操作目标
file, err := os.Create("test.jpeg")
if err != nil {
log.Fatal(err)
}
defer file.Close()
//调用NewAlpha函数,实现image接口
alpha := image.NewAlpha(image.Rect(0, 0, dx, dy))
//遍历每一个像素点,设置图片
for x := 0; x < dx; x++ {
for y := 0; y < dy; y++ {
alpha.Set(x, y, color.Alpha{uint8(x % 256)}) //设定alpha图片的透明度
}
}
//在这一行的后边,尝试调用上边提到的各种方法
fmt.Println(alpha.At(400, 100)) //查看在指定位置的像素
fmt.Println(alpha.Bounds()) //查看图片边界
fmt.Println(alpha.Opaque()) //查看是否图片完全透明
fmt.Println(alpha.PixOffset(1, 1)) //查看指定点相对于第一个点的距离
fmt.Println(alpha.Stride) //查看两个垂直像素之间的距离
jpeg.Encode(file, alpha, nil) //将alpha中的信息写入图片文件中
}
在示例中,先使用os包下的Create函数在项目中创建了test.jpeg图片文件。
运行结果如下:
所创建的图片如下图所示:
这个是一个黑白渐变的图片,因为这里只使用Alpha对图片进行了透明度渐变设定。
示例二
和上文一样,这个示例依旧是使用RGBA对图片的像素点进行设置,但这个示例调整了RGBA,图像结果会不一样。
package main
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"log"
"os"
)
const (
dx = 500
dy = 200
)
func main() {
//创建图片文件jpeg
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}
defer file.Close()
//新建图片接口起始点是0,0,定义矩形边界
rgba := image.NewRGBA(image.Rect(0, 0, dx, dy))
//为图片添加颜色
for x := 0; x < dx; x++ {
for y := 0; y < dy; y++ {
//set函数设定(x,y)的color
//NRGBA,保存像素信息
rgba.Set(x, y, color.NRGBA{uint8(x % 256), uint8(y % 256), 0, 255})
}
}
fmt.Println(rgba.At(400, 100)) //{144 100 0 255}
fmt.Println(rgba.Bounds()) //(0,0)-(500,200)
fmt.Println(rgba.Opaque()) //true,其完全透明
fmt.Println(rgba.PixOffset(1, 1)) //2004
fmt.Println(rgba.Stride) //2000
jpeg.Encode(file, rgba, nil) //将image信息存入文件中
}
运行结果:
可以看到,左上角是绿色,右上角是红色,中间呈现出渐变的颜色,因为这里使用了RGBA对每一个像素点进行了颜色调控。
示例三
当然,可以使用这个方法去创建纯色的图像:
package main
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"log"
"os"
)
const (
dx = 500
dy = 200
)
func main() {
//创建图片文件jpeg
file, err := os.Create("test4.png")
if err != nil {
log.Fatal(err)
}
defer file.Close()
//新建图片接口起始点是0,0,定义矩形边界
rgba := image.NewRGBA(image.Rect(0, 0, dx, dy))
//为图片添加颜色
for x := 0; x < dx; x++ {
for y := 0; y < dy; y++ {
//set函数设定(x,y)的color
//NRGBA,保存像素信息
rgba.Set(x, y, color.NRGBA{240,255,255, 255})
}
}
jpeg.Encode(file, rgba, nil) //将image信息存入文件中
}
运行结果如图所示(我的查看器有背景图片所以可以看到一个动漫小姐姐的轮廓):