之前文章中的水印一直是通过其它图片处理的应用程序批量添加的,每个月把服务器上的当月图片 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 服务,上传图片效果如下:
完整 Jar 包下载
关注文章首部微信公众号发送 #halo-1.3.2
即可获取 halo-1.3.2 支持水印版
完整 jar 包。
下载好 jar 包后上传到服务器替换原有 jar 包,在 ~/application.yml
中添加如下配置:
zze:
water-marker-text: '博客名称 博客地址'
water-marker-text
的值就是水印文本内容,博客名称和博客地址需要以空格隔开,否则会报错~~~
重启 halo 服务就 OK 啦~~
评论区