解决Metabase pulses发送图片中文乱码的问题

解决Metabase pulses发送图片中文乱码的问题

解决Metabase pulses发送图片中文乱码的问题

1 简介

关于metabase pulses的介绍可以参考上篇文章,对于生成的png图片中文显示乱码的问题,这篇文章把排查问题的过程一步步记录下来。

2 定位问题

首先要找到生成png图片的函数。

在发送图片的时候,可以看到log日志请求

GET /api/pulse/preview_card_info/

在代码中搜索preview_card_info,定位到文件src\metabase\api\pulse.clj,其中有一行

api/defendpoint GET "/preview_card_png/:id"

是把card转换为png文件,主要功能跳到src\metabase\pulse\render.clj文件:

render/render-pulse-card-to-png
render-html-to-png ;; 应该是主要目标了,转换html到png文件。

在repl中测试这个函数,发现输出的图片是能正常显示中文的。

3 测试输出的文件

修改render.clj,添加测试代码:

 1: ;;添加保存doc到html文件的函数
 2: (import 'org.fit.cssbox.css.NormalOutput)
 3: (defn write-html
 4:   "保存doc到文件中"
 5:   [doc-source file-name]
 6:   (with-open [out (io/output-stream (io/file file-name))]
 7:     (->  (NormalOutput. doc-source)
 8:          (.dumpTo out))))
 9: 
10: ;;; 然后修改render-to-png 保存html文件
11: (defn- render-to-png
12:   [^String html, ^ByteArrayOutputStream os, width]
13:   (let [is            (ByteArrayInputStream. (.getBytes html StandardCharsets/UTF_8))
14:         doc-source    (StreamDocumentSource. is nil "text/html; charset=utf-8")
15:         parser        (DefaultDOMSource. doc-source)
16:         doc           (.parse parser)
17:         window-size   (Dimension. width 1)
18:         media         (doto (MediaSpec. "screen")
19:                         (.setDimensions       (.width window-size) (.height window-size))
20:                         (.setDeviceDimensions (.width window-size) (.height window-size)))
21:         da            (doto (DOMAnalyzer. doc (.getURL doc-source))
22:                         (.setMediaSpec media)
23:                         .attributesToStyles
24:                         (.addStyleSheet nil (CSSNorm/stdStyleSheet)   DOMAnalyzer$Origin/AGENT)
25:                         (.addStyleSheet nil (CSSNorm/userStyleSheet)  DOMAnalyzer$Origin/AGENT)
26:                         (.addStyleSheet nil (CSSNorm/formsStyleSheet) DOMAnalyzer$Origin/AGENT)
27:                         .getStyleSheets)
28:         content-canvas (doto (BrowserCanvas. (.getRoot da) da (.getURL doc-source))
29:                          (.setAutoMediaUpdate false)
30:                          (.setAutoSizeUpdate true))]
31:     (write-html doc "last-render.html") ;;; 只需要这里加一行,保存最后一次输出的html
32:     (doto (.getConfig content-canvas)
33:       (.setClipViewport false)
34:       (.setLoadImages true)
35:       (.setLoadBackgroundImages true))
36:     (.createLayout content-canvas window-size)
37:     (write-image (.getImage content-canvas) "png" os)))
38: 
39: ;;; 修改render-html-to-png 保存生成的png文件
40: (s/defn ^:private render-html-to-png :- bytes
41:   [{:keys [content]} :- RenderedPulseCard
42:    width]
43:   (let [html (html [:html [:head
44:                            ;; 怀疑文件编码设置问题,加了一个meta做测试
45:                            [:meta {:charset "UTF-8"}]]
46:                     [:body {:style (style {:margin           0
47:                                            :padding          0
48:                                            :background-color :white})}
49:                      ;; 内置一句中文进行测试
50:                      [:p "测试中文"]
51:                      content]])
52:         os   (ByteArrayOutputStream.)]
53:     (render-to-png html os width)
54:     ;; 保存最后一次生成的png图片到last-pic.png文件中
55:     (let [png-bytes (.toByteArray os)]
56:       (with-open [w (io/output-stream "last-pic.png")]
57:         (.write w png-bytes)
58:         png-bytes))))

保存文件后,重新编译项目:

bin/build no-translations

启动metabase后,新建一个pulse,查询结果包含中文,发送目标选择slack,点立即发送进行测试,发现中文还是乱码,不过自己添加的"测试中文"能正常显示,结果图片如下:

https://img2018.cnblogs.com/blog/1545892/201906/1545892-20190603164913533-2024456400.jpg

图1  添加测试代码后生成的图片截图

打开生成的html文件,发现中文编码是正常的,文件编码也是utf-8。

4 测试其他方法

搜索关于html转png图片的文章,有讲到如果中文是方块状,应该是缺少字体。 查看生成的html文件,发现生成的文字都有指定font-family属性,于是添加几个中文字体到font-family下,测试还是乱码,尝试把中文字体放在最前面,render.clj文件的font-style函数改为:

;; 修改后的font-style函数
(defn- font-style []
  {:font-family "微软雅黑,Microsoft YaHei,SimSun,sans-serif,Helvetica, Arial, sans-serif"})

最后图片成功显示中文。

https://img2018.cnblogs.com/blog/1545892/201906/1545892-20190603164916051-1566835695.jpg

图2  html2image 成功显示中文

5 总结

html输出到图片,中文显示乱码,字体有设置,应该是org.fit.cssbox不会自动适配字体造成的,把中文字体放在第一个,成功解决。

作者: ntestoc

Created: 2019-06-03 一 16:49

posted @ 2019-06-03 16:49  cloca  阅读(1122)  评论(0编辑  收藏  举报