java实现图片添加水印


前言

给图片添加水印是一个很常见的需求,一般是用来防盗用。比如我们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);
            // 设置字体  画笔字体样式为微软雅黑,加粗,文字大小为45pt
            graphics.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 {

    @Test
    void 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原生提供的处理图片的方式。使用的图片都是一些网上随便找的,如有侵权请评论区找我,我会及时撤下哈。

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用 Java 中的 `javax.imageio.ImageIO` 和 `java.awt.Graphics2D` 类来实现图片添加水印的功能,并将结果转换为 Base64 格式返回。以下是一个示例代码: ```java import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Base64; public class WatermarkUtil { public static String addWatermark(InputStream imageStream, String watermarkText) throws IOException { // 读取输入流中的图片 BufferedImage image = ImageIO.read(imageStream); // 创建一个新的 BufferedImage,并使用原始图片的宽度、高度和类型 BufferedImage watermarkedImage = new BufferedImage( image.getWidth(), image.getHeight(), image.getType()); // 创建 Graphics2D 对象,用于在新图片上绘制水印 Graphics2D g2d = watermarkedImage.createGraphics(); // 在新图片上绘制原始图片 g2d.drawImage(image, 0, 0, null); // 设置水印的字体、大小和颜色 Font font = new Font("Arial", Font.BOLD, 36); g2d.setFont(font); g2d.setColor(Color.RED); // 计算水印文本的坐标,居中显示在图片上 FontMetrics fontMetrics = g2d.getFontMetrics(); int x = (image.getWidth() - fontMetrics.stringWidth(watermarkText)) / 2; int y = image.getHeight() / 2; // 绘制水印文本 g2d.drawString(watermarkText, x, y); // 释放资源 g2d.dispose(); // 将水印图片转换为 Base64 字符串 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageIO.write(watermarkedImage, "png", outputStream); byte[] imageBytes = outputStream.toByteArray(); String base64Image = Base64.getEncoder().encodeToString(imageBytes); return base64Image; } } ``` 你可以调用 `addWatermark` 方法,传入原始图片的输入流和水印文本,它将返回添加水印后的图片的 Base64 字符串。 请注意,上述代码假设输入的图片格式为 PNG,并使用了默认的字体、大小、颜色等设置。你可以根据实际需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值