java 实现图片新增水印(动态计算水印背景 + 水印文字),附带文字乱码解决方案

7 篇文章 0 订阅

概要

图片增加水印背景以及水印文字,根据文字内容是否换行,以及文字行高大小自适应计算背景大小
结果图如下:
实现效果图

实现流程

  1. 定义图片来源,以及读取字体来源(防止中文乱码)
  2. 计算文字所需高度 + 与背景的边距为背景高度
  3. 打印文字

代码如下

public static void main(String[] args) {
        imageWatermark("流淌着阳关的小溪", "深圳市黄浦江", "2024.02.26", "哆啦A梦");
    }

    // 读取项目字体路径
    static final String FONT_PATH = "C:/Users/didadiandi/Desktop/font/simsun.ttc";

    /**
     * 图片水印
     *
     * @date 2024/2/26 15:15
     */
    public static void imageWatermark(String name, String location, String date, String userName) {
        try {
            boolean multiLine = false;
            String locationData = String.format("地    点:%s", location);
            String dateData = String.format("拍摄时间:%s", date);
            String userNameData = String.format("拍摄人员:%s", userName);
            File inputFile = new File("C:/Users/didadiandi/Desktop/微信截图_20240303165815.png");
            BufferedImage inputImage = ImageIO.read(inputFile);

            Graphics2D g2d = (Graphics2D) inputImage.getGraphics();
            // 背景距离下一行数据的距离
            int bgBottomY = inputImage.getWidth() > inputImage.getHeight() ? inputImage.getHeight() / 30 : inputImage.getWidth() / 30;
            // 文字1
            int fontSize01 = inputImage.getWidth() / 42;
            // 文字2
            int fontSize02 = fontSize01 - 2;
            // 文字3
            int fontSize03 = fontSize01 / 2;
            // 时间距离下一行数据的距离
            int dataBottomY = bgBottomY - (bgBottomY / 2);
            // 背景2左边距离
            int bgLeftX02 = bgBottomY + (bgBottomY / 2);

            // 背景
            // 背景2定义
            // 颜色定义
            Color color2 = new Color(255, 255, 255, 111);
            g2d.setColor(color2);
            // 字体文件读取
            Font locationFont = loadStyleFont(FONT_PATH, Font.BOLD, fontSize02);
            g2d.setFont(locationFont);
            // 背景宽度计算
            int bgWatermarkWidth = (inputImage.getWidth() / 3) + (inputImage.getWidth() / 20);
            // 背景X坐标定义
            int bg2X = bgBottomY;
            // 水印文字换行处理
            // 一个文字所占的高度
            int lineHeight02 = g2d.getFontMetrics().getHeight();
            // 每一行的宽度
            int lineWidthLimit2 = bgWatermarkWidth - (dataBottomY * 2);
            // 加上时间以及时间与地点的间隔,总高度累计
            int locationHeightSum = lineHeight02;
            // 换行后地址的X坐标
            int locationXLen = bgLeftX02;
            // 计算任务目标名称的文字换行的总高度
            StringBuilder sbBg2 = new StringBuilder();
            for (char c : locationData.toCharArray()) {
                sbBg2.append(c);
                int locationLen = g2d.getFontMetrics().stringWidth(sbBg2.toString());
                // 一行的宽度 是否大于规定的行宽度
                if (locationLen + locationXLen > lineWidthLimit2) {
                    locationXLen = fontSize02 * 6;
                    locationHeightSum += lineHeight02;
                    sbBg2 = new StringBuilder();
                }
            }
            // 时间所需高度
            int dateHeight = lineHeight02 + dataBottomY;
            // 地址所需高度
            locationHeightSum = locationHeightSum + (dataBottomY * 2);
            // 图形的大小等于文字的换行总长度 + 间距
            int bg2WatermarkHeight = locationHeightSum + dateHeight + (lineHeight02 + dataBottomY);
            // 背景X坐标定义
            int bg1X = bgBottomY;
            // 背景图片的坐标
            int bg2Y = inputImage.getHeight() - (bg2WatermarkHeight + bgBottomY);
            // 将图形定义到图片上
            g2d.fillRect(bg2X, bg2Y, bgWatermarkWidth, bg2WatermarkHeight);
            // 背景1
            // 背景1颜色定义
            Color color1 = new Color(203, 82, 82, 150);
            g2d.setColor(color1);
            // 背景1上文字的定义
            Font nameFont = loadStyleFont(FONT_PATH, Font.BOLD, fontSize01);
            g2d.setFont(nameFont);
            // 水印文字换行处理
            // 一个文字所占的高度
            int lineHeight = g2d.getFontMetrics().getHeight();
            // 每一行的宽度
            int lineWidthLimit1 = bgWatermarkWidth - (dataBottomY * 2) - (bgLeftX02 * 2) + fontSize03;
            int nameHeight = lineHeight;
            // 计算任务目标名称的文字换行的总高度
            StringBuilder sbBg1 = new StringBuilder();
            for (char c : name.toCharArray()) {
                sbBg1.append(c);
                // 一行的宽度 是否大于规定的行宽度
                if (g2d.getFontMetrics().stringWidth(sbBg1.toString()) > lineWidthLimit1) {
                    nameHeight += lineHeight;
                    sbBg1 = new StringBuilder();
                }
            }
            // 图形的大小等于文字的换行总长度 + 间距
            int bg1WatermarkHeight = nameHeight + dataBottomY + (fontSize01 / 2);
            // 背景图片的坐标
            int bg1Y = bg2Y - (bg1WatermarkHeight);
            g2d.fillRect(bg1X, bg1Y, bgWatermarkWidth, bg1WatermarkHeight);

            // 文字

            // 字体定义
            Font font3 = loadStyleFont(FONT_PATH, Font.BOLD, fontSize01);
            g2d.setFont(font3);
            // 颜色定义
            Color color3 = new Color(231, 243, 243, 255);
            g2d.setColor(color3);
            // 任务目标名称的水印文字换行处理
            // 获取名称当前字体行高
            int nameLineHeight = g2d.getFontMetrics().getHeight();
            // 稳字行高累计
            int nameSumLineHeight = nameLineHeight;
            // 名字X坐标为 两倍bgLeftX02 边距 + 稳字所需大小
            int nameX = (bgLeftX02 * 2) + fontSize03;
            // 名字Y坐标为,在背景Y坐标的基础上向下移动 数据的Y坐标边距 + 文字1大小的边距
            int nameY = bg1Y + (dataBottomY + fontSize01);
            // 名字实际Y坐标(换行所必须参数)
            int nameY2 = nameY;
            StringBuilder nameSb = new StringBuilder();
            for (char c : name.toCharArray()) {
                nameSb.append(c);
                if (g2d.getFontMetrics().stringWidth(nameSb.toString()) > lineWidthLimit1 - dataBottomY) {
                    // 将文字写入图片
                    g2d.drawString(nameSb.toString(), nameX, nameY2);
                    // 名字下次换行所需Y坐标
                    nameY2 += nameLineHeight;
                    // 名字总高度
                    nameSumLineHeight += nameLineHeight;
                    nameSb = new StringBuilder();
                    // 是否换行
                    multiLine = true;
                }
            }
            g2d.drawString(nameSb.toString(), nameX, nameY2);

            // 点坐标定义
            Font font5 = loadStyleFont(FONT_PATH, Font.BOLD, fontSize03);
            g2d.setFont(font5);
            Color color5 = new Color(0, 0, 0, 255);
            g2d.setColor(color5);
            String point = "●";
            int pointX = bgLeftX02;
            // 点坐标等于初始文字坐标,如果有多行,则是多行的二分之一坐标
            int pointY = multiLine ? nameY + (nameSumLineHeight / 2) : nameY;
            g2d.drawString(point, pointX, pointY);

            // 时间定义
            Font font4 = loadStyleFont(FONT_PATH, Font.BOLD, fontSize02);
            g2d.setFont(font4);
            Color color4 = new Color(35, 40, 36, 255);
            g2d.setColor(color4);
            // 水印文字换行处理
            int fontSize02LineHeight = g2d.getFontMetrics().getHeight();

            int dateX = bgLeftX02;
            int dateY = bg2Y + (dataBottomY + fontSize02);
            g2d.drawString(dateData, dateX, dateY);

            // 人员定义
            int userNameX = bgLeftX02;
            int userNameY = dateY + (dataBottomY + fontSize02);
            g2d.drawString(userNameData, userNameX, userNameY);

            // 地址
            int locationX = bgLeftX02;

            int locationY = userNameY + dataBottomY + fontSize02LineHeight;
            StringBuilder locationSb = new StringBuilder();
            for (char c : locationData.toCharArray()) {
                locationSb.append(c);
                int locationLen = g2d.getFontMetrics().stringWidth(locationSb.toString());
                if (locationLen + locationX > lineWidthLimit2 - dataBottomY) {
                    g2d.drawString(locationSb.toString(), locationX, locationY);
                    locationY += fontSize02LineHeight;
                    locationX = fontSize02 * 6;
                    locationSb = new StringBuilder();
                }
            }
            g2d.drawString(locationSb.toString(), locationX, locationY);
            // 回收资源
            g2d.dispose();

            File outputFile = new File("output.png");
            ImageIO.write(inputImage, "png", outputFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Created by <a href="https://blog.csdn.net/weixin_44951037/article/details/109623821">马男波杰克</a>
     *
     * @param fontFileName 外部字体名
     * @param style        字体样式
     * @param fontSize     字体大小
     * @return
     */
    public static Font loadStyleFont(String fontFileName, int style, float fontSize) throws IOException, FontFormatException {
        try (InputStream in = ResourceUtil.getStream(fontFileName);){
            Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, in);
            return dynamicFont.deriveFont(style, fontSize);
        }
    }

小结

  1. 背景的高度是文字高度 + 文字与背景所需边距
  2. x坐标都是一致的
  3. 图片第一个文字水印Y坐标定义好之后,其他坐标都可以在这个Y坐标的基础上进行计算,可以保证水印的整体性(即调整前面一个元素的Y坐标,后边元素的Y坐标同时变动)

文字乱码解决方式参考:马男波杰克,读取字体文件解决乱码

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java可以使用Java2D API来实现图片文字水印。下面是一个简单的示例代码: ```java import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class ImageWatermark { public static void main(String[] args) throws IOException { // 读取原始图片 BufferedImage image = ImageIO.read(new File("original.jpg")); // 创建一个空白的图片,大小和原始图片一样 BufferedImage result = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB); // 获取图片的Graphics2D对象 Graphics2D g = result.createGraphics(); // 将原始图片绘制到空白图片上 g.drawImage(image, 0, 0, null); // 设置水印文字的相关属性 String text = "Hello, world!"; Font font = new Font("Arial", Font.BOLD, 36); Color color = Color.WHITE; // 绘制水印文字 g.setFont(font); g.setColor(color); int x = (image.getWidth() - g.getFontMetrics().stringWidth(text)) / 2; int y = image.getHeight() / 2; g.drawString(text, x, y); // 保存水印图片 ImageIO.write(result, "jpg", new File("watermark.jpg")); } } ``` 在这个示例代码中,我们首先读取原始图片,然后创建一个空白的图片,大小和原始图片一样。接着,我们获取空白图片的Graphics2D对象,将原始图片绘制到空白图片上。然后,我们设置水印文字的相关属性,包括文字内容、字体和颜色,并在空白图片上绘制水印文字。最后,我们将水印图片保存到文件中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值