问题场景:
笔者所在的SpringCloud项目中有较为常见的需求,那就是用户上传图片时需要生成文字水印,用于标识该图片的出处。项目使用HuTool工具生成文字水印(可选用其他水印生成工具,效果都差不多),附依赖如下:
PS:个人感觉Hutool还不错,整合了开发中常用的功能.推荐一波~
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.6</version>
</dependency>
问题描述:
生成水印方式比较简单,直接调用HuTool的ImgUtil工具即可生成,伪代码和参数描述如下;
ImgUtil.pressText(
//用户上传的文件输入流
file.getInputStream(),
//你需要将带有水印文字的图片输出到哪里的输出流.
new FileOutPutStream("newFile") ,
"我是水印文字",
//我需要设置水印文字的颜色
new Color(215, 215, 215),
//字体设置
new Font("黑体", Font.BOLD, 100),
//下面三个数字分贝代表,x轴位置,Y轴位置,透明度.
0, 0, 0.5f);
代码开发完毕后,本地自测发现我是文印文字这种中文字符可以正常加到图片上,但是一旦移到Linux环境后就会出现类似于口口口口口口的问题(此处是用口这个字模拟的).
原因分析:
出现这种问题,最先提上怀疑日程的一定是编码格式的问题,但是,经测试与验证,排除了编码乱码并且也顺便排除文件格式错误的问题…
老生坐定想了很久之后,才注意到【new Font(“黑体”, Font.BOLD, 100)】这个乐色玩意儿,想起之前做报表时也遇到过类似的问题,就开始研究这个字体了,后面看网上也有很多同僚遇到过类似的问题,不过他们的解决方案几乎都是“清一色”,下面列出他们的解决方案(PS:感觉异常麻烦,而且不适用于Linux环境下再放Docker容器的问题.)
-
网上解决方案1
··· 在Linux环境上添加字体支持,同时安装【黑体】字体文件的支持库. 即可;命令什么的我就不放了,反正笔者的重点也并非这中形式去处理,有需要的可以自己去了解. -
网上解决方案2
··· 先找到Linux环境上的JDK安装路径,将Jar包中的fonts文件路径指向已有的Linux环境字体库[/usr/local/fonts],同时重启服务器即可.
两个方案或许都能解决,但或多或少会存在一些小的问题,浪费咱们宝贵的开发时间,最重点的是当Linux环境一旦发生改变,则又要重复上述步骤!!!(反正各种贬低,为下列终极解决方案做准备.)
终极解决方案:
解决提示:聪明的你看到这里可能也猜到了,既然外部环境无法满足字体的稳定性,那么能否将字体文件放在内部呢?
有了提示,则可以进行验证,由于Java的Font类,提供下列几种方法,因此就把不可能变成可行了,
方法如图:
这充分说明Java能支持开发者自定义外部字体文件引入,这已经为咱们的内部字体文件创造了充分的可能性;下面通过两项步骤完成内部自定义字体文件的读取和引入,各位客官请看好:
-
引入自定义字体文件(笔者所有字体文件为黑体)
将字体放入本项目自带的【/resources】目录下,如图所示:
-
代码中引入字体文件流并指定字体类型
这一步笔者踩了较多的坑,挑几个比较恶心的坑放在此处。
一、需要通过classloader去加载resources目录下的内部字体文件;
二、指定fontFormat一定得是【Font.TRUETYPE_FONT】
三、如需重新设置字体大小和字体样式,需要调用font.deriveFont( size: 123 F)方法,因为字体一旦设置,貌似无法更改大小和样式,只能重新通过deriveFont方法生成一个新的字体对象来使用.
代码最终展示如下:
//通过当前类的类加载器获取到字体文件流
final InputStream fontInputStream= FontUtil.class.getClassLoader().getResourceAsStream("simhei.ttf");
//通过字体流创建字体并重新创建一个字体大小为(25.0F)的字体对象
final Font font = Font.createFont(Font.TRUETYPE_FONT, fontInputStream).deriveFont(25F);
结论:上述步骤完毕,则完美搞定内部字体的引用,并能成功加载文字水印,且不受外部环境的影响。这意味着你的项目所在环境无论是在Linux还是Mac、无论是真实环境还是Docker等容器中,都可以引用该字体。当然若各位的项目需要其他的字体,则对应添加即可,本项目中使用的是【黑体】字体,如需要获取其他字体,windows环境下可以直接在C:\windows\fonts目录下获取.
总结
额,没什么总结的,就先这样吧,反正Bug这么多,后面总结的机会多的是…