Java实现添加文字水印、图片水印功能

news2024/11/6 7:20:52

Java实现添加水印功能

  • 添加水印
    • Java 2D API介绍
    • 绘制文字水印
    • 绘制图片水印
    • 循环添加文字水印

添加水印

为图片添加水印的主要作用是保护图片版权,防止图片被未经授权的人使用或传播。为图片添加水印是一种常用的图片处理技术。在Java 中可以使用JDK自带的 Graphics2D 类来绘制水印。可以添加图片水印或者文字水印。

Java 2D API是Java 平台上用于绘制 2D 图形的一组类和方法。它支持多种格式的图像、字体和颜色管理,并提供了许多高级特性,如 alpha 融合、深度缓冲区等。

Java 2D API介绍

1.创建一个绘制图形的对象

使用Graphics2D 类来创建一个绘制图形的对象。Graphics2D 对象是扩展了 Graphics 类的一个子类,提供了更多的绘制功能。

// 创建一个大小为 800x600 像素的空白图像
BufferedImage image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
// 递给 Graphics2D 对象以进行绘制操作
Graphics2D g2d = image.createGraphics();

2.绘制基本图形

Java 2D API 支持绘制各种基本的 2D 图形,例如线段、矩形、椭圆、弧形等

// 绘制一条线段
g2d.drawLine(100, 100, 200, 200);

// 绘制一个矩形
g2d.drawRect(300, 100, 100, 50);

// 绘制一个椭圆
g2d.drawOval(500, 100, 100, 150);

// 绘制一个弧形
g2d.drawArc(100, 300, 100, 100, 0, 90);

3.绘制文本

可以使用 Graphics2D 对象的 drawString() 方法来在图像上绘制字符串文本

// 将字符串 "Hello, Java 2D!" 绘制在坐标 (200, 400) 处
g2d.drawString("Hello, Java 2D!", 200, 400);

4.绘制图像

支持加载和绘制各种格式的图像,例如 JPEG、PNG、GIF 等。还可以使用 ImageIO 类加载图像文件,并使用 Graphics2D 对象的 drawImage() 方法将其绘制到图像上。

// 从指定的文件路径加载一张图片,并将其绘制在图像的左上角
BufferedImage image = ImageIO.read(new File("image.jpg"));
g2d.drawImage(image, 0, 0, null);

5.设置绘制属性

可以使用 Graphics2D 对象的 set 方法来设置多种绘制属性,例如颜色、字体、线宽等。

// 设置绘制颜色为红色
g2d.setColor(Color.RED);

// 设置字体为 Arial,大小为 24
g2d.setFont(new Font("Arial", Font.PLAIN, 24));

// 设置线宽为 3 像素
g2d.setStroke(new BasicStroke(3));

绘制文字水印

对图片添加文字水印,执行步骤操作如下:

使用ImageIO类加载需要添加水印的图片

创建一个BufferedImage的自定义图像对象,并使用Graphics2D对象将原始图像绘制到该对象上

创建字体对象,并设置字体、颜色、透明度等属性

使用Graphics2D对象的drawString()方法在需要添加水印的位置绘制字符串

