我的编程空间,编程开发者的网络收藏夹
学习永远不晚

golang中如何实现给gif、png、jpeg图片添加文字水印

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

golang中如何实现给gif、png、jpeg图片添加文字水印

小编给大家分享一下golang中如何实现给gif、png、jpeg图片添加文字水印,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

什么是golang

golang 是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言,其语法与 C语言相近,但并不包括如枚举、异常处理、继承、泛型、断言、虚函数等功能。

添加水印示例

添加main文件:“watermark/main.go”

package mainimport ( "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 textwatermarkimport ("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 = iotaTopRightBottomLeftBottomRightCenter)//字体路径var Ttf stringtype Water struct {Pattern string //增加按时间划分的子目录:默认没有时间划分的子目录}func (w *Water) New(SavePath, fileName string, typeface []FontInfo) error {var subPath stringsubPath = w.Patterndirs, 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 errorgifimg2, _ := gif.DecodeAll(imgfile)gifs := make([]*image.Paletted, 0)x0 := 0y0 := 0yuan := 0for 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 = 1break}if x0 == img.Bounds().Dx() && y0 == img.Bounds().Dy() {for y := 0; y < img.Bounds().Dy(); y++ {for x := 0; x < img.Bounds().Dx(); x++ {img.Set(x, y, gifimg.At(x, y))}}img, err2 = common(img, typeface) //添加文字水印if err2 != nil {break}//定义一个新的图片调色板img.Bounds():使用原图的颜色域,gifimg.Palette:使用原图的调色板p1 := image.NewPaletted(gifimg.Bounds(), gifimg.Palette)//把绘制过文字的图片添加到新的图片调色板上draw.Draw(p1, gifimg.Bounds(), img, image.ZP, draw.class="lazy" data-src)//把添加过文字的新调色板放入调色板slicegifs = append(gifs, p1)} else {gifs = append(gifs, gifimg)}}if yuan == 1 {return errors.New("gif: image block is out of bounds")} else {if err2 != nil {return err2}//保存到新文件中newfile, err := os.Create(name)if err != nil {return err}defer newfile.Close()g1 := &gif.GIF{Image:     gifs,Delay:     gifimg2.Delay,LoopCount: gifimg2.LoopCount,}err = gif.EncodeAll(newfile, g1)return err}}//png,jpeg图片水印func staticFontWater(file, name, status string, typeface []FontInfo) (err error) {//需要加水印的图片imgfile, _ := os.Open(file)defer imgfile.Close()var staticImg image.Imageif status == "png" {staticImg, _ = png.Decode(imgfile)} else {staticImg, _ = jpeg.Decode(imgfile)}img := image.NewNRGBA(staticImg.Bounds())for y := 0; y < img.Bounds().Dy(); y++ {for x := 0; x < img.Bounds().Dx(); x++ {img.Set(x, y, staticImg.At(x, y))}}img, err = common(img, typeface) //添加文字水印if err != nil {return err}//保存到新文件中newfile, err := os.Create(name)if err != nil {return err}defer newfile.Close()if status == "png" {err = png.Encode(newfile, img)} else {err = jpeg.Encode(newfile, img, &jpeg.Options{100})}return err}//添加文字水印函数func common(img *image.NRGBA, typeface []FontInfo) (*image.NRGBA, error) {var err2 error//拷贝一个字体文件到运行目录fontBytes, err := ioutil.ReadFile(Ttf)if err != nil {err2 = errreturn nil, err2}font, err := freetype.ParseFont(fontBytes)if err != nil {err2 = errreturn nil, err2}errNum := 1Loop:for _, t := range typeface {info := t.Messagef := freetype.NewContext()f.SetDPI(108)f.SetFont(font)f.SetFontSize(t.Size)f.SetClip(img.Bounds())f.SetDst(img)f.Setclass="lazy" data-src(image.NewUniform(color.RGBA{R: t.R, G: t.G, B: t.B, A: t.A}))//第一行的文字// pt := freetype.Pt(img.Bounds().Dx()-len(info)*4-20, img.Bounds().Dy()-100)first := 0two := 0switch int(t.Position) {case 0:first = t.Dxtwo = t.Dy + int(f.PointToFixed(t.Size)>>6)case 1:first = img.Bounds().Dx() - len(info)*4 - t.Dxtwo = t.Dy + int(f.PointToFixed(t.Size)>>6)case 2:first = t.Dxtwo = img.Bounds().Dy() - t.Dycase 3:first = img.Bounds().Dx() - len(info)*4 - t.Dxtwo = img.Bounds().Dy() - t.Dycase 4:first = (img.Bounds().Dx() - len(info)*4) / 2two = (img.Bounds().Dy() - t.Dy) / 2default:errNum = 0break Loop}// fmt.Printf("%v, %v, %v\n", first, two, info)pt := freetype.Pt(first, two)_, err = f.DrawString(info, pt)if err != nil {err2 = errbreak}}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 < lenght; i++ {result = append(result, bytes[r.Intn(bytesLen)])}return string(result)}//检查并生成存放图片的目录func createDir(SavePath, subPath string) (string, error) {var dirs stringif subPath == "" {dirs = fmt.Sprintf("%s/", SavePath)} else {dirs = fmt.Sprintf("%s/%s/", SavePath, time.Now().Format(subPath))}_, err := os.Stat(dirs)if err != nil {err = os.MkdirAll(dirs, os.ModePerm)if err != nil {return "", err}}return dirs, nil}

