使用Openhtmltopdf,PDFBox在Java中将HTML转换为PDF

时间:2020-01-09 10:35:24  来源:igfitidea点击:

在使用Flying Saucer在Java中将HTML转换为PDF的文章OpenPDF中,我们看到了一种将HTML转换为PDF的方法,在本教程中,我们将了解如何使用Openhtmltopdf,PDFBox和jsoup在Java中将HTML转换为PDF。

使用Openhtmltopdf将HTML转换为PDF –工作原理

Open HTML to PDF是一个纯Java库,用于使用CSS 2.1进行布局和格式设置来呈现任意格式正确的XML / XHTML(甚至HTML5),并输出为PDF或者图像。将HTML转换为PDF的步骤如下-

  • 第一步是确保我们使用jsoup将HTML用作输入并解析它以返回格式正确的HTML,从而形成格式正确的HTML。
  • Openhtmltopdf使用CSS生成XHTML的呈现形式,以进行布局和格式设置。
  • PDFBox用于从该渲染表示形式生成PDF文档。

Maven依赖

Openhtmltopdf,jsoup和PDFBox的Apache Maven依赖关系如下-

<dependency>
  <!-- ALWAYS required -->
  <groupId>com.openhtmltopdf</groupId>
  <artifactId>openhtmltopdf-core</artifactId>
  <version>${openhtml.version}</version>
</dependency>
   
<dependency>
  <!-- Required for PDF output. -->
  <groupId>com.openhtmltopdf</groupId>
  <artifactId>openhtmltopdf-pdfbox</artifactId>
  <version>${openhtml.version}</version>
</dependency>
<!-- jsoup -->
<dependency>
  <groupId>org.jsoup</groupId>
  <artifactId>jsoup</artifactId>
  <version>1.13.1</version>
</dependency>

在POM的属性部分添加

<properties>         
  <openhtml.version>1.0.4</openhtml.version>
</properties>

使用Openhtmltopdf和PDFBox Java程序将HTML转换为PDF

在将HTML转换为PDF的过程中,Java程序试图解决三个常见问题:

  • 如何使用<img src ="" ..>标签在PDF中显示以HTML格式显示的图像。
  • 如何添加任何特定的网络字体。
  • 如何确保HTML中使用的外部CSS也可以用来设置生成的PDF的样式。

示例程序使用的文件夹结构如下所示。在PDFBox文件夹中,我们有HTML文件,真型字体文件和png图像文件,而PDFBox / css文件夹中有css文件。

- PDFBox
 MyPage.html
 Gabriola.ttf
 image.png
--css
  mystyles.css

MyPage.html

这是我们必须转换为PDF的HTML。

<html lang="en">
  <head>
    <title>MyPage</title>  
    <style type="text/css">
      body{background-color: powderblue;}
    </style>
    <link href="css/mystyles.css" rel="stylesheet" >
  </head>
  <body>
    <h1>Convert HTML to PDF</h1>
    <p>Here is an embedded image</p>
    <img src="image.png" width="250" height="150">
    <p style="color:red">Styled text using Inline CSS</p>
    <i>This is italicised text</i>
    <p class="fontclass">This text uses the styling from font face font</p>
    <p class="myclass">This text uses the styling from external CSS class</p>
  </body>
</html>

如我们所见,此HTML将内联CSS与<p>标记一起使用

<p style="color:red">Styled text using Inline CSS</p>

在<style> </ style>标记中使用内部CSS,还使用外部CSS。所有这些样式也应反映在PDF中。

还有一个带有相对路径的图像。

mystyles.css

在css中,@ font-face规则用于指定字体和可以找到它的URL。
使用@page规则指定在打印文档时要使用的CSS属性。

@font-face {
  font-family: myFont;
  src: url("../Gabriola.ttf");
}
.fontclass{
  font-family: myFont;
}
@Page {
  size: 8.5in 11in;
  margin: 1in;
}
.myclass{
  font-family: Helvetica, sans-serif;
  font-size:25;
  font-weight: normal;
  color: blue;
}

这就是在Chrome浏览器中呈现HTML的方式。

Java程序将HTML转换为PDF

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.FileSystems;
import org.jsoup.Jsoup;
import org.jsoup.helper.W3CDom;
import org.w3c.dom.Document;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;

public class HtmlToPdf {
   public static void main(String[] args) {
     try {
      // Source HTML file
      String inputHTML = "F:\theitroad\Java\Java Programs\PDF using Java\PDFBox\MyPage.html";
      // Generated PDF file name
      String outputPdf = "F:\theitroad\Java\Java Programs\PDF using Java\PDFBox\Output.pdf";
      htmlToPdf(inputHTML, outputPdf);	      
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
	
  private static Document html5ParseDocument(String inputHTML) throws IOException{
    org.jsoup.nodes.Document doc;
    System.out.println("parsing ...");
    doc = Jsoup.parse(new File(inputHTML), "UTF-8");
    System.out.println("parsing done ..." + doc);
    return new W3CDom().fromJsoup(doc);
  }
	
  private static void htmlToPdf(String inputHTML, String outputPdf) throws IOException {
    Document doc = html5ParseDocument(inputHTML);
    String baseUri = FileSystems.getDefault()
              .getPath("F:/", "theitroad/Java/", "Java Programs/PDF using Java/PDFBox/")
              .toUri()
              .toString();
    OutputStream os = new FileOutputStream(outputPdf);
    PdfRendererBuilder builder = new PdfRendererBuilder();
    builder.withUri(outputPdf);
    builder.toStream(os);
    // using absolute path here
    builder.useFont(new File("F:\theitroad\Java\Java Programs\PDF using Java\PDFBox\Gabriola.ttf"), 
    "Gabriola");
    builder.withW3cDocument(doc, baseUri);
    //builder.useUriResolver(new MyResolver());
    builder.run();
    System.out.println("PDF generation completed");
    os.close();
  }
}

在程序中,要注意的一些重要点是:

  • 在html5ParseDocument方法中,jsoup.parse()方法用于生成格式正确的HTML。
  • 然后,使用HTML作为输入,使用格式正确的HTML生成PDF。
  • 我们会看到创建了一个BaseUri,然后将其传递给builder方法。withW3cDocument(doc,baseUri);这样,程序就知道如何针对此bseUri解析相对路径。
  • 使用useFont方法,还通过将绝对路径传递到下载字体文件的位置来添加一种字体。

生成的PDF
编写自定义解析器

我们还可以插入自己的自定义解析器,该解析器可用于解析相对URI,私有地址空间中的URI甚至拒绝URI。自定义解析器需要实现FSUriResolver接口。

import java.net.URI;
import java.net.URISyntaxException;
import com.openhtmltopdf.extend.FSUriResolver;
import com.openhtmltopdf.swing.NaiveUserAgent;

public class MyResolver implements FSUriResolver {
  final NaiveUserAgent.DefaultUriResolver defaultUriResolver = new NaiveUserAgent.DefaultUriResolver();
  @Override
  public String resolveURI(String baseUri, String uri) {
    System.out.println("URI--- " + uri);
    String supResolved = defaultUriResolver.resolveURI(baseUri, uri);
    if (supResolved == null || supResolved.isEmpty())
      return null;
    
    try {
      URI uriObj = new URI(supResolved);
      //System.out.println("resolveURI..." + uriObj.toString());
      return uriObj.toString();
    }catch (URISyntaxException e) {
      e.printStackTrace();
    }
    return null;
  }
}

我们可以通过如下设置来使用此自定义解析器:

builder.useUriResolver(new MyResolver());