需求分析

项目中用到了 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  (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  toc --toc-header-text "第四季度季报" index.html export.pdf

模拟商业环境

我们拿到项目中实践验证下方案。商业项目,往往是残酷的要求,会遇到各种各样demo时碰不上的挑战。

思路还是先用docker神器,模拟商业环境,验证方案,然后再修订验证后的方案到正式项目环境验证。

客户方提供的环境是SuSE。我们先来看看是哪个版本

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

请 Docker 神器

查找 SuSE 镜像,恰好有一个11版本的,下载镜像先

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

启动镜像

docker run --name suse-ep -it yuzhenpin/suse--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) -Bit Server VM (build 24.51-b03, mixed mode)
9e023776a1d5:/ # id
uid=(root) gid=(root) groups=(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. =>  (0x00007ffe40bd2000)
  libXrender.so. => not found
  libfontconfig.so. => not found
  libfreetype.so. => not found
  libXext.so. => not found
  libX11.so. => not found
  libz.so. => /lib64/libz.so. (0x00007f9ca59ad000)
  libdl.so. => /lib64/libdl.so. (0x00007f9ca57a9000)
  librt.so. => /lib64/librt.so. (0x00007f9ca55a0000)
  libpthread.so. => /lib64/libpthread.so. (0x00007f9ca5383000)
  libstdc++.so. => /usr/lib64/libstdc++.so. (0x00007f9ca507b000)
  libm.so. => /lib64/libm.so. (0x00007f9ca4e02000)
  libgcc_s.so. => /lib64/libgcc_s.so. (0x00007f9ca4bec000)
  libc.so. => /lib64/libc.so. (0x00007f9ca4870000)
  /lib64/ld-linux-x86-.so. (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:  for conversion, iconv_open failed
QIconvCodec::convertFromUnicode:  for conversion, iconv_open failed
Loading pages (/)
Counting pages (/)
Resolving links (/)
Loading headers and footers (/)
Printing pages (/)
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:
) "Issue found on page:wkhtmltopdf reported an error:
Mon Mar  :: unreg--.dyn.carleton.edu wkhtmltopdf[] <Error>: CGContextSetShouldAntialias: invalid context 0x0"
As of Spring  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 (/)
^C===========================>                               ] %
ChinaDreams:WebRoot kangcunhua$ wkhtmltopdf --disable-smart-shrinking index.html export.pdf
Loading pages (/)
QFont::setPixelSize: Pixel size <=  ()                     ] %
Counting pages (/)
QFont::setPixelSize: Pixel size <=  ()=====================] Object  of
Resolving links (/)
Loading headers and footers (/)
Printing pages (/)
Nov   ::  wkhtmltopdf[] <Error>: CGContextSetShouldAntialias: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov   ::  wkhtmltopdf[] <Error>: CGContextSetShouldSmoothFonts: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov   ::  wkhtmltopdf[] <Error>: CGContextSetFillColorSpace: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov   ::  wkhtmltopdf[] <Error>: CGContextSetFillColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Done
Exit with code  due to network error: SslHandshakeFailedError

报错 convertToUnicode:

在容器中,配置好之后,运行转换命令,报了一个错误,但从结果来看,不影响最终 pdf 生产。故此处没有特殊处理,不过网友给出了解决方案:强迫症或时间充分的网友可以自行验证和修复:

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

注意上文报了一个 Qt 错误,

QIconvCodec::convertToUnicode:  for conversion, iconv_open failed
QIconvCodec::convertFromUnicode:  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=">
  <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=">
        <tr><td>第一行第一列</td><td colspan=" 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: [, , , , , ]
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>
</html>
# 离线 # docke

51Reboot  Docker +K8s 课程正在火热招生中,有需求的小伙伴可以了解一下

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 是一门简洁、高效、强大且灵活的编程语言。

关于课程的具体内容想要了解的, 扫码加小助手咨询

