Java给图片增加水印,根据图片大小自适应,右下角/斜角/平铺

news/2024/4/24 10:10:40/文章来源:https://blog.csdn.net/qq_41806966/article/details/128088472

Hi,I’m Shendi
最近写自己的文件服务器,上传图片时需要自动增加水印,在这里记录一下



文章目录

  • 效果展示
  • 读取图片
    • 从 byte[] 读取图片
  • 获取画板
  • 绘制水印
    • 根据图片大小自适应水印大小
    • 右下角文字水印
    • 斜角水印
    • 平铺水印
    • 图片水印
  • 输出图片


水印就是在图片上绘画,文字水印是最常见的,比如CSDN文章里图片右下角就会有文字水印

在 Java 中,给图片添加水印一般可以分为以下几步

  1. 读取图片
  2. 获取/创建图片画板
  3. 将水印内容绘制到图片中
  4. 输出图片


效果展示

下面展示的是我所使用的水印效果

测试图片是百度拿的


原图
测试图片

加上水印后
加上水印后的图片
因我的要求不高,所以仅仅对角水印就可以了,可以根据自己需求绘制



读取图片

因为需要在图片上绘制,需要使用到 java.awt.image.BufferedImage 这个类

创建此类对象的方法有多种,这里只列出使用 ImageIO 将原图读取为 BufferedImage 的方式

// read 函数还可以传递输入流,例如直接使用FileInputStream -但需要自己关闭流
BufferedImage img = ImageIO.read(new File("文件地址"));


从 byte[] 读取图片

// 图片数据
byte[] imgData;
ByteArrayInputStream bInput = new ByteArrayInputStream(imgData);
BufferedImage img = ImageIO.read(bInput);


获取画板

Graphics g = img.getGraphics();

上面这种拿到的画板可以画线条圆圈文字等,但是不能旋转

需要旋转的话使用 Graphics2D

Graphics2D g = img.createGraphics();


绘制水印

绘制文字的函数

// 参数一为需要绘制的文字,参数2,3为绘制的位置
img.drawString("文字", x, y);

经过测试,在坐标 0,0 绘制的文字显示的位置是在左上角,但文字是往上显示的,如下图所示
在这里插入图片描述
所以如果想让文字在最左上角显示的话,y需要加上文字的大小

// 设置文字大小,参数一为字体名称,二为样式,三为大小
g.setFont(new Font("黑体", Font.PLAIN, 20));
img.drawString("Shendi", x, 20);

效果如下
在这里插入图片描述


根据图片大小自适应水印大小

首先需要知道如何获取图片大小,拿到BufferedImage,可以通过以下函数获取

// width宽, height高
int width = img.getWidth();
int height = img.getHeight();

拿到宽高后,实现自适应就很简单了,按比例设置文字大小即可
例如

// 这里根据自己需求操作
int fontSize = (width+height) / 40;
g.setFont(new Font("黑体", Font.PLAIN, fontSize));


右下角文字水印

上面已经实现左上角水印了,而且将图片位置拿到了,于是右下角水印就非常简单了

因为在右下角,文字是往右显示的,所以需要得到文字显示占用的宽度,经过测试

单个汉字占用宽度=文字大小
单个字母数字符号占用=文字大小 / 2

中文转bytes占3字节,字母数字只占一字节
于是封装了以下函数

