参考网上的文章写了一个制作水印的包,支持文字水印以及图片水印,喜欢的点个赞~~

package watermarkimport ("github.com/golang/freetype""go.uber.org/zap/buffer""image""image/color""image/draw""image/jpeg""image/png""io/ioutil""os"
)const (TopLeft int = iotaTopRightBottomLeftBottomRightCenter
)var (FontColorBlack = RGBA{R: 0, G: 0, B: 0, A: 255}FontColorRed   = RGBA{R: 255, G: 0, B: 0, A: 255}FontColorGreen = RGBA{R: 0, G: 255, B: 0, A: 255}FontColorBlue  = RGBA{R: 0, G: 0, B: 255, A: 255}FontColorWhite = RGBA{R: 255, G: 255, B: 255, A: 255}
)type Water struct{}type FontInfo struct {Size     float64 //文字大小Text     string  //文字内容Position int     //文字存放位置Dx       int     //文字x轴留白距离Dy       int     //文字y轴留白距离RGBA
}type RGBA struct {R uint8G uint8B uint8A uint8
}// Demo 根据传入的信息绘制文字水印(例子)
func (w *Water) Demo(savePath, filePath, ttfPath string, fonts []FontInfo, photos []PhotoInfo) ([]byte, error) {img, imgType, err := w.New(filePath)if err != nil {return nil, err}img, err = w.BatchFontWatermark(img, fonts, ttfPath) //添加文字水印if err != nil {return nil, err}img, err = w.BatchPhotoWatermark(img, photos)if err != nil {return nil, err}err = w.Create(img, savePath, imgType)b, err := w.GetBuffer(img)if err != nil {return nil, err}return b, err
}// MakeFonts 创建需要打水印的文字结构体切片
func (w *Water) MakeFonts(infos ...FontInfo) []FontInfo {fonts := make([]FontInfo, 0)for _, info := range infos {fonts = append(fonts, info)}return fonts
}// MakePhotos 创建需要打水印的图片结构体切片
func (w *Water) MakePhotos(infos ...PhotoInfo) []PhotoInfo {photos := make([]PhotoInfo, 0)for _, info := range infos {photos = append(photos, info)}return photos
}// New 创建一个需要打水印的对象
func (w *Water) New(filePath string) (*image.NRGBA, string, error) {imgFile, err := os.Open(filePath)if err != nil {return nil, "", err}defer imgFile.Close()_, imgType, err := image.DecodeConfig(imgFile)if err != nil {return nil, "", err}imgFile, err = os.Open(filePath)if err != nil {return nil, "", err}defer imgFile.Close()// 根据文件类型生成对应的对象var staticImg image.Imageif imgType == "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))}}return img, imgType, nil
}// Create 生成新的图片文件
func (w *Water) Create(img *image.NRGBA, savePath, imgType string) error {//保存到新文件中newfile, err := os.Create(savePath)if err != nil {return err}defer newfile.Close()if imgType == "png" {err = png.Encode(newfile, img)} else {err = jpeg.Encode(newfile, img, &jpeg.Options{100})}return nil
}// GetBuffer 获取图片的byte
func (w *Water) GetBuffer(img *image.NRGBA) ([]byte, error) {var b buffer.Buffererr := png.Encode(&b, img)if err != nil {return nil, err}return b.Bytes(), nil
}// BatchFontWatermark 批量追加文字水印(同一字体)
func (w *Water) BatchFontWatermark(img *image.NRGBA, fonts []FontInfo, ttfPath string) (*image.NRGBA, error) {if len(fonts) == 0 {return img, nil}//拷贝一个字体文件到运行目录fontBytes, err := ioutil.ReadFile(ttfPath)if err != nil {return img, err}font, err := freetype.ParseFont(fontBytes)if err != nil {return img, err}for _, t := range fonts {info := t.Textf := freetype.NewContext()f.SetDPI(108)f.SetFont(font)f.SetFontSize(t.Size)f.SetClip(img.Bounds())f.SetDst(img)f.SetSrc(image.NewUniform(color.RGBA{R: t.R, G: t.G, B: t.B, A: t.A}))x := 0y := 0switch int(t.Position) {case 0:x = t.Dxy = t.Dy + int(f.PointToFixed(t.Size)>>6)case 1:x = img.Bounds().Dx() - len(info)*4 - t.Dxy = t.Dy + int(f.PointToFixed(t.Size)>>6)case 2:x = t.Dxy = img.Bounds().Dy() - t.Dycase 3:x = img.Bounds().Dx() - len(info)*4 - t.Dxy = img.Bounds().Dy() - t.Dycase 4:x = (img.Bounds().Dx() - len(info)*4) / 2y = (img.Bounds().Dy() - t.Dy) / 2default:x = t.Dxy = t.Dy + int(f.PointToFixed(t.Size)>>6)}pt := freetype.Pt(x, y)_, err = f.DrawString(info, pt)if err != nil {return img, err}}return img, err
}type PhotoInfo struct {Path string //图片路径Dx   int    //图片位置Dy   int    //图片位置
}// BatchPhotoWatermark 根据传入的信息绘制图片水印
func (w *Water) BatchPhotoWatermark(img *image.NRGBA, photos []PhotoInfo) (*image.NRGBA, error) {for _, photo := range photos {watermark, err := os.Open(photo.Path)if err != nil {return nil, err}defer watermark.Close()_, imgType, err := image.DecodeConfig(watermark)if err != nil {return nil, err}watermark, err = os.Open(photo.Path)if err != nil {return nil, err}defer watermark.Close()var imgwatermark image.Imageswitch imgType {case "png":imgwatermark, err = png.Decode(watermark)case "jpeg":imgwatermark, err = jpeg.Decode(watermark)default:return nil, err}if imgwatermark == nil {return nil, err}offset := image.Pt(photo.Dx, photo.Dy)draw.Draw(img, imgwatermark.Bounds().Add(offset), imgwatermark, image.ZP, draw.Over)}return img, nil
}

