1. 概述
在这个快速教程中,我们将学习如何使用OpenPDF在Java中实现HTML生成PDF文件。
2. OpenPDF
OpenPDF 是一个用于创建和编辑PDF文件的Java库,遵守LGPL和MPL协议。它是iText项目的分支。实际上,在版本5之前,使用OpenPDF生成PDF的代码几乎与iText API相同。它是一个维护良好的Java生成PDF的解决方案。
3. 使用Flying Saucer库实现
Flying Saucer是一个Java库,底层封装了OpenPDF,允许我们使用XML/XHTML + CSS 技术渲染生成为PDF文件。
3.1. Maven依赖
首先,我们需要添加Maven依赖:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-openpdf</artifactId>
<version>9.5.1</version>
</dependency>
我们将使用库jsoup来解析HTML文件、输入流、URL和字符串。它提供了DOM(文档对象模型)遍历功能、CSS以及类似jQuery的选择器,以从HTML中提取数据。
flying-saucer-pdf-openpdf库接受HTML文件的XML表示,应用CSS格式和样式,并输出PDF。
3.2. HTML转PDF
在这个教程中,我们将讨论HTML到PDF转换的一些常见情况,如HTML中的图像和样式,使用Flying Saucer和OpenPDF。我们还将讨论如何定制代码以接受外部样式、图像和字体。
让我们看一个示例HTML代码:
<html>
<head>
<style>
.center_div {
border: 1px solid gray;
margin-left: auto;
margin-right: auto;
width: 90%;
background-color: #d0f0f6;
text-align: left;
padding: 8px;
}
</style>
<link href="style.css" rel="stylesheet">
</head>
<body>
<div class="center_div">
<h1>Hello Baeldung!</h1>
<img src="Java_logo.png">
<div class="myclass">
<p>This is the tutorial to convert html to pdf.</p>
</div>
</div>
</body>
</html>
要将HTML转换为PDF,首先从定义的位置读取HTML文件:
File inputHTML = new File(HTML);
接下来,我们将使用jsoup将上述HTML文件转换为jsoup Document,以便渲染XHTML。
以下是XHTML输出:
Document document = Jsoup.parse(inputHTML, "UTF-8");
document.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
return document;
最后一步,我们将使用ITextRenderer从上一步生成的XHTML文档创建PDF文件。请注意,我们使用了try-with-resources
块来确保输出流在结束后关闭:
try (OutputStream outputStream = new FileOutputStream(outputPdf)) {
ITextRenderer renderer = new ITextRenderer();
SharedContext sharedContext = renderer.getSharedContext();
sharedContext.setPrint(true);
sharedContext.setInteractive(false);
renderer.setDocumentFromString(xhtml.html());
renderer.layout();
renderer.createPDF(outputStream);
}
3.3. 为外部样式自定义
我们可以将HTML输入文档中使用的额外字体注册到ITextRenderer,以便在生成PDF时包含它们:
renderer.getFontResolver().addFont(getClass().getClassLoader().getResource("fonts/PRISTINA.ttf").toString(), true);
ITextRenderer可能需要注册相对URL,以便访问外部样式:
String baseUrl = FileSystems.getDefault()
.getPath("src/main/resources/")
.toUri().toURL().toString();
renderer.setDocumentFromString(xhtml, baseUrl);
通过实现ReplacedElementFactory
,我们可以自定义与图像相关的属性:
public ReplacedElement createReplacedElement(LayoutContext lc, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) {
Element e = box.getElement();
String nodeName = e.getNodeName();
if (nodeName.equals("img")) {
String imagePath = e.getAttribute("src");
try {
InputStream input = new FileInputStream("src/main/resources/"+imagePath);
byte[] bytes = IOUtils.toByteArray(input);
Image image = Image.getInstance(bytes);
FSImage fsImage = new ITextFSImage(image);
if (cssWidth != -1 || cssHeight != -1) {
fsImage.scale(cssWidth, cssHeight);
} else {
fsImage.scale(2000, 1000);
}
return new ITextImageElement(fsImage);
} catch (Exception e1) {
e1.printStackTrace();
}
}
return null;
}
注意:以上代码会在图像路径前添加基路径,并在未提供时设置默认图像大小。
然后,我们将自定义的ReplacedElementFactory
添加到SharedContext
:
sharedContext.setReplacedElementFactory(new CustomElementFactoryImpl());
4. 使用Open HTML库实现
Open HTML to PDF 是另一个基于Flying Saucer + Apache PDF-BOX2 实现的Java库
4.1. Maven依赖
除了上述的jsoup库外,我们还需要在pom.xml
文件中添加几个Open HTML to PDF库:
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-core</artifactId>
<version>1.0.10</version>
</dependency>
<dependency>
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId>
<version>1.0.10</version>
</dependency>
库openhtmltopdf-core用于渲染规范的XML/XHTML,而*openhtmltopdf-pdfbox*则从渲染后的XHTML表示中生成PDF文档。
4.2. HTML转PDF
在这个程序中,使用Open HTML将HTML转换为PDF,我们将使用第3.2节中的相同HTML。首先,我们将像前面的例子一样将HTML文件转换为jsoup Document。
在最后一步,从XHTML文档创建PDF,PdfRendererBuilder
会接收这个XHTML文档并创建输出文件。同样,我们使用try-with-resources
来包裹我们的逻辑:
try (OutputStream os = new FileOutputStream(outputPdf)) {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.withUri(outputPdf);
builder.toStream(os);
builder.withW3cDocument(new W3CDom().fromJsoup(doc), "/");
builder.run();
}
4.3. 为外部样式自定义
我们也可以将HTML输入文档中使用的额外字体注册到PdfRendererBuilder
,以便在生成PDF时包含它们:
builder.useFont(new File(getClass().getClassLoader().getResource("fonts/PRISTINA.ttf").getFile()), "PRISTINA");
与先前的示例类似,PdfRendererBuilder
库可能也需要注册相对URL以访问外部样式:
String baseUrl = FileSystems.getDefault()
.getPath("src/main/resources/")
.toUri().toURL().toString();
builder.withW3cDocument(new W3CDom().fromJsoup(doc), baseUrl);
5. 结论
在这篇文章中,我们学习了如何使用Flying Saucer和Open HTML将HTML转换为PDF。我们还讨论了如何注册外部字体、样式和自定义选项。
如惯例,本文中所有使用的代码示例可在GitHub上找到这里。