我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿
来一个嫦娥奔月祝 xdm 中秋快乐
GOLang 有很多图形库,咱们今天玩一个简单的标准图形库 image
image 包实现了一个基本的二维图像库,基本的接口叫做 Image 。
我们可以这样导入包
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
复制代码
GO image 的官方文档: pkg.go.dev/image 在 GOLAND 开发工具里面导入image 包,我们可以看到源码目录如下
- color
实现了一个基本的颜色库
- draw
绘制提供图像组成功能
- gif
gif 图像解码器和编码器
- jpeg
JPEG 图像解码器和编码器
- png
PNG 图像解码器和编码器
- internal
imageutil包含与图像相关的包共享的代码
image.go 源码
图像是一个有限的矩形颜色网格。从颜色中获取的颜色值
type Config struct {
ColorModel color.Model
Width, Height int
}
type Image interface {
ColorModel() color.Model
Bounds() Rectangle
At(x, y int) color.Color
}
复制代码
image 包里面的 image.go 是具体实现,且包里面有相应的单元测试可以模仿学习 ,一起来看看 Image
接口 , 这个 Image
接口是 image 包的基本接口,非常重要
一个图像包含颜色,它是在 image/color
包中进行描述的 , Image 接口的值是通过调用这样的函数(NewRGBA 和 NewPaletted,或通过调用解码的 io)来创建的
- ColorModel() color.Model
ColorModel返回图像的颜色模型
- Bounds() Rectangle
Bounds返回At可以为其返回非零颜色的域,边界不一定包含点(0,0)。
- At(x, y int) color.Color
At 返回像素在 (x, y) 处的颜色 ,
At(Bounds().Min.X, Bounds().Min.Y) 会返回网格左上角的像素
At(Bounds().Max.X-1, Bounds().Max.Y-1) 会返回网格右下角的像素
咱们可以通过 image 的单元测试来玩一下这个库
案例1 画一张 png 图片
我们使用“image/png”
包来进行绘制图像
// 画一张彩图
func drawEncode(){
const width, height = 500, 500
// 画一张彩图,指定好宽和高
img := image.NewNRGBA(image.Rect(0, 0, width, height))
// 一张个图像分为 上下两个部分进行渲染
for y := 0; y < height/2; y++ {
for x := 0; x < width; x++ {
img.Set(x, y, color.NRGBA{
R: uint8((x - y) & 255),
G: uint8((x - y) << 1 & 255),
B: uint8((x - y) << 2 & 255),
A: 255,
})
}
}
for y := height/2; y < height; y++ {
for x := 0; x < width; x++ {
img.Set(x, y, color.NRGBA{
R: uint8((x + y) & 255),
G: uint8((x + y) << 1 & 255),
B: uint8((x + y) << 2 & 255),
A: 255,
})
}
}
f, err := os.Create("image.png")
if err != nil {
log.Fatal(err)
}
if err := png.Encode(f, img); err != nil {
f.Close()
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
复制代码
- image.NewNRGBA
创建一张图片,指定好宽和高
- img.Set(x, y, color.NRGBA{})
设置颜色
NRGBA 结构体如下:
// NRGBA represents a non-alpha-premultiplied 32-bit color.
type NRGBA struct {
R, G, B, A uint8
}
复制代码
我们知道红绿蓝是计算机色彩的三基色
R: uint8((x - y) & 255),
G: uint8((x - y) << 1 & 255),
B: uint8((x - y) << 2 & 255),
复制代码
通过与 和 移位 方式来计算 R G B 的值分别是多少
- R
红色
- G
绿色
- B
蓝色
- A
透明度,255 则为不透明 , 0 为全透明
效果如下:
透明度 255 的效果如下
透明度上半部分设置 255, 下半部分设置 100
案例 2 来一个应景的 嫦娥奔月
准备如下素材
1、月亮一张
moon.jpg
2、嫦娥一枚
goddess.jpg
尝试使用 golang image 里面提供的包 jpeg 来进行图片合并操作
image/jpeg
func drawGoddess(){
file, err := os.Create("res.jpg")
if err != nil {
fmt.Println(err)
}
defer file.Close()
file1, err := os.Open("./back.jpg")
if err != nil {
fmt.Println(err)
}
defer file1.Close()
img, _ := jpeg.Decode(file1)
file2, err := os.Open("./goddess.jpg")
if err != nil {
fmt.Println(err)
}
defer file2.Close()
img2, _ := jpeg.Decode(file2)
file3, err := os.Open("./moon.jpg")
if err != nil {
fmt.Println(err)
}
defer file3.Close()
img3, _ := jpeg.Decode(file3)
// 设置画布大小 1250 * 790
jpg := image.NewRGBA(image.Rect(0, 0, 1250, 790))
draw.Draw(jpg, jpg.Bounds(), img, img.Bounds().Min, draw.Over) //首先将一个图片信息存入jpg
draw.Draw(jpg, jpg.Bounds(), img3, img3.Bounds().Min.Sub(image.Pt(140, 0)), draw.Over) //将另外一张图片信息存入jpg
draw.Draw(jpg, jpg.Bounds(), img2, img2.Bounds().Min.Sub(image.Pt(790, 315)), draw.Over)
jpeg.Encode(file, jpg, nil)
}
复制代码
- 创建一张图片
res.jpg
, 打开三张图片,分别是月亮,嫦娥,和背景图片 jpeg.Decode
将 月亮,嫦娥,和背景图片解码- image.NewRGBA
创建画布,设置画布大小 1250 * 790
- draw.Draw
分别将月亮,嫦娥,和背景图片 画到画布上面,并设置好合适的位置
- jpeg.Encode
将图片数据,回写到 res 的 io 中,生成 res.jpg 文件,效果如下图
案例 3 将图片做成字符画
将图片转成字符串也非常简单,思路简单如下几步:
- 读取图片,成二进制流
- 将二进制流通过 base64 加密成字符串
- 再使用 base64 将字符串转成二进制流
- 使用 “image/png” 的包解码出来,按照图片的宽高,咱们用字符来填充即可
上述第二步主要是得到一个字符串,这个字符串,可以写到文件中,也可以获取后,定义成 const,作为 demo
head.png
原图如下:
func imgToBase64()string{
srcByte, err := ioutil.ReadFile("head.png")
if err != nil {
log.Fatal(err)
}
res := base64.StdEncoding.EncodeToString(srcByte)
return res
}
func drawDecode(str string){
// 例如知道某张图片的base64,那么就可以直接定义一个常量来进行处理
//const head = `iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAIAAAD9b0jDAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAFpSURBVEhLtZTblcMgDESpi4JcD9W4GRfjlTTSIBOcxTnJfOzyGF09QlLOH2iEHq2WUmo7fD8I17zft6l5Feo00bb7kcig+QB6VGkwzKSsDtUVTKKSargTU1ygekqoLWASBdTSiYZKzczwq2rbIxRwhIhWodzACUpzc7OdE0TrUNyoppUn5vJME7JWT0Mwa3A9mCnbVA8HaiMYqMtPam/tsBRIn3xMTH30Tr1xjtG3vvsMSnaSnvnyFfoV/RRqbaeuZy1OhXmpevRDqB3fieGx8oT+FkeFHa5/G1CHWvV7YuHyqvWcleYWwLxmYHlJReIEULdNY/UvXFMomo9C30BxOX7bOipBQXknBwwf1HSiptdBIsdNpaZUUOzuUblwW+tcknUK9YHqv6EQTBUEQqMEeifQvrxkckg/wN53ng07/fRVEQ8nW8mBcqc/qp4i7mgVrDzHw6B+CocpDcdkRSRY9ubjrmj/izrPP5x5Eu8xcV+2AAAAAElFTkSuQmCC`
// 使用 png.Decode 解码 png 图片
img, err := png.Decode(base64.NewDecoder(base64.StdEncoding, strings.NewReader(str)))
if err != nil {
log.Fatal(err)
}
levels := []string{" ", "$", "=", "@", "█"}
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
c := color.GrayModel.Convert(img.At(x, y)).(color.Gray)
level := c.Y / 51 // 51 * 5 = 255
if level == 5 {
level--
}
fmt.Print(levels[level])
}
fmt.Print("\n")
}
}
复制代码
- imgToBase64
将图片二进制流通过 base64 加密得到 字符串
- drawDecode
从字符串中解析出 png 图片,获取到 png 图片的属性,并使用自定义的字符进行填充
- color.GrayModel.Convert
设置颜色模式
效果如下:
██████████████████████████████████████████████████████
████████████████████@ ████████████████████████████████
████████████████████@ ████████████████████████████████
████████████████████@ ████████████████████████████████
████████@ ███$$██ = ██$@ █= @████████████████████
█████████=$█@ ██$=██$ ██$ ██$ @█@ ████████████████████
██████████$= ██@ ███@ ██$@██@ ███ @███████████████████
███████████ @██@ ███@ ██$@██@$███ @███████████████████
██████████$= ██@ ███@ ██$@██@$███ @███████████████████
█████████=$█=$██ =██ ██$@██@$███ @███████████████████
████████= ███ $██ @ ██$@██@$███ @███████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████$█████████$ ███ ██████ ████=@████████████ ████
██████$██████@ @████ ██████ ████=@█████@ @██████
██████$████████$@████ ████@$ @ @██@$████████████
█ ███$@█$██ ██@@@= @$██=@█@@██==███$@███████
█ ████$████$█$ $@█ ██$█@@ ████=@█@@██$@███$@███████
█ ████$████$███ @██$█ @$@█$@ ████$@█@@██ @██
█ ████$████$██@ @█== $=████ █ $██████$@███████
█ ██=$@=@█=$ █████ ████ $███████ ██$@█ █████
█ ████$████$█@=$@███ @ @████ ███@=$@█████$@██$@█@ ████
██████$██████=█$@██ $█@ ████ ██@ ██ ████ @███$@██@ @██
██████$████████$@█ ███= ███ █@ ███@ @█=@████$@███@$██
██████$████████$@$=█████=$██ = ██████ @███@ ████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
复制代码
参考资料:
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是小魔童哪吒,欢迎点赞关注收藏,下次见~