java实现图片添加水印
文章目录
- 前言
- 一、工具类WatermarkUtil
- 二、工具类介绍
- 2.1 图片来源类型
- 2.2 水印类型
- 2.3 读取本地图片
- 2.4 读取网络图片
- 2.5 水印处理
- 2.6 添加水印
- 三、测试添加水印
- 总结
前言
给图片添加水印是一个很常见的需求,一般是用来防盗用。比如我们csdn上面写的文章中,如果包含图片,那么可以给图片带上个人水印标志。笔者是因为工作需要,特此研究一下使用java实现给图片加水印的方法。
一、工具类WatermarkUtil
完整的工具类代码如下
package com.hulei.watermark;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;/*** 添加水印util*/
public class WatermarkUtil {/*** 添加水印** @param pictureSourceType 图片来源类型* @param watermarkType 水印类型* @param path 图片路径* @param watermark 水印内容(文字水印内容/图片水印的存放路径)* @param formatName 图片格式* @param targetPath 输出图片存放路径* @param color 水印颜色*/public static void addWatermark(PictureSourceType pictureSourceType, WatermarkType watermarkType, String path, String watermark, String formatName, String targetPath, Color color) {if (null == pictureSourceType) {throw new RuntimeException("图片来源类型不能为空");}if (null == watermarkType) {throw new RuntimeException("水印类型不能为空");}Image image;if (pictureSourceType == PictureSourceType.LOCAL_PICTURE) {// 读取本地图片image = readLocalPicture(path);} else {// 读取网络图片image = readNetworkPicture(path);}// 水印处理manageWatermark(image, watermarkType, watermark, formatName, targetPath, color);}//图片来源类型枚举public enum PictureSourceType {//本地图片LOCAL_PICTURE,//网络图片NETWORK_PICTURE;}//水印类型枚举public enum WatermarkType {//文字水印TEXT_WATERMARK,//图片水印IMAGE_WATERMARK;}/*** 读取本地图片** @param path 本地图片存放路径*/public static Image readLocalPicture(String path) {if (null == path) {throw new RuntimeException("本地图片路径不能为空");}// 读取原图片信息 得到文件File srcImgFile = new File(path);try {// 将文件对象转化为图片对象return ImageIO.read(srcImgFile);} catch (IOException e) {throw new RuntimeException(e);}}/*** 读取网络图片** @param path 网络图片地址*/public static Image readNetworkPicture(String path) {if (null == path) {throw new RuntimeException("网络图片路径不能为空");}try {// 创建一个URL对象,获取网络图片的地址信息URL url = new URL(path);// 将URL对象输入流转化为图片对象 (url.openStream()方法,获得一个输入流)BufferedImage bugImg = ImageIO.read(url.openStream());if (null == bugImg) {throw new RuntimeException("网络图片地址不正确");}return bugImg;} catch (IOException e) {throw new RuntimeException(e);}}/*** 水印处理** @param image 图片对象* @param watermarkType 水印类型(1-文字水印 2-图片水印)* @param watermark 水印内容(文字水印内容/图片水印的存放路径)* @param formatName 图片格式* @param tarImgPath 输出图片存放路径* @param color 水印颜色*/public static void manageWatermark(Image image, WatermarkType watermarkType, String watermark, String formatName, String tarImgPath, Color color) {int imgWidth = image.getWidth(null);int imgHeight = image.getHeight(null);BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);// 加水印,创建画笔Graphics2D graphics = bufImg.createGraphics();// 绘制原始图片graphics.drawImage(image, 0, 0, imgWidth, imgHeight, null);// 校验水印的类型if (watermarkType == WatermarkType.TEXT_WATERMARK) {if (watermark.isEmpty()) {throw new RuntimeException("文字水印内容不能为空");}// 添加文字水印:// 根据图片的背景设置水印颜色graphics.setColor(color == null ? Color.RED : color);// 设置字体 画笔字体样式为微软雅黑,加粗,文字大小为45ptgraphics.setFont(new Font("微软雅黑", Font.BOLD, 45));// 设置水印的坐标(为原图片中间位置)int x = (imgWidth - getWatermarkLength(watermark, graphics)) / 2;int y = imgHeight / 2;// 画出水印 第一个参数是水印内容,第二个参数是x轴坐标,第三个参数是y轴坐标graphics.drawString(watermark, x, y);graphics.dispose();} else {// 添加图片水印:if (watermark.isEmpty()) {throw new RuntimeException("图片水印存放路径不能为空");}Image srcWatermark = readLocalPicture(watermark);int watermarkWidth = srcWatermark.getWidth(null);int watermarkHeight = srcWatermark.getHeight(null);// 设置 alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.9f));// 绘制水印图片 坐标为中间位置graphics.drawImage(srcWatermark, (imgWidth - watermarkWidth) / 2, (imgHeight - watermarkHeight) / 2, watermarkWidth, watermarkHeight, null);graphics.dispose();}// 输出图片try {FileOutputStream outImgStream = new FileOutputStream(tarImgPath);ImageIO.write(bufImg, formatName, outImgStream);outImgStream.flush();outImgStream.close();} catch (IOException e) {throw new RuntimeException(e);}}/*** 获取水印文字的长度** @param watermarkContent 文字水印内容* @param graphics 图像类*/private static int getWatermarkLength(String watermarkContent, Graphics2D graphics) {return graphics.getFontMetrics(graphics.getFont()).charsWidth(watermarkContent.toCharArray(), 0, watermarkContent.length());}}
二、工具类介绍
2.1 图片来源类型
这个枚举主要包括两个待添加水印的图片来源类型,分别为本地图片和网络图片,即是给本地图片加水印还是网络图片加水印。
//图片来源类型枚举public enum PictureSourceType {//本地图片LOCAL_PICTURE,//网络图片NETWORK_PICTURE;}
2.2 水印类型
给图片加水印,水印也分为两种类型,分别为文字水印和图片水印,图片水印即是把图片作为水印添加到另外一个图片上。
//水印类型枚举public enum WatermarkType {//文字水印TEXT_WATERMARK,//图片水印IMAGE_WATERMARK;}
2.3 读取本地图片
该函数用于读取指定路径下的本地图片,并返回一个Image对象。如果路径为空,则抛出运行时异常;如果读取图片失败,则将捕获的IOException转换为运行时异常抛出。
2.4 读取网络图片
该函数用于读取网络图片。首先检查传入的网络图片地址是否为空,如果为空则抛出运行时异常。然后通过URL对象获取网络图片的输入流,并使用ImageIO的read方法将输入流转化为图片对象。如果转化失败则抛出运行时异常。最后返回转化成功的图片对象。
2.5 水印处理
该函数用于给图片添加水印,支持文字水印和图片水印两种类型。根据传入的水印类型,选择添加文字水印或图片水印。对于文字水印,会根据传入的颜色设置水印颜色,设置字体样式为微软雅黑加粗45pt,将水印内容居中显示在图片上。对于图片水印,会读取指定路径的图片,并将其居中显示在图片上。最后将添加了水印的图片输出到指定路径。
2.6 添加水印
该函数用于给图片添加水印。根据传入的图片来源类型和水印类型,读取相应的图片并进行水印处理,最后将处理后的图片保存到指定路径。具体流程如下:
- 检查传入的图片来源类型和水印类型是否为空,若为空则抛出异常。
- 根据图片来源类型,读取本地图片或网络图片。
- 调用manageWatermark方法对图片进行水印处理,处理包括水印类型、水印内容、图片格式、输出路径和水印颜色等参数。
- 完成水印处理后,函数执行结束。
public static void addWatermark(PictureSourceType pictureSourceType, WatermarkType watermarkType, String path, String watermark, String formatName, String targetPath, Color color) {if (null == pictureSourceType) {throw new RuntimeException("图片来源类型不能为空");}if (null == watermarkType) {throw new RuntimeException("水印类型不能为空");}Image image;if (pictureSourceType == PictureSourceType.LOCAL_PICTURE) {// 读取本地图片image = readLocalPicture(path);} else {// 读取网络图片image = readNetworkPicture(path);}// 水印处理manageWatermark(image, watermarkType, watermark, formatName, targetPath, color);}
三、测试添加水印
主要功能是给图片添加水印。具体来说,函数使用了WatermarkUtil工具类的addWatermark方法,实现了给本地图片和网络图片添加文字水印和图片水印,并将添加水印后的图片保存到指定路径。函数中定义了图片的本地路径、网络地址、水印内容、水印图片路径、输出格式以及水印颜色等参数。通过调用addWatermark方法,实现了给本地图片和网络图片添加文字水印和图片水印的功能。
测试类完整代码
package com.hulei.watermark;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.awt.*;@SpringBootTest
class AddWaterMarkApplicationTests {@Testvoid contextLoads() {// 本地图片路径String localPath = "D:/localImage.png";// 网络图片地址String networkPath = "https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2023%2F0329%2F31dc71faj00rs8saz004sd000vc015sm.jpg&thumbnail=660x2147483647&quality=80&type=jpg";// 文字水印内容String textWatermark = "Hello World!";// 图片水印路径String pictureWatermark = "D:/imageWaterMark.png";//输出图片的格式String outputFormat = "jpg";//本地图片添加文字水印输出地址String local_image_text_watermark = "E:/local_image_text_watermark.jpg";//本地图片添加图片水印输出地址String local_image_picture_watermark = "E:/local_image_picture_watermark.jpg";//网络图片添加文字水印输出地址String network_image_text_watermark = "E:/network_image_text_watermark.jpg";//网络图片添加图片水印输出地址String network_image_picture_watermark = "E:/network_image_picture_watermark.jpg";// 本地图片 添加文字水印WatermarkUtil.addWatermark(WatermarkUtil.PictureSourceType.LOCAL_PICTURE, WatermarkUtil.WatermarkType.TEXT_WATERMARK, localPath,textWatermark,outputFormat,local_image_text_watermark,Color.RED);// 本地图片 添加图片水印,图片水印不需要设置颜色WatermarkUtil.addWatermark(WatermarkUtil.PictureSourceType.LOCAL_PICTURE, WatermarkUtil.WatermarkType.IMAGE_WATERMARK, localPath, pictureWatermark,outputFormat,local_image_picture_watermark,null);// 网络图片 添加文字水印WatermarkUtil.addWatermark(WatermarkUtil.PictureSourceType.NETWORK_PICTURE, WatermarkUtil.WatermarkType.TEXT_WATERMARK, networkPath, textWatermark,outputFormat,network_image_text_watermark,Color.RED);// 网络图片 添加图片水印,图片水印不需要设置颜色WatermarkUtil.addWatermark(WatermarkUtil.PictureSourceType.NETWORK_PICTURE, WatermarkUtil.WatermarkType.IMAGE_WATERMARK, networkPath, pictureWatermark,outputFormat,network_image_picture_watermark,null);}}
注意:png图片不能是非png格式的图片通过改名和修改后缀得到,否则将会读取不到图片
这两个图片分别为本地图片和作为水印的图片,笔者放在了D盘根目录下
点击测试类方法后会在E盘得到四张不同图片,依次如下:
- 本地图片添加文字水印
- 本地图片添加图片水印
- 网络图片添加文字水印
- 网络图片添加图片水印
总结
以上就是笔者在探索使用java为图片添加水印完整过程,使用的都是java原生提供的处理图片的方式。使用的图片都是一些网上随便找的,如有侵权请评论区找我,我会及时撤下哈。
相关文章:

java实现图片添加水印
文章目录 前言一、工具类WatermarkUtil二、工具类介绍2.1 图片来源类型2.2 水印类型2.3 读取本地图片2.4 读取网络图片2.5 水印处理2.6 添加水印 三、测试添加水印总结 前言 给图片添加水印是一个很常见的需求,一般是用来防盗用。比如我们csdn上面写的文章中&#…...

CSS规则——font-face
font-face 什么是font-face? 想要让网页文字千变万化,仅靠font-family还不够,还要借助font-face(是一个 CSS 规则,它允许你在网页上使用自定义字体,而不仅仅是用户系统中预装的字体。这意味着你可以通过提…...

【单片机毕业设计选题24034】-基于STM32的手机智能充电系统
系统功能: 系统可以设置充电时长,启动充电后按设置的充电时长充电,充电时间到后自动 停止充电,中途检测到温度过高也会结束充电并开启风扇和蜂鸣器报警。 系统上电后,OLED显示“欢迎使用智能充电系统请稍后”,两秒钟…...

[C++][数据结构][图][中][图的遍历][最小生成树]详细讲解
目录 1.图的遍历1.广度优先遍历2.深度优先遍历 2.最小生成树1.Kruskal算法2.Prim算法 1.图的遍历 给定一个图G和其中任意一个顶点 v 0 v_0 v0,从 v 0 v_0 v0出发,沿着图中各边访问图中的所有顶点,且每个顶 点仅被遍历一次 “遍历”&…...
退市新规解读—财务类强制退市
一、退市风险警示:第一年触及相关指标 上市公司最近一个会计年度触及下列退市风险指标之一,公司股票或存托凭证被实施退市风险警示(*ST): 第1项 组合类财务指标 仅发行A股或B股,最近一个会计年度或追溯重述后最近一个会计年度 …...
小程序的生命周期使用方法和应用场景
小程序生命周期 初始化(App Launch) • 触发时机:小程序首次启动时。 • 主要事件:onLaunch。 • 功能与适用场景: • 全局数据初始化:设置应用的全局状态和变量。 • 登录状态检查:判断用户是…...
什么是C++模块化系统?C++20的模块化系统。
C20引入的模块化系统是一种新的代码组织和编译机制,它旨在替代传统的头文件机制,提供更好的代码组织、更快的编译速度和更强的封装性。模块化系统的主要目标包括: 减少编译时间:通过减少冗余的头文件解析和宏定义传播,…...

智慧校园-档案管理系统总体概述
智慧校园档案管理系统,作为教育信息化进程中的重要一环,它运用现代信息技术的力量,彻底改变了传统档案管理的面貌,为学校档案资源的收集、整理、存储、检索与利用开辟了全新的途径。这一系统全面覆盖学生、教职工、教学科研及行政…...

文心一言 VS 讯飞星火 VS chatgpt (290)-- 算法导论21.3 3题
三、给出一个包含 m 个 MAKE-SET 、UNION 和 FINDSET 操作的序列(其中有 n 个是 MAKE-SET 操作),当仅使用按秩合并时,需要 Ω(mlgn) 的时间。如果要写代码,请用go语言。 文心一言: 在并查集(Union-Find)数…...
逻辑回归梯度推导
逻辑回归是一种广泛使用的分类算法,用于估计一个事件发生的概率。它是线性回归的扩展,通过sigmoid函数将线性回归的输出映射到[0, 1]区间,从而用于分类任务。 在逻辑回归中,我们使用对数似然损失函数(log-likelihood l…...
Python 使用函数输出一个整数的逆序数
在Python中,你可以定义一个函数来输出一个整数的逆序数。这里有一个简单的实现方法: def reverse_integer(x):# 检查输入是否为整数if not isinstance(x, int):raise ValueError("Input must be an integer")# 将整数转换为字符串,…...

【Linux】Wmware Esxi磁盘扩容
目录 一、概述 1.1 磁盘分区概念 1.2 LVM概念 二、扩容步骤 二、报错 一、概述 1.1 磁盘分区概念 在 Linux 中,每一个硬件设备都映射到一个系统的文件,对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux把各种 IDE 设备分配了一个由 hd 前缀组成的文…...

树莓派4B_OpenCv学习笔记15:OpenCv定位物体实时坐标
今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi) 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1: 今日学习 OpenCv定位物体实时位置,代码来源是…...

MySQL之如何定位慢查询
1、如何定位慢查询 1.1、使用开源工具 调试工具:Arthas 运维工具:Promethuss、Skywalking 1.2、MySQL自带慢日志 慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒&#x…...

Open3D 删除点云中重复的点
目录 一、算法原理1、重叠点2、主要函数二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、重叠点 原始点云克隆一份 构造重叠区域 合并点云获得重叠点 2、主要…...

填报志愿选专业是兴趣重要还是前景重要?
进行专业评估,找到一个适合自己的专业是一件非常困难的事情。在进行专业选择时,身上理想化色彩非常严重的人,会全然不顾及他人的劝阻,义无反顾的以兴趣为主,选择自己热爱的专业。一些较多考虑他人建议,能听…...
python开发基础——day9 函数基础与函数参数
一、初识函数(function) 编程函数!数学函数,里面的是逻辑,功能,而不是套公式 编程函数的作用实现特定操作的一段代码 你现在请客,每个人都点同样的一份吃的,请100个人 1.薯条 2.上校鸡块 3.可乐 那…...

STM32——使用TIM输出比较产生PWM波形控制舵机转角
一、输出比较简介: 只有高级定时器和通用寄存器才有输入捕获/输出比较电路,他们有四个CCR(捕获/比较寄存器),共用一个CNT(计数器),而输出比较功能是用来输出PWM波形的。 红圈部分…...
第十五章 集合(set)(Python)
文章目录 前言一、集合 前言 集合(set)是一个无序的不重复元素序列。 一、集合 set {1, 2, 3, 4}...

面试-javaIO机制
1.BIO BIO:是传统的javaIO以及部分java.net下部分接口和类。例如,socket,http等,因为网络通信同样是IO行为。传统IO基于字节流和字符流进行操作。提供了我们最熟悉的IO功能,譬如基于字节流的InputStream 和OutputStream.基于字符流…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...