Docker 快速验证 HTML 导出 PDF 高效方案的更多相关文章

  1. Docker中部署puppeteer导出pdf

    最近在做puppeteer容器化的过程中发现问题. 在容器中npm install puppeteer仍然会报错,不能launch 随后错误提示中也给出了官方的文档,https://github.co ...

  2. 一文教您如何通过 Docker 快速搭建各种测试环境(Mysql, Redis, Elasticsearch, MongoDB) | 建议收藏

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  3. 个人永久性免费-Excel催化剂功能第50波-批量打印、导出PDF、双面打印功能

    在倡导无纸化办公的今天,是否打印是一个碍眼的功能呢,某些时候的确是,但对于数据的留存,在现在鼓吹区块链技术的今天,仍然不失它的核心价值,数据报表.单据打印出来留存,仍然是一种不可或缺的数据存档和防篡改 ...

  4. 用前端姿势玩docker【四】基于docker快速构建webpack的开发与生产环境

    目录 用前端姿势玩docker[一]Docker通俗理解常用功能汇总与操作埋坑 用前端姿势玩docker[二]dockerfile定制镜像初体验 用前端姿势玩docker[三]基于nvm的前端环境构建 ...

  5. Spring Boot 系列教程18-itext导出pdf下载

    Java操作pdf框架 iText是一个能够快速产生PDF文件的java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好 ...

  6. asp.net2.0导出pdf文件完美解决方案【转载】

    asp.net2.0导出pdf文件完美解决方案 作者:清清月儿 PDF简介:PDF(Portable Document Format)文件格式是Adobe公司开发的电子文件格式.这种文件格式与操作系统 ...

  7. 使用 puppeteer 创建一个自动化导出 PDF 的服务

    最近在基于 RAP2 做内网的一个 API 管理平台,涉及到与外部人员进行协议交换,需要提供 PDF 文档. 在设置完成 CSS 后已经可以使用浏览器的打印功能实现导出 PDF,但全手动,总是觉得不爽 ...

  8. 使用Docker快速搭建ELK环境

    今天由于Win系统的笔记本没带回家,其次Docker在非Linux系统下都需要安装额外的软件去镜像才行 所以感觉没有差别,先直接用Mac搭建一遍呢, 本篇部分命令和配置内容为摘抄 Mac下使用Dock ...

  9. Docker 快速安装&搭建 Ngnix 环境,并配置反向代理

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

随机推荐

  1. JavaScript大杂烩7 - 理解内置集合

    JavaScript内置了很多对象,简单的类型如String,Number,Boolean (相应的"值类型"拥有相同的方法),复杂一点的如Function,Object,Arra ...

  2. jquery判断checkBox的checked

    jquery判断checked的三种方法:.attr('checked):   //看版本1.6+返回:”checked”或”undefined” ;1.5-返回:true或false.prop('c ...

  3. Linux RCU 机制详解

    1.简介: RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用. RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用R ...

  4. 3.8Python数据处理篇之Numpy系列(八)---Numpy的梯度函数

    目录 目录 前言 (一)函数说明 (二)一维数组的应用 (三)多维数组的应用 目录 前言 梯度函数,其中的梯度也就是斜率,反映的是各个数据的变化率.在numpy中只有一个梯度函数. (一)函数说明 ( ...

  5. golang中数组与切片的区别

    初始化:数组需要指定大小,不指定也会根据初始化的自动推算出大小,不可改变 数组: a := [...],,} a := [],,} 切片: a:= [],,} a := make([]) a := m ...

  6. MySQL的并发控制与加锁分析

    本文主要是针对MySQL/InnoDB的并发控制和加锁技术做一个比较深入的剖析,并且对其中涉及到的重要的概念,如多版本并发控制(MVCC),脏读(dirty read),幻读(phantom read ...

  7. socket 总结

    网络编程之进程:http://www.cnblogs.com/1a2a/p/7428759.html 网络编程之进阶:http://www.cnblogs.com/1a2a/p/7444446.htm ...

  8. vue - 状态管理器 Vuex

    状态管理 vuex是一个专门为vue.js设计的集中式状态管理架构.状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态.简单的说就是data中需要共用的属性.

  9. 【html5】如何让Canvas标签自适应设备

    javascript方法: var oC=document.querySelectorAll('canvas')[0];oC.width=document.documentElement.client ...

  10. 转载 [ZooKeeper.net] 3 ZooKeeper的分布式锁

    [ZooKeeper.net] 3 ZooKeeper的分布式锁   基于ZooKeeper的分布式锁  源码分享:http://pan.baidu.com/s/1miQCDKk ZooKeeper ...