注:原创文件,转载请注明出处

使用phantomjs生成还原度比较高的pdf文件,理论上生成word也可以,因需求没有做这块要求,功课留给大家去做了。

下载

https://phantomjs.org/download.html

根据需要选择对应版本下载使用

使用总结

担心有人等不及看下面内容,先贴出来总结,在贴代码,最后贴介绍

邮件模板可以用ftl格式来做, 使用这个类来封装import freemarker.template.Template;
############liunx下安装步骤:################# 1,解压,配置引用,安装字体防止图片汉字乱码
tar -jxvf phantomjs-2.1.1-liunx-x86.tar.bz2
mv phantomjs-2.1.1-liunx-x86 /usr/local/src/phantomjs
ln -sf /usr/local/src/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
yum install fontconfig freetype2
phantomjs -v #测试版本号 2,配置环境变量
vim /etc/profile
export PATH=${PATH}:/usr/local/src/phantomjs/bin/ 记得刷新环境变量,生效 3,在liunx服务器的任意文件目录下输入命令: phantomjs, 正常输出,则配置成功,ctrl+c退出 ###############window下使用:################ 1, 解压zip包,
2,不是全局用的话,直接在bin目录搜索栏输入cmd打开即可, 不用配置环境变量
3,命令: 共四段,第一,二段不用改;第三段为自己的index.html文件路径,也即要生成pdf的html文件路径;第四段为输出文件路径
在bin目录下: phantomjs htmlToPdf.js "file:///D://temp//index.html" "D://temp/outpdf.pdf"
注: 路径file:/// 和全路径中要用"//"来加载而不是"\\" 用到的文件名:
index.html ##html原页面
htmlToPdf.js ##将html转成pdf的关键js
outpdf.pdf ##最终生成的pdf文件 #############echarts图片生成:################### 1, 生成的echarts图片需要放到pdf中,要分两步, 使用命令生成图片:
phantomjs echarts-convert.js -infile echarts-options.js -outfile echarts-demo.png -scale 0.01 -width 800 用到的文件名:
echarts-all.js
echarts-options.js ##这个内容可以从echarts官网直接copy,实际在用的时候,可以自己生成该文件
jquery-3.2.1.min.js
echarts-demo.png ##最终生成的图片 2,第一步先生成echart.png, 然后将图片路径放到index.html中,然后在去生成pdf

上目录

上代码

Html2pdfUtil.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; /**
* 转换html为pdf
*/
public class Html2pdfUtil { public static String parseHtml2Pdf(String url) throws IOException {
System.out.println(url);
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("/Users/a/Downloads/phantomjs2/bin/phantomjs /Users/a/Downloads/phantomjs2/bin/html2pdf.js "+url + " D://tmp//outpdf.pdf");
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer sbf = new StringBuffer();
String tmp = "";
while ((tmp = br.readLine()) != null) {
sbf.append(tmp);
}
String resultstr = sbf.toString();
System.out.println("resultstr:"+resultstr);
String[] arr = resultstr.split("\\$");
String result = "";
for(String s : arr){
if(s.endsWith("pdf"))result = s;
}
return result;
}
} public class Converter {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
String result = Html2pdfUtil.parseHtml2Pdf("https://www.baidu.com");
long all = System.currentTimeMillis()- start;
System.out.println("pdf生成地址:"+result+",用时:"+all/1000+"秒");
}
}

echarts-convert.js