/*** 获取字符串占用的宽度* <br>* @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>* @param str		字符串* @param fontSize	文字大小* @return 字符串占用的宽度*/
public static int getStrWidth(String str, int fontSize) {char[] chars = str.toCharArray();int fontSize2 = fontSize / 2;int width = 0;for (char c : chars) {int len = String.valueOf(c).getBytes().length;// 汉字为3,其余1// 可能还有一些特殊字符占用2等等,统统计为汉字if (len != 1) {width += fontSize;} else {width += fontSize2;}}return width;
}

接下来将文字绘制到右下角就可以看到效果了

String str = "Shendi 砷碲";
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.drawString(str, width - getStrWidth(str, fontSize), height);

在这里插入图片描述

可以给 x 往左移动一点,y往上移动一点,不要在最右下角
水印颜色一般都是透明的,设置透明度达到比较好的效果

String str = "Shendi 砷碲";
// 这里的 new Color四个参数为 rgba,值可以为 0-255, r红,g绿,b蓝,a透明度
g.setColor(new Color(0, 0, 0, 50));
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.drawString(str, width - getStrWidth(str, fontSize) - 30, height - 30);

效果如下
在这里插入图片描述

换张图效果如下
在这里插入图片描述

完整代码如下

BufferedImage img = ImageIO.read(new File("图片位置"));
int width = img.getWidth();
int height = img.getHeight();
int fontSize = (width+height) / 40;String str = "Shendi 砷碲";Graphics2D g = img.createGraphics();
g.setColor(new Color(0, 0, 0, 50));
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.drawString(str, width - getStrWidth(str, fontSize) - 30, height - 30);
g.dispose();ImageIO.write(img, "png", new File("水印图片保存地址"));


斜角水印

右下角水印只有一个,而且所在位置很容易被p图去掉

于是我使用多个水印,简单的排列的话可以横着,竖着,但是斜着是比较好的,所以我使用了这种,也是最开始的展示效果

绘制一定数量的水印,将图片宽高按比例分成 n 份,然后循环绘制水印

BufferedImage img = ImageIO.read(new File("图片地址"));
int width = img.getWidth();
int height = img.getHeight();
// 绘制几个水印/分成几份
int num = 5;
// 每一份x,y的大小
int splitX = width / num, splitY = height / num;
// 每一份中间的位置
int centerX = splitX / 2, centerY = splitY / 2;
int fontSize = (width+height) / 40;Graphics2D g = img.createGraphics();
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
// 设置旋转角度,可以为0-1
g.rotate(0.2);for (int i = 1; i <= num; i++) {int x = splitX * i - centerX - fontSize, y = splitY * i - centerY - fontSize;g.drawString("砷碲测试水印", x, y);
}
g.dispose();
ImageIO.write(img, "png", new File("输出位置"));

效果如下
在这里插入图片描述

绘制了五个水印,其中一个因为旋转而超出图片范围了,问题不大



平铺水印

暴力横竖二层循环绘制就可以了,最后加个旋转

首先需要计算横排能绘制多少个,竖排能绘制多少个

String str = "砷碲测试水印 Shendi";
// 文字占用宽度
int xWidth = getStrWidth(str, fontSize);// x,y可以绘制的数量,多加一个补充空白
int xCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;

按顺序绘制,所以需要有文字间隔,这里使用文字大小作为间隔

// 间隔
int split = fontSize;

设置颜色,旋转,文字大小
接下来循环绘制即可

// i是y轴, 文字默认在y坐标上面,所以这里初始化1
for (int i = 1; i <= yCanNum; i++) {int y = fontSize * i + split * i;for (int j = 0; j < xCanNum; j++) {int x = xWidth * j + split * j;g.drawString(str, x, y);}
}

效果如下
在这里插入图片描述

这种效果不理想,加上旋转后,旋转点是左上角,于是要给 y 减去一定的数值将文字上拉
我这里就使用 y - (文字大小+间隔大小) * j

for (int i = 1; i <= yCanNum; i++) {int y = fontSize * i + split * i;for (int j = 0; j < xCanNum; j++) {int x = xWidth * j + split * j;g.drawString(str, x, y-(fontSize+split)*j);}
}

对于这种水印,文字显得太大了,将文字改小,间距拉大

int fontSize = (width+height) / 80;
int split = fontSize*2;

效果如下
在这里插入图片描述
在这里插入图片描述

完整代码如下

BufferedImage img = ImageIO.read(new File("图片文件"));
int width = img.getWidth();
int height = img.getHeight();int fontSize = (width+height) / 80;Graphics2D g = img.createGraphics();
g.setFont(new Font("黑体", Font.PLAIN, fontSize));
g.setColor(new Color(0, 0, 0, 30));
g.rotate(0.2);String str = "砷碲测试水印 Shendi";
// 间隔
int split = fontSize*2;
// 文字占用的宽度
int xWidth = getStrWidth(str, fontSize);
// x,y可以绘制的数量,多加一个补充空白
intxCanNum = width / xWidth + 1;
int yCanNum = height / fontSize + 1;
for (int i = 1; i <= yCanNum; i++) {int y = fontSize * i + split * i;for (int j = 0; j < xCanNum; j++) {int x = xWidth * j + split * j;g.drawString(str, x, y-(fontSize+split)*j);}
}
g.dispose();
ImageIO.write(img, "png", new File("水印图片保存地址"));

图片水印

绘制文字水印使用 g.drawString,绘制图片水印使用 g.drawImage
例如

BufferedImage wmImg = ImageIO.read(new File("水印图"));
g.drawImage(wmImg, x, y, null);

效果如下
在这里插入图片描述

与文字水印绘制方法一致,但是需要计算坐标和水印图片大小等



输出图片

使用 ImageIO.write 输出

ImageIO.write(img, "png", new File("水印图片保存地址"));

其中第一个参数为图片,第二个参数为图片格式,第三个参数为保存地址

需要注意的是,第二个参数只能为 ImageIO.getReaderFormatNames() 中的项
在这里插入图片描述

如果是图片,最好传 png,使用jpg增加透明度可能 ImageIO.write 为 false(写入失败)



END

一键三连嘛?

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

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

相关文章

SLAM学习笔记(二)

5.相机与图像 相机将三维世界中的坐标点&#xff08;单位米&#xff09;映射到二维图像平面&#xff08;单位为像素&#xff09;的过程中能够用一个几何模型进行描述。 单目相机(Mono)的成像过程&#xff1a; 1、世界坐标系下有个固定的点P&#xff0c;世界坐标为 2、由于相…

基于Java+SSM+Vue+ElementUi的汉语言类网上考试系统

项目介绍 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信…

前置微小信号放大器在光声技术的血管识别研究中的应用

实验名称&#xff1a;前置微小信号放大器在光声技术的血管识别研究中的应用 研究方向&#xff1a;生物识别技术 测试目的&#xff1a; 利用MATLAB对光声血管进行识别&#xff1a;1、对光声血管图库的图像进行预处理包括归一化、二值化、平滑、细化和毛刺修剪得到细化图像&#…

【安卓逆向】去除云注入(使用MT论坛dl的方法总结拓展)

1 需求 因为最近使用的虚拟机突然不能用了&#xff0c;被人云注入强制弹窗&#xff0c;如下图&#xff1a;&#xff08;这一看就是云注入了&#xff09; 2 大佬的方法 如图&#xff08;MT大佬分享的&#xff0c;感兴趣的朋友可以去大佬主页看看他其他文章&#xff09;&…

蓝海创意云接受【看苏州】独家专访:助力苏州数字文化行业全方位发展

近日&#xff0c;由蓝海创意云提供渲染服务的动漫电影《老鹰抓小鸡》获金鸡奖最佳美术片提名&#xff0c;位列获奖名单的《长津湖》《独行月球》也由蓝海创意云渲染提供了后期服务。 就此&#xff0c;苏州广播电视总台旗下的苏州权威热点新闻和视频平台【看苏州】对蓝海彤翔执…

[附源码]计算机毕业设计springboot基于Java的失物招领平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

用R Shiny生态快速搭建交互Web网页APP应用

什么是Shiny&#xff1f; Shiny包可以快速搭建基于R的交互网页应用。对于web的交互&#xff0c;之前已经有一些相关的包&#xff0c;不过都需要开发者熟悉网页编程语言&#xff08;html,CSS,JS&#xff09;。最近我们被客户要求撰写关于R Shiny的研究报告&#xff0c;包括一些…

快速复现 实现 facenet-pytorch 人脸识别 windows上 使用cpu实现 人脸对比

目录0 前言1 搭建环境与项目2 人脸预测与结果展示0 前言 这一次要复现的是人脸识别中的 facenet-pytorch 参考了&#xff1a; Pytorch 搭建自己的Facenet人脸识别网络&#xff08;Bubbliiiing 深度学习 教程&#xff09; https://gitee.com/xiaozhao123666/facenet-pytorch ht…

分布式消息中间件RabbitMQ解析

RabbitMQ作为分布式消息存储和转发系统&#xff0c;已广泛使用于分布式系统中。本文简要介绍RabbitMQ相关概念、集群架构和消息转发流程&#xff0c;并与Kafka做了简要对比&#xff0c;以加深理解。 1、RabbitMQ相关概念 1.1 AMQP介绍 消息&#xff08;Message&#xff09;是…

Zookeeper(一)- Zookeeper介绍与集群部署

文章目录一、Zookeeper 介绍1. Zookeeper概述2. Zookeeper工作机制3. Zookeeper特点4. Zookeeper数据结构5. Zookeeper应用场景&#xff08;1&#xff09;统一命名服务&#xff08;2&#xff09;统一配置管理&#xff08;3&#xff09;统一集群管理&#xff08;4&#xff09;服…

低代码与mes生产管理系统:功能篇

随着信息技术的发展和应用,信息系统在企业中的使用也越来越广泛。不仅可以使企业内部和企业间的信息流通更为便捷和频繁&#xff0c;同时可以提高管理的水平&#xff0c;有助于提高企业的生产效益。其中mes生产管理系统就是美豳的调查资询公司AMR(Advanced Manufacturing Resea…

【目标检测】Faster R-CNN的几点理解

目录&#xff1a;Faster R-CNN的几点理解一、Faster R-CNN概述二、R-CNN、Fast R-CNN、Faster R-CNN的对照2.1 R-CNN2.1.1 R-CNN的检测步骤2.1.2 R-CNN的主要缺点2.2 Fast R-CNN2.2.1 Fast R-CNN的检测步骤2.2.2 Fast R-CNN的缺点2.3 R-CNN、Fast R-CNN、Faster R-CNN的比较三、…

(二)devops持续集成开发——jenkins的权限管理配置

前言 jenkins作为目前主流的devops工具&#xff0c;受到了广大开发用户的追捧。由于其丰富的插件库&#xff0c;其可插拔的功能使得其功能和生态都十分强大。本节内容是关于jenkins的权限管理组件Role-based Authorization Strategy的安装及使用。 正文 下载安装Role-based A…

ThinkPHP5文档学习——配置

文章目录一、配置目录二、配置格式PHP数组定义其它格式的支持二级配置三、配置加载惯例配置应用配置拓展配置场景配置四、读取配置参数五、动态配置设置配置参数六、独立配置独立配置文件V5.0.1版本已经废除该写法自动读取扩展配置七、配置作用域八、环境变量配置一、配置目录 …

历届图灵奖得主盘点

图灵奖&#xff0c;全称A.M.图灵奖&#xff08;ACM A.M Turing Award&#xff09;&#xff0c;是由美国计算机协会于1966年设立的计算机奖项&#xff0c;名称取自艾伦麦席森图灵&#xff0c;旨在奖励对计算机事业作出重要贡献的个人 。图灵奖对获奖条件要求极高&#xff0c;评奖…

第十三章《集合》第3节:Set集合

Set也是Collection的子接口,它定义了另一种形式的集合,专业上称之为Set集合。Set集合的特点如图13-9所示。 图13-9 Set类型集合 从图13-9可以看出:Set类型的集合就像是一个装苹果的筐子,程序员只要把元素存入这个筐子即可。集合中的元素像是胡乱堆积在一起,因此元素没有索…

12【MyBatis注解开发】

文章目录三、Mybatis注解开发3.1 快速入门3.1.1 常用注解说明3.1.2 注解实现开发3.2 注解实现一对一映射3.2.1 接口3.2.2 测试类3.3 注解实现一对多映射3.2.1 接口3.2.2 测试类三、Mybatis注解开发 3.1 快速入门 3.1.1 常用注解说明 注解功能Insert新增Update更新Delete删除…

小学生python游戏编程arcade----单词对错检测及记录写入excel中

小学生python游戏编程arcade----单词对错检测及记录写入excel中前言单词对错检测及记录写入excel中1、excel读取修改1.1 excel读取1.2 修改用到的库1.3 获取Excel表格名称的三种方式1.4 excel格式问题excel文件保存2.1 保存函数2.2 实验2.3 游戏中调用修改2.4 升级时保存字典内…

PCL 点云的法向量

一&#xff0c;点的法向量 点云法线 法向量的概念是很小的时候我们就已经说的&#xff0c;法向量是我们点云中一个非常重要的属性&#xff0c;诸如饿哦们常说的三维重建、点云分割&#xff0c;点云去噪 以及特种描述算法等。 特性&#xff1a; 点云中每一点的法向量夹角和曲率…

面试汇总-MySQL-杂项

目录 1、悲观锁和乐观锁 2、数据库关键字的执行顺序是什么&#xff1f; 3、SQL优化 3.1、如何进行sql优化&#xff1f; 3.2、常见的join算法 3.2.1、Hash Join 3.2.2、Merge Join 3.2.3、Nested Loop Join 3.3、Join前后表的数据量对查询性能有什么影响&#xff1f; …