0
点赞
收藏
分享

微信扫一扫

GO使用image/draw库给图片添加水印完全解析



目录


  • 一、前言
  • 二、`image/draw`
  • 三、`image/jpeg`和`image/png`
  • 四、思路分析
  • 五、代码实装
  • 1.读取图片
  • 2.根据图片类型使用不同类
  • 3.添加图片水印
  • 4.添加文字水印
  • 5. 水印效果
  • 6. 完整代码
  • 六、总结
  • 1. 需要熟悉的库
  • 2.处理思路
  • 七、评论区作业


一、前言

图片水印是很实用的功能,可以标注图片的来源,防止第三方盗图。

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. 读取原始图片
  2. 读取水印图片或者获取水印文字
  3. 创建新图片,写入原始图片和水印图片或者文字
  4. 保存图片到文件

五、代码实装

1.读取图片

比如我的原始图片是这个猫猫图

GO使用image/draw库给图片添加水印完全解析_图片水印

那么作为输入,我应该获取图片,并且判断图片的文件类型,由于我会事先声明只支持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. 水印效果

GO使用image/draw库给图片添加水印完全解析_原力计划_02

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.处理思路


  • 找到合适的库
  • 通过文档确认合适的方法
  • 完善代码健壮性

七、评论区作业

这个水印工具还有哪些可以优化的点?

欢迎给出你的思路!



举报

相关推荐

0 条评论