(function() {
var system = require('system');
var fs = require('fs');
var config = {
// define the location of js files
JQUERY : 'jquery-3.2.1.min.js',
ECHARTS : 'echarts-all.js',
// default container width and height
DEFAULT_WIDTH : '800',
DEFAULT_HEIGHT : '400'
}, parseParams, render, pick, usage; usage = function() {
console.log("\nUsage: phantomjs echarts-convert.js -options options -outfile filename -width width -height height"
+ "OR"
+ "Usage: phantomjs echarts-convert.js -infile URL -outfile filename -width width -height height\n");
}; pick = function() {
var args = arguments, i, arg, length = args.length;
for (i = 0; i < length; i += 1) {
arg = args[i];
if (arg !== undefined && arg !== null && arg !== 'null' && arg != '0') {
return arg;
}
}
}; parseParams = function() {
var map = {}, i, key;
if (system.args.length < 2) {
usage();
phantom.exit();
}
for (i = 0; i < system.args.length; i += 1) {
if (system.args[i].charAt(0) === '-') {
key = system.args[i].substr(1, i.length);
if (key === 'infile') {
// get string from file
// force translate the key from infile to options.
key = 'options';
try {
map[key] = fs.read(system.args[i + 1]).replace(/^\s+/, '');
} catch (e) {
console.log('Error: cannot find file, ' + system.args[i + 1]);
phantom.exit();
}
} else {
map[key] = system.args[i + 1];
}
}
}
return map;
}; render = function(params) {
var page = require('webpage').create(), createChart; page.onConsoleMessage = function(msg) {
console.log(msg);
}; page.onAlert = function(msg) {
console.log(msg);
}; createChart = function(inputOption, width, height) {
var counter = 0;
function decrementImgCounter() {
counter -= 1;
if (counter < 1) {
console.log(messages.imagesLoaded);
}
} function loadScript(varStr, codeStr) {
var script = $('<script>').attr('type', 'text/javascript');
script.html('var ' + varStr + ' = ' + codeStr);
document.getElementsByTagName("head")[0].appendChild(script[0]);
if (window[varStr] !== undefined) {
console.log('Echarts.' + varStr + ' has been parsed');
}
} function loadImages() {
var images = $('image'), i, img;
if (images.length > 0) {
counter = images.length;
for (i = 0; i < images.length; i += 1) {
img = new Image();
img.onload = img.onerror = decrementImgCounter;
img.src = images[i].getAttribute('href');
}
} else {
console.log('The images have been loaded');
}
}
// load opitons
if (inputOption != 'undefined') {
// parse the options
loadScript('options', inputOption);
// disable the animation
options.animation = false;
} // we render the image, so we need set background to white.
$(document.body).css('backgroundColor', 'white');
var container = $("<div>").appendTo(document.body);
container.attr('id', 'container');
container.css({
width : width,
height : height
}); // render the chart
var myChart = echarts.init(container[0]);
myChart.setOption(options);
// load images
loadImages();
}; // parse the params
page.open("about:blank", function(status) {
// inject the dependency js
page.injectJs(config.JQUERY);
page.injectJs(config.ECHARTS); var width = pick(params.width, config.DEFAULT_WIDTH);
var height = pick(params.height, config.DEFAULT_HEIGHT); // create the chart
page.evaluate(createChart, params.options, width, height); // define the clip-rectangle
page.clipRect = {
top : 0,
left : 0,
width : width, height : height
};
// render the image
page.render(params.outfile);
console.log('render complete:' + params.outfile);
// exit
phantom.exit();
});
};
// get the args
var params = parseParams(); // validate the params
if (params.options === undefined || params.options.length === 0) {
console.log("ERROR: No options or infile found.");
usage();
phantom.exit();
}
// set the default out file
if (params.outfile === undefined) {
var tmpDir = fs.workingDirectory + '/tmp';
// exists tmpDir and is it writable?
if (!fs.exists(tmpDir)) {
try {
fs.makeDirectory(tmpDir);
} catch (e) {
console.log('ERROR: Cannot make tmp directory');
}
}
params.outfile = tmpDir + "/" + new Date().getTime() + ".png";
} // render the image
render(params);
}());

echarts-options.js

该内容可以参考https://echarts.apache.org/examples/zh/index.html 官网,寻找自己需要的图表样式

