Java之Graphics2D图片生成水印

2023-11-18

目录

一、介绍

二、效果图

三、代码

四、优化方向

五、参考链接


一、介绍

百度百科:Graphics2D ,Graphics 类,提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制

不止通过JDK提供的工具类,还可以使用第三方的Thumbnailator工具,进行添加水印、制作缩略图等功能

二、效果图

1、生成水印前:

2、生成水印后:

三、代码

public class WaterMarkUtil {

    private final static String[] IMAGE_TYPE = {"PNG","JPEG","JPG", "BMP", "GIF"};

    private final static int HEADER_SIZE = 4;

    public static byte[] getImageWithWaterMark(InputStream inputStream, String waterMarkContent) throws Exception {
        if(null == inputStream){
            throw new Exception("输入流不能为空");
        }

        if(null == waterMarkContent || waterMarkContent.isEmpty()){
            throw new Exception("水印内容不能为空");
        }

        // 封装为BufferedInputStream,用于流文件类型读取后的重置
        BufferedInputStream bufferedInputStream  = new BufferedInputStream(inputStream);
        // 标记读取的文件类型长度
        bufferedInputStream.mark(HEADER_SIZE);

        // 获取文件类型
        String fileType = getFileType(bufferedInputStream);

        // 重置流到开始位置
        bufferedInputStream.reset();

        // 判断是否图片,否则结束处理
        boolean isImage = matchImageType(fileType);
        if(!isImage){
            throw new Exception("文件类型非图片类型,支持:png、jpeg、jpg、bmp、gif,当前文件类型:" + fileType);
        }

        BufferedImage targetImg = ImageIO.read(bufferedInputStream);
        int height = targetImg.getHeight();
        int width = targetImg.getWidth();

        //-------------------------文字水印 start----------------------------
        BufferedImage waterMarkImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 创建画笔
        Graphics2D graphics2D = waterMarkImage.createGraphics();
        // 绘制原始图片
        graphics2D.drawImage(targetImg, 0, 0, width, height, null);

        // 设置水印颜色
        graphics2D.setColor(new Color(255, 255, 255, 50));

        double scale = 1.0;
        if(width < height){
            scale = (double) width / height;
        }
        int fontSize = (int) Math.ceil((double) (height / 25) * scale);
        // 设置字体 画笔字体样式为微软雅黑,加粗,文字大小按比例给
        graphics2D.setFont(new Font("微软雅黑", Font.BOLD, fontSize));

        // 水印旋转度
        graphics2D.rotate(Math.toRadians(-25), (double) width / 2, (double) height / 2);

        int x = -width * 3;
        int y;
        // 计算水印文字的宽度
        FontMetrics fontMetrics = graphics2D.getFontMetrics();
        int watermarkWidth = fontMetrics.stringWidth(waterMarkContent);
        // 水印横向间隔
        int positionWidth = (int)(width * 0.15);
        // 水印竖向间隔
        int positionHeight  = (int)(height * 0.15);

        while (x < width * 3) {
            y = -height * 3;
            while (y < height * 3) {
                graphics2D.drawString(waterMarkContent, x, y);
                y += fontSize + positionWidth;
            }
            x += watermarkWidth + positionHeight;
        }

        graphics2D.dispose();
        //-------------------------文字水印 end----------------------------

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(waterMarkImage, fileType, byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }

    private static boolean matchImageType(String fileType){
        if(null == fileType || fileType.isEmpty()){
            return false;
        }

        for (String type : IMAGE_TYPE) {
            if (fileType.equalsIgnoreCase(type)) {
                return true;
            }
        }

        return false;
    }


    private static String getFileType(InputStream is){
        String fileType = null;
        String fileHeader;
        byte[] temp = new byte[HEADER_SIZE];

        try {
            is.read(temp, 0, HEADER_SIZE);
            // 将读取到的字节数组转为十六进制字符串,,方法来自apache的commons-codec包
            fileHeader = Hex.encodeHexString(temp).toUpperCase();

            // 以下罗列几种类型,更多自行拓展
            if (fileHeader.contains("504B0304")) {

                fileType = "xlsx";
            } else if (fileHeader.contains("FFD8FF")) {

                fileType = "jpg";
            } else if (fileHeader.contains("89504E47")) {

                fileType = "png";
            } else if (fileHeader.contains("47494638")) {

                fileType = "gif";
            } else if (fileHeader.contains("25504446")) {

                fileType = "pdf";
            } else if (fileHeader.contains("424D")) {

                fileType = "bmp";
            } else {

                fileType = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return fileType;
    }


}

四、优化方向

目前这个版本的水印生成还是有局限性的,比如:图片太小、水印内容太长之类的问题,会导致生成的效果有问题,所有如果你遇到这种情况,可以通过以下的方面进行优化:

1、水印文字大小按照图片等比例进行控制

2、限制水印文字大小,水印宽度不得超过图片宽度的百分之多少,通过水印宽度反出水印文字字数过多

3、限制图文长度与宽度,过小就不生成,或者只生成一个水印之类的

五、参考链接

Java实现给图片加单个、多个文字水印_java添加多个水印_斯内克喜欢吃益达的博客-CSDN博客

java实现给图片添加水印(文字水印或图片水印)_12程序猿的博客-CSDN博客 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java之Graphics2D图片生成水印 的相关文章

  • Spring @PostConstruct 依赖于 @Profile

    我想在一个配置类中拥有多个 PostConstruct 带注释的方法 这些方法应该根据 Profile 进行调用 你可以想象这样的代码 Configuration public class SilentaConfiguration priv
  • Spring 框架 application.properties 与 logback.xml

    我正在使用 Spring 和 Spring boot 最近 在尝试使用 EhCache 时 我尝试为 EhCache 启用日志记录 在 application properties 中设置日志级别 logging level org spr
  • Spring Kafka - 为任何主题的分区消耗最后 N 条消息

    我正在尝试读取请求的卡夫卡消息数 对于非事务性消息 我们将从 endoffset N 对于 M 个分区 开始轮询并收集当前偏移量小于每个分区的结束偏移量的消息 对于幂等 事务消息 我们必须考虑事务标记 重复消息 这意味着偏移量将不连续 在这
  • Vaadin框架播放视频

    我可以使用 Vaadin Framewotk 播放视频吗 主要思想是从本地驱动器加载 flv 或 avi 格式的视频文件 并使用 vaadin 框架在网络上播放 谢谢 Sampler中有一个示例 http demo vaadin com s
  • 如何获取JavaFX的版本号?

    如何在运行时找出我正在使用哪个版本的 JavaFX 简单的方法之一就是简单地阅读javafx properties文件位于您的 JAVA HOME jre lib目录 我现在安装了 Java 1 7 u9 与之捆绑的 JavaFX 是 v2
  • 原型组件的 Spring 事件处理

    假设我有两个组件 X 和 Y 其中 X 是单例 而 Y 不是 当我发布XUpdateEvent时 没有问题 我可以捕获该事件 但是 对于 YUpdateEvent 我无法捕获事件 Spring 为每个触发的事件创建新实例 而不是使用已经创建
  • Java RCP/SWT - Eclipse RCP 中的“Android Toast like”对话框

    有谁知道是否存在某些弹出窗口的实现 例如 Android TOAST 通知是以下内容的一部分迈林公共区 https projects eclipse org projects mylyn commons 要集成它们 请添加Mylyn Com
  • 为什么在java中加载JNI是在静态初始化程序中完成的?

    在许多使用 JNI 的示例中 我看到类似以下内容 class SampleClass static System loadLibrary somelib 这种特殊语法的目的是什么 为什么使用这个 而不仅仅是在类构造函数或类似的东西中 我想你
  • 如何在 TestNG 报告中包含 Log4j2 消息

    我希望在所有测试用例的 TestNG 报告中提供 Log4j2 日志记录信息 TestNG 使用一个名为 Reporter java 的特殊记录器类来跟踪日志输出并将其保存在其结果 XML 中 在 log4j 中 可以简单地创建一个路由到
  • 自 Java 7 以来 HttpServer 延迟 1 秒

    我们正在使用内部HttpServer项目中的类 用于通过 HTTP 在客户端和服务器之间交换数据 当我们切换到 Java 7 时 我们意识到结果交付存在延迟 我们可以将问题简化为以下示例 Class EchoServer创建上下文 echo
  • ImageIO read() 和 write() 操作后 GIF 图像变得错误

    我有这个代码 它只是读取 GIF 文件 用背景重新绘制它 然后输出到新的 GIF 文件 问题是结果文件变得奇怪 我不知道为什么它的质量变得很差 JPG 文件不会出现此问题 如何修复它 import java awt Color import
  • javax.validation 的 @AssertTrue - 它不应该创建错误消息吗?

    我在 Spring MVC 命令 bean 中有以下代码 AssertTrue public boolean isConditionTrue return false private boolean conditionTrue 我的 JSP
  • 使用 Spring 的 SimpleNamingContextBuilder 的应用程序如何知道在其目录中搜索资源?

    使用 Spring 的应用程序如何SimpleNamingContextBuilder http static springsource org spring docs 3 0 x api org springframework mock
  • 用于计算句子中单词数的正则表达式

    public static int getWordCount String sentence return sentence split a zA Z0 9 a zA Z0 9 1 length sentence replaceAll a
  • Eclipse 错误:“设置构建路径”遇到错误

    我正在使用一个名为 jtwitter 的 API 它有一个 jar 文件 jtwitter jar 我一直在使用它并使用 git 维护它 我把代码托管在github上 有些天 我没有碰过它的代码 今天 当我克隆我的 git repo 时 实
  • 如何使用二叉树中的递归来完成回溯

    我正在尝试插入一个二进制节点 我的代码很复杂 没有希望挽救它 所以我计划重写它 基本上我没有考虑回溯 也没有仔细考虑算法 我正在尝试使用顺序遍历插入二进制节点 但我不明白应该如何回溯 D B E A C F 我如何搜索根 D 的左子树 然后
  • 通过命令行增加Java中的MaxPermSize内存

    您能否解释一下如何增加此 PermSpace 大小 我正在使用 Gate 应用程序并加载大量数据和大量插件 不幸的是每次运行后都会出现有关内存不足 maxPermSpace 的错误 我到处搜索 但我找不到如何通过命令行增加这个大小 或者可能
  • java.lang.Object#getClass() 的 Eclipse 外部空注释

    我正在使用 Eclipse Mars 中提供的外部空注释工具 我正在尝试添加外部注释java lang Object getClass 但似乎无法正确签名 我尝试过以下变体 NonNull Class getClass L1java lan
  • Tomcat 与 Weblogic JNDI 查找

    我们使用的 Weblogic 服务器已配置为允许 JNDI 数据源名称 例如 appds 对于开发 本地主机 我们可能会运行 Tomcat 并且在 server xml 的 部分中声明时 Tomcat 会将 JNDI 数据源挂在 JNDI
  • 删除子类中的注释?

    我有一个子类 需要一个注释 在删除的父类中声明 做这个的最好方式是什么 public class Parent MyAnnoation String foobar public class Child extends Parent here

随机推荐

  • Linux启动网卡时出现RTNETLINK answers: File exists错误解决方法

    一 问题描述 VMware中克隆虚拟机是经常的事情 虽然如此 用到虚拟机时 本人还是喜欢新安装一个操作系统 针对服务器的应用 在安装操作系统时 一并安装好 并且也花不了多少时间 但最近需要大量的配置一样的虚拟机进行测试 故安装了一个模板虚拟
  • 几种基本放大电路详解

    可提前了解的文章 运算放大器 运放 介绍 注意 此处我们采用的是Multisim软件仿真 链接中有详细安装教程 注意 仿真只是数学运算 实际情况的话 就不是数学运算那么简单 有很多复杂的因数在里面 所以具体情况要参照实际电路搭建 比如说 之
  • C++模板-33-类模板和函数模板的区别

    这篇开始学习类模板相关知识 本篇主要学习什么是类模板 还有类模板和函数模板的区别 1 类模板语法 template
  • Java调试的变迁:从System.out.println到log4j

    jungleford如是说 用惯了VC的人刚接触Java大概很不习惯代码的调试 的确 在M 的大部分IDE都做得相当出色 包括像VJ 这样一直被Java程序员称为是 垃圾 的类库 记得以前在瀚海星云的Java版提有关VJ问题的人是有可能被封
  • linux下python第三库(setuptools)的安装

    rpm源的下载网址 http rpm pbone net http www rpmfind net linux RPM index html python第三方模块的下载网址 https pypi python org pypi setup
  • amd 皓龙 服务器 芯片,全面解读 关于AMD皓龙6000平台的那些事

    今年3月30日 AMD面向全球发布了代号 Magny Cours 的AMD皓龙6100处理器 在4月19日 AMD在上海召开AMD皓龙6000系列平台发布会 标志着AMD皓龙6000平台正式登录中国 在x86服务器处理器中 AMD皓龙堪称一
  • java中的静态方法是什么

    静态方法是使用公共内存空间的 就是说所有对象都可以直接引用 不需要创建对象再使用该方法 然后在含有main方法的类中使用这个类时 对与以上非静态和静态方法的引用方式是不同的 如下 public class mainClass int sum
  • vscode可以调试c但是无法调试c++程序的

    安装Vscode后调试c程序正常 但是调试c 程序出现问题 出现launch program xxxxxx does not exist的问题 我发现是无法正常生成exe文件导致的问题 当我们对c程序进行调试时 可以正常生成exe文件 但是
  • 太牛逼了!从Python入门到入魔

    总被读者问到 我看完了python入门的书 后面就不知道要学什么了 今天就给你们整理全套入门到进阶的教程 这套教程非常全面而且详细 从Python入门到Python进阶 Django Flask等Web框架以及爬虫 数据库 算法与数据结构等
  • 计算机ip保留地址,分类ip地址中,保留地址有哪些?具体点说说,作业。

    分类ip地址中 保留地址有哪些 具体点说说 作业 以下文字资料是由 历史新知网www lishixinzhi com 小编为大家搜集整理后发布的内容 让我们赶快一起来看一下吧 分类ip地址中 保留地址有哪些 具体点说说 作业 A类地址中的私
  • Vue开发组件库

    Vue开发组件库 1 创建项目 npm install g vue cli vue create 项目名 针对于vue脚手架生成的项目需要做出一些调整 将src重命名为examples 防止第三方开发者产生的歧义 添加examples同级目
  • MySQL CRUD (带样例)

    目录 1 Create 创建 1 1 单行数据 全列插入 1 2 多行数据 指定列插入 1 3 插入否则更新 1 4 替换 2 Retrieve 读取 2 1 SELECT 列 全列查询 指定列查询 查询字段为表达式 为查询结果指定别名 结
  • 螺旋式排列数组

    文章目录 前言 解题思路 上代码 总结 前言 螺旋式排列数组在letcode中属于中等难度的题型 但是对于俺这种道行浅的人再次重新拾起正吃灰的C语言的菜鸟来说确实不容易 其实思路不难 按主要是卡在了二维数组空间的分配问题上 最后调试才将代码
  • 【软件测试】selenium3

    自动化测试的概念 自动化测试指软件测试的自动化 在预设状态下运行应用程序或者系统 预设条件包括正常和异常 最 后评估运行结果 将人为驱动的测试行为转化为机器执行的过程 自动化测试就相当于将人工测试手段进行转换 让代码去执行 提高测试效率 保
  • python中的groupby()函数

    1 groupby 函数介绍 groupby 函数扫描整个序列并且查找连续相同值 或者根据指定key函数返回值相同 的元素序列 在每次迭代的时候 它会返回一个值和一个迭代器对象 这个迭代器对象可以生成元素值全部等于上面那个值的组中所有对象
  • 【深度学习】经典的卷积神经网络模型介绍(LeNet、AlexNet、VGGNet、GoogLeNet、ResNet和MobileNet)

    经典的卷积神经网络模型介绍 卷积神经网络简介 一 LeNet 1 INPUT层 输入层 2 C1层 卷积层 3 S2层 池化层 下采样层 4 C3层 卷积层 5 S4层 池化层 下采样层 6 C5层 卷积层 7 F6层 全连接层 二 Ale
  • 灰色预测模型matlab_灰色预测

    你好 我是goldsunC让我们一起进步吧 文章目录 灰色预测引言灰色预测的类型最简单的模型 GM 1 1 GM 1 1 模型实例原理及求解数据处理方法 1 累加生成2 累减生成3 均值生成求解步骤框图求解步骤小误差概率p及方差比检验标准
  • 企业管理靠员工自觉只能是海市蜃楼

    企业管理靠员工自觉只能是海市蜃楼 凭良心做事好不好 好 要不要凭良心做事 要 但得有前提 这个前提就是这家企业人人讲良心 个个讲良心 特别是老板讲良心 如果老板让员工讲良心 自己不讲良心 讲良心的人不是伤心走了 就是有样学样 也不讲良心了
  • C++进阶 智能指针

    本篇博客简介 介绍C 中的智能指针 智能指针 为什么会存在智能指针 内存泄露 内存泄漏定义 内存泄漏的危害 如何检测内存泄漏 如何避免内存泄漏 智能指针的使用及其原理 RAII 设计一个智能指针 C 官方的智能指针 定制删除器 智能指针总结
  • Java之Graphics2D图片生成水印

    目录 一 介绍 二 效果图 三 代码 四 优化方向 五 参考链接 一 介绍 百度百科 Graphics2D Graphics 类 提供了对几何形状 坐标转换 颜色管理和文本布局更为复杂的控制 不止通过JDK提供的工具类 还可以使用第三方的T