当前位置: 首页 > news >正文

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盘得到四张不同图片,依次如下:

  1. 本地图片添加文字水印

在这里插入图片描述

  1. 本地图片添加图片水印

在这里插入图片描述

  1. 网络图片添加文字水印

在这里插入图片描述

  1. 网络图片添加图片水印

在这里插入图片描述

总结

以上就是笔者在探索使用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引入的模块化系统是一种新的代码组织和编译机制,它旨在替代传统的头文件机制,提供更好的代码组织、更快的编译速度和更强的封装性。模块化系统的主要目标包括: 减少编译时间:通过减少冗余的头文件解析和宏定义传播&#xff0c…...

智慧校园-档案管理系统总体概述

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

文心一言 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")# 将整数转换为字符串&#xff0c…...

【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.基于字符流…...

centos 7 部署awstats 网站访问检测

一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

条件运算符

C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...

MMaDA: Multimodal Large Diffusion Language Models

CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...