golang 图片加水印

需求:
1,员工签到图片加水印
2,水印文字需要有半透明的底色,避免水印看不清
3,图片宽设置在600,小于600或者大于600都需要等比例修改图片的高度,保持水印在图片中的大小和位置
4,处理后图片和原图大小不要相差太多

调用:

	fileName := "display_20231229134926805_9512.jpg"waterMark := WaterMarkInfo{UserInfo: "1123456789-仲夏夜的梦  2023-12-28 17:23:54",SignAddress: "[119.092868,34.887314] 中国广东省深圳市龙岗区坂田街道华为基地广东省深圳市南山区广东省深圳市南山区广东省深圳市南山区广东省深圳市南山区广东省深圳市南山区",}addSigninWaterMark(fileName, waterMark)

图片加水印方法:

// WaterMarkInfo 水印信息
type WaterMarkInfo struct {UserInfo string //用户信息SignAddress string //签到地址
}// 增加打卡水印
func addSigninWaterMark(fileName string, waterMarkInfo WaterMarkInfo) error {//接口异常捕获defer func() {if err := recover(); err != nil {sbjlog.ExcLog("100", "addSigninWaterMark-图片增加水印异常:err=%v", err)}}()//需要加水印的图片imgfile, err := os.Open(tempImgDir + fileName)if err != nil {sbjlog.Debug("addSigninWaterMark os.Open ERROR:%v \r\n", err)return err}defer imgfile.Close()jpgimg, err := jpeg.Decode(imgfile)if err != nil {sbjlog.Debug("addSigninWaterMark jpeg.Decode ERROR:%v \r\n", err)return err}//对图片进行大小变更,图片的宽必须是600,水印文字长度是按照600来设置的imgWidth := uint(600)imgHeight := uint(800)if uint(jpgimg.Bounds().Dx()) != imgWidth {imgHeight = uint(imgWidth) * uint(jpgimg.Bounds().Dy()) / uint(jpgimg.Bounds().Dx())jpgimg = resize.Resize(600, imgHeight, jpgimg, resize.Bilinear)}//新建空白图层img := image.NewRGBA64(jpgimg.Bounds())pic2FramePadding := 20waterMarkHeight := 80waterMarkWidth := 600//新建空白白色图层transparentImg := image.NewRGBA64(image.Rect(0, 0, waterMarkWidth-pic2FramePadding/2, waterMarkHeight))//设置空白白色图层的大小draw.Draw(transparentImg,image.Rect(pic2FramePadding/2, pic2FramePadding/2, transparentImg.Bounds().Dx(), transparentImg.Bounds().Dy()),image.White,image.Point{},draw.Over)//把原来的图片画到空白图层上draw.Draw(img, jpgimg.Bounds(), jpgimg, jpgimg.Bounds().Min, draw.Over)//设置白色图层透明度,color.Alpha值在0-255之间,越靠近0越来透明mask := image.NewUniform(color.Alpha{180})//把空白图层画到空白图层上draw.DrawMask(img, img.Bounds().Add(image.Pt(0, jpgimg.Bounds().Dy()-waterMarkHeight-pic2FramePadding/2)), transparentImg, image.ZP, mask, image.Point{}, draw.Over)//给空白图层加水印err = addWaterMarkToImage(img, waterMarkInfo)if err != nil {return err}//保存到新文件中newfile, err := os.Create(tempImgDir + fileName)//在尽量不损失图片质量的情况下,保证绘制后图片和原图片一样大:jpeg.Options{94}err = jpeg.Encode(newfile, img, &jpeg.Options{94})if err != nil {fmt.Println(err)}return nil
}

图片加文字:

func addWaterMarkToImage(newTemplateImage *image.RGBA64, waterMarkInfo WaterMarkInfo) error {// 在写入之前有一些准备工作content := freetype.NewContext()fontTtf, err := loadFont("runtime/fonts/simsun.ttc")if err != nil {sbjlog.Debug("addWaterMarkToImage loadFont ERROR:%v \r\n", err)return err}content.SetClip(newTemplateImage.Bounds())content.SetDst(newTemplateImage)content.SetSrc(image.Black) // 设置字体颜色content.SetDPI(72)          // 设置字体分辨率content.SetFontSize(14)  // 设置字体大小content.SetFont(fontTtf) // 设置字体样式,就是我们上面加载的字体// 	正式写入文字// 参数1:要写入的文字// 参数2:文字坐标//dx := newTemplateImage.Bounds().Dx()dy := newTemplateImage.Bounds().Dy()topSignAddress := waterMarkInfo.SignAddressendSignAddress := ""if len(waterMarkInfo.SignAddress) > 100 {topSignAddress = xstring.SubString(waterMarkInfo.SignAddress, 100)endSignAddress = waterMarkInfo.SignAddress[len(topSignAddress):]}pic2FramePadding := 20markHeiht := dy - pic2FramePadding*3content.DrawString(waterMarkInfo.UserInfo, freetype.Pt(pic2FramePadding, markHeiht))markHeiht = markHeiht + 20content.DrawString(topSignAddress, freetype.Pt(pic2FramePadding, markHeiht))markHeiht = markHeiht + 20content.DrawString(endSignAddress, freetype.Pt(pic2FramePadding, markHeiht))return nil
}

加载字体:

// 根据路径加载字体文件
// path 字体的路径
func loadFont(path string) (font *truetype.Font, err error) {var fontBytes []bytefontBytes, err = ioutil.ReadFile(path) // 读取字体文件if err != nil {err = fmt.Errorf("加载字体文件出错:%s", err.Error())return}font, err = freetype.ParseFont(fontBytes) // 解析字体文件if err != nil {err = fmt.Errorf("解析字体文件出错,%s", err.Error())return}return
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/230295.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【2023年中国高校大数据挑战赛 】赛题 B DNA 存储中的序列聚类与比对 Python实现

【2023年中国高校大数据挑战赛 】赛题 B DNA 存储中的序列聚类与比对 Python实现 更新时间:2023-12-29 1 题目 赛题 B DNA 存储中的序列聚类与比对 近年来,随着新互联网设备的大量涌入和对其服务需求的指数级增长,越来越多的数据信息被产…

【日积月累】Java Lambda 表达式

目录 【日积月累】Java Lambda 表达式 1.前言2.语法3.应用场景3.1简化匿名内部类的编写3.1简化匿名内部类的编写3.2简化集合类中的操作3.3实现函数式接口3.4简化多个方法的调用3.5简化异步编程 4.总结5.参考 文章所属专区 日积月累 1.前言 Lambda表达式是一个匿名函数&#…

快速打通 Vue 3(二):响应式对象基础

很激动进入了 Vue 3 的学习,作为一个已经上线了三年多的框架,很多项目都开始使用 Vue 3 来编写了 这一组文章主要聚焦于 Vue 3 的新技术和新特性 如果想要学习基础的 Vue 语法可以看我专栏中的其他博客 Vue(一):Vue 入…

2023年.AI域名销售额达550万美元 2024还要继续涨

根据域名投资专家Elliot Silver的最新文章,2023年公开报道的.AI域名销售额已经达到了550万美元,而2022年和2021年分别为90万美元和120万美元。 Silver观察到过去几年.AI域名销售额呈现逐年增长的趋势,尤其是2023年的销售额相较前两年有了显著…

【计算机毕业设计】SSM二手交易网站

项目介绍 该项目分为前后台,前台普通用户角色,后台管理员角色。 管理员主要功能如下: 登陆,商品分类管理,商品管理,商品订单管理,用户管理等功能。 用户角色主要功能如下: 包含以下功能:查看所有商品,用户登陆注册…

骨传导耳机不踩坑推荐指南,南卡/韶音/墨觉实测告诉你答案!

你知道怎么选骨传导耳机吗?作为一个音响测评博主,我用过不下10款骨传导耳机,有的是普通款式,有的是专业运动款式,甚至为了维修也拆过一些骨传导耳机。可以说,骨传导耳机的选购绝不是表面看起来那么简单&…

单位转换工具类

单位转换工具类 1. 工具类转换- 定义装换枚举转换类型- 创建转换工具类,1. 通过反射去除字段,2.对照传入map标记的字段需要转换的类型转换3. 重新赋值 2. 注解转换- 定义注解- 解析注解 1. 工具类转换 - 定义装换枚举转换类型 public enum UnitConvertType {/*** 精确度*/ACC…

break,continue跳出指定循环小案例

某一天,你犯了一个错误,你老婆罚你做5天家务,每天去洗碗,洗碗到第三天心软了,原谅你了只有第三太不用洗碗 public class BreakDemo {public static void main(String[] args) {//某一天,你犯了一个错误&am…

视频监控可视化云平台EasyCVR智能视频技术优势分析

TSINGSEE青犀视频安防视频管理系统EasyCVR视频智能融合共享平台,是一个支持Windows/Linux(CentOS ubuntu)/国产化系统的视频管理平台。平台可以支持多协议接入,通过视频应用引擎将多种格式的视频数据转换为统一的视频流数据,支持无插件H5直播…

现在的人们如何看待数据隐私?

PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 在当前时代,每一次点击、触摸或按键都留下了数字痕迹。但是我们对自己的个人数据几乎没有控制的权限,这让…

主流桌面浏览器Chrome,FireFox和Edge等如何禁用弹出式窗口阻止程序,这里有详细步骤

为什么你想知道如何禁用浏览器中的弹出式窗口阻止程序?毕竟,弹出式窗口是网络的祸害:显示烦人的广告、虚假的安全消息和其他刺激,会分散你的浏览注意力,甚至可能包含恶意代码。 所有主要的桌面浏览器现在都默认阻止弹出式窗口,那么你到底为什么要取消阻止这些害虫呢?事…

c++的三大特性之关于继承

目录 继承的概念及定义 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 继承与友元,静态成员 继承的概念及定义 概念: 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类…

gitee创建仓库

描述 本文章记录了怎么在gitee上创建项目,以及使用vscode提代码到远程呢个仓库,如何创建一个新分支,并将新分支提交到远程仓库。 1、创建远程仓库 在创建远程仓库之前要先进行ssh密钥的设置 (1)打开黑窗口&#xff…

iptables 防火墙(二)

目录 1. SNAT 策略及应用 1.1 SNAT策略概述 1. 只开启路由转发,未设置地址转换的情况 2. 开启路由转发,并设置SNAT转换的情况 1.2 SNAT策略的应用 1. 2.1 共享固定IP上网 (1)打开网关的路由转发 (2)…

[C#]C# OpenVINO部署yolov8目标检测模型

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 YOLOv8 抛弃了前几代模型的 Anchor-Base。 YOLO 是一种基于图像全局信息进行预测的目标检测系统。自 2015 年 Joseph Redmon、Ali Farhadi 等人提出初代模型以来,领域内的研究者们…

大数据Doris(四十九):Doris数据导出介绍

文章目录 Doris数据导出介绍 一、​​​​​​​使用示例

静态网页设计——个人简介网站

前言 使用经典前端三件套HTMLCSSJavascript编写了一个关于个人简介的静态网页,可以根据自己的需要,十分简单的进行修改。 首页 首页由上方的菜单栏以及菜单栏下面的轮播图组成,再往下走,是关于自己的兴趣爱好的部分&#xff0c…

django学习:页面渲染与请求和响应

1.请求过程 2.页面渲染 在app中新建一个目录(Directory),文件名命名为templates。该文件名命名是固定的,不可命名出错,如若后续步骤出错,该目录文件名是一个检查的重点项目。在该目录下新建一个html文件&a…

深度学习:大规模模型分布式训练框架DeepSpeed

深度学习:大规模模型分布式训练框架DeepSpeed DeepSpeed简介DeepSpeed核心特点DeepSpeed如何工作?DeepSpeed如何使用?参考文献 DeepSpeed简介 随着机器学习模型变得越来越复杂和庞大,训练这些模型所需的计算资源也在不断增加。特别…