单元测试代码~~~

package watermarkimport ("fmt""testing"
)func TestWater_Draw(t *testing.T) {var (savePath = "./image/test.png" // 打完水印后保存的目录filePath = "./image/base.png" // 基础图片的位置ttfPath  = "./font/NotoSansSC-Regular.ttf" //存放字体TTL的位置)w := new(Water)fonts := w.MakeFonts(FontInfo{Size:     12,Text:     "heiheihei",Position: TopLeft,Dx:       104,Dy:       101,RGBA:     FontColorBlack,},FontInfo{Size:     12,Text:     "lalalala",Position: TopLeft,Dx:       104,Dy:       200,RGBA:     FontColorBlack,},)photos := w.MakePhotos(PhotoInfo{Path: "./image/dog.jpg", // 水印图片Dx:   132,Dy:   510,},)b, err := w.Demo(savePath, filePath, ttfPath, fonts, photos)if err != nil {fmt.Println(err)}t.Log("图片的buffer长度为", len(b))return
}

面向猴子编程 GO制作水印相关推荐

  1. 【Spring】面向切面编程AOP

    AOP基础 什么是AOP [废话解释]在软件业,AOP全称Aspect Oriented Programming 即:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AO ...

  2. 频频曝出程序员被抓,我们该如何避免面向监狱编程?

    过去几年,频频有程序员被抓的消息刷爆技术圈,无论是技术高手.公司合伙人还是普通程序员,甚至整个科技公司,都有因为违法被抓的案例. 案例 比如: 1.著名的Nignx之父Igor Sysoev的前东家R ...

  3. 程序员,技术的“背锅侠”,盘点 2020 年面向监狱编程的那些事!

    [CSDN 编者按]过去一年,"删库跑路".安全漏洞等事件层出不穷,企业.技术人深受其害,作为一名程序员,在新的一年即将到来之际,我们该如何避免面向监狱编程? 作者 | 马超    ...

  4. 黑马java教程是什么_Java教程:揭秘什么是面向接口编程

    先用一个案例来给大家说明一下面向接口编程. 案例:有一个电脑类(Computer),电脑除了有基本的开机关机功能外,还有连接任何外接设备的功能,比如能电脑能连接外置键盘(Keyboard),鼠标(Mo ...

  5. 第四十六期:最近程序员频繁被抓,如何避免面向监狱编程?!

    最近,有很多关于程序员被抓甚至被判刑的新闻在朋友圈疯传:"某程序员因为接了个外包,帮别人写了个软件,结果这个软件被用于赌博导致被抓.某公司利用爬虫抓取用户信息,最后被发现,导致该公司的程序员 ...

  6. 最近程序员频繁被抓,如何避免面向监狱编程?!

    最近,有很多关于程序员被抓甚至被判刑的新闻在朋友圈疯传: "某程序员因为接了个外包,帮别人写了个软件,结果这个软件被用于赌博导致被抓. 某公司利用爬虫抓取用户信息,最后被发现,导致该公司的程 ...

  7. 从 Nginx 到 Pandownload,程序员如何避免面向监狱编程?

    作者 | 马超 来源 | CSDN博客,责编 | 夕颜 封图 | CSDN付费下载视觉中国 出品 | CSDN(ID:CSDNnews) 据扬州网警巡查执法官方消息,百度网盘破解版Pandownloa ...

  8. 最近程序员频繁被抓,如何避免面向监狱编程!?

    最近,有关程序员因为参与某些项目开发导致被起诉,甚至被判刑的事件发生的比较多: 某程序员因为接了个外包,帮别人写了个软件,结果这个软件被用于赌博导致被抓. 某公司利用爬虫抓取用户信息,最后被发现,导致 ...

  9. 最近经常看到网上程序员被抓,如何避免面向监狱编程!?

    最近,有关程序员因为参与某些项目开发导致被起诉,甚至被判刑的事件发生的比较多: 某程序员因为接了个外包,帮别人写了个软件,结果这个软件被用于赌博导致被抓. 某公司利用爬虫抓取用户信息,最后被发现,导致 ...

  10. 程序员如何避免面向监狱编程?避免踩雷!

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 233篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) 最近,有很多关于程序员 ...

最新文章

  1. 2015 HIAST Collegiate Programming Contest J
  2. 一天一种设计模式(一)------观察者模式
  3. PMCAFF | 团队有20名产品经理,如何争取更多开发资源?
  4. sed搜索某行在行末追加_linux shell 用sed命令在文本的行尾或行首添加字符
  5. [C#] 接收和发送UDP数据
  6. 问题总结2015/05/05
  7. 【Java用法】java 8两个List集合取交集、并集、差集、去重并集
  8. 机器学习降维算法三:LLE (Locally Linear Embedding) 局部线性嵌入
  9. ubuntu 12.04安装与配置
  10. php 变量 类名,关于php:使用变量类名和静态方法时出错
  11. 经纬度绘图_Python气象绘图教程(二十二)—mpl_toolkits.axes_grid1
  12. 【MySQL】性能优化之 Index Condition Pushdown
  13. [Ext JS 4] 实战之多选下拉单 (带checkbox) 续 - 带ALL 选项
  14. 案例-三角形(CSS3)
  15. Struct1中 Form表单提交的几种方式以及无刷新提交的方式
  16. python 分页插件
  17. Java基础知识总结(2021版)
  18. Unity学习笔记:unity脚本常用API
  19. 【转】GBK编码表和GBK编码规范
  20. 电子教室软件 android,【转载】退出极域学生端电子教室教程9种方法

热门文章

  1. C# pdf转png图片
  2. Vue 上传图片裁剪
  3. Java实现OpenOffice将word转换为pdf
  4. iOS创建自定义相册
  5. Python在图片上添加文字
  6. 【中科院】分子生物学-朱玉贤第四版-笔记-第2-4讲 DNA 染色体 DNA复制
  7. 如何面试大厂web前端?(沟通软技能总结)
  8. 腾讯云服务器SSH密匙登录教程(创建密匙/关联/登录)
  9. 使用HTML编写浣溪沙,浣溪沙_巅峰Hacker_新浪博客
  10. python_csv文件写入