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
}
相关文章:
golang 图片加水印
需求: 1,员工签到图片加水印 2,水印文字需要有半透明的底色,避免水印看不清 3,图片宽设置在600,小于600或者大于600都需要等比例修改图片的高度,保持水印在图片中的大小和位置 4,处理…...
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set问题解决方案
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set问题解决方案 当我们使用sudo su切换权限时提示错误: sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set该错误出现原因:是因为/usr/bin/sudo的权限被…...
提升效率:使用注解实现精简而高效的Spring开发
IOC/DI注解开发 1.0 环境准备1.1 注解开发定义bean步骤1:删除原XML配置步骤2:Dao上添加注解步骤3:配置Spring的注解包扫描步骤4:运行程序步骤5:Service上添加注解步骤6:运行程序知识点1:Component等 1.2 纯注解开发模式1.2.1 思路分析1.2.2 实现步骤步骤1:创建配置类…...
全面好用的setting.xml配置
<?xml version"1.0" encoding"UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information…...
八股文打卡day14——计算机网络(14)
面试题:TCP的Keepalive和HTTP的Keep-Alive是一个东西吗? 我的回答: TCP的Keepalive 1.位于TCP/IP模型的传输层。 2.是用来判活的。客户端会向服务器发送一个Keepalive包来判断,这个TCP连接是否还存活着。 HTTP中的Keep-Alive 1.…...
NCNN环境部署及yolov5pt转ncnn模型转换推理
该内容还未完整,笔记内容,持续补充。 〇开发环境版本 vs2022 cmake3.21.1 ncnn20231027发行版 yolov5s v6.2 vunlkan1.2.198.1 Protobuf3.20.0 Opencv3.4.1 一、模型转换 yolov5s v6.2训练的pt模型,直接导出tourchscript,…...
selenium模块有哪些用途?
Selenium模块是一个用于Web应用程序测试的模块,具有多种示例用法。以下是一些示例: 1.打开网页并执行一些基本操作,如点击按钮、输入文本等。 定位网页元素并执行操作,例如使用 find_element 方法查找单个元素,使用 f…...
精品Nodejs实现的校园疫情防控管理系统的设计与实现健康打卡
《[含文档PPT源码等]精品Nodejs实现的校园疫情防控管理系统的设计与实现[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功! 软件开发环境及开发工具: 操作系统:Windows 10、Windows 7、Win…...
爬虫工作量由小到大的思维转变---<第三十五章 Scrapy 的scrapyd+Gerapy 部署爬虫项目>
前言: 项目框架没有问题大家布好了的话,接着我们就开始部署scrapy项目(没搭好架子的话,看我上文爬虫工作量由小到大的思维转变---<第三十四章 Scrapy 的部署scrapydGerapy>-CSDN博客) 正文: 1.创建主机: 首先gerapy的架子,就相当于部署服务器上的;所以…...
python测试工具: 实现数据源自动核对
测试业务需要: 现有A系统作为下游数据系统,上游系统有A1,A2,A3... 需要将A1,A2,A3...的数据达到某条件后(比如:A1系统销售单提交出库成功)自动触发MQ然后再经过数据清洗落到A系统,并将清洗后数据通过特定…...
要学习openfoam,c++需要掌握到什么程度?
要学习openfoam,c需要掌握到什么程度? 在开始前我有一些资料,是我根据自己从业十年经验,熬夜搞了几个通宵,精心整理了一份「c的资料从专业入门到高级教程工具包」,点个关注,全部无偿共享给大家&…...
web一些实验代码——Servlet请求与响应
实验4:Servlet请求与响应 1、在页面输入学生学号,从数据库中查询学生信息并显示。 (1)启动MySQL数据库服务,新建数据库,将student.sql文件导入到新建数据库(建立表,并插入3条数据&…...
GPT系列概述
OPENAI做的东西 Openai老窝在爱荷华州,微软投资的数据中心 万物皆可GPT下咱们要失业了? 但是世界不仅仅是GPT GPT其实也只是冰山一角,2022年每4天就有一个大型模型问世 GPT历史时刻 GPT-1 带回到2018年的NLP 所有下游任务都需要微调&#x…...
基于遗传算法的集装箱吊装优化,基于遗传算法的集装箱装卸优化
目录 背影 遗传算法的原理及步骤 基本定义 编码方式 适应度函数 运算过程 代码 结果分析 完整代码下载: 基于遗传算法的集装箱吊装优化,基于遗传算法的集装箱装卸优化(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/download/abc991835105/88674652 背影 …...
postgreSQL单机部署
一、环境准备 架构操作系统IP主机名PG版本端口磁盘空间内存CPUsingle 单机centos7192.168.1.10pgserver01PostgreSQL 14.7543350G4G2 1、官网下载源码包 https://www.postgresql.org/download/2、操作系统参数修改 2.1 sysctl.conf配置 vi /etc/sysctl.conf kernel.sysrq …...
思维逻辑题3
题目1: 如果所有A都是B,且某个对象是B,那么它一定是A吗? 答案:不一定,尽管所有A都是B,但还有其他的对象可能也是B。 题目2: 如果A和B都是真,那么以下哪个选项是真&…...
强大的音乐乐谱控件库
2023 Conmajia, 2018 Ajcek84 SN: 23C.1 本中文翻译已获原作者首肯。 简介 PSAM 控件库——波兰音乐文档系统——是用于显示、排版乐谱的强大 WinForm 库,包含用于绘制乐谱的名为 IncipitViewer 控件,乐谱内容可以从 MusicXml 文件读取,或者…...
数据库——简单查询复杂查询
1.实验内容及原理 1. 在 Windows 系统中安装 VMWare 虚拟机,在 VMWare 中安装 Ubuntu 系统,并在 Ubuntu 中搭建 LAMP 实验环境。 2. 使用 MySQL 进行一些基本操作: (1)登录 MySQL,在 MySQL 中创建用户,…...
java虚拟机内存管理
文章目录 概要一、jdk7与jdk8内存结构的差异二、程序计数器三、虚拟机栈3.1 什么是虚拟机栈3.2 什么是栈帧3.3 栈帧的组成 四、本地方法栈五、堆5.1 堆的特点5.2 堆的结构5.3 堆的参数配置 六、方法区6.1 方法区结构6.2 运行时常量池 七、元空间 概要 根据 JVM 规范࿰…...
Hive实战:词频统计
文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据文件1、在虚拟机上创建文本文件2、将文本文件上传到HDFS指定目录 (二)实现步骤1、启动Hive Metastore服务2、启动Hive客户端3、基于HDFS文件创建外部表4、查询单词表&a…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
