侧边栏壁纸
博主头像
张种恩博主等级

一个能运维的 JPG 搬运工

  • 累计撰写 703 篇文章
  • 累计创建 60 个标签
  • 累计收到 24 条评论

Halo 最新版上传图片自动添加水印

张种恩
2022-01-21 / 0 评论 / 0 点赞 / 63 阅读 / 5,450 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-01-21,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

之前已经写过一篇博文来记录 halo 图片添加水印的方法,如下:

那时候 halo 使用的还是 jdk8,现在最新版的 halo jdk 版本已经升级到了 11,所以相对之前的步骤有些许修改,这里重新做下记录。

我这里是在 Linux 下进行操作,步骤如下。

1、拉取源代码:

$ git clone https://github.com/halo-dev/halo.git

2、添加 gradle 依赖并取消代码风格检查:

$ cd halo
$ vim build.gradle 
// 取消使用代码风格检查插件
plugins {
    id "org.springframework.boot" version "2.5.1"
    id "io.spring.dependency-management" version "1.0.11.RELEASE"
    // id "checkstyle"
    id "java"
}

// checkstyle {
//    toolVersion = "8.39"
//    showViolations = false
//    ignoreFailures = false
// }
...
// 修改 gradle 源为国内源加快打包速度
repositories {
    mavenLocal()
    maven { url 'https://maven.aliyun.com/nexus/content/repositories/google' }
    maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
    maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'}
    mavenCentral()
    //maven { url 'https://repo.spring.io/milestone' }
    jcenter()
}
...
// 引入绘图依赖
implementation "commons-fileupload:commons-fileupload:1.4"
implementation "commons-io:commons-io:2.6"
...

3、添加工具类:

$ touch src/main/java/run/halo/app/utils/ImageWatermarkUtil.java

其内容如下:

package run.halo.app.utils;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

public class ImageWatermarkUtil {
    // 水印透明度
    private static float alpha = 0.2f;
    // 水印文字大小
    public static final int FONT_SIZE = 25;
    // 水印文字字体
    private static Font font = new Font("微软雅黑", Font.BOLD, FONT_SIZE);
    // 水印文字颜色
    private static Color color = Color.gray;
    // 水印文字
    private static String word = "张种恩的技术小栈 www.zze.xyz";
    // 水印之间的间隔
    private static final int XMOVE = 80;
    // 水印之间的间隔
    private static final int YMOVE = 80;

    /**
     * 加水印
     */
    public static MultipartFile addWorkMarkToMutipartFile(MultipartFile multipartFile) throws IOException {

        MultipartFile newFile = null;
        // 获取图片文件名 xxx.png xxx
        String originFileName = multipartFile.getOriginalFilename();
        // 获取原图片后缀 png
        int lastSplit = originFileName.lastIndexOf(".");
        String suffix = originFileName.substring(lastSplit + 1);
        // 获取图片原始信息
        String dOriginFileName = multipartFile.getOriginalFilename();
        String dContentType = multipartFile.getContentType();
        // 是图片且不是gif才加水印
        if (!suffix.equalsIgnoreCase("gif") && dContentType.contains("image")) {
            // 获取水印图片
            InputStream inputImg = multipartFile.getInputStream();
            Image img = ImageIO.read(inputImg);
            // 加图片水印
            int imgWidth = img.getWidth(null);
            int imgHeight = img.getHeight(null);

            BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight,
                    BufferedImage.TYPE_INT_RGB);
            //调用画文字水印的方法
            markWord(bufImg, img, word);
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(bufImg, suffix, imOut);
            InputStream is = new ByteArrayInputStream(bs.toByteArray());

            FileItemFactory factory = new DiskFileItemFactory(16, null);
            FileItem item = factory.createItem(dOriginFileName, dContentType, true, originFileName);

            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            try {
                OutputStream os = item.getOutputStream();
                while ((bytesRead = is.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
                os.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            newFile = new CommonsMultipartFile(item);
        }
        //返回加了水印的上传对象
        return newFile;
    }

    public static void markWord(BufferedImage buffImg, Image srcImg, String text) {
        Graphics2D g = buffImg.createGraphics();
        // 设置对线段的锯齿状边缘处理
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg.getHeight(null), Image.SCALE_SMOOTH),
                0, 0, null);
        Integer degree = 35;
        // 设置水印旋转
        if (null != degree) {
            g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
        }

        int width = srcImg.getWidth(null);// 原图宽度
        int height = srcImg.getHeight(null);// 原图高度

        // 设置水印文字颜色
        g.setColor(color);
        // 设置水印文字Font
        g.setFont(font);
        // 设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

        int x = -width / 2;

        int markWidth = FONT_SIZE * getTextLength(text);// 字体长度
        int markHeight = FONT_SIZE;// 字体高度
        int loopIndex = 0;
        // 循环添加水印
        while (x < width * 1.5) {
            int y = -height / 2;
            while (y < height * 1.5) {
                g.drawString(text.split(" ")[loopIndex % 2], x, y);
                y += markHeight + YMOVE;
                loopIndex++;
            }
            x += markWidth + XMOVE;
        }
        // 释放资源
        g.dispose();
    }

    private 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;
    }
}

4、修改 AttachmentServiceImpl 类的 upload 方法,在方法首部加上加水印代码:

// 导包
import java.io.*;
...
public Attachment upload(MultipartFile file) {
    // 加水印
    try {
        file = ImageWatermarkUtil.addWorkMarkToMutipartFile(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
    ...

5、编译输出 jar 包:

$ ./gradlew clean build -x test
$ ls build/libs/halo-*.jar
build/libs/halo-1.4.13-SNAPSHOT.jar  build/libs/halo-1.4.13-SNAPSHOT-plain.jar

6、安装中文字体库解决渲染中文乱码:

$ yum install fontconfig mkfontscale -y
# 检查中文字体库,如果下面命令没有任何输出就说明当前 jdk 不支持中文渲染
$ fc-list :lang=zh
$ mkdir /usr/share/fonts/chinese && cd /usr/share/fonts/chinese && chmod -R 755 /usr/share/fonts/chinese
# mysh.ttf 是微软雅黑字体库文件,它的下载链接我放在下面
$ cp /root/msyh.ttf .
# 关联字体库
$ mkfontscale
# 再次检查中文字体库
$ fc-list :lang=zh
/usr/share/fonts/chinese/msyh.ttf: Microsoft YaHei:style=Regular,Normal

msyh.ttf - 链接: https://pan.baidu.com/s/1czx-yPZ83hU6rDpaKX4cUQ 提取码:9adl

7、最后使用新编译的 Jar 替换原来的 Jar 重启 halo 服务即可。

$ systemctl restart halo
0

评论区