如何使用iText和Flying Saucer将字体嵌入从HTML创建的PDF中?

16

我在将HTML转换为PDF时,嵌入波兰字体遇到了问题。

我的HTML代码中在body中有样式:

<BODY style="font-family: Tahoma, Arial, sans-serif;font-size : 8pt;">

我尝试了两种方法将这样的HTML转换为PDF:

  • 使用htmlcleaner和FOP
  • 使用flying-saucer和iText

对于FOP,我可以将所有使用过的字体添加到其配置文件中,然后创建的PDF将嵌入这些字体(如果HTML中使用了该字体)。在生成的PDF中,我有Tahoma字体和Identity-H编码。它看起来很好 - 所有波兰字母都按预期显示。

然后我尝试使用iText进行此类转换:似乎更简单,因为我不需要为每个HTML创建转换。不幸的是,我不知道如何将所用字体嵌入到生成的PDF中。我找到的大多数示例都是从头开始创建PDF,而我不知道如何将这些方法应用于Flying Saucer ITextRenderer或其他用于转换的对象。

我的当前代码尝试在 PDFCreationListener.preOpen() 中添加字体,通过获取ITextFontResolver并添加字体 fs.addFont(path,true); 。但我创建的所有.pdf都没有我想要的字体。

第二个问题是结果PDF没有波兰字母。这是Flying Saucer还是iText的问题?Acrobat显示创建的PDF文档使用Helvetica和Ansi编码的ArialMT字体。我认为这种Ansi编码不好。我该如何设置波兰编码(Identity-H)?

4个回答

21
您可以尝试使用 -fs-pdf-font-embed 和 -fs-pdf-font-encoding CSS 规则。来自用户指南

-fs-pdf-font-embed:与字体面规则中的嵌入值一起使用,使Flying Saucer在PDF文档中嵌入字体文件,避免调用FontResolver类的addFont()方法。

-fs-pdf-font-encoding:在字体面规则中使用以指定您在PDF中嵌入的自定义字体的编码;将编码名称作为值。

例如,在您的打印CSS中:
@font-face {
    font-family: DejaVu Serif;
    src: url(fonts/DejaVuSerif.ttf);
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: Identity-H;
}

谢谢,我试了这个但不起作用。当然我也尝试了 FontResolver.addFont(),但是在生成的PDF中没有我想要的字体。 - Michał Niklas
1
奇怪,这对我来说很好用。只需确保使用正确的 src 语法;FS似乎只理解 url() 部分,而不是 format() 或其他任何内容。必须只有一个带有ttf文件的src。上面的示例有效。 - rustyx
2
这对我有用。使用 @font-face { font-family: Roboto; src: url(file:///home/fonts/Roboto-Regular.ttf); font-weight: normal; font-style: normal; -fs-pdf-font-embed: embed; -fs-pdf-font-encoding: Identity-H; } 添加了更详细的 Google Roboto 字体,例如 <body style="font-family: Roboto;"> 使用它。 - micfra
更新用户指南链接: https://flyingsaucerproject.github.io/flyingsaucer/r8/guide/users-guide-R8.html - Saurabh Gupta

5

示例代码:

根目录下的文件:

  • Calibri.ttf
  • input.html

代码:

File inputFile = new File("input.html");
File outputFile = new File("example.pdf");

ITextRenderer renderer = new ITextRenderer();

String url = inputFile.toURI().toURL().toString();
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);

renderer.setDocument(url);
renderer.getFontResolver().addFont("Calibri.ttf", BaseFont.IDENTITY_H, true);
renderer.layout();
renderer.createPDF(fileOutputStream);

fileOutputStream.close();       

HTML:

<style type="text/css">
    body {
        font-family: Calibri, sans-serif;
    }
</style>

令人惊讶的是,不需要@font-face css。


3

我的错误是在PDFCreationListener.preOpen()中使用FontResolver.addFont(),我将其移动到renderer.layout();之前,现在它可以工作了!


2
嘿,我有同样的问题,我尝试了这段代码 renderer.getFontResolver().addFont("c:/simsun.ttf", "UTF-8",BaseFont.EMBEDDED);//I also tried with arialuni.ttf 但它没有起作用。 - Ankur

1

如果您已尝试了所有选项,但仍无法解决问题,那么很可能是font-family值与文件名不匹配所致。

您可以使用 FontForge 找到正确的值。在该程序中打开字体文件,然后选择菜单项 Element -> Font Info。正确的值将在 Family Name字段中。

最小所需的 HTML 代码:

<html>
<head>
    <style>
        body {
            font-family: 'Calibri 123', sans-serif;
        }
    </style>
</head>
<body>
<p>
    Hello, Calibri 123
</p>
</body>
</html>

最少需要的Java代码:

ITextRenderer renderer = new ITextRenderer();
renderer.getFontResolver().addFont("/path/to/font/Calibri.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
renderer.setDocumentFromString(/*read html from file*/);
renderer.layout();
renderer.createPDF(/*stream here*/);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接