GO使用image/draw库给图片添加水印完全解析
Posted 邻座的小雨同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GO使用image/draw库给图片添加水印完全解析相关的知识,希望对你有一定的参考价值。
目录
一、前言
图片水印是很实用的功能,可以标注图片的来源,防止第三方盗图。
GO实现图片水印功能主要使用绘图库image/draw
。
二、image/draw
主要的方法有
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op)
三、image/jpeg
和image/png
image/jpeg
和image/png
的作用是图片的读取和写入。
读取图片
func Decode(r io.Reader) (image.Image, error)
写入图片
func Encode(w io.Writer, m image.Image, o *Options) error
两个库的方法名都是一致的。
四、思路分析
和之前php写的水印思路没什么区别
- 读取原始图片
- 读取水印图片或者获取水印文字
- 创建新图片,写入原始图片和水印图片或者文字
- 保存图片到文件
五、代码实装
1.读取图片
比如我的原始图片是这个猫猫图
那么作为输入,我应该获取图片,并且判断图片的文件类型,由于我会事先声明只支持jpg和png的图,那么在判断图片不属于jpg或png之后应该返回错误信息。
package main
import (
"os"
imgtype "codechina.csdn.net/diandianxiyu/goimgtype"
)
func main() {
var imgdiandianxiyu_geek string = `./bg.jpg`
imgb, err := os.Open(imgdiandianxiyu_geek)
if err != nil {
panic(err)
}
defer imgb.Close()
datatype, err2 := imgtype.Get(imgdiandianxiyu_geek)
var imgtype string = ""
if err2 != nil {
imgtype = ""
} else {
// 根据文件类型执行响应的操作
switch datatype {
case `image/jpeg`:
imgtype = "jpeg"
case `image/png`:
imgtype = "png"
}
}
if imgtype == "" {
panic("暂不支持文件类型")
}
print(imgtype)
}
jpeg
由于go不支持原生的获取图片类型方式,所以这个引入了第三方库。
2.根据图片类型使用不同类
如果是jpeg的图片,就在对象初始化的时候用image/jpeg
。
如果是png的图片,就在对象初始化的时候用image/png
var imgbinfo image.Image
if imgtype == "jpeg" {
imgbinfo, _ = jpeg.Decode(imgb)
} else {
imgbinfo, _ = png.Decode(imgb)
}
3.添加图片水印
因为图片水印的图片是已知的,所以我们不需要判断图片类型了
//读取水印图片
watermark, err := os.Open("watermark.png")
if err != nil {
panic(err)
}
defer watermark.Close()
imgwatermark, err := png.Decode(watermark)
if err != nil {
panic(err)
}
offset := image.Pt(imgbinfo.Bounds().Dx()-imgwatermark.Bounds().Dx()-19, imgbinfo.Bounds().Dy()-imgwatermark.Bounds().Dy()-19)
b := imgbinfo.Bounds()
m := image.NewNRGBA(b) //按原图生成新图
这里要注意的是,imgbinfo.Bounds().Dx()
指的是原图的宽度,imgbinfo.Bounds().Dy()
指的是原图的高度。
代码的意思是水印图放在右下角19像素的位置上,实际应用中可以根据需求调整。
4.添加文字水印
文字水印必须引入字体文件,如果水印中有中文的话,引入的字体文件必需支持中文。
//文字水印
fontBytes, err := ioutil.ReadFile("Arial Unicode.ttf") //读取字体文件
if err != nil {
log.Println(err)
}
font, err := freetype.ParseFont(fontBytes)
if err != nil {
log.Println(err)
}
f := freetype.NewContext()
f.SetDPI(72) //设置DPI
f.SetFont(font) //设置字体
f.SetFontSize(24) //设置字号
f.SetClip(imgbinfo.Bounds())
f.SetDst(m)
f.SetSrc(image.NewUniform(color.RGBA{R: 255, G: 0, B: 0, A: 255})) //设置颜色
pt := freetype.Pt(10, 50)
_, err = f.DrawString("blog.csdn.net/diandianxiyu_geek 邻座的小雨同学", pt)
pt
指的是坐标,我设置的是横坐标10和纵坐标的位置。
5. 水印效果
备注:右下角的白色的文字是CSDN的水印,不是代码里的。
6. 完整代码
package main
import (
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"log"
"os"
"codechina.csdn.net/diandianxiyu/freetype"
imgtype "codechina.csdn.net/diandianxiyu/goimgtype"
)
func main() {
var imgdiandianxiyu_geek string = `./bg.jpg`
imgb, err := os.Open(imgdiandianxiyu_geek)
if err != nil {
panic(err)
}
defer imgb.Close()
datatype, err2 := imgtype.Get(imgdiandianxiyu_geek)
var imgtype string = ""
if err2 != nil {
imgtype = ""
} else {
// 根据文件类型执行响应的操作
switch datatype {
case `image/jpeg`:
imgtype = "jpeg"
case `image/png`:
imgtype = "png"
}
}
if imgtype == "" {
panic("暂不支持文件类型")
}
var imgbinfo image.Image
if imgtype == "jpeg" {
imgbinfo, _ = jpeg.Decode(imgb)
} else {
imgbinfo, _ = png.Decode(imgb)
}
//读取水印图片
watermark, err := os.Open("watermark.png")
if err != nil {
panic(err)
}
defer watermark.Close()
imgwatermark, err := png.Decode(watermark)
if err != nil {
panic(err)
}
offset := image.Pt(imgbinfo.Bounds().Dx()-imgwatermark.Bounds().Dx()-19, imgbinfo.Bounds().Dy()-imgwatermark.Bounds().Dy()-19)
b := imgbinfo.Bounds()
m := image.NewNRGBA(b) //按原图生成新图
//文字水印
fontBytes, err := ioutil.ReadFile("Arial Unicode.ttf") //读取字体文件
if err != nil {
log.Println(err)
}
font, err := freetype.ParseFont(fontBytes)
if err != nil {
log.Println(err)
}
f := freetype.NewContext()
f.SetDPI(72) //设置DPI
f.SetFont(font) //设置字体
f.SetFontSize(24) //设置字号
f.SetClip(imgbinfo.Bounds())
f.SetDst(m)
f.SetSrc(image.NewUniform(color.RGBA{R: 255, G: 0, B: 0, A: 255})) //设置颜色
//新图写入原图和背景图
draw.Draw(m, b, imgbinfo, image.ZP, draw.Src)
draw.Draw(m, imgwatermark.Bounds().Add(offset), imgwatermark, image.ZP, draw.Over)
pt := freetype.Pt(10, 50)
_, err = f.DrawString("blog.csdn.net/diandianxiyu_geek 邻座的小雨同学", pt)
//输出图像
imgw, _ := os.Create("new.jpg")
jpeg.Encode(imgw, m, &jpeg.Options{100})
}
本地引入库
go get codechina.csdn.net/diandianxiyu/freetype
go get codechina.csdn.net/diandianxiyu/goimgtype
六、总结
1. 需要熟悉的库
image/draw
image/jpeg
和image/png
2.处理思路
- 找到合适的库
- 通过文档确认合适的方法
- 完善代码健壮性
七、评论区作业
这个水印工具还有哪些可以优化的点?
欢迎给出你的思路!
以上是关于GO使用image/draw库给图片添加水印完全解析的主要内容,如果未能解决你的问题,请参考以下文章