补充:golang基础--image/draw渲染图片、利用golang/freetype库在图片上生成文字

需求

在一张A4纸上,利用image/draw标准库生成4张二维码,和该二维码的客户信息

二维码生成利用到的库就是image/draw,通过draw.Draw进行写入

然后字体渲染利用了golang/freetype开源库

https://github.com/golang/freetype/blob/master/example/freetype/main.go

安装依赖

"github.com/golang/freetype""golang.org/x/image/font"

以上的golang.org/x/image/font需要翻墙,如果不能翻墙利用如下方法也可以:

golang中如何实现给gif、png、jpeg图片添加文字水印

逻辑

通过os.Create("dst.jpg")生成一个最终的图片,该图片上画了4个二维码,和头部文字渲染

通过os.Open("/Users/zhiliao/zhiliao/gopro/go_safly/class="lazy" data-src/qr.png")去获取本地的一个二维码图片路径,然后通过png.Decode(file1)生成图片

修改二维码图片的尺寸resize.Resize(314, 314, img, resize.Lanczos3)

通过image.NewRGBA(image.Rect(0, 0, 827, 1169))生成一个RGBA结构体的矩形框,就好比是画布的概念

选渲染头部的客户信息字体,需要一个中文字体库,这个可以用Mac系统库的中文字体,或者自行下载ttf字体库,然后加载该字体

draw.Draw(jpg, jpg.Bounds(), bg, image.ZP, draw.class="lazy" data-src)是进行设置渲染的参数,参数是画布、渲染开始的地方、图片来源、图片参数、渲染模式

然后就是设置baseline,我这里去掉了,然后就是划线,最后就是渲染字体,通过c.DrawString(s, pt)

接下来就是画4个二维码

draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 150)), img, img.Bounds().Min, draw.class="lazy" data-src) //截取图片的一部分draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 150)), img, img.Bounds().Min, draw.class="lazy" data-src) //截取图片的一部分draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 610)), img, img.Bounds().Min, draw.class="lazy" data-src) //截取图片的一部分draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 610)), img, img.Bounds().Min, draw.class="lazy" data-src) //截取图片的一部分

最后通过png.Encode(file, jpg)输出到我们最终生成的图片

效果图

golang中如何实现给gif、png、jpeg图片添加文字水印

实例

