2

我们正在转换基于iText 7.1.2和的邮件消息htmlPDF 2.0.2。转换是在一个静态方法中完成的,该方法由并行线程为每个基于 html 的消息调用。代码看起来像这样简化(流在 finally 块中关闭):

ConverterProperties properties = new ConverterProperties();
FontProvider fontProvider = new DefaultFontProvider();
for (String font : ITEXT_FONTS) {
   FontProgram fontProgram = FontProgramFactory.createFont(font);
   fontProvider.addFont(fontProgram);
}
properties.setFontProvider(fontProvider);

fos = new FileOutputStream(targetFile);
HtmlConverter.convertToPdf(is, fos, properties);

for 循环用于从Noto位于类路径的包中添加中文字体。在我们的环境中,我们现在有时会看到以下错误场景:

Caused by: java.lang.OutOfMemoryError: Java heap space
   at java.util.Arrays.copyOf(Arrays.java:3236)
   at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)
   at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
   at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)
   at com.itextpdf.io.util.StreamUtil.inputStreamToArray(StreamUtil.java:212)
   at com.itextpdf.html2pdf.resolver.font.DefaultFontProvider.addShippedFreeFonts(DefaultFontProvider.java:111)
   at com.itextpdf.html2pdf.resolver.font.DefaultFontProvider.<init>(DefaultFontProvider.java:97)
   at com.itextpdf.html2pdf.resolver.font.DefaultFontProvider.<init>(DefaultFontProvider.java:81)

问题是:

  • 是否为每个调用创建 DefaultFontProvider 是合法的,还是应该只有一个实例(例如,因为创建成本)?
  • 如果 DefaultFontProvider 仅初始化一次 -> 此实例线程是否保存?

提前致谢!

4

1 回答 1

2

简短的回答是:请阅读文档。

回答问题 1

为每个调用创建 DefaultFontProvider 是否合法,还是应该只有一个实例(例如,因为创建成本)?

您应该像现在一样为每次转换创建一个新实例。字体提供程序与文档相关联,这在基FontProvider类的文档中有所说明。尽管如果您重用字体提供程序,它仍然很可能工作,但这不是我推荐的方式。

您正在使用的方法的文档setFontProvider对此很明确:

请注意,FontProvider 实例不能在多个文档中重复使用,因此一旦您设置了此属性,此 ConverterProperties 实例就仅对单个 HTML 转换有用。

回答问题 2

如果 DefaultFontProvider 仅初始化一次 -> 此实例线程是否保存?

无法保证线程安全。文档指导您仅将 aDefaultFontProvider用于单次转换。

优化提示

(为了我会尝试应用它们)

  1. 看一下DefaultFontProvider(boolean, boolean, boolean)构造函数。默认情况下,pdfHTML 加载标准 PDF 字体以及 pdfHTML 附带的字体。如果您确定手动添加的字体涵盖了您在 HTML 文件中使用的所有脚本,则可以传递false给所有三个构造函数参数 ( new DefaultFontProvider(false, false, false))。但是如果你不确定不要这样做,因为它可能会导致结果中缺少一些文本。或者将必要的字体添加到您的收藏中以确保。
  2. 重用FontProgram实例。它们是线程安全的,可用于许多文档的转换。但是,这是 iText 的默认行为,除了使事实明确之外,这很可能不会改善您的情况。
  3. 如果你可以做点1.,那么你也可以重用FontSet,如果你使用另一个实现FontProvider- 首先,创建你的DefaultFontProvider 一次并在那里添加所有字体一次,然后,FontSet通过获取实例defaultFP.getFontSet(),之后你可以通过字体集创建字体提供程序new FontProvider(fontSet)-每次进行转换时都必须这样做(请参阅问题 1 的答案)。
于 2018-11-07T18:38:14.110 回答