URL如何转换成pdf?
IText | FlyingSaucer | WKHtmlToPdf | pd4ml | |
跨平台性 | 跨平台 | 跨平台 | 跨平台 | 跨平台 |
是否安装软件 | 否 | 否 | 需安装WKHtmlToPdf | 否 |
是否收费 | 免费 | 免费 | 免费 | 收费 |
转换Html效率 | 速度快 | 未测 | 速度慢。相比URL来说,效率较慢。能忽略一些html语法或资源是否存在问题。 | 速度快。部分CSS样式不支持。 |
转换Html效果 | 存在样式失真问题。对html语法有一定要求 | 存在样式失真问题。对html语法有较高要求。 | 失真情况较小,大部分网页能按Chome浏览器显示的页面转换 | 部分CSS样式有问题。 |
转换URL效率 | 未测 | 未测 | 效率不是特别高 | 未测 |
转换URL效果 | 未测 | 未测 | 部分网页由于其限制,或将出现html网页不完整。 | 未测 |
优点 | 不需安装软件、转换速度快 | 不需安装软件、转换速度快 | 生成PDF质量高 | 不需要安装软件、转换速度快 |
缺点 | 对html标签严格,少一个结束标签就会报错;服务器需要安装字体 | 对html标签严格,少一个结束标签就会报错;服务器需要安装字体 | 需要安装软件、时间效率不高 | 对部分CSS样式不支持。 |
图片 | 表格 | 链接 | 中文 | 特殊字符 | 整体样式 | 速度 | |
IText | 支持 | 支持 | 支持 | 支持 | 支持 | 失真问题 | 快 |
FlyingSaucer | 未知 | 未知 | 未知 | 未知 | 未知 | 未知 | 快 |
WKHtmlToPdf | 支持 | 支持 | 支持 | 支持 | 支持 | 很好 | 慢 |
pd4ml | 支持 | 支持 | 支持 | 支持 | 支持 | 失真问题 | 快 |
对比以上各类实现:
1.WKHtmlToPdf因为转换速度慢、需要安装软件的缺点被暂时排除在外;pd4ml因为是收费的,并且同样存在一些常见的样式失真问题,直接排除;
2.剩下的就是在IText和FlyingSaucer的实现方案中做选择,对比之下,选择IText作为我们的最终实现方案
方案一: IText方式
【相关依赖】
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13.2</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.13.2</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf-itext5</artifactId> <version>9.1.22</version> </dependency>
【代码实现】
import com.itextpdf.text.pdf.BaseFont; import org.xhtmlrenderer.pdf.ITextFontResolver; import org.xhtmlrenderer.pdf.ITextRenderer; import java.io.File; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; public final class HtmlUtil { private HtmlUtil() { } // 字体路径,放在资源目录下 private static final String FONT_PATH = "classpath:simsun.ttc"; public static void file2Pdf(File htmlFile, String pdfFile) { try (OutputStream os = Files.newOutputStream(Paths.get(pdfFile))) { String url = htmlFile.toURI().toURL().toString(); ITextRenderer renderer = new ITextRenderer(); renderer.setDocument(url); // 解决中文支持 ITextFontResolver fontResolver = renderer.getFontResolver(); // 获取字体绝对路径,ApplicationContextUtil是我自己写的类 String fontPath = "c:/Windows/Fonts/simsun.ttc"; fontResolver.addFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); renderer.layout(); renderer.createPDF(os); } catch (Exception e) { // 抛出自定义异常 e.printStackTrace(); } } public static void html2Pdf(String html, String pdfFile) { String pdfDir = pdfFile; /* File file = new File(pdfDir); if (!file.exists()) { file.mkdirs(); }*/ java.io.File targetFile = new java.io.File(pdfDir); if (!targetFile.getParentFile().exists()) { targetFile.getParentFile().mkdirs(); // 创建父级文件路径 } try (OutputStream os = Files.newOutputStream(Paths.get(pdfFile))) { ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString(html); // 解决中文支持 ITextFontResolver fontResolver = renderer.getFontResolver(); // 获取字体绝对路径,ApplicationContextUtil是我自己写的类 String fontPath = "c:/Windows/Fonts/simsun.ttc"; fontResolver.addFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); renderer.layout(); renderer.createPDF(os); } catch (Exception e) { // 抛出自定义异常 e.printStackTrace(); } } }
【字体文件】
simsun.tcc
方案二: FlyingSaucerf方式
依赖:
implementation("com.itextpdf:itextpdf:5.5.13.3") implementation("com.itextpdf:itext-asian:5.2.0") implementation("com.itextpdf.tool:xmlworker:5.5.13.3") implementation group: 'org.xhtmlrenderer', name: 'flying-saucer-pdf-itext5', version: '9.1.22'
代码实现:
import com.itextpdf.text.pdf.BaseFont; import org.xhtmlrenderer.pdf.ITextFontResolver; import org.xhtmlrenderer.pdf.ITextRenderer; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; public class UrlToPdfUtil { //private static final String OUT_PUT_PDF_PATH = "/home/data/pdf/"; //pdf文件的存放路径(Linux) private static final String OUT_PUT_PDF_PATH = "D:\\test\\"; //pdf文件的存放路径(windows) /** * @param url 链接地址 * @param outputFileName 转存的PDF文件名 * @Title 网页转存为PDF文件 */ public static void urlToPdf(String url, String outputFileName) { try { String folder = outputFileName.substring(0, 6); System.out.println("folder = " + folder); String outputFile = OUT_PUT_PDF_PATH + folder + "\\" + outputFileName; java.io.File targetFile = new java.io.File(outputFile); if (!targetFile.getParentFile().exists()) { targetFile.getParentFile().mkdirs(); // 创建父级文件路径 } OutputStream os = Files.newOutputStream(Paths.get(outputFile)); ITextRenderer renderer = new ITextRenderer(); renderer.setDocument(url); ITextFontResolver fontResolver = renderer.getFontResolver(); //fontResolver.addFont("/usr/share/fonts/chinese/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); //Linux fontResolver.addFont("c:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //windows renderer.layout(); renderer.createPDF(os); os.close(); } catch (Exception e) { e.printStackTrace(); } } }
测试用例:
import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest @RunWith(SpringRunner.class) public class TestPDF { @org.junit.Test public void testPdf(){ UrlToPdfUtil.urlToPdf("https://mp.weixin.qq.com/s/zFTQVmWlbqj2wgeboIexMQ", "Pdf.pdf"); HtmlUtil.html2Pdf("https://mp.weixin.qq.com/s/zFTQVmWlbqj2wgeboIexMQ", "D:\\test\\Pdf.pdf"); } }
以上实现就完成了html转换成pdf的功能 ~
常见错误: