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


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

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

    1 简介

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

    2 定位问题

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

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

    GET /api/pulse/preview_card_info/
    

    在代码中搜索preview_card_info,定位到文件srcmetabaseapipulse.clj,其中有一行

    api/defendpoint GET "/preview_card_png/:id"
    

    是把card转换为png文件,主要功能跳到srcmetabasepulse ender.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

  • 相关阅读:
    centos7 使用docker 一键部署服务器
    node 连接mysql失败
    面试必会---模块化
    es6异步解决方案
    centos7 apache后台转nginx后台
    React + Ts 实现三子棋小游戏
    让你的项目使用Ts吧
    ES6 入门系列 ArrayBuffer
    怎么把使用vuepress搭建的博客部署到Github Pages
    Navicat Premium 15安装教程(完整激活版)
  • 原文地址:https://www.cnblogs.com/ntestoc/p/10968541.html
Copyright © 2020-2023  润新知