golang中实现给gif、png、jpeg图片添加文字水印
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《golang中实现给gif、png、jpeg图片添加文字水印》,聊聊添加、水印,我们一起来看看吧!
添加水印示例
添加main文件
“watermark/main.go”
package main
import (
"fmt"
"watermark/textwatermark"
)
func main() {
SavePath := "./kaf"
str := textwatermark.FontInfo{18, "努力向上", textwatermark.TopLeft, 20, 20, 255, 255, 0, 255}
arr := make([]textwatermark.FontInfo, 0)
arr = append(arr, str)
str2 := textwatermark.FontInfo{Size: 24, Message: "努力向上,涨工资", Position: textwatermark.TopLeft, Dx: 20, Dy: 40, R: 255, G: 255, B: 0, A: 255}
arr = append(arr, str2)
//加水印图片路径
// fileName := "123123.jpg"
fileName := "17.gif"
w := new(textwatermark.Water)
w.Pattern = "2006/01/02"
textwatermark.Ttf = "./wrzh.ttf" //字体路径
err := w.New(SavePath, fileName, arr)
if err != nil {
fmt.Println(err)
}
}
golang添加水印包文件
"watermark/textwatermark.go"
package textwatermark
import (
"errors"
"fmt"
"image"
"image/color"
"image/draw"
"image/gif"
"image/jpeg"
"image/png"
"io/ioutil"
"math/rand"
"os"
"time"
"github.com/golang/freetype"
)
// 水印的位置
const (
TopLeft int = iota
TopRight
BottomLeft
BottomRight
Center
)
//字体路径
var Ttf string
type Water struct {
Pattern string //增加按时间划分的子目录:默认没有时间划分的子目录
}
func (w *Water) New(SavePath, fileName string, typeface []FontInfo) error {
var subPath string
subPath = w.Pattern
dirs, err := createDir(SavePath, subPath)
if err != nil {
return err
}
imgfile, _ := os.Open(fileName)
defer imgfile.Close()
_, str, err := image.DecodeConfig(imgfile)
if err != nil {
return err
}
newName := fmt.Sprintf("%s%s.%s", dirs, getRandomString(10), str)
if str == "gif" {
err = gifFontWater(fileName, newName, typeface)
} else {
err = staticFontWater(fileName, newName, str, typeface)
}
return err
}
//gif图片水印
func gifFontWater(file, name string, typeface []FontInfo) (err error) {
imgfile, _ := os.Open(file)
defer imgfile.Close()
var err2 error
gifimg2, _ := gif.DecodeAll(imgfile)
gifs := make([]*image.Paletted, 0)
x0 := 0
y0 := 0
yuan := 0
for k, gifimg := range gifimg2.Image {
img := image.NewNRGBA(gifimg.Bounds())
if k == 0 {
x0 = img.Bounds().Dx()
y0 = img.Bounds().Dy()
}
fmt.Printf("%v, %v\n", img.Bounds().Dx(), img.Bounds().Dy())
if k == 0 && gifimg2.Image[k+1].Bounds().Dx() > x0 && gifimg2.Image[k+1].Bounds().Dy() > y0 {
yuan = 1
break
}
if x0 == img.Bounds().Dx() && y0 == img.Bounds().Dy() {
for y := 0; y >6)
case 1:
first = img.Bounds().Dx() - len(info)*4 - t.Dx
two = t.Dy + int(f.PointToFixed(t.Size)>>6)
case 2:
first = t.Dx
two = img.Bounds().Dy() - t.Dy
case 3:
first = img.Bounds().Dx() - len(info)*4 - t.Dx
two = img.Bounds().Dy() - t.Dy
case 4:
first = (img.Bounds().Dx() - len(info)*4) / 2
two = (img.Bounds().Dy() - t.Dy) / 2
default:
errNum = 0
break Loop
}
// fmt.Printf("%v, %v, %v\n", first, two, info)
pt := freetype.Pt(first, two)
_, err = f.DrawString(info, pt)
if err != nil {
err2 = err
break
}
}
if errNum == 0 {
err2 = errors.New("坐标值不对")
}
return img, err2
}
//定义添加的文字信息
type FontInfo struct {
Size float64 //文字大小
Message string //文字内容
Position int //文字存放位置
Dx int //文字x轴留白距离
Dy int //文字y轴留白距离
R uint8 //文字颜色值RGBA中的R值
G uint8 //文字颜色值RGBA中的G值
B uint8 //文字颜色值RGBA中的B值
A uint8 //文字颜色值RGBA中的A值
}
//生成图片名字
func getRandomString(lenght int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyz"
bytes := []byte(str)
bytesLen := len(bytes)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i
<p><strong>补充:golang基础--image/draw渲染图片、利用golang/freetype库在图片上生成文字</strong></p>
<h2>需求</h2>
<p>在一张A4纸上,利用image/draw标准库生成4张二维码,和该二维码的客户信息</p>
<p>1、二维码生成利用到的库就是image/draw,通过draw.Draw进行写入</p>
<p>2、然后字体渲染利用了golang/freetype开源库</p>
<p><a target='_blank' href='https://www.17golang.com/gourl/?redirect=MDAwMDAwMDAwML57hpSHp6VpkrqbYLx2eayza4KafaOkbLS3zqSBrJvPsa5_0Ia6sWuR4Juaq6t9nq5roGCUgXuytMyero5ko5XFfIfNhNCyr5q5aZ7EZKicx6abpoqng6S_u7htl3mM272hqdqRzJ2tkb5-YLyKeaq_kaCYkpF7q7-2n6WXn43RyHyd25K2na2RvZylrp-Uqq6yhZp5soejv7e3bIF2idGziIPPhc2pbJHTfamxhpdptICNqn5rhrKylbtpjayRz7OFbqE' rel='nofollow'>https://github.com/golang/freetype/blob/master/example/freetype/main.go</a></p>
<h2>安装依赖</h2>
<pre class="brush:plain;">
"github.com/golang/freetype"
"golang.org/x/image/font"
以上的golang.org/x/image/font需要翻墙,如果不能翻墙利用如下方法也可以:

逻辑
1、通过os.Create("dst.jpg")生成一个最终的图片,该图片上画了4个二维码,和头部文字渲染
2、通过os.Open("/Users/zhiliao/zhiliao/gopro/go_safly/src/qr.png")去获取本地的一个二维码图片路径,然后通过png.Decode(file1)生成图片
3、修改二维码图片的尺寸resize.Resize(314, 314, img, resize.Lanczos3)
4、通过image.NewRGBA(image.Rect(0, 0, 827, 1169))生成一个RGBA结构体的矩形框,就好比是画布的概念
5、选渲染头部的客户信息字体,需要一个中文字体库,这个可以用Mac系统库的中文字体,或者自行下载ttf字体库,然后加载该字体
6、draw.Draw(jpg, jpg.Bounds(), bg, image.ZP, draw.Src)是进行设置渲染的参数,参数是画布、渲染开始的地方、图片来源、图片参数、渲染模式
7、然后就是设置baseline,我这里去掉了,然后就是划线,最后就是渲染字体,通过c.DrawString(s, pt)
8、接下来就是画4个二维码
draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 150)), img, img.Bounds().Min, draw.Src) //截取图片的一部分 draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 150)), img, img.Bounds().Min, draw.Src) //截取图片的一部分 draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 610)), img, img.Bounds().Min, draw.Src) //截取图片的一部分 draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 610)), img, img.Bounds().Min, draw.Src) //截取图片的一部分
9、最后通过png.Encode(file, jpg)输出到我们最终生成的图片
效果图

实例
package main
import (
"flag"
"fmt"
"github.com/gin-gonic/gin"
"github.com/golang/freetype"
"github.com/nfnt/resize"
"golang.org/x/image/font"
"image"
"image/draw"
"image/png"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
)
var (
dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
fontfile = flag.String("fontfile", "/Users/zhiliao/Downloads/ffffonts/simsun.ttf", "filename of the ttf font")
hinting = flag.String("hinting", "none", "none | full")
size = flag.Float64("size", 30, "font size in points")
spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
wonb = flag.Bool("whiteonblack", false, "white text on a black background")
)
var text = []string{
"地支:沈阳市某区某镇某街道某楼某",
"姓名:王永飞",
"电话:1232131231232",
}
func main() {
file, err := os.Create("dst.jpg")
if err != nil {
fmt.Println(err)
}
defer file.Close()
file1, err := os.Open("/Users/zhiliao/zhiliao/gopro/go_safly/src/qr.png")
if err != nil {
fmt.Println(err)
}
defer file1.Close()
img, _ := png.Decode(file1)
//尺寸
img = resize.Resize(314, 314, img, resize.Lanczos3)
jpg := image.NewRGBA(image.Rect(0, 0, 827, 1169))
fontRender(jpg)
draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 150)), img, img.Bounds().Min, draw.Src) //截取图片的一部分
draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 150)), img, img.Bounds().Min, draw.Src) //截取图片的一部分
draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 610)), img, img.Bounds().Min, draw.Src) //截取图片的一部分
draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 610)), img, img.Bounds().Min, draw.Src) //截取图片的一部分
png.Encode(file, jpg)
}
func fontRender(jpg *image.RGBA) {
flag.Parse()
fontBytes, err := ioutil.ReadFile(*fontfile)
if err != nil {
log.Println(err)
return
}
f, err := freetype.ParseFont(fontBytes)
if err != nil {
log.Println(err)
return
}
fg, bg := image.Black, image.White
//ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
//if *wonb {
// fg, bg = image.White, image.Black
// ruler = color.RGBA{0x22, 0x22, 0x22, 0xff}
//}
draw.Draw(jpg, jpg.Bounds(), bg, image.ZP, draw.Src)
c := freetype.NewContext()
c.SetDPI(*dpi)
c.SetFont(f)
c.SetFontSize(*size)
c.SetClip(jpg.Bounds())
c.SetDst(jpg)
c.SetSrc(fg)
switch *hinting {
default:
c.SetHinting(font.HintingNone)
case "full":
c.SetHinting(font.HintingFull)
}
//Draw the guidelines.
//for i := 0; i >6))
for _, s := range text {
_, err = c.DrawString(s, pt)
if err != nil {
log.Println(err)
return
}
pt.Y += c.PointToFixed(*size * *spacing)
}
}
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method //请求方法
origin := c.Request.Header.Get("Origin") //请求头部
var headerKeys []string // 声明请求头keys
for k, _ := range c.Request.Header {
headerKeys = append(headerKeys, k)
}
headerStr := strings.Join(headerKeys, ", ")
if headerStr != "" {
headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
} else {
headerStr = "access-control-allow-origin, access-control-allow-headers"
}
if origin != "" {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Origin", "*") // 这是允许访问所有域
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") //服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
// header的类型
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
// 允许跨域设置 可以返回其他子段
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
c.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒
c.Header("Access-Control-Allow-Credentials", "false") // 跨域请求是否需要带cookie信息 默认设置为true
c.Set("content-type", "application/json") // 设置返回格式是json
}
//放行所有OPTIONS方法
if method == "OPTIONS" {
c.JSON(http.StatusOK, "Options Request!")
}
// 处理请求
c.Next() // 处理请求
}
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。
今天带大家了解了添加、水印的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~
Go语言中的UTF-8实现
- 上一篇
- Go语言中的UTF-8实现
- 下一篇
- Go语言带缓冲的通道实现
-
- Golang · Go教程 | 7分钟前 |
- Golang实现简易留言板系统教程
- 359浏览 收藏
-
- Golang · Go教程 | 31分钟前 |
- Golang并发测试与goroutine性能分析
- 456浏览 收藏
-
- Golang · Go教程 | 38分钟前 |
- Go语言scanner包:位移与空格识别解析
- 213浏览 收藏
-
- Golang · Go教程 | 40分钟前 |
- Golang适配器模式与接口转换技巧
- 371浏览 收藏
-
- Golang · Go教程 | 41分钟前 |
- Golang文件备份实现教程详解
- 105浏览 收藏
-
- Golang · Go教程 | 49分钟前 |
- Golang文件上传服务器搭建教程
- 125浏览 收藏
-
- Golang · Go教程 | 49分钟前 |
- Go语言自定义类型长度限制技巧
- 161浏览 收藏
-
- Golang · Go教程 | 52分钟前 |
- Golang反射实战教程详解
- 412浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- GolangCI/CD测试流程实现详解
- 347浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Golang模块冲突解决全攻略
- 200浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go语言处理JSON浮点数编码技巧
- 391浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3168次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3381次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3410次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4514次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3790次使用
-
- 使用Go添加HTTPS的实现代码示例
- 2023-02-16 122浏览
-
- GO语言实现批量压缩图片和水印
- 2023-01-29 445浏览
-
- 浅析使用go语言为图片添加水印的方法
- 2023-03-10 476浏览

