一个巧妙的方法,解决Linux或者Mac环境加中文文字水印时出现小方格的问题![亲测可用]

问题场景:

笔者所在的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. 网上解决方案1
    ··· 在Linux环境上添加字体支持,同时安装【黑体】字体文件的支持库. 即可;命令什么的我就不放了,反正笔者的重点也并非这中形式去处理,有需要的可以自己去了解.

  2. 网上解决方案2
    ··· 先找到Linux环境上的JDK安装路径,将Jar包中的fonts文件路径指向已有的Linux环境字体库[/usr/local/fonts],同时重启服务器即可.

两个方案或许都能解决,但或多或少会存在一些小的问题,浪费咱们宝贵的开发时间,最重点的是当Linux环境一旦发生改变,则又要重复上述步骤!!!(反正各种贬低,为下列终极解决方案做准备.)


终极解决方案:

解决提示:聪明的你看到这里可能也猜到了,既然外部环境无法满足字体的稳定性,那么能否将字体文件放在内部呢?

有了提示,则可以进行验证,由于Java的Font类,提供下列几种方法,因此就把不可能变成可行了,
方法如图:
Font原生地址提供类图
这充分说明Java能支持开发者自定义外部字体文件引入,这已经为咱们的内部字体文件创造了充分的可能性;下面通过两项步骤完成内部自定义字体文件的读取和引入,各位客官请看好:

  1. 引入自定义字体文件(笔者所有字体文件为黑体)
    将字体放入本项目自带的【/resources】目录下,如图所示:
    字体放置路径

  2. 代码中引入字体文件流并指定字体类型
    这一步笔者踩了较多的坑,挑几个比较恶心的坑放在此处。
    一、需要通过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这么多,后面总结的机会多的是…

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,我可以为您解答这个问题。首先,您需要了解九宫重排问题的规则和定义。九宫重排是一种经典的智力游戏,游戏目标是将一个 3*3 的方格中的数字 1 到 8 排列成正确的顺序,空格表示为 0。每次可以将 0 所在的格子与上下左右相邻的数字交换位置。下面是一个例子: ``` 2 8 3 1 0 4 7 6 5 ``` 在这个例子中,0 可以与 2、1、4 和 6 进行交换,但不能与 8、3、7 和 5 进行交换。最终的正确状态是: ``` 1 2 3 8 0 4 7 6 5 ``` 接下来,我们可以使用 Python 编写一个九宫重排的框架,可以使用 BFS、DFS 和 A* 算法来解决问题。我们可以定义一个类来表示每个状态,其中包含以下属性: - state:表示当前的状态矩阵。 - parent:表示当前状态的父状态。 - action:表示从父状态到当前状态的操作。 - depth:表示当前状态的深度。 下面是一些示例代码,展示如何使用 BFS、DFS 和 A* 算法来解决九宫重排问题。这些代码只是示例,需要您进行修改和扩展,以满足您的具体需求。 ```python class State: def __init__(self, state, parent=None, action=None, depth=0): self.state = state self.parent = parent self.action = action self.depth = depth def __eq__(self, other): return self.state == other.state def __hash__(self): return hash(str(self.state)) def __str__(self): return str(self.state) def get_successors(self): successors = [] for i in range(3): for j in range(3): if self.state[i][j] == 0: if i > 0: new_state = [row[:] for row in self.state] new_state[i][j], new_state[i-1][j] = new_state[i-1][j], new_state[i][j] successors.append(State(new_state, self, 'up', self.depth+1)) if j > 0: new_state = [row[:] for row in self.state] new_state[i][j], new_state[i][j-1] = new_state[i][j-1], new_state[i][j] successors.append(State(new_state, self, 'left', self.depth+1)) if i < 2: new_state = [row[:] for row in self.state] new_state[i][j], new_state[i+1][j] = new_state[i+1][j], new_state[i][j] successors.append(State(new_state, self, 'down', self.depth+1)) if j < 2: new_state = [row[:] for row in self.state] new_state[i][j], new_state[i][j+1] = new_state[i][j+1], new_state[i][j] successors.append(State(new_state, self, 'right', self.depth+1)) return successors def is_goal(self, goal_state): return self.state == goal_state def bfs(start_state, goal_state): queue = [start_state] visited = set() while queue: state = queue.pop(0) if state.is_goal(goal_state): return state visited.add(state) for successor in state.get_successors(): if successor not in visited and successor not in queue: queue.append(successor) def dfs(start_state, goal_state): stack = [start_state] visited = set() while stack: state = stack.pop() if state.is_goal(goal_state): return state visited.add(state) for successor in state.get_successors()[::-1]: if successor not in visited and successor not in stack: stack.append(successor) def heuristic(state, goal_state): count = 0 for i in range(3): for j in range(3): if state[i][j] != goal_state[i][j]: count += 1 return count def astar(start_state, goal_state): queue = [(heuristic(start_state.state, goal_state), start_state)] visited = set() while queue: state = queue.pop(0)[1] if state.is_goal(goal_state): return state visited.add(state) for successor in state.get_successors(): if successor not in visited and successor not in [q[1] for q in queue]: queue.append((heuristic(successor.state, goal_state) + successor.depth, successor)) queue.sort() # Example usage start_state = State([[2, 8, 3], [1, 0, 4], [7, 6, 5]]) goal_state = State([[1, 2, 3], [8, 0, 4], [7, 6, 5]]) bfs_result = bfs(start_state, goal_state) dfs_result = dfs(start_state, goal_state) astar_result = astar(start_state, goal_state) print('BFS solution:', bfs_result.action_sequence()) print('DFS solution:', dfs_result.action_sequence()) print('A* solution:', astar_result.action_sequence()) ``` 在这个示例代码中,我们定义了三个函数,分别使用 BFS、DFS 和 A* 算法来解决九宫重排问题。在这些函数中,我们创建了一个起始状态和一个目标状态,并使用 State 类来表示这些状态。然后我们使用不同的算法来搜索状态空间,并找到从起始状态到目标状态的最短路径。最后,我们打印出每个算法的解决方案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值