Docker 快速驗證 HTML 導出 PDF 高效方案

需求分析

項目中用到了Echarts,想要把圖文混排,當然包括echarts生成的Canvas圖也導出PDF。

設計和實現時,分析了POI、iText、freemaker、world的xml模版、Jquery-printArea.js、JQuery Plugin-TableExport、flying saucer等等技術組合,不盡人意。甚至因爲echarts不支持後端調用導出圖片(沒有簡單易行的辦法),一度考慮要在導出時用JfreeCharts重新畫一遍圖表。一是不能完整體現原有設計樣式,二是工期不支持這麼龐大的工作量(硬擼代碼解析html生成word或pdf。好吧,也同時覺得挺low的);

最終選擇了wkhtmltopdf,實現了預期目標。整理成筆記,分享給大家。同時,發現docker hub有wkhtmltopdf基於apline搭建的web service鏡像,生產環境可以上Docker的同學有福了,這應該是個更加高效的方案。後續考慮整合到支撐平臺中,一併開源出來。

筆記本實驗

本地測試爲Mac Book,生產環境請自行評估調整。

下載和安裝

B4下,brew倉庫里居然沒有,所以 brew install wkhtmltopdf安裝報錯。

直接貼官方鏈接了:有依賴親自行安裝依賴;

驗證

ChinaDreams:workspace kangcunhua$ wkhtmltopdf --version
wkhtmltopdf 0.12.4 (with patched qt)

測試

聯網抓取

ChinaDreams:~ kangcunhua$ wkhtmltopdf --header-center  '報表' --outline  --header-line --margin-top 2cm --header-line http://www.qq.com/  qq.pdf

本地頁面測試

index.html見靜態頁面

–zoom 4 是Mac book上實驗出來的參數,這樣頁面是正常A4寬幅;在windows10、Suse 11下不用加這個參數。

toc 參數生成目錄,包括左側導航;—toc-header-text自定義目錄名;

ChinaDreams:~ kangcunhua$ wkhtmltopdf  --zoom 4 toc --toc-header-text "第四季度季報" index.html export.pdf

模擬商業環境

我們拿到項目中實踐驗證下方案。商業項目,往往是殘酷的要求,會遇到各種各樣demo時碰不上的挑戰。

思路還是先用docker神器,模擬商業環境,驗證方案,然後再修訂驗證後的方案到正式項目環境驗證。

客戶方提供的環境是SuSE。我們先來看看是哪個版本

cat /etc/SuSE-release # 可以看到補丁版本
SUSE LINUX Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 4

請 Docker 神器

查找SuSE鏡像,恰好有一個11版本的,下載鏡像先

$ docker search SUSE # yuzhenpin/suse-11-sp3-x86_64-java
$ docker pull yuzhenpin/suse-11-sp3-x86_64-java

啓動鏡像

 

docker run --name suse-ep -it yuzhenpin/suse-11-sp3-x86_64-java /bin/bash
9e023776a1d5:/ # java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
9e023776a1d5:/ # id 
uid=0(root) gid=0(root) groups=0(root)
9e023776a1d5:/ # groupadd prms && useradd -d /prms -g prms -m prms
9e023776a1d5:/ # passwd prms
9e023776a1d5:/ # su prms

安裝和配置

因爲下載的二進制版本的,直接把 wkhtmltopdf 拷貝進容器即可。index.html是寫的測試頁面,後文附有源碼:此文件用到的jquery相關js直接引用了CDN,故實驗在聯網環境下進行的。

ChinaDreams:copy2docker kangcunhua$ docker cp wkhtmltox-0.12.4_linux-generic-amd64.tar.xz su-ext:/prms/workspace
ChinaDreams:copy2docker kangcunhua$ docker cp index.html su-ext:/prms/workspace

檢查運行依賴

使用ldd命令,not found的就是對應的依賴包不存在:

7d183ecb0026:/prms/workspace/wkhtmltox/bin # ldd wkhtmltopdf 
  linux-vdso.so.1 =>  (0x00007ffe40bd2000)
  libXrender.so.1 => not found
  libfontconfig.so.1 => not found
  libfreetype.so.6 => not found
  libXext.so.6 => not found
  libX11.so.6 => not found
  libz.so.1 => /lib64/libz.so.1 (0x00007f9ca59ad000)
  libdl.so.2 => /lib64/libdl.so.2 (0x00007f9ca57a9000)
  librt.so.1 => /lib64/librt.so.1 (0x00007f9ca55a0000)
  libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9ca5383000)
  libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f9ca507b000)
  libm.so.6 => /lib64/libm.so.6 (0x00007f9ca4e02000)
  libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f9ca4bec000)
  libc.so.6 => /lib64/libc.so.6 (0x00007f9ca4870000)
  /lib64/ld-linux-x86-64.so.2 (0x00007f9ca5bc5000)

安裝依賴

使用 zypper se 命令查找,根據查找結果,來安裝需要的版本;

7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper se libXrender                                                                       
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper install xorg-x11-libXrender
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper se libfreetype     
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper install libfreetype6
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper se libXext
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper install xorg-x11-libXext
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper se fontconfig
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper install fontconfig
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper se libX11
7d183ecb0026:/prms/workspace/wkhtmltox/bin # zypper install xorg-x11-libX11

需要在html代碼中指定font-face,所以需要一種支持中英文的字體。這裏不指定的話,中英文都是黑色方框。因爲不知容器使用的是何種字體,沒找到Suse如何查看當前已有字體。從網下下載了文泉驛正黑,cp了字體進來,發現是亂碼,mv重命名爲tt.tff;cp到字體目錄。

7d183ecb0026:/usr/share/fonts # mkdir windows
7d183ecb0026:/prms/workspace # mv tt.ttf /usr/share/fonts/windows/
7d183ecb0026:/prms/workspace # ./wkhtmltox/bin/wkhtmltopdf index.html exp.pdf
QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed
QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv_open failed
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done

和容器之間複製文件

ChinaDreams:copy2docker kangcunhua$ docker cp wkhtmltox-0.12.4_linux-generic-amd64.tar.xz su-ext:/prms/workspace
ChinaDreams:copy2docker kangcunhua$ docker cp index.html su-ext:/prms/workspace
ChinaDreams:copy2docker kangcunhua$ docker cp 文泉驛等寬正黑.ttf su-ext:/prms/workspace
ChinaDreams:copy2docker kangcunhua$ docker cp su-ext:/prms/workspace/exp.pdf .

商業環境實戰

待補充。

2017.11.10update: 商業環境最大的挑戰是內網。還有個挑戰是客戶使用的是SuSE Enterprise,這種情況下,如果缺少依賴,補丁包安裝很麻煩。

通過走手續,在內網申請了wkhtmltopdf二進制包,工程師傳到測試環境,直接運行了測試命令,居然一條就過!依賴不缺,甚至中文字體也不缺。這隻能說是運氣。不過,凡事預則立,多準備一些,事情周密一些總是沒錯的。

接下來,就是撰寫個工具類調用shell命令了,可能還要考慮權限認證的問題。不過,從前臺登錄後的UI發起導出,應該不會存在需要認證的問題。

皆大歡喜!

錯誤、參考和源碼

報錯:SslHandshakeFailedError

筆記本實驗時,報了個錯。貌似也不影響最終需要的導出PDF結果。後來猜測應該是頁面上有button或與打印無關的js導致的,刪了就好了。國外的網友寫了一個工具carleton/moodle-scraper,也碰上了這個問題:這個錯誤貌似不是我第一個碰上,官方也沒有修復。

moodle-scraper的KNOWN CURRENT ISSUES

WebToPDF
KNOWN CURRENT ISSUES:
1) "Issue found on page:wkhtmltopdf reported an error:
Mon Mar 28 20:51:52 unreg-30-152.dyn.carleton.edu wkhtmltopdf[3817] <Error>: CGContextSetShouldAntialias: invalid context 0x0" 
As of Spring 2016 this problem has not been solved and seems to be a problem with whtmltopdf using a deprecated library of Mac OSX. Try it with Windows and see if it breaks?
Additionally, reported issue on GitHub: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2196

報錯信息:

Loading pages (1/6)
^C===========================>                               ] 48%
ChinaDreams:WebRoot kangcunhua$ wkhtmltopdf --disable-smart-shrinking index.html export.pdf
Loading pages (1/6)
QFont::setPixelSize: Pixel size <= 0 (0)                     ] 49%
Counting pages (2/6)                                               
QFont::setPixelSize: Pixel size <= 0 (0)=====================] Object 1 of 1
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Nov  7 13:53:25  wkhtmltopdf[2603] <Error>: CGContextSetShouldAntialias: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov  7 13:53:25  wkhtmltopdf[2603] <Error>: CGContextSetShouldSmoothFonts: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov  7 13:53:25  wkhtmltopdf[2603] <Error>: CGContextSetFillColorSpace: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov  7 13:53:25  wkhtmltopdf[2603] <Error>: CGContextSetFillColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Done                                                                      
Exit with code 1 due to network error: SslHandshakeFailedError

報錯convertToUnicode:

在容器中,配置好之後,運行轉換命令,報了一個錯誤,但從結果來看,不影響最終pdf生產。故此處沒有特殊處理,不過網友給出瞭解決方案:強迫症或時間充分的網友可以自行驗證和修復:

7d183ecb0026:/prms/workspace # ./wkhtmltox/bin/wkhtmltopdf index.html exp.pdf
QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed
QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv_open failed
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done

注意上文報了一個Qt錯誤,

QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed
QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv_open failed

這是個Qt移植錯誤

下載 http://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz

>  ./configure -prefix=$PWD/_install -host=arm-linux-gnueabihf 
>   make
>   make install 
>

把 _install/lib 下的 preloadable_libiconv.so 拷到系統的 /system/lib 下, 

export LD_PRELOAD=/system/lib/preloadable_libiconv.so

參考鏈接1

感謝各位勇於分享的親:

參考鏈接2

wkhtmltopdf網頁轉PDF程序安裝教程

linux下查看yum/rpm/dpkg某軟件是否已安裝的方法

Error while loading shared libraries: libXrender.so.1 on Linux

靜態頁面

<html>
  <head>
    <meta http-equiv="Content_Type" content="text/html" charset="UTF-8">
    <title>My JSP 'index.jsp' starting page</title>
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">    
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="export echarts to pdf">
  <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
  	<script type="text/javascript" src="https://cdn.bootcss.com/echarts/3.7.2/echarts.simple.min.js"></script>
</head>
  <style type="text/css">
  	@font-face{
		font-family: Simsun;
		src:url(“/usr/share/fonts/windows/tt.ttf”)
	}
	body{
		font-family: tt ;
	}
  	
	div{page-break-inside:avoid;}  
  	table{
		page-break-inside:avoid;
  	}
  	td{
  		 border:1px solid #F00
  	}
  </style>
  <body>
    
  <H1>First Title</H1>
  <p>測試:test</p>
  <p>by kang.cunhua;</p>
    <H2>二級標題</H2>
    
    <pre>
    正文:
    輕輕的我走了,
    正如我輕輕的來;
    我輕輕的招手,
    作別西天的雲彩。

    ----
    
    那河畔的金柳,
    是夕陽中的新娘;
    波光裏的豔影,
    在我的心頭盪漾。
    
    ----
    
    軟泥上的青荇⑴,
    油油的在水底招搖⑵;
    在康河的柔波里,
    我甘心做一條水草!
    
    ----
    
    那榆蔭下的一潭,
    不是清泉,是天上虹;
    揉碎在浮藻間,
    沉澱着彩虹似的夢。
    
    </pre>
    
    <H3>三級標題</H3>
    <table border="0" cellpadding="0" cellspacing="0">
    	<tr><td>第一行第一列</td><td colspan="2" align="center">第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td></tr>
    	<tr><td>第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td></tr>
    	<tr><td>第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td><td>第一行第一列</td></tr>
    </table>
  <!-- 爲ECharts準備一個具備大小(寬高)的Dom -->
  <H4>四級標題</H4>
    <div id="main" style="width: 600px;height:400px;"></div>
    
    <script type="text/javascript">
        // 基於準備好的dom,初始化echarts實例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定圖表的配置項和數據
        var option = {
            title: {
                text: 'ECharts 入門示例'
            },
            tooltip: {},
            legend: {
                data:['銷量']
            },
            xAxis: {
                data: ["襯衫","羊毛衫","雪紡衫","褲子","高跟鞋","襪子"]
            },
            yAxis: {},
            series: [{
                name: '銷量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // 使用剛指定的配置項和數據顯示圖表。
        myChart.setOption(option);
	</script>	
</body>
</html>

本文由作者:蠻大人  授權發佈
鏈接:https://opsdev.fun/2017/11/07/O1-8-20-Docker%E5%BF%AB%E9%80%9F%E9%AA%8C%E8%AF%81HTML%E5%AF%BC%E5%87%BAPDF%E9%AB%98%E6%95%88%E6%96%B9%E6%A1%88/
著作權歸作者所有。
轉載請聯繫作者獲得授權。


docker + k8s

此課程爲網絡直播課程,一共 10 個課時,每週上一個全天,歷時兩個多月。附加:錄播視頻+筆記+除課堂外的答疑時間(7次+)2019-1-13 開課,原價 5800 ,現在週年活動 100 定金抵 800

課程主講師:GY 老師

10 年一線軟件開發經驗,先後經歷了傳統安全公司,以及多家互聯網公司;在安全開發方面,曾開發過 Linux 防火牆、web 應用防火牆、Linux 安全內核加固,基於大流量的 Web 安全威脅分析等項目;在互聯網公司工作時,曾基於 DPDK 高性能網絡開發框架開發過基於全流量的網絡流量分析平臺和基於 Sflow 網絡流量分析平臺,基於Golang 開發SmartDNS 等;開發語言也是從C -> python -> golang 的轉變過程?現從事基於 K8S 和 Docker在私有云平臺建設方面的研發工作;具備豐富的Linux系統開發經驗、網絡開發經驗以及項目管理經驗;目前開發工作90+% 都在用 Golang,Golang 是一門簡潔、高效、強大且靈活的編程語言。

關於課程的具體內容想要了解的, 掃碼加小助手諮詢瞭解

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章