使用ImageIO类将修改后的图像保存到指定目录
    public static void addWatermark(File input, File out, String text, int fontSize) {
        // 读取原图片
        BufferedImage image = null;
        try {
            image = ImageIO.read(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取图片的宽度和高度
        int width = image.getWidth();
        int height = image.getHeight();
        
        // 创建一个图片缓存对象
        BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 获取图片的画笔
        Graphics2D g = newImage.createGraphics();
        // 将原图片绘制到缓存图片上
        g.drawImage(image, 0, 0, width, height, null);
        
        // 创建字体对象
        Font font = new Font("微软雅黑", Font.BOLD, fontSize);
        // 创建字体渲染上下文
        FontRenderContext frc = new FontRenderContext(null, true, true);
        // 计算字符串的宽度和高度
        Rectangle2D bounds = font.getStringBounds(text, frc);
        // 字符宽度
        int strWidth = (int) bounds.getWidth();
        // 字符高度
        int strHeight = (int) bounds.getHeight();

        // 设置水印的字体样式
        g.setFont(font);
        // 设置水印的颜色
        g.setColor(Color.red);
        // 设置水印的位置 根据需要再自行调整宽度、高度
        g.drawString(text, width - strWidth - 10, height - strHeight + 15);
        // 释放图形上下文使用的系统资源
        g.dispose();
        
        // 保存带水印的图片
        try {
            ImageIO.write(newImage, "png", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        File input = new File("D://test.png");
        File out = new File("D://watermark.png");
        // 水印文本内容,中文转Unicode
        String text = "\u6dfb\u52a0\u6c34\u5370";
        addWatermark(input, out, text, 20);
    }

在这里插入图片描述

绘制图片水印

对图片添加图片水印,执行步骤操作如下:

使用ImageIO类加载需要添加水印的图片

创建一个BufferedImage的自定义图像对象,并使用Graphics2D对象将原始图像绘制到该对象上

使用ImageIO类加载水印图片,并设置透明度等属性

绘制水印图片,释放相关资源

使用ImageIO类将修改后的图像保存到指定目录
    public static void addWatermark(File input, File out, File watermarkImage) {
        // 读取添加水印的图片
        BufferedImage image = null;
        try {
            image = ImageIO.read(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取图片的宽度和高度
        int width = image.getWidth();
        int height = image.getHeight();
        
        // 创建一个图片缓存对象
        BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 获取图片的画笔
        Graphics2D g = newImage.createGraphics();
        // 将原图片绘制到缓存图片上
        g.drawImage(image, 0, 0, width, height, null);
        
        // 读取水印图片
        BufferedImage watermark = null;
        try {
            watermark = ImageIO.read(watermarkImage);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取水印图片的宽度和高度
        int wmWidth = watermark.getWidth();
        int wmHeight = watermark.getHeight();
        
        // 设置水印图片的透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
        // 绘制水印图片
        g.drawImage(watermark, width - wmWidth - 10, height - wmHeight - 10, wmWidth, wmHeight, null);
        // 释放图形上下文使用的系统资源
        g.dispose();
        
        // 保存带水印的图片
        try {
            ImageIO.write(newImage, "png", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        File input = new File("D://test.png");
        File out = new File("D://watermark.png");
        File watermarkImage = new File("D://watermarkImage .png");
        addWatermark(input, out, watermarkImage);
    }

在这里插入图片描述

循环添加文字水印

public class AddWatermarkUtils {

    // 水印字体
    private static final Font FONT = new Font("微软雅黑", Font.PLAIN, 24);

    // 透明度
    private static final AlphaComposite COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);

    // 水印之间的间隔
    private static final int X_MOVE = 150;

    // 水印之间的间隔
    private static final int Y_MOVE = 200;

    public static void markWithContent(String inputImgPath, Font font, Color markContentColor,
                                       String waterMarkContent,
                                       String outImgPath) throws IOException {

        // 读取原图片信息
        File srcFile = new File(inputImgPath);
        File outFile = new File(outImgPath);
        BufferedImage srcImg = ImageIO.read(srcFile);

        // 图片宽、高
        int imgWidth = srcImg.getWidth();
        int imgHeight = srcImg.getHeight();

        // 图片缓存
        BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

        // 创建绘图工具
        Graphics2D graphics = bufImg.createGraphics();

        // 画入原始图像
        graphics.drawImage(srcImg, 0, 0, imgWidth, imgHeight, null);

        // 设置水印颜色
        graphics.setColor(markContentColor);

        // 设置水印透明度
        graphics.setComposite(COMPOSITE);

        // 设置倾斜角度
        graphics.rotate(Math.toRadians(-35), (double) bufImg.getWidth() / 2,
                (double) bufImg.getHeight() / 2);

        // 设置水印字体
        graphics.setFont(font);

        // 消除java.awt.Font字体的锯齿
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int xCoordinate = -imgWidth / 2, yCoordinate;
        // 字体长度
        int markWidth = FONT.getSize() * getTextLength(waterMarkContent);
        // 字体高度
        int markHeight = FONT.getSize();

        // 循环添加水印
        while (xCoordinate < imgWidth * 1.5) {
            yCoordinate = -imgHeight / 2;
            while (yCoordinate < imgHeight * 1.5) {
                graphics.drawString(waterMarkContent, xCoordinate, yCoordinate);
                yCoordinate += markHeight + Y_MOVE;
            }
            xCoordinate += markWidth + X_MOVE;
        }

        // 释放画图工具
        graphics.dispose();

        try (FileOutputStream fos = new FileOutputStream(outFile)) {
            // 输出图片
            ImageIO.write(bufImg, "jpg", fos);
            fos.flush();
        }
    }


    /**
     * 计算水印文本长度
     * 中文长度即文本长度
     * 英文长度为文本长度二分之一
     */
    public static int getTextLength(String text) {
        //水印文字长度
        int length = text.length();

        for (int i = 0; i < text.length(); i++) {
            String s = String.valueOf(text.charAt(i));
            if (s.getBytes().length > 1) {
                length++;
            }
        }
        length = length % 2 == 0 ? length / 2 : length / 2 + 1;
        return length;
    }
}

    public static void main(String[] args) throws IOException {
        // 输入图片路径
        String inputFile = "D://test.png";
        // 输出图片路径
        String outputFile = "D://watermark.png";
        // 水印文本内容,中文转Unicode
        String watermarkText = "\u6dfb\u52a0\u6c34\u5370";
        AddWatermarkUtils.markWithContent(inputFile, FONT, Color.darkGray, watermarkText, outputFile);
    }

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快速上手Django(九) -Django下载文件、Django上传文件、Django实现excel导入导出

文章目录 快速上手Django(九) -django 上传文件request.FILES&#xff0c;下载文件一、Django下载文件1. Django下载文件方案和思路2. HttpResponse、StreamingHttpResponse和FileResponse区别和选择StreamingHttpResponse和FileResponse对象的对比和选择使用HttpResponse使用S…

浏览器安全之XSS跨站脚本

基本概念 跨站脚本&#xff08;Cross-Site Scripting&#xff0c;XSS&#xff09;是一种经常出现在Web应用程序中的计算机安全漏洞&#xff0c;是由于Web应用程序对用户的输入过滤不足而产生的。 攻击者利用网站漏洞把恶意的脚本代码&#xff08;通常包括HTML代码和客户端Javas…

采用.Net Core技术框架开发的B/S版区域检验管理系统(云LIS)

实验室信息管理系统云LIS源码 SaaS模式运维管理系统 云LIS系统源码是一款全面的实验室信息管理系统源码&#xff0c;其主要功能包括样本管理、检测项目管理、质控管理、报告管理、数据分析、两癌筛查等多个方面。具有独立的配套SaaS模式运维管理系统&#xff0c;支持远程运维&…

AtCoder Beginner Contest 300——A-G题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 300这场比赛的A-G题&#xff01; A - N-choice question 原题 Problem Statement Given integers A A A and…

数据埋点2

文章目录 1 数据埋点流程2 六个步骤实现数据埋点设计2.1 确认事件与变量2.2 明确事件的触发时机2.3 明确事件的上报机制2.4 设计数据表结构2.5 统一字段命名规范2.6 明确优先级 3 以电商购物成交转化为例实现数据埋点设计 作为数据分析师的你&#xff0c;是否和我一样经常会被业…

基于改进的离散PSO算法的FJSP的研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

排位赛结果“测谎”

甲乙丙丁说的关于排位赛结果只正确一半&#xff0c;根据甲乙丙丁说的信息求出正确的排位赛结果顺序。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那…

chatGPT免费入口-ChatGPT国内中文版网站

chatgpt怎么使用 如果您有Chat GPT的API Key并想要使用Chat GPT进行自然语言处理或生成处理&#xff0c;您可以按照以下步骤操作&#xff1a; 安装必要的软件和工具 在使用Chat GPT之前&#xff0c;您需要先安装一些必要的软件和工具&#xff0c;例如Python解释器、HTTP客户…

【Android车载系列】第11章 系统服务-SystemServer自定义服务

1 编写自定义系统服务 1.1 AIDL接口定义 系统源码目录/frameworks/base/core/java/android/app/下新建AIDL接口IYvanManager.aidl package android.app;/** * 目录&#xff1a;/frameworks/base/core/java/android/app/IYvanManager.aidl */ interface IYvanManager{String …

YOLOV5入门讲解+常用数据集

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

TIM-输出比较(PWM)——STM32

TIM-输出比较——STM32 Oc (Output Compare) 输出比较 输出比较可以通过比较CNT与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形 每个高级定时器和通用定时器都拥有4个输出比较通道高级定时器的前3个通道…

2023年股票质押违约处置研究报告

第一章 行业概况 1.1 产品定义 股票质押违约处置是指在股票质押融资中&#xff0c;当质押人&#xff08;股票持有者&#xff09;无法按照约定履行还款义务时&#xff0c;质权人&#xff08;通常为金融机构&#xff09;对质押股票进行处置的一系列活动。这个行业涉及到多个领域…

DAY 55 mysql数据库管理

常用的数据类型&#xff1a; 类型说明int整型&#xff0c;用于定义整数类型的数据fload单精度浮点4字节32位&#xff0c;准确表示到小数点后六位double双精度浮点8字节64位char固定长度的字符类型&#xff0c;用于定义字符类型数据。varchar可变长度的字符类型text文本image图…

Python基础合集 练习23 (错误与异常语句处理3)

‘’’ raise语句 raise[ExceptionName[(reason)]] 其中ExceptionName[(reason)]是可选参数用来指定抛出异常名称和原因,如果省略该参数,就会原样输出当前的错误 ‘’’ 在下面程序中,使用raise语句抛出ValueError异常 def num_calu(): book int(input(输入图书数量: )) stu…

探秘C语言:位运算符的奥秘

本篇博客会讲解C语言中的6个位操作符&#xff1a;按位取反(~)、按位与(&)、按位或(|)、按位异或(^)、左移(<<)、右移(>>)。这6个操作符都是操作整数的二进制位的。在学习这6个位操作符之前&#xff0c;大家需要先掌握“整数在内存中的存储”这个知识点&#xf…

数电中需要注意的问题

逻辑函数表达式之间的相互转换 &#xff08;更多请详见PPT&#xff09;若题目要求用&#xff1a; 与非门实现逻辑函数&#xff0c;则画卡诺图圈出值为1的然后化简 或非门实现逻辑函数&#xff0c;则画卡诺图圈出值为0的然后化简 与或非门实现逻辑函数&#xff0c;则画卡诺图圈…

一文了解获得 Zebec Labs 投资的 Coral Finance,空投计划或在不久推出

在前不久&#xff0c;Zebec Labs宣布对链上衍生品协议Coral Finance进行150万美元的投资&#xff0c;以帮助该协议完成早期启动并&#xff0c;并在后续持续的为其提供孵化支持。Coral Finance将在不久部署在Nautilus Chain主网上。据了解&#xff0c;Coral Finance是Nautilus C…

51单片机电路基础

一.电平特性 单片机是一种数字集成芯片&#xff0c;数字电路中只有两种电平:高电平和低电平。 高电平: 5V低电平: 0V TTL电平信号被利用的最多是因为通常数据表示采用二进制&#xff0c;5V等价于逻辑“1”&#xff0c;0V等价于逻辑“0”。 TTL电平规定高电平输出电压>2.…

博客系统的后端设计(一) - 准备工作与设计数据库

文章目录 准备工作1. 创建一个 Maven 项目2. 引入依赖3. 创建目录结构 设计数据库 这次开始进行博客系统后端的进度&#xff0c;本篇博客讲的是 准备工作和 设计数据库两个步骤。 准备工作 1. 创建一个 Maven 项目 2. 引入依赖 在地址栏中搜素 https://mvnrepository.com/&a…

【微信小程序开发】【SpringBoot】解决真机调试中无法向后台请求数据的问题

前言 最近做了一个微信小程序SpringBoot的一个项目&#xff0c;在编译器中用localhost请求后台可以实现&#xff0c;但是在手机上进行真机调试就无法正确的从后台请求数据&#xff0c;问题已经解决&#xff0c;下面是我的一点经验 获取本机的ip地址&#xff08;ipv4&#xff09…