iText 7, htmlPDF 2 - параллельное использование DefaultFontProvider - PullRequest
0 голосов
/ 15 октября 2018

Мы конвертируем почтовые сообщения на основе 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 инициализируется только один раз -> сохранить этот поток экземпляра?

Заранее спасибо!

1 Ответ

0 голосов
/ 07 ноября 2018

Краткий ответ: пожалуйста, прочитайте документацию.

Ответ на вопрос 1

Является ли создание DefaultFontProvider допустимым для каждого отдельного вызова илидолжен ли быть только один экземпляр (например, из-за затрат на создание)?

Вы должны создавать новый экземпляр для каждого преобразования, как сейчас.Поставщики шрифтов привязаны к документам, что указано в документации для базового FontProvider класса.Хотя если вы повторно используете поставщик шрифтов, он все равно будет работать, но я не рекомендую это делать.

Документация по методу setFontProvider, который вы используете, прямо говорит об этом:

Обратите внимание, что экземпляры FontProvider не могут быть повторно использованы в нескольких документах и, следовательно, как только вы установите этосвойство, этот экземпляр ConverterProperties становится полезным только для одного преобразования HTML.

Ответ на вопрос 2

Если DefaultFontProvider инициализируется только один раз -> сохраняет ли этот экземпляр поток?

Нет гарантии безопасности потока.Документация поможет вам использовать DefaultFontProvider только для одного преобразования.

Советы по оптимизации

(чтобы я мог их применить)

  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).
...