侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 747 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

修改源码为halo后台上传的图片自动加上水印

zze
zze
2020-04-19 / 1 评论 / 0 点赞 / 1683 阅读 / 7404 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

之前文章中的水印一直是通过其它图片处理的应用程序批量添加的,每个月把服务器上的当月图片 download 下来然后批量添加水印再上传怼回去,实在是有点烦了???

怎么解怎么解,,自己动手丰衣足食!!只能下载 halo 的源码下来自己撸一个加水印的功能了?

halo 源码的下载、gradle 环境的搭建就不多说了~~~

修改源码

1、添加 gradle 依赖:

implementation "commons-fileupload:commons-fileupload:1.4"
implementation "commons-io:commons-io:2.6"

2、添加工具类 run.halo.app.utils.ImageWatermarkUtil

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

3、修改 run.halo.app.service.impl.AttachmentServiceImpl 类的 upload 方法,在方法首部加上加水印代码:

public Attachment upload(MultipartFile file) {
    // 加水印
    try {
        file = ImageWatermarkUtil.addWorkMarkToMutipartFile(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
    ...

即在原来的 MultipartFile 的实例基础上打完水印,然后替换原来的对象。

4、打 jar 包,替换服务器上原来的 jar 包即可。

试着通过后台上传图片,如果发现中文乱码了。。继续往下看~~~

解决中文乱码

1、中文乱码是因为 jdk 缺少对应的字体包,比如上面我使用的是微软雅黑,则需要添加对应的微软雅黑的字体包,关注文章首部微信公众号发送 #msyh_ttf 获取微软雅黑字体包。

2、首先要找到 jdk 的字体目录,如下:

$ rpm -ql jdk1.8 | grep fonts
/usr/java/jdk1.8.0_202-amd64/jre/lib/fonts
/usr/java/jdk1.8.0_202-amd64/jre/lib/fonts/LucidaBrightDemiBold.ttf
...

3、一目了然,就是第一个 /usr/java/jdk1.8.0_202-amd64/jre/lib/fonts,进入到该目录并创建 fallback 目录然后进入 fallback 目录:

$ mkdir fallback
$ cd fallback

4、将字体文件上传到 fallback 目录:

$ ls
fonts.dir  fonts.scale  msyh.ttf

5、执行下面命令让字体库生效:

$ mkfontscale && mkfontdir

6、重启 halo 服务,上传图片效果如下:

image.png

完整 Jar 包下载

关注文章首部微信公众号发送 #halo-1.3.2 即可获取 halo-1.3.2 支持水印版 完整 jar 包。

下载好 jar 包后上传到服务器替换原有 jar 包,在 ~/application.yml 中添加如下配置:

zze:
  water-marker-text: '博客名称 博客地址'

water-marker-text 的值就是水印文本内容,博客名称和博客地址需要以空格隔开,否则会报错~~~

重启 halo 服务就 OK 啦~~

0

评论区