最近要实现打印echart图的功能,echart图自带的是生成图片,研究了一下,在这总结一下,总共有两种方式:
- 第一种:前台直接打印,不走服务器端,原理是扫描html页面生成图片流再生成pdf,弊端是ie浏览器不能用
- 第二种:获取echarts图的base64编码,通过后台生成图片,再生成pdf
第一种前台直接打印:
需要引入的包html2canvas.js和jsPdf.debug.js。我所打印的页面是不需要分页的,大家自行选择,注释部分的代码为测试代码,请斟酌后再使用。
//导出
$("#exportImg").click(function () {
var target = document.getElementById("test");//需要打印区域的id
target.style.background = "#FFFFFF";//设置打印背景的颜色为白色,若不设置,会发现背景为黑色
html2canvas(target, {
onrendered:function(canvas) {
//返回图片URL,参数:图片格式和清晰度(0-1)
var pageData = canvas.toDataURL('image/jpeg', 1.0);
//方向默认竖直,尺寸ponits,格式a4【595.28,841.89]
var pdf = new jsPDF('', 'pt', 'a4');
//需要dataUrl格式
//arg3-->距离左边距;arg4-->距离上边距;arg5-->宽度;arg6-->高度
pdf.addImage(pageData, 'JPEG', 20, 20, 595.28, 592.28/canvas.width * canvas.height );
pdf.save('echart图.pdf');
}
})
/* html2canvas(document.getElementById('zbChart'), {
onrendered: function(canvas) {
document.body.appendChild(canvas);
createPDFObject(canvas.toDataURL("image/jpeg"));
}
});*/
/*html2canvas(target, {
onrendered:function(canvas) {
var contentWidth = canvas.width;
var contentHeight = canvas.height;
//一页pdf显示html页面生成的canvas高度;
var pageHeight = contentWidth / 592.28 * 841.89;
//未生成pdf的html页面高度
var leftHeight = contentHeight;
//页面偏移
var position = 0;
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
var imgWidth = 595.28;
var imgHeight = 592.28/contentWidth * contentHeight;
var pageData = canvas.toDataURL('image/jpeg', 1.0);
var pdf = new jsPDF('', 'pt', 'a4');
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
} else {
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight;
position -= 841.89;
//避免添加空白页
if(leftHeight > 0) {
pdf.addPage();
}
}
}
pdf.save("content.pdf");
}
})
});
function createPDFObject(imgData) {
var doc = new jsPDF('p', 'pt');
// 修改背景色
$('#test').css("background", "#fff")
doc.addImage(imgData, 5, 5, 600, 300, 'img');
doc.save('echart图' + '.pdf')
}*/
第二种:走后台服务端
因生成图片编码会很长,用window.open会报请求头过长的错误,虽然这个错误可通过修改tomcat中server.xml文件来解决,本人亲测,修改后会导致部分请求不好用,建议不用。所以在这里用form表单请求提交后台,用form表单时如果想新跳转一个窗口,需添加target="_black",否则是在本窗口显示。ie9浏览器初次加载时会不好用,但是多次重新加载后会好用,此问题尚未发现原因。
- html页面代码:
<form id="chartForm" style="display:none" target="_blank">
<input id="pdfTitle" name="pdfTitle" type="text" maxlength="100"/>
<input id="imageValue" name="base64Info" type="text" maxlength="50000"/>
</form>
- js代码:
$('#exportImg').click(function(){
var chartExportUrl = '../echartImg/export.htm';
var thisChart = echarts.init(document.getElementById('zbChart'));
var picBase64Info = thisChart.getDataURL();//获取echarts图的base64编码,为png格式。
exportImg(chartExportUrl,picBase64Info,"echart图");
});
function exportImg(chartExportUrl,picBase64Info,title){
$('#chartForm').find('input[name="base64Info"]').val(picBase64Info);//将编码赋值给输入框
$('#chartForm').find('input[name="pdfTitle"]').val(title);//将标题赋值给输入框
$('#chartForm').attr('action',chartExportUrl).attr('method', 'post');//设置提交到的url地址
$('#chartForm').attr('action',chartExportUrl).attr('method', 'post');//设置提交方式为post
$('#chartForm').submit();
// window.open(chartExportUrl+"?base64Info="+picBase64Info);请求头太长,只能用form提交
}
- 后台代码:此处只展示工具类,控制类请自己写
public static String exportFilePath = "D:/image/";
//echart图生成图片,所以需要在服务器新建一个文件夹来存放
public static void exportImg(HttpServletResponse response,String base64Info,String pdfTitle){
String newFileName = pdfTitle + System.currentTimeMillis() + ".pdf";
String newPngName = newFileName.replaceFirst(".pdf", ".png");
base64Info = base64Info.replaceAll(" ", "+");
BASE64Decoder decoder = new BASE64Decoder();
String[] arr = base64Info.split("base64,");
byte[] buffer;
try {
buffer = decoder.decodeBuffer(arr[1]);
} catch (IOException e) {
throw new RuntimeException();
}
OutputStream output = null;
try {
output = new FileOutputStream(new File(exportFilePath+newPngName));//生成png文件
output.write(buffer);
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
printPdf(response,exportFilePath+newPngName,exportFilePath+newFileName,pdfTitle);
}
//通过png文件来生成pdf文件
public static void printPdf(HttpServletResponse response, String imagePath, String mOutputPdfFileName, String pdfTitle) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
Document doc = new Document(PageSize.A4, 20, 20, 20, 20);
try {
PdfWriter.getInstance(doc, buffer);
Font font = PrintPdfUtil.createFont("宋体",14);
//用table添加,可以直接添加到doc文档中,但是标题和图上下距离太远,设置间距也不管用,所以用的table
PdfPTable table = new PdfPTable(1);//1列
table.setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setBorderWidth(0);
table.setWidthPercentage(100);//宽度百分百
doc.addTitle(pdfTitle);
doc.open();
doc.newPage();
Image png = Image.getInstance(imagePath);
float heigth = png.getHeight();
float width = png.getWidth();
int percent = getPercent2(heigth, width);
png.setAlignment(Image.MIDDLE);//图像居中显示
png.setAlignment(Image.TEXTWRAP);//文字围绕图像
png.scalePercent(percent + 3);//表示是原来图像的比例
Paragraph title = new Paragraph(pdfTitle,font);
title.setAlignment(Paragraph.ALIGN_CENTER);
PdfPCell cell = new PdfPCell(title);
cell = createCell(cell);
cell.setFixedHeight(30);//行高
table.addCell(cell);
PdfPCell cellImg = new PdfPCell(png);
cellImg = createCell(cellImg);
table.addCell(cellImg);
doc.add(table);
doc.close();
//开始打印
PrintPdfUtil.printUtil(response, buffer);
response.setContentType("application/octet-stream");
/* 此处注释的代码为下载,我所做的效果是生成预览pdf文件,若需下载,请用下面的
InputStream input = null;
OutputStream outputString = null;
try {
response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode(pdfTitle + ".pdf", "UTF-8"));
input = new BufferedInputStream(new FileInputStream(new File(mOutputPdfFileName)));
outputString = new BufferedOutputStream(response.getOutputStream());
copy(input, outputString);
outputString.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally{
input.close();
outputString.close();
}*/
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static PdfPCell createCell(PdfPCell cell) throws DocumentException, IOException {
//设置垂直居中
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setBorderWidth(0);
return cell;
}
//按照宽度压缩,呈现最好视觉效果
private static int getPercent2(float h, float w) {
int p = 0;
float p2 = 0.0f;
p2 = 530 / w * 100;
p = Math.round(p2);
return p;
}
//输入流读取到输出流
public static void copy(InputStream input, OutputStream outputString) throws IOException {
byte [] but = new byte[input.available()];
try {
while(input.read()!=-1){
int by = input.read(but);
outputString.write(but, 0, by);
outputString.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 打印到页面预览
public static void printUtil(HttpServletResponse response, ByteArrayOutputStream buffer) throws IOException {
response.reset();
response.setContentType("application/pdf");
DataOutput output = new DataOutputStream(response.getOutputStream());
byte[] bytes = buffer.toByteArray();
response.setContentLength(bytes.length);
for (int j = 0; j < bytes.length; j++) {
output.writeByte(bytes[j]);
}
}