package mainimport ("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/class="lazy" data-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.class="lazy" data-src) //截取图片的一部分draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 150)), img, img.Bounds().Min, draw.class="lazy" data-src) //截取图片的一部分draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 610)), img, img.Bounds().Min, draw.class="lazy" data-src) //截取图片的一部分draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 610)), img, img.Bounds().Min, draw.class="lazy" data-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.class="lazy" data-src)c := freetype.NewContext()c.SetDPI(*dpi)c.SetFont(f)c.SetFontSize(*size)c.SetClip(jpg.Bounds())c.SetDst(jpg)c.Setclass="lazy" data-src(fg)switch *hinting {default:c.SetHinting(font.HintingNone)case "full":c.SetHinting(font.HintingFull)}//Draw the guidelines.//for i := 0; i < 200; i++ {//jpg.Set(10, 10+i, ruler)//jpg.Set(10+i, 10, ruler)//}// Draw the text.pt := freetype.Pt(200, 10+int(c.PointToFixed(*size)>>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                             // 声明请求头keysfor 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信息 默认设置为truec.Set("content-type", "application/json")       // 设置返回格式是json}//放行所有OPTIONS方法if method == "OPTIONS" {c.JSON(http.StatusOK, "Options Request!")}// 处理请求c.Next()        //  处理请求}}

看完了这篇文章,相信你对“golang中如何实现给gif、png、jpeg图片添加文字水印”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

golang中如何实现给gif、png、jpeg图片添加文字水印

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

golang中如何实现给gif、png、jpeg图片添加文字水印

小编给大家分享一下golang中如何实现给gif、png、jpeg图片添加文字水印,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!什么是golanggolang 是Google开发的一种静态强类型、编译型、并发型,并具有垃圾
2023-06-14

Python实现给图片添加文字或图片水印

在现今的数字化时代,网络上的图片泛滥,盗图现象也越来越严重。因此,在发布文章时,为了保护自己的原创作品版权,很多人选择使用水印来保护他们的图片。本文就和大家分享了Python实现给图片添加文字或图片水印的方法,需要的可以收藏一下
2023-05-19

PHP怎么实现给图片添加文字水印

本篇内容主要讲解“PHP怎么实现给图片添加文字水印”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP怎么实现给图片添加文字水印”吧!PHP给图片添加文字水印实例,支持中文文字水印,是否覆盖原图
2023-06-04

Java实现添加文字水印和图片水印功能

为图片添加水印是一种常用的图片处理技术,本文主要介绍了Java实现添加文字水印和图片水印功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-18

java怎么实现添加图片水印和文字水印

这篇文章主要介绍java怎么实现添加图片水印和文字水印,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!我们经常会在一些图片或者图片上看到某某公司或品牌的水印,那么我们可不可以自己在喜欢的图片或文件上添加水印呢?答案当然
2023-06-09

Java如何实现给Word文件添加文字水印

这篇文章主要为大家展示了“Java如何实现给Word文件添加文字水印”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java如何实现给Word文件添加文字水印”这篇文章吧。方法思路在给Word每一
2023-06-29

如何使用canvas实现给图片添加平铺水印

小编给大家分享一下如何使用canvas实现给图片添加平铺水印,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!最近项目中遇到一个需求,需要把一张图片加上平铺的水印类似
2023-06-09

Java实现添加文字水印&图片水印的方法详解

为图片添加水印的主要作用是保护图片版权,防止图片被未经授权的人使用或传播。本文为大家介绍了Java实现添加文字水印&图片水印的具体方法,需要的可以参考一下
2023-02-06

如何在PHP项目中实现图片处理和水印添加?

如何在PHP项目中实现图片处理和水印添加?近年来,随着互联网的快速发展,图片的使用在网页设计和应用开发中扮演了越来越重要的角色。为了满足用户对高质量图片的需求,我们需要在PHP项目中实现图片处理和水印添加的功能。本文将介绍一种简单而有效的方
如何在PHP项目中实现图片处理和水印添加?
2023-11-02

如何在Android中实现一个在图片中添加文字功能

这篇文章给大家介绍如何在Android中实现一个在图片中添加文字功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Android自定义实现图片加文字功能分四步来写: 1,组合控件的xml; 2,自定义组合控件的属性;
2023-05-31

Android开发中如何实现一个图片中叠加文字功能

本篇文章为大家展示了Android开发中如何实现一个图片中叠加文字功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。效果图:功能:1.用户自由输入内容,可手动换行,并且行满也会自动换行。2.可拖动改
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录