{
title : {
text: '未来一周气温变化',
subtext: '纯属虚构'
},
tooltip : {
trigger: 'axis'
},
legend: {
data:['最高气温','最低气温']
},
toolbox: {
show : false,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
magicType : {show: true, type: ['line', 'bar']},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : true,
xAxis : [
{
type : 'category',
boundaryGap : false,
data : ['周一','周二','周三','周四','周五','周六','周日']
}
],
yAxis : [
{
type : 'value',
axisLabel : {
formatter: '{value} °C'
}
}
],
series : [
{
name:'最高气温',
type:'line',
data:[11, 11, 15, 13, 12, 13, 10],
markPoint : {
data : [
{type : 'max', name: '最大值'},
{type : 'min', name: '最小值'}
]
},
markLine : {
data : [
{type : 'average', name: '平均值'}
]
}
},
{
name:'最低气温',
type:'line',
data:[1, -2, 2, 5, 3, 2, 0],
markPoint : {
data : [
{name : '周最低', value : -2, xAxis: 1, yAxis: -1.5}
]
},
markLine : {
data : [
{type : 'average', name : '平均值'}
]
}
}
]
}

htmlToPdf.js

var page = require('webpage').create();
var system = require('system'); ////读取命令行参数,也就是js文件路径。
if (system.args.length === 1) {
console.log('Usage: loadspeed.js <some URL>');
//这行代码很重要。凡是结束必须调用。否则phantomjs不会停止
phantom.exit();
}
page.settings.loadImages = true; //加载图片
page.settings.resourceTimeout = 10000;//超过10秒放弃加载
//缩放比例
page.zoomFactor=1;
// 设置浏览器
page.settings.userAgent='Mozilla/5.0 AppleWebKit/537.36 (KHTML,like Gecko) Chrome/33.0.1750.117 Safari/537.36';
//截图设置,
//page.viewportSize = {
// width: 1000,
// height: 3000
//};
// 设置尺寸
page.paperSize={format: 'A4',orientation:'portrait',margin:'0.8cm',border:'1cm'};
// page.paperSize = { width:'1500px',height:'2000px',orientation: 'portrait',border: '1cm' };
var address = system.args[1];
var outpathstr = system.args[2];
page.open(address, function(status) {
function checkReadyState() {//等待加载完成将页面生成pdf
setTimeout(function () {
var readyState = page.evaluate(function () {
return document.readyState;
});
if ("complete" === readyState) {
// var timestamp = Date.parse(new Date());
// var pdfname = 'HT_'+timestamp + Math.floor(Math.random()*1000000);
// var outpathstr = "/Users/zachary/Downloads/phantomjs2/bin/"+pdfname+".pdf";
setTimeout(function () {
page.render(outpathstr);
//console.log就是传输回去的内容。
console.log("生成成功");
console.log("$"+outpathstr+"$");
phantom.exit();
},200);
} else {
checkReadyState();
}
},200);
}
checkReadyState();
});

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div></div> 这是个demo,随便写的,
如果要加载图片路径,可以使用相对路径,也可使用绝对路径
</body>
</html>

jquery-3.2.1.min.js 该文件自己百度下载下即可,就不贴了

echarts-all.js 该文件自己去百度下载下,这里就不贴了

使用方式

参考最上边贴的总结,命令行也在,自己动手试一试即可

PDF 格式设置

我们需要的设置,基本上就是页面格式、缩放、加载图片等,但有些例外,下面一一讲解。

page.paperSize = { format: 'A4', orientation: 'portrait', margin: '0.8cm' };

注释掉了官方例子的设置代码,因为传入的参数只有3个,到 .pdf 为止,如果写成通用模式,当然可以作为外部参数传入。

format :A4 纸,可以设置 "5in7.5in", "10cm20cm", "Letter" 等

orientation :纸方向是竖着的,或者 landscape

margin :与纸四边间距,可自定义,也可详细设置 margin : { left: '0.8cm', top : '0.8cm', right : '0.8cm', bottom : '0.8cm' }

page.zoomFactor = 1;

page.settings.loadImages = true;

zoomFactor :页面缩放比例

loadImages :页面加载图片

page.settings.userAgent = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36';

这个设置比较不常见,一般的示例中都没有提及,因为发现用 chrome 和 IE 打开生成的 pdf 时格式有点不一样(表现在分页方面),由于偏向 Chrome 浏览格式,故设置此值,解决这个不一致问题。

page.open 里面的 setTimeout 方法作用:等待页面执行完 js ,再生成 pdf。当然对于 js 要执行多久(要等多久),这个就不知道怎么预算了。其实我有试过 ajax 方式加载内容,但因此问题而作罢了。

PDF 分页

分页来说,更好控制,不需要代码(js)设置,页面使用样式即可:

style = “page-break-after: always;”

控制每页内容的大小,使用

content

就行。

更多选择 style=“page-break-before: always;” , style="page-break-inside: avoid;" 这个可以避免内容散到两页中

就写道这里了,觉得文章不错,留言鼓励下哦!

生成pdf phantomjs的更多相关文章

  1. 生成PDF的新选择-Phantomjs

    最近在node.js项目开发中,遇见生成PDF的需求,当然生成PDF不是一个新意的需求:我可以选择利用开源的pdfkit或者其他node pdf模块,或者通过edge.js调用.net/python下 ...

  2. 使用webdriver + phantomjs + pdfkit 生成PDF文件

    实例 #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on Dec 6, 2013 @author: Jay <smile665@gm ...

  3. java调用wkhtmltopdf生成pdf文件,美观,省事

    最近项目需要导出企业风险报告,文件格式为pdf,于是搜了一大批文章都是什么Jasper Report,iText ,flying sauser ,都尝试了一遍,感觉不是我想要的效果, 需要自己调整好多 ...

  4. 电子凭证 : Java 生成 Pdf

    来源:蛙牛, my.oschina.net/lujianing/blog/894365 如有好文章投稿,请点击 → 这里了解详情 1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中 ...

  5. Itext生成pdf文件

    来源:https://my.oschina.net/lujianing/blog/894365 1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等. ...

  6. Java iText+FreeMarker生成PDF(HTML转PDF)

    1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打印.目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户. ...

  7. 利用Java动态生成 PDF 文档

    利用Java动态生成 PDF 文档,则需要开源的API.首先我们先想象需求,在企业应用中,客户会提出一些复杂的需求,比如会针对具体的业务,构建比较典型的具备文档性质的内容,一般会导出PDF进行存档.那 ...

  8. html 生成pdf

    HTML生成PDF(c#) 最近因为工作需要,小小的研究了一下HTML生成PDF的方法,这方面的内容很多,但要么是不尽如人意的方法,要么就是那种收费的类库!为了广大.neter的福利,把自己的一点小小 ...

  9. iTextSharp生成pdf的一个简单例子

    效果图: 参考:http://www.cnblogs.com/CareySon/archive/2011/11/09/2243496.html http://www.cnblogs.com/julyl ...

随机推荐

  1. 牛客NC15879 A Simple Problem

    传送门:A Simple Problem 题意 给定两个序列s1和s2,同样的数字可以用相同的别的数字代替(并且也可以是出现过的数字),问s2在s1中出现了几次. 题解 首先预处理一下这两个序列,因为 ...

  2. Codeforces Round #655 (Div. 2) A. Omkar and Completion

    题目链接:https://codeforces.com/contest/1372/problem/A 题意 构造一个大小为 $n$ 的数组 $a$,要求满足 $1 \le a_i \le n$,且不存 ...

  3. HDU5286 wyh2000 and sequence【分块 均摊复杂度】

    HDU5286 wyh2000 and sequence 题意: 给出长为\(N\)的序列\(A_1,A_2,A_3,\cdots,A_n\),\(q\)次询问,每次询问给出区间\([L,R]\),假 ...

  4. NOIP2015提高组 信息传递 ---并查集问题

    题目描述 有 n 个同学(编号为 1 到 n )正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 Ti​ 的同学. 游戏开始时,每人都只 ...

  5. POJ - 3693 Maximum repetition substring(重复次数最多的连续重复子串)

    传送门:POJ - 3693   题意:给你一个字符串,求重复次数最多的连续重复子串,如果有一样的,取字典序小的字符串. 题解: 比较容易理解的部分就是枚举长度为L,然后看长度为L的字符串最多连续出现 ...

  6. AtCoder Beginner Contest 163

    比赛链接:https://atcoder.jp/contests/abc163/tasks A - Circle Pond 题意 由半径输出圆周长. 代码 #include <bits/stdc ...

  7. kubernetes进阶(五)dashboard--WEB管理

    dashboard是k8s的可视化管理平台,是三种管理k8s集群方法之一 首先下载镜像上传到我们的私有仓库中:hdss7-200 # docker pull k8scn/kubernetes-dash ...

  8. 实现基于股票收盘价的时间序列的统计(用Python实现)

    时间序列是按时间顺序的一组真实的数字,比如股票的交易数据.通过分析时间序列,能挖掘出这组序列背后包含的规律,从而有效地预测未来的数据.在这部分里,将讲述基于时间序列的常用统计方法. 1 用rollin ...

  9. μC/OS-III---I笔记6---互斥信号量

    互斥信号量 操作系统中利用信号量解决进程间的同步和互斥(互斥信号量)的问题,在多道程序环境下,操作系统就是遮掩实现进程之间的同步和互斥.但是在使用的过程中厉害的前辈还是发现了这一优秀机制的缺陷,它会导 ...

  10. 018-019 NET5_内置容器支持依赖注入+IServiceCollection的生命周期

    概念: DI依赖注入: IServiceCollection仅支持构造函数注入 什么是依赖注入? 如果对象A依赖对象B,对象B依赖对象C,就可以先构造对象C,然后传递给对象B,再把对象B传递给A.得到 ...