使用Playwright把带有echarts图表的html优雅转成pdf
这是一个工作中遇到的需求:自定义HTML页面里有大量的ECharts图表,需要程序填充数据之后再转成PDF发送给客户端。
我是这么做的(以下只做简单示例,并不贴出实际项目中的应用代码):
Maven依赖配置
首先添加Playwright的Maven依赖,这里我使用的是比较新的1.57.0版本:
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.57.0</version>
</dependency>
环境变量配置
由于国内网络原因,需要配置Playwright下载镜像源:
PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright/
可以是项目变量也可以是系统变量。
核心转换代码
package org.at930;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.Margin;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* HTML转PDF转换器 - 使用Playwright for Java
* 将HTML文件(包含ECharts图表、图片等资源)转换为PDF格式
*/
public class HtmlToPdfConverter {
public static void convertHtmlToPdf(String htmlFilePath, String outputPdfPath) throws Exception {
Browser browser = null;
try {
BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions()
.setChannel("msedge")
.setHeadless(true)
.setArgs(java.util.Arrays.asList(
"--no-sandbox",
"--disable-dev-shm-usage"
));
browser = Playwright.create().chromium().launch(launchOptions);
Page page = browser.newPage();
page.navigate("file://" + Paths.get(htmlFilePath).toAbsolutePath());
page.waitForFunction("() => document.readyState === 'complete'");
byte[] pdfBytes = page.pdf(new Page.PdfOptions()
.setFormat("A4")
.setPrintBackground(true)
.setMargin(new Margin()
.setTop("13mm")
.setRight("11mm")
.setBottom("13mm")
.setLeft("11mm")
)
);
Path outputPath = Paths.get(outputPdfPath);
Path outputDir = outputPath.getParent();
if (outputDir != null && !Files.exists(outputDir)) {
Files.createDirectories(outputDir);
}
// 保存PDF文件
Files.write(outputPath, pdfBytes);
// 关闭页面
page.close();
} catch (Exception e) {
System.err.println("PDF转换失败: " + e.getMessage());
e.printStackTrace();
throw e;
} finally {
// 关闭浏览器
if (browser != null) {
browser.close();
}
}
}
public static void main(String[] args) {
String htmlFilePath = "D:\\java_playwrightHtmlToPDF\\html\\健康监测报告-无病例用药简约版本.html";
String outputPdfPath = "D:\\java_playwrightHtmlToPDF\\output\\text2.pdf";
if (args.length >= 2) {
htmlFilePath = args[0];
outputPdfPath = args[1];
}
System.out.println("HTML文件: " + htmlFilePath);
System.out.println("输出PDF: " + outputPdfPath);
System.out.println();
try {
convertHtmlToPdf(htmlFilePath, outputPdfPath);
System.out.println("========================================");
System.out.println("转换完成!PDF已保存至: " + outputPdfPath);
System.out.println("========================================");
} catch (Exception e) {
System.err.println("========================================");
System.err.println("转换失败: " + e.getMessage());
System.err.println("========================================");
e.printStackTrace();
System.exit(1);
}
}
}
服务器环境配置
在Linux服务器上配置环境变量:
echo 'export PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright/' >> /etc/profile.d/playwright.sh
验证配置是否生效:
[root@iZ2vc8cxg4knyehdo5xmzsZ ~]# echo $PLAYWRIGHT_DOWNLOAD_HOST
https://npmmirror.com/mirrors/playwright/
Docker容器配置
如果是在Docker容器中运行,需要在Dockerfile中配置环境变量:
FROM openjdk:17
RUN mkdir -p /zhyl-ylhealth-server
WORKDIR /zhyl-ylhealth-server
COPY zhyl-ylhealth-server.jar app.jar
ENV PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright/
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/zhyl-ylhealth-server/heapdump.hprof"
EXPOSE 48101
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
关键配置说明
- setChannel("msedge"):使用Microsoft Edge浏览器内核,对ECharts等Canvas渲染支持更好
- setHeadless(true):无头模式运行,适合服务器环境
- --no-sandbox:禁用沙箱模式,解决Linux权限问题
- --disable-dev-shm-usage:禁用/dev/shm共享内存,避免Docker容器内存不足
- waitForFunction:等待页面完全加载,确保ECharts图表渲染完成
- setPrintBackground(true):打印背景色和背景图,保证PDF视觉效果
- Margin设置:上下13mm,左右11mm,可根据实际需求调整边距
优势分析
- 完美支持ECharts:Playwright基于Chromium内核,能够完整渲染Canvas绘制的ECharts图表
- 资源自动加载:自动处理HTML中的图片、CSS、JS等外部资源
- 异步等待机制:通过
waitForFunction确保动态内容完全渲染后再转换 - 高质量输出:生成的PDF清晰度高,文字可选中,图表不失真
- 跨平台支持:Windows、Linux、macOS均可运行
- Docker友好:配合无头模式和适当参数,可在容器中稳定运行
注意事项
- 首次运行下载:首次运行会自动下载浏览器内核,建议提前配置镜像源加速下载
- ECharts异步加载:如果ECharts是异步加载数据,需要增加等待时间或自定义等待条件
- 内存管理:及时关闭Browser和Page对象,避免内存泄漏
- 字体支持:Linux服务器可能需要安装中文字体,否则PDF中文可能显示异常
- 超时控制:可以设置
page.setDefaultTimeout()防止页面加载超时
相关资源
- Playwright版本仓库:https://mvnrepository.com/artifact/com.microsoft.playwright/playwright/versions
- Playwright官方文档:https://playwright.cn/java/docs/intro
相比传统的iText、Flying Saucer等方案,Playwright的优势在于它是真正的浏览器引擎,能够完整渲染现代Web页面的所有特性,特别是对于ECharts这类基于Canvas的动态图表,能够实现像素级的完美转换。